Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0b9cfd9
feat(attendance): add Cohort Overview stats panel
AlexVOiceover Jan 7, 2026
50f5f27
fix(attendance): use consistent 'Attendance Stats' title for both cards
AlexVOiceover Jan 7, 2026
682d87f
feat(attendance): add Event Breakdown panel to cohort view
AlexVOiceover Jan 7, 2026
33d27b5
feat(attendance): consolidate filters into unified card
AlexVOiceover Jan 7, 2026
8d83a3c
fix(attendance): polish cohort view tables
AlexVOiceover Jan 7, 2026
6b94d9a
feat(attendance): show global attendance and lateness rates
AlexVOiceover Jan 7, 2026
42d6d2b
fix(attendance): remove redundant Attended column, improve badge padding
AlexVOiceover Jan 7, 2026
a554300
feat(attendance): add event count to panel headers
AlexVOiceover Jan 7, 2026
dc98ccc
feat(attendance): improve navigation with Change Cohorts back link
AlexVOiceover Jan 7, 2026
02ca6ce
feat(attendance): improve time period filter visibility
AlexVOiceover Jan 7, 2026
ac242cc
fix(attendance): remove redundant time period display
AlexVOiceover Jan 7, 2026
72431f6
feat(attendance): add date range validation
AlexVOiceover Jan 8, 2026
cd7e476
docs: updated scratchpad
AlexVOiceover Jan 8, 2026
9129fe8
docs: updated scratchpad
AlexVOiceover Jan 8, 2026
26f95c9
feat(ui): apply consistent styling to checkin pages
AlexVOiceover Jan 8, 2026
7f53bbc
feat(attendance): add percentage displays to apprentice stats card
AlexVOiceover Jan 8, 2026
eacc2c4
feat(checkin): add optional reason field for absence
AlexVOiceover Jan 8, 2026
cbd8329
feat(attendance): add reason column with staff editing capability
AlexVOiceover Jan 8, 2026
011b201
feat(attendance): unify filter interface between cohort and apprentic…
AlexVOiceover Jan 8, 2026
3895697
feat(attendance): create unified stats component for cohort and appre…
AlexVOiceover Jan 8, 2026
996e07e
docs: update event type from Hackathon to Online Class
AlexVOiceover Jan 8, 2026
12e1fec
docs: update terminology from Missed to Did not attend
AlexVOiceover Jan 8, 2026
ac42e08
feat: implement dynamic event types from Airtable
AlexVOiceover Jan 8, 2026
f88a4bd
feat(events): fix event type display and add survey auto-population
AlexVOiceover Jan 8, 2026
4ce5e8d
feat(events): improve survey modal UX and fix auto-population
AlexVOiceover Jan 8, 2026
8b7f667
feat(events): add ESC key cancellation and mutual exclusivity for forms
AlexVOiceover Jan 8, 2026
d7e1c36
feat(admin): add Search Apprentice feature to dashboard
AlexVOiceover Jan 8, 2026
2acf901
feat(search): improve search apprentice layout and navigation
AlexVOiceover Jan 8, 2026
8a77da8
fix: fixed lint errors
AlexVOiceover Jan 8, 2026
9aa0e32
fix: resolve linting errors and update tests for dynamic event types
AlexVOiceover Jan 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,14 @@ The generated schema file can be used to update `src/lib/airtable/config.ts` wit

### Event Types

Event types are defined as a single source of truth in `src/lib/types/event.ts`:
Event types are now managed dynamically through Airtable's "Event types - Apprentice Pulse" table. This provides:

```typescript
export const EVENT_TYPES = ['Regular class', 'Workshop', 'Hackathon'] as const;
export type EventType = typeof EVENT_TYPES[number];
```
- **Single source of truth**: Event types defined in Airtable only
- **No code deployments**: Add/remove event types without touching code
- **Flexible management**: Administrators can manage types directly in Airtable
- **Automatic validation**: API endpoints validate against current Airtable data

To add a new event type, update the `EVENT_TYPES` array - all forms and validation will automatically use the new values.
Event types are cached for performance (5-minute cache) and include automatic color assignment for UI consistency.

### Default Values

Expand Down
204 changes: 204 additions & 0 deletions docs/plan-search-apprentice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# Search Apprentice Feature - Implementation Plan

## Overview
Add a Search Apprentice card to the admin dashboard that allows users to quickly search for apprentices by name and navigate directly to their detail page.

## User Flow
1. User types in search field on admin dashboard
2. System shows live search results matching the query
3. User clicks on an apprentice from results
4. System navigates to apprentice detail page (`/admin/apprentices/[id]`)

## Technical Architecture

### 1. Search API Endpoint
**File**: `src/routes/api/apprentices/search/+server.ts`

