import { useState } from 'react'; import { useBlocker } from 'react-router'; import { toast } from 'react-toastify'; import AddIcon from '@mui/icons-material/Add'; import CancelIcon from '@mui/icons-material/Cancel'; import WarningIcon from '@mui/icons-material/Warning'; import { Box, Button, Typography } from '@mui/material'; import { Body, Cell, Header, HeaderCell, HeaderRow, Row, Table } from '@table-library/react-table-library/table'; import { useTheme } from '@table-library/react-table-library/theme'; import { updateState, useRequest } from 'alova/client'; import { BlockNavigation, ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components'; import { useI18nContext } from 'i18n/i18n-react'; import { useInterval } from 'utils'; import { readCommands, writeCommands } from '../../api/app'; import CommandsDialog from './CommandsDialog'; import type { CommandItem, Commands as CommandsType } from './types'; import { commandItemValidation } from './validators'; const INTERVAL_DELAY = 30000; const MIN_ID = -100; const MAX_ID = 100; const DEFAULT_COMMAND_ITEM: Omit = { cmd: '', value: '', name: '', deleted: false }; const commandsTheme = { Table: ` --data-table-library_grid-template-columns: repeat(1, minmax(100px, 1fr)) repeat(1, minmax(100px, 1fr)) 160px; `, BaseRow: ` font-size: 14px; .td { height: 32px; } `, BaseCell: ` &:nth-of-type(1) { padding: 8px; } `, HeaderRow: ` text-transform: uppercase; background-color: black; color: #90CAF9; .th { border-bottom: 1px solid #565656; height: 36px; } `, Row: ` background-color: #1e1e1e; position: relative; cursor: pointer; .td { border-bottom: 1px solid #565656; } &:hover .td { background-color: #177ac9; } ` }; const CommandsPage = () => { const { LL } = useI18nContext(); const [numChanges, setNumChanges] = useState(0); const blocker = useBlocker(numChanges !== 0); const [selectedItem, setSelectedItem] = useState(); const [creating, setCreating] = useState(false); const [dialogOpen, setDialogOpen] = useState(false); useLayoutTitle(LL.COMMANDS()); const { data: commands, send: fetchCommands, error } = useRequest(readCommands, { initialData: [] }); const { send: updateCommands } = useRequest( (data: CommandsType) => writeCommands(data), { immediate: false } ); const hasChanged = (ci: CommandItem) => ci.id !== ci.o_id || (ci.name || '') !== (ci.o_name || '') || ci.cmd !== ci.o_cmd || ci.value !== ci.o_value || ci.deleted !== ci.o_deleted; useInterval(() => { if (numChanges === 0) { void fetchCommands(); } }, INTERVAL_DELAY); const theme = useTheme(commandsTheme); const saveCommands = async () => { try { await updateCommands({ commands: commands .filter((ci: CommandItem) => !ci.deleted) .map((ci: CommandItem) => ({ id: ci.id, cmd: ci.cmd, value: ci.value, name: ci.name })) }); toast.success(LL.UPDATED_OF(LL.COMMANDS(0))); } catch (error: unknown) { const message = error instanceof Error ? error.message : String(error); toast.error(message); } finally { await fetchCommands(); setNumChanges(0); } }; const editItem = (ci: CommandItem) => { setCreating(false); setSelectedItem(ci); setDialogOpen(true); if (ci.o_name === undefined) { ci.o_name = ci.name; } }; const onDialogClose = () => { setDialogOpen(false); }; const onDialogCancel = async () => { await fetchCommands().then(() => { setNumChanges(0); }); }; const onDialogSave = (updatedItem: CommandItem) => { setDialogOpen(false); void updateState(readCommands(), (data: CommandItem[]) => { const new_data = creating ? [...data, updatedItem] : data.map((ci) => ci.id === updatedItem.id ? { ...ci, ...updatedItem } : ci ); setNumChanges(new_data.filter((ci) => hasChanged(ci)).length); return new_data; }); }; const addItem = () => { setCreating(true); const newItem: CommandItem = { id: Math.floor(Math.random() * (MAX_ID - MIN_ID) + MIN_ID), ...DEFAULT_COMMAND_ITEM }; setSelectedItem(newItem); setDialogOpen(true); }; const filteredCommands = commands.filter((ci: CommandItem) => !ci.deleted); const renderCommands = () => { if (!commands) { return ( ); } return ( {(tableList: CommandItem[]) => ( <>
{LL.COMMAND(0)} {LL.VALUE(0)} {LL.NAME(0)}
{tableList.map((ci: CommandItem) => ( editItem(ci)}> {ci.cmd} {ci.value} {ci.name} ))} )}
); }; return ( {blocker ? : null} {LL.COMMANDS_HELP_1()}. {renderCommands()} {selectedItem && ( )} {numChanges !== 0 && ( )} ); }; export default CommandsPage;