Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
308ee9b
feat: Create route and page structure for `/admin/attendance/apprenti…
AlexVOiceover Jan 5, 2026
5fe2c08
docs: clarify two-step workflow in README (plan then start)
AlexVOiceover Jan 5, 2026
77b6483
feat: Create route and page structure for `/admin/attendance/apprenti…
AlexVOiceover Jan 5, 2026
e30ea51
feat: Create route and page structure for `/admin/attendance/apprenti…
AlexVOiceover Jan 5, 2026
46533c2
feat: Create route and page structure for `/admin/attendance/apprenti…
AlexVOiceover Jan 5, 2026
b120f56
feat: Create route and page structure for `/admin/attendance/apprenti…
AlexVOiceover Jan 5, 2026
a2565c7
feat(attendance): implement apprentice attendance view with cohort se…
AlexVOiceover Jan 5, 2026
31a37d1
fix(attendance): include events attended outside cohort in history
AlexVOiceover Jan 5, 2026
ba82543
fix(attendance): filter attendance records in JavaScript instead of A…
AlexVOiceover Jan 5, 2026
13b938b
fix(checkin): prevent duplicate check-ins by filtering in JavaScript
AlexVOiceover Jan 5, 2026
e9af3a0
feat(checkin): sort events by most recent first
AlexVOiceover Jan 5, 2026
7a677aa
feat(checkin): add styled header with user info
AlexVOiceover Jan 5, 2026
02d7f8b
feat(checkin): show attendance count on event cards
AlexVOiceover Jan 5, 2026
6cc6cb5
feat(checkin): show attendance count for open events
AlexVOiceover Jan 5, 2026
e5d8eff
feat(checkin): disable check-in for future events
AlexVOiceover Jan 5, 2026
d30a501
feat(checkin): improve guest check-in with event selection
AlexVOiceover Jan 5, 2026
f6b2aeb
fix(checkin): improve guest check-in styling consistency
AlexVOiceover Jan 5, 2026
13e5048
docs: update scratchpad notes
AlexVOiceover Jan 5, 2026
220d32e
feat(attendance): add 'Not Coming' status for apprentices
AlexVOiceover Jan 5, 2026
36b122e
config: added mcp servers config
AlexVOiceover Jan 6, 2026
9aced9b
feat(attendance): improve cohort selection UI with grouping and bulk …
AlexVOiceover Jan 6, 2026
8cabd91
fix(checkin): fix UI reactivity and improve button consistency
AlexVOiceover Jan 6, 2026
7a60b4c
docs: added notes to scatchpad
AlexVOiceover Jan 6, 2026
8143ecc
fix: fixed lint errors
AlexVOiceover Jan 6, 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
16 changes: 11 additions & 5 deletions .claude/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,26 @@ Custom automation for working with Jira tasks.

## Complete Workflow

### 1. Start a Task
### 1. Create the Plan

```
/plan AP-23
```

This will:
- Fetch AP-23 from Jira
- Fetch AP-23 from Jira (if connection fails, you'll be asked to run `/mcp` → `atlassian` → `4. Reconnect`)
- Move it to "In Progress"
- Create branch: `feature/ap-23-{slugified-summary}`
- Write `docs/plan.md` with checkbox tasks
- Create `.claude/loop` (activates the iterator)

### 2. Automatic Loop
**Claude stops here.** Review the plan if you want.

### 2. Start Implementation

Say `start` (or any prompt to begin working). This triggers the first task.

### 3. Automatic Loop

The hook (`.claude/hooks/plan-iterator.sh`) runs after each Claude response:

Expand All @@ -45,13 +51,13 @@ For each task, Claude:
4. Evaluates if `/update-report` is needed
5. Hook triggers → continues to next task

### 3. Loop Ends
### 4. Loop Ends

**Automatic:** When all tasks are `[x]`, `.claude/loop` is deleted and loop stops. Claude does NOT auto-start the next Jira ticket.

**Manual:** Run `/stop` or `rm .claude/loop`

### 4. Finish (manual steps)
### 5. Finish (manual steps)

When the loop ends, you decide what to do next:
- Create PR
Expand Down
16 changes: 8 additions & 8 deletions .claude/hooks/plan-iterator.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,21 @@ COMPLETED=$(grep -c '^\s*- \[x\]' "$PLAN_FILE" 2>/dev/null | head -1 || echo "0"
COMPLETED=${COMPLETED:-0}

# Stage all changes FIRST
git add -A 2>/dev/null || true
git add -A >/dev/null 2>&1 || true

# Then commit if there are staged changes
if ! git diff --cached --quiet 2>/dev/null; then
if [[ "$COMPLETED" -gt 0 ]]; then
LAST_DONE=$(grep -E '^\s*- \[x\]' "$PLAN_FILE" | tail -1 | sed 's/.*\[x\] //')
git commit -m "feat: $LAST_DONE" 2>/dev/null || true
git commit -m "feat: $LAST_DONE" >/dev/null 2>&1 || true
fi
fi

# Find next task
NEXT_TASK=$(grep -m1 '^\s*- \[ \]' "$PLAN_FILE" | sed 's/.*\[ \] //' | sed 's/"/\\"/g')

# Build the system message
read -r -d '' MESSAGE << MSGEOF
# Build the reason message for Claude
read -r -d '' REASON << MSGEOF
PLAN ITERATOR: Continue with the next task.

## Current Progress
Expand All @@ -76,8 +76,8 @@ $NEXT_TASK
Run /stop or delete .claude/loop
MSGEOF

# Escape message for JSON
ESCAPED_MSG=$(echo "$MESSAGE" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read())[1:-1])')
# Escape reason for JSON
ESCAPED_REASON=$(echo "$REASON" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read())[1:-1])')

# Return JSON to continue
echo "{\"continue\": true, \"systemMessage\": \"$ESCAPED_MSG\"}"
# Return JSON with decision: block to prevent Claude from stopping
echo "{\"decision\": \"block\", \"reason\": \"$ESCAPED_REASON\"}"
24 changes: 24 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"mcpServers": {
"atlassian": {
"type": "sse",
"url": "https://mcp.atlassian.com/v1/sse"
},
"github": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
}
},
"postman": {
"type": "stdio",
"command": "npx",
"args": ["@postman/postman-mcp-server@latest"],
"env": {
"POSTMAN_API_KEY": "${POSTMAN_API_KEY}"
}
}
}
}
34 changes: 15 additions & 19 deletions docs/plan.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
# AP-27 Attendance service - aggregate queries
# AP-25 Individual apprentice attendance view

> Extend attendance service with aggregate query functions for dashboard metrics. Functions needed: getApprenticeAttendanceStats, getCohortAttendanceStats, getAttendanceSummary. Returns: total events, attended count, attendance rate, late count, excused count, trend data.
> Create a view to track individual apprentice attendance history and rates. List apprentices with metrics, per-apprentice attendance rate, history of events attended/missed, filter by cohort, sort options, and visual indicator for low attendance.

## Tasks

- [x] Define TypeScript types for attendance stats (AttendanceStats, ApprenticeAttendanceStats, CohortAttendanceStats, AttendanceSummary)
- [x] Add getAllAttendance() helper to fetch all attendance records
- [x] Add getAllEvents() helper to fetch all events (needed for total event counts)
- [x] Implement getApprenticeAttendanceStats(apprenticeId) - individual apprentice stats
- [x] Implement getCohortAttendanceStats(cohortId) - cohort aggregate stats
- [x] Implement getAttendanceSummary() - overall summary for dashboard card
- [x] Add trend calculation helper (compare last 4 weeks vs previous 4 weeks)
- [x] Write tests for getApprenticeAttendanceStats
- [x] Write tests for getCohortAttendanceStats
- [x] Write tests for getAttendanceSummary
- [x] Create route and page structure for `/admin/attendance/apprentices`
- [x] Add server load function to fetch all apprentices with their attendance stats
- [x] Create ApprenticeAttendanceCard component to display individual metrics
- [x] Implement attendance history list showing events attended/missed per apprentice
- [x] Add cohort filter dropdown
- [x] Add sort functionality (by name, by attendance rate)
- [x] Add visual indicator for low attendance (below 80%)
- [x] Add click-through to detailed apprentice view
- [x] Write tests for the attendance apprentices page

## Notes

- Existing attendance service is in `src/lib/airtable/attendance.ts`
- Existing types in `src/lib/types/attendance.ts`
- Cohort data available via `listCohorts()` and `getApprenticesByCohortId()` in airtable.ts
- Events have cohortIds array (multi-cohort support)
- Status values: Present, Absent, Late, Excused
- Client-side aggregation approach (no Airtable schema changes)
- Attendance rate = (Present + Late) / Total events for cohort
- Use existing `getApprenticeAttendanceStats` from attendance service (AP-27)
- Attendance rate = (attended / total events) * 100
- Low attendance threshold: 80%
- Filter by cohort uses existing cohort data
10 changes: 5 additions & 5 deletions docs/scratchpad.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
Attendance is not showing names? (check Airtable)


td elements reduce padding


Not coming status

Checkin page show who I am
When checked in disable button or show that I already logged in. Now allows multiple
Login page pretty


Staff - Apprentice pulse, now has the student email. Use this for checkin as a student, not as an external


Show mii plaza

Integration with LUMA



security for not checkin if not close to date.



On readme how give permissions
12 changes: 0 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading