Browse Source

added dynamic page no. for formCode

master
PC-20260115JRSN\Administrator 5 days ago
parent
commit
76972a125d
7 changed files with 565 additions and 64 deletions
  1. +13
    -2
      src/menu-items/setting.js
  2. +84
    -0
      src/pages/formSigPage/FormSigPageSearchForm.js
  3. +325
    -0
      src/pages/formSigPage/FormSigPageTable.js
  4. +78
    -0
      src/pages/formSigPage/index.js
  5. +51
    -62
      src/pages/pdf/PdfSearchPage/PdfTable.js
  6. +11
    -0
      src/routes/SettingRoutes.js
  7. +3
    -0
      src/utils/ApiPathConst.js

+ 13
- 2
src/menu-items/setting.js View File

@@ -13,7 +13,8 @@ import {
MenuUnfoldOutlined,
FileSearchOutlined,
MailOutlined,
ApartmentOutlined
ApartmentOutlined,
FilePdfOutlined
} from '@ant-design/icons';

// icons
@@ -31,7 +32,8 @@ const icons = {
MenuUnfoldOutlined,
FileSearchOutlined,
MailOutlined,
ApartmentOutlined
ApartmentOutlined,
FilePdfOutlined
};

// ==============================|| MENU ITEMS - EXTRA PAGES ||============================== //
@@ -141,6 +143,15 @@ const setting = {
breadcrumbs: false,
ability:['VIEW','USER']
},
{
id: 'formSigPage',
title: 'Form Sig Page',
type: 'item',
url: '/formSigPage',
icon: icons.FilePdfOutlined,
breadcrumbs: false,
ability:['MANAGE','SYSTEM_CONFIGURATION']
},
// {
// id: 'passwordPolicy',
// title: 'Password Policy',


+ 84
- 0
src/pages/formSigPage/FormSigPageSearchForm.js View File

@@ -0,0 +1,84 @@
import {
Button,
Grid,
InputLabel,
MenuItem,
TextField,
} from '@mui/material';
import MainCard from "../../components/MainCard";
import { useForm } from "react-hook-form";
import * as React from "react";
import { ThemeProvider } from "@emotion/react";
import { LIONER_BUTTON_THEME } from "../../themes/colorConst";
import { CARD_MAX_WIDTH } from "../../themes/themeConst";

const FORM_CODES = ['IDA', 'FNA', 'HSBCFIN', 'HSBCA31', 'MLB03S', 'MLFNA_EN', 'MLFNA_CHI', 'SLFNA_EN', 'SLFNA_CHI', 'SLAPP', 'SLGII'];
const SIG_TYPES = ['upload1', 'upload2'];

const FormSigPageSearchForm = ({ applySearch }) => {
const { reset, register, handleSubmit } = useForm();

const onSubmit = (data) => {
applySearch(data);
};

return (
<MainCard
xs={12}
md={12}
lg={12}
content={false}
sx={{ width: CARD_MAX_WIDTH }}
>
<form onSubmit={handleSubmit(onSubmit)}>
<Grid sx={{ mb: 2 }} />
<Grid container alignItems="center" spacing={2}>
<Grid item xs={12} sm={6} md={4} lg={3} sx={{ ml: 3, mr: 3 }}>
<InputLabel>Form Code</InputLabel>
<TextField
fullWidth
select
{...register("formCode")}
id="formCode"
>
<MenuItem value="">All</MenuItem>
{FORM_CODES.map((c) => (
<MenuItem key={c} value={c}>{c}</MenuItem>
))}
</TextField>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={3}>
<InputLabel>Sig Type</InputLabel>
<TextField
fullWidth
select
{...register("sigType")}
id="sigType"
>
<MenuItem value="">All</MenuItem>
{SIG_TYPES.map((t) => (
<MenuItem key={t} value={t}>{t}</MenuItem>
))}
</TextField>
</Grid>
</Grid>
<Grid container maxWidth justifyContent="flex-start" sx={{ mt: 2, mb: 2 }}>
<ThemeProvider theme={LIONER_BUTTON_THEME}>
<Grid item sx={{ ml: 3, mr: 1.5 }}>
<Button variant="contained" type="submit" color="save">
Search
</Button>
</Grid>
<Grid item>
<Button variant="outlined" type="button" onClick={() => { reset(); applySearch({}); }}>
Reset
</Button>
</Grid>
</ThemeProvider>
</Grid>
</form>
</MainCard>
);
};

