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 = (
{
if (lang) {
setPending((pd) =>
pd
.map((v) => ({ ...v, language: lang }))
.map((v) => ({ ...v, ...validate(v) }))
);
}
}}
>
);
return (
);
}