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;