export default FormSigPageSearchForm;

+ 325
- 0
src/pages/formSigPage/FormSigPageTable.js View File

@@ -0,0 +1,325 @@
import * as React from 'react';
import {
Button,
} from '@mui/material';
import {
DataGrid,
GridActionsCellItem,
GridRowEditStopReasons,
GridRowModes,
GridToolbarContainer
} from "@mui/x-data-grid";
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import dayjs from 'dayjs';
import EditIcon from '@mui/icons-material/Edit';
import DeleteIcon from '@mui/icons-material/DeleteOutlined';
import SaveIcon from '@mui/icons-material/Save';
import CancelIcon from '@mui/icons-material/Close';
import AddIcon from '@mui/icons-material/Add';
import axios from "axios";
import { apiPath } from "../../auth/utils";
import {
GET_FORM_SIG_PAGE_LIST,
UPDATE_FORM_SIG_PAGE_PATH,
} from "../../utils/ApiPathConst";
import {
CustomNoRowsOverlay,
GeneralConfirmWindow,
notifyDeleteError,
notifyDeleteSuccess,
notifySaveSuccess,
removeObjectWithId
} from "../../utils/CommonFunction";
import UploadContext from "../../components/UploadProvider";
import { LIONER_BUTTON_THEME } from "../../themes/colorConst";
import { ThemeProvider } from "@emotion/react";

const FORM_CODES = ['IDA', 'FNA', 'HSBCFIN', 'HSBCA31', 'MLB03S', 'MLFNA_EN', 'MLFNA_CHI', 'SLFNA_EN', 'SLFNA_CHI', 'SLAPP', 'SLGII'];
const SIG_TYPES = ['upload1', 'upload2'];
const ACTIONS = ['REPLACE', 'SKIP_AND_APPEND'];

let newRowId = -1;

function normalizeStartDate(value) {
if (value == null || value === '') return '';
if (dayjs.isDayjs(value)) return value.format('YYYY-MM-DD');
const d = dayjs(value);
return d.isValid() ? d.format('YYYY-MM-DD') : String(value);
}

function toDayjsOrNull(value) {
if (value == null || value === '') return null;
if (dayjs.isDayjs(value)) return value;
if (typeof value === 'string') {
const d = dayjs(value);
return d.isValid() ? d : null;
}
if (Array.isArray(value) && value.length >= 3) {
const y = value[0];
const m = String(value[1]).padStart(2, '0');
const d = dayjs(`${y}-${m}-${String(value[2]).padStart(2, '0')}`);
return d.isValid() ? d : null;
}
if (typeof value === 'object' && value.year != null && value.month != null && value.day != null) {
const d = dayjs(`${value.year}-${String(value.month).padStart(2, '0')}-${String(value.day).padStart(2, '0')}`);
return d.isValid() ? d : null;
}
const d = dayjs(value);
return d.isValid() ? d : null;
}

function formatStartDate(value) {
const d = toDayjsOrNull(value);
return d ? d.format('YYYY-MM-DD') : '';
}

function EditToolbar({ setRows, setRowModesModel }) {
const handleClick = () => {
const id = newRowId--;
setRows((oldRows) => [
{
id,
formCode: 'IDA',
startDate: '2000-01-01',
sigType: 'upload1',
pageFrom: 1,
pageTo: 1,
action: 'REPLACE',
isNew: true,
},
...oldRows,
]);
setRowModesModel((oldModel) => ({
...oldModel,
[id]: { mode: GridRowModes.Edit, fieldToFocus: 'formCode' },
}));
};

return (
<GridToolbarContainer sx={{ ml: 1 }}>
<Button color="primary" startIcon={<AddIcon />} onClick={handleClick}>
Add Form Sig Page
</Button>
</GridToolbarContainer>
);
}

