"use client"; import { ActionIcon, Anchor, Avatar, Badge, Box, Card, Group, Image, ScrollArea, Stack, Text, Tooltip, } from "@mantine/core"; import { IconSearch, 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 { toValidDate } from "@homarr/common"; import type { MediaRequestStatus } from "@homarr/integrations/types"; import { mediaAvailabilityConfiguration, mediaRequestStatusConfiguration } from "@homarr/integrations/types"; import { openMediaRequestSearch } from "@homarr/spotlight"; import { useScopedI18n } from "@homarr/translation/client"; import { WidgetEmptyState } from "../../common/empty-state"; import type { WidgetComponentProps } from "../../definition"; import { NoIntegrationDataError } from "../../errors/no-data-integration"; import classes from "../search-button.module.css"; export default function MediaServerWidget({ integrationIds, isEditMode, options, width, }: WidgetComponentProps<"mediaRequests-requestList">) { const { data: mediaRequests } = clientApi.widget.mediaRequests.getLatestRequests.useQuery({ integrationIds, statuses: options.statusFilter.length > 0 ? options.statusFilter : ["pending", "approved", "declined", "failed", "completed"], recentDays: options.recentDays, }); if (!mediaRequests) return ; if (mediaRequests.length === 0) throw new NoIntegrationDataError(); return ( {!isEditMode && } {mediaRequests.map((mediaRequest) => ( ))} ); } const MediaRequestSearchButton = ({ integrationIds }: { integrationIds: string[] }) => { const t = useScopedI18n("search.mode.media"); return ( openMediaRequestSearch({ integrationIds })} > ); }; 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 && ( )} {toValidDate(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 utils = clientApi.useUtils(); const { mutate: mutateRequestAnswer } = clientApi.widget.mediaRequests.answerRequest.useMutation({ onSettled: () => void utils.widget.mediaRequests.invalidate(), }); 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)} ); };