@propriety/court-calendar 1.0.149 → 1.0.151

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.
Files changed (36) hide show
  1. package/dist/__tests__/StatusTimeline.test.d.ts +1 -0
  2. package/dist/__tests__/helpers/dateHistory.test.d.ts +1 -0
  3. package/dist/__tests__/timelineStages.test.d.ts +1 -0
  4. package/dist/_components/Modal/CaseDetails/CaseDetails.d.ts +4 -1
  5. package/dist/_components/Modal/DateDetails/DateDetails.d.ts +4 -2
  6. package/dist/_components/Modal/DateDetails/DateHistory.d.ts +10 -0
  7. package/dist/_components/Modal/DateDetails/timelineStages.d.ts +51 -0
  8. package/dist/_components/Modal/Layout/ModalActions.d.ts +3 -1
  9. package/dist/helpers/api/courtDates.d.ts +11 -2
  10. package/dist/helpers/cases.d.ts +10 -0
  11. package/dist/helpers/dateHistory.d.ts +50 -0
  12. package/dist/hooks/UseDateHistory.d.ts +17 -0
  13. package/dist/index.mjs +7228 -6996
  14. package/dist/types.d.ts +33 -1
  15. package/package.json +1 -1
  16. package/src/__tests__/StatusTimeline.test.tsx +84 -0
  17. package/src/__tests__/fixtures.ts +1 -0
  18. package/src/__tests__/helpers/api/courtDates.test.ts +63 -1
  19. package/src/__tests__/helpers/dateHistory.test.ts +199 -0
  20. package/src/__tests__/hooks/UseModalActions.test.ts +1 -0
  21. package/src/__tests__/timelineStages.test.ts +406 -0
  22. package/src/_components/Modal/CaseDetails/CaseDetails.tsx +24 -2
  23. package/src/_components/Modal/DateDetails/DateDetails.tsx +44 -66
  24. package/src/_components/Modal/DateDetails/DateHistory.tsx +81 -0
  25. package/src/_components/Modal/DateDetails/LogViewer.tsx +4 -0
  26. package/src/_components/Modal/DateDetails/timelineStages.ts +137 -0
  27. package/src/_components/Modal/DateEdit/CreateEditCase.tsx +13 -0
  28. package/src/_components/Modal/Layout/ModalActions.tsx +51 -17
  29. package/src/_components/Modal/Modal.tsx +12 -0
  30. package/src/constants.ts +1 -0
  31. package/src/helpers/api/courtDates.ts +46 -1
  32. package/src/helpers/cases.ts +15 -2
  33. package/src/helpers/dateHistory.ts +146 -0
  34. package/src/hooks/UseDateHistory.ts +60 -0
  35. package/src/hooks/UseModalActions.ts +1 -0
  36. package/src/types.ts +36 -0
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,9 @@
1
- import { Case } from '../../../types';
1
+ import { AdjournmentEntry, Case, DateEditItem } from '../../../types';
2
2
  declare const CaseDetails: import('react').NamedExoticComponent<{
3
3
  selectedCase: Case | null;
4
4
  isVillage: boolean;
5
+ muniCode?: string;
6
+ adjournments?: AdjournmentEntry[];
7
+ courtDateHistory?: DateEditItem[];
5
8
  }>;
6
9
  export default CaseDetails;
