From 7c3e0dad13bd93d4ca6be5b7584f2444c2a18581 Mon Sep 17 00:00:00 2001 From: sajan moon Date: Tue, 13 May 2025 12:00:55 +0530 Subject: [PATCH] FixedTheBugOfHeaderInMultiBooking --- src/app/dashboard/page.js | 43 +++-- src/app/pages/MultiBooking/page.js | 238 ++++++++++++++++++++------ src/app/pages/entries/EntriesTable.js | 91 ++++++---- 3 files changed, 276 insertions(+), 96 deletions(-) diff --git a/src/app/dashboard/page.js b/src/app/dashboard/page.js index 16a2c5a..959bf67 100644 --- a/src/app/dashboard/page.js +++ b/src/app/dashboard/page.js @@ -1,5 +1,6 @@ -// src/app/dashboard/page.js + "use client"; + import { useRouter } from "next/navigation"; import { useAuth } from "../context/AuthContext"; import { useEffect } from "react"; @@ -22,12 +23,16 @@ export default function DashboardPage() { return (
-
-

+

+

Loading...

@@ -39,12 +44,28 @@ export default function DashboardPage() { return null; } + // Check if user is admin or staff to show entries table + const canViewEntries = userRole === "admin" || userRole === "staff"; + return ( -
+
- + {canViewEntries ? ( + + ) : ( +
+

+ Welcome to your Dashboard +

+

+ You don't have permission to view entries. +

+
+ )}
); diff --git a/src/app/pages/MultiBooking/page.js b/src/app/pages/MultiBooking/page.js index fd4d9ad..35915e7 100644 --- a/src/app/pages/MultiBooking/page.js +++ b/src/app/pages/MultiBooking/page.js @@ -1,44 +1,126 @@ + "use client"; -import { useState } from 'react'; -import { useRouter } from 'next/navigation'; +import { useState, useEffect } from "react"; +import { useRouter } from "next/navigation"; import Header from "../../components/partials/header"; import { useTheme } from "../../context/ThemeContext"; +import { databases, Query } from "../../lib/appwrite"; +import { DATABASE_ID, COLLECTION_ID } from "../../lib/api"; export default function MultiBooking() { const { darkMode } = useTheme(); const router = useRouter(); - const [appointmentDate, setAppointmentDate] = useState(new Date().toISOString().split('T')[0]); + + const [appointmentDate, setAppointmentDate] = useState( + new Date().toISOString().split("T")[0] + ); const [patients, setPatients] = useState( - Array(5).fill().map((_, i) => ({ id: i+1, name: "" })) + Array(5) + .fill() + .map((_, i) => ({ id: i + 1, name: "" })) ); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); + // Header related states - matching EntriesTable + const [entries, setEntries] = useState([]); + const [currentToken, setCurrentToken] = useState(null); + const [previousToken, setPreviousToken] = useState(null); + const [nextToken, setNextToken] = useState(null); + const [missedTokens, setMissedTokens] = useState(""); + const [dataLoading, setDataLoading] = useState(true); + const handleNameChange = (id, value) => { - setPatients(patients.map(p => - p.id === id ? { ...p, name: value } : p - )); + setPatients(patients.map((p) => (p.id === id ? { ...p, name: value } : p))); }; + // Get entries from database - similar to EntriesTable + const getEntries = async () => { + try { + const today = new Date().toISOString().split("T")[0]; + const response = await databases.listDocuments( + DATABASE_ID, + COLLECTION_ID, + [Query.equal("date", today), Query.orderAsc("tokenNumber")], + 100 + ); + return response.documents; + } catch (error) { + console.error("Fetch error:", error); + throw error; + } + }; + + // Update token information - same as EntriesTable + const updateTokenInfo = (entries) => { + if (entries.length === 0) { + setCurrentToken(null); + setPreviousToken(null); + setNextToken(null); + setMissedTokens(""); + return; + } + + const currentIndex = entries.findIndex( + (entry) => entry.status === "booked" + ); + const current = currentIndex >= 0 ? entries[currentIndex] : null; + + setCurrentToken(current?.tokenNumber || null); + setPreviousToken( + currentIndex > 0 ? entries[currentIndex - 1]?.tokenNumber : null + ); + setNextToken( + currentIndex < entries.length - 1 + ? entries[currentIndex + 1]?.tokenNumber + : null + ); + + const missed = entries + .filter((entry) => entry.status === "missed") + .map((entry) => entry.tokenNumber) + .join(", "); + setMissedTokens(missed || "None"); + }; + + // Load token data - similar to EntriesTable + useEffect(() => { + const loadTokenData = async () => { + try { + setDataLoading(true); + const data = await getEntries(); + setEntries(data); + updateTokenInfo(data); + } catch (err) { + console.error("Error loading token data:", err); + } finally { + setDataLoading(false); + } + }; + + loadTokenData(); + }, []); + const handleSubmit = async (e) => { e.preventDefault(); setLoading(true); setError(null); try { - // Filter out empty names and validate - const validPatients = patients.filter(p => p.name.trim() !== ""); + const validPatients = patients.filter((p) => p.name.trim() !== ""); if (validPatients.length === 0) { - throw new Error("Please enter at least one patient name"); + throw new Error("Please enter at least one patient name."); } - // Store in session to use in MultiBooked page - sessionStorage.setItem('multiBookingData', JSON.stringify({ - date: appointmentDate, - patients: validPatients - })); + sessionStorage.setItem( + "multiBookingData", + JSON.stringify({ + date: appointmentDate, + patients: validPatients, + }) + ); - router.push('/pages/MultiBooked'); + router.push("/pages/MultiBooked"); } catch (error) { setError(error.message); } finally { @@ -47,23 +129,32 @@ export default function MultiBooking() { }; const addMorePatients = () => { - const newId = patients.length > 0 ? - Math.max(...patients.map(p => p.id)) + 1 : 1; + if (patients.length >= 20) return; + const newId = + patients.length > 0 ? Math.max(...patients.map((p) => p.id)) + 1 : 1; setPatients([...patients, { id: newId, name: "" }]); }; return ( -
- {/* Content Area */} +
- {/* Sticky Header */}
-
+ {/* Pass the same props to Header as in EntriesTable */} +
- {/* Main Content */}
{error && ( @@ -73,47 +164,72 @@ export default function MultiBooking() { )}
-

+

Staff Multi-Booking

-
- +
{patients.map((patient) => (
- + {patient.id}. handleNameChange(patient.id, e.target.value)} + onChange={(e) => + handleNameChange(patient.id, e.target.value) + } placeholder="Patient name" className={`flex-1 shadow-theme-xs h-11 rounded-lg border px-4 py-2.5 text-sm focus:outline-none focus:ring-2 ${ - darkMode ? - 'bg-gray-800 border-gray-700 text-white placeholder-gray-500 focus:border-blue-800 focus:ring-blue-800/30' : - 'bg-white border-gray-300 text-gray-800 placeholder-gray-400 focus:border-blue-300 focus:ring-blue-500/10' + darkMode + ? "bg-gray-800 border-gray-700 text-white placeholder-gray-500 focus:border-blue-800 focus:ring-blue-800/30" + : "bg-white border-gray-300 text-gray-800 placeholder-gray-400 focus:border-blue-300 focus:ring-blue-500/10" }`} /> {patient.id > 5 && ( @@ -122,20 +238,27 @@ export default function MultiBooking() { ))}
-
+
-
- {patients.length} patients entered +
+ {patients.length} / 20 patients entered
@@ -144,34 +267,43 @@ export default function MultiBooking() { type="submit" disabled={loading} className={`text-center rounded-lg px-5 py-3.5 text-sm font-medium text-white shadow-theme-xs transition w-full ${ - loading ? 'bg-blue-400 cursor-not-allowed' : 'bg-blue-700 hover:bg-blue-600' + loading + ? "bg-blue-400 cursor-not-allowed" + : "bg-blue-700 hover:bg-blue-600" }`} > - {loading ? 'Processing...' : 'Generate Tokens'} + {loading ? "Processing..." : "Generate Tokens"}
- -
-

Staff can book multiple tokens at once. All tokens will be assigned for the same date.

-

Minimum 1 patient required. Maximum 20 patients per batch.

+ +
+

+ Staff can book multiple tokens at once. All tokens will be + assigned for the same date. +

+

+ Minimum 1 patient required. Maximum 20 patients per batch. +

); -} \ No newline at end of file +} diff --git a/src/app/pages/entries/EntriesTable.js b/src/app/pages/entries/EntriesTable.js index 3590897..00b58e3 100644 --- a/src/app/pages/entries/EntriesTable.js +++ b/src/app/pages/entries/EntriesTable.js @@ -1,3 +1,4 @@ + "use client"; import { useEffect, useState } from "react"; import { databases, Query } from "../../lib/appwrite"; @@ -25,21 +26,20 @@ export default function EntriesTable() { // Calculate waiting time based on position in queue const calculateWaitTime = (tokenNumber) => { - const bookedEntries = entries.filter(e => e.status === "booked"); - const position = bookedEntries.findIndex(e => e.tokenNumber === tokenNumber); - return position >= 0 ? (position * avgConsultTime) : 0; + const bookedEntries = entries.filter((e) => e.status === "booked"); + const position = bookedEntries.findIndex( + (e) => e.tokenNumber === tokenNumber + ); + return position >= 0 ? position * avgConsultTime : 0; }; const getEntries = async () => { try { - const today = new Date().toISOString().split('T')[0]; + const today = new Date().toISOString().split("T")[0]; const response = await databases.listDocuments( DATABASE_ID, COLLECTION_ID, - [ - Query.equal('date', today), - Query.orderAsc('tokenNumber') - ], + [Query.equal("date", today), Query.orderAsc("tokenNumber")], 100 ); return response.documents; @@ -58,12 +58,20 @@ export default function EntriesTable() { return; } - const currentIndex = entries.findIndex((entry) => entry.status === "booked"); + const currentIndex = entries.findIndex( + (entry) => entry.status === "booked" + ); const current = currentIndex >= 0 ? entries[currentIndex] : null; setCurrentToken(current?.tokenNumber || null); - setPreviousToken(currentIndex > 0 ? entries[currentIndex - 1]?.tokenNumber : null); - setNextToken(currentIndex < entries.length - 1 ? entries[currentIndex + 1]?.tokenNumber : null); + setPreviousToken( + currentIndex > 0 ? entries[currentIndex - 1]?.tokenNumber : null + ); + setNextToken( + currentIndex < entries.length - 1 + ? entries[currentIndex + 1]?.tokenNumber + : null + ); const missed = entries .filter((entry) => entry.status === "missed") @@ -75,12 +83,9 @@ export default function EntriesTable() { const updateStatus = async (entryId, newStatus) => { try { setLoading(true); - await databases.updateDocument( - DATABASE_ID, - COLLECTION_ID, - entryId, - { status: newStatus } - ); + await databases.updateDocument(DATABASE_ID, COLLECTION_ID, entryId, { + status: newStatus, + }); const data = await getEntries(); setEntries(data); setFilteredEntries(data); @@ -128,20 +133,32 @@ export default function EntriesTable() { const indexOfLastEntry = currentPage * entriesPerPage; const indexOfFirstEntry = indexOfLastEntry - entriesPerPage; - const currentEntries = filteredEntries.slice(indexOfFirstEntry, indexOfLastEntry); + const currentEntries = filteredEntries.slice( + indexOfFirstEntry, + indexOfLastEntry + ); const totalPages = Math.ceil(filteredEntries.length / entriesPerPage); - if (loading) return
-
-

Loading...

-
; + if (loading) + return ( +
+
+

Loading...

+
+ ); if (error) return
Error: {error}
; // Check user role and show permission message if patient if (userRole === "patient") { return ( -
+

Access Denied

@@ -153,7 +170,11 @@ export default function EntriesTable() { } return ( -
+
( {entry.tokenNumber} {entry.patientName} @@ -205,12 +228,13 @@ export default function EntriesTable() { */} {entry.status === "booked" ? "In-Queue" : entry.status} @@ -244,8 +268,11 @@ export default function EntriesTable() { {/* Pagination */} -
+
); -} \ No newline at end of file +}