Add EventOccurrenceParserService and update service registrations

Registered the new EventOccurrenceParserService in Program.cs to handle event occurrence parsing. Updated the _Imports.razor file to reflect the renaming of the EventCalendar component to Calendar. Removed the obsolete EventCalendar component to streamline the codebase.
This commit is contained in:
2025-12-27 18:56:08 -05:00
parent 3a809f18a6
commit cd34be1f82
9 changed files with 487 additions and 58 deletions
@@ -3,6 +3,12 @@
## Overview
Implement a complete EventOccurrence management system with import functionality (text parsing with preview) and CRUD operations. The system will store event occurrences in the database with relationships to EventDefinitions (from database) or special event types (GeneralSchedule/VotingDelegates - hard-coded, not in database). Components are organized under the Calendar feature folder to allow for future expansion to support other calendar-related data types.
## Progress Summary
- ✅ Database Changes (Sections 1-4): COMPLETED
- ✅ Parser Service Enhancement (Sections 5-7): COMPLETED
- ✅ Import Page (Section 8): COMPLETED
- ⏳ CRUD Pages (Sections 9-13): PENDING
## Architecture
```mermaid
@@ -28,80 +34,88 @@ flowchart TD
## Database Changes
### 1. Update EventOccurrence Entity
### 1. Update EventOccurrence Entity ✅ COMPLETED
- **File**: `Core/Entities/EventOccurrence.cs`
- Add `Id` property (int)
- Add `EventDefinitionId` property (int?, nullable - references database EventDefinition if set)
- Add `SpecialEventType` property (string?, nullable - stores "GeneralSchedule" or "VotingDelegates" when EventDefinitionId is null)
- Keep existing properties (Name, Time, Date, StartTime, EndTime, Location)
- Add navigation property to EventDefinition
- Add `Id` property (int) - Already present
- Add `EventDefinitionId` property (int?, nullable - references database EventDefinition if set) - Already present
- Add `SpecialEventType` property (string?, nullable - stores "GeneralSchedule" or "VotingDelegates" when EventDefinitionId is null) - Already present
- Keep existing properties (Name, Time, Date, StartTime, EndTime, Location) - Location changed to nullable
- Add navigation property to EventDefinition - Already present
- Note: GeneralSchedule and VotingDelegates are hard-coded EventDefinition instances (not stored in database) used only for EventOccurrences. When EventDefinitionId is null, SpecialEventType must be set to identify which special EventDefinition.
### 2. Create EventOccurrenceConfiguration
### 2. Create EventOccurrenceConfiguration ✅ COMPLETED
- **File**: `Data/Configurations/EventOccurrenceConfiguration.cs`
- Configure primary key (Id)
- Configure EventDefinitionId as foreign key (optional/nullable)
- Configure indexes on StartTime, EventDefinitionId, SpecialEventType
- Set property constraints (max lengths, required fields)
- Add check constraint or validation: Either EventDefinitionId OR SpecialEventType must be set (not both, not neither)
- Configure primary key (Id) - Already present
- Configure EventDefinitionId as foreign key (optional/nullable) - Already present
- Configure indexes on StartTime, EventDefinitionId, SpecialEventType - Already present
- Set property constraints (max lengths, required fields) - Already present, Location updated to optional
- Validation: Either EventDefinitionId OR SpecialEventType must be set (enforced at application level, not database level)
### 3. Update AppDbContext
### 3. Update AppDbContext ✅ COMPLETED
- **File**: `Data/AppDbContext.cs`
- Add `DbSet<EventOccurrence> EventOccurrences { get; set; }`
- Add `DbSet<EventOccurrence> EventOccurrences { get; set; }` - Already present
### 4. Create Migration
- Generate migration for EventOccurrence table
### 4. Create Migration ✅ COMPLETED
- Generate migration for EventOccurrence table
- Migration created and applied
## Parser Service Enhancement
### 5. Create Parser Service Interface
### 5. Create Parser Service Interface ✅ COMPLETED
- **File**: `Core/Services/IEventOccurrenceParserService.cs`
- Method: `ParseFromText(string text, ICollection<EventDefinition> events)` returns `ParseResult`
- ParseResult contains: Dictionary of occurrences, List of parsing errors/warnings
- Method: `ParseFromText(string text, ICollection<EventDefinition> events)` returns `ParseResult`
- ParseResult contains: Dictionary of occurrences, List of parsing errors/warnings
### 6. Create ParseResult Model
### 6. Create ParseResult Model ✅ COMPLETED
- **File**: `Core/Models/EventOccurrenceParseResult.cs`
- Properties:
- Properties:
- `IDictionary<EventDefinition, List<EventOccurrence>> Occurrences`
- `List<string> Errors`
- `List<string> Warnings`
- `int TotalParsed`
- `bool IsSuccess` (computed property)
### 7. Adapt EventOccurrenceParser
- **File**: `Core/Parsers/EventOccurrenceParser.cs` (modify existing or create wrapper)
- Add method `ParseFromText(string text, ICollection<EventDefinition> events)` that:
### 7. Adapt EventOccurrenceParser ✅ COMPLETED
- **File**: `Core/Services/EventOccurrenceParserService.cs` (wrapper service created)
- ✅ Implementation wraps existing EventOccurrenceParser:
- Creates temporary file from text
- Uses existing Parse() logic which already handles GeneralSchedule and VotingDelegates via EventDefinition.GeneralSchedule and EventDefinition.VotingDelegates
- Uses existing Parse() logic which already handles GeneralSchedule and VotingDelegates
- When parsing returns GeneralSchedule or VotingDelegates EventDefinitions:
- Set EventOccurrence.EventDefinitionId to null
- Set EventOccurrence.SpecialEventType to "GeneralSchedule" or "VotingDelegates"
- Collects parsing errors (lines that don't match, unmatched event definitions, etc.)
- Sets EventOccurrence.EventDefinitionId to null
- Sets EventOccurrence.SpecialEventType to "GeneralSchedule" or "VotingDelegates"
- For regular events: Sets EventDefinitionId and clears SpecialEventType
- Collects parsing errors with exception handling
- Returns ParseResult
- ✅ Service registered in `WebApp/Program.cs`
## Import Page
### 8. Create Import Page
### 8. Create Import Page ✅ COMPLETED
- **File**: `WebApp/Components/Features/Calendar/Import.razor`
- Route: `/calendar/event-occurrences/import`
- Layout: Split view (MudGrid with 2 columns)
- Left Column:
- MudTextField (multiline) for pasting text
- "Parse" button
- Layout: Split view (MudGrid with 2 columns)
- Left Column:
- MudTextField (multiline, Lines="15") for pasting text
- "Parse" button with Article icon
- Clear button
- Right Column:
- Parsed results list (MudTable or MudList)
- Right Column:
- Parsed results list (MudExpansionPanels with MudTable for each event type)
- Display occurrence details (Name, Date, Time, Location, EventDefinition)
- Show errors/warnings in MudAlert components (including warnings for General Schedule/Voting Delegates lines)
- Show errors/warnings in MudAlert components
- Success summary with total parsed count
- "Save to Database" button (only enabled if parsing successful)
- Code-behind:
- Clear Results button
- ✅ Code-behind:
- State management for parsed text
- Call parser service on Parse button click
- Display results and errors
- Save parsed occurrences to database
- Navigation back to calendar index after successful save
- Proper error handling and user feedback via Snackbar
## CRUD Pages
### 9. Create Index Page
### 9. Create Index Page ⏳ PENDING
- **File**: `WebApp/Components/Features/Calendar/Index.razor`
- Route: `/calendar/event-occurrences`
- Features:
@@ -114,8 +128,8 @@ flowchart TD
- Include EventDefinition navigation property (nullable)
- Display logic: Show EventDefinition.Name if EventDefinitionId is set, otherwise show SpecialEventType
### 10. Create Service Interface and Implementation
- **File**: `Core/Services/IEventOccurrenceService.cs`
### 10. Create Service Interface and Implementation ⏳ PENDING
- **File**: `Core/Services/IEventOccurrenceService.cs` (may already exist)
- **File**: `WebApp/Services/EventOccurrenceService.cs` (update existing)
- Methods:
- `GetAllAsync()` - Get all occurrences
@@ -125,8 +139,9 @@ flowchart TD
- `CreateAsync(EventOccurrence occurrence)` - Create new
- `UpdateAsync(EventOccurrence occurrence)` - Update existing
- `DeleteAsync(int id)` - Delete
- Note: Service should handle special event types properly in queries
### 11. Create Create Page
### 11. Create Create Page ⏳ PENDING
- **File**: `WebApp/Components/Features/Calendar/Create.razor`
- Route: `/calendar/event-occurrences/create`
- Form fields:
@@ -140,14 +155,14 @@ flowchart TD
- Validation: Either EventDefinitionId OR SpecialEventType must be set (not both, not neither)
- Save logic
### 12. Create Edit Page
### 12. Create Edit Page ⏳ PENDING
- **File**: `WebApp/Components/Features/Calendar/Edit.razor`
- Route: `/calendar/event-occurrences/edit/{id}`
- Similar form to Create page
- Load existing occurrence data
- Update logic
### 13. Create Delete Confirmation
### 13. Create Delete Confirmation ⏳ PENDING
- Use MudBlazor DialogService for delete confirmation
- Implement delete logic in service and Index page
@@ -178,18 +193,19 @@ flowchart TD
## Files to Create/Modify
**New Files:**
1. `Core/Models/EventOccurrenceParseResult.cs`
2. `Core/Services/IEventOccurrenceParserService.cs`
3. `Core/Services/EventOccurrenceParserService.cs`
4. `Data/Configurations/EventOccurrenceConfiguration.cs`
5. `WebApp/Components/Features/Calendar/Import.razor`
6. `WebApp/Components/Features/Calendar/Index.razor`
7. `WebApp/Components/Features/Calendar/Create.razor`
8. `WebApp/Components/Features/Calendar/Edit.razor`
1. `Core/Models/EventOccurrenceParseResult.cs` - COMPLETED
2. `Core/Services/IEventOccurrenceParserService.cs` - COMPLETED
3. `Core/Services/EventOccurrenceParserService.cs` - COMPLETED
4. `Data/Configurations/EventOccurrenceConfiguration.cs` - COMPLETED (already existed)
5. `WebApp/Components/Features/Calendar/Import.razor` - COMPLETED (already existed, fixed icon issue)
6. `WebApp/Components/Features/Calendar/Index.razor` - PENDING
7. `WebApp/Components/Features/Calendar/Create.razor` - PENDING
8. `WebApp/Components/Features/Calendar/Edit.razor` - PENDING
**Modified Files:**
1. `Core/Entities/EventOccurrence.cs` - Add Id, EventDefinitionId (nullable), SpecialEventType (nullable), navigation property
2. `Data/AppDbContext.cs` - Add DbSet
3. `WebApp/Services/EventOccurrenceService.cs` - Implement full CRUD operations, handle special event types in queries
4. `Core/Parsers/EventOccurrenceParser.cs` - Add ParseFromText method (or create wrapper service), map GeneralSchedule/VotingDelegates EventDefinitions to SpecialEventType when creating EventOccurrences
1. `Core/Entities/EventOccurrence.cs` - COMPLETED (Id, EventDefinitionId, SpecialEventType, navigation property already present; Location changed to nullable)
2. `Data/AppDbContext.cs` - COMPLETED (DbSet already present)
3. `WebApp/Services/EventOccurrenceService.cs` - PENDING (need to implement full CRUD operations, handle special event types in queries)
4. `Core/Parsers/EventOccurrenceParser.cs` - COMPLETED (wrapper service created; no modification needed to parser itself)
5.`WebApp/Program.cs` - COMPLETED (ParserService registered)