@propriety/court-calendar 1.0.35 → 1.0.39

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 (97) hide show
  1. package/dist/_components/Modal/{View → DateDetails}/CaseViewer.d.ts +1 -3
  2. package/dist/_components/Modal/{CreateEdit → DateEdit}/CreateEditCase.d.ts +2 -1
  3. package/dist/_components/Modal/{ModalActions.d.ts → Layout/ModalActions.d.ts} +1 -1
  4. package/dist/_components/Modal/Layout/ModalPanel.d.ts +4 -0
  5. package/dist/_components/Modal/Modal.d.ts +3 -10
  6. package/dist/_components/Modal/types.d.ts +6 -0
  7. package/dist/_components/Toolbar/CalendarTypeDropdown.d.ts +1 -0
  8. package/dist/_components/Toolbar/Toolbar.d.ts +1 -4
  9. package/dist/constants.d.ts +15 -0
  10. package/dist/context/CalendarContext.d.ts +9 -0
  11. package/dist/context/FilterContext.d.ts +8 -0
  12. package/dist/context/ReferenceDataContext.d.ts +5 -1
  13. package/dist/court-calendar.css +1 -1
  14. package/dist/helpers/api/cases.d.ts +9 -0
  15. package/dist/helpers/api/courtDates.d.ts +6 -0
  16. package/dist/helpers/api/munis.d.ts +6 -0
  17. package/dist/helpers/{people.d.ts → api/people.d.ts} +5 -2
  18. package/dist/helpers/cache.d.ts +2 -0
  19. package/dist/helpers/cases.d.ts +0 -8
  20. package/dist/helpers/courtDates.d.ts +6 -5
  21. package/dist/hooks/UseCalendarEvents.d.ts +41 -0
  22. package/dist/hooks/UseCaseData.d.ts +34 -0
  23. package/dist/hooks/UseCourtDates.d.ts +34 -0
  24. package/dist/hooks/UseModalActions.d.ts +37 -0
  25. package/dist/hooks/UseModalSelection.d.ts +34 -0
  26. package/dist/hooks/UseModalState.d.ts +38 -0
  27. package/dist/hooks/UseScrollbarClickDetection.d.ts +19 -0
  28. package/dist/index.mjs +7216 -7076
  29. package/dist/types.d.ts +5 -15
  30. package/package.json +1 -1
  31. package/src/_components/CCalendar.css +11 -0
  32. package/src/_components/CCalendar.tsx +109 -733
  33. package/src/_components/List/CalendarList.tsx +4 -4
  34. package/src/_components/Modal/CaseDetails/CaseDetails.tsx +2 -1
  35. package/src/_components/Modal/CaseDetails/EvidenceSection.tsx +2 -1
  36. package/src/_components/Modal/{View → DateDetails}/CaseViewer.tsx +3 -5
  37. package/src/_components/Modal/{View → DateDetails}/NoticeFileLink.tsx +2 -3
  38. package/src/_components/Modal/{CreateEdit → DateEdit}/CreateEditCase.tsx +22 -1
  39. package/src/_components/Modal/{CreateEdit → DateEdit}/EditUserFieldDropdown.tsx +5 -7
  40. package/src/_components/Modal/{ModalActions.tsx → Layout/ModalActions.tsx} +1 -1
  41. package/src/_components/Modal/Layout/ModalPanel.tsx +19 -0
  42. package/src/_components/Modal/Modal.tsx +34 -263
  43. package/src/_components/Modal/types.ts +6 -0
  44. package/src/_components/Shared/FirstSecondChairIcons.tsx +4 -5
  45. package/src/_components/Toolbar/CalendarTypeDropdown.tsx +30 -0
  46. package/src/_components/Toolbar/DateTypeFilter.tsx +0 -8
  47. package/src/_components/Toolbar/Toolbar.tsx +4 -5
  48. package/src/_components/Toolbar/UserFilter.tsx +5 -7
  49. package/src/constants.ts +73 -0
  50. package/src/context/CalendarContext.tsx +20 -0
  51. package/src/context/FilterContext.tsx +19 -0
  52. package/src/context/ReferenceDataContext.tsx +8 -4
  53. package/src/helpers/api/cases.ts +122 -0
  54. package/src/helpers/api/courtDates.ts +166 -0
  55. package/src/helpers/{munis.ts → api/munis.ts} +8 -2
  56. package/src/helpers/{people.ts → api/people.ts} +10 -6
  57. package/src/helpers/cache.ts +25 -3
  58. package/src/helpers/cases.ts +3 -132
  59. package/src/helpers/courtDates.ts +10 -146
  60. package/src/hooks/UseCalendarEvents.ts +381 -0
  61. package/src/hooks/UseCaseData.ts +172 -0
  62. package/src/hooks/UseCourtDates.ts +156 -0
  63. package/src/hooks/UseModalActions.ts +154 -0
  64. package/src/hooks/UseModalSelection.ts +61 -0
  65. package/src/hooks/UseModalState.ts +82 -0
  66. package/src/hooks/UseScrollbarClickDetection.ts +42 -0
  67. package/src/types.ts +5 -17
  68. package/dist/helpers/munis.d.ts +0 -2
  69. /package/dist/_components/Modal/{View → DateDetails}/CaseToolbar.d.ts +0 -0
  70. /package/dist/_components/Modal/{View → DateDetails}/ChairBox.d.ts +0 -0
  71. /package/dist/_components/Modal/{View → DateDetails}/DateDetails.d.ts +0 -0
  72. /package/dist/_components/Modal/{View → DateDetails}/InfoBox.d.ts +0 -0
  73. /package/dist/_components/Modal/{View → DateDetails}/InfoBoxBtn.d.ts +0 -0
  74. /package/dist/_components/Modal/{View → DateDetails}/NoticeFileLink.d.ts +0 -0
  75. /package/dist/_components/Modal/{View → DateDetails}/StatusBox.d.ts +0 -0
  76. /package/dist/_components/Modal/{View → DateDetails}/StatusTimeline.d.ts +0 -0
  77. /package/dist/_components/Modal/{CreateEdit → DateEdit}/DateSelector.d.ts +0 -0
  78. /package/dist/_components/Modal/{CreateEdit → DateEdit}/EditUserFieldDropdown.d.ts +0 -0
  79. /package/dist/_components/Modal/{CreateEdit → DateEdit}/EnumDropdown.d.ts +0 -0
  80. /package/dist/_components/Modal/{CreateEdit → DateEdit}/HearingOfficerDropdown.d.ts +0 -0
  81. /package/dist/_components/Modal/{CreateEdit → DateEdit}/NotesField.d.ts +0 -0
  82. /package/dist/_components/Modal/{CreateEdit → DateEdit}/TextFieldList.d.ts +0 -0
  83. /package/dist/_components/Modal/{CreateEdit → DateEdit}/ToggleableTextField.d.ts +0 -0
  84. /package/src/_components/Modal/{View → DateDetails}/CaseToolbar.tsx +0 -0
  85. /package/src/_components/Modal/{View → DateDetails}/ChairBox.tsx +0 -0
  86. /package/src/_components/Modal/{View → DateDetails}/DateDetails.tsx +0 -0
  87. /package/src/_components/Modal/{View → DateDetails}/InfoBox.tsx +0 -0
  88. /package/src/_components/Modal/{View → DateDetails}/InfoBoxBtn.css +0 -0
  89. /package/src/_components/Modal/{View → DateDetails}/InfoBoxBtn.tsx +0 -0
  90. /package/src/_components/Modal/{View → DateDetails}/StatusBox.tsx +0 -0
  91. /package/src/_components/Modal/{View → DateDetails}/StatusTimeline.tsx +0 -0
  92. /package/src/_components/Modal/{CreateEdit → DateEdit}/DateSelector.tsx +0 -0
  93. /package/src/_components/Modal/{CreateEdit → DateEdit}/EnumDropdown.tsx +0 -0
  94. /package/src/_components/Modal/{CreateEdit → DateEdit}/HearingOfficerDropdown.tsx +0 -0
  95. /package/src/_components/Modal/{CreateEdit → DateEdit}/NotesField.tsx +0 -0
  96. /package/src/_components/Modal/{CreateEdit → DateEdit}/TextFieldList.tsx +0 -0
  97. /package/src/_components/Modal/{CreateEdit → DateEdit}/ToggleableTextField.tsx +0 -0