export default function FormSigPageTable({ recordList }) {
const [rows, setRows] = React.useState([]);
const [rowModesModel, setRowModesModel] = React.useState({});
const { setIsUploading } = React.useContext(UploadContext);
const [isWindowOpen, setIsWindowOpen] = React.useState(false);
const [selectedId, setSelectedId] = React.useState(null);
const [paginationModel, setPaginationModel] = React.useState({ page: 0, pageSize: 10 });

React.useEffect(() => {
setPaginationModel({ page: 0, pageSize: 10 });
setRows(recordList || []);
}, [recordList]);

const handleClose = () => setIsWindowOpen(false);

const handleDeleteClick = (id) => () => {
setIsWindowOpen(true);
setSelectedId(id);
};

const updateData = () => {
setIsUploading(true);
axios
.delete(`${apiPath}${GET_FORM_SIG_PAGE_LIST}/${selectedId}`)
.then((response) => {
if (response.status === 204) {
notifyDeleteSuccess();
setRows((prev) => removeObjectWithId(prev, selectedId));
setIsWindowOpen(false);
}
setIsUploading(false);
})
.catch((err) => {
console.error(err);
notifyDeleteError(err?.response?.data?.message || 'Delete failed');
setIsUploading(false);
});
};

const handleRowEditStop = (params, event) => {
if (params.reason === GridRowEditStopReasons.rowFocusOut) {
event.defaultMuiPrevented = true;
}
};

const handleEditClick = (id) => () => {
setRowModesModel((prev) => ({ ...prev, [id]: { mode: GridRowModes.Edit, fieldToFocus: 'formCode' } }));
};

const handleSaveClick = (id) => () => {
setRowModesModel((prev) => ({ ...prev, [id]: { mode: GridRowModes.View } }));
};

const handleCancelClick = (id) => () => {
setRowModesModel((prev => {
const next = { ...prev, [id]: { mode: GridRowModes.View, ignoreModifications: true } };
return next;
}));
const editedRow = rows.find((r) => r.id === id);
if (editedRow?.isNew) {
setRows((prev) => prev.filter((r) => r.id !== id));
}
};

const processRowUpdate = (newRow) => {
const isCreate = newRow.isNew === true || newRow.id == null || Number(newRow.id) <= 0;
const payload = {
formCode: newRow.formCode,
startDate: normalizeStartDate(newRow.startDate),
sigType: newRow.sigType,
pageFrom: Number(newRow.pageFrom),
pageTo: Number(newRow.pageTo),
action: newRow.action,
};
if (!isCreate) payload.id = Number(newRow.id);

return new Promise((resolve, reject) => {
if (!payload.formCode || !payload.startDate || !payload.sigType ||
payload.pageFrom == null || payload.pageTo == null || !payload.action) {
reject(new Error('All fields are required'));
return;
}
if (payload.pageFrom > payload.pageTo) {
reject(new Error('pageFrom must be <= pageTo'));
return;
}
setIsUploading(true);
axios
.post(`${apiPath}${UPDATE_FORM_SIG_PAGE_PATH}`, payload)
.then((res) => {
const savedId = res.data?.id;
const updatedRow = { ...newRow, id: savedId != null ? savedId : newRow.id, isNew: false };
setRows((prev) => prev.map((r) => (r.id === newRow.id ? updatedRow : r)));
notifySaveSuccess();
setIsUploading(false);
resolve(updatedRow);
})
.catch((err) => {
setIsUploading(false);
notifyDeleteError(err?.response?.data?.message || 'Save failed');
reject(err);
});
});
};

const columns = [
{
field: 'actions',
type: 'actions',
headerName: 'Actions',
width: 120,
getActions: ({ id }) => {
const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit;
if (isInEditMode) {
return [
<ThemeProvider key="cancel" theme={LIONER_BUTTON_THEME}>
<GridActionsCellItem icon={<CancelIcon />} label="Cancel" onClick={handleCancelClick(id)} color="delete" />,
</ThemeProvider>,
<ThemeProvider key="save" theme={LIONER_BUTTON_THEME}>
<GridActionsCellItem icon={<SaveIcon />} label="Save" onClick={handleSaveClick(id)} color="save" />,
</ThemeProvider>,
];
}
return [
<ThemeProvider key="delete" theme={LIONER_BUTTON_THEME}>
<GridActionsCellItem icon={<DeleteIcon />} label="Delete" onClick={handleDeleteClick(id)} color="delete" />,
</ThemeProvider>,
<ThemeProvider key="edit" theme={LIONER_BUTTON_THEME}>
<GridActionsCellItem icon={<EditIcon />} label="Edit" onClick={handleEditClick(id)} color="edit" />,
</ThemeProvider>,
];
},
},
{
field: 'formCode',
headerName: 'Form Code',
width: 120,
editable: true,
type: 'singleSelect',
valueOptions: FORM_CODES,
},
{
field: 'startDate',
headerName: 'Start Date',
width: 140,
editable: true,
valueGetter: (params) => formatStartDate(params.row?.startDate),
renderCell: (params) => formatStartDate(params.row?.startDate),
renderEditCell: (params) => (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DatePicker
value={toDayjsOrNull(params.row?.startDate)}
onChange={(d) =>
params.api.setEditCellValue({
id: params.id,
field: params.field,
value: d ? d.format('YYYY-MM-DD') : '',
})
}
slotProps={{ textField: { size: 'small', fullWidth: true } }}
/>
</LocalizationProvider>
),
},
{
field: 'sigType',
headerName: 'Sig Type',
width: 90,
editable: true,
type: 'singleSelect',
valueOptions: SIG_TYPES,
},
{ field: 'pageFrom', headerName: 'Page From', type: 'number', width: 95, editable: true },
{ field: 'pageTo', headerName: 'Page To', type: 'number', width: 95, editable: true },
{
field: 'action',
headerName: 'Action',
width: 140,
editable: true,
type: 'singleSelect',
valueOptions: ACTIONS,
},
];

return (
<div style={{ width: '100%' }}>
<DataGrid
rows={rows}
columns={columns}
columnHeaderHeight={45}
editMode="row"
rowModesModel={rowModesModel}
onRowModesModelChange={setRowModesModel}
onRowEditStop={handleRowEditStop}
processRowUpdate={processRowUpdate}
onProcessRowUpdateError={(err) => notifyDeleteError(err?.message || 'Update failed')}
getRowHeight={() => 'auto'}
paginationModel={paginationModel}
onPaginationModelChange={setPaginationModel}
pageSizeOptions={[10, 25, 50]}
slots={{
toolbar: EditToolbar,
noRowsOverlay: () => CustomNoRowsOverlay(),
}}
slotProps={{ toolbar: { setRows, setRowModesModel } }}
autoHeight
/>
<GeneralConfirmWindow
isWindowOpen={isWindowOpen}
title="Delete Form Sig Page"
content="Are you sure you want to delete this record?"
onNormalClose={handleClose}
onConfirmClose={updateData}
/>
</div>
);
}