@@ -1,8 +1,10 @@
1
- import { Case, CourtDate } from '../../../types';
2
- export default function DateDetails({ selectedCourtDate, cases, isVillage, isFetchingCases, onUpdateChair, }: {
1
+ import { AdjournmentEntry, Case, CourtDate, DateEditItem } from '../../../types';
2
+ export default function DateDetails({ selectedCourtDate, cases, isVillage, isFetchingCases, onUpdateChair, adjournments, courtDateHistory, }: {
3
3
  selectedCourtDate: CourtDate | null;
4
4
  cases: Case[];
5
5
  isVillage: boolean;
6
6
  isFetchingCases?: boolean;
7
7
  onUpdateChair?: (position: 'first' | 'second', userId: number | null) => void;
8
+ adjournments?: AdjournmentEntry[];
9
+ courtDateHistory?: DateEditItem[];
8
10
  }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { HistoryEntry } from '../../../helpers/dateHistory';
2
+ /**
3
+ * Compact, newest-first trail of everything that has moved this court date — reschedules
4
+ * and bulk case adjournments. Renders nothing when there is no history, so unchanged court
5
+ * dates keep their header exactly as it was.
6
+ */
7
+ export default function DateHistory({ entries, align, }: {
8
+ entries: HistoryEntry[];
9
+ align?: 'center' | 'flex-start';
10
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,51 @@
1
+ import { Case } from '../../../types';
2
+ import { Status } from './StatusTimeline';
3
+ export interface StageResult {
4
+ status: Status;
5
+ count?: {
6
+ done: number;
7
+ total: number;
8
+ };
9
+ date?: Date;
10
+ }
11
+ /** Most recent of a set of possibly-missing dates, or undefined when none are set. */
12
+ export declare function latestDate(dates: (Date | null | undefined)[]): Date | undefined;
13
+ /**
14
+ * What an empty base means for a stage. The two cases are deliberately NOT symmetric:
15
+ *
16
+ * - 'complete' No work is left, so the stage is finished (green check). Used by
17
+ * Reviewed/Sent Offers/Uploaded: you cannot review, offer on, or upload
18
+ * for a case that already settled, so once every case is settled those
19
+ * stages are done by definition.
20
+ * - 'notStarted' The stage cannot have begun yet (empty circle). Used by Stipulation:
21
+ * a stipulation only exists once a case settles, so "nothing settled"
22
+ * means not started, not finished.
23
+ */
24
+ type EmptyBase = 'complete' | 'notStarted';
25
+ /**
26
+ * Collapses one timeline stage into a status.
27
+ *
28
+ * `base` is the population the stage is measured against — the "X of Y" label is always
29
+ * done/base, never cases.length. `cases` is the full list on the date, used only to blank
30
+ * the timeline when the date has no cases at all, and to date the check when the base is
31
+ * empty but the stage still counts as complete.
32
+ */
33
+ export declare function stageStatus({ cases, base, isDone, dateOf, whenBaseEmpty, }: {
34
+ cases: Case[];
35
+ base: Case[];
36
+ isDone: (c: Case) => boolean;
37
+ dateOf: (done: Case[]) => Date | undefined;
38
+ whenBaseEmpty: EmptyBase;
39
+ }): StageResult;
40
+ export declare function reviewedStage(cases: Case[], isVillage: boolean): StageResult;
41
+ export declare function sentOffersStage(cases: Case[], isVillage: boolean): StageResult;
42
+ export declare function uploadedStage(cases: Case[], isVillage: boolean): StageResult;
43
+ /** Settled is the one stage measured against every case — it *is* the settlement rate. */
44
+ export declare function settledStage(cases: Case[], isVillage: boolean): StageResult;
45
+ /**
46
+ * Stipulations only exist on settled cases (~98% of stip rows in production sit on one),
47
+ * so "stips done / settled cases" is the meaningful ratio. Note the asymmetry with the
48
+ * stages above: an empty base here means not-started, not finished.
49
+ */
50
+ export declare function stipulationStage(cases: Case[], isVillage: boolean): StageResult;
51
+ export {};
@@ -1,9 +1,11 @@
1
1
  import { ModalMode } from '../types';
2
- export default function ModalActions({ modalMode, onDelete, onSave, setModalMode, setIsOpen, isAdmin, }: {
2
+ export default function ModalActions({ modalMode, onDelete, onSave, setModalMode, setIsOpen, isAdmin, createdBy, createdOn, }: {
3
3
  modalMode: ModalMode;
4
4
  onDelete: () => void;
5
5
  onSave: () => void;
6
6
  setModalMode: (mode: ModalMode) => void;
7
7
  setIsOpen: (isOpen: boolean) => void;
8
8
  isAdmin: boolean;
9
+ createdBy?: number | null;
10
+ createdOn?: Date | string | null;
9
11
  }): import("react/jsx-runtime").JSX.Element;
@@ -1,8 +1,17 @@
1
- import { DateType, CourtDate, DateEditLog } from '../../types';
1
+ import { DateType, CourtDate, CourtDateDetail, DateEditLog } from '../../types';
2
2
  export declare function getAllDates(apiKey: string, type?: DateType, dateFrom?: string, dateTo?: string): Promise<Array<CourtDate>>;
3
3
  export declare function updateCourtDate(courtDateId: number, updatedData: Partial<CourtDate>, apiKey: string, courtCases?: string[], user?: number, type?: DateType, skipMotion?: boolean, noticeFiles?: File[]): Promise<boolean>;
4
4
  export declare function getCourtDate(courtDateId: number, apiKey: string, type?: DateType): Promise<CourtDate | null>;
5
+ /**
6
+ * The full GET /court-dates/{id} payload, including the two history fields `getCourtDate`
7
+ * discards. Kept separate from `getCourtDate` so callers that only want the date itself
8
+ * (e.g. the post-save refresh in UseModalActions) keep their narrow return type.
9
+ *
10
+ * The negotiation branch of the endpoint returns neither `adjournments` nor the `CourtDate`
11
+ * edit-log trail, so both come back empty for negotiation dates rather than throwing.
12
+ */
13
+ export declare function getCourtDateDetail(courtDateId: number, apiKey: string, type?: DateType): Promise<CourtDateDetail | null>;
5
14
  export declare function deleteCourtDate(courtDateId: number, apiKey: string, type?: DateType): Promise<boolean>;
6
- export declare function createCourtDate(courtDate: Date, muniCode: string, apiKey: string, courtCases?: string[], hearingTime?: string, multipleDates?: Date[], type?: DateType, noticeFiles?: File[]): Promise<number | null>;
15
+ export declare function createCourtDate(courtDate: Date, muniCode: string, apiKey: string, courtCases?: string[], hearingTime?: string, multipleDates?: Date[], type?: DateType, noticeFiles?: File[], editUser?: number): Promise<number | null>;
7
16
  export declare function snoozeUploadDeadline(courtDateId: number, apiKey: string): Promise<boolean>;
8
17
  export declare function getDateEditLogs(courtDateId: number, apiKey: string, type?: DateType): Promise<DateEditLog | null>;
@@ -1,5 +1,15 @@
1
1
  import { CalendarFilterCtx, Case, NegotiationLog } from '../types';
2
2
  export declare function isCaseSettled(c: Case, isVillage: boolean): boolean;
3
+ /**
4
+ * The raw upload fact: this case's evidence is up on NYSCEF. Says nothing about
5
+ * settlement — use this when settled cases have already been filtered out.
6
+ */
7
+ export declare function hasCaseUploadedEvidence(c: Case): boolean;
8
+ /**
9
+ * True when the case needs no upload — either it settled (mooting the upload) or the
10
+ * evidence is already up. This is the "nothing left to chase" predicate behind the
11
+ * calendar/week upload badges; it is NOT the Uploaded timeline stage.
12
+ */
3
13
  export declare function isCaseUploadedOrSettled(c: Case, isVillage: boolean): boolean;
4
14
  export declare function isCaseMissingEvidence(c: Case): boolean;
5
15
  export declare function hasCaseUnuploadedEvidence(c: Case): boolean;
@@ -0,0 +1,50 @@
1
+ import { AdjournmentEntry, Case, DateEditItem, User } from '../types';
2
+ export interface HistoryEntry {
3
+ /** Stable React key. */
4
+ key: string;
5
+ kind: 'reschedule' | 'adjournment';
6
+ /** When the change was recorded. Used for ordering. */
7
+ at: Date | null;
8
+ /** Reschedule only — the date it moved off of. */
9
+ from: Date | null;
10
+ /** The date it moved to (reschedule) or was adjourned to (adjournment). */
11
+ to: Date | null;
12
+ /** Adjournment only — how many cases share this adjourned-to date. */
13
+ caseCount: number;
14
+ /** Resolved user name, or '—' when unattributable. Adjournment rows are never attributed. */
15
+ by: string;
16
+ }
17
+ /**
18
+ * Parse a date coming out of the history payloads.
19
+ *
20
+ * Two formats arrive here: the edit log stores `"2026-04-22 10:00:00"` (a space, no zone),
21
+ * while serialized `AdjournmentDate` values are ISO. Both are parsed from their Y-M-D parts
22
+ * as *local* time — `new Date("2026-04-22")` would be read as UTC and render as the previous
23
+ * day for anyone west of Greenwich, which is the same trap `formatDate` in DateDetails guards.
24
+ */
25
+ export declare function parseHistoryDate(value: Date | string | null | undefined): Date | null;
26
+ /**
27
+ * Resolve an edit-log `UpdatedBy` to a display name.
28
+ *
29
+ * The underlying column is a varchar that in practice holds user IDs, the literal 420,
30
+ * usernames, and NULL. Anything that doesn't resolve to a known user becomes '—' rather
31
+ * than a meaningless "User 420".
32
+ */
33
+ export declare function resolveUserName(updatedBy: number | string | null | undefined, allUsers: Record<number, User>): string;
34
+ /**
35
+ * Merge the court date's reschedule trail with its case adjournments into one
36
+ * time-ordered list, newest first.
37
+ *
38
+ * Adjournments are grouped by the date they were adjourned *to*, so a bulk adjournment of
39
+ * 20 cases onto one date collapses into a single entry. Without this the header trail would
40
+ * be 20 identical chips — CourtDateID 296 is exactly that shape in production.
41
+ */
42
+ export declare function buildDateHistory(courtDateHistory: DateEditItem[], adjournments: AdjournmentEntry[], allUsers: Record<number, User>): HistoryEntry[];
43
+ /**
44
+ * The adjournment rows belonging to a single case.
45
+ *
46
+ * Village dates key on VillageSCARIndexNumber and town dates on SCARIndexNumber, so the
47
+ * muni decides which index to match on — matching the wrong one silently returns nothing.
48
+ * `caseIndexForMuni` is the single source of truth for that rule.
49
+ */
50
+ export declare function adjournmentsForCase(adjournments: AdjournmentEntry[], muniCode: string, c: Pick<Case, 'SCARIndexNumber' | 'VillageSCARIndexNumber'>): AdjournmentEntry[];
@@ -0,0 +1,17 @@
1
+ import { AdjournmentEntry, CourtDate, DateEditItem } from '../types';
2
+ /**
3
+ * Fetches the history side of `GET /court-dates/{id}` — the case adjournment rows and the
4
+ * trail of CourtDate reschedules.
5
+ *
6
+ * Lives at the modal level rather than inside a panel because every `ModalPanel` stays
7
+ * mounted (they cross-fade rather than unmount), so fetching per-panel would fire the same
8
+ * request from both the details header and the case details panel.
9
+ *
10
+ * @param selectedCourtDate The court date currently displayed in the modal.
11
+ * @param modalIsOpen Whether the modal is open; nothing is fetched while closed.
12
+ */
13
+ export declare function useDateHistory(selectedCourtDate: CourtDate | null, modalIsOpen: boolean): {
14
+ adjournments: AdjournmentEntry[];
15
+ courtDateHistory: DateEditItem[];
16
+ isLoading: boolean;
17
+ };