@@ -1,9 +1,7 @@
1
- import { CalendarFilterCtx, Case } from '../../../types';
1
+ import { Case } from '../../../types';
2
2
  declare const CaseViewer: import('react').NamedExoticComponent<{
3
3
  cases: Case[];
4
4
  isFetchingCases: boolean;
5
- filterCtx: CalendarFilterCtx;
6
- setFilterCtx: (ctx: CalendarFilterCtx) => void;
7
5
  setClickedCase: (caseItem: Case | null) => void;
8
6
  selectedDate: Date;
9
7
  isVillage: boolean;
@@ -1,4 +1,5 @@
1
- import { ModalMode, Case, CourtDate } from '../../../types';
1
+ import { Case, CourtDate } from '../../../types';
2
+ import { ModalMode } from '../types';
2
3
  declare const CreateEditCase: import('react').NamedExoticComponent<{
3
4
  edited: CourtDate | undefined;
4
5
  setEdited: (data: CourtDate) => void;
@@ -1,4 +1,4 @@
1
- import { ModalMode } from '../../types';
1
+ import { ModalMode } from '../types';
2
2
  export default function ModalActions({ modalMode, onDelete, onSave, setModalMode, setIsOpen, isAdmin, }: {
3
3
  modalMode: ModalMode;
4
4
  onDelete: () => void;
@@ -0,0 +1,4 @@
1
+ export default function ModalPanel({ isActive, children }: {
2
+ isActive: boolean;
3
+ children: React.ReactNode;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -1,19 +1,12 @@
1
- import { ModalMode, CalendarFilterCtx, Case, CourtDate } from '../../types';
2
- export default function CCModal({ modalIsOpen, modalMode, setModalMode, setIsOpen, selectedCourtDate, selectedDate, updateCourtDateInMemory, filterCtx, setFilterCtx, selectedCases, updateCases, deleteCases, isFetchingCases, apiKey, activeUser, isAdmin, }: {
1
+ import { Case, CourtDate } from '../../types';
2
+ import { ModalMode } from './types';
3
+ export default function CCModal({ modalIsOpen, modalMode, setModalMode, setIsOpen, selectedCourtDate, selectedDate, selectedCases, isFetchingCases, }: {
3
4
  modalIsOpen: boolean;
4
5
  modalMode: ModalMode;
5
6
  setModalMode: (mode: ModalMode) => void;
6
7
  setIsOpen: (isOpen: boolean) => void;
7
8
  selectedCourtDate: CourtDate | null;
8
9
  selectedDate: Date | null;
9
- updateCourtDateInMemory: (updatedDate: CourtDate, del?: boolean) => void;
10
- filterCtx: CalendarFilterCtx;
11
- setFilterCtx: (ctx: CalendarFilterCtx) => void;
12
10
  selectedCases: Case[];
13
- updateCases: (cases: Record<string, Case[]>) => void;
14
- deleteCases: (courtDateId: string) => void;
15
11
  isFetchingCases: boolean;
16
- apiKey: string;
17
- activeUser: number;
18
- isAdmin: boolean;
19
12
  }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ export declare enum ModalMode {
2
+ DETAILS = "Details",
3
+ EDIT = "Edit",
4
+ CREATE = "Create",
5
+ CASE_DETAILS = "Case Details"
6
+ }
@@ -0,0 +1 @@
1
+ export default function CalendarTypeDropdown(): import("react/jsx-runtime").JSX.Element;
@@ -1,9 +1,6 @@
1
1
  import { Calendar } from '@fullcalendar/core/index.js';
2
- import { CalendarFilterCtx } from '../../types';
3
- export default function Toolbar({ calendarApi, filterCtx, setFilterCtx, handleCreateClick, onPrint, currentView, setCurrentView, currentDate, setCurrentDate, activeUser, isFetchingCases, isAdmin, }: {
2
+ export default function Toolbar({ calendarApi, handleCreateClick, onPrint, currentView, setCurrentView, currentDate, setCurrentDate, activeUser, isFetchingCases, isAdmin, }: {
4
3
  calendarApi: Calendar | null;
5
- filterCtx: CalendarFilterCtx;
6
- setFilterCtx: (ctx: CalendarFilterCtx) => void;
7
4
  handleCreateClick: () => void;
8
5
  onPrint: () => void;
9
6
  currentView: string;
@@ -0,0 +1,15 @@
1
+ import { CalendarFilterCtx, Case, CourtDate } from './types';
2
+ export declare const API_BASE_URL = "https://utils.aventine.ai";
3
+ export declare const S3_PHOTOS_URL = "https://aventine-photos.s3.us-east-1.amazonaws.com";
4
+ export declare const S3_NOTICES_URL = "https://aventine-court-notices.s3.us-east-1.amazonaws.com";
5
+ export declare const S3_DOCS_URL = "https://aventine-court-docs.s3.amazonaws.com";
6
+ export declare const SETTLED_ACTIONS: string[];
7
+ export declare const EXCLUDED_USER_NAMES: string[];
8
+ export declare const ADMIN_GROUP = "calendar-admin";
9
+ export declare const PRIMARY_USER_IDS: number[];
10
+ export declare const CASES_CACHE_EXPIRY: number;
11
+ export declare const COURT_DATES_CACHE_EXPIRY: number;
12
+ export declare const NEGOTIATIONS_CACHE_EXPIRY: number;
13
+ export declare const DEFAULT_FILTER_CTX: CalendarFilterCtx;
14
+ export declare const DEFAULT_CASE: Case;
15
+ export declare const DEFAULT_COURT_DATE: CourtDate;
@@ -0,0 +1,9 @@
1
+ import { Case, CourtDate } from '../types';
2
+ interface CalendarContextType {
3
+ updateCourtDateInMemory: (updatedDate: CourtDate, del?: boolean) => void;
4
+ updateCases: (cases: Record<string, Case[]>) => void;
5
+ deleteCases: (courtDateId: string) => void;
6
+ }
7
+ export declare const CalendarProvider: import('react').Provider<CalendarContextType | null>;
8
+ export declare function useCalendar(): CalendarContextType;
9
+ export {};
@@ -0,0 +1,8 @@
1
+ import { CalendarFilterCtx } from '../types';
2
+ interface FilterContextType {
3
+ filterCtx: CalendarFilterCtx;
4
+ setFilterCtx: (ctx: CalendarFilterCtx) => void;
5
+ }
6
+ export declare const FilterProvider: import('react').Provider<FilterContextType | null>;
7
+ export declare function useFilter(): FilterContextType;
8
+ export {};
@@ -1,4 +1,6 @@
1
- import { User, HearingOfficer, Muni } from '../types';
1
+ import { User } from '../types';
2
+ import { HearingOfficer } from '../helpers/api/people';
3
+ import { Muni } from '../helpers/api/munis';
2
4
  interface ReferenceDataContextType {
3
5
  allUsers: Record<number, User>;
4
6
  allHearingOfficers: Record<number, HearingOfficer>;
@@ -7,6 +9,8 @@ interface ReferenceDataContextType {
7
9
  getCountyName: (muniCode: string) => string;
8
10
  isLoading: boolean;
9
11
  isAdmin: boolean;
12
+ apiKey: string;
13
+ activeUser: number;
10
14
  }
11
15
  export declare function ReferenceDataProvider({ apiKey, activeUser, children, }: {
12
16
  apiKey: string;
@@ -1 +1 @@
1
- .pop-in-ccalendar-event{opacity:0;transform:scale(.8);transform-origin:center center;animation:popInBounce .4s cubic-bezier(.34,1.56,.64,1) forwards;will-change:opacity,transform}@keyframes popInBounce{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}:root{--bg: #ffffff;--text: #212121;--fc-today-bg-color: #e3eefa;--fc-border-color: #cccccc;--fc-event-inperson-color: #1da39c;--fc-event-virtual-color: #216edf;--fc-event-unknown-color: #9e9e9e}[data-theme=dark]{--bg: #121212;--text: #ffffff;--fc-today-bg-color: #303e4a;--fc-border-color: #353333}.themed,.themed div:not(.MuiAvatar-root,.iconHolder,.evidence-row,.evidence-row *,.timeline-connector,.fab-bar),.themed .MuiInputBase-root,.themed label,.themed a,.themed .MuiSelect-select,.themed button:not(.MuiFab-root){background-color:var(--bg)!important;color:var(--text)!important;border-color:var(--fc-border-color)!important;scrollbar-color:var(--fc-border-color) var(--bg)}:is(.themed,.themed div:not(.MuiAvatar-root,.iconHolder,.evidence-row,.evidence-row *,.timeline-connector,.fab-bar),.themed .MuiInputBase-root,.themed label,.themed a,.themed .MuiSelect-select,.themed button:not(.MuiFab-root)):focus{outline-color:var(--fc-border-color)!important}.court-calendar a{color:var(--text)!important;text-decoration:none!important}.themed .MuiMenuItem-root,.themed .MuiMenuItem-root div:not(.MuiAvatar-root){background-color:transparent!important}.themed .MuiMenuItem-root:hover,.themed .MuiMenuItem-root:hover div:not(.MuiAvatar-root){background-color:var(--fc-today-bg-color)!important}.themed button.MuiToggleButton-root.Mui-selected{background-color:var(--fc-today-bg-color)!important}.themed button.MuiToggleButton-root:hover{background-color:var(--fc-border-color)!important}.themed .Mui-disabled *:not(input){color:var(--text)!important;cursor:not-allowed!important;opacity:.8!important}.themed::-webkit-scrollbar,.themed div::-webkit-scrollbar{width:8px;background:var(--bg)}.themed::-webkit-scrollbar-thumb,.themed div::-webkit-scrollbar-thumb{background:var(--fc-border-color);border-radius:4px}.themed::-webkit-scrollbar-track,.themed div::-webkit-scrollbar-track{background:var(--bg)}.themed input::placeholder,.themed .MuiFab-root>svg{color:var(--text)!important}.themed *{border-color:var(--fc-border-color)!important}.themed button:hover,.themed .MuiSelect-select:hover,.themed input:hover{background-color:var(--fc-today-bg-color)!important}.themed .MuiDataGrid-row:hover,.themed .MuiDataGrid-row:hover>*{background-color:var(--fc-today-bg-color)!important}.themed .MuiCheckbox-root{color:var(--text)!important}.themed .MuiInputBase-root:hover .MuiAutocomplete-endAdornment,.themed .MuiInputBase-root:hover input{background-color:var(--fc-today-bg-color)!important}:is(.themed .MuiInputBase-root:hover .MuiAutocomplete-endAdornment,.themed .MuiInputBase-root:hover input) button,:is(.themed .MuiInputBase-root:hover .MuiAutocomplete-endAdornment,.themed .MuiInputBase-root:hover input) input{background-color:var(--fc-today-bg-color)!important}.themed .MuiFormControl-root:hover .MuiFormLabel-root{background-color:var(--fc-today-bg-color)!important}.month-day-cell{background-color:var(--bg);color:var(--text);cursor:pointer;height:120px;padding:3px!important;position:relative}.month-day-cell.fc-day-other{filter:brightness(.9)}.month-day-cell.fc-day-today{background-color:var(--fc-today-bg-color)}.month-day-cell:hover:after{content:"";position:absolute;top:0;left:0;width:100%;height:100%;background-color:var(--fc-today-bg-color);opacity:.5;pointer-events:none}.day-header{background-color:var(--bg);color:var(--text);border-bottom:1px solid var(--fc-border-color)}.day-header a{padding:6px 4px!important;display:inline-block}.court-calendar th[role=presentation]{background-color:var(--bg)}.day-cell-allday{background-color:var(--bg)!important;color:var(--text)!important}.fc-daygrid-day-events{max-height:100px;min-height:100px;overflow-y:inherit;margin:0!important;overflow-y:auto;scrollbar-color:var(--fc-border-color) transparent}.fc-day-today .fc-daygrid-day-events{scrollbar-color:var(--fc-event-unknown-color) transparent}.court-calendar .fc-timegrid-slot-label{background-color:var(--bg);color:var(--text)}.court-calendar .fc-timegrid-axis{border-color:var(--fc-border-color);background-color:var(--bg);color:var(--text)}.court-calendar .fc-timegrid-divider{border-color:var(--fc-border-color);background-color:var(--bg)}.fc .fc-button,.fc-button{background-color:var(--bg);color:var(--text);border:1px solid var(--fc-border-color);font-family:Roboto,Helvetica,Arial,"sans-serif";padding:.25rem .5rem;cursor:pointer}:is(.fc .fc-button,.fc-button).fc-button-primary{background-color:var(--bg);color:var(--text);border:1px solid var(--fc-border-color)}:is(.fc .fc-button,.fc-button).fc-button-active.fc-button-primary{background-color:var(--fc-today-bg-color);color:var(--text)}:is(.fc .fc-button,.fc-button):hover{background-color:var(--fc-today-bg-color)}.fc.fc-media-screen{background-color:var(--bg);color:var(--text);font-family:Roboto,Helvetica,Arial,"sans-serif"}#event-tooltip{background-color:var(--text);color:var(--bg);border:1px solid var(--fc-border-color);border-radius:4px;padding:8px;box-shadow:0 4px 8px #00000026;z-index:9999;font-size:16px}.court-event{cursor:pointer;padding:4px 2px}.CCButton{background-color:var(--bg);color:var(--text);border:1px solid var(--fc-border-color);font-family:Roboto,Helvetica,Arial,"sans-serif";padding:8px 16px;margin-right:8px;border-radius:4px;cursor:pointer;-webkit-user-select:none;user-select:none}.CCButton:hover{background-color:var(--fc-today-bg-color)}.CCButton-Icon{min-width:35px;max-width:35px;min-height:35px;max-height:35px;border:none;padding:0;display:flex;align-items:center;justify-content:center}.CCDropdown-Button{width:75px}.CCDropdown-Menu{background-color:var(--bg);color:var(--text);border:1px solid var(--fc-border-color);font-family:Roboto,Helvetica,Arial,"sans-serif";box-shadow:0 2px 8px #00000026}.CCDropdown-Menu div{padding:8px 19px}.CCDropdown-Menu div:hover{background-color:var(--fc-today-bg-color)}.CCButton-Primary{background-color:#1976d2;color:#fff;border:none}.CCButton-Primary:hover{background-color:#1565c0}.CCButton-Error{background-color:#c15a5a;color:#fff;border:none}.CCButton-Error:hover{background-color:#953838}.modal-footer{background-color:var(--bg);color:var(--text);border-top:1px solid var(--fc-border-color)}.MuiInputBase-root.Mui-disabled{opacity:.5!important}.ccdisabled{pointer-events:none;opacity:.6}.switch-track{outline:2px solid var(--fc-border-color)}.fc-list-day-cushion{background-color:var(--bg)!important;color:var(--text)}.fc-list .fc-list-event:hover td{background-color:var(--fc-today-bg-color)!important}.fc-list .deadline-event .fc-list-event-dot{border:none;width:1em;height:1em;vertical-align:middle;background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><circle cx="8" cy="8" r="8" fill="%2300c853"/><path d="M4 8l3 3 5-5" stroke="white" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>') no-repeat center center;background-size:contain}.fc-list .deadline-event.inperson{--color: var(--fc-event-inperson-color)}.fc-list .deadline-event.virtual{--color: var(--fc-event-virtual-color)}.fc-list .deadline-event.unknown{--color: var(--fc-event-unknown-color)}.fc-view:not(.fc-list) .deadline-event{background-color:transparent!important;border-color:transparent!important;display:flex;align-items:center;overflow-x:hidden;position:relative}.fc-view:not(.fc-list) .deadline-event .fc-event-title{color:var(--text)!important}.fc-view:not(.fc-list) .deadline-event.inperson{--color: var(--fc-event-inperson-color)}.fc-view:not(.fc-list) .deadline-event.virtual{--color: var(--fc-event-virtual-color)}.fc-view:not(.fc-list) .deadline-event.unknown{--color: var(--fc-event-unknown-color)}.fc-view:not(.fc-list) .deadline-event.adjourned-no-date{--color: rgb(151, 11, 134) !important}.fc-view:not(.fc-list) .deadline-event.status-uploaded:before{content:"";display:inline-block;width:1em;height:1em;vertical-align:middle;background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><circle cx="8" cy="8" r="8" fill="%2300c853"/><path d="M4 8l3 3 5-5" stroke="white" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>') no-repeat center center;background-size:contain;margin:0 4px 0 0;top:.35em;border:none;position:absolute}.fc-view:not(.fc-list) .deadline-event.status-uploaded .fc-event-main{margin-left:1.5em!important}.fc-view:not(.fc-list) .deadline-event:not(.status-uploaded):before{content:"";display:inline-block;border-radius:calc(var(--fc-daygrid-event-dot-width) / 2);box-sizing:content-box;height:0px;margin:0 4px;width:0px;border:calc(var(--fc-daygrid-event-dot-width) / 2) solid var(--color)}.courtdate-event,.adjournment-event{border:1px solid var(--fc-border-color)!important}:is(.courtdate-event,.adjournment-event) .fc-event-title,:is(.courtdate-event,.adjournment-event) .fc-event-time{color:#fff!important}:is(.courtdate-event,.adjournment-event).inperson{background-color:var(--fc-event-inperson-color)!important;border-color:var(--fc-event-inperson-color)!important}:is(.courtdate-event,.adjournment-event).virtual{background-color:var(--fc-event-virtual-color)!important;border-color:var(--fc-event-virtual-color)!important}:is(.courtdate-event,.adjournment-event).unknown{background-color:var(--fc-event-unknown-color)!important;border-color:var(--fc-event-unknown-color)!important}:is(.courtdate-event,.adjournment-event) .fc-daygrid-event-dot,:is(.courtdate-event,.adjournment-event) .fc-list-event-dot{display:none}:is(.courtdate-event,.adjournment-event).adjourned-no-date{border-color:#970b86!important;background-color:#970b86!important}.ccalendar-list-row{cursor:pointer}.CCAvatarIcon:hover{cursor:pointer;transform:scale(1.1);box-shadow:0 4px 8px #0003}@page{size:landscape;margin:.5in}@media print{#ccalendar-container>.MuiStack-root:first-child,#event-tooltip,.ReactModal__Overlay,.MuiDataGrid-footerContainer{display:none!important}#ccalendar-container{width:100%!important;overflow:visible!important}.fc.fc-media-screen,.fc .fc-scrollgrid,.fc .fc-scrollgrid-section>td,.fc .fc-daygrid-body,.fc table{width:100%!important;max-width:100%!important}.fc .fc-scrollgrid{overflow:visible!important}.fc colgroup col{width:auto!important}.fc-daygrid-day-events{max-height:none!important;min-height:auto!important;overflow:visible!important}.month-day-cell{height:auto!important}#ccalendar-container .MuiDataGrid-root{height:auto!important;max-height:none!important}#ccalendar-container .MuiDataGrid-virtualScroller{overflow:visible!important;height:auto!important}*{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}}.modal-appear-animate{animation:modalFadeIn .35s cubic-bezier(.4,0,.2,1)}@keyframes modalFadeIn{0%{opacity:0;transform:scale(.96) translateY(24px)}to{opacity:1;transform:scale(1) translateY(0)}}
1
+ .pop-in-ccalendar-event{opacity:0;transform:scale(.8);transform-origin:center center;animation:popInBounce .4s cubic-bezier(.34,1.56,.64,1) forwards;will-change:opacity,transform}@keyframes popInBounce{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}:root{--bg: #ffffff;--text: #212121;--fc-today-bg-color: #e3eefa;--fc-border-color: #cccccc;--fc-event-inperson-color: #1da39c;--fc-event-virtual-color: #216edf;--fc-event-unknown-color: #9e9e9e;--fc-event-negotiations-color: #33d391}[data-theme=dark]{--bg: #121212;--text: #ffffff;--fc-today-bg-color: #303e4a;--fc-border-color: #353333}.themed,.themed div:not(.MuiAvatar-root,.iconHolder,.evidence-row,.evidence-row *,.timeline-connector,.fab-bar),.themed .MuiInputBase-root,.themed label,.themed a,.themed .MuiSelect-select,.themed button:not(.MuiFab-root){background-color:var(--bg)!important;color:var(--text)!important;border-color:var(--fc-border-color)!important;scrollbar-color:var(--fc-border-color) var(--bg)}:is(.themed,.themed div:not(.MuiAvatar-root,.iconHolder,.evidence-row,.evidence-row *,.timeline-connector,.fab-bar),.themed .MuiInputBase-root,.themed label,.themed a,.themed .MuiSelect-select,.themed button:not(.MuiFab-root)):focus{outline-color:var(--fc-border-color)!important}.court-calendar a{color:var(--text)!important;text-decoration:none!important}.themed .MuiMenuItem-root,.themed .MuiMenuItem-root div:not(.MuiAvatar-root){background-color:transparent!important}.themed .MuiMenuItem-root:hover,.themed .MuiMenuItem-root:hover div:not(.MuiAvatar-root){background-color:var(--fc-today-bg-color)!important}.themed button.MuiToggleButton-root.Mui-selected{background-color:var(--fc-today-bg-color)!important}.themed button.MuiToggleButton-root:hover{background-color:var(--fc-border-color)!important}.themed .Mui-disabled *:not(input){color:var(--text)!important;cursor:not-allowed!important;opacity:.8!important}.themed::-webkit-scrollbar,.themed div::-webkit-scrollbar{width:8px;background:var(--bg)}.themed::-webkit-scrollbar-thumb,.themed div::-webkit-scrollbar-thumb{background:var(--fc-border-color);border-radius:4px}.themed::-webkit-scrollbar-track,.themed div::-webkit-scrollbar-track{background:var(--bg)}.themed input::placeholder,.themed .MuiFab-root>svg{color:var(--text)!important}.themed *{border-color:var(--fc-border-color)!important}.themed button:hover,.themed .MuiSelect-select:hover,.themed input:hover{background-color:var(--fc-today-bg-color)!important}.themed .MuiDataGrid-row:hover,.themed .MuiDataGrid-row:hover>*{background-color:var(--fc-today-bg-color)!important}.themed .MuiCheckbox-root{color:var(--text)!important}.themed .MuiInputBase-root:hover .MuiAutocomplete-endAdornment,.themed .MuiInputBase-root:hover input{background-color:var(--fc-today-bg-color)!important}:is(.themed .MuiInputBase-root:hover .MuiAutocomplete-endAdornment,.themed .MuiInputBase-root:hover input) button,:is(.themed .MuiInputBase-root:hover .MuiAutocomplete-endAdornment,.themed .MuiInputBase-root:hover input) input{background-color:var(--fc-today-bg-color)!important}.themed .MuiFormControl-root:hover .MuiFormLabel-root{background-color:var(--fc-today-bg-color)!important}.month-day-cell{background-color:var(--bg);color:var(--text);cursor:pointer;height:120px;padding:3px!important;position:relative}.month-day-cell.fc-day-other{filter:brightness(.9)}.month-day-cell.fc-day-today{background-color:var(--fc-today-bg-color)}.month-day-cell:hover:after{content:"";position:absolute;top:0;left:0;width:100%;height:100%;background-color:var(--fc-today-bg-color);opacity:.5;pointer-events:none}.day-header{background-color:var(--bg);color:var(--text);border-bottom:1px solid var(--fc-border-color)}.day-header a{padding:6px 4px!important;display:inline-block}.court-calendar th[role=presentation]{background-color:var(--bg)}.day-cell-allday{background-color:var(--bg)!important;color:var(--text)!important}.fc-daygrid-day-events{max-height:100px;min-height:100px;overflow-y:inherit;margin:0!important;overflow-y:auto;scrollbar-color:var(--fc-border-color) transparent}.fc-day-today .fc-daygrid-day-events{scrollbar-color:var(--fc-event-unknown-color) transparent}.court-calendar .fc-timegrid-slot-label{background-color:var(--bg);color:var(--text)}.court-calendar .fc-timegrid-axis{border-color:var(--fc-border-color);background-color:var(--bg);color:var(--text)}.court-calendar .fc-timegrid-divider{border-color:var(--fc-border-color);background-color:var(--bg)}.fc .fc-button,.fc-button{background-color:var(--bg);color:var(--text);border:1px solid var(--fc-border-color);font-family:Roboto,Helvetica,Arial,"sans-serif";padding:.25rem .5rem;cursor:pointer}:is(.fc .fc-button,.fc-button).fc-button-primary{background-color:var(--bg);color:var(--text);border:1px solid var(--fc-border-color)}:is(.fc .fc-button,.fc-button).fc-button-active.fc-button-primary{background-color:var(--fc-today-bg-color);color:var(--text)}:is(.fc .fc-button,.fc-button):hover{background-color:var(--fc-today-bg-color)}.fc.fc-media-screen{background-color:var(--bg);color:var(--text);font-family:Roboto,Helvetica,Arial,"sans-serif"}#event-tooltip{background-color:var(--text);color:var(--bg);border:1px solid var(--fc-border-color);border-radius:4px;padding:8px;box-shadow:0 4px 8px #00000026;z-index:9999;font-size:16px}.court-event{cursor:pointer;padding:4px 2px}.CCButton{background-color:var(--bg);color:var(--text);border:1px solid var(--fc-border-color);font-family:Roboto,Helvetica,Arial,"sans-serif";padding:8px 16px;margin-right:8px;border-radius:4px;cursor:pointer;-webkit-user-select:none;user-select:none}.CCButton:hover{background-color:var(--fc-today-bg-color)}.CCButton-Icon{min-width:35px;max-width:35px;min-height:35px;max-height:35px;border:none;padding:0;display:flex;align-items:center;justify-content:center}.CCDropdown-Button{width:75px}.CCDropdown-Menu{background-color:var(--bg);color:var(--text);border:1px solid var(--fc-border-color);font-family:Roboto,Helvetica,Arial,"sans-serif";box-shadow:0 2px 8px #00000026}.CCDropdown-Menu div{padding:8px 19px}.CCDropdown-Menu div:hover{background-color:var(--fc-today-bg-color)}.CCButton-Primary{background-color:#1976d2;color:#fff;border:none}.CCButton-Primary:hover{background-color:#1565c0}.CCButton-Error{background-color:#c15a5a;color:#fff;border:none}.CCButton-Error:hover{background-color:#953838}.modal-footer{background-color:var(--bg);color:var(--text);border-top:1px solid var(--fc-border-color)}.MuiInputBase-root.Mui-disabled{opacity:.5!important}.ccdisabled{pointer-events:none;opacity:.6}.switch-track{outline:2px solid var(--fc-border-color)}.fc-list-day-cushion{background-color:var(--bg)!important;color:var(--text)}.fc-list .fc-list-event:hover td{background-color:var(--fc-today-bg-color)!important}.fc-list .deadline-event .fc-list-event-dot{border:none;width:1em;height:1em;vertical-align:middle;background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><circle cx="8" cy="8" r="8" fill="%2300c853"/><path d="M4 8l3 3 5-5" stroke="white" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>') no-repeat center center;background-size:contain}.fc-list .deadline-event.inperson{--color: var(--fc-event-inperson-color)}.fc-list .deadline-event.virtual{--color: var(--fc-event-virtual-color)}.fc-list .deadline-event.unknown{--color: var(--fc-event-unknown-color)}.fc-list .deadline-event.negotiations{--color: var(--fc-event-negotiations-color)}.fc-view:not(.fc-list) .deadline-event{background-color:transparent!important;border-color:transparent!important;display:flex;align-items:center;overflow-x:hidden;position:relative}.fc-view:not(.fc-list) .deadline-event .fc-event-title{color:var(--text)!important}.fc-view:not(.fc-list) .deadline-event.inperson{--color: var(--fc-event-inperson-color)}.fc-view:not(.fc-list) .deadline-event.virtual{--color: var(--fc-event-virtual-color)}.fc-view:not(.fc-list) .deadline-event.unknown{--color: var(--fc-event-unknown-color)}.fc-view:not(.fc-list) .deadline-event.negotiations{--color: var(--fc-event-negotiations-color)}.fc-view:not(.fc-list) .deadline-event.adjourned-no-date{--color: rgb(151, 11, 134) !important}.fc-view:not(.fc-list) .deadline-event.status-uploaded:before{content:"";display:inline-block;width:1em;height:1em;vertical-align:middle;background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><circle cx="8" cy="8" r="8" fill="%2300c853"/><path d="M4 8l3 3 5-5" stroke="white" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>') no-repeat center center;background-size:contain;margin:0 4px 0 0;top:.35em;border:none;position:absolute}.fc-view:not(.fc-list) .deadline-event.status-uploaded .fc-event-main{margin-left:1.5em!important}.fc-view:not(.fc-list) .deadline-event:not(.status-uploaded):before{content:"";display:inline-block;border-radius:calc(var(--fc-daygrid-event-dot-width) / 2);box-sizing:content-box;height:0px;margin:0 4px;width:0px;border:calc(var(--fc-daygrid-event-dot-width) / 2) solid var(--color)}.courtdate-event,.adjournment-event{border:1px solid var(--fc-border-color)!important}:is(.courtdate-event,.adjournment-event) .fc-event-title,:is(.courtdate-event,.adjournment-event) .fc-event-time{color:#fff!important}:is(.courtdate-event,.adjournment-event).inperson{background-color:var(--fc-event-inperson-color)!important;border-color:var(--fc-event-inperson-color)!important}:is(.courtdate-event,.adjournment-event).virtual{background-color:var(--fc-event-virtual-color)!important;border-color:var(--fc-event-virtual-color)!important}:is(.courtdate-event,.adjournment-event).unknown{background-color:var(--fc-event-unknown-color)!important;border-color:var(--fc-event-unknown-color)!important}:is(.courtdate-event,.adjournment-event).negotiations{background-color:var(--fc-event-negotiations-color)!important;border-color:var(--fc-event-negotiations-color)!important}:is(.courtdate-event,.adjournment-event) .fc-daygrid-event-dot,:is(.courtdate-event,.adjournment-event) .fc-list-event-dot{display:none}:is(.courtdate-event,.adjournment-event).adjourned-no-date{border-color:#970b86!important;background-color:#970b86!important}.ccalendar-list-row{cursor:pointer}.CCAvatarIcon:hover{cursor:pointer;transform:scale(1.1);box-shadow:0 4px 8px #0003}@page{size:landscape;margin:.5in}@media print{#ccalendar-container>.MuiStack-root:first-child,#event-tooltip,.ReactModal__Overlay,.MuiDataGrid-footerContainer{display:none!important}#ccalendar-container{width:100%!important;overflow:visible!important}.fc.fc-media-screen,.fc .fc-scrollgrid,.fc .fc-scrollgrid-section>td,.fc .fc-daygrid-body,.fc table{width:100%!important;max-width:100%!important}.fc .fc-scrollgrid{overflow:visible!important}.fc colgroup col{width:auto!important}.fc-daygrid-day-events{max-height:none!important;min-height:auto!important;overflow:visible!important}.month-day-cell{height:auto!important}#ccalendar-container .MuiDataGrid-root{height:auto!important;max-height:none!important}#ccalendar-container .MuiDataGrid-virtualScroller{overflow:visible!important;height:auto!important}*{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}}.modal-appear-animate{animation:modalFadeIn .35s cubic-bezier(.4,0,.2,1)}@keyframes modalFadeIn{0%{opacity:0;transform:scale(.96) translateY(24px)}to{opacity:1;transform:scale(1) translateY(0)}}
@@ -0,0 +1,9 @@
1
+ import { DateType, Case } from '../../types';
2
+ export declare function searchByCaseTerm(term: string, apiKey: string): AsyncGenerator<any, void, unknown>;
3
+ export declare function fetchCasesByCourtDate(id: string, apiKey: string, type?: DateType): Promise<Case[]>;
4
+ export declare function fetchAllCasesPaginated(apiKey: string, pageSize?: number): AsyncGenerator<Record<string, Case[]>, void, unknown>;
5
+ export declare function adjournCases(cases: {
6
+ indexNumber: string;
7
+ year: number;
8
+ }[], adjournedDate: Date | null, apiKey: string): Promise<boolean>;
9
+ export declare function updateCaseAdjournment(parcelId: string, scarIndexNumber: string, adjournedDate: Date | null, apiKey: string): Promise<boolean>;
@@ -0,0 +1,6 @@
1
+ import { DateType, CourtDate } from '../../types';
2
+ export declare function getAllDates(apiKey: string, type?: DateType): Promise<Array<CourtDate>>;
3
+ export declare function updateCourtDate(courtDateId: number, updatedData: Partial<CourtDate>, apiKey: string, courtCases?: string[], user?: number, type?: DateType): Promise<boolean>;
4
+ export declare function deleteCourtDate(courtDateId: number, apiKey: string, type?: DateType): Promise<boolean>;
5
+ export declare function createCourtDate(courtDate: Date, muniCode: string, apiKey: string, courtCases?: string[], hearingTime?: string, multipleDates?: Date[], type?: DateType): Promise<number | null>;
6
+ export declare function snoozeUploadDeadline(courtDateId: number, apiKey: string): Promise<boolean>;
@@ -0,0 +1,6 @@
1
+ export interface Muni {
2
+ County: string;
3
+ Township: string;
4
+ Village: string;
5
+ }
6
+ export declare function getAllMuniNames(apiKey: string): Promise<Record<string, Muni>>;
@@ -1,5 +1,8 @@
1
- import { User, HearingOfficer } from '../types';
2
- export declare const primaryUserIds: number[];
1
+ import { User } from '../../types';
2
+ export interface HearingOfficer {
3
+ OfficerID: number;
4
+ OfficerName: string;
5
+ }
3
6
  export declare function getAllUsers(apiKey: string): Promise<Record<number, User>>;
4
7
  export declare function getAllHearingOfficers(apiKey: string): Promise<Record<number, HearingOfficer>>;
5
8
  export declare function isUserAdmin(User: User, apiKey: string): Promise<boolean>;
@@ -16,3 +16,5 @@ export declare function updateCasesCache(courtDateId: string, data: Case[]): Pro
16
16
  export declare function removeCasesCache(courtDateId: string): Promise<void>;
17
17
  export declare function getCourtDatesCache(): Promise<CourtDate[] | null>;
18
18
  export declare function setCourtDatesCache(data: CourtDate[]): Promise<void>;
19
+ export declare function getNegotiationsCache(): Promise<CourtDate[] | null>;
20
+ export declare function setNegotiationsCache(data: CourtDate[]): Promise<void>;
@@ -1,13 +1,5 @@
1
1
  import { CalendarFilterCtx, Case } from '../types';
2
- export declare function searchByCaseTerm(term: string, apiKey: string): AsyncGenerator<any, void, unknown>;
3
- export declare function fetchCasesByCourtDate(id: string, apiKey: string): Promise<Case[]>;
4
- export declare function fetchAllCasesPaginated(apiKey: string, pageSize?: number): AsyncGenerator<Record<string, Case[]>, void, unknown>;
5
2
  export declare function isCaseSettled(c: Case, isVillage: boolean): boolean;
6
3
  export declare function isCaseUploadedOrSettled(c: Case, isVillage: boolean): boolean;
7
4
  export declare function isCaseMissingEvidence(c: Case): boolean;
8
- export declare function adjournCases(cases: {
9
- indexNumber: string;
10
- year: number;
11
- }[], adjournedDate: Date | null, apiKey: string): Promise<boolean>;
12
- export declare function updateCaseAdjournment(parcelId: string, scarIndexNumber: string, adjournedDate: Date | null, apiKey: string): Promise<boolean>;
13
5
  export declare function filterCases(cases: Case[], filterCtx: CalendarFilterCtx, isVillage: boolean, selectedDate?: Date): Case[];
@@ -1,7 +1,8 @@
1
1
  import { CourtDate } from '../types';
2
- export declare function getAllDates(apiKey: string): Promise<Array<CourtDate>>;
3
- export declare function updateCourtDate(courtDateId: number, updatedData: Partial<CourtDate>, apiKey: string, courtCases?: string[], user?: number): Promise<boolean>;
4
- export declare function deleteCourtDate(courtDateId: number, apiKey: string): Promise<boolean>;
5
- export declare function createCourtDate(courtDate: Date, muniCode: string, apiKey: string, courtCases?: string[], hearingTime?: string, multipleDates?: Date[]): Promise<number | null>;
6
- export declare function snoozeUploadDeadline(courtDateId: number, apiKey: string): Promise<boolean>;
7
2
  export declare function isVillageDate(muniCode: string): boolean;
3
+ /**
4
+ * Returns a unique string key for a court date suitable for use in the allCases map.
5
+ * Negotiation IDs and SCAR IDs come from separate auto-increment sequences and can
6
+ * overlap numerically, so negotiations are prefixed with "neg_".
7
+ */
8
+ export declare function caseKey(date: CourtDate): string;
@@ -0,0 +1,41 @@
1
+ import { Case, CourtDate, CalendarFilterCtx } from '../types';
2
+ import { EventSourceInput, EventMountArg, Calendar } from '@fullcalendar/core/index.js';
3
+ /**
4
+ * Derives FullCalendar event objects from court dates, cases, and filter state.
5
+ *
6
+ * Responsibilities:
7
+ * - Runs async case-term searches and accumulates matching court date IDs.
8
+ * - Filters `courtDates` according to every dimension in `filterCtx`
9
+ * (hearing type, assignment, muni, unsettled/no-evidence/unreviewed, search term).
10
+ * - Builds three event arrays from the filtered dates:
11
+ * - **courtDateEvents** – one event per court date (plus adjournment bucket events).
12
+ * - **mdates** – secondary "day N" events for dates with `MultipleDates`.
13
+ * - **deadlines** – all-day upload-deadline events.
14
+ * - Suppresses event updates while the modal is open to avoid UI churn.
15
+ * - Applies a staggered `pop-in` CSS animation to newly-appearing events via
16
+ * `handleEventMount`, and attaches HTML tooltip content to each event element.
17
+ *
18
+ * @param courtDates Full list of court dates to derive events from.
19
+ * @param allCases Map of `CourtDateID → Case[]` for case-count display.
20
+ * @param apiKey API key forwarded to the search helper.
21
+ * @param modalIsOpen When `true`, event state updates are paused.
22
+ * @param filterCtx Active filter/search context from the calendar UI.
23
+ *
24
+ * @returns
25
+ * - `events` – current FullCalendar `EventSourceInput` array.
26
+ * - `filteredDates` – court dates that survive all active filters.
27
+ * - `eventHash` – JSON hash of `events`; changes whenever the event list changes.
28
+ * - `handleEventMount` – callback to pass to FullCalendar's `eventDidMount` prop.
29
+ */
30
+ export declare function useCalendarEvents({ courtDates, allCases, apiKey, modalIsOpen, filterCtx, }: {
31
+ courtDates: CourtDate[];
32
+ allCases: Record<string, Case[]>;
33
+ apiKey: string;
34
+ modalIsOpen: boolean;
35
+ filterCtx: CalendarFilterCtx;
36
+ }): {
37
+ events: EventSourceInput;
38
+ filteredDates: CourtDate[];
39
+ eventHash: string;
40
+ handleEventMount: (info: EventMountArg, calendarApi: Calendar | null) => void;
41
+ };
@@ -0,0 +1,34 @@
1
+ import { Case, CourtDate } from '../types';
2
+ /**
3
+ * Manages fetching, caching, and in-memory storage of cases for court dates.
4
+ *
5
+ * Uses a three-tier lookup strategy for each court date ID:
6
+ * 1. **Memory** – React state already holds the cases; no I/O needed.
7
+ * 2. **Cache** – IndexedDB/session cache is checked for any IDs missing from memory.
8
+ * 3. **API** – Remaining IDs are fetched; bulk pagination is used when >10 IDs are missing.
9
+ *
10
+ * State is updated incrementally as each tier resolves so the UI stays responsive.
11
+ *
12
+ * @param apiKey API key forwarded to case fetch helpers.
13
+ * @param courtDates Full list of court dates; cases are loaded for every ID in this list.
14
+ * @param selectedCourtDate The currently-selected court date; its cases are always force-refreshed
15
+ * from the API (bypassing memory and cache) when the selection changes.
16
+ *
17
+ * @returns
18
+ * - `allCases` – Map of `CourtDateID → Case[]` for all loaded court dates.
19
+ * - `selectedCases` – Cases belonging to `selectedCourtDate`.
20
+ * - `isFetchingCases` – `true` while any API fetch is in flight.
21
+ * - `addPartialCasesToMemoryAndCache` – Merges a partial cases map into state and optionally the cache.
22
+ * - `deleteCaseMemoryAndCache` – Removes all cases for a given court date from memory and cache.
23
+ */
24
+ export declare function useCaseData({ apiKey, courtDates, selectedCourtDate, }: {
25
+ apiKey: string;
26
+ courtDates: CourtDate[];
27
+ selectedCourtDate: CourtDate | null;
28
+ }): {
29
+ allCases: Record<string, Case[]>;
30
+ selectedCases: Case[];
31
+ isFetchingCases: boolean;
32
+ addPartialCasesToMemoryAndCache: (cases: Record<string, Case[]>, skipCache: boolean) => Promise<void>;
33
+ deleteCaseMemoryAndCache: (courtDateID: string) => Promise<void>;
34
+ };
@@ -0,0 +1,34 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ import { CourtDate } from '../types';
3
+ /**
4
+ * Loads, caches, and mutates the full list of court dates.
5
+ *
6
+ * On mount, checks the local cache first; falls back to the API if the cache is
7
+ * empty or absent. `MultipleDates` strings are normalized to `Date` objects when
8
+ * restoring from cache.
9
+ *
10
+ * Optimistic updates are applied immediately to both React state and the cache;
11
+ * chair-assignment changes are rolled back if the API call fails.
12
+ *
13
+ * @param apiKey API key forwarded to court-date helpers.
14
+ * @param activeUser Current user ID, forwarded to `updateCourtDate`.
15
+ * @param setSelectedCourtDate Setter for the selected court date; kept in sync
16
+ * when the selected date is updated or deleted.
17
+ *
18
+ * @returns
19
+ * - `courtDates` – Current list of all SCAR court dates.
20
+ * - `negotiations` – Current list of all negotiation court dates.
21
+ * - `updateCourtDateInMemory` – Upserts or deletes a court date in state and cache.
22
+ * - `handleUpdateChair` – Optimistically updates a first/second chair assignment
23
+ * and persists it to the API, reverting on failure.
24
+ */
25
+ export declare function useCourtDates({ apiKey, activeUser, setSelectedCourtDate, }: {
26
+ apiKey: string;
27
+ activeUser: number;
28
+ setSelectedCourtDate: Dispatch<SetStateAction<CourtDate | null>>;
29
+ }): {
30
+ courtDates: CourtDate[];
31
+ negotiations: CourtDate[];
32
+ updateCourtDateInMemory: (updatedDate: CourtDate, del?: boolean) => void;
33
+ handleUpdateChair: (courtDateId: number, position: "first" | "second", userId: number | null) => void;
34
+ };
@@ -0,0 +1,37 @@
1
+ import { Case, CourtDate } from '../types';
2
+ import { ModalMode } from '../_components/Modal/types';
3
+ /**
4
+ * Provides save, delete, chair-update, and adjournment actions for the court-date modal.
5
+ *
6
+ * All mutations follow an optimistic pattern: state is updated immediately and
7
+ * reverted if the API call fails. Reads `apiKey` and `activeUser` from
8
+ * `ReferenceDataContext`, and calendar mutation helpers from `CalendarContext`.
9
+ *
10
+ * @param modalMode Current modal mode (`DETAILS`, `EDIT`, or `CREATE`).
11
+ * @param selectedCourtDate The court date currently displayed in the modal.
12
+ * @param selectedCases Cases associated with `selectedCourtDate`.
13
+ * @param editedData Draft court-date state while in EDIT/CREATE mode.
14
+ * @param editedCases Draft case list while in EDIT/CREATE mode.
15
+ * @param setEditedData Setter for `editedData`.
16
+ * @param setIsOpen Controls modal open/close state.
17
+ *
18
+ * @returns
19
+ * - `handleSave` – Validates and persists the edited court date (creates or updates).
20
+ * - `handleDelete` – Confirms, then deletes the selected court date.
21
+ * - `handleViewUpdateChair` – Optimistically updates a first/second chair in view mode.
22
+ * - `handleSelectedCasesAdjournmentChange` – Updates the adjournment date for a set of cases.
23
+ */
24
+ export declare function useModalActions({ modalMode, selectedCourtDate, selectedCases, editedData, editedCases, setEditedData, setIsOpen, }: {
25
+ modalMode: ModalMode;
26
+ selectedCourtDate: CourtDate | null;
27
+ selectedCases: Case[];
28
+ editedData: CourtDate | undefined;
29
+ editedCases: Case[];
30
+ setEditedData: (data: CourtDate) => void;
31
+ setIsOpen: (isOpen: boolean) => void;
32
+ }): {
33
+ handleSave: () => Promise<void>;
34
+ handleDelete: () => Promise<void>;
35
+ handleViewUpdateChair: (position: "first" | "second", userId: number | null) => void;
36
+ handleSelectedCasesAdjournmentChange: (casesToUpdate: Case[], date: Date | null) => Promise<void>;
37
+ };
@@ -0,0 +1,34 @@
1
+ import { CourtDate } from '../types';
2
+ import { ModalMode } from '../_components/Modal/types';
3
+ import { EventClickArg } from '@fullcalendar/core/index.js';
4
+ /**
5
+ * Manages which court date is selected and how the modal is opened.
6
+ *
7
+ * Tracks open/close state, the selected `CourtDate`, the active `ModalMode`,
8
+ * and the calendar date associated with the selection.
9
+ *
10
+ * @returns
11
+ * - `modalIsOpen` – Whether the modal is currently open.
12
+ * - `setIsOpen` – Directly set the open/close state.
13
+ * - `selectedCourtDate` – The court date currently displayed in the modal.
14
+ * - `setSelectedCourtDate` – Override the selected court date directly.
15
+ * - `modalMode` – Current mode (`DETAILS` or `CREATE`).
16
+ * - `setModalMode` – Override the modal mode directly.
17
+ * - `selectedDate` – Calendar date extracted from the last clicked event.
18
+ * - `openCreateModal` – Opens the modal in CREATE mode pre-filled with a date.
19
+ * - `openDetailsModal` – Opens the modal in DETAILS mode for a given court date.
20
+ * - `handleEventClick` – FullCalendar `eventClick` handler; extracts the court date
21
+ * from event props and opens the details modal.
22
+ */
23
+ export declare function useModalSelection(): {
24
+ modalIsOpen: boolean;
25
+ setIsOpen: import('react').Dispatch<import('react').SetStateAction<boolean>>;
26
+ selectedCourtDate: CourtDate | null;
27
+ setSelectedCourtDate: import('react').Dispatch<import('react').SetStateAction<CourtDate | null>>;
28
+ modalMode: ModalMode;
29
+ setModalMode: import('react').Dispatch<import('react').SetStateAction<ModalMode>>;
30
+ selectedDate: Date | null;
31
+ openCreateModal: (date: Date) => void;
32
+ openDetailsModal: (date: CourtDate) => void;
33
+ handleEventClick: (clickInfo: EventClickArg) => void;
34
+ };
@@ -0,0 +1,38 @@
1
+ import { Case, CourtDate } from '../types';
2
+ import { ModalMode } from '../_components/Modal/types';
3
+ /**
4
+ * Manages the internal editing state of the court-date modal.
5
+ *
6
+ * Derives draft state from `selectedCourtDate`/`selectedCases` when the mode
7
+ * changes to EDIT or CREATE, resets to DETAILS mode and clears the clicked case
8
+ * when the modal closes, and automatically switches to CASE_DETAILS mode when
9
+ * a case is clicked.
10
+ *
11
+ * @param modalIsOpen Whether the modal is currently open.
12
+ * @param modalMode Current modal mode (`DETAILS`, `EDIT`, `CREATE`, or `CASE_DETAILS`).
13
+ * @param setModalMode Setter for `modalMode`.
14
+ * @param selectedCourtDate The court date currently displayed in the modal.
15
+ * @param selectedCases Cases associated with `selectedCourtDate`.
16
+ *
17
+ * @returns
18
+ * - `editedData` – Draft court date for EDIT/CREATE forms.
19
+ * - `setEditedData` – Update the draft court date.
20
+ * - `editedCases` – Draft case list for EDIT/CREATE forms.
21
+ * - `setEditedCases` – Update the draft case list.
22
+ * - `clickedCase` – The case the user clicked to view case-level details.
23
+ * - `setClickedCase` – Set (or clear) the clicked case.
24
+ */
25
+ export declare function useModalState({ modalIsOpen, modalMode, setModalMode, selectedCourtDate, selectedCases, }: {
26
+ modalIsOpen: boolean;
27
+ modalMode: ModalMode;
28
+ setModalMode: (mode: ModalMode) => void;
29
+ selectedCourtDate: CourtDate | null;
30
+ selectedCases: Case[];
31
+ }): {
32
+ editedData: CourtDate | undefined;
33
+ setEditedData: import('react').Dispatch<import('react').SetStateAction<CourtDate | undefined>>;
34
+ editedCases: Case[];
35
+ setEditedCases: import('react').Dispatch<import('react').SetStateAction<Case[]>>;
36
+ clickedCase: Case | null;
37
+ setClickedCase: import('react').Dispatch<import('react').SetStateAction<Case | null>>;
38
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Detects whether the user clicked on the scrollbar of a FullCalendar day-events cell.
3
+ *
4
+ * Listens for `mousedown` events in the capture phase. When the primary mouse button
5
+ * is pressed on an `.fc-daygrid-day-events` element and the click X position falls
6
+ * within the last 10px of the client width (i.e. in the scrollbar gutter), sets
7
+ * `scrollbarClicked` to `true`; otherwise resets it to `false`.
8
+ *
9
+ * This is used to suppress calendar day-click / event-click handlers that would
10
+ * otherwise fire incorrectly when the user is scrolling the event list.
11
+ *
12
+ * @returns
13
+ * - `scrollbarClicked` – `true` if the most recent mousedown targeted the scrollbar.
14
+ * - `clearScrollbarClick` – Resets `scrollbarClicked` to `false`.
15
+ */
16
+ export declare function useScrollbarClickDetection(): {
17
+ scrollbarClicked: boolean;
18
+ clearScrollbarClick: () => void;
19
+ };