@@ -68,7 +68,7 @@ const AutoLogoutProvider = ({ children }) => { | |||
} = useIdleTimer({ | |||
onIdle, | |||
onActive, | |||
timeout: 10_000, | |||
timeout: 60_000, | |||
throttle: 500, | |||
crossTab: true, | |||
syncTimers: 200, | |||
@@ -1,13 +1,17 @@ | |||
// assets | |||
import BoyIcon from '@mui/icons-material/Boy'; | |||
import AssignmentIcon from '@mui/icons-material/Assignment'; | |||
// icons | |||
const ClientIcon = () => { | |||
return ( | |||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', marginLeft: '-4px' }}> | |||
<BoyIcon fontSize="medium"/> | |||
</div> | |||
); | |||
const icons = { | |||
ClientIcon : () => { return ( | |||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', marginLeft: '-4px' }}> | |||
<BoyIcon fontSize="medium"/> | |||
</div> | |||
) | |||
}, | |||
AssignmentIcon, | |||
}; | |||
// ==============================|| MENU ITEMS - DASHBOARD ||============================== // | |||
@@ -19,14 +23,23 @@ const client = { | |||
//ability:['SUPPRESS','REMINDER'], | |||
children: [ | |||
{ | |||
id: 'Client', | |||
id: 'client', | |||
title: 'Client', | |||
type: 'item', | |||
url: '/client', | |||
icon: ClientIcon, | |||
icon: icons.ClientIcon, | |||
breadcrumbs: false, | |||
ability:['VIEW','DASHBOARD'] | |||
}, | |||
// { | |||
// id: 'template', | |||
// title: 'Template', | |||
// type: 'item', | |||
// url: '/template', | |||
// icon: icons.AssignmentIcon, | |||
// breadcrumbs: false, | |||
// ability:['VIEW','DASHBOARD'] | |||
// }, | |||
] | |||
}; | |||
@@ -32,7 +32,8 @@ const dashboard = { | |||
id: 'lionerdashboard', | |||
title: <FormattedMessage id="Dashboard"/>, | |||
type: 'item', | |||
url: '/lionerDashboard', | |||
url: '/client', | |||
// url: '/lionerDashboard', | |||
icon: icons.SpeedIcon, | |||
breadcrumbs: false, | |||
ability:['VIEW','DASHBOARD'] | |||
@@ -12,7 +12,8 @@ import appreciation from "./appreciation"; | |||
// ==============================|| MENU ITEMS ||============================== // | |||
const menuItems = { | |||
items: [dashboard, client, setting] | |||
items: [client, setting] | |||
// items: [dashboard, client, setting] | |||
}; | |||
// pages, utilities, support, misc | |||
@@ -86,15 +86,15 @@ const setting = { | |||
// breadcrumbs: false, | |||
// ability:['MAINTAIN','CLIENT_DEPARTMENT'] | |||
// }, | |||
{ | |||
id: 'userGroup', | |||
title: 'User Group', | |||
type: 'item', | |||
url: '/usergroupSearchview', | |||
icon: icons.UsergroupAddOutlined, | |||
breadcrumbs: false, | |||
ability:['MAINTAIN','USER_GROUP'] | |||
}, | |||
// { | |||
// id: 'userGroup', | |||
// title: 'User Group', | |||
// type: 'item', | |||
// url: '/usergroupSearchview', | |||
// icon: icons.UsergroupAddOutlined, | |||
// breadcrumbs: false, | |||
// ability:['MAINTAIN','USER_GROUP'] | |||
// }, | |||
{ | |||
id: 'user', | |||
title: 'User', | |||
@@ -1012,14 +1012,15 @@ const ClientForm = ({ refClientDetail, | |||
</Grid> | |||
<Grid item sx={{ml:{xs:1.5,md:1.5,lg:1.5}, mr:3, mb:1, mt:2}}> | |||
<Button | |||
{!isNewRecord && (<Button | |||
variant="contained" | |||
color="delete" | |||
disabled={isNewRecord || !ability.can('DELETE','EVENT')} | |||
disabled={!ability.can('DELETE','EVENT')} | |||
onClick={handleDeleteClick} | |||
> | |||
Delete | |||
</Button> | |||
)} | |||
<GeneralConfirmWindow | |||
isWindowOpen={isWindowOpen} | |||
title={"Attention"} | |||
@@ -91,15 +91,22 @@ export default function ClientTable({recordList}) { | |||
id: 'fullname', | |||
field: 'fullname', | |||
headerName: 'Client Name', | |||
flex: 2, | |||
flex: 1.5, | |||
renderCell: (params) => { | |||
return ( | |||
<div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> | |||
{params.row.title ? `(${params.row.title})` : ''} {params.value} | |||
{params.value} | |||
{/* {params.row.title ? `(${params.row.title})` : ''} {params.value} */} | |||
</div> | |||
); | |||
} | |||
}, | |||
{ | |||
id: 'title', | |||
field: 'title', | |||
headerName: 'Title', | |||
flex: 1.5, | |||
}, | |||
{ | |||
id: 'joinDate', | |||
field: 'joinDate', | |||
@@ -1,8 +1,8 @@ | |||
import React, { useEffect, useRef, useState } from 'react'; | |||
import { Button, Grid } from '@mui/material'; | |||
import { Button, Grid, InputLabel, TextField } from '@mui/material'; | |||
import { GeneralConfirmWindow, notifySaveSuccess } from "../../../utils/CommonFunction"; | |||
import axios from 'axios'; | |||
import {apiPath, appURL} from "../../../auth/utils"; | |||
import {apiPath, adobeAPIKey} from "../../../auth/utils"; | |||
import { | |||
GET_PDF_TEMPLATE_PATH, | |||
GET_PDF_PATH, | |||
@@ -16,14 +16,19 @@ import {useLocation, useParams} from "react-router-dom"; | |||
// Import your chosen commercial PDF SDK (e.g., PSPDFKit) | |||
import PSPDFKit from 'pspdfkit'; | |||
import WebViewer from '@compdfkit_pdf_sdk/webviewer'; | |||
import Nutrient from "@nutrient-sdk/viewer"; | |||
import { CollectionsBookmarkRounded } from '../../../../node_modules/@mui/icons-material/index'; | |||
import LoadingComponent from "../../extra-pages/LoadingComponent"; | |||
import { fill } from 'lodash'; | |||
function PDF() { | |||
const viewerRef = useRef(null); // Ref for the DOM element where PDF will render | |||
const [pdfLoaded, setPdfLoaded] = useState(false); | |||
const [viewerLoaded, setViewerLoaded] = useState(false); | |||
const [viewInstance,setViewInstance] = useState(); | |||
const [pdfBytes, setPdfBytes] = useState(); | |||
const [adobeDCView,setAdobeDCView] = useState(); | |||
const [pdfUrl, setPdfUrl] = useState(); | |||
const [record, setRecord] = useState(); | |||
const navigate = useNavigate() | |||
@@ -32,7 +37,7 @@ function PDF() { | |||
const queryParams = new URLSearchParams(location.search); | |||
const refId = queryParams.get("refId"); | |||
const loadPdfForm = async (id, templateId = 0) => { | |||
const loadPdfForm = async (id, templateId = 0, clientId = 0) => { | |||
if (!pdfLoaded) { | |||
if (id > 0) { | |||
// axios.get(`${apiPath}${GET_PDF_TEMPLATE_PATH}`, { | |||
@@ -60,7 +65,7 @@ function PDF() { | |||
byteNum[i] = byteChar.charCodeAt(i); | |||
} | |||
setPdfBytes(byteNum); | |||
handlePdfUrl(byteNum); | |||
setPdfLoaded(true); | |||
} | |||
}) | |||
@@ -71,11 +76,16 @@ function PDF() { | |||
} else { | |||
axios.get(`${apiPath}${GET_PDF_TEMPLATE_PATH}`, { | |||
// axios.get(`${apiPath}${GET_PDF_TEMPLATE_PATH}/${templateId}`, { | |||
responseType: 'arraybuffer', // Essential for binary data | |||
params: { | |||
templateId: templateId, | |||
clientId: clientId, | |||
}, | |||
}) | |||
.then((response) => { | |||
if (response.status === 200) { | |||
setPdfBytes(response.data); | |||
handlePdfUrl(response.data); | |||
setPdfLoaded(true); | |||
} | |||
}) | |||
@@ -87,66 +97,72 @@ function PDF() { | |||
} | |||
}; | |||
const handlePdfUrl = (pdfBytes) => { | |||
const pdfBlob = new Blob([pdfBytes], { type: 'application/pdf' }); | |||
// const pdfFile = new File([pdfBlob], 'document.pdf', { type: 'application/pdf' }); | |||
console.log(pdfBlob); | |||
const pdfUrl = URL.createObjectURL(pdfBlob); | |||
setPdfUrl(pdfUrl); | |||
} | |||
const loadPdfViewer = async () => { | |||
if (pdfLoaded && viewerRef.current && !viewerLoaded) { | |||
if (pdfLoaded && viewerRef.current && !viewerLoaded && !adobeDCView) { | |||
try { | |||
//New try | |||
const pdfBlob = new Blob([pdfBytes], { type: 'application/pdf' }); | |||
console.log(pdfBlob); | |||
const pdfUrl = URL.createObjectURL(pdfBlob); | |||
// console.log('Template: '); | |||
// console.log(record); | |||
// console.log('URL: '); | |||
// console.log(pdfUrl); | |||
// console.log('Viewer: '); | |||
// console.log(viewerRef.current); | |||
// await PSPDFKit.unload(viewerRef.current); | |||
await PSPDFKit.load({//click into load | |||
container: viewerRef.current, | |||
// container: '#viewer', | |||
document: pdfUrl, | |||
// baseUrl: `./sdk/`, // Path to SDK assets | |||
baseUrl: `${appURL}/sdk/`, // Path to SDK | |||
// baseUrl: `${window.location.protocol}//${window.location.host}/${import.meta.env.BASE_URL}`, | |||
// baseUrl: `https://cdn.jsdelivr.net/npm/pspdfkit@VERSION/dist/`, // Path to SDK assets so this is work? | |||
// baseUrl: `${process.env.PUBLIC_URL}/`, // Path to SDK assets | |||
disableWebAssemblyStreaming: true, | |||
initialViewState: new PSPDFKit.ViewState({ | |||
sidebarMode: PSPDFKit.SidebarMode.THUMBNAILS | |||
}) | |||
}) | |||
.then(instance => { | |||
URL.revokeObjectURL(pdfUrl); | |||
setViewInstance(instance); | |||
console.log('instance: '); | |||
console.log(instance); | |||
setViewerLoaded(true); | |||
// instance.addEventListener("formFields.load", (loadedFormFields) => { | |||
// console.log("loaded fields:", loadedFormFields); | |||
// }); | |||
const formFieldValues = instance.getFormFieldValues(); | |||
// console.log(formFieldValues); // => { textField: 'Text Value', checkBoxField: ['A', 'B'], buttonField: null }e.log(getFormFieldValues); | |||
}); | |||
// instanceRef.current = instance; | |||
// 3. Clean up on component unmount | |||
// return () => { | |||
// if (instance) { | |||
// instance.unload(); // Unload SDK instance | |||
// } | |||
// URL.revokeObjectURL(pdfUrl); // Revoke the Blob URL | |||
// }; | |||
loadAdobeSDK(); | |||
} catch (error) { | |||
console.error('Error loading PDF:', error); | |||
} | |||
} | |||
}; | |||
const loadAdobeSDK = async() => { | |||
// const token = localStorage.getItem('accessToken'); | |||
if (window.AdobeDC) { | |||
const DCViewer = (new window.AdobeDC.View({ | |||
clientId: `${adobeAPIKey}`, | |||
divId: 'adobe-dc-view', | |||
})); | |||
setAdobeDCView(DCViewer); | |||
await DCViewer.previewFile( | |||
{ | |||
content: { | |||
location: { | |||
url: pdfUrl, | |||
// headers: [{ key: 'Authorization', value: `Bearer ${token}` }], | |||
}, | |||
}, | |||
metaData: { fileName: 'document.pdf'/*templateName */ }, | |||
}, | |||
{ | |||
embedMode: 'FULL_WINDOW', | |||
showAnnotationTools: true, | |||
enableFormFilling: true, | |||
} | |||
).catch(error => { | |||
console.error('Preview error:', error); | |||
setError('Failed to load PDF: ' + error.message); | |||
}).then(instance => { | |||
URL.revokeObjectURL(pdfUrl); | |||
setViewInstance(instance); | |||
console.log('Instance: ', instance); | |||
setViewerLoaded(true); | |||
}); | |||
DCViewer.registerCallback( | |||
window.AdobeDC.View.Enum.CallbackType.SAVE_API, | |||
handleSavePdf, | |||
{ autoSaveFrequency: 0, enableFormFilling: true } | |||
); | |||
} else { | |||
console.error('AdobeDC not available'); | |||
setError('Adobe SDK not loaded'); | |||
} | |||
}; | |||
useEffect(() => { | |||
if (params.id !== null) { | |||
const pdfData = (params.id).split("T"); | |||
@@ -154,53 +170,61 @@ function PDF() { | |||
if (pdfData[0] > 0) { // Existing Record | |||
loadPdfForm(pdfData[0]); | |||
} else { // New Record | |||
const clientId = pdfData[0] * -1; | |||
const templateId = pdfData[1] * 1; | |||
setRecord({ | |||
id: -1, | |||
clientId: pdfData[0] * -1, //If PDF ID is negative, convert it to client ID | |||
templateId: pdfData[1],}); | |||
loadPdfForm(-1, pdfData[1]); // Load new Template | |||
clientId: clientId, //If PDF ID is negative, convert it to client ID | |||
templateId: templateId}); | |||
loadPdfForm(-1, templateId, clientId); // Load new Template | |||
} | |||
} | |||
}, [params.id]); | |||
// useEffect(() => { | |||
// if (record) { | |||
// console.log(record); | |||
// loadPdfForm(); | |||
// } | |||
// }, [record]); | |||
useEffect(() => { // Update Save function callback after record is updated | |||
console.log("Record Updated: ",record); | |||
if (record && adobeDCView) { | |||
adobeDCView.registerCallback( | |||
window.AdobeDC.View.Enum.CallbackType.SAVE_API, | |||
handleSavePdf, | |||
{ autoSaveFrequency: 0, enableFormFilling: true } | |||
); | |||
} | |||
}, [record]); | |||
useEffect(() => { | |||
loadPdfViewer(); | |||
}, [viewerRef.current, pdfLoaded]); | |||
const handleSavePdf = async () => { | |||
if (viewInstance) { | |||
try { | |||
// Export the filled PDF from the SDK as an ArrayBuffer | |||
const arrayBuffer = await viewInstance.exportPDF(); | |||
const filledPdfBlob = new Blob([arrayBuffer], { type: 'application/pdf' }); | |||
// Create FormData to send the file to Spring Boot | |||
const formData = new FormData(); | |||
formData.append('file', filledPdfBlob, 'filled_form.pdf'); | |||
formData.append('record', JSON.stringify(record)); | |||
// Send the filled PDF to your Spring Boot backend's save endpoint | |||
const response = await axios.post(`${apiPath}${POST_PDF_PATH}`, formData, { | |||
headers: { | |||
'Content-Type': 'multipart/form-data' // Important for file uploads | |||
}, | |||
}); | |||
const handleSavePdf = async (metaData, content, options) => { | |||
try { | |||
const filledPdfBlob = new Blob([content], { type: 'application/pdf' }); | |||
// Create FormData to send the file to Spring Boot | |||
const formData = new FormData(); | |||
formData.append('file', filledPdfBlob, 'filled_form.pdf'); | |||
formData.append('record', JSON.stringify(record)); | |||
// Send the filled PDF to your Spring Boot backend's save endpoint | |||
await axios.post(`${apiPath}${POST_PDF_PATH}`, formData, { | |||
headers: { | |||
'Content-Type': 'multipart/form-data' // Important for file uploads | |||
}, | |||
}) | |||
.then(response => { | |||
console.log('PDF saved on server:', response.data); | |||
notifySaveSuccess(); | |||
if (viewerLoaded) { | |||
await PSPDFKit.unload(viewerRef.current); | |||
} | |||
navigate(`/pdf/${record.clientId}`); | |||
} catch (error) { | |||
console.error('Error saving PDF:', error); | |||
alert('Failed to save PDF.'); | |||
} | |||
setRecord({ | |||
id: response.data.data.id, | |||
clientId: record.clientId, | |||
templateId: record.templateId | |||
}); | |||
notifySaveSuccess()}); | |||
return { | |||
code: window.AdobeDC.View.Enum.ApiResponseCode.SUCCESS, | |||
data: { metaData } // Return metaData to prevent t.data undefined | |||
}; | |||
} catch (error) { | |||
console.error('Error saving PDF:', error); | |||
alert('Failed to save PDF.'); | |||
return { code: window.AdobeDC.View.Enum.ApiResponseCode.FAIL }; | |||
} | |||
}; | |||
@@ -224,11 +248,22 @@ function PDF() { | |||
const handleBack = async () => { | |||
if (viewerLoaded) { | |||
await PSPDFKit.unload(viewerRef.current); | |||
await Nutrient.unload(viewerRef.current); | |||
} | |||
navigate(`/pdf/${record.clientId}`); | |||
}; | |||
const handleTest = () => { | |||
// const element = document.getElementById('pdfViewer'); | |||
// const inputFields = element.querySelectorAll('iframe')[0]; | |||
// console.log(element); | |||
// console.log(inputFields.contentDocument); | |||
// inputFields.forEach(input => { | |||
// console.log('Name:', input.name, 'Value:', input.value); | |||
// }); | |||
}; | |||
return ( | |||
<ThemeProvider theme={LIONER_BUTTON_THEME}> | |||
<div className="pdf-form-page"> {/* This is your 'pdfForm' page */} | |||
@@ -236,15 +271,16 @@ function PDF() { | |||
<Grid item> | |||
<Grid container> | |||
<Grid item sx={{ml:3, mr:1.5, mb:2}}> | |||
<Button | |||
{/* <Button | |||
variant="contained" | |||
type="submit" | |||
color="save" | |||
disabled={!viewerLoaded} | |||
onClick={handleSavePdf} | |||
// disabled={!viewerLoaded} | |||
onClick={handleTest} | |||
// onClick={handleSavePdf} | |||
> | |||
Save | |||
</Button> | |||
</Button> */} | |||
</Grid> | |||
<Grid item sx={{ml:{xs:1.5, md:1.5, lg:1.5}, mr:1.5, mb:2}}> | |||
<Button | |||
@@ -252,7 +288,7 @@ function PDF() { | |||
color="cancel" | |||
onClick={viewerLoaded ? handleBackClick : handleBack} | |||
> | |||
Cancel | |||
Back | |||
</Button> | |||
<GeneralConfirmWindow | |||
isWindowOpen={isWindowOpen} | |||
@@ -263,6 +299,18 @@ function PDF() { | |||
onConfirmClose={handleBack} | |||
/> | |||
</Grid> | |||
{/* <Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:0.5}}> | |||
<InputLabel htmlFor="remarks">Remarks</InputLabel> | |||
</Grid> | |||
<Grid item xs={9} s={6} md={5} lg={3} sx={{ml:3, mr:3, mb:0.5}}> | |||
<TextField | |||
fullWidth | |||
inputProps={{maxLength: 500}} | |||
id="remarks" | |||
autoComplete="off" | |||
/> | |||
</Grid> */} | |||
</Grid> | |||
</Grid> | |||
{/* {pdfLoaded ? ( | |||
@@ -278,18 +326,25 @@ function PDF() { | |||
<p>Loading PDF viewer...</p> | |||
)} */} | |||
</header> | |||
<div | |||
{!pdfLoaded && (<LoadingComponent/>)} | |||
<div id="adobe-dc-view" ref={viewerRef} style={{ | |||
width: '100%', | |||
height: 'calc(100vh - 180px)', // Adjust height based on header/footer | |||
border: '1px solid #ccc', | |||
}} | |||
hidden={!pdfLoaded} | |||
/> | |||
{/* <div | |||
// id={viewerRef} | |||
ref={viewerRef} | |||
// className="pdf-viewer-container" | |||
style={{ | |||
width: '100%', | |||
height: 'calc(100vh - 180px)', // Adjust height based on header/footer | |||
border: '1px solid #ccc' | |||
border: '1px solid #ccc', | |||
}} | |||
> | |||
{/* The PDF SDK will render the PDF viewer here */} | |||
</div> | |||
</div> */} | |||
</div> | |||
</ThemeProvider> | |||
); | |||
@@ -41,6 +41,12 @@ import {ExpandMore} from "@mui/icons-material"; | |||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; | |||
import { isNull } from 'lodash'; | |||
import DialogTitle from '@mui/material/DialogTitle'; | |||
import DialogContent from '@mui/material/DialogContent'; | |||
import DialogContentText from '@mui/material/DialogContentText'; | |||
import DialogActions from '@mui/material/DialogActions'; | |||
import Dialog from '@mui/material/Dialog'; | |||
// ==============================|| DASHBOARD - DEFAULT ||============================== // | |||
// const EventSearchForm = ({applySearch, refTemplateData, isUpdating, | |||
@@ -50,6 +56,8 @@ const PdfSearchForm = ({applySearch, setExpanded,expanded, clientId}) => { | |||
const navigate = useNavigate() | |||
const ability = useContext(AbilityContext); | |||
const [isWindowOpen, setIsWindowOpen] = useState(false); | |||
const [createDateFrom, setCreateDateFrom] = useState(null); | |||
const [createDateTo, setCreateDateTo] = useState(null); | |||
@@ -77,25 +85,25 @@ const PdfSearchForm = ({applySearch, setExpanded,expanded, clientId}) => { | |||
} | |||
}, [createDateToError]); | |||
const createNewForm = () => { | |||
navigate(`/pdf/maintain/-${clientId}T${1}`); | |||
const createNewForm = (templateId) => { | |||
navigate(`/pdf/maintain/-${clientId}T${templateId}`); | |||
}; | |||
const createFormUpDown = () => { | |||
navigate(`/pdf/form-up-down/-${clientId}T${1}`); | |||
}; | |||
// const createFormUpDown = () => { | |||
// navigate(`/pdf/form-up-down/-${clientId}T${1}`); | |||
// }; | |||
const createFormIDA = () => { | |||
navigate(`/pdf/newIDA/${clientId}`); | |||
}; | |||
// const createFormIDA = () => { | |||
// navigate(`/pdf/newIDA/${clientId}`); | |||
// }; | |||
const createFormFNA = () => { | |||
navigate(`/pdf/newFNA/${clientId}`); | |||
}; | |||
// const createFormFNA = () => { | |||
// navigate(`/pdf/newFNA/${clientId}`); | |||
// }; | |||
const createFormHSBCFIN = () => { | |||
navigate(`/pdf/newHSBCFIN/${clientId}`); | |||
}; | |||
// const createFormHSBCFIN = () => { | |||
// navigate(`/pdf/newHSBCFIN/${clientId}`); | |||
// }; | |||
const onSubmit = (data) => { | |||
const criteria = { | |||
@@ -299,26 +307,90 @@ const PdfSearchForm = ({applySearch, setExpanded,expanded, clientId}) => { | |||
</Grid> | |||
</Grid> | |||
<Grid container spacing={1}> | |||
{/* <Grid item> | |||
<Button | |||
variant="contained" | |||
color="create" | |||
onClick={createNewForm} | |||
> | |||
New | |||
</Button> | |||
<Grid item> | |||
<Grid container> | |||
{ability.can('EDIT','EVENT') ? | |||
<Grid item sx={{ml:3, mr:3, mb:0.5}}> | |||
<Button | |||
variant="contained" | |||
color="create" | |||
onClick={() => setIsWindowOpen(true)} | |||
> | |||
New Form | |||
</Button> | |||
<Dialog | |||
open={isWindowOpen} | |||
onClose={() => setIsWindowOpen(false)} | |||
aria-labelledby="alert-dialog-title" | |||
aria-describedby="alert-dialog-description" | |||
PaperProps={{ | |||
sx: { | |||
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '30vw' }, | |||
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '50vh' } | |||
} | |||
}} | |||
> | |||
<DialogTitle id="alert-dialog-title"> | |||
<Typography variant="lionerBold" component="span"> | |||
Select Template | |||
</Typography> | |||
</DialogTitle> | |||
<DialogContent> | |||
<DialogContentText id="alert-dialog-description"> | |||
<Button | |||
variant="contained" | |||
color="create" | |||
sx={{mr: 1}} | |||
onClick={() => createNewForm(1)} | |||
> | |||
Lioner IDA | |||
</Button> | |||
<Button | |||
variant="contained" | |||
color="create" | |||
sx={{mr: 1}} | |||
onClick={() => createNewForm(2)} | |||
> | |||
Lioner FNA | |||
</Button> | |||
<Button | |||
variant="contained" | |||
color="create" | |||
sx={{mr: 1}} | |||
onClick={() => createNewForm(3)} | |||
> | |||
HSBC FIN | |||
</Button> | |||
</DialogContentText> | |||
</DialogContent> | |||
<DialogActions> | |||
<Button onClick={() => setIsWindowOpen(false)}> | |||
<Typography variant="lionerSize" component="span"> | |||
Cancel | |||
</Typography> | |||
</Button> | |||
</DialogActions> | |||
</Dialog> | |||
{/* <Button | |||
variant="contained" | |||
color="create" | |||
onClick={createFormUpDown} | |||
> | |||
New Form By Upload/Download | |||
</Button> */} | |||
</Grid> | |||
: | |||
<Grid/> | |||
} | |||
</Grid> | |||
<Grid item> | |||
<Button | |||
variant="contained" | |||
color="create" | |||
onClick={createFormUpDown} | |||
> | |||
New By Upload/Download | |||
</Button> | |||
</Grid> */} | |||
<Grid item> | |||
{/* <Grid item> | |||
<Button | |||
variant="contained" | |||
color="create" | |||
@@ -416,7 +488,7 @@ const PdfSearchForm = ({applySearch, setExpanded,expanded, clientId}) => { | |||
> | |||
New SL Saving | |||
</Button> | |||
</Grid> | |||
</Grid> */} | |||
</Grid> | |||
</ThemeProvider> | |||
</Grid> | |||
@@ -85,9 +85,22 @@ export default function PdfTable({recordList}) { | |||
headerName: 'Form Name', | |||
flex: 2, | |||
renderCell: (params) => { | |||
const getFormLabel = (value) => { | |||
switch (value) { | |||
case 1: | |||
return 'Lioner IDA'; | |||
case 2: | |||
return 'Lioner FNA'; | |||
case 3: | |||
return 'HSBC FIN'; | |||
default: | |||
return 'Form'; | |||
} | |||
}; | |||
return ( | |||
<div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> | |||
{params.value} | |||
{getFormLabel(params.value)} | |||
</div> | |||
); | |||
} | |||
@@ -203,9 +216,6 @@ export default function PdfTable({recordList}) { | |||
return ( | |||
<div> | |||
<h2 style={{ marginBottom: '16px', color: '#333' }}> | |||
Existing Forms | |||
</h2> | |||
<DataGrid | |||
rows={rows} | |||
columns={columns} | |||
@@ -9,6 +9,7 @@ import {apiPath} from "../../../auth/utils"; | |||
import { | |||
// GET_DIVISION_FROM_SUB_DIVISION, | |||
GET_PDF_PATH, | |||
GET_CLIENT_PATH, | |||
// GET_SEARCH_TEMPLATE_COMBO_PATH, | |||
// GET_SEARCH_TEMPLATE_PATH | |||
} from "../../../utils/ApiPathConst"; | |||
@@ -33,6 +34,7 @@ import {useParams} from "react-router-dom"; | |||
const PdfSearchPage = () => { | |||
const [onReady, setOnReady] = useState(false); | |||
const [expanded, setExpanded] = React.useState(true); | |||
const [clientInfo,setClientInfo] = useState([]); | |||
const [record,setRecord] = useState([]); | |||
const [searchCriteria, setSearchCriteria] = useState({}); | |||
const params = useParams(); | |||
@@ -62,6 +64,21 @@ const PdfSearchPage = () => { | |||
} | |||
useEffect(() => { | |||
if (params.id) { | |||
if (params.id > 0) {console.log("loggg"); | |||
axios.get(`${apiPath}${GET_CLIENT_PATH}/${params.id}` | |||
) | |||
.then((response) => { | |||
if (response.status === 200) { | |||
setClientInfo(response.data); | |||
} | |||
}) | |||
.catch(error => { | |||
console.log(error); | |||
return false; | |||
}); | |||
} | |||
} | |||
setSearchCriteria({clientId: params.id, | |||
...searchCriteria}); | |||
}, [params.id]); | |||
@@ -80,6 +97,15 @@ const PdfSearchPage = () => { | |||
return ( | |||
<Grid container rowSpacing={3} columnSpacing={2.75} > | |||
<ThemeProvider theme={LIONER_FORM_THEME}> | |||
<Grid item xs={12} md={12} lg={12} > | |||
<Grid container maxWidth justifyContent="space-between" sx={{mt:-2, width:CARD_MAX_WIDTH}} > | |||
<Grid item xs={4} s={4} md={4} lg={4} | |||
sx={{ mb: 2, display: 'flex', alignItems: 'center'}}> | |||
<Typography variant="h2">{clientInfo.data? clientInfo.data.fullname:""}</Typography> | |||
</Grid> | |||
</Grid> | |||
</Grid> | |||
<Grid item xs={12} md={12} lg={12} > | |||
<Grid container maxWidth justifyContent="space-between" sx={{mt:-2, width:CARD_MAX_WIDTH}} > | |||
<Grid item xs={4} s={4} md={4} lg={4} | |||
@@ -104,12 +130,22 @@ const PdfSearchPage = () => { | |||
/> | |||
</Grid> | |||
<Grid item xs={12} md={12} lg={12} > | |||
<Grid container maxWidth justifyContent="space-between" sx={{mt:-2, width:CARD_MAX_WIDTH}} > | |||
<Grid item xs={4} s={4} md={4} lg={4} | |||
sx={{ mb: -2.25, display: 'flex', alignItems: 'center'}}> | |||
<Typography variant="h4">Existing Forms</Typography> | |||
</Grid> | |||
</Grid> | |||
</Grid> | |||
{!onReady? <LoadingComponent/> : | |||
// PDF Table | |||
<Grid item xs={12} md={12} lg={12}> | |||
<MainCard elevation={0} | |||
content={false} | |||
sx={{mt:{lg:-1.5}, width: CARD_MAX_WIDTH}} | |||
sx={{//mt:{lg:-1.5}, | |||
width: CARD_MAX_WIDTH}} | |||
> | |||
<div style={{/*height: expanded? '46vh' : '75vh',*/ width: '100%'}}> | |||
@@ -15,6 +15,7 @@ const PdfMaintainPage = Loadable(lazy(() => import('pages/pdf/PdfMaintainPage')) | |||
const PdfFormUpAndDown = Loadable(lazy(() => import('pages/pdf/PdfFormUpAndDown'))); | |||
const PdfViewer = Loadable(lazy(() => import('pages/pdf/PdfViewer'))); | |||
const PdfSearchPage = Loadable(lazy(() => import('pages/pdf/PdfSearchPage'))); | |||
const TemplateSearchPage = Loadable(lazy(() => import('pages/pdf/TemplateSearchPage'))); | |||
// ==============================|| AUTH ROUTING ||============================== // | |||
@@ -64,7 +65,17 @@ const ClientRoutes =() => { | |||
<Navigate to="/" /> | |||
) | |||
), | |||
}, | |||
}, | |||
{ | |||
path: '/template/', | |||
element: ( | |||
handleRouteAbility( | |||
ability.can('VIEW', 'DASHBOARD'), | |||
<TemplateSearchPage />, | |||
<Navigate to="/" /> | |||
) | |||
), | |||
}, | |||
{ | |||
path: '/pdf/form-up-down/:id', | |||
element: ( | |||
@@ -6,6 +6,7 @@ import MainLayout from 'layout/MainLayout'; | |||
import AbilityContext from "../components/AbilityProvider"; | |||
import {handleRouteAbility} from "../utils/CommonFunction"; | |||
import {Navigate} from "react-router"; | |||
import ClientSearchPage from 'pages/client/ClientSearchPage/index'; | |||
// render - dashboard | |||
//const DashboardDefault = Loadable(lazy(() => import('pages/dashboard'))); | |||
@@ -47,7 +48,8 @@ const MainRoutes = () => { | |||
element: ( | |||
handleRouteAbility( | |||
ability.can('VIEW', 'DASHBOARD'), | |||
<LIONERDashboard />, | |||
<ClientSearchPage />, | |||
// <LIONERDashboard />, | |||
<Navigate to="/client" /> | |||
) | |||
), | |||
@@ -878,6 +878,20 @@ export function UploadFileWindow({ isWindowOpen, title, video, onNormalClose, on | |||
}); | |||
} | |||
} | |||
const handleDragOver = (e) => { | |||
e.preventDefault(); | |||
e.stopPropagation(); | |||
}; | |||
const handleDrop = (e) => { | |||
e.preventDefault(); | |||
e.stopPropagation(); | |||
const droppedFiles = Array.from(e.dataTransfer.files); | |||
console.log(droppedFiles); | |||
// setFiles((prevFiles) => [...prevFiles, ...droppedFiles]); | |||
}; | |||
return ( | |||
<Dialog | |||
PaperProps={{ | |||
@@ -972,7 +986,57 @@ export function UploadFileWindow({ isWindowOpen, title, video, onNormalClose, on | |||
</Grid> | |||
</Grid> | |||
) : ( | |||
<Grid /> | |||
<Grid container alignItems={'center'} sx={{ mt: 3 }}> | |||
<Grid item xs={7} s={7} md={7} lg={7}> | |||
<FormControl fullWidth required> | |||
<Grid container alignItems={'flex-start'} sx={{ mt: 3 }}> | |||
<Grid item xs={7} s={7} md={7} lg={8} sx={{display: 'flex', alignItems: 'flex-start' }}> | |||
<MuiFileInput | |||
inputProps={{ | |||
accept: '.png, .jpeg, .jpg', | |||
}} | |||
InputProps={{ | |||
padding: '7.5px 8px 7.5px 12px', | |||
startAdornment: null, // Set startAdornment to null to disable it | |||
}} | |||
value={file} | |||
onChange={handleFieldChange} | |||
error={!!errors.error} | |||
helperText={errors.error} | |||
// disabled={video.mimetype !== 'video'} | |||
/> | |||
</Grid> | |||
<Grid item xs={4} s={4} md={4} lg={4} sx={{ display: 'flex', justifyContent: 'flex-end' }}> | |||
<div | |||
onDragOver={handleDragOver} | |||
onDrop={handleDrop}> | |||
<input | |||
type="file" | |||
accept=".png, .jpeg, .jpg" | |||
style={{ display: 'none' }} | |||
ref={fileInputRef} | |||
onChange={handleChange} | |||
/> | |||
<Button | |||
component="label" | |||
variant="contained" | |||
startIcon={<CloudUploadIcon />} | |||
inputprops={{ | |||
accept: '.png, .jpeg, .jpg', | |||
startAdornment: <AttachFileIcon /> | |||
}} | |||
onClick={handleOpenFileSelect} | |||
> | |||
Upload file | |||
</Button> | |||
{/*Selected file: {file ? file.name : 'None'}*/} | |||
</div> | |||
</Grid> | |||
</Grid> | |||
</FormControl> | |||
</Grid> | |||
</Grid> | |||
)} | |||
<Grid container alignItems={'flex-start'} sx={{ mt: 3 }}> | |||