import { memo, useCallback, useMemo, useState } from 'react';
import { useBlocker } from 'react-router';
import { toast } from 'react-toastify';
import CancelIcon from '@mui/icons-material/Cancel';
import CircleIcon from '@mui/icons-material/Circle';
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 { readModules, writeModules } from '../../api/app';
import ModulesDialog from './ModulesDialog';
import type { ModuleItem } from './types';
const PENDING_COLOR = 'red';
const ACTIVATED_COLOR = '#00FF7F';
const hasModulesChanged = (mi: ModuleItem): boolean =>
mi.enabled !== mi.o_enabled || mi.license !== mi.o_license;
const ColorStatus = memo(({ status }: { status: number }) => {
if (status === 1) {
return
Pending Activation
;
}
return Activated
;
});
const Modules = () => {
const { LL } = useI18nContext();
const [numChanges, setNumChanges] = useState(0);
const blocker = useBlocker(numChanges !== 0);
const [selectedModuleItem, setSelectedModuleItem] = useState();
const [dialogOpen, setDialogOpen] = useState(false);
useLayoutTitle(LL.MODULES());
const {
data: modules,
send: fetchModules,
error
} = useRequest(readModules, {
initialData: []
});
const { send: updateModules } = useRequest(
(data: { key: string; enabled: boolean; license: string }) => writeModules(data),
{
immediate: false
}
);
const modules_theme = useTheme(
useMemo(
() => ({
Table: `
--data-table-library_grid-template-columns: 48px 180px 120px 100px repeat(1, minmax(160px, 1fr)) 180px;
`,
BaseRow: `
font-size: 14px;
.td {
height: 32px;
}
`,
BaseCell: `
&:nth-of-type(1) {
text-align: center;
}
`,
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-top: 1px solid #565656;
border-bottom: 1px solid #565656;
}
&:hover .td {
border-top: 1px solid #177ac9;
border-bottom: 1px solid #177ac9;
}
&:nth-of-type(odd) .td {
background-color: #303030;
}
`
}),
[]
)
);
const onDialogClose = useCallback(() => {
setDialogOpen(false);
}, []);
const updateModuleItem = useCallback((updatedItem: ModuleItem) => {
void updateState(readModules(), (data: ModuleItem[]) => {
const new_data = data.map((mi) =>
mi.id === updatedItem.id ? { ...mi, ...updatedItem } : mi
);
setNumChanges(new_data.filter(hasModulesChanged).length);
return new_data;
});
}, []);
const onDialogSave = useCallback(
(updatedItem: ModuleItem) => {
setDialogOpen(false);
updateModuleItem(updatedItem);
},
[updateModuleItem]
);
const editModuleItem = useCallback((mi: ModuleItem) => {
setSelectedModuleItem(mi);
setDialogOpen(true);
}, []);
const onCancel = useCallback(async () => {
await fetchModules().then(() => {
setNumChanges(0);
});
}, [fetchModules]);
const saveModules = useCallback(async () => {
try {
await Promise.all(
modules.map((condensed_mi: ModuleItem) =>
updateModules({
key: condensed_mi.key,
enabled: condensed_mi.enabled,
license: condensed_mi.license
})
)
);
toast.success(LL.MODULES_UPDATED());
} catch (error) {
toast.error(error instanceof Error ? error.message : String(error));
} finally {
await fetchModules();
setNumChanges(0);
}
}, [modules, updateModules, LL, fetchModules]);
const content = useMemo(() => {
if (!modules) {
return (
);
}
if (modules.length === 0) {
return (
{LL.MODULES_NONE()}
);
}
return (
<>
{LL.MODULES_DESCRIPTION()}.
{(tableList: ModuleItem[]) => (
<>
{LL.NAME(0)}
Author
{LL.VERSION()}
Message
{LL.STATUS_OF('')}
{tableList.map((mi: ModuleItem) => (
editModuleItem(mi)}>
|
{mi.enabled ? (
) : (
)}
|
{mi.name} |
{mi.author} |
{mi.version} |
{mi.message} |
|
))}
>
)}
{numChanges !== 0 && (
}
variant="outlined"
onClick={onCancel}
color="secondary"
>
{LL.CANCEL()}
}
variant="contained"
color="info"
onClick={saveModules}
>
{LL.APPLY_CHANGES(numChanges)}
)}
>
);
}, [
modules,
fetchModules,
error,
modules_theme,
editModuleItem,
LL,
numChanges,
onCancel,
saveModules
]);
return (
{blocker ? : null}
{content}
{selectedModuleItem && (
)}
);
};
export default Modules;