Closed techiemokhele closed 2 months ago
Funny enough when I console log from admin page, i get this:
appointments: { totalCount: 3, scheduledCount: 0, pendingCount: 3, cancelledCount: 0, documents: [ { schedule: '2024-07-08T21:37:28.704+00:00', reason: 'No reason', note: 'No reason', primaryPhysician: 'John Green', status: 'pending', userId: '668c5bb8001bf93e7cf4', cancellationReason: null, '$id': '668c5d2c0013367d0a15', '$tenant': '162849', '$createdAt': '2024-07-08T21:42:05.727+00:00', '$updatedAt': '2024-07-08T21:42:05.727+00:00', '$permissions': [], patient: [Object], '$databaseId': '66891e2500263fca754c', '$collectionId': '66891ed20007d81e2704' }, { schedule: '2024-07-08T15:22:25.328+00:00', reason: 'I am lazy', note: 'I am lazy', primaryPhysician: 'John Green', status: 'pending', userId: '668a306e0000a11011b2', cancellationReason: null, '$id': '668c086700176dc0764f', '$tenant': '162849', '$createdAt': '2024-07-08T15:40:24.787+00:00', '$updatedAt': '2024-07-08T15:40:24.787+00:00', '$permissions': [], patient: [Object], '$databaseId': '66891e2500263fca754c', '$collectionId': '66891ed20007d81e2704' }, { schedule: '2024-07-07T09:00:00.000+00:00', reason: 'Monthly checkup', note: 'Monthly checkup', primaryPhysician: 'Alyana Cruz', status: 'pending', userId: '668a306e0000a11011b2', cancellationReason: null, '$id': '668a30fd001f6995daa3', '$tenant': '162849', '$createdAt': '2024-07-07T06:09:02.303+00:00', '$updatedAt': '2024-07-07T06:09:02.303+00:00', '$permissions': [], patient: [Object], '$databaseId': '66891e2500263fca754c', '$collectionId': '66891ed20007d81e2704' } ] }
But when I try to get the data again by reloading or initially accessing the page this is what I see
@techiemokhele use optional chaining operator
{table.getRowModel().rows?.length ? (table.getRowModel().rows.map()) : ()}
Still not working, this is how my table looks:
<Table className="shad-table">
<TableHeader className=" bg-dark-200">
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="shad-table-row-header">
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="shad-table-row"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
Can you see what you get if you console log table.getRowModel().rows
?
I am getting this exception also
@techiemokhele is it a client component or not?
Check if you have added "use client"
on top or not
Yes, it does have "use client";
Here is the full file code:
"use client";
import Image from "next/image";
import { redirect } from "next/navigation";
import { useEffect } from "react";
import {
getPaginationRowModel,
ColumnDef,
flexRender,
getCoreRowModel,
useReactTable,
} from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { decryptKey } from "@/lib/utils";
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
}
export function AppointmentDataTableComponent<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
const encryptedKey =
typeof window !== "undefined"
? window.localStorage.getItem("accessKey")
: null;
useEffect(() => {
const accessKey = encryptedKey && decryptKey(encryptedKey);
if (accessKey !== process.env.NEXT_PUBLIC_ADMIN_PASSKEY!.toString()) {
redirect("/");
}
}, [encryptedKey]);
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
});
console.log(table.getRowModel()?.rows);
return (
<div className="data-table">
<Table className="shad-table">
<TableHeader className=" bg-dark-200">
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id} className="shad-table-row-header">
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
className="shad-table-row"
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<div className="table-actions">
<Button
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
className="shad-gray-btn"
>
<Image
src="/assets/icons/arrow.svg"
width={24}
height={24}
alt="arrow"
/>
</Button>
<Button
variant="outline"
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
className="shad-gray-btn"
>
<Image
src="/assets/icons/arrow.svg"
width={24}
height={24}
alt="arrow "
className="rotate-180"
/>
</Button>
</div>
</div>
);
}
Code seems perfect. What do you get if you console log data props in this component?
You get the proper data, right? @techiemokhele
I get Undefined
Okay, we're close. Check where you're calling this component, see if it's right, if data is on that main page, which is adming/page.tsx
, etc.
Not the server side. Check if the data that we're passing to this DataTable component is passed rightly on the admin page
admin.tsx file code:
import Link from "next/link";
import Image from "next/image";
import { getRecentAppointmentList } from "@/lib/actions/appointment.actions";
import StatCardComponent from "@/components/sections/StatCardComponent";
import { columns } from "@/components/table/columns";
import { AppointmentDataTableComponent } from "@/components/table/AppointmentDataTableComponent";
const AdminDashboardPage = async () => {
const appointments = await getRecentAppointmentList();
return (
<div className="mx-auto flex flex-col max-w-7xl space-y-14">
<header className="admin-header">
<Link href="/" className="cursor-pointer flex flex-row space-x-2">
<Image
priority
src="/assets/icons/logo-icon.svg"
alt="logo"
width={32}
height={162}
className="h-8 w-fit"
/>
<p className="text-white text-lg font-semibold pt-0.5">
Mokhele Medics
</p>
</Link>
<p className="text-16-semibold">Admin Dashboard</p>
</header>
<main className="admin-main">
{/* greeting section */}
<section className="w-full space-y-4">
<h1 className="header">Welcome 👋</h1>
<p className="text-dark-700">
Begin the day by managing new appointments.
</p>
</section>
{/* stat cards section */}
<section className="admin-stat">
<StatCardComponent
type="appointments"
count={appointments.scheduledCount}
label="Scheduled appointments"
icon="/assets/icons/appointments.svg"
/>
<StatCardComponent
type="pending"
count={appointments.pendingCount}
label="Pending appointments"
icon="/assets/icons/pending.svg"
/>
<StatCardComponent
type="cancelled"
count={appointments.cancelledCount}
label="Cancelled appointments"
icon="/assets/icons/cancelled.svg"
/>
</section>
<AppointmentDataTableComponent
columns={columns}
data={appointments.document}
/>
</main>
</div>
);
};
export default AdminDashboardPage;
getRecentApplicationList code:
// GET RECENT APPOINTMENTS
export const getRecentAppointmentList = async () => {
try {
const appointments = await databases.listDocuments(
DATABASE_ID!,
APPOINTMENT_COLLECTION_ID!,
[Query.orderDesc("$createdAt")]
);
const initialCounts = {
scheduledCount: 0,
pendingCount: 0,
cancelledCount: 0,
};
const counts = (appointments.documents as Appointment[]).reduce(
(acc, appointment) => {
if (appointment.status === "scheduled") {
acc.scheduledCount += 1;
} else if (appointment.status === "pending") {
acc.pendingCount += 1;
} else if (appointment.status === "cancelled") {
acc.cancelledCount += 1;
}
return acc;
},
initialCounts
);
const data = {
totalCount: appointments.total,
...counts,
documents: appointments.documents,
};
return parseStringify(data);
} catch (error) {
console.error(
"An error occurred while retrieving the recent appointments:",
error
);
}
};
columns code:
"use client";
import Image from "next/image";
import { ColumnDef } from "@tanstack/react-table";
import { Doctors } from "@/constants";
import { formatDateTime } from "@/lib/utils";
import { Appointment } from "@/types/appwrite.types";
import { StatusBadgeComponent } from "../constants/StatusBadgeComponent";
import { AppointmentModalComponent } from "../modal/AppointmentModalComponent";
export const columns: ColumnDef<Appointment>[] = [
{
header: "#",
cell: ({ row }) => <p className="text-14-medium ">{row.index + 1}</p>,
},
{
accessorKey: "patient",
header: "Patient",
cell: ({ row }) => (
<p className="text-14-medium ">{row.original.patient.name}</p>
),
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => (
<div className="min-w-[115px]">
<StatusBadgeComponent status={row.original.appointment.status} />
</div>
),
},
{
accessorKey: "schedule",
header: "Appointment",
cell: ({ row }) => (
<p className="text-14-regular min-w-[100px]">
{formatDateTime(row.original.schedule).dateTime}
</p>
),
},
{
accessorKey: "primaryPhysician",
header: "Doctor",
cell: ({ row }) => {
const doctor = Doctors.find(
(doc) => doc.name === row.original.primaryPhysician
);
return (
<div className="flex items-center gap-3">
<Image
src={doctor?.image!}
alt={doctor?.name!}
width={100}
height={100}
className="size-8"
/>
<p className="whitespace-nowrap">Dr. {doctor?.name!}</p>
</div>
);
},
},
{
id: "actions",
header: () => <div className="pl-4">Actions</div>,
cell: ({ row: { original: data } }) => {
return (
<div className="flex gap-1">
<AppointmentModalComponent
patientId={data.patient.$id}
userId={data.userId}
appointment={data}
type="schedule"
/>
<AppointmentModalComponent
patientId={data.patient.$id}
userId={data.userId}
appointment={data}
type="cancel"
/>
</div>
);
},
},
];
home page code:
import Image from "next/image";
import Link from "next/link";
import LogoComponent from "@/components/constants/LogoComponent";
import PatientFormComponent from "@/components/forms/PatientFormComponent";
import OTPModalComponent from "@/components/modal/OTPModalComponent";
const HomePage = ({ searchParams }: SearchParamProps) => {
const isAdmin = searchParams.admin === "true";
return (
<div className="flex h-screen max-h-screen">
{isAdmin && <OTPModalComponent />}
<section className="remove-scrollbar container my-auto">
<div className="sub-container max-w-[496px]">
<LogoComponent />
<PatientFormComponent />
<div className="text-14-regular mt-20 flex justify-between">
<p className="justify-items-end text-dark-600 xl:text-left">
© 2024 Mokhele Medics
</p>
<Link href="/?admin=true" className="text-green-500">
Admin
</Link>
</div>
</div>
</section>
<Image
src="/assets/images/onboarding-img.png"
alt="nurse-image"
width={1000}
height={1000}
className="side-img max-w-[50%]"
/>
</div>
);
};
export default HomePage;
@techiemokhele damn, it's documents
and not document
❌ data={appointments.document}
✅ data={appointments.documents}
This is actual data,
const data = {
totalCount: appointments.total,
...counts,
documents: appointments.documents,
};
My bad 😫 It worked, but now I have a new error I think I will resolve it:
Resolved!
Nice, like that. Keep it up @techiemokhele ✌️
Every time I try to access the admin, I get 500.
The code is the same, but there is this issue that won't go away. I tried debugging and going through your source code but nothing is working.
All env credentials are correct, as I have some data in the database and users are created seamlessly, including the creation of appointments. Just view my appointments in the admin. Even the types are correct
TypeError: Cannot read properties of undefined (reading 'length')
components/table/AppointmentDataTableComponent.tsx (77:18) @ getRowModel
DataTable code:
columns code:
appointment.actions code
AppointmentFormComponent code: