adrianhajdin / healthcare

Build a healthcare platform that streamlines patient registration, appointment scheduling, and medical records, and learn to implement complex forms and SMS notifications.
https://jsmastery.pro
1.81k stars 432 forks source link

Unable to see appointment data in admin - 500 status code #9

Closed techiemokhele closed 2 months ago

techiemokhele commented 2 months ago

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

  75 |
  76 |         <TableBody>
> 77 |           {table.getRowModel().rows.length ? (
     |                  `^`
  78 |             table.getRowModel().rows.map((row) => (
  79 |               <TableRow
  80 |                 key={row.id}

DataTable code:


import {
  getPaginationRowModel,
  ColumnDef,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";
import Image from "next/image";
import { redirect } from "next/navigation";
import { useEffect } from "react";

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(),
  });

  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>
  );
}

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>
      );
    },
  },
];

appointment.actions 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
    );
  }
};

AppointmentFormComponent code:

"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import Image from "next/image";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";

import { AppointmentProps, FormFieldType } from "@/types/";
import { getAppointmentSchema } from "@/lib/validation";
import {
  createAppointment,
  updateAppointment,
} from "@/lib/actions/appointment.actions";
import { Doctors } from "@/constants";
import { Form } from "../ui/form";
import { SelectItem } from "../ui/select";

import CustomFormFieldComponent from "./CustomFormFieldComponent";
import SubmitButtonComponent from "../constants/SubmitButtonComponent";

export const AppointmentFormComponent = ({
  type,
  userId,
  patientId,
  appointment,
  setOpen,
}: AppointmentProps) => {
  const router = useRouter();
  const [isLoading, setIsLoading] = useState<boolean>(false);

  const AppointmentFormValidation = getAppointmentSchema(type);

  const form = useForm<z.infer<typeof AppointmentFormValidation>>({
    resolver: zodResolver(AppointmentFormValidation),
    defaultValues: {
      primaryPhysician: appointment ? appointment?.primaryPhysician : "",
      schedule: appointment
        ? new Date(appointment?.schedule!)
        : new Date(Date.now()),
      reason: appointment ? appointment.reason : "",
      note: appointment?.note || "",
      cancellationReason: appointment?.cancellationReason || "",
    },
  });

  const onSubmit = async (
    values: z.infer<typeof AppointmentFormValidation>
  ) => {
    setIsLoading(true);

    let status;
    switch (type) {
      case "schedule":
        status = "scheduled";
        break;
      case "cancel":
        status = "cancelled";
        break;
      default:
        status = "pending";
    }

    try {
      if (type === "create" && patientId) {
        const appointment = {
          userId,
          patient: patientId,
          primaryPhysician: values.primaryPhysician,
          schedule: new Date(values.schedule),
          reason: values.reason!,
          status: status as Status,
          note: values.note,
        };

        const newAppointment = await createAppointment(appointment);

        if (newAppointment) {
          form.reset();
          router.push(
            `/patients/${userId}/new-appointment/success?appointmentId=${newAppointment.$id}`
          );
        }
      } else {
        const appointmentToUpdate = {
          userId,
          appointmentId: appointment?.$id!,
          appointment: {
            primaryPhysician: values?.primaryPhysician,
            schedule: new Date(values?.schedule),
            status: status as Status,
            cancellationReason: values?.cancellationReason,
          },
          type,
        };

        const updatedAppointment = await updateAppointment(appointmentToUpdate);

        if (updatedAppointment) {
          setOpen && setOpen(false);
          form.reset();
        }
      }
    } catch (error) {
      console.log("Error thrown in patient form: \n", error);
    }
  };

  let buttonLabel;

  switch (type) {
    case "cancel":
      buttonLabel = "Cancel Appointment";
      break;
    case "create":
      buttonLabel = "Create Appointment";
      break;
    case "schedule":
      buttonLabel = "Schedule Appointment";
      break;

    default:
      break;
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6 flex-1">
        {type === "create" && (
          <section className="mb-12 space-y-4">
            <h1 className="header">New Appointment</h1>
            <p className="text-dark-700">
              In less than 10 seconds, you can request a new appointment.
            </p>
          </section>
        )}

        {type !== "cancel" && (
          <>
            <CustomFormFieldComponent
              fieldType={FormFieldType.SELECT}
              control={form.control}
              name="primaryPhysician"
              label="Doctor"
              placeholder="Select a doctor"
            >
              {Doctors.map((doctor, i) => (
                <SelectItem key={doctor.name + i} value={doctor.name}>
                  <div className="flex cursor-pointer items-center gap-2">
                    <Image
                      src={doctor.image}
                      alt={doctor.name}
                      width={32}
                      height={32}
                      className="rounded-full border border-dark-500"
                    />
                    <p>Dr. {doctor.name}</p>
                  </div>
                </SelectItem>
              ))}
            </CustomFormFieldComponent>

            <CustomFormFieldComponent
              showTimeSelect
              control={form.control}
              fieldType={FormFieldType.DATE_PICKER}
              name="schedule"
              label="Expected appointment date"
              dateFormat="dd/MM/yyyy - hh:mm aa"
            />
          </>
        )}

        <div
          className={`flex flex-col gap-6  ${
            type === "create" && "xl:flex-row"
          }`}
        >
          <CustomFormFieldComponent
            fieldType={FormFieldType.TEXTAREA}
            control={form.control}
            name="reason"
            label="Appointment reason"
            placeholder="Annual monthly check-up"
            disabled={type === "schedule"}
          />

          <CustomFormFieldComponent
            fieldType={FormFieldType.TEXTAREA}
            control={form.control}
            name="note"
            label="Comments/notes"
            placeholder="Prefer afternoon appointments, if possible"
            disabled={type === "schedule"}
          />
        </div>

        {type === "cancel" && (
          <CustomFormFieldComponent
            control={form.control}
            fieldType={FormFieldType.TEXTAREA}
            name="cancellationReason"
            label="Reason for cancellation"
            placeholder="Enter a reason for your cancellation"
          />
        )}

        <SubmitButtonComponent
          type="submit"
          isLoading={isLoading}
          className={`w-full ${
            type === "cancel" ? "shad-danger-btn" : "shad-primary-btn"
          }`}
        >
          {buttonLabel}
        </SubmitButtonComponent>
      </form>
    </Form>
  );
};
techiemokhele commented 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

