import { faCheck, faCircleNotch, faInfoCircle, faTimes, faTrash, } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Button, Container, Form } from "react-bootstrap"; import { Column, TableUpdater } from "react-table"; import { LanguageSelector, MessageIcon } from ".."; import { BuildKey } from "../../utilities"; import { FileForm } from "../inputs"; import { SimpleTable } from "../tables"; import BaseModal, { BaseModalProps } from "./BaseModal"; import { useCloseModal } from "./hooks"; export interface PendingSubtitle

{ file: File; state: "valid" | "fetching" | "warning" | "error"; messages: string[]; language: Language.Info | null; forced: boolean; hi: boolean; payload: P; } export type Validator = ( item: PendingSubtitle ) => Pick, "state" | "messages">; interface Props { initial: T; availableLanguages: Language.Info[]; upload: (items: PendingSubtitle[]) => void; update: (items: PendingSubtitle[]) => Promise[]>; validate: Validator; columns: Column>[]; hideAllLanguages?: boolean; } export default function SubtitleUploadModal( props: Props & Omit ) { const { initial, columns, upload, update, validate, availableLanguages, hideAllLanguages, } = props; const closeModal = useCloseModal(); const [pending, setPending] = useState[]>([]); const fileList = useMemo(() => pending.map((v) => v.file), [pending]); const initialRef = useRef(initial); const setFiles = useCallback( async (files: File[]) => { const initialLanguage = availableLanguages.length > 0 ? availableLanguages[0] : null; let list = files.map>((file) => ({ file, state: "fetching", messages: [], language: initialLanguage, forced: false, hi: false, payload: { ...initialRef.current }, })); if (update) { setPending(list); list = await update(list); } else { list = list.map>((v) => ({ ...v, state: "valid", })); } list = list.map((v) => ({ ...v, ...validate(v), })); setPending(list); }, [update, validate, availableLanguages] ); const modify = useCallback>>( (row, info?: PendingSubtitle) => { setPending((pd) => { const newPending = [...pd]; if (info) { info = { ...info, ...validate(info) }; newPending[row.index] = info; } else { newPending.splice(row.index, 1); } return newPending; }); }, [validate] ); useEffect(() => { setPending((pd) => { const newPd = pd.map((v) => { if (v.state !== "fetching") { return { ...v, ...validate(v) }; } else { return v; } }); return newPd; }); }, [validate]); const columnsWithAction = useMemo>[]>( () => [ { id: "icon", accessor: "state", className: "text-center", Cell: ({ value, row }) => { let icon = faCircleNotch; let color: string | undefined = undefined; let spin = false; switch (value) { case "fetching": spin = true; break; case "warning": icon = faInfoCircle; color = "var(--warning)"; break; case "valid": icon = faCheck; color = "var(--success)"; break; default: icon = faTimes; color = "var(--danger)"; break; } const messages = row.original.messages; return ( ); }, }, { Header: "File", accessor: (d) => d.file.name, }, { id: "hi", Header: "HI", accessor: "hi", Cell: ({ row, value, update }) => { const { original, index } = row; return ( { const newInfo = { ...row.original }; newInfo.hi = v.target.checked; update && update(row, newInfo); }} > ); }, }, { id: "forced", Header: "Forced", accessor: "forced", Cell: ({ row, value, update }) => { const { original, index } = row; return ( { const newInfo = { ...row.original }; newInfo.forced = v.target.checked; update && update(row, newInfo); }} > ); }, }, { id: "language", Header: "Language", accessor: "language", className: "w-25", Cell: ({ row, update, value }) => { return ( { if (lang && update) { const newInfo = { ...row.original }; newInfo.language = lang; update(row, newInfo); } }} > ); }, }, ...columns, { id: "action", accessor: "file", Cell: ({ row, update }) => ( ), }, ], [columns, availableLanguages] ); const showTable = pending.length > 0; const canUpload = useMemo( () => pending.length > 0 && pending.every((v) => v.state === "valid" || v.state === "warning"), [pending] ); const footer = (

); return (
); }