"use client"; import { ActionIcon, Anchor, Avatar, Badge, Card, Group, Image, ScrollArea, Stack, Text, Tooltip } from "@mantine/core"; import { IconThumbDown, IconThumbUp } from "@tabler/icons-react"; import type { RouterInputs, RouterOutputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; import { useRequiredBoard } from "@homarr/boards/context"; import type { MediaRequestStatus } from "@homarr/integrations/types"; import { mediaAvailabilityConfiguration, mediaRequestStatusConfiguration } from "@homarr/integrations/types"; import { useScopedI18n } from "@homarr/translation/client"; import { WidgetEmptyState } from "../../common/empty-state"; import type { WidgetComponentProps } from "../../definition"; import { NoIntegrationDataError } from "../../errors/no-data-integration"; export default function MediaServerWidget({ integrationIds, isEditMode, options, width, }: WidgetComponentProps<"mediaRequests-requestList">) { const { data: mediaRequests } = clientApi.widget.mediaRequests.getLatestRequests.useQuery( { integrationIds, }, { refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false, }, ); const utils = clientApi.useUtils(); clientApi.widget.mediaRequests.subscribeToLatestRequests.useSubscription( { integrationIds, }, { onData(data) { utils.widget.mediaRequests.getLatestRequests.setData({ integrationIds }, (prevData) => { if (!prevData) return []; const filteredData = prevData.filter(({ integrationId }) => integrationId !== data.integrationId); const newData = filteredData.concat( data.requests.map((request) => ({ ...request, integrationId: data.integrationId })), ); return newData.toSorted((dataA, dataB) => { if (dataA.status === dataB.status) { return dataB.createdAt.getTime() - dataA.createdAt.getTime(); } return ( mediaRequestStatusConfiguration[dataA.status].position - mediaRequestStatusConfiguration[dataB.status].position ); }); }); }, }, ); if (!mediaRequests) return ; if (mediaRequests.length === 0) throw new NoIntegrationDataError(); return ( {mediaRequests.map((mediaRequest) => ( ))} ); } interface MediaRequestCardProps { request: RouterOutputs["widget"]["mediaRequests"]["getLatestRequests"][number]; isTiny: boolean; options: WidgetComponentProps<"mediaRequests-requestList">["options"]; } const MediaRequestCard = ({ request, isTiny, options }: MediaRequestCardProps) => { const board = useRequiredBoard(); const t = useScopedI18n("widget.mediaRequests-requestList"); return ( {!isTiny && ( )} {request.airDate?.getFullYear() ?? t("toBeDetermined")} {!isTiny && ( {t(`availability.${request.availability}`)} )} {(request.requestedBy?.displayName ?? "") || "unknown"} {request.name || "unknown"} {request.status === "pending" ? ( ) : ( )} ); }; interface DecisionButtonsProps { requestId: number; integrationId: string; } const DecisionButtons = ({ requestId, integrationId }: DecisionButtonsProps) => { const { mutate: mutateRequestAnswer } = clientApi.widget.mediaRequests.answerRequest.useMutation(); const t = useScopedI18n("widget.mediaRequests-requestList"); const handleDecision = (answer: RouterInputs["widget"]["mediaRequests"]["answerRequest"]["answer"]) => { mutateRequestAnswer({ integrationId, requestId, answer, }); }; return ( { handleDecision("approve"); }} > { handleDecision("decline"); }} > ); }; interface StatusBadgeProps { status: MediaRequestStatus; } const StatusBadge = ({ status }: StatusBadgeProps) => { const tStatus = useScopedI18n("widget.mediaRequests-requestList.status"); return ( {tStatus(status)} ); };