@propriety/court-calendar 1.0.18 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts CHANGED
@@ -84,7 +84,7 @@ export interface Evidence {
84
84
  Evidence: string;
85
85
  ParcelID: string;
86
86
  Year: number;
87
- Uploaded: {
87
+ uploaded: {
88
88
  Evidence: string;
89
89
  UploadDate: Date | null;
90
90
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@propriety/court-calendar",
3
3
  "private": false,
4
- "version": "1.0.18",
4
+ "version": "1.0.21",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "./dist/index.mjs",
@@ -36,7 +36,7 @@
36
36
  }
37
37
 
38
38
  .themed,
39
- .themed div:not(.MuiAvatar-root, .iconHolder, .evidence-row, .timeline-connector),
39
+ .themed div:not(.MuiAvatar-root, .iconHolder, .evidence-row, .evidence-row *, .timeline-connector),
40
40
  .themed .MuiInputBase-root,
41
41
  .themed label,
42
42
  .themed a,
@@ -247,9 +247,7 @@ export default function CalendarList({
247
247
  .filter((date) => {
248
248
  if (!date.CourtDate) return false;
249
249
  const courtDate = new Date(date.CourtDate);
250
- return (
251
- courtDate.getMonth() === currentDate.getMonth() && courtDate.getFullYear() === currentDate.getFullYear()
252
- );
250
+ return courtDate.getFullYear() === currentDate.getFullYear();
253
251
  })
254
252
  .map((date) => ({
255
253
  id: date.CourtDateID,
@@ -8,7 +8,7 @@ export default function EvidenceSection({ evidence }: { evidence: Evidence | nul
8
8
  console.log('evidence in EvidenceSection:', evidence);
9
9
 
10
10
  // Check if uploaded evidence exists
11
- const hasUploadedEvidence = evidence?.Uploaded?.Evidence;
11
+ const hasUploadedEvidence = evidence?.uploaded?.Evidence;
12
12
 
13
13
  // Parse evidence types
14
14
  const parseEvidenceTypes = (evidenceStr: string | undefined): string[] => {
@@ -26,7 +26,7 @@ export default function EvidenceSection({ evidence }: { evidence: Evidence | nul
26
26
 
27
27
  // Get evidence types to display
28
28
  const evidenceTypes = hasUploadedEvidence
29
- ? parseEvidenceTypes(evidence.Uploaded.Evidence)
29
+ ? parseEvidenceTypes(evidence.uploaded.Evidence)
30
30
  : parseEvidenceTypes(evidence?.Evidence);
31
31
 
32
32
  const hasSales = evidenceTypes.some((type) => type.includes('sales') || type.includes('unequal'));
@@ -34,8 +34,8 @@ export default function EvidenceSection({ evidence }: { evidence: Evidence | nul
34
34
  const hasAnyEvidence = hasSales || hasEquity;
35
35
 
36
36
  // Format upload date if available
37
- const uploadDate = evidence?.Uploaded?.UploadDate
38
- ? new Date(evidence.Uploaded.UploadDate).toLocaleDateString()
37
+ const uploadDate = evidence?.uploaded?.UploadDate
38
+ ? new Date(evidence.uploaded.UploadDate).toLocaleDateString()
39
39
  : '';
40
40
 
41
41
  // format creation date if available
@@ -3,13 +3,14 @@ import type { CalendarFilterCtx, Case } from '@/types';
3
3
  import Box from '@mui/material/Box';
4
4
  import Stack from '@mui/material/Stack';
5
5
  import Typography from '@mui/material/Typography';
6
- import { formatEvidence } from '@/helpers/formatter';
7
6
  import CircularProgress from '@mui/material/CircularProgress';
7
+ import Tooltip from '@mui/material/Tooltip';
8
8
  import { DataGrid, type GridColDef } from '@mui/x-data-grid';
9
9
  import CaseToolbar from './CaseToolbar';
10
10
  import { filterCases } from '@/helpers/cases';
11
11
  import CheckCircleIcon from '@mui/icons-material/CheckCircle';
12
12
  import CancelIcon from '@mui/icons-material/Cancel';
13
+ import HourglassBottomIcon from '@mui/icons-material/HourglassBottom';
13
14
 
14
15
  const CaseViewer = memo(function CaseViewer({
15
16
  cases,
@@ -78,8 +79,44 @@ const CaseViewer = memo(function CaseViewer({
78
79
  {
79
80
  field: 'evidence',
80
81
  headerName: 'Evidence',
81
- width: 100,
82
+ width: 150,
82
83
  disableColumnMenu: true,
84
+ renderCell: (params) => {
85
+ const evidence = params.row._case.evidence;
86
+ if (!evidence || !evidence.Evidence) {
87
+ return (
88
+ <Tooltip title='No evidence'>
89
+ <Box display='flex' alignItems='center' gap={0.5} width='100%' mt={1.7}>
90
+ <CancelIcon sx={{ color: '#f44336', fontSize: 20 }} />
91
+ <Typography variant='body2'>None</Typography>
92
+ </Box>
93
+ </Tooltip>
94
+ );
95
+ }
96
+ const evidenceType = (evidence.uploaded?.Evidence || evidence.Evidence).replace(/[[\]"]+/g, '');
97
+ const hasBeenUploaded = evidence.uploaded && evidence.uploaded.Evidence;
98
+ if (hasBeenUploaded) {
99
+ const uploadDate = evidence.uploaded.UploadDate
100
+ ? new Date(evidence.uploaded.UploadDate).toLocaleDateString()
101
+ : 'unknown date';
102
+ return (
103
+ <Tooltip title={`Uploaded on ${uploadDate}`}>
104
+ <Box display='flex' alignItems='center' gap={0.5} width='100%' mt={1.7}>
105
+ <CheckCircleIcon sx={{ color: '#4caf50', fontSize: 20 }} />
106
+ <Typography variant='body2'>{evidenceType}</Typography>
107
+ </Box>
108
+ </Tooltip>
109
+ );
110
+ }
111
+ return (
112
+ <Tooltip title='Created, not yet uploaded'>
113
+ <Box display='flex' alignItems='center' gap={0.5} width='100%' mt={1.7}>
114
+ <HourglassBottomIcon sx={{ color: '#ff9800', fontSize: 20 }} />
115
+ <Typography variant='body2'>{evidenceType}</Typography>
116
+ </Box>
117
+ </Tooltip>
118
+ );
119
+ },
83
120
  },
84
121
  {
85
122
  field: 'determination',
@@ -130,7 +167,7 @@ const CaseViewer = memo(function CaseViewer({
130
167
  owner: caseItem.property_data?.PropertyOwnerFull || 'Loading...',
131
168
  reviewed: caseItem.DateCompleted ? 'Yes' : 'No',
132
169
  address: caseItem.property_data?.Address || 'Loading...',
133
- evidence: caseItem.evidence ? formatEvidence(caseItem.evidence) : 'N/A',
170
+ evidence: caseItem.evidence,
134
171
  determination: getActionDetail(caseItem),
135
172
  pid: caseItem.ParcelID || 'N/A',
136
173
  _case: caseItem,
@@ -164,22 +201,24 @@ const CaseViewer = memo(function CaseViewer({
164
201
  <div
165
202
  className='case-table-anim'
166
203
  style={{
167
- maxHeight: tableOpen ? 1000 : 0,
168
- overflow: 'hidden',
204
+ maxHeight: tableOpen ? 5000 : 0,
205
+ overflow: tableOpen ? 'visible' : 'hidden',
169
206
  transition: 'max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1)',
170
207
  }}
171
208
  >
172
209
  {!isFetchingCases && cases.length > 0 && (
173
- <Stack>
174
- <Box mb={2}>
175
- <CaseToolbar filterCtx={filterCtx} setFilterCtx={setFilterCtx} />
176
- </Box>
177
- <Box mx={1} mb={1} justifyContent={'center'} alignItems={'center'} display='flex'>
178
- <Typography variant='body1' fontStyle={''}>
179
- {rows.length} case{rows.length !== 1 ? 's' : ''} found, click a row to view additional
180
- case details.
181
- </Typography>
182
- </Box>
210
+ <>
211
+ <Stack>
212
+ <Box mb={2}>
213
+ <CaseToolbar filterCtx={filterCtx} setFilterCtx={setFilterCtx} />
214
+ </Box>
215
+ <Box mx={1} mb={1} justifyContent={'center'} alignItems={'center'} display='flex'>
216
+ <Typography variant='body1' fontStyle={''}>
217
+ {rows.length} case{rows.length !== 1 ? 's' : ''} found, click a row to view
218
+ additional case details.
219
+ </Typography>
220
+ </Box>
221
+ </Stack>
183
222
  <DataGrid
184
223
  autoHeight
185
224
  rows={rows}
@@ -196,7 +235,7 @@ const CaseViewer = memo(function CaseViewer({
196
235
  },
197
236
  }}
198
237
  />
199
- </Stack>
238
+ </>
200
239
  )}
201
240
  </div>
202
241
  </Box>
@@ -1,4 +1,4 @@
1
- import { HearingType, Lifecycle, type Case, type CourtDate } from '../../../types';
1
+ import { HearingType, type Case, type CourtDate } from '../../../types';
2
2
  import Box from '@mui/material/Box';
3
3
  import Typography from '@mui/material/Typography';
4
4
  import FormRow from '../../Shared/FormRow';
@@ -7,7 +7,7 @@ import Stack from '@mui/material/Stack';
7
7
  import { useReferenceData } from '@/context/ReferenceDataContext';
8
8
  import { useMemo } from 'react';
9
9
  import NoticeFileLink from './NoticeFileLink';
10
- import { isCaseSettled } from '@/helpers/cases';
10
+ import { isCaseSettled, isCaseUploadedOrSettled } from '@/helpers/cases';
11
11
  import StatusTimeline from './StatusTimeline';
12
12
  import AdjournedBox from './AdjournedBox';
13
13
  import ChairBox from './ChairBox';
@@ -36,12 +36,9 @@ export default function DateDetails({
36
36
 
37
37
  const allUploaded = useMemo(() => {
38
38
  if (!selectedCourtDate) return false;
39
- return (
40
- selectedCourtDate.Lifecycle === Lifecycle.UPLOADED ||
41
- selectedCourtDate.Lifecycle === Lifecycle.SCHEDULED ||
42
- selectedCourtDate.Lifecycle === Lifecycle.ADJOURNED
43
- );
44
- }, [selectedCourtDate]);
39
+ if (cases.length === 0) return false;
40
+ return cases.every((c) => isCaseUploadedOrSettled(c, isVillage));
41
+ }, [selectedCourtDate, cases]);
45
42
 
46
43
  const allSettled = useMemo(() => {
47
44
  if (cases.length === 0) return false;
@@ -65,7 +65,7 @@ export default function StatusTimeline({
65
65
  sx={{ color: 'var(--text, inherit)' }}
66
66
  >
67
67
  {stage.label}
68
- {skipped && ' (Skipped)'}
68
+ {skipped && ''}
69
69
  </Typography>
70
70
  </Stack>
71
71
  {index < stages.length - 1 && (
@@ -24,6 +24,7 @@ export default function Toolbar({
24
24
  handleCreateClick,
25
25
  currentView,
26
26
  setCurrentView,
27
+ currentDate,
27
28
  setCurrentDate,
28
29
  activeUser,
29
30
  isFetchingCases,
@@ -46,34 +47,43 @@ export default function Toolbar({
46
47
  useEffect(() => {
47
48
  if (calendarApi) {
48
49
  const handleDatesSet = () => {
49
- setCurrentTitle(calendarApi.getCurrentData().viewTitle);
50
+ if (currentView !== 'tableView') {
51
+ setCurrentTitle(calendarApi.getCurrentData().viewTitle);
52
+ }
50
53
  };
51
54
  calendarApi.on('datesSet', handleDatesSet);
52
55
  return () => {
53
56
  calendarApi.off('datesSet', handleDatesSet);
54
57
  };
55
58
  }
56
- }, [calendarApi]);
59
+ }, [calendarApi, currentView]);
57
60
 
58
61
  useEffect(() => {
62
+ if (currentView === 'tableView') {
63
+ setCurrentTitle(currentDate.getFullYear().toString());
64
+ return;
65
+ }
59
66
  if (calendarApi) {
60
- if (currentView === 'tableView') {
61
- setCurrentTitle(calendarApi.getDate().toLocaleDateString('en-US', { month: 'long', year: 'numeric' }));
62
- return;
63
- }
64
67
  setCurrentTitle(calendarApi.getCurrentData().viewTitle);
65
68
  }
66
- }, [calendarApi, currentView]);
69
+ }, [calendarApi, currentView, currentDate]);
67
70
 
68
71
  function goToToday() {
72
+ setCurrentDate(new Date());
73
+ if (currentView === 'tableView') return;
69
74
  if (calendarApi) {
70
75
  calendarApi.today();
71
- setCurrentDate(new Date());
72
76
  setCurrentTitle(calendarApi.getCurrentData().viewTitle);
73
77
  }
74
78
  }
75
79
 
76
80
  function handleNext() {
81
+ if (currentView === 'tableView') {
82
+ const next = new Date(currentDate);
83
+ next.setFullYear(next.getFullYear() + 1);
84
+ setCurrentDate(next);
85
+ return;
86
+ }
77
87
  if (calendarApi) {
78
88
  calendarApi.next();
79
89
  setCurrentDate(calendarApi.getDate());
@@ -82,6 +92,12 @@ export default function Toolbar({
82
92
  }
83
93
 
84
94
  function handlePrev() {
95
+ if (currentView === 'tableView') {
96
+ const prev = new Date(currentDate);
97
+ prev.setFullYear(prev.getFullYear() - 1);
98
+ setCurrentDate(prev);
99
+ return;
100
+ }
85
101
  if (calendarApi) {
86
102
  calendarApi.prev();
87
103
  setCurrentDate(calendarApi.getDate());
@@ -81,6 +81,11 @@ export function isCaseSettled(c: Case, isVillage: boolean): boolean {
81
81
  return false;
82
82
  }
83
83
 
84
+ export function isCaseUploadedOrSettled(c: Case, isVillage: boolean): boolean {
85
+ if (isCaseSettled(c, isVillage)) return true;
86
+ return c.evidence !== null && c.evidence.uploaded !== null && c.evidence.uploaded.Evidence !== null;
87
+ }
88
+
84
89
  export function isCaseMissingEvidence(c: Case): boolean {
85
90
  if (!c.evidence) return true;
86
91
  if (!c.evidence.Evidence || c.evidence.Evidence === null) return true;
@@ -38,8 +38,8 @@ function to24Hour(time: string): string {
38
38
  // [\"Sales\"] -> Sales
39
39
  export function formatEvidence(evidence: Evidence): string {
40
40
  if (!evidence || !evidence.Evidence) return '';
41
- const hasBeenUploaded = evidence.Uploaded && evidence.Uploaded.Evidence;
41
+ const hasBeenUploaded = evidence.uploaded && evidence.uploaded.Evidence;
42
42
  if (!hasBeenUploaded) return `${evidence.Evidence.replace(/[[\]"]+/g, '')} created`;
43
- const uploadDate = evidence.Uploaded.UploadDate ?? '';
44
- return `${evidence.Uploaded.Evidence.replace(/[[\]"]+/g, '')} uploaded on ${uploadDate ? new Date(uploadDate).toLocaleDateString() : 'unknown date'}`;
43
+ const uploadDate = evidence.uploaded.UploadDate ?? '';
44
+ return `${evidence.uploaded.Evidence.replace(/[[\]"]+/g, '')} uploaded on ${uploadDate ? new Date(uploadDate).toLocaleDateString() : 'unknown date'}`;
45
45
  }
package/src/types.ts CHANGED
@@ -104,7 +104,7 @@ export interface Evidence {
104
104
  Evidence: string;
105
105
  ParcelID: string;
106
106
  Year: number;
107
- Uploaded: {
107
+ uploaded: {
108
108
  Evidence: string;
109
109
  UploadDate: Date | null;
110
110
  };