changes in Sidebar

This commit is contained in:
ATUL GUNJAL 2025-04-23 13:35:50 +05:30
parent be9ecf4224
commit aaf876f098
5 changed files with 257 additions and 4 deletions

View File

@ -123,6 +123,43 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen, isCollapsed }) => {
{!isCollapsed && "Add Multiple Tokens"} {!isCollapsed && "Add Multiple Tokens"}
</Link> </Link>
{/* Done tokens Link */}
<Link
href="/pages/done"
className={`flex items-center gap-2 p-3 rounded-md text-sm font-semibold transition-colors ${isActive("/pages/CustomReport")
? darkMode
? "bg-blue-900 text-blue-200"
: "bg-blue-100 text-blue-800"
: darkMode
? "hover:bg-gray-700"
: "hover:bg-gray-200"
} ${isCollapsed ? 'justify-center' : ''}`}
onClick={closeSidebarOnMobile}
>
<FileText size={18} className="w-5" />
{!isCollapsed && "Done List"}
</Link>
{/* Missed tokens Link */}
<Link
href="/pages/missed"
className={`flex items-center gap-2 p-3 rounded-md text-sm font-semibold transition-colors ${isActive("/pages/CustomReport")
? darkMode
? "bg-blue-900 text-blue-200"
: "bg-blue-100 text-blue-800"
: darkMode
? "hover:bg-gray-700"
: "hover:bg-gray-200"
} ${isCollapsed ? 'justify-center' : ''}`}
onClick={closeSidebarOnMobile}
>
<FileText size={18} className="w-5" />
{!isCollapsed && "Missed List"}
</Link>
{/* -----------------------Entries-------------------------------------------- */} {/* -----------------------Entries-------------------------------------------- */}
{/* User Profile Link */} {/* User Profile Link */}
@ -144,7 +181,7 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen, isCollapsed }) => {
{!isCollapsed && "Entries"} {!isCollapsed && "Entries"}
</Link> */} </Link> */}
{/* ------------staffBooking---------------- */} {/* ------------staffBooking----------------
<Link <Link
href="/pages/StaffBooking" href="/pages/StaffBooking"
className={`flex items-center gap-2 p-3 rounded-md text-sm font-semibold transition-colors ${isActive("/pages/UserProfile") className={`flex items-center gap-2 p-3 rounded-md text-sm font-semibold transition-colors ${isActive("/pages/UserProfile")
@ -161,7 +198,7 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen, isCollapsed }) => {
<path strokeLinecap="round" strokeLinejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"></path> <path strokeLinecap="round" strokeLinejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"></path>
</svg> </svg>
{!isCollapsed && "StaffBooking"} {!isCollapsed && "StaffBooking"}
</Link> </Link> */}
{/* ------------------------Setting--------------------------------- */} {/* ------------------------Setting--------------------------------- */}
<Link <Link
href="/pages/setting" href="/pages/setting"

View File

