"use client";
import { ActionIcon, Anchor, Avatar, Badge, 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 { useIntegrationsWithInteractAccess } from "@homarr/auth/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 { useI18n } from "@homarr/translation/client";
import { WidgetEmptyState } from "../../common/empty-state";
import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../../common/application-url";
import { getUsableWidgetQueryData, isInitialWidgetQueryPending } from "../../common/query-state";
import { WidgetQueryLoadingState } from "../../common/query-state-indicator";
import actionTargetClasses from "../../common/action-target.module.css";
import { IntegrationErrorIndicator } from "../../common/integration-error-indicator";
import type { WidgetComponentProps } from "../../definition";
import { MediaRequestsEmptyState } from "../empty-state";
import classes from "./component.module.css";
import searchClasses from "../search-button.module.css";
export default function MediaServerWidget({
integrationIds,
isEditMode,
options,
width,
}: WidgetComponentProps<"mediaRequests-requestList">) {
const t = useI18n("widget.mediaRequests-requestList");
const interactIntegrationIds = new Set(
useIntegrationsWithInteractAccess()
.filter(({ id }) => integrationIds.includes(id))
.map(({ id }) => id),
);
const mediaRequestQuery = clientApi.widget.mediaRequests.getLatestRequests.useQuery({
integrationIds,
statuses:
options.statusFilter.length > 0
? options.statusFilter
: ["pending", "approved", "declined", "failed", "completed"],
recentDays: options.recentDays,
});
const mediaRequestData = getUsableWidgetQueryData(mediaRequestQuery);
if (isInitialWidgetQueryPending(mediaRequestQuery)) return ;
if (!mediaRequestData) return ;
const { requests: mediaRequests, failedIntegrations } = mediaRequestData;
if (mediaRequests.length === 0 && failedIntegrations.length === 0) {
return (
);
}
const showIntegrationSource = new Set(mediaRequests.map(({ integrationId }) => integrationId)).size > 1;
return (
{!isEditMode && }
{failedIntegrations.length > 0 && (
)}
{mediaRequests.map((mediaRequest) => (
))}
);
}
const MediaRequestSearchButton = ({ integrationIds }: { integrationIds: string[] }) => {
const t = useI18n("search.mode.media");
return (
openMediaRequestSearch({ integrationIds })}
>
);
};
interface MediaRequestCardProps {
request: RouterOutputs["widget"]["mediaRequests"]["getLatestRequests"]["requests"][number];
isTiny: boolean;
showIntegrationSource: boolean;
canInteract: boolean;
options: WidgetComponentProps<"mediaRequests-requestList">["options"];
}
const MediaRequestCard = ({ request, isTiny, showIntegrationSource, canInteract, options }: MediaRequestCardProps) => {
const board = useRequiredBoard();
const t = useI18n("widget.mediaRequests-requestList");
const requestHref = getSafeApplicationUrl(request.href);
const requestedByHref = getSafeApplicationUrl(request.requestedBy?.link);
return (
{!isTiny && (
)}
{toValidDate(request.airDate)?.getFullYear() ?? t("toBeDetermined")}
{!isTiny && (
{t(`availability.${request.availability}`)}
)}
{showIntegrationSource && !isTiny && (
{request.integration.name}
)}
{(request.requestedBy?.displayName ?? "") || t("unknown")}
{request.name || t("unknown")}
{request.status === "pending" ? (
) : (
)}
);
};
interface DecisionButtonsProps {
requestId: number;
integrationId: string;
canInteract: boolean;
alwaysVisible: boolean;
}
const DecisionButtons = ({ requestId, integrationId, canInteract, alwaysVisible }: DecisionButtonsProps) => {
const utils = clientApi.useUtils();
const {
mutate: mutateRequestAnswer,
isPending,
error,
} = clientApi.widget.mediaRequests.answerRequest.useMutation({
onSettled: () => void utils.widget.mediaRequests.invalidate(),
});
const t = useI18n("widget.mediaRequests-requestList");
const handleDecision = (answer: RouterInputs["widget"]["mediaRequests"]["answerRequest"]["answer"]) => {
if (!canInteract || isPending) return;
mutateRequestAnswer({
integrationId,
requestId,
answer,
});
};
return (
{
handleDecision("approve");
}}
>
{
handleDecision("decline");
}}
>
);
};
interface StatusBadgeProps {
status: MediaRequestStatus;
}
const StatusBadge = ({ status }: StatusBadgeProps) => {
const tStatus = useI18n("widget.mediaRequests-requestList.status");
return (
{tStatus(status)}
);
};