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;