Shift Table 30.04.2024 working perfecly, needs to change components to <Conditional> and <Loading>

PHOTO EMBED

Thu Apr 18 2024 08:08:00 GMT+0000 (Coordinated Universal Time)

Saved by @rafal_rydz

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 { getFilename } from "@/functions";
import Link from "next/link";
import { CommandInterface } from "@/components";

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 supabaseClient = useSupabaseClient();
  const router = useRouter();
  const nonUser = ["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", nonUser);

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

        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;
            const image = metaData.avatar_url || "/avatar_url.png";
            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: unknown) {
        if (err instanceof Error) {
          setError("Failed to fetch user data: " + err.message);
        } else {
          setError("Failed to fetch user data: An unknown error occurred.");
        }
      } finally {
        setLoading(false);
      }
    };

    fetchUsers();
  }, [supabaseClient]);
  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(usersOnShift);
  const usersOffShiftCounts = countUsersInGroups(usersOffShift);

  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"></div>
      <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 (
          {Object.entries(usersOnShiftCounts)
            .map(([group, count]) => `${group}: ${count}`)
            .join(", ")}
          ). Offline users: {usersOffShift.length} (
          {Object.entries(usersOffShiftCounts)
            .map(([group, count]) => `${group}: ${count}`)
            .join(", ")}
          ).
        </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 || "email-interface/public/avatar_url.png"}
                  alt={user.fullName}
                  className="h-full w-full rounded-full object-cover"
                />
                {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>
              {user.email && (
                <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">
                    Working on Email
                  </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;
content_copyCOPY