+ 78
- 0
src/pages/formSigPage/index.js View File

@@ -0,0 +1,78 @@
import {
Box,
Grid,
Typography
} from '@mui/material';
import MainCard from "../../components/MainCard";
import FormSigPageSearchForm from "./FormSigPageSearchForm";
import FormSigPageTable from "./FormSigPageTable";
import { useEffect, useState } from "react";
import * as React from "react";
import axios from "axios";
import { apiPath } from "../../auth/utils";
import { GET_FORM_SIG_PAGE_LIST } from "../../utils/ApiPathConst";
import LoadingComponent from "../extra-pages/LoadingComponent";
import { LIONER_FORM_THEME, CARD_MAX_WIDTH } from "../../themes/themeConst";
import { ThemeProvider } from "@emotion/react";

const FormSigPageSearchPanel = () => {
const [record, setRecord] = useState([]);
const [searchCriteria, setSearchCriteria] = useState({});
const [onReady, setOnReady] = useState(false);

const fetchList = () => {
const params = {};
if (searchCriteria.formCode) params.formCode = searchCriteria.formCode;
if (searchCriteria.sigType) params.sigType = searchCriteria.sigType;
axios
.get(`${apiPath}${GET_FORM_SIG_PAGE_LIST}`, { params })
.then((response) => {
if (response.status === 200 && response.data?.records) {
setRecord(response.data.records);
}
})
.catch((err) => {
console.error(err);
});
};

useEffect(() => {
fetchList();
}, [searchCriteria]);

useEffect(() => {
setOnReady(true);
}, [record]);

const applySearch = (input) => {
setSearchCriteria(input || {});
};

if (!onReady) return <LoadingComponent />;

return (
<Grid container rowSpacing={3} columnSpacing={2.75}>
<ThemeProvider theme={LIONER_FORM_THEME}>
<Grid item xs={12} md={12} lg={12} sx={{ mt: -1 }}>
<Grid container justifyContent="flex-start" alignItems="center">
<Grid item xs={3} sx={{ mb: -2.25 }}>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Typography variant="h5">Form Signature Page Config</Typography>
</Box>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} md={12} lg={12}>
<FormSigPageSearchForm applySearch={applySearch} />
</Grid>
<Grid item xs={12} md={12} lg={12} sx={{ mt: { lg: -1.5 } }}>
<MainCard elevation={0} content={false} sx={{ width: CARD_MAX_WIDTH }}>
<FormSigPageTable recordList={record} />
</MainCard>
</Grid>
</ThemeProvider>
</Grid>
);
};

