@propriety/court-calendar
v1.0.29
Published
A React component library for managing court dates, cases, and evidence. Built with FullCalendar, MUI, and Dexie (IndexedDB caching).
Keywords
Readme
@propriety/court-calendar
A React component library for managing court dates, cases, and evidence. Built with FullCalendar, MUI, and Dexie (IndexedDB caching).
Installation
npm install @propriety/court-calendarYou must also have the following peer dependencies installed:
npm install react react-dom @mui/material @mui/icons-material @mui/x-data-grid @mui/x-date-pickers @emotion/react @emotion/styledUsage
import { CCalendar } from '@propriety/court-calendar';
import '@propriety/court-calendar/styles.css';
function App() {
return <CCalendar apiKey="your-api-key" activeUser={1} />;
}Props
| Prop | Type | Description |
|------|------|-------------|
| apiKey | string | API key for authenticating with the Aventine API |
| activeUser | number | The current user's ID (used for chair assignments and edit tracking) |
CSS Import
You must import the stylesheet separately:
import '@propriety/court-calendar/styles.css';Theming
The component supports light and dark themes via the data-theme attribute on the document body:
document.body.setAttribute('data-theme', 'dark'); // or 'light'Components use the .themed CSS class to pick up theme variables.
Development
Prerequisites
- Node.js 20+
- npm
Setup
git clone [email protected]:Aventine-Git/court-calendar.git
cd court-calendar
npm installDev Server
npm run devThis 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.
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.
Environment Variables
Create a .env file in the project root:
VITE_CALENDAR_API_KEY=your-api-key-hereThis key is used by the dev app and is accessed via import.meta.env.VITE_CALENDAR_API_KEY.
Build
npm run buildRuns TypeScript compilation (tsc -b) followed by the Vite library build. Output goes to dist/:
dist/index.mjs- ES module bundledist/index.d.ts- TypeScript type definitionsdist/court-calendar.css- Compiled styles
The build externalizes React, React-DOM, MUI, and Emotion packages (they are peer dependencies and not bundled).
Lint
npm run lintUses ESLint with TypeScript plugin. Biome is also configured for formatting (4-space indent, 120 char line width, single quotes).
Testing
There are currently no automated tests. Testing is done manually through the dev server.
API
All data is fetched from https://utils.aventine.ai. Every request requires the x-api-key header.
Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| /court-dates/all | GET | Fetch all court dates |
| /court-dates/create | POST | Create a new court date |
| /court-dates/{id}/update | PUT | Update a court date |
| /court-dates/{id} | DELETE | Delete a court date |
| /court-dates/{id}/cases | GET | Fetch cases for a court date |
| /court-cases/search?term=...&page=... | GET | Search cases (paginated) |
| /court-cases/filtering?page=...&page_size=... | GET | List all cases (paginated) |
| /court-cases/snooze/upload/{id} | GET | Snooze upload deadline by 1 business day |
| /users/all | GET | Fetch all users |
| /users/hearing-officers | GET | Fetch hearing officers |
| /utils/get-muni-names | GET | Fetch municipality names |
Limitations
- Port restriction: The API only accepts requests from
localhost:8000. Running the dev server on any other port will result in CORS failures. - 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).
- 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.
- No pagination for court dates:
getAllDatesfetches every court date in a single request. For large datasets this could be slow. - Municipality and user data loads on import:
munis.tsandpeople.tsfire fetch requests at module load time, not lazily.
Architecture
Components
| Component | Description |
|-----------|-------------|
| CCalendar | Root component. Manages state, events, filtering, and renders the calendar + modal. |
| Toolbar | Navigation and filter controls (date type, hearing type, case filters, user filter, view switcher, municipality dropdown, search). |
| CalendarList | MUI DataGrid table view of court dates with color-coded status, county, and location columns. |
| Modal | Dialog with 4 modes: Details, Edit, Create, Case Details. |
| CreateEditCase | Form for court date fields (dates, municipality, hearing details, chair assignments, case IDs). |
| CaseViewer | DataGrid listing cases for a selected court date. |
| CaseDetails | Read-only view of a single case with evidence and SCAR data. |
Helpers
| Helper | Description |
|--------|-------------|
| courtDates.ts | CRUD operations for court dates. Sends datetime strings combining date + hearing time. |
| cases.ts | Case fetching (by court date, paginated, search). Settlement and evidence checks. |
| cache.ts | Dexie-based IndexedDB caching with TTL (5 min for dates, 1 hour for cases). |
| formatter.ts | Date formatting for API (YYYY-MM-DD or YYYY-MM-DD HH:mm:00). 12h/24h time conversion. Evidence string formatting. |
| munis.ts | Municipality name lookups. Fetches data once on module load. |
| people.ts | User and hearing officer lookups. Fetches data once on module load. |
Key Types
interface CourtDate {
CourtDateID: number;
CourtDate: Date;
MuniCode: string;
UploadDeadline: Date | null;
CourtCases: number;
Lifecycle: Lifecycle | null; // Scheduled | Assigned | Uploaded | Adjourned
HearingTime: string;
HearingLink: string | null;
Source: SourceType | null; // manual | email | etrack
Type: HearingType | null; // Other | Virtual | InPerson
FirstChair: number | null;
SecondChair: number | null;
HearingOfficer: number | null;
IsAdjourned: boolean;
AdjournmentDate: Date | null;
Notes: string | null;
NoticeFile: string | null;
}
interface Case {
ParcelID: string;
Municipality: string;
SCARIndexNumber: string;
SCARDeterminationAction: string;
property_data: { Address: string; PropertyOwnerFull: string };
evidence: Evidence | null;
DateCompleted: Date | null;
// ... plus Village SCAR fields
}CI/CD
Publishing is automated via GitHub Actions (.github/workflows/publish.yml).
Trigger: Every merged PR to main.
Steps:
- Checkout code
- Install dependencies (
npm ci) - Build (
npm run build) - Set version to
0.0.{run_number}(auto-incrementing, no commit needed) - Publish to npm with provenance
Required secrets:
NPM_TOKEN- npm access token with publish permissions for the@proprietyscope
Known Limitations
- 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. - No test suite: The project has no automated tests.
- 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.
- 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).
- Single API key: The component expects a single API key passed as a prop. There is no built-in token refresh or rotation mechanism.
- No error UI: API failures are logged to console but there are no user-facing error notifications (marked with TODO comments in the codebase).
