Preview:
import React, { useEffect, useState } from "react";
import { useSupabaseClient } from "@supabase/auth-helpers-react";
import { HeadingLink, MinimalPage, PageHeading, Spinner } from "ui";
import dayjs from "dayjs";
import { useRouter } from "next/router";
import { useGetFilename } from "@/hooks";
import { getFilename } from "@/functions";
import Link from "next/link";

type User = {
  shift_start: string | null;
  break_start: string | null;
  user: any;
  image: string;
  fullName: string;
  group: string | null;
  users_view?: {
    email?: string;
    raw_user_meta_data?: {
      avatar_url?: string;
      full_name?: string;
    };
  };
  email: string;
};

const ShiftTable = () => {
  const [usersOnShift, setUsersOnShift] = useState<User[]>([]);
  const [usersOffShift, setUsersOffShift] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const { data: fileNameId } = useGetFilename(
    "88ccb685-8532-454b-a1c4-f69425af7e93"
  );
  console.log(fileNameId);
  const supabaseClient = useSupabaseClient();
  const router = useRouter();
  const excludedUuid = "2b78abeb-133d-4248-8469-21620903cbb3";

  useEffect(() => {
    const fetchUsers = async () => {
      setLoading(true);
      setError("");

      try {
        const { data: usersData, error: fetchError } = await supabaseClient
          .from("UserLastWorkedOn")
          .select(
            "shift_start, break_start, user, users_view ( raw_user_meta_data), email,  group"
          )
          .not("user", "eq", excludedUuid);

        if (fetchError) {
          setError(fetchError.message || "Failed to fetch user data.");
          return;
        }
        console.log(usersData);

        const mappedUsers = await Promise.all(
          usersData.map(async (user) => {
            const meta_data = user.users_view as any;
            const metaData = meta_data?.raw_user_meta_data;
            console.log(user.users_view);
            const image = metaData.avatar_url;
            const fullName = metaData.full_name || "No Name Provided";
            const filename = await getFilename(supabaseClient, user.email);
            return {
              shift_start: user.shift_start
                ? dayjs(user.shift_start).format("DD-MM-YYYY | HH:mm")
                : null,
              break_start: user.break_start
                ? dayjs(user.break_start).format("DD-MM-YYYY | HH:mm")
                : null,
              user: user.user,
              image: image,
              fullName: fullName,
              group: user.group || "No Group",
              email: filename ?? "",
            };
          })
        );

        setUsersOnShift(
          mappedUsers.filter((user) => user.shift_start !== null)
        );
        setUsersOffShift(
          mappedUsers.filter((user) => user.shift_start === null)
        );
      } catch (err) {
        setError("Failed to fetch user data: " + err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchUsers();
  }, [supabaseClient]);

  return (
    <MinimalPage
      pageTitle="Shift Table | Email Interface"
      pageDescription="Spot Ship Email Interface | Shift Table"
    >
      <div className="w-full">
        <HeadingLink icon="back" text="Home" href="/secure/home" />
        <PageHeading text="Spot Ship Shift Table" />
        <div className="mb-4 text-sm text-gray-400">
          {usersOnShift.length} user(s) currently on shift. Offline users:{" "}
          {usersOffShift.length}.
        </div>
        {loading ? (
          <Spinner />
        ) : error ? (
          <p className="text-red-500">{error}</p>
        ) : (
          <>
            {renderUsersGrid(
              "Data Analysts",
              usersOnShift.filter((user) => user.group === "Data Analyst"),
              true,
              false
            )}
            {renderUsersGrid(
              "Senior Data Analysts",
              usersOnShift.filter(
                (user) => user.group === "Senior Data Analyst"
              ),
              true,
              false
            )}
            {renderUsersGrid(
              "Data Team Managers",
              usersOnShift.filter((user) => user.group === "Data Team Manager"),
              true,
              false
            )}
            {renderUsersGrid(
              "Europe Team",
              usersOnShift.filter((user) => user.group === "Europe Team"),
              true,
              false
            )}
            {renderUsersGrid("Offline Users", usersOffShift, false, true)}
          </>
        )}
      </div>
    </MinimalPage>
  );

  function renderUsersGrid(
    title: string,
    users: User[],
    showShiftStart: boolean,
    dim: boolean
  ) {
    return (
      <div
        className={`overflow-hidden overflow-x-auto rounded-lg shadow ${
          dim ? "opacity-50" : ""
        }`}
      >
        <h2 className="text-center text-lg font-semibold">{title}</h2>
        <div className="grid grid-cols-4 gap-4 p-4">
          {users.map((user, index) => (
            <div
              key={index}
              className={`relative flex flex-col items-center justify-center rounded-lg bg-gray-800 p-4 ${
                dim ? "bg-opacity-50" : ""
              }`}
            >
              <div className="relative h-12 w-12">
                <img
                  src={user.image || "avatar_url.jpg"} // Fallback to default avatar if none
                  alt={user.fullName}
                  className="h-full w-full rounded-full object-cover"
                />
                {/* Status Indicators placed on the image */}
                {user.shift_start && !user.break_start && (
                  <span className="absolute bottom-0 right-0 block h-5 w-5 rounded-full border-2 border-black bg-green-400" />
                )}
                {user.break_start && (
                  <span className="absolute bottom-0 right-0 block h-5 w-5 rounded-full border-2 border-black bg-yellow-400" />
                )}
                {!user.shift_start && (
                  <span className="absolute bottom-0 right-0 block h-5 w-5 rounded-full border-2 border-black bg-gray-400" />
                )}
              </div>
              <Link
                href={`/secure/review/email?filename=${user.email}`}
                passHref
                rel="noopener noreferrer"
                target="_blank"
              >
                <button className="mt-2 rounded bg-blue-500 px-2 py-1 text-xs font-bold text-white hover:bg-blue-700">
                  {user.email !== "" ? "Working on Email" : "No Email Assigned"}
                </button>
              </Link>
              <p className="mt-2 text-sm text-white">{user.fullName}</p>
              {showShiftStart && user.shift_start && (
                <p className="text-xs text-gray-400">{user.shift_start}</p>
              )}
            </div>
          ))}
        </div>
      </div>
    );
  }
};

export default ShiftTable;
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter