import { useEffect, useState } from "react"; import { useSupabaseClient } from "@supabase/auth-helpers-react"; import { HeadingLink, MinimalPage, PageHeading, Spinner } from "ui"; import type { Database } from "../../../types"; import dayjs from "dayjs"; const ShiftTable = () => { const [usersOnShift, setUsersOnShift] = useState< Array<{ user: string; shift_start: string | undefined; image: string | undefined; fullName: string; }> >([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const supabaseClient = useSupabaseClient<Database>(); useEffect(() => { const fetchUsersOnShift = async () => { setLoading(true); try { const { data: usersData, error: usersError } = await supabaseClient .from("UserLastWorkedOn") .select("shift_start, user, users_view (email, raw_user_meta_data)") .not("shift_start", "is", null); if (usersError) { setError(usersError.message ?? "Failed to fetch user shift data"); console.error(usersError); } const mappedUsers = usersData?.map((user) => { const userMetaData = Array.isArray(user.users_view) ? user.users_view[0].raw_user_meta_data : user.users_view?.raw_user_meta_data; const fullName = userMetaData ? userMetaData["full_name"] ?? "No Name Provided" : "No Name Provided"; const image = userMetaData ? userMetaData["avatar_url"] : undefined; return { shift_start: user.shift_start ? dayjs(user.shift_start).format("DD-MM-YYYY | HH:mm") : undefined, user: fullName, image: image, fullName: fullName, }; }); setUsersOnShift(mappedUsers ?? []); } catch (err) { setError("Failed to fetch user shift data"); console.error(err); } finally { setLoading(false); } }; fetchUsersOnShift(); }, [supabaseClient]); const defaultAvatar = "/path_to_default_avatar.jpg"; // Replace with actual path to your default avatar image return ( <MinimalPage pageTitle="Shift Table | Email Interface" pageDescription="Spot Ship Email Interface | Shift Table" commandPrompt > <div className="w-full"> <HeadingLink icon="back" text="Home" href="/secure/home" /> </div> <PageHeading text="Spot Ship Shift Table" /> <div className="flex w-full flex-col"> {loading ? ( <Spinner /> ) : error ? ( <p className="text-red-500">Error: {error}</p> ) : usersOnShift.length ? ( <table className="mt-4 min-w-full"> <thead> <tr> <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"> User Name </th> <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"> Shift Started </th> </tr> </thead> <tbody className="divide-white-200 divide-x "> {usersOnShift.map((user, index) => ( <tr key={index}> <td className="text-white-500 flex items-center px-6 py-4 text-sm"> <img src={user.image || defaultAvatar} onError={(e) => (e.currentTarget.src = defaultAvatar)} alt={user.fullName} style={{ height: 30, width: 30, borderRadius: "50%", marginRight: "0.5rem", }} /> {user.user} </td> <td className="text-white-500 px-6 py-4 text-sm"> {user.shift_start ?? "No Data"} </td> </tr> ))} </tbody> </table> ) : ( <p>No users are currently on shift</p> )} </div> </MinimalPage> ); }; export default ShiftTable;
Preview:
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