| @@ -20,7 +20,8 @@ function hasGazetteIssueFilter(params) { | |||||
| export function FiDataGrid({ rows, columns, sx, autoHeight = true, | export function FiDataGrid({ rows, columns, sx, autoHeight = true, | ||||
| hideFooterSelectedRowCount, rowModesModel, editMode, | hideFooterSelectedRowCount, rowModesModel, editMode, | ||||
| pageSizeOptions, filterItems, customPageSize, doLoad, applyGridOnReady, applySearch, | pageSizeOptions, filterItems, customPageSize, doLoad, applyGridOnReady, applySearch, | ||||
| tab, height, maxHeight, pagination = true, serverSorting = false, ...props }) { | |||||
| tab, height, maxHeight, pagination = true, serverSorting = false, | |||||
| disablePagingOnGazetteIssue = true, ...props }) { | |||||
| const intl = useIntl(); | const intl = useIntl(); | ||||
| const [_rows, set_rows] = useState([]); | const [_rows, set_rows] = useState([]); | ||||
| const [_doLoad, set_doLoad] = useState({}); | const [_doLoad, set_doLoad] = useState({}); | ||||
| @@ -113,7 +114,7 @@ export function FiDataGrid({ rows, columns, sx, autoHeight = true, | |||||
| delete params.sort; | delete params.sort; | ||||
| delete params.direction; | delete params.direction; | ||||
| } | } | ||||
| if (hasGazetteIssueFilter(params)) { | |||||
| if (disablePagingOnGazetteIssue && hasGazetteIssueFilter(params)) { | |||||
| delete params.start; | delete params.start; | ||||
| delete params.limit; | delete params.limit; | ||||
| } else { | } else { | ||||
| @@ -129,7 +130,7 @@ export function FiDataGrid({ rows, columns, sx, autoHeight = true, | |||||
| } | } | ||||
| }; | }; | ||||
| const ignorePaging = hasGazetteIssueFilter(_doLoad?.params); | |||||
| const ignorePaging = disablePagingOnGazetteIssue && hasGazetteIssueFilter(_doLoad?.params); | |||||
| const effectivePagination = pagination && !ignorePaging; | const effectivePagination = pagination && !ignorePaging; | ||||
| useEffect(() => { | useEffect(() => { | ||||
| @@ -215,7 +216,7 @@ export function FiDataGrid({ rows, columns, sx, autoHeight = true, | |||||
| if (_doLoad.params == undefined) return; | if (_doLoad.params == undefined) return; | ||||
| if (_doLoad.params.searchCriteria !== undefined) return; | if (_doLoad.params.searchCriteria !== undefined) return; | ||||
| if (_doLoad.params == null) _doLoad.params = {}; | if (_doLoad.params == null) _doLoad.params = {}; | ||||
| if (hasGazetteIssueFilter(_doLoad.params)) { | |||||
| if (disablePagingOnGazetteIssue && hasGazetteIssueFilter(_doLoad.params)) { | |||||
| delete _doLoad.params.start; | delete _doLoad.params.start; | ||||
| delete _doLoad.params.limit; | delete _doLoad.params.limit; | ||||
| } else { | } else { | ||||
| @@ -21,9 +21,10 @@ export default function SearchPublicNoticeTable({searchCriteria, applyGridOnRead | |||||
| const columns = [ | const columns = [ | ||||
| { | { | ||||
| field: 'actions', | |||||
| field: 'refNo', | |||||
| headerName: 'Proof No.', | headerName: 'Proof No.', | ||||
| width: 170, | width: 170, | ||||
| sortable: true, | |||||
| cellClassName: 'actions', | cellClassName: 'actions', | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| return clickableLink('/proof/reply/' + params.row.id, params.row.refNo); | return clickableLink('/proof/reply/' + params.row.id, params.row.refNo); | ||||
| @@ -34,6 +35,7 @@ export default function SearchPublicNoticeTable({searchCriteria, applyGridOnRead | |||||
| field: 'appId', | field: 'appId', | ||||
| headerName: 'Application No./ Gazette Code/ Gazette Issue No.', | headerName: 'Application No./ Gazette Code/ Gazette Issue No.', | ||||
| width: 400, | width: 400, | ||||
| sortable: true, | |||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| let appNo = params.row.appNo; | let appNo = params.row.appNo; | ||||
| let code = params.row.groupNo; | let code = params.row.groupNo; | ||||
| @@ -51,7 +53,7 @@ export default function SearchPublicNoticeTable({searchCriteria, applyGridOnRead | |||||
| headerName: 'Status', | headerName: 'Status', | ||||
| flex: 1, | flex: 1, | ||||
| minWidth: 150, | minWidth: 150, | ||||
| sortable: false, | |||||
| sortable: true, | |||||
| filterable: false, | filterable: false, | ||||
| valueGetter: () => '', | valueGetter: () => '', | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| @@ -64,23 +66,14 @@ export default function SearchPublicNoticeTable({searchCriteria, applyGridOnRead | |||||
| headerName: 'Proof Issue Date', | headerName: 'Proof Issue Date', | ||||
| flex: 1, | flex: 1, | ||||
| minWidth: 200, | minWidth: 200, | ||||
| // sorting/filtering uses this value | |||||
| sortable: true, | |||||
| valueGetter: (params) => DateUtils.toDate(params?.value), | valueGetter: (params) => DateUtils.toDate(params?.value), | ||||
| // display uses this (params.value is the *Date* returned above) | |||||
| valueFormatter: (params) => { | valueFormatter: (params) => { | ||||
| const d = params.value; // Date or Invalid Date | |||||
| const d = params.value; | |||||
| return d instanceof Date && !isNaN(d.getTime()) | return d instanceof Date && !isNaN(d.getTime()) | ||||
| ? DateUtils.dateStr(d) | ? DateUtils.dateStr(d) | ||||
| : ""; | : ""; | ||||
| }, | }, | ||||
| // make sorting 100% deterministic | |||||
| sortComparator: (v1, v2) => { | |||||
| const t1 = v1 instanceof Date && !isNaN(v1.getTime()) ? v1.getTime() : -Infinity; | |||||
| const t2 = v2 instanceof Date && !isNaN(v2.getTime()) ? v2.getTime() : -Infinity; | |||||
| return t1 - t2; | |||||
| } | |||||
| }, | }, | ||||
| { | { | ||||
| id: 'replyDate', | id: 'replyDate', | ||||
| @@ -88,23 +81,14 @@ export default function SearchPublicNoticeTable({searchCriteria, applyGridOnRead | |||||
| headerName: 'Confirmed/ Return Date', | headerName: 'Confirmed/ Return Date', | ||||
| flex: 1, | flex: 1, | ||||
| minWidth: 200, | minWidth: 200, | ||||
| // sorting/filtering uses this value | |||||
| sortable: true, | |||||
| valueGetter: (params) => DateUtils.toDate(params?.value), | valueGetter: (params) => DateUtils.toDate(params?.value), | ||||
| // display uses this (params.value is the *Date* returned above) | |||||
| valueFormatter: (params) => { | valueFormatter: (params) => { | ||||
| const d = params.value; // Date or Invalid Date | |||||
| const d = params.value; | |||||
| return d instanceof Date && !isNaN(d.getTime()) | return d instanceof Date && !isNaN(d.getTime()) | ||||
| ? DateUtils.dateStr(d) | ? DateUtils.dateStr(d) | ||||
| : ""; | : ""; | ||||
| }, | }, | ||||
| // make sorting 100% deterministic | |||||
| sortComparator: (v1, v2) => { | |||||
| const t1 = v1 instanceof Date && !isNaN(v1.getTime()) ? v1.getTime() : -Infinity; | |||||
| const t2 = v2 instanceof Date && !isNaN(v2.getTime()) ? v2.getTime() : -Infinity; | |||||
| return t1 - t2; | |||||
| } | |||||
| }, | }, | ||||
| { | { | ||||
| id: 'contactPerson', | id: 'contactPerson', | ||||
| @@ -112,6 +96,7 @@ export default function SearchPublicNoticeTable({searchCriteria, applyGridOnRead | |||||
| headerName: 'Client', | headerName: 'Client', | ||||
| flex: 1, | flex: 1, | ||||
| minWidth: 200, | minWidth: 200, | ||||
| sortable: true, | |||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| let company = params.row.enCompanyName != null?params.row.enCompanyName: params.row.chCompanyName; | let company = params.row.enCompanyName != null?params.row.enCompanyName: params.row.chCompanyName; | ||||
| company = company != null ? company : ""; | company = company != null ? company : ""; | ||||
| @@ -129,6 +114,7 @@ export default function SearchPublicNoticeTable({searchCriteria, applyGridOnRead | |||||
| headerName: 'Gazette Group', | headerName: 'Gazette Group', | ||||
| flex: 1, | flex: 1, | ||||
| minWidth: 200, | minWidth: 200, | ||||
| sortable: true, | |||||
| valueGetter: (params) => { | valueGetter: (params) => { | ||||
| return (params?.value) ? (params?.value) : ""; | return (params?.value) ? (params?.value) : ""; | ||||
| } | } | ||||
| @@ -139,6 +125,7 @@ export default function SearchPublicNoticeTable({searchCriteria, applyGridOnRead | |||||
| headerName: 'Amount ($)', | headerName: 'Amount ($)', | ||||
| flex: 1, | flex: 1, | ||||
| minWidth: 200, | minWidth: 200, | ||||
| sortable: true, | |||||
| valueGetter: (params) => { | valueGetter: (params) => { | ||||
| return (params?.value) ? "$ " + FormatUtils.currencyFormat(params?.value) : ""; | return (params?.value) ? "$ " + FormatUtils.currencyFormat(params?.value) : ""; | ||||
| } | } | ||||
| @@ -158,10 +145,8 @@ export default function SearchPublicNoticeTable({searchCriteria, applyGridOnRead | |||||
| onRowDoubleClick={handleRowDoubleClick} | onRowDoubleClick={handleRowDoubleClick} | ||||
| applyGridOnReady={applyGridOnReady} | applyGridOnReady={applyGridOnReady} | ||||
| applySearch = {applySearch} | applySearch = {applySearch} | ||||
| // doLoad={{ | |||||
| // url: LIST_PROOF, | |||||
| // params: _searchCriteria, | |||||
| // }} | |||||
| serverSorting | |||||
| disablePagingOnGazetteIssue={false} | |||||
| doLoad={React.useMemo(() => ({ | doLoad={React.useMemo(() => ({ | ||||
| url: LIST_PROOF, | url: LIST_PROOF, | ||||
| params: _searchCriteria, | params: _searchCriteria, | ||||
| @@ -21,6 +21,21 @@ import dayjs from "dayjs"; | |||||
| import {DemoItem} from "@mui/x-date-pickers/internals/demo"; | import {DemoItem} from "@mui/x-date-pickers/internals/demo"; | ||||
| import {LocalizationProvider} from "@mui/x-date-pickers/LocalizationProvider"; | import {LocalizationProvider} from "@mui/x-date-pickers/LocalizationProvider"; | ||||
| import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs"; | import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs"; | ||||
| const getDefaultDateFrom = () => DateUtils.dateValue(new Date().setDate(new Date().getDate() - 14)); | |||||
| const getDefaultDateTo = () => DateUtils.dateValue(new Date()); | |||||
| const isSubmitDateEmpty = (value) => | |||||
| value == null || value === "" || value === "dd / mm / yyyy"; | |||||
| const isBlank = (value) => value == null || String(value).trim() === ""; | |||||
| const toDayjsOrNull = (value) => { | |||||
| if (isSubmitDateEmpty(value)) return null; | |||||
| const d = dayjs(value); | |||||
| return d.isValid() ? d : null; | |||||
| }; | |||||
| // ==============================|| DASHBOARD - DEFAULT ||============================== // | // ==============================|| DASHBOARD - DEFAULT ||============================== // | ||||
| const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, onGridReady | const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, onGridReady | ||||
| }) => { | }) => { | ||||
| @@ -40,19 +55,8 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| const [maxDate, setMaxDate] = React.useState(searchCriteria.dateTo); | const [maxDate, setMaxDate] = React.useState(searchCriteria.dateTo); | ||||
| const [fromDateValue, setFromDateValue] = React.useState("dd / mm / yyyy"); | const [fromDateValue, setFromDateValue] = React.useState("dd / mm / yyyy"); | ||||
| const [toDateValue, setToDateValue] = React.useState("dd / mm / yyyy"); | const [toDateValue, setToDateValue] = React.useState("dd / mm / yyyy"); | ||||
| const prevHasOtherRef = React.useRef(null); | |||||
| // React.useEffect(() => { | |||||
| // if(searchCriteria.status!=undefined){ | |||||
| // if(searchCriteria.status === ""){ | |||||
| // ComboData.proofStatus_GLD[0] | |||||
| // }else{ | |||||
| // setSelectedStatus(ComboData.proofStatus_GLD.find(item => item.type === searchCriteria.status)) | |||||
| // } | |||||
| // }else{ | |||||
| // setSelectedStatus(ComboData.proofStatus_GLD[0]) | |||||
| // } | |||||
| // }, [searchCriteria]); | |||||
| React.useEffect(() => { | React.useEffect(() => { | ||||
| setFromDateValue(minDate); | setFromDateValue(minDate); | ||||
| }, [minDate]); | }, [minDate]); | ||||
| @@ -65,7 +69,55 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| const { locale } = intl; | const { locale } = intl; | ||||
| const marginBottom = 2.5; | const marginBottom = 2.5; | ||||
| const { reset, register, handleSubmit } = useForm() | |||||
| const { reset, register, handleSubmit, watch } = useForm({ | |||||
| defaultValues: { | |||||
| refNo: searchCriteria.refNo || "", | |||||
| code: searchCriteria.code || "", | |||||
| contact: searchCriteria.contact || "" | |||||
| } | |||||
| }); | |||||
| const refNo = watch("refNo"); | |||||
| const code = watch("code"); | |||||
| const contact = watch("contact"); | |||||
| const clearSubmitDates = () => { | |||||
| setMinDate(null); | |||||
| setMaxDate(null); | |||||
| }; | |||||
| const restoreDefaultSubmitDates = () => { | |||||
| setMinDate(getDefaultDateFrom()); | |||||
| setMaxDate(getDefaultDateTo()); | |||||
| }; | |||||
| const hasOtherCriteria = (textFields = {}) => { | |||||
| if (!isBlank(textFields.refNo)) return true; | |||||
| if (!isBlank(textFields.code)) return true; | |||||
| if (!isBlank(textFields.contact)) return true; | |||||
| if (groupSelected?.title) return true; | |||||
| if (orgSelected?.key && orgSelected.key > 0) return true; | |||||
| if (issueSelected?.id) return true; | |||||
| if (status?.type && status.type !== "all" && status.type !== "") return true; | |||||
| return false; | |||||
| }; | |||||
| React.useEffect(() => { | |||||
| const hasOther = hasOtherCriteria({ refNo, code, contact }); | |||||
| if (prevHasOtherRef.current === null) { | |||||
| prevHasOtherRef.current = hasOther; | |||||
| return; | |||||
| } | |||||
| if (hasOther && !prevHasOtherRef.current) { | |||||
| clearSubmitDates(); | |||||
| } else if (!hasOther && prevHasOtherRef.current) { | |||||
| // Only refill defaults when From or To is empty; keep user-entered dates otherwise | |||||
| if (isSubmitDateEmpty(minDate) || isSubmitDateEmpty(maxDate)) { | |||||
| restoreDefaultSubmitDates(); | |||||
| } | |||||
| } | |||||
| prevHasOtherRef.current = hasOther; | |||||
| }, [refNo, code, contact, groupSelected, orgSelected, issueSelected, status]); | |||||
| const onSubmit = (data) => { | const onSubmit = (data) => { | ||||
| let typeArray = []; | let typeArray = []; | ||||
| let sentDateFrom = ""; | let sentDateFrom = ""; | ||||
| @@ -75,11 +127,26 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| typeArray.push(type[i].label); | typeArray.push(type[i].label); | ||||
| } | } | ||||
| if (fromDateValue != "dd / mm / yyyy" && toDateValue != "dd / mm / yyyy") { | |||||
| sentDateFrom = DateUtils.dateValue(fromDateValue) | |||||
| sentDateTo = DateUtils.dateValue(toDateValue) | |||||
| const hasOther = hasOtherCriteria({ | |||||
| refNo: data.refNo, | |||||
| code: data.code, | |||||
| contact: data.contact | |||||
| }); | |||||
| const datesEmpty = isSubmitDateEmpty(fromDateValue) || isSubmitDateEmpty(toDateValue) | |||||
| || minDate == null || maxDate == null; | |||||
| if (!hasOther && datesEmpty) { | |||||
| const dateFrom = getDefaultDateFrom(); | |||||
| const dateTo = getDefaultDateTo(); | |||||
| setMinDate(dateFrom); | |||||
| setMaxDate(dateTo); | |||||
| sentDateFrom = dateFrom; | |||||
| sentDateTo = dateTo; | |||||
| } else if (!datesEmpty) { | |||||
| sentDateFrom = DateUtils.dateValue(fromDateValue); | |||||
| sentDateTo = DateUtils.dateValue(toDateValue); | |||||
| } | } | ||||
| const temp = { | const temp = { | ||||
| refNo: data.refNo, | refNo: data.refNo, | ||||
| code: data.code, | code: data.code, | ||||
| @@ -90,9 +157,14 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| contact: data.contact, | contact: data.contact, | ||||
| orgId: (orgSelected?.key && orgSelected?.key > 0) ? orgSelected?.key : "", | orgId: (orgSelected?.key && orgSelected?.key > 0) ? orgSelected?.key : "", | ||||
| statusKey:status?.key, | statusKey:status?.key, | ||||
| start: 0, | |||||
| limit: 10, | |||||
| }; | }; | ||||
| if (searchCriteria?.sort && searchCriteria?.direction) { | |||||
| temp.sort = searchCriteria.sort; | |||||
| temp.direction = searchCriteria.direction; | |||||
| } | |||||
| if(status?.type && status?.type != 'all'){ | if(status?.type && status?.type != 'all'){ | ||||
| if (status?.type == "Confirmed"){ | if (status?.type == "Confirmed"){ | ||||
| @@ -130,18 +202,34 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| function resetForm() { | function resetForm() { | ||||
| setType([]); | setType([]); | ||||
| setStatus(ComboData.proofStatus[0]); | |||||
| setStatus(ComboData.proofStatus_GLD[0]); | |||||
| setOrgSelected(null); | setOrgSelected(null); | ||||
| setIssueSelected(null); | setIssueSelected(null); | ||||
| setGroupSelected(null); | setGroupSelected(null); | ||||
| setMinDate(DateUtils.dateValue(new Date().setDate(new Date().getDate()-14))) | |||||
| setMaxDate(DateUtils.dateValue(new Date())) | |||||
| const dateFrom = getDefaultDateFrom(); | |||||
| const dateTo = getDefaultDateTo(); | |||||
| setMinDate(dateFrom); | |||||
| setMaxDate(dateTo); | |||||
| reset({ | reset({ | ||||
| refNo:"", | refNo:"", | ||||
| code:"", | code:"", | ||||
| contact:"" | contact:"" | ||||
| }); | }); | ||||
| localStorage.setItem('searchCriteria',"") | |||||
| prevHasOtherRef.current = false; | |||||
| localStorage.setItem('searchCriteria',""); | |||||
| applySearch({ | |||||
| refNo: "", | |||||
| code: "", | |||||
| issueId: "", | |||||
| gazettGroup: "", | |||||
| dateFrom, | |||||
| dateTo, | |||||
| contact: "", | |||||
| orgId: "", | |||||
| statusKey: 0, | |||||
| start: 0, | |||||
| limit: 10 | |||||
| }); | |||||
| } | } | ||||
| function getIssueLabel(data) { | function getIssueLabel(data) { | ||||
| @@ -279,22 +367,21 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| <DemoItem components={['DatePicker']}> | <DemoItem components={['DatePicker']}> | ||||
| <DatePicker | <DatePicker | ||||
| id="dateFrom" | id="dateFrom" | ||||
| // onError={(newError) => setReceiptFromError(newError)} | |||||
| onError={() => {}} | |||||
| slotProps={{ | slotProps={{ | ||||
| field: { readOnly: true, }, | |||||
| // textField: { | |||||
| // helperText: receiptFromErrorMessage, | |||||
| // }, | |||||
| field: { readOnly: true, clearable: true }, | |||||
| textField: { | |||||
| InputLabelProps: { shrink: true }, | |||||
| error: false, | |||||
| helperText: null | |||||
| }, | |||||
| }} | }} | ||||
| format="DD/MM/YYYY" | format="DD/MM/YYYY" | ||||
| label="Proof Issue Date (From)" | label="Proof Issue Date (From)" | ||||
| value={minDate === null ? null : dayjs(minDate)} | |||||
| maxDate={maxDate === null ? null : dayjs(maxDate)} | |||||
| value={toDayjsOrNull(minDate)} | |||||
| maxDate={toDayjsOrNull(maxDate)} | |||||
| onChange={(newValue) => { | onChange={(newValue) => { | ||||
| // console.log(newValue) | |||||
| if(newValue!=null){ | |||||
| setMinDate(newValue); | |||||
| } | |||||
| setMinDate(newValue && newValue.isValid?.() ? newValue : null); | |||||
| }} | }} | ||||
| /> | /> | ||||
| </DemoItem > | </DemoItem > | ||||
| @@ -306,22 +393,21 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| <DemoItem components={['DatePicker']}> | <DemoItem components={['DatePicker']}> | ||||
| <DatePicker | <DatePicker | ||||
| id="dateTo" | id="dateTo" | ||||
| // onError={(newError) => setReceiptFromError(newError)} | |||||
| onError={() => {}} | |||||
| slotProps={{ | slotProps={{ | ||||
| field: { readOnly: true, }, | |||||
| // textField: { | |||||
| // helperText: receiptFromErrorMessage, | |||||
| // }, | |||||
| field: { readOnly: true, clearable: true }, | |||||
| textField: { | |||||
| InputLabelProps: { shrink: true }, | |||||
| error: false, | |||||
| helperText: null | |||||
| }, | |||||
| }} | }} | ||||
| format="DD/MM/YYYY" | format="DD/MM/YYYY" | ||||
| label="Proof Issue Date (To)" | label="Proof Issue Date (To)" | ||||
| value={maxDate === null ? null : dayjs(maxDate)} | |||||
| minDate={minDate === null ? null : dayjs(minDate)} | |||||
| value={toDayjsOrNull(maxDate)} | |||||
| minDate={toDayjsOrNull(minDate)} | |||||
| onChange={(newValue) => { | onChange={(newValue) => { | ||||
| // console.log(newValue) | |||||
| if(newValue!=null){ | |||||
| setMaxDate(newValue); | |||||
| } | |||||
| setMaxDate(newValue && newValue.isValid?.() ? newValue : null); | |||||
| }} | }} | ||||
| /> | /> | ||||
| </DemoItem > | </DemoItem > | ||||
| @@ -106,10 +106,11 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea | |||||
| const columns = [ | const columns = [ | ||||
| { | { | ||||
| field: 'actions', | |||||
| field: 'refNo', | |||||
| headerName: intl.formatMessage({ id: 'proofId' }), | headerName: intl.formatMessage({ id: 'proofId' }), | ||||
| width: isMdOrLg ? 'auto' : 200, | width: isMdOrLg ? 'auto' : 200, | ||||
| flex: isMdOrLg ? 1.5 : undefined, | flex: isMdOrLg ? 1.5 : undefined, | ||||
| sortable: true, | |||||
| cellClassName: 'actions', | cellClassName: 'actions', | ||||
| renderHeader: renderHeaderWithAria, | renderHeader: renderHeaderWithAria, | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| @@ -122,6 +123,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea | |||||
| headerName: isORGLoggedIn() ? intl.formatMessage({ id: 'gazetteCount3' }) : intl.formatMessage({ id: 'gazetteCount2' }), | headerName: isORGLoggedIn() ? intl.formatMessage({ id: 'gazetteCount3' }) : intl.formatMessage({ id: 'gazetteCount2' }), | ||||
| width: isMdOrLg ? 'auto' : 330, | width: isMdOrLg ? 'auto' : 330, | ||||
| flex: isMdOrLg ? 2 : undefined, | flex: isMdOrLg ? 2 : undefined, | ||||
| sortable: true, | |||||
| renderHeader: renderHeaderWithAria, | renderHeader: renderHeaderWithAria, | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| // let appNo = params.row.appNo; | // let appNo = params.row.appNo; | ||||
| @@ -138,6 +140,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea | |||||
| headerName: intl.formatMessage({ id: 'proofDate' }), | headerName: intl.formatMessage({ id: 'proofDate' }), | ||||
| width: isMdOrLg ? 'auto' : 200, | width: isMdOrLg ? 'auto' : 200, | ||||
| flex: isMdOrLg ? 1.5 : undefined, | flex: isMdOrLg ? 1.5 : undefined, | ||||
| sortable: true, | |||||
| renderHeader: renderHeaderWithAria, | renderHeader: renderHeaderWithAria, | ||||
| valueGetter: (params) => { | valueGetter: (params) => { | ||||
| return DateUtils.datetimeStr(params?.value); | return DateUtils.datetimeStr(params?.value); | ||||
| @@ -149,6 +152,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea | |||||
| headerName: intl.formatMessage({ id: 'replyBefore' }), | headerName: intl.formatMessage({ id: 'replyBefore' }), | ||||
| width: isMdOrLg ? 'auto' : 200, | width: isMdOrLg ? 'auto' : 200, | ||||
| flex: isMdOrLg ? 1.5 : undefined, | flex: isMdOrLg ? 1.5 : undefined, | ||||
| sortable: true, | |||||
| renderHeader: renderHeaderWithAria, | renderHeader: renderHeaderWithAria, | ||||
| valueGetter: (params) => { | valueGetter: (params) => { | ||||
| const proofPaymentDeadline = DateUtils.convertToDate(params?.value); | const proofPaymentDeadline = DateUtils.convertToDate(params?.value); | ||||
| @@ -164,6 +168,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea | |||||
| headerName: intl.formatMessage({ id: 'replyDate' }), | headerName: intl.formatMessage({ id: 'replyDate' }), | ||||
| width: isMdOrLg ? 'auto' : 200, | width: isMdOrLg ? 'auto' : 200, | ||||
| flex: isMdOrLg ? 1.5 : undefined, | flex: isMdOrLg ? 1.5 : undefined, | ||||
| sortable: true, | |||||
| renderHeader: renderHeaderWithAria, | renderHeader: renderHeaderWithAria, | ||||
| valueGetter: (params) => { | valueGetter: (params) => { | ||||
| return params?.value ? DateUtils.datetimeStr(params?.value) : ""; | return params?.value ? DateUtils.datetimeStr(params?.value) : ""; | ||||
| @@ -174,6 +179,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea | |||||
| headerName: intl.formatMessage({ id: 'status' }), | headerName: intl.formatMessage({ id: 'status' }), | ||||
| width: isMdOrLg ? 'auto' : 160, | width: isMdOrLg ? 'auto' : 160, | ||||
| flex: isMdOrLg ? 1 : undefined, | flex: isMdOrLg ? 1 : undefined, | ||||
| sortable: true, | |||||
| renderHeader: renderHeaderWithAria, | renderHeader: renderHeaderWithAria, | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| return locale === 'en' ? ProofStatus.getStatus_Eng(params) : locale === 'zh-HK' ? ProofStatus.getStatus_Cht(params) : ProofStatus.getStatus_Cn(params); | return locale === 'en' ? ProofStatus.getStatus_Eng(params) : locale === 'zh-HK' ? ProofStatus.getStatus_Cht(params) : ProofStatus.getStatus_Cn(params); | ||||
| @@ -185,6 +191,7 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea | |||||
| headerName: intl.formatMessage({ id: 'fee' }), | headerName: intl.formatMessage({ id: 'fee' }), | ||||
| width: isMdOrLg ? 'auto' : 160, | width: isMdOrLg ? 'auto' : 160, | ||||
| flex: isMdOrLg ? 1 : undefined, | flex: isMdOrLg ? 1 : undefined, | ||||
| sortable: true, | |||||
| renderHeader: renderHeaderWithAria, | renderHeader: renderHeaderWithAria, | ||||
| valueGetter: (params) => { | valueGetter: (params) => { | ||||
| return (params?.value) ? "$ " + FormatUtils.currencyFormat(params?.value) : ""; | return (params?.value) ? "$ " + FormatUtils.currencyFormat(params?.value) : ""; | ||||
| @@ -207,6 +214,8 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea | |||||
| onRowDoubleClick={handleRowDoubleClick} | onRowDoubleClick={handleRowDoubleClick} | ||||
| applyGridOnReady={applyGridOnReady} | applyGridOnReady={applyGridOnReady} | ||||
| applySearch={applySearch} | applySearch={applySearch} | ||||
| serverSorting | |||||
| disablePagingOnGazetteIssue={false} | |||||
| doLoad={React.useMemo(() => ({ | doLoad={React.useMemo(() => ({ | ||||
| url: LIST_PROOF, | url: LIST_PROOF, | ||||
| params: _searchCriteria, | params: _searchCriteria, | ||||
| @@ -214,4 +223,4 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| ); | ); | ||||
| } | |||||
| } | |||||
| @@ -21,6 +21,21 @@ import dayjs from "dayjs"; | |||||
| import {DemoItem} from "@mui/x-date-pickers/internals/demo"; | import {DemoItem} from "@mui/x-date-pickers/internals/demo"; | ||||
| import {LocalizationProvider} from "@mui/x-date-pickers/LocalizationProvider"; | import {LocalizationProvider} from "@mui/x-date-pickers/LocalizationProvider"; | ||||
| import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs"; | import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs"; | ||||
| const getDefaultDateFrom = () => DateUtils.dateValue(new Date().setDate(new Date().getDate() - 14)); | |||||
| const getDefaultDateTo = () => DateUtils.dateValue(new Date()); | |||||
| const isSubmitDateEmpty = (value) => | |||||
| value == null || value === "" || value === "dd / mm / yyyy"; | |||||
| const isBlank = (value) => value == null || String(value).trim() === ""; | |||||
| const toDayjsOrNull = (value) => { | |||||
| if (isSubmitDateEmpty(value)) return null; | |||||
| const d = dayjs(value); | |||||
| return d.isValid() ? d : null; | |||||
| }; | |||||
| // ==============================|| DASHBOARD - DEFAULT ||============================== // | // ==============================|| DASHBOARD - DEFAULT ||============================== // | ||||
| const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, onGridReady | const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, onGridReady | ||||
| }) => { | }) => { | ||||
| @@ -37,6 +52,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| const [maxDate, setMaxDate] = React.useState(searchCriteria.dateTo); | const [maxDate, setMaxDate] = React.useState(searchCriteria.dateTo); | ||||
| const [fromDateValue, setFromDateValue] = React.useState("dd / mm / yyyy"); | const [fromDateValue, setFromDateValue] = React.useState("dd / mm / yyyy"); | ||||
| const [toDateValue, setToDateValue] = React.useState("dd / mm / yyyy"); | const [toDateValue, setToDateValue] = React.useState("dd / mm / yyyy"); | ||||
| const prevHasOtherRef = React.useRef(null); | |||||
| React.useEffect(() => { | React.useEffect(() => { | ||||
| setFromDateValue(minDate); | setFromDateValue(minDate); | ||||
| @@ -62,7 +78,50 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| } | } | ||||
| } | } | ||||
| const { reset, register, handleSubmit } = useForm() | |||||
| const { reset, register, handleSubmit, watch } = useForm({ | |||||
| defaultValues: { | |||||
| refNo: searchCriteria.refNo || "", | |||||
| code: searchCriteria.code || "" | |||||
| } | |||||
| }); | |||||
| const refNo = watch("refNo"); | |||||
| const code = watch("code"); | |||||
| const clearSubmitDates = () => { | |||||
| setMinDate(null); | |||||
| setMaxDate(null); | |||||
| }; | |||||
| const restoreDefaultSubmitDates = () => { | |||||
| setMinDate(getDefaultDateFrom()); | |||||
| setMaxDate(getDefaultDateTo()); | |||||
| }; | |||||
| const hasOtherCriteria = (textFields = {}) => { | |||||
| if (!isBlank(textFields.refNo)) return true; | |||||
| if (!isBlank(textFields.code)) return true; | |||||
| if (issueSelected?.id) return true; | |||||
| if (status?.type && status.type !== "all" && status.type !== "") return true; | |||||
| return false; | |||||
| }; | |||||
| React.useEffect(() => { | |||||
| const hasOther = hasOtherCriteria({ refNo, code }); | |||||
| if (prevHasOtherRef.current === null) { | |||||
| prevHasOtherRef.current = hasOther; | |||||
| return; | |||||
| } | |||||
| if (hasOther && !prevHasOtherRef.current) { | |||||
| clearSubmitDates(); | |||||
| } else if (!hasOther && prevHasOtherRef.current) { | |||||
| // Only refill defaults when From or To is empty; keep user-entered dates otherwise | |||||
| if (isSubmitDateEmpty(minDate) || isSubmitDateEmpty(maxDate)) { | |||||
| restoreDefaultSubmitDates(); | |||||
| } | |||||
| } | |||||
| prevHasOtherRef.current = hasOther; | |||||
| }, [refNo, code, issueSelected, status]); | |||||
| const onSubmit = (data) => { | const onSubmit = (data) => { | ||||
| let typeArray = []; | let typeArray = []; | ||||
| let sentDateFrom = ""; | let sentDateFrom = ""; | ||||
| @@ -72,11 +131,25 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| typeArray.push(type[i].label); | typeArray.push(type[i].label); | ||||
| } | } | ||||
| if (fromDateValue != "dd / mm / yyyy" && toDateValue != "dd / mm / yyyy") { | |||||
| sentDateFrom = DateUtils.dateValue(fromDateValue) | |||||
| sentDateTo = DateUtils.dateValue(toDateValue) | |||||
| const hasOther = hasOtherCriteria({ | |||||
| refNo: data.refNo, | |||||
| code: data.code | |||||
| }); | |||||
| const datesEmpty = isSubmitDateEmpty(fromDateValue) || isSubmitDateEmpty(toDateValue) | |||||
| || minDate == null || maxDate == null; | |||||
| if (!hasOther && datesEmpty) { | |||||
| const dateFrom = getDefaultDateFrom(); | |||||
| const dateTo = getDefaultDateTo(); | |||||
| setMinDate(dateFrom); | |||||
| setMaxDate(dateTo); | |||||
| sentDateFrom = dateFrom; | |||||
| sentDateTo = dateTo; | |||||
| } else if (!datesEmpty) { | |||||
| sentDateFrom = DateUtils.dateValue(fromDateValue); | |||||
| sentDateTo = DateUtils.dateValue(toDateValue); | |||||
| } | } | ||||
| const temp = { | const temp = { | ||||
| refNo: data.refNo, | refNo: data.refNo, | ||||
| code: data.code, | code: data.code, | ||||
| @@ -85,7 +158,15 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| dateFrom: sentDateFrom, | dateFrom: sentDateFrom, | ||||
| dateTo: sentDateTo, | dateTo: sentDateTo, | ||||
| statusKey:status?.key, | statusKey:status?.key, | ||||
| start: 0, | |||||
| limit: 10, | |||||
| }; | }; | ||||
| if (searchCriteria?.sort && searchCriteria?.direction) { | |||||
| temp.sort = searchCriteria.sort; | |||||
| temp.direction = searchCriteria.direction; | |||||
| } | |||||
| if(status?.type && status?.type != 'all'){ | if(status?.type && status?.type != 'all'){ | ||||
| if (status?.type == "Confirmed"){ | if (status?.type == "Confirmed"){ | ||||
| temp["replyed"] = "T"; | temp["replyed"] = "T"; | ||||
| @@ -120,13 +201,27 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| setStatus(ComboData.proofStatusFull[0]); | setStatus(ComboData.proofStatusFull[0]); | ||||
| setIssueSelected(null); | setIssueSelected(null); | ||||
| setGroupSelected({}); | setGroupSelected({}); | ||||
| setMinDate(DateUtils.dateValue(new Date().setDate(new Date().getDate()-14))) | |||||
| setMaxDate(DateUtils.dateValue(new Date())) | |||||
| const dateFrom = getDefaultDateFrom(); | |||||
| const dateTo = getDefaultDateTo(); | |||||
| setMinDate(dateFrom); | |||||
| setMaxDate(dateTo); | |||||
| reset({ | reset({ | ||||
| refNo:"", | refNo:"", | ||||
| code:"", | code:"", | ||||
| }); | }); | ||||
| localStorage.setItem('searchCriteria',"") | |||||
| prevHasOtherRef.current = false; | |||||
| localStorage.setItem('searchCriteria',""); | |||||
| applySearch({ | |||||
| refNo: "", | |||||
| code: "", | |||||
| issueId: "", | |||||
| gazettGroup: "", | |||||
| dateFrom, | |||||
| dateTo, | |||||
| statusKey: 0, | |||||
| start: 0, | |||||
| limit: 10 | |||||
| }); | |||||
| } | } | ||||
| function getIssueLabel(data) { | function getIssueLabel(data) { | ||||
| @@ -261,22 +356,21 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| <DemoItem components={['DatePicker']}> | <DemoItem components={['DatePicker']}> | ||||
| <DatePicker | <DatePicker | ||||
| id="dateFrom" | id="dateFrom" | ||||
| // onError={(newError) => setReceiptFromError(newError)} | |||||
| onError={() => {}} | |||||
| slotProps={{ | slotProps={{ | ||||
| field: { readOnly: true, }, | |||||
| // textField: { | |||||
| // helperText: receiptFromErrorMessage, | |||||
| // }, | |||||
| field: { readOnly: true, clearable: true }, | |||||
| textField: { | |||||
| InputLabelProps: { shrink: true }, | |||||
| error: false, | |||||
| helperText: null | |||||
| }, | |||||
| }} | }} | ||||
| format="DD/MM/YYYY" | format="DD/MM/YYYY" | ||||
| label={intl.formatMessage({id: 'proofDateFrom'})} | label={intl.formatMessage({id: 'proofDateFrom'})} | ||||
| value={minDate === null ? null : dayjs(minDate)} | |||||
| maxDate={maxDate === null ? null : dayjs(maxDate)} | |||||
| value={toDayjsOrNull(minDate)} | |||||
| maxDate={toDayjsOrNull(maxDate)} | |||||
| onChange={(newValue) => { | onChange={(newValue) => { | ||||
| // console.log(newValue) | |||||
| if(newValue!=null){ | |||||
| setMinDate(newValue); | |||||
| } | |||||
| setMinDate(newValue && newValue.isValid?.() ? newValue : null); | |||||
| }} | }} | ||||
| /> | /> | ||||
| </DemoItem > | </DemoItem > | ||||
| @@ -288,22 +382,21 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| <DemoItem components={['DatePicker']}> | <DemoItem components={['DatePicker']}> | ||||
| <DatePicker | <DatePicker | ||||
| id="dateTo" | id="dateTo" | ||||
| // onError={(newError) => setReceiptFromError(newError)} | |||||
| onError={() => {}} | |||||
| slotProps={{ | slotProps={{ | ||||
| field: { readOnly: true, }, | |||||
| // textField: { | |||||
| // helperText: receiptFromErrorMessage, | |||||
| // }, | |||||
| field: { readOnly: true, clearable: true }, | |||||
| textField: { | |||||
| InputLabelProps: { shrink: true }, | |||||
| error: false, | |||||
| helperText: null | |||||
| }, | |||||
| }} | }} | ||||
| format="DD/MM/YYYY" | format="DD/MM/YYYY" | ||||
| label={intl.formatMessage({id: 'proofDateTo'})} | label={intl.formatMessage({id: 'proofDateTo'})} | ||||
| value={maxDate === null ? null : dayjs(maxDate)} | |||||
| minDate={minDate === null ? null : dayjs(minDate)} | |||||
| value={toDayjsOrNull(maxDate)} | |||||
| minDate={toDayjsOrNull(minDate)} | |||||
| onChange={(newValue) => { | onChange={(newValue) => { | ||||
| // console.log(newValue) | |||||
| if(newValue!=null){ | |||||
| setMaxDate(newValue); | |||||
| } | |||||
| setMaxDate(newValue && newValue.isValid?.() ? newValue : null); | |||||
| }} | }} | ||||
| /> | /> | ||||
| </DemoItem > | </DemoItem > | ||||
| @@ -121,7 +121,10 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, onGridReady }) => | |||||
| if (hasOther && !prevHasOtherRef.current) { | if (hasOther && !prevHasOtherRef.current) { | ||||
| clearSubmitDates(); | clearSubmitDates(); | ||||
| } else if (!hasOther && prevHasOtherRef.current) { | } else if (!hasOther && prevHasOtherRef.current) { | ||||
| restoreDefaultSubmitDates(); | |||||
| // Only refill defaults when From or To is empty; keep user-entered dates otherwise | |||||
| if (isSubmitDateEmpty(minDate) || isSubmitDateEmpty(maxDate)) { | |||||
| restoreDefaultSubmitDates(); | |||||
| } | |||||
| } | } | ||||
| prevHasOtherRef.current = hasOther; | prevHasOtherRef.current = hasOther; | ||||
| }, [appNo, contact, careOf, status]); | }, [appNo, contact, careOf, status]); | ||||
| @@ -122,7 +122,10 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData, o | |||||
| if (hasOther && !prevHasOtherRef.current) { | if (hasOther && !prevHasOtherRef.current) { | ||||
| clearSubmitDates(); | clearSubmitDates(); | ||||
| } else if (!hasOther && prevHasOtherRef.current) { | } else if (!hasOther && prevHasOtherRef.current) { | ||||
| restoreDefaultSubmitDates(); | |||||
| // Only refill defaults when From or To is empty; keep user-entered dates otherwise | |||||
| if (isSubmitDateEmpty(minDate) || isSubmitDateEmpty(maxDate)) { | |||||
| restoreDefaultSubmitDates(); | |||||
| } | |||||
| } | } | ||||
| prevHasOtherRef.current = hasOther; | prevHasOtherRef.current = hasOther; | ||||
| }, [appNo, contact, groupNo, groupSelected, orgSelected, issueSelected, selectedStatus, selectedMode]); | }, [appNo, contact, groupNo, groupSelected, orgSelected, issueSelected, selectedStatus, selectedMode]); | ||||