Compare commits

...

14 Commits

Author SHA1 Message Date
a30cf6fd60 Merge pull request 'Token table caching issue resolved' (#5) from dev/TokenTableCachingIssue into main
Reviewed-on: #5
2025-05-19 06:10:16 +00:00
febea32de8 Token table caching issue resolved 2025-05-19 11:39:00 +05:30
2d9b89fdd8 Merge pull request 'dev/loading-animation-searchbox-mahima' (#4) from dev/loading-animation-searchbox-mahima into main
Reviewed-on: #4
2025-05-13 12:00:30 +00:00
Mahima Sonwane
3c7ff4cceb Delete Unwanted Sigup Signin Folders 2025-05-13 17:01:28 +05:30
Mahima Sonwane
82a05e5c6d Same loading animation on all pages and Updated search box style in entries table to match navbar 2025-05-13 16:59:36 +05:30
Mahima Sonwane
71a0ebef34 Updated search box style in entries table to match navbar and Same loading animation on all pages 2025-05-13 16:43:31 +05:30
e7d9b6966b Merge pull request 'Bug fixed Logout Sidebar' (#3) from dev/dashboard-rbac into main
Reviewed-on: #3
2025-05-13 07:02:47 +00:00
Mahima Sonwane
50484287f2 Bug fixed Logout Sidebar 2025-05-13 12:27:24 +05:30
f9ea8901d5 Merge pull request 'FixedTheBugOfHeaderInMultiBooking' (#2) from dev/fixTheBugOfHeaderInMultiBooking-sajan into main
Reviewed-on: #2
2025-05-13 06:40:20 +00:00
7c3e0dad13 FixedTheBugOfHeaderInMultiBooking 2025-05-13 12:00:55 +05:30
34a4d7b05a Merge pull request 'dev/ui-changes-atul' (#1) from dev/ui-changes-atul into main
Reviewed-on: #1
2025-05-08 07:56:39 +00:00
3f96a8203d recovered collection, removed "alert" & "back to dashboard" 2025-05-08 13:04:43 +05:30
6101f34bdc removed unwanted files, improved dashboard darkmode 2025-04-24 17:01:20 +05:30
00b51f3b48 improved sidebar icons in dark mode 2025-04-24 16:42:36 +05:30
31 changed files with 560 additions and 1683 deletions

View File

@ -1,5 +1,5 @@
NEXT_PUBLIC_APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
NEXT_PUBLIC_APPWRITE_PROJECT_ID=67e1445400053dca1d9b
NEXT_PUBLIC_APPWRITE_DATABASE_ID=67e1452b00016444b37f
NEXT_PUBLIC_APPWRITE_COLLECTION_ID=67fe4029000f7e0a7b92
NEXT_PUBLIC_APPWRITE_USERS_COLLECTION_ID=67ff72bd00370366ae3e
NEXT_PUBLIC_APPWRITE_COLLECTION_ID=681c367b0016f9ba0e8e
NEXT_PUBLIC_APPWRITE_USERS_COLLECTION_ID=681c35690038f9798152

View File

@ -2,9 +2,9 @@
import { useState, useEffect } from "react";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import { FileText, Moon, Sun } from "lucide-react";
import { FaLock, FaChevronDown, FaChevronUp } from "react-icons/fa";
import { FileText } from "lucide-react";
import { useTheme } from "../context/ThemeContext";
import { account } from "../lib/appwrite";
const Sidebar = ({ sidebarOpen, setSidebarOpen, isCollapsed }) => {
const pathname = usePathname();
@ -25,10 +25,17 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen, isCollapsed }) => {
setSidebarOpen(false);
}
};
const handleLogout = () => {
localStorage.removeItem("token"); // or account.deleteSession("current") if using Appwrite
router.push("/signup");
const handleLogout = async () => {
try {
await account.deleteSession("current");
localStorage.removeItem("token");
// Force a full page reload to reset all state
window.location.href = "/";
} catch (error) {
console.error("Logout failed:", error);
}
};
// ---------------logo handling in dark mode-----------------------
// Create a separate LogoImage component for better error handling
function LogoImage({ darkSrc, lightSrc, darkMode, className, alt }) {
@ -71,25 +78,7 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen, isCollapsed }) => {
>
<div className="h-full flex flex-col border-r border-gray-200 p-4 overflow-y-auto scrollbar-hide">
{/* Logo Section */}
<div className={`flex items-center gap-2 mb-6 ${isCollapsed ? 'justify-center' : ''}`}>
{isCollapsed ? (
<LogoImage
darkSrc="/images/logo/logo-icon-white.svg"
lightSrc="/images/logo/logo-icon.svg"
darkMode={darkMode}
className="w-8"
alt="Collapsed Logo"
/>
) : (
<LogoImage
darkSrc="/images/logo/logo-white.svg"
lightSrc="/images/logo/logo.svg"
darkMode={darkMode}
className="h-8"
alt="Full Logo"
/>
)}
</div>
{/* MENU section - Only show when not collapsed */}
{!isCollapsed && (
@ -105,21 +94,21 @@ const Sidebar = ({ sidebarOpen, setSidebarOpen, isCollapsed }) => {
<Link
href="/dashboard"
className={`flex items-center gap-2 p-3 rounded-md text-sm font-semibold transition-colors ${isActive("/dashboard")
? darkMode
? "bg-blue-900 text-blue-200"
: "bg-blue-100 text-blue-800"
: darkMode
? "hover:bg-gray-700 text-gray-200"
: "hover:bg-gray-200"
? darkMode
? "bg-blue-900 text-blue-200"
: "bg-blue-100 text-blue-800"
: darkMode
? "hover:bg-gray-700 text-gray-200"
: "hover:bg-gray-200"
} ${isCollapsed ? 'justify-center' : ''}`}
onClick={closeSidebarOnMobile}
>
<img
src={darkMode ? "/images/icons/grid-white.svg" : "/images/icons/grid.svg"}
src={darkMode ? "/images/icons/grid.svg" : "/images/icons/grid.svg"}
alt="Dashboard"
className={`w-5 ${darkMode ? 'filter brightness-0 invert' : ''}`}
onError={(e) => {
e.target.src = darkMode ? "/images/icons/grid.svg" : "/images/icons/grid-white.svg";
e.target.src = darkMode ? "/images/icons/grid.svg" : "/images/icons/grid.svg";
e.target.className = 'w-5'; // Remove filter if fallback
}}
/>

View File

@ -55,15 +55,15 @@ export default function TokenTable({ statusFilter }) {
const applyFilters = (data, search) => {
let filtered = data.filter((entry) => {
const matchesSearch =
const matchesSearch =
entry.patientName.toLowerCase().includes(search.toLowerCase()) ||
entry.tokenNumber.toString().includes(search);
const matchesFilter =
statusFilter === "all" ||
const matchesFilter =
statusFilter === "all" ||
entry.status === statusFilter ||
(statusFilter === "booked" && entry.status === "booked");
return matchesSearch && matchesFilter;
});
setFilteredEntries(filtered);
@ -96,162 +96,153 @@ export default function TokenTable({ statusFilter }) {
// Handle theme loading state
if (darkMode === undefined) {
return (
<div className={`flex items-center justify-center min-h-[200px] ${darkMode ? 'bg-gray-900' : 'bg-white'}`}>
<div className="text-center">
<div className={`animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mx-auto ${
darkMode === true ? 'border-gray-100' : 'border-gray-900'
}`}></div>
<p className={`mt-4 text-lg font-semibold ${
darkMode === true ? 'text-gray-100' : 'text-gray-900'
}`}>
Loading...
</p>
// Handle theme loading state
if (darkMode === undefined) {
return (
<div className={`flex items-center justify-center min-h-[200px] ${darkMode ? 'bg-gray-900' : 'bg-white'}`}>
<div className="text-center">
<div
className={`animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mx-auto ${darkMode === true ? "border-gray-100" : "border-blue-400"
}`}
></div>
<p className={`mt-4 text-lg font-semibold ${darkMode === true ? 'text-gray-100' : 'text-gray-900'
}`}>
Loading...
</p>
</div>
</div>
);
}
if (loading) return (
<div className={`text-center py-10 ${darkMode ? 'bg-gray-900' : 'bg-white'}`}>
<div className={`animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 mx-auto ${darkMode ? 'border-gray-100' : 'border-blue-400'
}`}></div>
<p className={`mt-4 text-lg font-semibold ${darkMode ? 'text-gray-100' : 'text-gray-900'
}`}>
Loading...
</p>
</div>
);
}
if (loading) return (
<div className={`text-center py-10 ${darkMode ? 'bg-gray-900' : 'bg-white'}`}>
<div className={`animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 mx-auto ${
darkMode ? 'border-gray-100' : 'border-gray-900'
}`}></div>
<p className={`mt-4 text-lg font-semibold ${
darkMode ? 'text-gray-100' : 'text-gray-900'
}`}>
Loading...
</p>
</div>
);
if (error) return (
<div className={`p-4 rounded ${darkMode ? 'bg-red-900 text-red-100' : 'bg-red-100 text-red-900'}`}>
Error: {error}
</div>
);
if (error) return (
<div className={`p-4 rounded ${darkMode ? 'bg-red-900 text-red-100' : 'bg-red-100 text-red-900'}`}>
Error: {error}
</div>
);
return (
<div className={`transition-colors duration-300 ${darkMode ? 'text-gray-100' : 'text-gray-800'}`}>
<input
type="text"
placeholder="Search by token or name"
className={`mb-4 p-2 border rounded w-full max-w-sm transition-colors ${
darkMode
? 'bg-gray-800 border-gray-700 text-white placeholder-gray-400 focus:ring-blue-500 focus:border-blue-500'
return (
<div className={`transition-colors duration-300 ${darkMode ? 'text-gray-100' : 'text-gray-800'}`}>
<input
type="text"
placeholder="Search by token or name"
className={`mb-4 p-2 border rounded w-full max-w-sm transition-colors ${darkMode
? 'bg-gray-800 border-gray-700 text-white placeholder-gray-400 focus:ring-blue-500 focus:border-blue-500'
: 'bg-white border-gray-300 placeholder-gray-500 focus:ring-blue-500 focus:border-blue-500'
}`}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
}`}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
{filteredEntries.length === 0 ? (
<div className={`p-4 rounded ${darkMode ? 'bg-gray-800' : 'bg-gray-50'}`}>
No entries found.
</div>
) : (
<>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead className={darkMode ? "bg-gray-800" : "bg-gray-100"}>
<tr>
<th className={`p-3 text-left ${darkMode ? 'text-gray-200' : 'text-gray-700'}`}>Token</th>
<th className={`p-3 text-left ${darkMode ? 'text-gray-200' : 'text-gray-700'}`}>Name</th>
<th className={`p-3 text-left ${darkMode ? 'text-gray-200' : 'text-gray-700'}`}>Status</th>
<th className={`p-3 text-left ${darkMode ? 'text-gray-200' : 'text-gray-700'}`}>Actions</th>
</tr>
</thead>
<tbody>
{currentEntries.map((entry) => (
<tr
key={entry.$id}
className={`${darkMode ? 'bg-gray-900 border-gray-700 hover:bg-gray-800' : 'bg-white border-gray-200 hover:bg-gray-50'}`}
>
<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 font-semibold ${
entry.status === "done"
? darkMode
? "bg-green-900 text-green-100"
{filteredEntries.length === 0 ? (
<div className={`p-4 rounded ${darkMode ? 'bg-gray-800' : 'bg-gray-50'}`}>
No entries found.
</div>
) : (
<>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead className={darkMode ? "bg-gray-800" : "bg-gray-100"}>
<tr>
<th className={`p-3 text-left ${darkMode ? 'text-gray-200' : 'text-gray-700'}`}>Token</th>
<th className={`p-3 text-left ${darkMode ? 'text-gray-200' : 'text-gray-700'}`}>Name</th>
<th className={`p-3 text-left ${darkMode ? 'text-gray-200' : 'text-gray-700'}`}>Status</th>
<th className={`p-3 text-left ${darkMode ? 'text-gray-200' : 'text-gray-700'}`}>Actions</th>
</tr>
</thead>
<tbody>
{currentEntries.map((entry) => (
<tr
key={entry.$id}
className={`${darkMode ? 'bg-gray-900 border-gray-700 hover:bg-gray-800' : 'bg-white border-gray-200 hover:bg-gray-50'}`}
>
<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 font-semibold ${entry.status === "done"
? darkMode
? "bg-green-900 text-green-100"
: "bg-green-100 text-green-800"
: entry.status === "booked"
? darkMode
? "bg-yellow-900 text-yellow-100"
? darkMode
? "bg-yellow-900 text-yellow-100"
: "bg-yellow-100 text-yellow-800"
: darkMode
? "bg-red-900 text-red-100"
: darkMode
? "bg-red-900 text-red-100"
: "bg-red-100 text-red-800"
}`}
>
{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 rounded-full px-2 py-1 text-xs transition-colors ${
darkMode
}`}
>
{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 rounded-full px-2 py-1 text-xs transition-colors ${darkMode
? 'border-green-400 text-green-400 hover:bg-green-900'
: 'border-green-600 text-green-600 hover:bg-green-50'
}`}
>
Done
</button>
<button
onClick={() => updateStatus(entry.$id, "missed")}
className={`border rounded-full px-2 py-1 text-xs transition-colors ${
darkMode
}`}
>
Done
</button>
<button
onClick={() => updateStatus(entry.$id, "missed")}
className={`border rounded-full px-2 py-1 text-xs transition-colors ${darkMode
? 'border-red-400 text-red-400 hover:bg-red-900'
: 'border-red-600 text-red-600 hover:bg-red-50'
}`}
>
Missed
</button>
</>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
}`}
>
Missed
</button>
</>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
<div className={`flex justify-between items-center mt-4 p-2 rounded ${
darkMode ? 'bg-gray-800' : 'bg-gray-100'
}`}>
<button
disabled={currentPage === 1}
onClick={() => setCurrentPage((prev) => prev - 1)}
className={`px-3 py-1 border rounded disabled:opacity-50 transition-colors ${
darkMode
? 'border-gray-600 hover:bg-gray-700 disabled:hover:bg-transparent'
<div className={`flex justify-between items-center mt-4 p-2 rounded ${darkMode ? 'bg-gray-800' : 'bg-gray-100'
}`}>
<button
disabled={currentPage === 1}
onClick={() => setCurrentPage((prev) => prev - 1)}
className={`px-3 py-1 border rounded disabled:opacity-50 transition-colors ${darkMode
? 'border-gray-600 hover:bg-gray-700 disabled:hover:bg-transparent'
: 'border-gray-300 hover:bg-gray-200 disabled:hover:bg-transparent'
}`}
>
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 transition-colors ${
darkMode
? 'border-gray-600 hover:bg-gray-700 disabled:hover:bg-transparent'
}`}
>
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 transition-colors ${darkMode
? 'border-gray-600 hover:bg-gray-700 disabled:hover:bg-transparent'
: 'border-gray-300 hover:bg-gray-200 disabled:hover:bg-transparent'
}`}
>
Next
</button>
</div>
</>
)}
</div>
);
}`}
>
Next
</button>
</div>
</>
)}
</div>
);
}

View File

@ -1,92 +0,0 @@
'use client';
export default function SuccessMessage() {
return (
<>
{/* First Message with Link */}
<div
className="rounded-xl border p-4"
style={{
borderColor: '#f04438',
backgroundColor: '#fef3f2',
}}
>
<div className="flex items-start gap-3">
<div className="-mt-0.5" style={{ color: '#3b82f6' }}>
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.6501 11.9996C3.6501 7.38803 7.38852 3.64961 12.0001 3.64961C16.6117 3.64961 20.3501 7.38803 20.3501 11.9996C20.3501 16.6112 16.6117 20.3496 12.0001 20.3496C7.38852 20.3496 3.6501 16.6112 3.6501 11.9996ZM12.0001 1.84961C6.39441 1.84961 1.8501 6.39392 1.8501 11.9996C1.8501 17.6053 6.39441 22.1496 12.0001 22.1496C17.6058 22.1496 22.1501 17.6053 22.1501 11.9996C22.1501 6.39392 17.6058 1.84961 12.0001 1.84961ZM10.9992 7.52468C10.9992 8.07697 11.4469 8.52468 11.9992 8.52468H12.0002C12.5525 8.52468 13.0002 8.07697 13.0002 7.52468C13.0002 6.9724 12.5525 6.52468 12.0002 6.52468H11.9992C11.4469 6.52468 10.9992 6.9724 10.9992 7.52468ZM12.0002 17.371C11.586 17.371 11.2502 17.0352 11.2502 16.621V10.9445C11.2502 10.5303 11.586 10.1945 12.0002 10.1945C12.4144 10.1945 12.7502 10.5303 12.7502 10.9445V16.621C12.7502 17.0352 12.4144 17.371 12.0002 17.371Z"
fill="currentColor"
/>
</svg>
</div>
<div>
<h4 className="mb-1 text-sm font-semibold text-gray-800 dark:text-white/90">
Success Message
</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
You can insert a description for the message here. The text relates
to the action that has been performed.
</p>
<a
href="#"
className="mt-3 inline-block text-sm font-medium underline"
style={{ color: '#f87171' }} // optional: changed to a more visible red
>
Learn more
</a>
</div>
</div>
</div>
{/* Second Message without Link */}
<div
className="rounded-xl border p-4 mt-4"
style={{
borderColor: '#f04438',
backgroundColor: '#fef3f2',
}}
>
<div className="flex items-start gap-3">
<div className="-mt-0.5" style={{ color: '#3b82f6' }}>
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.6501 11.9996C3.6501 7.38803 7.38852 3.64961 12.0001 3.64961C16.6117 3.64961 20.3501 7.38803 20.3501 11.9996C20.3501 16.6112 16.6117 20.3496 12.0001 20.3496C7.38852 20.3496 3.6501 16.6112 3.6501 11.9996ZM12.0001 1.84961C6.39441 1.84961 1.8501 6.39392 1.8501 11.9996C1.8501 17.6053 6.39441 22.1496 12.0001 22.1496C17.6058 22.1496 22.1501 17.6053 22.1501 11.9996C22.1501 6.39392 17.6058 1.84961 12.0001 1.84961ZM10.9992 7.52468C10.9992 8.07697 11.4469 8.52468 11.9992 8.52468H12.0002C12.5525 8.52468 13.0002 8.07697 13.0002 7.52468C13.0002 6.9724 12.5525 6.52468 12.0002 6.52468H11.9992C11.4469 6.52468 10.9992 6.9724 10.9992 7.52468ZM12.0002 17.371C11.586 17.371 11.2502 17.0352 11.2502 16.621V10.9445C11.2502 10.5303 11.586 10.1945 12.0002 10.1945C12.4144 10.1945 12.7502 10.5303 12.7502 10.9445V16.621C12.7502 17.0352 12.4144 17.371 12.0002 17.371Z"
fill="currentColor"
/>
</svg>
</div>
<div>
<h4 className="mb-1 text-sm font-semibold text-gray-800 dark:text-white/90">
Success Message
</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
You can insert a description for the message here. The text relates
to the action that has been performed.
</p>
</div>
</div>
</div>
</>
);
}

View File

@ -1,84 +0,0 @@
import React from 'react';
const AlertInfo = () => {
return (
<div className="space-y-4 p-4">
{/* First Alert with Learn More link */}
<div className="rounded-xl border border-[#36bffa] bg-[#f0f9ff] p-4 dark:border-[#36bffa]/30 dark:bg-[#36bffa]/15">
<div className="flex items-start gap-3">
<div className="-mt-0.5 text-[#36bffa]">
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.6501 11.9996C3.6501 7.38803 7.38852 3.64961 12.0001 3.64961C16.6117 3.64961 20.3501 7.38803 20.3501 11.9996C20.3501 16.6112 16.6117 20.3496 12.0001 20.3496C7.38852 20.3496 3.6501 16.6112 3.6501 11.9996ZM12.0001 1.84961C6.39441 1.84961 1.8501 6.39392 1.8501 11.9996C1.8501 17.6053 6.39441 22.1496 12.0001 22.1496C17.6058 22.1496 22.1501 17.6053 22.1501 11.9996C22.1501 6.39392 17.6058 1.84961 12.0001 1.84961ZM10.9992 7.52468C10.9992 8.07697 11.4469 8.52468 11.9992 8.52468H12.0002C12.5525 8.52468 13.0002 8.07697 13.0002 7.52468C13.0002 6.9724 12.5525 6.52468 12.0002 6.52468H11.9992C11.4469 6.52468 10.9992 6.9724 10.9992 7.52468ZM12.0002 17.371C11.586 17.371 11.2502 17.0352 11.2502 16.621V10.9445C11.2502 10.5303 11.586 10.1945 12.0002 10.1945C12.4144 10.1945 12.7502 10.5303 12.7502 10.9445V16.621C12.7502 17.0352 12.4144 17.371 12.0002 17.371Z"
fill="currentColor"
/>
</svg>
</div>
<div>
<h4 className="mb-1 text-sm font-semibold text-[#1d2939] dark:text-white/90">
Success Message
</h4>
<p className="text-sm text-[#667085] dark:text-[#98a2b3]">
You can insert a description for the message here.The text relates to
the action that has been performed.
</p>
<a
href="#"
className="mt-3 inline-block text-sm font-medium text-[#667085] underline dark:text-[#98a2b3]"
>
Learn more
</a>
</div>
</div>
</div>
{/* Second Alert without Learn More link */}
<div className="rounded-xl border border-[#36bffa] bg-[#f0f9ff] p-4 dark:border-[#36bffa]/30 dark:bg-[#36bffa]/15">
<div className="flex items-start gap-3">
<div className="-mt-0.5 text-[#36bffa]">
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.6501 11.9996C3.6501 7.38803 7.38852 3.64961 12.0001 3.64961C16.6117 3.64961 20.3501 7.38803 20.3501 11.9996C20.3501 16.6112 16.6117 20.3496 12.0001 20.3496C7.38852 20.3496 3.6501 16.6112 3.6501 11.9996ZM12.0001 1.84961C6.39441 1.84961 1.8501 6.39392 1.8501 11.9996C1.8501 17.6053 6.39441 22.1496 12.0001 22.1496C17.6058 22.1496 22.1501 17.6053 22.1501 11.9996C22.1501 6.39392 17.6058 1.84961 12.0001 1.84961ZM10.9992 7.52468C10.9992 8.07697 11.4469 8.52468 11.9992 8.52468H12.0002C12.5525 8.52468 13.0002 8.07697 13.0002 7.52468C13.0002 6.9724 12.5525 6.52468 12.0002 6.52468H11.9992C11.4469 6.52468 10.9992 6.9724 10.9992 7.52468ZM12.0002 17.371C11.586 17.371 11.2502 17.0352 11.2502 16.621V10.9445C11.2502 10.5303 11.586 10.1945 12.0002 10.1945C12.4144 10.1945 12.7502 10.5303 12.7502 10.9445V16.621C12.7502 17.0352 12.4144 17.371 12.0002 17.371Z"
fill="currentColor"
/>
</svg>
</div>
<div>
<h4 className="mb-1 text-sm font-semibold text-[#1d2939] dark:text-white/90">
Success Message
</h4>
<p className="text-sm text-[#667085] dark:text-[#98a2b3]">
You can insert a description for the message here.The text relates to
the action that has been performed.
</p>
</div>
</div>
</div>
</div>
);
};
export default AlertInfo;

View File

@ -1,78 +0,0 @@
// app/alert-success/page.js
export default function AlertSuccessPage() {
return (
<div className="space-y-6 p-6">
{/* Alert 1 */}
<div className="rounded-xl border border-[#12B76A] bg-[#ECFDF3] p-4 dark:border-[#12B76A]/30 dark:bg-[#12B76A]/15">
<div className="flex items-start gap-3">
<div className="-mt-0.5 text-[#12B76A]">
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.70186 12.0001C3.70186 7.41711 7.41711 3.70186 12.0001 3.70186C16.5831 3.70186 20.2984 7.41711 20.2984 12.0001C20.2984 16.5831 16.5831 20.2984 12.0001 20.2984C7.41711 20.2984 3.70186 16.5831 3.70186 12.0001ZM12.0001 1.90186C6.423 1.90186 1.90186 6.423 1.90186 12.0001C1.90186 17.5772 6.423 22.0984 12.0001 22.0984C17.5772 22.0984 22.0984 17.5772 22.0984 12.0001C22.0984 6.423 17.5772 1.90186 12.0001 1.90186ZM15.6197 10.7395C15.9712 10.388 15.9712 9.81819 15.6197 9.46672C15.2683 9.11525 14.6984 9.11525 14.347 9.46672L11.1894 12.6243L9.6533 11.0883C9.30183 10.7368 8.73198 10.7368 8.38051 11.0883C8.02904 11.4397 8.02904 12.0096 8.38051 12.3611L10.553 14.5335C10.7217 14.7023 10.9507 14.7971 11.1894 14.7971C11.428 14.7971 11.657 14.7023 11.8257 14.5335L15.6197 10.7395Z"
fill="#12B76A"
/>
</svg>
</div>
<div>
<h4 className="mb-1 text-sm font-semibold text-[#1D2939] dark:text-[#FFFFFF]/90">
Success Message
</h4>
<p className="text-sm text-[#667085] dark:text-[#98A2B3]">
You can insert a description for the message here. The text relates to
the action that has been performed.
</p>
<a
href="#"
className="mt-3 inline-block text-sm font-medium text-[#667085] underline dark:text-[#98A2B3]"
>
Learn more
</a>
</div>
</div>
</div>
{/* Alert 2 (without link) */}
<div className="rounded-xl border border-[#12B76A] bg-[#ECFDF3] p-4 dark:border-[#12B76A]/30 dark:bg-[#12B76A]/15">
<div className="flex items-start gap-3">
<div className="-mt-0.5 text-[#12B76A]">
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.70186 12.0001C3.70186 7.41711 7.41711 3.70186 12.0001 3.70186C16.5831 3.70186 20.2984 7.41711 20.2984 12.0001C20.2984 16.5831 16.5831 20.2984 12.0001 20.2984C7.41711 20.2984 3.70186 16.5831 3.70186 12.0001ZM12.0001 1.90186C6.423 1.90186 1.90186 6.423 1.90186 12.0001C1.90186 17.5772 6.423 22.0984 12.0001 22.0984C17.5772 22.0984 22.0984 17.5772 22.0984 12.0001C22.0984 6.423 17.5772 1.90186 12.0001 1.90186ZM15.6197 10.7395C15.9712 10.388 15.9712 9.81819 15.6197 9.46672C15.2683 9.11525 14.6984 9.11525 14.347 9.46672L11.1894 12.6243L9.6533 11.0883C9.30183 10.7368 8.73198 10.7368 8.38051 11.0883C8.02904 11.4397 8.02904 12.0096 8.38051 12.3611L10.553 14.5335C10.7217 14.7023 10.9507 14.7971 11.1894 14.7971C11.428 14.7971 11.657 14.7023 11.8257 14.5335L15.6197 10.7395Z"
fill="#12B76A"
/>
</svg>
</div>
<div>
<h4 className="mb-1 text-sm font-semibold text-[#1D2939] dark:text-[#FFFFFF]/90">
Success Message
</h4>
<p className="text-sm text-[#667085] dark:text-[#98A2B3]">
You can insert a description for the message here. The text relates to
the action that has been performed.
</p>
</div>
</div>
</div>
</div>
);
}

View File

@ -1,79 +0,0 @@
"use client";
export default function AlertWarning() {
return (
<div className="space-y-4 p-6">
{/* Alert 1 */}
<div className="rounded-xl border border-[#F79009] bg-[#FFFAEB] p-4 dark:border-[#F79009]/30 dark:bg-[#F79009]/15">
<div className="flex items-start gap-3">
<div className="-mt-0.5 text-[#F79009] dark:text-[#FDB022]">
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.6501 12.0001C3.6501 7.38852 7.38852 3.6501 12.0001 3.6501C16.6117 3.6501 20.3501 7.38852 20.3501 12.0001C20.3501 16.6117 16.6117 20.3501 12.0001 20.3501C7.38852 20.3501 3.6501 16.6117 3.6501 12.0001ZM12.0001 1.8501C6.39441 1.8501 1.8501 6.39441 1.8501 12.0001C1.8501 17.6058 6.39441 22.1501 12.0001 22.1501C17.6058 22.1501 22.1501 17.6058 22.1501 12.0001C22.1501 6.39441 17.6058 1.8501 12.0001 1.8501ZM10.9992 7.52517C10.9992 8.07746 11.4469 8.52517 11.9992 8.52517H12.0002C12.5525 8.52517 13.0002 8.07746 13.0002 7.52517C13.0002 6.97289 12.5525 6.52517 12.0002 6.52517H11.9992C11.4469 6.52517 10.9992 6.97289 10.9992 7.52517ZM12.0002 17.3715C11.586 17.3715 11.2502 17.0357 11.2502 16.6215V10.945C11.2502 10.5308 11.586 10.195 12.0002 10.195C12.4144 10.195 12.7502 10.5308 12.7502 10.945V16.6215C12.7502 17.0357 12.4144 17.3715 12.0002 17.3715Z"
fill="#F79009"
/>
</svg>
</div>
<div>
<h4 className="mb-1 text-sm font-semibold text-[#1D2939] dark:text-[#FFFFFF]/90">
Warning Message
</h4>
<p className="text-sm text-[#667085] dark:text-[#98A2B3]">
You can insert a description for the message here. The text
relates to the action that has been performed.
</p>
<a
href="#"
className="mt-3 inline-block text-sm font-medium text-[#667085] underline dark:text-[#98A2B3]"
>
Learn more
</a>
</div>
</div>
</div>
{/* Alert 2 */}
<div className="rounded-xl border border-[#F79009] bg-[#FFFAEB] p-4 dark:border-[#F79009]/30 dark:bg-[#F79009]/15">
<div className="flex items-start gap-3">
<div className="-mt-0.5 text-[#F79009] dark:text-[#FDB022]">
<svg
className="fill-current"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.6501 12.0001C3.6501 7.38852 7.38852 3.6501 12.0001 3.6501C16.6117 3.6501 20.3501 7.38852 20.3501 12.0001C20.3501 16.6117 16.6117 20.3501 12.0001 20.3501C7.38852 20.3501 3.6501 16.6117 3.6501 12.0001ZM12.0001 1.8501C6.39441 1.8501 1.8501 6.39441 1.8501 12.0001C1.8501 17.6058 6.39441 22.1501 12.0001 22.1501C17.6058 22.1501 22.1501 17.6058 22.1501 12.0001C22.1501 6.39441 17.6058 1.8501 12.0001 1.8501ZM10.9992 7.52517C10.9992 8.07746 11.4469 8.52517 11.9992 8.52517H12.0002C12.5525 8.52517 13.0002 8.07746 13.0002 7.52517C13.0002 6.97289 12.5525 6.52517 12.0002 6.52517H11.9992C11.4469 6.52517 10.9992 6.97289 10.9992 7.52517ZM12.0002 17.3715C11.586 17.3715 11.2502 17.0357 11.2502 16.6215V10.945C11.2502 10.5308 11.586 10.195 12.0002 10.195C12.4144 10.195 12.7502 10.5308 12.7502 10.945V16.6215C12.7502 17.0357 12.4144 17.3715 12.0002 17.3715Z"
fill="#F79009"
/>
</svg>
</div>
<div>
<h4 className="mb-1 text-sm font-semibold text-[#1D2939] dark:text-[#FFFFFF]/90">
Warning Message
</h4>
<p className="text-sm text-[#667085] dark:text-[#98A2B3]">
You can insert a description for the message here. The text
relates to the action that has been performed.
</p>
</div>
</div>
</div>
</div>
);
}

View File

@ -1,32 +0,0 @@
// components/partials/avatar/Avatar01.tsx
import React from 'react';
import Image from 'next/image';
const Avatar01 = () => {
const sizes = [
{ container: 'h-6 w-6', max: 'max-w-6' },
{ container: 'h-8 w-8', max: 'max-w-8' },
{ container: 'h-10 w-10', max: 'max-w-10' },
{ container: 'h-12 w-12', max: 'max-w-12' },
{ container: 'h-14 w-14', max: 'max-w-14' },
{ container: 'h-16 w-16', max: 'max-w-16' },
];
return (
<div className="flex flex-col items-center justify-center gap-5 sm:flex-row">
{sizes.map((size, index) => (
<div key={index} className={`relative ${size.container} ${size.max} rounded-full`}>
<Image
src="/images/user/user-01.jpg"
alt="user"
width={parseInt(size.container.split('-')[1]) * 4} // Convert to pixels
height={parseInt(size.container.split('-')[1]) * 4}
className="overflow-hidden rounded-full"
/>
</div>
))}
</div>
);
};
export default Avatar01;

View File

@ -1,35 +0,0 @@
// components/partials/avatar/Avatar02.tsx
import React from 'react';
import Image from 'next/image';
const Avatar02 = () => {
const sizes = [
{ container: 'h-6 w-6', indicator: 'h-1.5 w-1.5' },
{ container: 'h-8 w-8', indicator: 'h-2 w-2' },
{ container: 'h-10 w-10', indicator: 'h-2.5 w-2.5' },
{ container: 'h-12 w-12', indicator: 'h-3 w-3' },
{ container: 'h-14 w-14', indicator: 'h-3.5 w-3.5' },
{ container: 'h-16 w-16', indicator: 'h-4 w-4' },
];
return (
<div className="flex flex-col items-center justify-center gap-5 sm:flex-row">
{sizes.map((size, index) => (
<div key={index} className={`relative ${size.container} rounded-full`}>
<Image
src="/images/user/user-01.jpg"
alt="user"
width={parseInt(size.container.split('-')[1]) * 4} // Convert tailwind size to pixels
height={parseInt(size.container.split('-')[1]) * 4}
className="overflow-hidden rounded-full"
/>
<span
className={`absolute bottom-0 right-0 ${size.indicator} rounded-full border-[1.5px] border-white bg-[#12b76a] dark:border-gray-900`}
></span>
</div>
))}
</div>
);
};
export default Avatar02;

View File

@ -1,35 +0,0 @@
// components/partials/avatar/Avatar03.tsx
import React from 'react';
import Image from 'next/image';
const Avatar03 = () => {
const sizes = [
{ container: 'h-6 w-6', indicator: 'h-1.5 w-1.5' },
{ container: 'h-8 w-8', indicator: 'h-2 w-2' },
{ container: 'h-10 w-10', indicator: 'h-2.5 w-2.5' },
{ container: 'h-12 w-12', indicator: 'h-3 w-3' },
{ container: 'h-14 w-14', indicator: 'h-3.5 w-3.5' },
{ container: 'h-16 w-16', indicator: 'h-4 w-4' },
];
return (
<div className="flex flex-col items-center justify-center gap-5 sm:flex-row">
{sizes.map((size, index) => (
<div key={index} className={`relative ${size.container} rounded-full`}>
<Image
src="/images/user/user-01.jpg"
alt="user"
width={parseInt(size.container.split('-')[1]) * 4}
height={parseInt(size.container.split('-')[1]) * 4}
className="overflow-hidden rounded-full"
/>
<span
className={`absolute bottom-0 right-0 ${size.indicator} rounded-full border-[1.5px] border-white bg-[#f04438] dark:border-gray-900`}
></span>
</div>
))}
</div>
);
};
export default Avatar03;

View File

@ -1,35 +0,0 @@
// components/partials/avatar/Avatar04.tsx
import React from 'react';
import Image from 'next/image';
const Avatar04 = () => {
const sizes = [
{ container: 'h-6 w-6', indicator: 'h-1.5 w-1.5' },
{ container: 'h-8 w-8', indicator: 'h-2 w-2' },
{ container: 'h-10 w-10', indicator: 'h-2.5 w-2.5' },
{ container: 'h-12 w-12', indicator: 'h-3 w-3' },
{ container: 'h-14 w-14', indicator: 'h-3.5 w-3.5' },
{ container: 'h-16 w-16', indicator: 'h-4 w-4' },
];
return (
<div className="flex flex-col items-center justify-center gap-5 sm:flex-row">
{sizes.map((size, index) => (
<div key={index} className={`relative ${size.container} rounded-full`}>
<Image
src="/images/user/user-01.jpg"
alt="user"
width={parseInt(size.container.split('-')[1]) * 4}
height={parseInt(size.container.split('-')[1]) * 4}
className="overflow-hidden rounded-full"
/>
<span
className={`absolute bottom-0 right-0 ${size.indicator} rounded-full border-[1.5px] border-white bg-[#f79009] dark:border-gray-900`}
></span>
</div>
))}
</div>
);
};
export default Avatar04;

View File

@ -1,45 +0,0 @@
// components/partials/badge/Badge01.tsx
import React from 'react';
const Badge01 = () => {
return (
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
{/* Primary Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#ecf3ff] px-2.5 py-0.5 text-sm font-medium text-[#465fff] dark:bg-[#465fff]/15 dark:text-[#3641f5]">
Primary
</span>
{/* Success Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#ecfdf3] px-2.5 py-0.5 text-sm font-medium text-[#12b76a] dark:bg-[#12b76a]/15 dark:text-[#039855]">
Success
</span>
{/* Error Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#fef3f2] px-2.5 py-0.5 text-sm font-medium text-[#f04438] dark:bg-[#f04438]/15 dark:text-[#d92d20]">
Error
</span>
{/* Warning Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#fffaeb] px-2.5 py-0.5 text-sm font-medium text-[#f79009] dark:bg-[#f79009]/15 dark:text-[#fd853a]">
Warning
</span>
{/* Info Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#f0f9ff] px-2.5 py-0.5 text-sm font-medium text-[#0ba5ec] dark:bg-[#0ba5ec]/15 dark:text-[#0086c9]">
Info
</span>
{/* Light Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#f2f4f7] px-2.5 py-0.5 text-sm font-medium text-[#475467] dark:bg-white/5 dark:text-white/80">
Light
</span>
{/* Dark Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#667085] px-2.5 py-0.5 text-sm font-medium text-white dark:bg-white/5 dark:text-white">
Dark
</span>
</div>
);
};
export default Badge01;

View File

@ -1,45 +0,0 @@
// components/partials/badge/Badge02.tsx
import React from 'react';
const Badge02 = () => {
return (
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
{/* Primary Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#465fff] px-2.5 py-0.5 text-sm font-medium text-white">
Primary
</span>
{/* Success Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#12b76a] px-2.5 py-0.5 text-sm font-medium text-white">
Success
</span>
{/* Error Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#f04438] px-2.5 py-0.5 text-sm font-medium text-white">
Error
</span>
{/* Warning Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#f79009] px-2.5 py-0.5 text-sm font-medium text-white">
Warning
</span>
{/* Info Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#0ba5ec] px-2.5 py-0.5 text-sm font-medium text-white">
Info
</span>
{/* Light Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#98a2b3] px-2.5 py-0.5 text-sm font-medium text-white dark:bg-white/5 dark:text-white/80">
Light
</span>
{/* Dark Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#1d2939] px-2.5 py-0.5 text-sm font-medium text-white dark:bg-white/15 dark:text-white">
Dark
</span>
</div>
);
};
export default Badge02;

View File

@ -1,69 +0,0 @@
// components/partials/badge/Badge03.tsx
import React from 'react';
const PlusIcon = () => (
<svg
className="fill-current"
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.25012 3C5.25012 2.58579 5.58591 2.25 6.00012 2.25C6.41433 2.25 6.75012 2.58579 6.75012 3V5.25012L9.00034 5.25012C9.41455 5.25012 9.75034 5.58591 9.75034 6.00012C9.75034 6.41433 9.41455 6.75012 9.00034 6.75012H6.75012V9.00034C6.75012 9.41455 6.41433 9.75034 6.00012 9.75034C5.58591 9.75034 5.25012 9.41455 5.25012 9.00034L5.25012 6.75012H3C2.58579 6.75012 2.25 6.41433 2.25 6.00012C2.25 5.58591 2.58579 5.25012 3 5.25012H5.25012V3Z"
/>
</svg>
);
const Badge03 = () => {
return (
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
{/* Primary Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#ecf3ff] py-0.5 pl-2 pr-2.5 text-sm font-medium text-[#465fff] dark:bg-[#465fff]/15 dark:text-[#3641f5]">
<PlusIcon />
Primary
</span>
{/* Success Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#ecfdf3] py-0.5 pl-2 pr-2.5 text-sm font-medium text-[#12b76a] dark:bg-[#12b76a]/15 dark:text-[#039855]">
<PlusIcon />
Success
</span>
{/* Error Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#fef3f2] py-0.5 pl-2 pr-2.5 text-sm font-medium text-[#f04438] dark:bg-[#f04438]/15 dark:text-[#d92d20]">
<PlusIcon />
Error
</span>
{/* Warning Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#fffaeb] py-0.5 pl-2 pr-2.5 text-sm font-medium text-[#f79009] dark:bg-[#f79009]/15 dark:text-[#fd853a]">
<PlusIcon />
Warning
</span>
{/* Info Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#f0f9ff] py-0.5 pl-2 pr-2.5 text-sm font-medium text-[#0ba5ec] dark:bg-[#0ba5ec]/15 dark:text-[#0086c9]">
<PlusIcon />
Info
</span>
{/* Light Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#f2f4f7] py-0.5 pl-2 pr-2.5 text-sm font-medium text-[#475467] dark:bg-white/5 dark:text-white/80">
<PlusIcon />
Light
</span>
{/* Dark Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#667085] py-0.5 pl-2 pr-2.5 text-sm font-medium text-white dark:bg-white/5 dark:text-white">
<PlusIcon />
Dark
</span>
</div>
);
};
export default Badge03;

View File

@ -1,69 +0,0 @@
// components/partials/badge/Badge04.tsx
import React from 'react';
const PlusIcon = () => (
<svg
className="fill-current"
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.25012 3C5.25012 2.58579 5.58591 2.25 6.00012 2.25C6.41433 2.25 6.75012 2.58579 6.75012 3V5.25012L9.00034 5.25012C9.41455 5.25012 9.75034 5.58591 9.75034 6.00012C9.75034 6.41433 9.41455 6.75012 9.00034 6.75012H6.75012V9.00034C6.75012 9.41455 6.41433 9.75034 6.00012 9.75034C5.58591 9.75034 5.25012 9.41455 5.25012 9.00034L5.25012 6.75012H3C2.58579 6.75012 2.25 6.41433 2.25 6.00012C2.25 5.58591 2.58579 5.25012 3 5.25012H5.25012V3Z"
/>
</svg>
);
const Badge04 = () => {
return (
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
{/* Primary Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#465fff] py-0.5 pl-2 pr-2.5 text-sm font-medium text-white">
<PlusIcon />
Primary
</span>
{/* Success Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#12b76a] py-0.5 pl-2 pr-2.5 text-sm font-medium text-white">
<PlusIcon />
Success
</span>
{/* Error Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#f04438] py-0.5 pl-2 pr-2.5 text-sm font-medium text-white">
<PlusIcon />
Error
</span>
{/* Warning Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#f79009] py-0.5 pl-2 pr-2.5 text-sm font-medium text-white">
<PlusIcon />
Warning
</span>
{/* Info Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#0ba5ec] py-0.5 pl-2 pr-2.5 text-sm font-medium text-white">
<PlusIcon />
Info
</span>
{/* Light Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#98a2b3] py-0.5 pl-2 pr-2.5 text-sm font-medium text-white dark:bg-white/5 dark:text-white/80">
<PlusIcon />
Light
</span>
{/* Dark Badge */}
<span className="inline-flex items-center justify-center gap-1 rounded-full bg-[#1d2939] py-0.5 pl-2 pr-2.5 text-sm font-medium text-white dark:bg-white/15 dark:text-white">
<PlusIcon />
Dark
</span>
</div>
);
};
export default Badge04;

View File

@ -1,90 +0,0 @@
// components/partials/badge/Badge05.tsx
import React from 'react';
const PlusIcon = () => (
<svg
className="fill-current"
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.25012 3C5.25012 2.58579 5.58591 2.25 6.00012 2.25C6.41433 2.25 6.75012 2.58579 6.75012 3V5.25012L9.00034 5.25012C9.41455 5.25012 9.75034 5.58591 9.75034 6.00012C9.75034 6.41433 9.41455 6.75012 9.00034 6.75012H6.75012V9.00034C6.75012 9.41455 6.41433 9.75034 6.00012 9.75034C5.58591 9.75034 5.25012 9.41455 5.25012 9.00034L5.25012 6.75012H3C2.58579 6.75012 2.25 6.41433 2.25 6.00012C2.25 5.58591 2.58579 5.25012 3 5.25012H5.25012V3Z"
/>
</svg>
);
const Badge05 = () => {
return (
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
{/* Primary Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium"
style={{ backgroundColor: '#ecf3ff', color: '#465fff' }}
>
Primary
<PlusIcon />
</span>
{/* Success Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium"
style={{ backgroundColor: '#ecfdf3', color: '#039855' }}
>
Success
<PlusIcon />
</span>
{/* Error Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium"
style={{ backgroundColor: '#fef3f2', color: '#d92d20' }}
>
Error
<PlusIcon />
</span>
{/* Warning Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium"
style={{ backgroundColor: '#fffaeb', color: '#fd853a' }}
>
Warning
<PlusIcon />
</span>
{/* Info Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium"
style={{ backgroundColor: '#f0f9ff', color: '#0ba5ec' }}
>
Info
<PlusIcon />
</span>
{/* Light Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium"
style={{ backgroundColor: '#f2f4f7', color: '#344054' }}
>
Light
<PlusIcon />
</span>
{/* Dark Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium"
style={{ backgroundColor: '#667085', color: '#ffffff' }}
>
Dark
<PlusIcon />
</span>
</div>
);
};
export default Badge05;

View File

@ -1,95 +0,0 @@
import React from 'react';
const PlusIcon = () => (
<svg
className="fill-current"
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5.25012 3C5.25012 2.58579 5.58591 2.25 6.00012 2.25C6.41433 2.25 6.75012 2.58579 6.75012 3V5.25012L9.00034 5.25012C9.41455 5.25012 9.75034 5.58591 9.75034 6.00012C9.75034 6.41433 9.41455 6.75012 9.00034 6.75012H6.75012V9.00034C6.75012 9.41455 6.41433 9.75034 6.00012 9.75034C5.58591 9.75034 5.25012 9.41455 5.25012 9.00034L5.25012 6.75012H3C2.58579 6.75012 2.25 6.41433 2.25 6.00012C2.25 5.58591 2.58579 5.25012 3 5.25012H5.25012V3Z"
/>
</svg>
);
const Badge06 = () => {
return (
<div className="flex flex-wrap gap-4 sm:items-center sm:justify-center">
{/* Primary Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium text-white"
style={{ backgroundColor: '#3B82F6' }} // Tailwind's brand-500 equivalent
>
Primary
<PlusIcon />
</span>
{/* Success Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium text-white"
style={{ backgroundColor: '#22C55E' }} // Tailwind's success-500 equivalent
>
Success
<PlusIcon />
</span>
{/* Error Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium text-white"
style={{ backgroundColor: '#EF4444' }} // Tailwind's error-500 equivalent
>
Error
<PlusIcon />
</span>
{/* Warning Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium text-white"
style={{ backgroundColor: '#F59E0B' }} // Tailwind's warning-500 equivalent
>
Warning
<PlusIcon />
</span>
{/* Info Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium text-white"
style={{ backgroundColor: '#38BDF8' }} // Tailwind's blue-light-500 equivalent
>
Info
<PlusIcon />
</span>
{/* Light Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium text-white"
style={{
backgroundColor: '#9CA3AF', // Tailwind's gray-400
color: 'rgba(255, 255, 255, 0.8)',
}}
>
Light
<PlusIcon />
</span>
{/* Dark Badge */}
<span
className="inline-flex items-center justify-center gap-1 rounded-full py-0.5 pl-2.5 pr-2 text-sm font-medium text-white"
style={{
backgroundColor: '#1F2937', // Tailwind's gray-800
color: '#ffffff',
}}
>
Dark
<PlusIcon />
</span>
</div>
);
};
export default Badge06;

View File

@ -18,7 +18,7 @@ export default function Header({
return (
<div className={`flex grow flex-col items-center ${darkMode ? 'bg-gray-500' : 'bg-white'} justify-between lg:flex-row lg:px-6 w-full`}> <div className="hidden lg:flex lg:justify-center lg:items-center lg:w-full lg:px-6 lg:py-3 xl:flex xl:justify-center xl:items-center xl:w-full xl:px-6 2xl:flex 2xl:justify-center 2xl:items-center 2xl:w-full 2xl:px-6">
<div className={`flex grow flex-col items-center ${darkMode ? 'bg-gray-900' : 'bg-white'} justify-between lg:flex-row lg:px-6 w-full`}> <div className="hidden lg:flex lg:justify-center lg:items-center lg:w-full lg:px-6 lg:py-3 xl:flex xl:justify-center xl:items-center xl:w-full xl:px-6 2xl:flex 2xl:justify-center 2xl:items-center 2xl:w-full 2xl:px-6">
<div className={`flex flex-col gap-3 p-4 rounded-lg ${darkMode ? 'bg-gray-800 text-gray-200' : 'bg-gray-50 text-gray-600'}`}>
<div className="grid grid-cols-4 gap-4">
{/* ----------Total Tokens Card---------------- */}

View File

@ -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 (
<div className="flex items-center justify-center min-h-screen bg-white dark:bg-gray-900">
<div className="text-center">
<div className={`animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mx-auto ${
darkMode === true ? 'border-gray-100' : 'border-gray-900'
}`}></div>
<p className={`mt-4 text-lg font-semibold ${
darkMode === true ? 'text-gray-100' : 'text-gray-900'
}`}>
<div
className={`animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mx-auto ${
darkMode === true ? "border-gray-100" : "border-gray-900"
}`}
></div>
<p
className={`mt-4 text-lg font-semibold ${
darkMode === true ? "text-gray-100" : "text-gray-900"
}`}
>
Loading...
</p>
</div>
@ -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 (
<main className={`min-h-screen transition-colors duration-300 ${
darkMode ? 'dark bg-gray-900' : 'bg-white'
}`}>
<div className="p-6">
<EntriesTable />
<main
className={`min-h-screen transition-colors duration-300 ${
darkMode ? "dark bg-gray-900" : "bg-white"
}`}
>
<div className="p-1">
{canViewEntries ? (
<EntriesTable />
) : (
<div className="text-center p-8">
<h2 className={`text-2xl font-semibold ${darkMode ? "text-white" : "text-gray-800"}`}>
Welcome to your Dashboard
</h2>
<p className={`mt-4 ${darkMode ? "text-gray-300" : "text-gray-600"}`}>
You don't have permission to view entries.
</p>
</div>
)}
</div>
</main>
);

View File

@ -6,6 +6,6 @@
// lib/config.js
export const DATABASE_ID = "67e1452b00016444b37f";
export const COLLECTION_ID = "67fe4029000f7e0a7b92";
export const COLLECTION_ID = "681c367b0016f9ba0e8e";
export const SETTINGS_COLLECTION_ID = "settings";
export const AVG_CONSULTATION_KEY = "avg_consultation";

View File

@ -84,13 +84,13 @@ export default function AuthPage() {
loginData.email,
loginData.password
);
if (session) {
const user = await account.get();
if (user) {
localStorage.setItem("isLoggedIn", "true");
setIsAuthenticated(true);
router.push("/dashboard");
window.location.href = '/dashboard';
}
}
} catch (error) {
@ -167,8 +167,8 @@ export default function AuthPage() {
{isLoginForm ? "Sign In" : "Sign Up"}
</h1>
<p className="text-sm text-gray-500 dark:text-gray-400">
{isLoginForm
? "Enter your email and password to sign In!"
{isLoginForm
? "Enter your email and password to sign In!"
: "Enter your deatils to create an account!"}
</p>
</div>

View File

@ -82,7 +82,7 @@ const createEntries = async () => {
}
setBookings(updatedBookings);
alert(`${validBookings.length} tokens created successfully!`);
// alert(`${validBookings.length} tokens created successfully!`);
} catch (error) {
console.error("Creation error:", error);
setError(error.message);

View File

@ -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,24 +129,33 @@ 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 (
<div className={`flex h-screen overflow-hidden ${darkMode ? 'dark bg-gray-900' : 'bg-white'}`}>
{/* Content Area */}
<div
className={`flex h-screen overflow-hidden ${
darkMode ? "dark bg-gray-900" : "bg-white"
}`}
>
<div className="relative flex flex-1 flex-col overflow-x-hidden overflow-y-auto">
{/* Sticky Header */}
<header className="sticky top-0 z-50 bg-white shadow-sm dark:bg-gray-800">
<div className="flex items-center justify-between p-4">
<Header />
<div className="flex items-center justify-between">
{/* Pass the same props to Header as in EntriesTable */}
<Header
currentToken={currentToken}
previousToken={previousToken}
nextToken={nextToken}
missedTokens={missedTokens}
entries={entries}
/>
</div>
</header>
{/* Main Content */}
<main className="flex-1 overflow-y-auto">
<main className="flex-1 overflow-y-auto scrollbar-hide">
<div className="mx-auto max-w-[--breakpoint-2xl] p-4 md:p-6 pt-20">
{error && (
<div className="mb-4 p-4 bg-red-100 text-red-700 rounded-md">
@ -73,47 +164,72 @@ export default function MultiBooking() {
)}
<div className="mb-6">
<h2 className={`text-2xl mb-2 ${darkMode ? 'text-white' : 'text-black'}`}>
<h2
className={`text-2xl mb-2 ${
darkMode ? "text-white" : "text-black"
}`}
>
Staff Multi-Booking
</h2>
<div className="flex items-center">
<label className={`mr-2 ${darkMode ? 'text-gray-300' : 'text-gray-700'}`}>
<label
className={`mr-2 ${
darkMode ? "text-gray-300" : "text-gray-700"
}`}
>
Date:
</label>
<input
type="date"
value={appointmentDate}
onChange={(e) => setAppointmentDate(e.target.value)}
className={`p-1 border rounded ${darkMode ? 'bg-gray-800 text-white border-gray-700' : 'bg-white'}`}
className={`p-1 border rounded ${
darkMode
? "bg-gray-800 text-white border-gray-700"
: "bg-white"
}`}
/>
</div>
</div>
<form onSubmit={handleSubmit} className="max-w-2xl mx-auto my-8">
<div className="space-y-4 mb-6">
{patients.map((patient) => (
<div key={patient.id} className="flex items-center gap-3">
<span className={`w-6 text-right ${darkMode ? 'text-gray-300' : 'text-gray-700'}`}>
<span
className={`w-6 text-right ${
darkMode ? "text-gray-300" : "text-gray-700"
}`}
>
{patient.id}.
</span>
<input
type="text"
value={patient.name}
onChange={(e) => 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 && (
<button
type="button"
onClick={() => setPatients(patients.filter(p => p.id !== patient.id))}
onClick={() =>
setPatients(
patients.filter((p) => p.id !== patient.id)
)
}
className={`p-2 rounded-full ${
darkMode ? 'text-red-400 hover:bg-gray-700' : 'text-red-500 hover:bg-gray-100'
darkMode
? "text-red-400 hover:bg-gray-700"
: "text-red-500 hover:bg-gray-100"
}`}
title="Remove"
>
</button>
@ -122,20 +238,27 @@ export default function MultiBooking() {
))}
</div>
<div className="flex flex-wrap gap-3 mb-6">
<div className="flex flex-wrap gap-3 mb-6 items-center">
<button
type="button"
onClick={addMorePatients}
disabled={patients.length >= 20}
className={`px-4 py-2 rounded-lg text-sm font-medium ${
darkMode ?
'bg-gray-700 text-white hover:bg-gray-600' :
'bg-gray-200 text-gray-700 hover:bg-gray-300'
darkMode
? "bg-gray-700 text-white hover:bg-gray-600"
: "bg-gray-200 text-gray-700 hover:bg-gray-300"
} ${
patients.length >= 20 ? "opacity-50 cursor-not-allowed" : ""
}`}
>
+ Add More Patients
</button>
<div className="text-sm text-gray-500 dark:text-gray-400 mt-1">
{patients.length} patients entered
<div
className={`text-sm mt-1 ${
darkMode ? "text-gray-400" : "text-gray-600"
}`}
>
{patients.length} / 20 patients entered
</div>
</div>
@ -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"}
</button>
<button
type="button"
onClick={() => router.push('/entries')}
onClick={() => router.push("/entries")}
className={`text-center rounded-lg px-5 py-3.5 text-sm font-medium shadow-theme-xs ring-1 ring-inset transition w-full ${
darkMode ?
'bg-gray-800 text-gray-300 ring-gray-700 hover:bg-gray-700' :
'bg-white text-gray-700 ring-gray-300 hover:bg-gray-50'
darkMode
? "bg-gray-800 text-gray-300 ring-gray-700 hover:bg-gray-700"
: "bg-white text-gray-700 ring-gray-300 hover:bg-gray-50"
}`}
>
View All Entries
</button>
</div>
</form>
<div className={`text-center mt-8 text-sm ${
darkMode ? 'text-gray-400' : 'text-gray-600'
}`}>
<p>Staff can book multiple tokens at once. All tokens will be assigned for the same date.</p>
<p className="mt-1">Minimum 1 patient required. Maximum 20 patients per batch.</p>
<div
className={`text-center mt-8 text-sm ${
darkMode ? "text-gray-400" : "text-gray-600"
}`}
>
<p>
Staff can book multiple tokens at once. All tokens will be
assigned for the same date.
</p>
<p className="mt-1">
Minimum 1 patient required. Maximum 20 patients per batch.
</p>
</div>
</div>
</main>
</div>
</div>
);
}
}

View File

@ -17,16 +17,24 @@ export default function ResetPasswordPage() {
const { darkMode, toggleDarkMode } = useTheme();
const [email, setEmail] = useState("");
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState({ text: "", type: "" }); // type can be "success" or "error"
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setMessage({ text: "", type: "" });
try {
await account.createRecovery(email, "http://localhost:3000/reset-password");
alert("Password reset link sent to your email!");
setMessage({
text: "Password reset link sent to your email!",
type: "success"
});
} catch (error) {
console.error("Error:", error);
alert(`Failed to send reset link: ${error.message}`);
setMessage({
text: `Failed to send reset link: ${error.message}`,
type: "error"
});
} finally {
setLoading(false);
}
@ -53,6 +61,15 @@ export default function ResetPasswordPage() {
<p className="text-sm text-gray-500 dark:text-gray-400">
Enter your email address linked to your account, and we&apos;ll send you a link to reset your password.
</p>
{message.text && (
<div className={`mt-4 p-3 rounded-md ${
message.type === "success"
? "bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-200"
: "bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-200"
}`}>
{message.text}
</div>
)}
<form onSubmit={handleSubmit}>
<div className="space-y-5">
<div>
@ -85,4 +102,4 @@ export default function ResetPasswordPage() {
</div>
</div>
);
}
}

View File

@ -87,7 +87,7 @@ export default function SignInPage() {
{/* Left Side - Form */}
<div className="w-full flex flex-col justify-center p-6 sm:p-12 lg:p-16">
<div className="w-full max-w-md mx-auto">
<Link
{/* <Link
href="/dashboard"
className="inline-flex items-center text-sm text-gray-500 transition-colors hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 mb-10"
>
@ -108,7 +108,7 @@ export default function SignInPage() {
/>
</svg>
Back to dashboard
</Link>
</Link> */}
<div className="mb-8">
<h1 className="mb-2 text-2xl font-bold text-gray-800 dark:text-white/90 sm:text-3xl">

View File

@ -86,7 +86,7 @@ export default function SignUpPage() {
{/* Form */}
<div className="flex flex-col flex-1 w-full">
<div className="w-full max-w-md pt-5 mx-auto sm:py-10">
<Link
{/* <Link
href="/dashboard"
className="inline-flex items-center text-sm text-gray-500 transition-colors hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300"
>
@ -107,7 +107,7 @@ export default function SignUpPage() {
/>
</svg>
Back to dashboard
</Link>
</Link> */}
</div>
<div className="flex flex-col justify-center flex-1 w-full max-w-md mx-auto">
<div className="mb-5 sm:mb-8">

View File

@ -1,109 +0,0 @@
'use client';
import { useState, useEffect } from 'react';
import Head from 'next/head';
import Preloader from "../../components/partials/preloaders";
// import Sidebar from './partials/sidebar';
import Overlay from "../../components/partials/overlay";
import Header from "../../components/partials/header";
import Breadcrumb from "../../components/partials/breadcrumb";
import AlertSuccess from '../../components/partials/alert/alert-success';
import AlertWarning from "../../components/partials/alert/alert-warning";
import AlertError from '../../components/partials/alert/alert-error';
import AlertInfo from '../../components/partials/alert/alert-info';
export default function AlertsPage() {
const [darkMode, setDarkMode] = useState(false);
const [loaded, setLoaded] = useState(true);
useEffect(() => {
// Initialize dark mode from localStorage
const savedDarkMode = JSON.parse(localStorage.getItem('darkMode') || 'false');
setDarkMode(savedDarkMode);
}, []);
useEffect(() => {
// Save dark mode preference to localStorage
localStorage.setItem('darkMode', JSON.stringify(darkMode));
}, [darkMode]);
if (!loaded) {
return <Preloader />;
}
return (
<div className={`${darkMode ? 'dark bg-[#101828]' : ''}`}>
<div className="flex h-screen overflow-hidden">
{/* <Sidebar /> */}
<div className="relative flex flex-1 flex-col overflow-y-auto overflow-x-hidden">
<Overlay />
<div className='flex bg-white dark:bg-gray-800 shadow-sm sticky top-0 z-50 w-full'>
<Header />
</div>
<main>
<div className="mx-auto max-w-[--breakpoint-2xl] p-4 md:p-6">
<Breadcrumb pageName="Alerts" />
<div className="space-y-5 sm:space-y-6">
<div className="rounded-2xl border border-[#E4E7EC] bg-white dark:border-[#1A2231] dark:bg-white/5">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-[#1D2939] dark:text-white/90">
Success Alert
</h3>
</div>
<div className="border-t border-[#F2F4F7] p-4 dark:border-[#1A2231] sm:p-6">
<div className="space-y-6">
<AlertSuccess />
</div>
</div>
</div>
<div className="rounded-2xl border border-[#E4E7EC] bg-white dark:border-[#1A2231] dark:bg-white/5">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-[#1D2939] dark:text-white/90">
Warning Alert
</h3>
</div>
<div className="border-t border-[#F2F4F7] p-4 dark:border-[#1A2231] sm:p-6">
<div className="space-y-6">
<AlertWarning />
</div>
</div>
</div>
<div className="rounded-2xl border border-[#E4E7EC] bg-white dark:border-[#1A2231] dark:bg-white/5">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-[#1D2939] dark:text-white/90">
Error Alert
</h3>
</div>
<div className="border-t border-[#F2F4F7] p-4 dark:border-[#1A2231] sm:p-6">
<div className="space-y-6">
<AlertError />
</div>
</div>
</div>
<div className="rounded-2xl border border-[#E4E7EC] bg-white dark:border-[#1A2231] dark:bg-white/5">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-[#1D2939] dark:text-white/90">
Info Alert
</h3>
</div>
<div className="border-t border-[#F2F4F7] p-4 dark:border-[#1A2231] sm:p-6">
<div className="space-y-6">
<AlertInfo />
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</div>
);
};

View File

@ -1,137 +0,0 @@
// app/avatars/page.tsx
'use client'
import { useState, useEffect } from 'react';
import Head from 'next/head';
import Preloader from "../../components/partials/preloaders";
// import Sidebar from '@/components/partials/Sidebar';
import Overlay from "../../components/partials/overlay";
import Header from "../../components/partials/header";
import Breadcrumb from "../../components/partials/breadcrumb";
import Avatar01 from "../../components/partials/avatar/avatar01";
import Avatar02 from"../../components/partials/avatar/avatar02";
import Avatar03 from "../../components/partials/avatar/avatar03";
import Avatar04 from "../../components/partials/avatar/avatar04";
export default function AvatarsPage() {
const [loaded, setLoaded] = useState(false);
const [darkMode, setDarkMode] = useState(false);
const [stickyMenu, setStickyMenu] = useState(false);
const [sidebarToggle, setSidebarToggle] = useState(false);
const [scrollTop, setScrollTop] = useState(false);
useEffect(() => {
const savedDarkMode = JSON.parse(localStorage.getItem('darkMode') || 'false');
setDarkMode(savedDarkMode);
const timer = setTimeout(() => {
setLoaded(true);
}, 500);
return () => clearTimeout(timer);
}, []);
useEffect(() => {
localStorage.setItem('darkMode', JSON.stringify(darkMode));
}, [darkMode]);
const pageName = 'Avatars';
return (
<>
<div className={`${darkMode ? 'dark bg-gray-900' : ''}`}>
{/* Preloader */}
{!loaded && <Preloader />}
{/* Page Wrapper */}
<div className="flex h-screen overflow-hidden">
{/* Sidebar */}
{/* <Sidebar
activePage="avatars"
darkMode={darkMode}
sidebarToggle={sidebarToggle}
setSidebarToggle={setSidebarToggle}
/> */}
{/* Content Area */}
<div className="relative flex flex-col flex-1 overflow-x-hidden overflow-y-auto">
{/* Small Device Overlay */}
<Overlay
sidebarToggle={sidebarToggle}
setSidebarToggle={setSidebarToggle}
/>
{/* Header */}
<Header
darkMode={darkMode}
setDarkMode={setDarkMode}
stickyMenu={stickyMenu}
setStickyMenu={setStickyMenu}
sidebarToggle={sidebarToggle}
setSidebarToggle={setSidebarToggle}
/>
{/* Main Content */}
<main>
<div className="p-4 mx-auto max-w-[--breakpoint-2xl] md:p-6">
{/* Breadcrumb */}
<Breadcrumb pageName={pageName} />
<div className="space-y-5 sm:space-y-6">
{/* Default Avatar */}
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
Default Avatar
</h3>
</div>
<div className="p-8 border-t border-gray-100 dark:border-gray-800">
<Avatar01 />
</div>
</div>
{/* Avatar with online indicator */}
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
Avatar with online indicator
</h3>
</div>
<div className="p-8 border-t border-gray-100 dark:border-gray-800">
<Avatar02 />
</div>
</div>
{/* Avatar with Offline indicator */}
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
Avatar with Offline indicator
</h3>
</div>
<div className="p-8 border-t border-gray-100 dark:border-gray-800">
<Avatar03 />
</div>
</div>
{/* Avatar with busy indicator */}
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
Avatar with busy indicator
</h3>
</div>
<div className="p-8 border-t border-gray-100 dark:border-gray-800">
<Avatar04 />
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</div>
</>
);
}

View File

@ -1,161 +0,0 @@
// app/badge/page.tsx
'use client'
import { useState, useEffect } from 'react';
import Head from 'next/head';
import Preloader from "../../components/partials/preloaders";
// import Sidebar from '@/components/partials/Sidebar';
import Overlay from "../../components/partials/overlay";
import Header from "../../components/partials/header";
import Breadcrumb from "../../components/partials/breadcrumb";
import Badge01 from "../../components/partials/badge/Badge01";
import Badge02 from "../../components/partials/badge/Badge02";
import Badge03 from "../../components/partials/badge/Badge03";
import Badge04 from "../../components/partials/badge/Badge04";
import Badge05 from "../../components/partials/badge/Badge05";
import Badge06 from "../../components/partials/badge/Badge06";
export default function BadgePage() {
const [loaded, setLoaded] = useState(false);
const [darkMode, setDarkMode] = useState(false);
const [stickyMenu, setStickyMenu] = useState(false);
const [sidebarToggle, setSidebarToggle] = useState(false);
const [scrollTop, setScrollTop] = useState(false);
useEffect(() => {
// Load dark mode preference from localStorage
const savedDarkMode = JSON.parse(localStorage.getItem('darkMode') || 'false');
setDarkMode(savedDarkMode);
// Simulate loading
const timer = setTimeout(() => {
setLoaded(true);
}, 500);
return () => clearTimeout(timer);
}, []);
useEffect(() => {
// Save dark mode preference to localStorage
localStorage.setItem('darkMode', JSON.stringify(darkMode));
}, [darkMode]);
const pageName = 'Badge';
return (
<>
<div className={`${darkMode ? 'dark bg-gray-900' : ''}`}>
{/* Preloader */}
{!loaded && <Preloader />}
{/* Page Wrapper */}
<div className="flex h-screen overflow-hidden">
{/* Sidebar */}
{/* <Sidebar
activePage="badge"
darkMode={darkMode}
sidebarToggle={sidebarToggle}
setSidebarToggle={setSidebarToggle}
/> */}
{/* Content Area */}
<div className="relative flex flex-1 flex-col overflow-y-auto overflow-x-hidden">
{/* Small Device Overlay */}
<Overlay
sidebarToggle={sidebarToggle}
setSidebarToggle={setSidebarToggle}
/>
{/* Header */}
<div darkMode={darkMode} setDarkMode={setDarkMode} className='flex bg-white dark:bg-gray-800 shadow-sm sticky top-0 z-50 w-full'>
<Header />
</div>
{/* Main Content */}
<main>
<div className="mx-auto max-w-[--breakpoint-2xl] p-4 md:p-6">
{/* Breadcrumb */}
<Breadcrumb pageName={pageName} />
<div className="space-y-5 sm:space-y-6">
{/* With Light Background */}
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
With Light Background
</h3>
</div>
<div className="border-t border-gray-100 p-6 dark:border-gray-800 xl:p-10">
<Badge01 />
</div>
</div>
{/* With Solid Background */}
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
With Solid Background
</h3>
</div>
<div className="border-t border-gray-100 p-6 dark:border-gray-800 xl:p-10">
<Badge02 />
</div>
</div>
{/* Light Background with Left Icon */}
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
Light Background with Left Icon
</h3>
</div>
<div className="border-t border-gray-100 p-6 dark:border-gray-800 xl:p-10">
<Badge03 />
</div>
</div>
{/* Solid Background with Left Icon */}
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
Solid Background with Left Icon
</h3>
</div>
<div className="border-t border-gray-100 p-6 dark:border-gray-800 xl:p-10">
<Badge04 />
</div>
</div>
{/* Light Background with Right Icon */}
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
Light Background with Right Icon
</h3>
</div>
<div className="border-t border-gray-100 p-6 dark:border-gray-800 xl:p-10">
<Badge05 />
</div>
</div>
{/* Solid Background with Right Icon */}
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]">
<div className="px-6 py-5">
<h3 className="text-base font-medium text-gray-800 dark:text-white/90">
Solid Background with Right Icon
</h3>
</div>
<div className="border-t border-gray-100 p-6 dark:border-gray-800 xl:p-10">
<Badge06 />
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</div>
</>
);
}

View File

@ -5,6 +5,7 @@ import { DATABASE_ID, COLLECTION_ID } from "../../lib/api";
import Header from "../../components/partials/header";
import { useTheme } from "../../context/ThemeContext";
import { useAuth } from "../../context/AuthContext";
import { FaSearch } from 'react-icons/fa';
export default function EntriesTable() {
const { userRole } = useAuth();
@ -13,7 +14,7 @@ export default function EntriesTable() {
const [filteredEntries, setFilteredEntries] = useState([]);
const [searchQuery, setSearchQuery] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [avgConsultTime, setAvgConsultTime] = useState(15); // Default 15 mins
const [avgConsultTime, setAvgConsultTime] = useState(15);
const entriesPerPage = 20;
const [currentToken, setCurrentToken] = useState(null);
@ -23,23 +24,21 @@ export default function EntriesTable() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// 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;
@ -63,7 +62,9 @@ export default function EntriesTable() {
setCurrentToken(current?.tokenNumber || null);
setPreviousToken(currentIndex > 0 ? entries[currentIndex - 1]?.tokenNumber : null);
setNextToken(currentIndex < entries.length - 1 ? 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 +76,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);
@ -94,18 +92,13 @@ export default function EntriesTable() {
};
useEffect(() => {
if (userRole === "patient") return; // Don't load data if patient
if (userRole === "patient") return;
const loadData = async () => {
try {
const data = await getEntries();
setEntries(data);
setFilteredEntries(data);
updateTokenInfo(data);
// Load settings (avg consultation time)
// const settings = await getSettings();
// setAvgConsultTime(settings?.avgConsultationTime || 15);
} catch (err) {
setError(err.message);
} finally {
@ -131,17 +124,19 @@ export default function EntriesTable() {
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 (loading)
return (
<div className="text-center mt-20">
<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>;
// Check user role and show permission message if patient
if (userRole === "patient") {
return (
<div className={`min-h-screen w-full ${darkMode ? 'bg-gray-900 text-white' : 'bg-white text-black'}`}>
<div className={`min-h-screen w-full ${darkMode ? "bg-gray-900 text-white" : "bg-white text-black"}`}>
<div className="flex items-center justify-center h-screen">
<div className="text-center">
<h1 className="text-2xl font-bold mb-4">Access Denied</h1>
@ -153,119 +148,141 @@ export default function EntriesTable() {
}
return (
<div className={`min-h-screen w-full ${darkMode ? 'bg-gray-900 text-white' : 'bg-white text-black'}`}>
<div className={`min-h-screen w-full ${darkMode ? "bg-gray-900 text-white" : "bg-white text-black"}`}>
<div className="sticky top-0 z-10 bg-white shadow-md mb-4">
<Header
currentToken={currentToken}
previousToken={previousToken}
nextToken={nextToken}
missedTokens={missedTokens}
entries={entries} // Pass the entries data
entries={entries}
/>
</div>
<h1 className="text-2xl font-bold mb-4">Today&apos;s Entries</h1>
<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 for today.</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">Booked By</th> */}
<th className="p-3 text-left">Status</th>
{/* <th className="p-3 text-left">Wait Time</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={`text-xs px-2 py-1 rounded ${entry.bookedBy === 'staff' ?
'bg-purple-100 text-purple-800' :
'bg-blue-100 text-blue-800'
}`}>
{entry.bookedBy}
</span>
</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">
{entry.status === "booked" ?
`~${calculateWaitTime(entry.tokenNumber)} mins` :
'-'}
</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>
<div className="p-4">
<h1 className="text-2xl font-bold mb-4">Today&apos;s Entries</h1>
<div className={`
hidden md:flex items-center gap-[2px]
border ${darkMode ? 'border-gray-600 bg-gray-800' : 'border-gray-300 bg-white'}
p-2 rounded-lg
h-[45px] w-[300px] lg:w-[400px] ml-2 mb-6
transition-colors duration-300
focus-within:ring-2 focus-within:ring-blue-500 focus-within:ring-opacity-50
${darkMode ? 'focus-within:border-gray-500' : 'focus-within:border-blue-500'}
`}>
<div className="relative flex-1">
<FaSearch className={`
absolute left-3 top-1/2 transform -translate-y-1/2
${darkMode ? 'text-gray-400' : 'text-gray-500'}
`} />
<input
type="text"
placeholder="Search by token or name"
className={`
w-full bg-transparent border-none
pl-10 pr-10 py-2
focus:outline-none
${darkMode ? 'text-gray-200 placeholder-gray-500' : 'text-gray-800 placeholder-gray-400'}
text-sm
`}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
<div className={`
px-2 py-1
${darkMode ? 'bg-gray-700 text-gray-300' : 'bg-gray-100 text-gray-500'}
text-xs rounded-md
font-mono
`}>
K
</div>
</div>
{filteredEntries.length === 0 ? (
<div className="p-4">No entries found for today.</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>
))}
</tbody>
</table>
</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 font-semibold ${
entry.status === "done"
? "bg-green-100 text-green-800"
: entry.status === "booked"
? "bg-yellow-100 text-yellow-800"
: "bg-red-100 text-red-800"
}`}
>
{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>
{/* Pagination */}
<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"
{/* Pagination */}
<div
className={`flex justify-between items-center mt-6 ${
darkMode ? "text-white" : "text-gray-700"
}`}
>
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>
</>
)}
<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>
</>
)}
</div>
</div>
);
}
}

View File

@ -107,7 +107,7 @@ export default function SignUpPage() {
{/* Left side - Form */}
<div className="lg:w-1/2 w-full flex flex-col items-center justify-center p-4">
<div className="w-full max-w-md">
<div className="w-full max-w-md pt-5 mx-auto sm:py-10">
{/* <div className="w-full max-w-md pt-5 mx-auto sm:py-10">
<Link
href="/dashboard"
className="inline-flex items-center text-sm text-gray-500 transition-colors hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300"
@ -130,7 +130,7 @@ export default function SignUpPage() {
</svg>
Back to dashboard
</Link>
</div>
</div> */}
<div className="mb-5 sm:mb-8">
<h1 className="mb-2 font-semibold text-gray-800 text-title-sm dark:text-white/90 sm:text-title-md">