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";
// Define types for users on and off shift
type UserOnShift = {
shift_start: string | null;
user: string; // Email from 'users_view'
};
type OfflineUser = {
user: string; // Email from 'users_view'
};
const ShiftTable = () => {
const [usersOnShift, setUsersOnShift] = useState<UserOnShift[]>([]);
const [usersOffShift, setUsersOffShift] = useState<OfflineUser[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [showModal, setShowModal] = useState(false);
const [selectedUser, setSelectedUser] = useState<UserOnShift | null>(null);
const supabaseClient = useSupabaseClient();
const router = useRouter();
const excludedUuid = "2b78abeb-133d-4248-8469-21620903cbb3";
useEffect(() => {
const fetchUsers = async () => {
setLoading(true);
setError("");
try {
const { data: usersOnShiftData, error: onShiftError } =
await supabaseClient
.from("UserLastWorkedOn")
.select("shift_start, user, users_view (email)")
.not("user", "eq", excludedUuid)
.not("shift_start", "is", null);
const { data: usersOffShiftData, error: offShiftError } =
await supabaseClient
.from("UserLastWorkedOn")
.select("user, users_view (email)")
.not("user", "eq", excludedUuid)
.is("shift_start", null);
if (onShiftError || offShiftError) {
setError(
onShiftError?.message ||
offShiftError?.message ||
"Failed to fetch user data."
);
return;
}
const sortedOnShift = usersOnShiftData
.map((user) => ({
shift_start: user.shift_start,
user: user.users_view?.email ?? user.user,
}))
.sort((a, b) => a.user.localeCompare(b.user));
const sortedOffShift = usersOffShiftData
.map((user) => ({
user: user.users_view?.email ?? user.user,
}))
.sort((a, b) => a.user.localeCompare(b.user));
setUsersOnShift(sortedOnShift);
setUsersOffShift(sortedOffShift);
} catch (err) {
setError("Failed to fetch user data: " + err.message);
} finally {
setLoading(false);
}
};
fetchUsers();
}, [supabaseClient]);
const handleUserClick = (user: UserOnShift) => {
setSelectedUser(user);
setShowModal(true);
};
const closeModal = () => {
setShowModal(false);
setSelectedUser(null);
};
const navigateToUserHistory = () => {
if (selectedUser) {
router.push(`/user-history/${selectedUser.user}`); // Adjust the route as needed
closeModal();
}
};
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="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>
) : (
<>
<div className="mt-8 w-full px-4">
{renderUsersGrid(
"Users Currently On Shift",
usersOnShift,
true,
handleUserClick
)}
</div>
<div className="mt-8 w-full px-4">
{renderUsersGrid(
"Offline Users",
usersOffShift,
false,
handleUserClick
)}
</div>
</>
)}
{showModal && selectedUser && (
<div className="absolute bottom-0 left-0 right-0 top-0 flex items-center justify-center bg-black bg-opacity-50">
<div className="rounded-lg bg-white p-4 shadow-lg">
<h3 className="text-lg font-bold">User Actions</h3>
<p>{`Show ${selectedUser.user}'s history?`}</p>
<button
className="rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700"
onClick={navigateToUserHistory}
>
View History
</button>
<button
className="ml-2 rounded bg-gray-300 px-4 py-2 text-black hover:bg-gray-400"
onClick={closeModal}
>
Cancel
</button>
</div>
</div>
)}
</MinimalPage>
);
function renderUsersGrid(
title: string,
users: any[],
showShiftStart: boolean,
onClick: (user: UserOnShift) => void
) {
return (
<div className="overflow-hidden overflow-x-auto rounded-3xl border-transparent shadow-lg">
<h2 className="my-4 px-6 text-lg font-semibold text-white">{title}</h2>
<div className="grid grid-cols-4 gap-4">
{users.map((user, index) => (
<div
key={index}
className="cursor-pointer rounded-xl bg-gray-800 p-4 text-center"
onClick={() => onClick(user)}
>
<p className="text-sm text-gray-400">{user.user}</p>
{showShiftStart && user.shift_start ? (
<p className="text-sm text-gray-400">
{dayjs(user.shift_start).format("DD-MM-YYYY | HH:mm")}
</p>
) : null}
</div>
))}
</div>
</div>
);
}
};
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