@propriety/court-calendar 0.0.13 → 0.0.15
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/.claude/settings.local.json +9 -8
- package/.github/workflows/publish.yml +28 -0
- package/README.md +237 -0
- package/dist/_components/Modal/Modal.d.ts +2 -1
- package/dist/helpers/courtDates.d.ts +2 -2
- package/dist/helpers/formatter.d.ts +1 -0
- package/dist/index.mjs +1641 -1612
- package/package.json +1 -1
- package/src/_components/CCalendar.tsx +4 -3
- package/src/_components/Modal/CreateEdit/DateSelector.tsx +42 -42
- package/src/_components/Modal/Modal.css +15 -15
- package/src/_components/Modal/Modal.tsx +4 -0
- package/src/_components/Modal/View/InfoBoxBtn.css +39 -39
- package/src/_components/Modal/View/InfoBoxBtn.tsx +29 -29
- package/src/_components/Shared/FormRow.tsx +37 -37
- package/src/_components/Shared/SearchBar.tsx +87 -87
- package/src/helpers/cases.ts +10 -2
- package/src/helpers/courtDates.ts +13 -7
- package/src/helpers/formatter.ts +28 -0
- package/src/index.ts +2 -2
- package/tsconfig.app.json +32 -32
- package/tsconfig.json +4 -4
- package/tsconfig.node.json +30 -30
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(dir:*)",
|
|
5
|
-
"Bash(ls:*)"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(dir:*)",
|
|
5
|
+
"Bash(ls:*)",
|
|
6
|
+
"Bash(git log:*)"
|
|
7
|
+
]
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Build & Publish to npm
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [closed]
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
if: github.event.pull_request.merged == true
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: 24
|
|
23
|
+
registry-url: https://registry.npmjs.org
|
|
24
|
+
|
|
25
|
+
- run: npm ci
|
|
26
|
+
- run: npm run build
|
|
27
|
+
- run: npm version "0.0.${{ github.run_number }}" --no-git-tag-version
|
|
28
|
+
- run: npm publish --access public
|
package/README.md
CHANGED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# @propriety/court-calendar
|
|
2
|
+
|
|
3
|
+
A React component library for managing court dates, cases, and evidence. Built with FullCalendar, MUI, and Dexie (IndexedDB caching).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @propriety/court-calendar
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
You must also have the following peer dependencies installed:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install react react-dom @mui/material @mui/icons-material @mui/x-data-grid @mui/x-date-pickers @emotion/react @emotion/styled
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { CCalendar } from '@propriety/court-calendar';
|
|
21
|
+
import '@propriety/court-calendar/styles.css';
|
|
22
|
+
|
|
23
|
+
function App() {
|
|
24
|
+
return <CCalendar apiKey="your-api-key" activeUser={1} />;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Props
|
|
29
|
+
|
|
30
|
+
| Prop | Type | Description |
|
|
31
|
+
|------|------|-------------|
|
|
32
|
+
| `apiKey` | `string` | API key for authenticating with the Aventine API |
|
|
33
|
+
| `activeUser` | `number` | The current user's ID (used for chair assignments and edit tracking) |
|
|
34
|
+
|
|
35
|
+
### CSS Import
|
|
36
|
+
|
|
37
|
+
You **must** import the stylesheet separately:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import '@propriety/court-calendar/styles.css';
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Theming
|
|
44
|
+
|
|
45
|
+
The component supports light and dark themes via the `data-theme` attribute on the document body:
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
document.body.setAttribute('data-theme', 'dark'); // or 'light'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Components use the `.themed` CSS class to pick up theme variables.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Development
|
|
56
|
+
|
|
57
|
+
### Prerequisites
|
|
58
|
+
|
|
59
|
+
- Node.js 20+
|
|
60
|
+
- npm
|
|
61
|
+
|
|
62
|
+
### Setup
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git clone git@github.com:Aventine-Git/court-calendar.git
|
|
66
|
+
cd court-calendar
|
|
67
|
+
npm install
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Dev Server
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm run dev
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This starts the Vite dev server using the `dev/` directory as the entry point (`dev/App.tsx` and `dev/main.tsx`). The dev app wraps the `CCalendar` component for local testing.
|
|
77
|
+
|
|
78
|
+
**Important:** The API only accepts requests from `localhost:8000`. The dev server must run on port 8000 or API calls will be rejected with CORS errors.
|
|
79
|
+
|
|
80
|
+
### Environment Variables
|
|
81
|
+
|
|
82
|
+
Create a `.env` file in the project root:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
VITE_CALENDAR_API_KEY=your-api-key-here
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
This key is used by the dev app and is accessed via `import.meta.env.VITE_CALENDAR_API_KEY`.
|
|
89
|
+
|
|
90
|
+
### Build
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm run build
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Runs TypeScript compilation (`tsc -b`) followed by the Vite library build. Output goes to `dist/`:
|
|
97
|
+
|
|
98
|
+
- `dist/index.mjs` - ES module bundle
|
|
99
|
+
- `dist/index.d.ts` - TypeScript type definitions
|
|
100
|
+
- `dist/court-calendar.css` - Compiled styles
|
|
101
|
+
|
|
102
|
+
The build externalizes React, React-DOM, MUI, and Emotion packages (they are peer dependencies and not bundled).
|
|
103
|
+
|
|
104
|
+
### Lint
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npm run lint
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Uses ESLint with TypeScript plugin. Biome is also configured for formatting (4-space indent, 120 char line width, single quotes).
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Testing
|
|
115
|
+
|
|
116
|
+
There are currently no automated tests. Testing is done manually through the dev server.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## API
|
|
121
|
+
|
|
122
|
+
All data is fetched from `https://utils.aventine.ai`. Every request requires the `x-api-key` header.
|
|
123
|
+
|
|
124
|
+
### Endpoints
|
|
125
|
+
|
|
126
|
+
| Endpoint | Method | Description |
|
|
127
|
+
|----------|--------|-------------|
|
|
128
|
+
| `/court-dates/all` | GET | Fetch all court dates |
|
|
129
|
+
| `/court-dates/create` | POST | Create a new court date |
|
|
130
|
+
| `/court-dates/{id}/update` | PUT | Update a court date |
|
|
131
|
+
| `/court-dates/{id}` | DELETE | Delete a court date |
|
|
132
|
+
| `/court-dates/{id}/cases` | GET | Fetch cases for a court date |
|
|
133
|
+
| `/court-cases/search?term=...&page=...` | GET | Search cases (paginated) |
|
|
134
|
+
| `/court-cases/filtering?page=...&page_size=...` | GET | List all cases (paginated) |
|
|
135
|
+
| `/court-cases/snooze/upload/{id}` | GET | Snooze upload deadline by 1 business day |
|
|
136
|
+
| `/users/all` | GET | Fetch all users |
|
|
137
|
+
| `/users/hearing-officers` | GET | Fetch hearing officers |
|
|
138
|
+
| `/utils/get-muni-names` | GET | Fetch municipality names |
|
|
139
|
+
|
|
140
|
+
### Limitations
|
|
141
|
+
|
|
142
|
+
- **Port restriction:** The API only accepts requests from `localhost:8000`. Running the dev server on any other port will result in CORS failures.
|
|
143
|
+
- **No offline support:** All CRUD operations require an active connection to the API. The IndexedDB cache is read-only (used for faster page loads, not offline editing).
|
|
144
|
+
- **Cache expiry:** Court dates cache expires after 5 minutes, cases cache after 1 hour. After expiry, data is re-fetched from the API on the next page load.
|
|
145
|
+
- **No pagination for court dates:** `getAllDates` fetches every court date in a single request. For large datasets this could be slow.
|
|
146
|
+
- **Municipality and user data loads on import:** `munis.ts` and `people.ts` fire fetch requests at module load time, not lazily.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Architecture
|
|
151
|
+
|
|
152
|
+
### Components
|
|
153
|
+
|
|
154
|
+
| Component | Description |
|
|
155
|
+
|-----------|-------------|
|
|
156
|
+
| `CCalendar` | Root component. Manages state, events, filtering, and renders the calendar + modal. |
|
|
157
|
+
| `Toolbar` | Navigation and filter controls (date type, hearing type, case filters, user filter, view switcher, municipality dropdown, search). |
|
|
158
|
+
| `CalendarList` | MUI DataGrid table view of court dates with color-coded status, county, and location columns. |
|
|
159
|
+
| `Modal` | Dialog with 4 modes: Details, Edit, Create, Case Details. |
|
|
160
|
+
| `CreateEditCase` | Form for court date fields (dates, municipality, hearing details, chair assignments, case IDs). |
|
|
161
|
+
| `CaseViewer` | DataGrid listing cases for a selected court date. |
|
|
162
|
+
| `CaseDetails` | Read-only view of a single case with evidence and SCAR data. |
|
|
163
|
+
|
|
164
|
+
### Helpers
|
|
165
|
+
|
|
166
|
+
| Helper | Description |
|
|
167
|
+
|--------|-------------|
|
|
168
|
+
| `courtDates.ts` | CRUD operations for court dates. Sends datetime strings combining date + hearing time. |
|
|
169
|
+
| `cases.ts` | Case fetching (by court date, paginated, search). Settlement and evidence checks. |
|
|
170
|
+
| `cache.ts` | Dexie-based IndexedDB caching with TTL (5 min for dates, 1 hour for cases). |
|
|
171
|
+
| `formatter.ts` | Date formatting for API (`YYYY-MM-DD` or `YYYY-MM-DD HH:mm:00`). 12h/24h time conversion. Evidence string formatting. |
|
|
172
|
+
| `munis.ts` | Municipality name lookups. Fetches data once on module load. |
|
|
173
|
+
| `people.ts` | User and hearing officer lookups. Fetches data once on module load. |
|
|
174
|
+
|
|
175
|
+
### Key Types
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
interface CourtDate {
|
|
179
|
+
CourtDateID: number;
|
|
180
|
+
CourtDate: Date;
|
|
181
|
+
MuniCode: string;
|
|
182
|
+
UploadDeadline: Date | null;
|
|
183
|
+
CourtCases: number;
|
|
184
|
+
Lifecycle: Lifecycle | null; // Scheduled | Assigned | Uploaded | Adjourned
|
|
185
|
+
HearingTime: string;
|
|
186
|
+
HearingLink: string | null;
|
|
187
|
+
Source: SourceType | null; // manual | email | etrack
|
|
188
|
+
Type: HearingType | null; // Other | Virtual | InPerson
|
|
189
|
+
FirstChair: number | null;
|
|
190
|
+
SecondChair: number | null;
|
|
191
|
+
HearingOfficer: number | null;
|
|
192
|
+
IsAdjourned: boolean;
|
|
193
|
+
AdjournmentDate: Date | null;
|
|
194
|
+
Notes: string | null;
|
|
195
|
+
NoticeFile: string | null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
interface Case {
|
|
199
|
+
ParcelID: string;
|
|
200
|
+
Municipality: string;
|
|
201
|
+
SCARIndexNumber: string;
|
|
202
|
+
SCARDeterminationAction: string;
|
|
203
|
+
property_data: { Address: string; PropertyOwnerFull: string };
|
|
204
|
+
evidence: Evidence | null;
|
|
205
|
+
DateCompleted: Date | null;
|
|
206
|
+
// ... plus Village SCAR fields
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## CI/CD
|
|
213
|
+
|
|
214
|
+
Publishing is automated via GitHub Actions (`.github/workflows/publish.yml`).
|
|
215
|
+
|
|
216
|
+
**Trigger:** Every merged PR to `main`.
|
|
217
|
+
|
|
218
|
+
**Steps:**
|
|
219
|
+
1. Checkout code
|
|
220
|
+
2. Install dependencies (`npm ci`)
|
|
221
|
+
3. Build (`npm run build`)
|
|
222
|
+
4. Set version to `0.0.{run_number}` (auto-incrementing, no commit needed)
|
|
223
|
+
5. Publish to npm with provenance
|
|
224
|
+
|
|
225
|
+
**Required secrets:**
|
|
226
|
+
- `NPM_TOKEN` - npm access token with publish permissions for the `@propriety` scope
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Known Limitations
|
|
231
|
+
|
|
232
|
+
- **Port 8000 only:** The backend API enforces CORS restrictions that only allow requests from `localhost:8000`. This applies to the dev server and any consuming application running locally.
|
|
233
|
+
- **No test suite:** The project has no automated tests.
|
|
234
|
+
- **Module-level side effects:** Municipality names and user data are fetched automatically when their modules are imported, which means network requests happen at import time rather than on demand.
|
|
235
|
+
- **Cache is not invalidated on external changes:** If another user modifies a court date, the change won't appear until the local cache expires (5 minutes for dates, 1 hour for cases).
|
|
236
|
+
- **Single API key:** The component expects a single API key passed as a prop. There is no built-in token refresh or rotation mechanism.
|
|
237
|
+
- **No error UI:** API failures are logged to console but there are no user-facing error notifications (marked with TODO comments in the codebase).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ModalMode, CalendarFilterCtx, Case, CourtDate } from '../../types';
|
|
2
|
-
export default function CCModal({ modalIsOpen, modalMode, setModalMode, setIsOpen, selectedCourtDate, updateCourtDateInMemory, filterCtx, setFilterCtx, selectedCases, updateCases, deleteCases, isFetchingCases, apiKey, }: {
|
|
2
|
+
export default function CCModal({ modalIsOpen, modalMode, setModalMode, setIsOpen, selectedCourtDate, updateCourtDateInMemory, filterCtx, setFilterCtx, selectedCases, updateCases, deleteCases, isFetchingCases, apiKey, activeUser, }: {
|
|
3
3
|
modalIsOpen: boolean;
|
|
4
4
|
modalMode: ModalMode;
|
|
5
5
|
setModalMode: (mode: ModalMode) => void;
|
|
@@ -13,4 +13,5 @@ export default function CCModal({ modalIsOpen, modalMode, setModalMode, setIsOpe
|
|
|
13
13
|
deleteCases: (courtDateId: string) => void;
|
|
14
14
|
isFetchingCases: boolean;
|
|
15
15
|
apiKey: string;
|
|
16
|
+
activeUser: number;
|
|
16
17
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CourtDate } from '../types';
|
|
2
2
|
export declare function getAllDates(apiKey: string): Promise<Array<CourtDate>>;
|
|
3
|
-
export declare function updateCourtDate(courtDateId: number, updatedData: Partial<CourtDate>, apiKey: string, courtCases?: string[]): Promise<boolean>;
|
|
3
|
+
export declare function updateCourtDate(courtDateId: number, updatedData: Partial<CourtDate>, apiKey: string, courtCases?: string[], user?: number): Promise<boolean>;
|
|
4
4
|
export declare function deleteCourtDate(courtDateId: number, apiKey: string): Promise<boolean>;
|
|
5
|
-
export declare function createCourtDate(courtDate: Date, muniCode: string, apiKey: string, courtCases?: string[]): Promise<number | null>;
|
|
5
|
+
export declare function createCourtDate(courtDate: Date, muniCode: string, apiKey: string, courtCases?: string[], hearingTime?: string): Promise<number | null>;
|
|
6
6
|
export declare function snoozeUploadDeadline(courtDateId: number, apiKey: string): Promise<boolean>;
|
|
7
7
|
export declare function isVillageDate(muniCode: string): boolean;
|