@ -0,0 +1,195 @@
"use client";
import { useState, useEffect } from "react";
import { databases, Query } from "../lib/appwrite";
import { DATABASE_ID, COLLECTION_ID } from "../lib/api";
import { useTheme } from "../context/ThemeContext";
export default function TokenTable({ statusFilter }) {
const { darkMode } = useTheme();
const [entries, setEntries] = useState([]);
const [filteredEntries, setFilteredEntries] = useState([]);
const [searchQuery, setSearchQuery] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const entriesPerPage = 20;
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
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;
}
};
const updateStatus = async (entryId, newStatus) => {
try {
setLoading(true);
await databases.updateDocument(
DATABASE_ID,
COLLECTION_ID,
entryId,
{ status: newStatus }
);
const data = await getEntries();
setEntries(data);
applyFilters(data, searchQuery);
} catch (error) {
console.error("Update error:", error);
setError(error.message);
} finally {
setLoading(false);
}
};
const applyFilters = (data, search) => {
let filtered = data.filter((entry) => {
const matchesSearch =
entry.patientName.toLowerCase().includes(search.toLowerCase()) ||
entry.tokenNumber.toString().includes(search);
const matchesFilter =
statusFilter === "all" ||
entry.status === statusFilter ||
(statusFilter === "booked" && entry.status === "booked");
return matchesSearch && matchesFilter;
});
setFilteredEntries(filtered);
};
useEffect(() => {
const loadData = async () => {
try {
const data = await getEntries();
setEntries(data);
applyFilters(data, searchQuery);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
loadData();
}, []);
useEffect(() => {
applyFilters(entries, searchQuery);
setCurrentPage(1);
}, [searchQuery, statusFilter, entries]);
const indexOfLastEntry = currentPage * entriesPerPage;
const indexOfFirstEntry = indexOfLastEntry - entriesPerPage;
const currentEntries = filteredEntries.slice(indexOfFirstEntry, indexOfLastEntry);
const totalPages = Math.ceil(filteredEntries.length / entriesPerPage);
if (loading) return (
<div className="text-center mt-50">
<div className={`animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mx-auto`}></div>
<p className={`mt-4 text-lg font-semibold`}>Loading...</p>
</div>
);
if (error) return <div className="p-4 text-red-500">Error: {error}</div>;
return (
<>
<input
type="text"
placeholder="Search by token or name"
className="mb-4 p-2 border rounded bg-white w-full max-w-sm"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
{filteredEntries.length === 0 ? (
<div className="p-4">No entries found.</div>
) : (
<>
<table className="w-full border-collapse">
<thead className={darkMode ? "bg-gray-800" : "bg-gray-100"}>
<tr>
<th className="p-3 text-left">Token</th>
<th className="p-3 text-left">Name</th>
<th className="p-3 text-left">Status</th>
<th className="p-3 text-left">Actions</th>
</tr>
</thead>
<tbody>
{currentEntries.map((entry) => (
<tr
key={entry.$id}
className={`border ${darkMode ? 'border-gray-700' : 'border-gray-200'}`}
>
<td className="p-3 font-mono">{entry.tokenNumber}</td>
<td className="p-3">{entry.patientName}</td>
<td className="p-3">
<span
className={`px-2 py-1 rounded-full text-xs ${entry.status === "done"
? "bg-green-100 text-green-800"
: entry.status === "booked"
? "bg-yellow-100 text-yellow-800"
: "bg-red-100 text-red-800"
} font-semibold`}
>
{entry.status === "booked" ? "In-Queue" : entry.status}
</span>
</td>
<td className="p-3 flex gap-2">
{entry.status === "booked" && (
<>
<button
onClick={() => updateStatus(entry.$id, "done")}
className="border border-green-600 text-green-600 rounded-full px-2 py-1 text-xs hover:bg-green-50"
>
Done
</button>
<button
onClick={() => updateStatus(entry.$id, "missed")}
className="border border-red-600 text-red-600 rounded-full px-2 py-1 text-xs hover:bg-red-50"
>
Missed
</button>
</>
)}
</td>
</tr>
))}
</tbody>
</table>
<div className={`flex justify-between items-center mt-4 ${darkMode ? 'text-white' : 'text-gray-700'}`}>
<button
disabled={currentPage === 1}
onClick={() => setCurrentPage((prev) => prev - 1)}
className="px-3 py-1 border rounded disabled:opacity-50"
>
Previous
</button>
<span className="text-sm">
Page {currentPage} of {totalPages}
</span>
<button
disabled={currentPage === totalPages}
onClick={() => setCurrentPage((prev) => prev + 1)}
className="px-3 py-1 border rounded disabled:opacity-50"
>
Next
</button>
</div>
</>
)}
</>
);
}

View File

@ -66,7 +66,7 @@ export default function StaffBooking() {
<main className="p-4 mx-auto max-w-[--breakpoint-2xl] md:p-6"> <main className="p-4 mx-auto max-w-[--breakpoint-2xl] md:p-6">
{/* Statistics Overview */} {/* Statistics Overview */}
<div className={`mb-8 p-6 rounded-lg ${darkMode ? 'bg-gray-800' : 'bg-gray-50'} border ${darkMode ? 'border-gray-700' : 'border-gray-200'}`}> {/* <div className={`mb-8 p-6 rounded-lg ${darkMode ? 'bg-gray-800' : 'bg-gray-50'} border ${darkMode ? 'border-gray-700' : 'border-gray-200'}`}>
<h3 className={`text-lg font-medium mb-4 ${darkMode ? 'text-white' : 'text-gray-800'}`}> <h3 className={`text-lg font-medium mb-4 ${darkMode ? 'text-white' : 'text-gray-800'}`}>
Today&apos;s Overview Today&apos;s Overview
</h3> </h3>
@ -84,7 +84,7 @@ export default function StaffBooking() {
<p className={`text-2xl font-bold ${darkMode ? 'text-white' : 'text-gray-900'}`}>{stats.done}</p> <p className={`text-2xl font-bold ${darkMode ? 'text-white' : 'text-gray-900'}`}>{stats.done}</p>
</div> </div>
</div> </div>
</div> </div> */}
{/* Booking Options */} {/* Booking Options */}
<div className="space-y-4"> <div className="space-y-4">

View File

@ -0,0 +1,11 @@
import TokenTable from "../../components/TokenTable";
export default function DoneTokensPage() {
return (
<div>
<h1 className="text-2xl font-bold mb-4">Done Tokens</h1>
<TokenTable statusFilter="done" />
</div>
);
}

View File

@ -0,0 +1,10 @@
import TokenTable from "../../components/TokenTable";
export default function MissedTokensPage() {
return (
<div>
<h1 className="text-2xl font-bold mb-4">Missed Tokens</h1>
<TokenTable statusFilter="missed" />
</div>
);
}