| @@ -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 }}> | |||