Preview:
import React from "react";
import {
  BodyText,
  Conditional,
  H2,
  HeadingLink,
  IntroText,
  Loading,
  MinimalPage,
  PageHeading,
  PrimaryButton,
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "ui";
import Link from "next/link";
import { CommandInterface } from "@/components";
import { useShiftTable } from "@/hooks";
import { timeSince } from "@/functions";
import dayjs from "dayjs";

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 { data, isLoading, error, isError } = useShiftTable();

  const countUsersInGroups = (users: User[]): Record<string, number> => {
    return users.reduce<Record<string, number>>((acc, user) => {
      const groupName = user.group || "No Group";
      acc[groupName] = (acc[groupName] || 0) + 1;
      return acc;
    }, {});
  };

  const usersOnShiftCounts = countUsersInGroups(data?.onShift ?? []);
  const usersOffShiftCounts = countUsersInGroups(data?.offShift ?? []);

  const sortUsers = (users: User[]) => {
    return users
      .slice()
      .sort((a, b) => a.fullName.localeCompare(b.fullName))
      .sort((a, b) => {
        const shiftA = a.shift_start ? new Date(a.shift_start).getTime() : 0;
        const shiftB = b.shift_start ? new Date(b.shift_start).getTime() : 0;
        return shiftA - shiftB;
      });
  };

  return (
    <MinimalPage
      pageTitle="Shift Table | Email Interface"
      pageDescription="Spot Ship Email Interface | Shift Table"
      commandPrompt
    >
      <CommandInterface />
      <div className="hidden">
        <PageHeading text="Homepage" />
      </div>
      <div className="w-full pl-1 pt-1">
        <HeadingLink icon="back" text="Home" href="/secure/home" />
        <PageHeading text="Spot Ship Shift Table" />
        <Conditional
          condition={!isLoading}
          elseChildren={
            <Loading style="grid" size="large" colour="#AAAAAA50" />
          }
        >
          <Conditional
            condition={!isError}
            elseChildren={<p className="text-red-500">{`${error?.message}`}</p>}
          >
            <div className="mb-4 text-center text-sm text-gray-400">
              Users currently on shift:{" "}
              {Object.entries(usersOnShiftCounts)
                .map(([group, count]) => `${group}: ${count}`)
                .join(", ")}
            </div>
            <RenderUsersGrid
              title="Data Analysts"
              users={sortUsers(
                data?.onShift?.filter(
                  (user) => user.group === "Data Analyst",
                ) ?? [],
              )}
            />
            <RenderUsersGrid
              title="Senior Data Analysts"
              users={sortUsers(
                data?.onShift?.filter(
                  (user) => user.group === "Senior Data Analyst",
                ) ?? [],
              )}
            />
            <RenderUsersGrid
              title="Data Team Managers"
              users={sortUsers(
                data?.onShift?.filter(
                  (user) => user.group === "Data Team Manager",
                ) ?? [],
              )}
            />
            <RenderUsersGrid
              title="Europe Team"
              users={sortUsers(
                data?.onShift?.filter((user) => user.group === "Europe Team") ??
                  [],
              )}
            />
            <div className="mb-4 text-center text-sm text-gray-400">
              Offline users:{" "}
              {Object.entries(usersOffShiftCounts)
                .map(([group, count]) => `${group}: ${count}`)
                .join(", ")}
            </div>
            <RenderUsersGrid
              title="Offline Data Analysts"
              users={sortUsers(
                data?.offShift?.filter(
                  (user) => user.group === "Data Analyst",
                ) ?? [],
              )}
              showShiftStart={false}
              dim={true}
            />
            <RenderUsersGrid
              title="Offline Senior Data Analysts"
              users={sortUsers(
                data?.offShift?.filter(
                  (user) => user.group === "Senior Data Analyst",
                ) ?? [],
              )}
              showShiftStart={false}
              dim={true}
            />
            <RenderUsersGrid
              title="Offline Data Team Managers"
              users={sortUsers(
                data?.offShift?.filter(
                  (user) => user.group === "Data Team Manager",
                ) ?? [],
              )}
              showShiftStart={false}
              dim={true}
            />
            <RenderUsersGrid
              title="Offline Europe Team"
              users={sortUsers(
                data?.offShift?.filter(
                  (user) => user.group === "Europe Team",
                ) ?? [],
              )}
              showShiftStart={false}
              dim={true}
            />
          </Conditional>
        </Conditional>
      </div>
    </MinimalPage>
  );
};
const RenderUsersGrid = ({
  title,
  users = [],
  showShiftStart = true,
  dim = false,
}: {
  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 ">{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-200 p-4 dark:bg-gray-800 ${
              dim ? "bg-opacity-50" : ""
            }`}
          >
            <div className="relative h-12 w-12">
              <img
                src={user.image || "/avatar_url.png"}
                alt={user.fullName}
                className="h-full w-full rounded-full object-cover"
              />
              <span
                className={`absolute bottom-0 right-0 block h-5 w-5 rounded-full border border-white/20 dark:border-black ${
                  user.shift_start === null
                    ? "bg-gray-400"
                    : user.break_start === null
                      ? "bg-green-400"
                      : "bg-yellow-400"
                }`}
              />
            </div>
            <Conditional condition={user.email !== ""}>
              <div className="mt-2">
                <Link
                  href={`/secure/review/email?filename=${user.email}`}
                  passHref
                  rel="noopener noreferrer"
                  target="_blank"
                >
                  <PrimaryButton size="small">Working on Email</PrimaryButton>
                </Link>
              </div>
            </Conditional>
            <IntroText className="mt-2">{user.fullName}</IntroText>
            <Conditional condition={showShiftStart && !!user.shift_start}>
              <TooltipProvider>
                <Tooltip>
                  <TooltipTrigger>
                    <BodyText>
                      {user.shift_start
                        ? `On shift for: ${timeSince(new Date(user.shift_start))}`
                        : ""}
                    </BodyText>
                  </TooltipTrigger>
                  <TooltipContent>
                    <p>
                      {dayjs(user.shift_start).format("DD-MM-YYYY | HH:mm")}
                    </p>
                  </TooltipContent>
                </Tooltip>
              </TooltipProvider>
            </Conditional>
            <Conditional condition={showShiftStart && !!user.break_start}>
              <TooltipProvider>
                <Tooltip>
                  <TooltipTrigger>
                    <BodyText>
                      {user.break_start
                        ? `On break for: ${timeSince(
                            new Date(user.break_start),
                          )}`
                        : ""}
                    </BodyText>
                  </TooltipTrigger>
                  <TooltipContent>
                    <p>
                      {dayjs(user.break_start).format("DD-MM-YYYY | HH:mm")}
                    </p>
                  </TooltipContent>
                </Tooltip>
              </TooltipProvider>
            </Conditional>
          </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