@propriety/court-calendar 1.0.155 → 1.0.157
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/__tests__/CalendarLegend.test.d.ts +1 -0
- package/dist/__tests__/CalendarListLabels.test.d.ts +1 -0
- package/dist/__tests__/CreateEditCaseOpenCases.test.d.ts +1 -0
- package/dist/__tests__/ReferenceDataLookups.test.d.ts +1 -0
- package/dist/__tests__/fixtures.d.ts +2 -0
- package/dist/__tests__/helpers/eventLabel.test.d.ts +1 -0
- package/dist/__tests__/helpers/openCases.test.d.ts +1 -0
- package/dist/_components/Modal/DateEdit/OpenCaseSelector.d.ts +20 -0
- package/dist/_components/Modal/DateEdit/TextFieldList.d.ts +4 -1
- package/dist/_components/Shared/CountyDropdown.d.ts +15 -0
- package/dist/_components/Shared/SearchBar.d.ts +2 -1
- package/dist/context/ReferenceDataContext.d.ts +1 -0
- package/dist/helpers/api/cases.d.ts +32 -0
- package/dist/helpers/api/counties.d.ts +12 -0
- package/dist/helpers/eventLabel.d.ts +52 -0
- package/dist/helpers/formatter.d.ts +8 -0
- package/dist/helpers/openCases.d.ts +108 -0
- package/dist/index.mjs +9192 -8663
- package/package.json +1 -1
- package/src/__tests__/CalendarLegend.test.tsx +42 -0
- package/src/__tests__/CalendarListLabels.test.tsx +111 -0
- package/src/__tests__/CreateEditCaseOpenCases.test.tsx +288 -0
- package/src/__tests__/ReferenceDataLookups.test.tsx +99 -0
- package/src/__tests__/WeekWidget.test.tsx +4 -1
- package/src/__tests__/collectionsPipeline.test.ts +36 -0
- package/src/__tests__/fixtures.ts +14 -0
- package/src/__tests__/helpers/api/cases.test.ts +71 -0
- package/src/__tests__/helpers/eventLabel.test.ts +133 -0
- package/src/__tests__/helpers/formatter.test.ts +37 -1
- package/src/__tests__/helpers/openCases.test.ts +504 -0
- package/src/__tests__/hooks/UseModalActions.test.ts +1 -0
- package/src/_components/CCalendar.tsx +9 -0
- package/src/_components/CalendarLegend.tsx +11 -3
- package/src/_components/List/CalendarList.tsx +22 -5
- package/src/_components/Modal/DateDetails/DateDetails.tsx +20 -3
- package/src/_components/Modal/DateEdit/CreateEditCase.tsx +123 -32
- package/src/_components/Modal/DateEdit/OpenCaseSelector.tsx +338 -0
- package/src/_components/Modal/DateEdit/TextFieldList.tsx +5 -1
- package/src/_components/Shared/CountyDropdown.tsx +73 -0
- package/src/_components/Shared/SearchBar.tsx +3 -1
- package/src/_components/WeekWidget/WeekWidget.tsx +24 -14
- package/src/context/ReferenceDataContext.tsx +61 -27
- package/src/helpers/api/cases.ts +52 -0
- package/src/helpers/api/counties.ts +32 -0
- package/src/helpers/eventLabel.ts +104 -0
- package/src/helpers/formatter.ts +18 -0
- package/src/helpers/openCases.ts +271 -0
- package/src/hooks/UseCalendarEvents.ts +34 -14
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Case, CourtDate, CalendarFilterCtx } from '../types';
|
|
2
|
+
import { OpenCase } from '../helpers/api/cases';
|
|
2
3
|
export declare const MOCK_API_KEY = "test-api-key-123";
|
|
3
4
|
export declare const MOCK_USER_ID = 42;
|
|
4
5
|
export declare function makeCourtDate(overrides?: Partial<CourtDate>): CourtDate;
|
|
6
|
+
export declare function makeOpenCase(overrides?: Partial<OpenCase>): OpenCase;
|
|
5
7
|
export declare function makeCase(overrides?: Partial<Case>): Case;
|
|
6
8
|
export declare const DEFAULT_FILTER_CTX: CalendarFilterCtx;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Case } from '../../../types';
|
|
2
|
+
/**
|
|
3
|
+
* The Case IDs list rendered as a pick-list of the muni's open cases, with the client name
|
|
4
|
+
* alongside each one — so a hearing notice that names only "Bonaimo" can be resolved to an
|
|
5
|
+
* index number without leaving the form.
|
|
6
|
+
*
|
|
7
|
+
* There is no selection state of its own: a row is checked exactly when its case is already
|
|
8
|
+
* in `editedCases`, which is the same array the manual text fields edit. That is what makes
|
|
9
|
+
* switching between the two modes seamless, and it means a checked row can never drift out
|
|
10
|
+
* of sync with what will actually be saved.
|
|
11
|
+
*/
|
|
12
|
+
export default function OpenCaseSelector({ muniCode, isVillage, editedCases, setEditedCases, isParcelIdMode, setIsParcelIdMode, defaultYear, }: {
|
|
13
|
+
muniCode: string;
|
|
14
|
+
isVillage: boolean;
|
|
15
|
+
editedCases: Case[];
|
|
16
|
+
setEditedCases: (cases: Case[]) => void;
|
|
17
|
+
isParcelIdMode: boolean[];
|
|
18
|
+
setIsParcelIdMode: (toggles: boolean[]) => void;
|
|
19
|
+
defaultYear: number;
|
|
20
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export default function TextFieldList({ textFields, setTextFields, label, fieldLabelPrefix, toggleStates, setToggleStates, alternateFieldLabelPrefix, headerAction, }: {
|
|
2
3
|
textFields: string[];
|
|
3
4
|
setTextFields: (fields: string[], toggles?: boolean[]) => void;
|
|
4
5
|
label: string;
|
|
@@ -6,4 +7,6 @@ export default function TextFieldList({ textFields, setTextFields, label, fieldL
|
|
|
6
7
|
toggleStates?: boolean[];
|
|
7
8
|
setToggleStates?: (toggles: boolean[]) => void;
|
|
8
9
|
alternateFieldLabelPrefix?: string;
|
|
10
|
+
/** Rendered at the end of the header row — e.g. an alternative way to fill the list. */
|
|
11
|
+
headerAction?: React.ReactNode;
|
|
9
12
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* County picker for collections dates, which are scheduled for a whole county rather
|
|
3
|
+
* than one municipality. The selected value is stored in the same MuniCode field every
|
|
4
|
+
* other date type uses, but holds a county code ('N') instead of a muni code ('N2000').
|
|
5
|
+
*
|
|
6
|
+
* Deliberately not part of MuniDropdown: only collections may pick a county, and county
|
|
7
|
+
* entries must never appear in the municipality list.
|
|
8
|
+
*/
|
|
9
|
+
export default function CountyDropdown({ selectedCounty, setSelectedCounty, size, onOpen, onClose, }: {
|
|
10
|
+
selectedCounty: string | null;
|
|
11
|
+
setSelectedCounty: (countyCode: string) => void;
|
|
12
|
+
size: 'small' | 'medium';
|
|
13
|
+
onOpen?: () => void;
|
|
14
|
+
onClose?: () => void;
|
|
15
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export default function SearchBar({ searchTerm, setSearchTerm, width, }: {
|
|
1
|
+
export default function SearchBar({ searchTerm, setSearchTerm, width, placeholder, }: {
|
|
2
2
|
searchTerm: string;
|
|
3
3
|
setSearchTerm: (term: string) => void;
|
|
4
4
|
width?: string | number;
|
|
5
|
+
placeholder?: string;
|
|
5
6
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -5,6 +5,7 @@ interface ReferenceDataContextType {
|
|
|
5
5
|
allUsers: Record<number, User>;
|
|
6
6
|
allHearingOfficers: Record<number, HearingOfficer>;
|
|
7
7
|
allMuniNames: Record<string, Muni>;
|
|
8
|
+
allCounties: Record<string, string>;
|
|
8
9
|
getTownshipName: (muniCode: string) => string;
|
|
9
10
|
getCountyName: (muniCode: string) => string;
|
|
10
11
|
isLoading: boolean;
|
|
@@ -48,4 +48,36 @@ export declare function uploadMotionToPreclude(courtDateId: number, apiKey: stri
|
|
|
48
48
|
test?: boolean;
|
|
49
49
|
userId?: number;
|
|
50
50
|
}): Promise<MotionUploadResult>;
|
|
51
|
+
/**
|
|
52
|
+
* A case returned by /court-cases/open-cases — a much thinner record than `Case`, carrying
|
|
53
|
+
* only what the picker needs to identify a property by owner name.
|
|
54
|
+
*
|
|
55
|
+
* `SCARIndexNumber` holds whichever index applies to the level queried: the backend aliases
|
|
56
|
+
* `VillageSCARIndexNumber AS SCARIndexNumber` for village munis, so there is one index field
|
|
57
|
+
* and it is always the right one. `retainer_name` is the *retainer*, not necessarily the
|
|
58
|
+
* assessment-roll owner, and both it and `Address` are nullable (they come from LEFT JOINs).
|
|
59
|
+
*/
|
|
60
|
+
export interface OpenCase {
|
|
61
|
+
ParcelID: string;
|
|
62
|
+
SCARIndexNumber: string;
|
|
63
|
+
Year: number;
|
|
64
|
+
retainer_name: string | null;
|
|
65
|
+
Address: string | null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Open (filed, unscheduled, unsettled) cases for a municipality and tax year.
|
|
69
|
+
*
|
|
70
|
+
* **Pass the court date's `MuniCode` verbatim — do not pad it.** The backend derives two
|
|
71
|
+
* things from this one string, and padding breaks both:
|
|
72
|
+
* - It decides town vs village by `len(muni_code) > 3`, so padding "S05" to "S0500" makes it
|
|
73
|
+
* run the *village* query for a town date.
|
|
74
|
+
* - It matches `ParcelID LIKE '<muni_code>%'`. A town's SCAR calendar legitimately includes
|
|
75
|
+
* parcels sitting inside its villages ("S0501-…" carries a town index number), so the
|
|
76
|
+
* short code is what selects the right population, not an over-broad one.
|
|
77
|
+
*
|
|
78
|
+
* Unlike its siblings this *throws* on a non-OK response instead of returning []. The picker
|
|
79
|
+
* has to tell "the request failed" apart from "this muni has no open cases", and a silent
|
|
80
|
+
* empty array reads as the latter.
|
|
81
|
+
*/
|
|
82
|
+
export declare function fetchOpenCases(muniCode: string, year: number, apiKey: string): Promise<OpenCase[]>;
|
|
51
83
|
export declare function updateCaseAdjournment(parcelId: string, scarIndexNumber: string, adjournedDate: Date | null, apiKey: string): Promise<boolean>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* County code -> county name, e.g. { N: 'Nassau', W: 'Westchester' }.
|
|
3
|
+
*
|
|
4
|
+
* A county code is the single letter every municipality code starts with, so 'N'
|
|
5
|
+
* covers all of Nassau just as 'N2000' covers Hempstead. Collections dates are
|
|
6
|
+
* scheduled per county rather than per municipality and store one of these codes
|
|
7
|
+
* in MuniCode.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately a separate endpoint from /utils/get-muni-names: county codes must
|
|
10
|
+
* not appear in the municipality dropdown.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getAllCounties(apiKey: string): Promise<Record<string, string>>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { DateType } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* The pieces every surface builds a date's label from.
|
|
4
|
+
*
|
|
5
|
+
* Kept as parts rather than a finished string because the surfaces compose them
|
|
6
|
+
* differently: the calendar wants one line, the week widget stacks two, and the table
|
|
7
|
+
* already has its own Type and County columns and only needs the place.
|
|
8
|
+
*/
|
|
9
|
+
export interface DateLabelParts {
|
|
10
|
+
/** 'Collections' | 'Negotiations'. Null for SCAR — a court date is the default. */
|
|
11
|
+
typeWord: string | null;
|
|
12
|
+
/** County for Collections, township/village otherwise. '' when unresolvable. */
|
|
13
|
+
place: string;
|
|
14
|
+
/** ' (3100)' — SCAR only. Non-court types drop the code. */
|
|
15
|
+
codeSuffix: string;
|
|
16
|
+
/**
|
|
17
|
+
* Whether a case count means anything. SCAR only: collections are scheduled
|
|
18
|
+
* without cases, and negotiation dates are never linked to any, so both would
|
|
19
|
+
* show a permanent "x0".
|
|
20
|
+
*/
|
|
21
|
+
showCaseCount: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a date's label parts.
|
|
25
|
+
*
|
|
26
|
+
* `getTownshipName` and `getCountyName` come from `useReferenceData()` — passed in
|
|
27
|
+
* rather than imported so this stays a pure function that tests can drive directly.
|
|
28
|
+
*/
|
|
29
|
+
export declare function dateLabelParts(dateType: DateType | null | undefined, muniCode: string, getTownshipName: (muniCode: string) => string, getCountyName: (muniCode: string) => string): DateLabelParts;
|
|
30
|
+
/**
|
|
31
|
+
* One line naming the date, with no counts or day/adjournment markers.
|
|
32
|
+
* Used by the tooltip, the details modal header and anywhere a plain title is wanted.
|
|
33
|
+
*/
|
|
34
|
+
export declare function dateHeadline(parts: DateLabelParts): string;
|
|
35
|
+
export interface EventTitleOptions {
|
|
36
|
+
/** Marks the occurrence as an adjournment: "Greenburgh (A) (3100)". */
|
|
37
|
+
adjourned?: boolean;
|
|
38
|
+
/** 1-based day for a multi-date hearing; omitted for a single-day date. */
|
|
39
|
+
dayNumber?: number;
|
|
40
|
+
/** Open case count, appended as "x4" when the type supports counts. */
|
|
41
|
+
unsettled?: number;
|
|
42
|
+
/** Leading verb for derived events, e.g. 'Upload' or 'Can Preclude'. */
|
|
43
|
+
prefix?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The FullCalendar event title.
|
|
47
|
+
*
|
|
48
|
+
* Carries no time — FullCalendar renders that itself from the event's `start`, using
|
|
49
|
+
* the `eventTimeFormat` set on the calendar, and prepends it. So a collections event
|
|
50
|
+
* reads "1pm Collections Nassau" on screen while this returns "Collections Nassau".
|
|
51
|
+
*/
|
|
52
|
+
export declare function formatEventTitle(parts: DateLabelParts, options?: EventTitleOptions): string;
|
|
@@ -9,4 +9,12 @@ export declare function formatDisplayDate(date: Date | string | null | undefined
|
|
|
9
9
|
export declare function formatDateForAPI(date: Date): string;
|
|
10
10
|
export declare function formatDateTimeForAPI(date: Date, hearingTime?: string): string;
|
|
11
11
|
export declare function to24Hour(time: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* A stored hearing time as "1pm" / "9:30am", or "" when there is nothing to show.
|
|
14
|
+
*
|
|
15
|
+
* Matches the `eventTimeFormat` the calendar passes to FullCalendar, so a chip rendered
|
|
16
|
+
* outside FullCalendar reads the same as the event it refers to. Accepts anything
|
|
17
|
+
* `to24Hour` accepts — "13:00:00" from Collections, "2:30 PM" from a picker, "10:30".
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatClockTime(time: string | null | undefined): string;
|
|
12
20
|
export declare function formatEvidence(evidence: Evidence): string;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Case } from '../types';
|
|
2
|
+
import { OpenCase } from './api/cases';
|
|
3
|
+
/** A grid row: an OpenCase plus the stable id the DataGrid and the selection Map key on. */
|
|
4
|
+
export type OpenCaseRow = OpenCase & {
|
|
5
|
+
id: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* June (0-based). A SCAR hearing held in Jan–May of calendar year N is leftover work for
|
|
9
|
+
* tax year N-1; hearings for tax year N start in the summer. Named because it is a
|
|
10
|
+
* heuristic, not a rule — the picker always lets the user change the year.
|
|
11
|
+
*/
|
|
12
|
+
export declare const TAX_YEAR_ROLLOVER_MONTH = 5;
|
|
13
|
+
export declare function defaultTaxYear(courtDate: Date | string | null | undefined, now?: Date): number;
|
|
14
|
+
/**
|
|
15
|
+
* Years offered in the picker, newest first, centred on `base` so a wrong guess is one click
|
|
16
|
+
* to fix. `current` is folded in so a year the user has already navigated to always remains a
|
|
17
|
+
* valid option for the Select, even once it falls outside the window.
|
|
18
|
+
*/
|
|
19
|
+
export declare function taxYearOptions(base: number, current?: number): number[];
|
|
20
|
+
/**
|
|
21
|
+
* Matches a case against the search box — owner name, address, index number or parcel,
|
|
22
|
+
* case-insensitive substring. An empty term matches everything.
|
|
23
|
+
*
|
|
24
|
+
* Fields are tested individually rather than joined into one string: joining lets a
|
|
25
|
+
* multi-word term straddle two fields and match a case it has nothing to do with.
|
|
26
|
+
*/
|
|
27
|
+
export declare function openCaseMatchesSearchTerm(oc: OpenCase, term: string): boolean;
|
|
28
|
+
export declare function openCaseRowId(oc: OpenCase): string;
|
|
29
|
+
/**
|
|
30
|
+
* Adds grid ids and drops duplicate rows. The endpoint has no DISTINCT and joins Retainers
|
|
31
|
+
* on (ParcelID, Year), so a parcel with more than one retainer row comes back more than
|
|
32
|
+
* once — and a duplicate id makes DataGrid throw rather than merely look odd.
|
|
33
|
+
*/
|
|
34
|
+
export declare function toOpenCaseRows(cases: OpenCase[]): OpenCaseRow[];
|
|
35
|
+
/**
|
|
36
|
+
* Every string by which a case can be recognised as "already here".
|
|
37
|
+
*
|
|
38
|
+
* Deliberately keyed on the *index numbers and parcel alone, never the year*: rows the user
|
|
39
|
+
* typed by hand inherit DEFAULT_CASE.Year (the current calendar year), which will not equal
|
|
40
|
+
* the tax year they are browsing, so a year-qualified parcel key would never match and the
|
|
41
|
+
* same property could be added twice.
|
|
42
|
+
*/
|
|
43
|
+
export declare function openCaseDedupeKeys(oc: OpenCase): string[];
|
|
44
|
+
/**
|
|
45
|
+
* The same keys for a row already in the form. Emits *both* index forms plus the one
|
|
46
|
+
* `caseIndexForMuni` resolves, so a village case typed in as a county index still matches.
|
|
47
|
+
*/
|
|
48
|
+
export declare function caseDedupeKeys(c: Case, muniCode: string): string[];
|
|
49
|
+
/** True for the empty row CREATE mode seeds, and for any row the user cleared out. */
|
|
50
|
+
export declare function isBlankCaseRow(c: Case): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* The index this case will be linked under.
|
|
53
|
+
*
|
|
54
|
+
* There is only one index field to read: the backend queries the town or village columns
|
|
55
|
+
* based on the muni code's length and aliases either one to `SCARIndexNumber`. Which *form*
|
|
56
|
+
* field it lands in on the way back is `openCaseToCase`'s job.
|
|
57
|
+
*/
|
|
58
|
+
export declare function openCaseIndexFor(oc: OpenCase): string;
|
|
59
|
+
/** A row can be checked only if it has a usable index and is not already in the form. */
|
|
60
|
+
export declare function isRowPickable(oc: OpenCase, existingKeys: Set<string>): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Normalises the MUI X v8 selection model (`{ type: 'include' | 'exclude', ids: Set }`) into
|
|
63
|
+
* a plain set of visible, selected ids. `ids` is defensively checked for being a Set — the
|
|
64
|
+
* same guard CaseViewer makes, since the shape changed between major versions.
|
|
65
|
+
*/
|
|
66
|
+
export declare function resolveSelectedIds(model: {
|
|
67
|
+
type?: 'include' | 'exclude';
|
|
68
|
+
ids?: unknown;
|
|
69
|
+
} | null | undefined, visibleIds: string[]): Set<string>;
|
|
70
|
+
/**
|
|
71
|
+
* A draft Case carrying just enough to be saved and displayed. Municipality and the
|
|
72
|
+
* determination/valuation fields are left at their defaults on purpose: these rows exist
|
|
73
|
+
* only to contribute index numbers to the `court_cases` payload, and the calendar refetches
|
|
74
|
+
* the real cases from the API once the date is saved.
|
|
75
|
+
*/
|
|
76
|
+
export declare function openCaseToCase(oc: OpenCase, isVillage: boolean): Case;
|
|
77
|
+
/**
|
|
78
|
+
* Adds and removes picked cases in one pass, keeping `toggles` aligned with `cases`.
|
|
79
|
+
*
|
|
80
|
+
* This is what makes the two Case-ID modes interchangeable: the checkbox list and the text
|
|
81
|
+
* fields are two views of the same `editedCases`, so a row checked in one is a field in the
|
|
82
|
+
* other, and "what have I selected" never needs its own state to drift out of sync.
|
|
83
|
+
*/
|
|
84
|
+
export declare function applyOpenCaseSelection(existingCases: Case[], existingToggles: boolean[], toAdd: OpenCase[], toRemove: OpenCase[], muniCode: string): OpenCaseMergeResult;
|
|
85
|
+
export interface OpenCaseMergeResult {
|
|
86
|
+
cases: Case[];
|
|
87
|
+
/** Parcel-ID-mode flags, positionally aligned with `cases`. Always the same length. */
|
|
88
|
+
toggles: boolean[];
|
|
89
|
+
added: number;
|
|
90
|
+
/** Picks already present in the form. */
|
|
91
|
+
skipped: number;
|
|
92
|
+
/**
|
|
93
|
+
* Picks the API returned with no index number. The backend filters these out, so this is
|
|
94
|
+
* a backstop rather than a path the UI walks — the grid deliberately does not mark such
|
|
95
|
+
* rows unselectable, because a row already on the date is also "unpickable" and must stay
|
|
96
|
+
* clickable in order to be unchecked.
|
|
97
|
+
*/
|
|
98
|
+
unusable: number;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The single place picked cases are deduplicated and folded into the form's state.
|
|
102
|
+
*
|
|
103
|
+
* Returns `toggles` alongside `cases` because the two arrays are positionally coupled in
|
|
104
|
+
* CreateEditCase and its length-sync effect only fires when the *length* changes — replacing
|
|
105
|
+
* one blank Parcel-ID-mode row with one picked case would otherwise leave a stale `true`
|
|
106
|
+
* behind and render the new row's parcel instead of its index.
|
|
107
|
+
*/
|
|
108
|
+
export declare function mergeOpenCases(existingCases: Case[], existingToggles: boolean[], picked: OpenCase[], muniCode: string): OpenCaseMergeResult;
|