export default FormSigPageSearchPanel;

+ 51
- 62
src/pages/pdf/PdfSearchPage/PdfTable.js View File

@@ -1,7 +1,7 @@
// material-ui
import * as React from 'react';
import {apiPath} from "../../../auth/utils";
import { POST_SIG_UPLOAD1 } from "../../../utils/ApiPathConst";
import { POST_SIG_UPLOAD1, GET_FORM_SIG_PAGE_CONFIG } from "../../../utils/ApiPathConst";
import axios from 'axios';
import {
DataGrid,
@@ -50,6 +50,7 @@ export default function PdfTable({recordList}) {
const [isDialogOpen, setIsDialogOpen] = React.useState(false);
// State to hold the ID, templateName, and refType for the current upload operation
const [currentUploadRow, setCurrentUploadRow] = React.useState(initialUploadState);
const [currentUploadLabel, setCurrentUploadLabel] = React.useState(null);
const [isUploading, setIsUploading] = React.useState(false);

const navigate = useNavigate()
@@ -72,32 +73,63 @@ export default function PdfTable({recordList}) {
navigate(`/pdf/maintain/${id}`);
};

/** Safely get YYYY-MM-DD from row.created; returns null if missing or invalid. */
const getAsOfDateString = (row) => {
const raw = row?.created;
if (raw == null || raw === "") return null;
const d = new Date(raw);
if (Number.isNaN(d.getTime())) return null;
return d.toISOString().slice(0, 10);
};

/**
* Opens the upload dialog and sets the current row details for Upload 1
* Opens the upload dialog and sets the current row details for Upload 1.
* Fetches form-sig-page config from API for dynamic label (page number).
*/
const handleUploadClick = (id, templateName, formCode) => () => {
const handleUploadClick = (id, templateName, formCode, row) => () => {
setCurrentUploadRow({
id: id,
templateName: templateName,
formCode: formCode,
refType: "upload1"
});
setCurrentUploadLabel(null);
setIsDialogOpen(true);
const asOfDate = getAsOfDateString(row);
const params = new URLSearchParams({ formCode });
if (asOfDate) params.set("asOfDate", asOfDate);
axios.get(`${apiPath}${GET_FORM_SIG_PAGE_CONFIG}?${params}`)
.then((res) => {
const configs = res.data?.configs || [];
const upload1 = configs.find((c) => c.sigType === "upload1");
setCurrentUploadLabel(upload1?.label || "Upload Signature");
})
.catch(() => setCurrentUploadLabel("Upload Signature"));
};

/**
* Opens the upload dialog and sets the current row details for Upload 2
* Opens the upload dialog and sets the current row details for Upload 2.
* Fetches form-sig-page config from API for dynamic label.
*/
const handleUpload2Click = (id, templateName, formCode) => () => {
// Placeholder for Upload 2
console.log(`Uploading for row ID ${id} (Upload 2)`);
setCurrentUploadRow({
const handleUpload2Click = (id, templateName, formCode, row) => () => {
setCurrentUploadRow({
id: id,
templateName: templateName,
formCode: formCode,
refType: "upload2" // A different refType for a different upload logic/API
refType: "upload2"
});
setIsDialogOpen(true);
setCurrentUploadLabel(null);
setIsDialogOpen(true);
const asOfDate = getAsOfDateString(row);
const params = new URLSearchParams({ formCode });
if (asOfDate) params.set("asOfDate", asOfDate);
axios.get(`${apiPath}${GET_FORM_SIG_PAGE_CONFIG}?${params}`)
.then((res) => {
const configs = res.data?.configs || [];
const upload2 = configs.find((c) => c.sigType === "upload2");
setCurrentUploadLabel(upload2?.label || "Upload 2");
})
.catch(() => setCurrentUploadLabel("Upload 2"));
};

/**
@@ -198,60 +230,18 @@ export default function PdfTable({recordList}) {

const handleCloseDialog = () => {
setIsDialogOpen(false);
setCurrentUploadRow(initialUploadState); // Reset the current row
setCurrentUploadRow(initialUploadState);
setCurrentUploadLabel(null);
if (fileInputRef.current) {
fileInputRef.current.value = ""; // Clear the file input
}
};

// Function to generate the dynamic dialog title
// Fallback dialog title when API config is not yet loaded or fails
const getUploadDialogTitle = (formCode, refType) => {
console.log("formCode:" + formCode + " refType:" + refType);
if (refType === 'upload1') {
switch (formCode) {
case "IDA":
return "Upload Page 15";
case "FNA":
return "Upload Page 10";
case "HSBCFIN":
return "Upload Page 11";
case "HSBCA31":
return "Upload Page 28-29";
case "MLB03S":
return "Upload Page 9";
case "MLFNA_EN":
return "Upload Page 4";
case "MLFNA_CHI":
return "Upload Page 4";
case "SLGII":
return "Upload Page 13";
case "SLAPP":
return "Upload Page 17";
case "SLFNA_EN":
return "Upload Page 5";
case "SLFNA_CHI":
return "Upload Page 5";
default:
return "Unknown Form";
}
}else if (refType === 'upload2') {
switch (formCode) {
case "MLB03S":
return "Upload Page 12-13";
case "SLGII":
return "Upload Page 15-16";
case "SLAPP":
return "Upload Page 19-20";
default:
return "Unknown Form";
}
}
// Handle other refTypes if needed, e.g., 'upload2'
if (refType === 'upload2') {
return `Upload Template 2 for ${formCode}`;
}

return "Upload File"; // Fallback
if (refType === "upload1") return "Upload Signature";
if (refType === "upload2") return "Upload 2";
return "Upload File";
};
// Function to handle file selection and API submission
@@ -401,7 +391,7 @@ export default function PdfTable({recordList}) {
icon={upload1Icon} // Use the dynamic icon
label={upload1Label} // Use the dynamic label
className="textPrimary"
onClick={handleUploadClick(id, templateName, formCode)}
onClick={handleUploadClick(id, templateName, formCode, row)}
color="upload"
/>
</ThemeProvider>
@@ -423,7 +413,7 @@ export default function PdfTable({recordList}) {
icon={upload2Icon}
label={upload2Label}
className="textPrimary"
onClick={handleUpload2Click(id, templateName, formCode)}
onClick={handleUpload2Click(id, templateName, formCode, row)}
color="upload"
/>
</ThemeProvider>
@@ -551,8 +541,7 @@ export default function PdfTable({recordList}) {
TransitionProps={{ onExited: handleCloseDialog }}
>
<DialogTitle>
{/* Dynamic Title based on currentUploadRow state */}
**{getUploadDialogTitle(currentUploadRow.formCode, currentUploadRow.refType)}**
{currentUploadLabel != null ? currentUploadLabel : getUploadDialogTitle(currentUploadRow.formCode, currentUploadRow.refType)}
</DialogTitle>
<DialogContent dividers>
<Box sx={{ mt: 2, textAlign: 'center' }}>


+ 11
- 0
src/routes/SettingRoutes.js View File

@@ -29,6 +29,7 @@ const EmailConfigPage = Loadable(lazy(() => import('pages/lionerEmailConfig')));
const GenerateReminderPage = Loadable(lazy(() => import('pages/lionerManualButtonPage')));
const ClientDepartmentPage = Loadable(lazy(() => import('pages/lionerClientDepartmentPage')));
const ProfilePage = Loadable(lazy(() => import('pages/profile/profile')));
const FormSigPageSearchPanel = Loadable(lazy(() => import('pages/formSigPage')));

// ==============================|| AUTH ROUTING ||============================== //

@@ -260,6 +261,16 @@ const SettingRoutes = () => {
)
),
},
{
path: 'formSigPage',
element: (
handleRouteAbility(
ability.can('MANAGE', 'SYSTEM_CONFIGURATION'),
<FormSigPageSearchPanel />,
<Navigate to="/" />
)
),
},
{
path: 'logout',
element: <LogoutPage />


+ 3
- 0
src/utils/ApiPathConst.js View File

@@ -72,6 +72,9 @@ export const GET_PDF_TEMPLATE_PATH = "/pdf/template"
export const GET_MERGE_PDF = "/pdf/merge-pdf"
export const GET_REMOVE_PDF_PASSWORD = "/pdf/remove-pdf-password"
export const POST_SIG_UPLOAD1 = "/pdf/upload1"
export const GET_FORM_SIG_PAGE_CONFIG = "/pdf/form-sig-page-config"
export const GET_FORM_SIG_PAGE_LIST = "/pdf/form-sig-page"
export const UPDATE_FORM_SIG_PAGE_PATH = "/pdf/form-sig-page/save"
export const GET_CLIENT_PATH = "/client"
export const POST_CLIENT_PATH = "/client/save"
export const GET_EVENT_PATH = "/event"


Loading…
Cancel
Save