Screenshot 2024-07-09 at 10 52 13

sujatagunale commented 2 months ago

@techiemokhele use optional chaining operator

{table.getRowModel().rows?.length ? (table.getRowModel().rows.map()) :  ()}
techiemokhele commented 2 months ago

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>
sujatagunale commented 2 months ago

Can you see what you get if you console log table.getRowModel().rows?

techiemokhele commented 2 months ago

Screenshot 2024-07-09 at 20 18 47

I am getting this exception also

sujatagunale commented 2 months ago

@techiemokhele is it a client component or not?

Check if you have added "use client" on top or not

techiemokhele commented 2 months ago

Yes, it does have "use client";

Screenshot 2024-07-09 at 20 25 00

techiemokhele commented 2 months ago

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>
  );
}
sujatagunale commented 2 months ago

Code seems perfect. What do you get if you console log data props in this component?

You get the proper data, right? @techiemokhele

techiemokhele commented 2 months ago

Screenshot 2024-07-09 at 20 34 13

I get Undefined

sujatagunale commented 2 months ago

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

techiemokhele commented 2 months ago

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">
              &copy; 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;
sujatagunale commented 2 months ago

@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,
};
techiemokhele commented 2 months ago

My bad 😫 It worked, but now I have a new error I think I will resolve it:

Screenshot 2024-07-09 at 20 56 51

techiemokhele commented 2 months ago

Resolved!

Screenshot 2024-07-09 at 20 59 05

sujatagunale commented 2 months ago

Nice, like that. Keep it up @techiemokhele ✌️