- **Method**: GET
- **Query params**: `q` (search query)
- **Returns**: Array of matching apprentices with id, name, email, cohort
- **Search logic**:
- Case-insensitive search
- Matches against apprentice name
- Returns up to 10 results
- Orders by relevance/alphabetical

### 2. Search Component
**File**: `src/lib/components/SearchApprentice.svelte`

**Features**:
- Text input field with search icon
- Debounced search (300ms) to avoid excessive API calls
- Loading state while searching
- Dropdown results list
- Keyboard navigation (arrow keys + enter)
- Click outside to close
- Empty state when no results
- Error handling

**Props**:
- No props needed (self-contained)

**State**:
- `searchQuery`: Current search text
- `searchResults`: Array of apprentice results
- `isSearching`: Loading state
- `showResults`: Dropdown visibility
- `selectedIndex`: For keyboard navigation

### 3. Dashboard Integration
**File**: `src/routes/admin/+page.svelte`

**Add new card**:
```svelte
<a href="/admin/apprentices" class="group block...">
<SearchApprentice />
</a>
```

**Card design**:
- Title: "Search Apprentice"
- Description: "Find and view apprentice details"
- Icon: 🔍 (magnifying glass)
- Color scheme: Purple (to differentiate from other cards)

### 4. Data Types
**File**: `src/lib/types/apprentice.ts`

```typescript
interface ApprenticeSearchResult {
id: string;
name: string;
email: string;
cohortNumber?: number;
status: 'Active' | 'On Leave' | 'Off-boarded';
}
```

## Implementation Steps

### Phase 1: Backend
1. Create search API endpoint
2. Implement Airtable search logic
3. Add proper error handling
4. Test with various search queries

### Phase 2: Search Component
1. Create SearchApprentice component structure
2. Implement search input with debouncing
3. Add API integration
4. Implement results dropdown
5. Add keyboard navigation
6. Style component to match existing design

### Phase 3: Dashboard Integration
1. Add new card to admin dashboard
2. Integrate SearchApprentice component
3. Style card to match existing cards
4. Test navigation to apprentice details

### Phase 4: Polish & Testing
1. Add loading states
2. Implement error handling
3. Add empty states
4. Test edge cases
5. Ensure mobile responsiveness

## Component Structure

```svelte
<div class="search-apprentice">
<div class="search-input-wrapper">
<input
type="text"
placeholder="Search apprentices..."
bind:value={searchQuery}
on:input={handleSearch}
/>
<svg class="search-icon">...</svg>
</div>

{#if showResults}
<div class="search-results">
{#if isSearching}
<div class="loading">Searching...</div>
{:else if searchResults.length > 0}
<ul>
{#each searchResults as result, index}
<li>
<a href="/admin/apprentices/{result.id}">
<span class="name">{result.name}</span>
<span class="email">{result.email}</span>
{#if result.cohortNumber}
<span class="cohort">Cohort {result.cohortNumber}</span>
{/if}
</a>
</li>
{/each}
</ul>
{:else if searchQuery}
<div class="no-results">No apprentices found</div>
{/if}
</div>
{/if}
</div>
```

## Styling Considerations
- Match existing card styles (rounded corners, shadows, hover effects)
- Use purple color scheme for differentiation
- Dropdown should have z-index to appear above other content
- Mobile-first responsive design
- Smooth transitions for dropdown appearance

## API Response Example
```json
{
"success": true,
"apprentices": [
{
"id": "recXXXXXXXXXXXXX",
"name": "John Doe",
"email": "john.doe@example.com",
"cohortNumber": 12,
"status": "Active"
}
]
}
```

## Error Handling
- Network errors: Show "Failed to search" message
- Empty results: Show "No apprentices found"
- Rate limiting: Implement debouncing
- Invalid input: Minimum 2 characters to search

## Performance Considerations
- Debounce search input (300ms)
- Limit results to 10 items
- Cancel previous search requests if new one initiated
- Cache recent searches (optional enhancement)

## Accessibility
- Proper ARIA labels for search input
- Keyboard navigation support
- Screen reader announcements for results
- Focus management when opening/closing dropdown

## Testing Checklist
- [ ] Search returns correct results
- [ ] Clicking result navigates to apprentice page
- [ ] Keyboard navigation works
- [ ] Click outside closes dropdown
- [ ] Debouncing prevents excessive API calls
- [ ] Error states display correctly
- [ ] Loading state shows during search
- [ ] Mobile responsive design works
- [ ] Accessibility features work

## Future Enhancements
- Search by email as well as name
- Search by cohort number
- Recent searches history
- Advanced filters (status, cohort, etc.)
- Fuzzy matching for typos
Loading