# CC Soccer D11 - Session Handoff

**Status:** Admin Group Invitations page added, duplicate invitation bug fixed

**Last Updated:** December 31, 2024

---

## **Current State - WORKING ✅**

### **Environment:**
- DDEV running Drupal 11
- Database: MySQL
- Git repo: Active, pushed to GitHub
- Site URL: http://ccsoccer-d11.ddev.site/
- Mailhog: http://ccsoccer-d11.ddev.site:8026

### **Core Systems Complete:**
- ✅ All 7 custom entities implemented and working
- ✅ Registration entity (custom, not contrib)
- ✅ Waitlist entity with override system
- ✅ Invitation entity for group/team invitations
- ✅ Commerce integration (products auto-created for seasons/tournaments)
- ✅ Notification system (email via Symfony Mailer, SMS via Clickatell)
- ✅ Complete checkout flow with custom panes
- ✅ Group management for seasons
- ✅ Team management for tournaments
- ✅ Order completion subscriber creating registrations
- ✅ Roles & permissions system with access control
- ✅ Captain access control for tournament teams
- ✅ Roster Builder with drag-and-drop UI and auto-save
- ✅ Team Balancer algorithm for auto-generating balanced rosters
- ✅ **Admin Group Invitations page for managing invitation statuses**

### **Admin Pages Working:**
- `/admin/ccsoccer/season/{season}/roster` - Roster Builder UI
- `/admin/ccsoccer/group/{group_id}/invitations` - **Group Invitations Management (NEW)**
- `/admin/ccsoccer/seasons` - Season management
- `/admin/ccsoccer/teams` - Team list
- `/admin/ccsoccer/registrations` - Registration list
- `/admin/ccsoccer/game-status` - Game status updates

### **User-Facing Pages Working:**
- `/register` - Main registration page with state-based cards
- `/my-registrations` - User's active registrations
- `/my-group/{registration}` - Group/team management
- `/tournament/{tournament}/team/{team}/manage` - Captain team management (UI TODO)

### **Test Data System:**
```bash
# Seed comprehensive test data (7 seasons + 3 tournaments)
ddev drush ccs-seed --test --force

# Seed with test users (board_test, slofriendly_test, etc)
ddev drush ccs-seed --users

# Test user credentials:
Username: testuser0 (or board_test, slofriendly_test, etc)
Password: password
```

---

## **Major Accomplishments This Session**

### **1. Admin Group Invitations Page**

**Goal:** Allow admin to manage group invitation statuses directly from the Roster Builder, so groups can be finalized before building rosters.

**Problem Solved:** Previously, admins could see groups in the Roster Builder but couldn't accept/reject pending invitations. They had to rely on players accepting invitations themselves.

**Implementation:**

#### **New Route:** `/admin/ccsoccer/group/{group_id}/invitations`

**Features:**
- Shows group manager (the person who created the group)
- Lists all invitations for the group with current status
- Dropdown to change status: Pending ↔ Accepted ↔ Declined (bidirectional)
- Summary stats: Accepted count, Pending count, Declined count
- "Back to Roster Builder" button

**Status Change Behavior:**
- **Pending → Accepted:** Sets `Registration.group_id` AND moves player to same team as group manager
- **Accepted → Pending/Declined:** Removes `Registration.group_id` (keeps team assignment for manual adjustment)
- **No notifications sent** - this is purely administrative, done before finalizing rosters

#### **Roster Builder Integration**

Group containers now have clickable three-dot link (`⋮⋮⋮`) that opens the admin group invitations page:
- **Old behavior:** Link went to player-facing `/my-group/{registration}` page
- **New behavior:** Link goes to admin `/admin/ccsoccer/group/{group_id}/invitations` page

**Files Created:**
- `src/Form/GroupInvitationsForm.php` - Admin form for managing invitations
- `css/group-invitations-admin.css` - Styling for the form

**Files Modified:**
- `ccsoccer.routing.yml` - Added `ccsoccer.group_invitations_admin` route
- `ccsoccer.libraries.yml` - Added `group-invitations-admin` library
- `src/Form/RosterBuilderForm.php` - Updated `buildGroupContainer()` to link to admin page

---

### **2. Fixed Duplicate Group Invitation Bug**

**Problem:** Users could send duplicate invitations to the same email address for the same group. This happened because the check only looked for `status = 'pending'`, missing:
1. Users who already accepted (have `Registration.group_id`)
2. Users who have an accepted invitation

**Example:** TestUser37 could be invited twice - once accepted, once pending - appearing twice in the Group Invitations list.

**Solution:** Updated `GroupController::invite()` to check:
1. **Is invitee already a group member?** - Check if they have `Registration.group_id` matching this group
2. **Is there any active invitation?** - Check for pending OR accepted invitations (not just pending)

**Error Messages:**
- "This player is already a member of your group." (already has group_id)
- "This player has already accepted an invitation to your group." (accepted invitation exists)  
- "An invitation has already been sent to this player." (pending invitation exists)

**File Modified:**
- `src/Controller/GroupController.php` - Updated duplicate check in `invite()` method

---

## **Files Created/Modified This Session**

### **New Files:**

| File | Purpose |
|------|---------|
| `src/Form/GroupInvitationsForm.php` | Admin form for managing group invitation statuses |
| `css/group-invitations-admin.css` | Styling for group invitations admin page |

### **Modified Files:**

| File | Changes |
|------|---------|
| `ccsoccer.routing.yml` | Added `ccsoccer.group_invitations_admin` route |
| `ccsoccer.libraries.yml` | Added `group-invitations-admin` library |
| `src/Form/RosterBuilderForm.php` | Updated `buildGroupContainer()` to link to admin invitations page |
| `src/Controller/GroupController.php` | Fixed duplicate invitation bug in `invite()` method |

---

## **Architecture Decisions**

### **Admin Group Invitations - Status Sync**

**Decision:** When admin accepts an invitation, automatically move the player to the group manager's team.

**Rationale:**
- Groups should stay together in Roster Builder
- Saves admin from manually dragging newly accepted members
- Keeps roster building workflow smooth

**Implementation:**
```php
// In GroupInvitationsForm::syncRegistrationGroupId()
if ($new_status === 'accepted') {
  $registration->set('group_id', $group_id);
  $manager_team_id = $this->getGroupManagerTeam($group_id, $season_id);
  if ($manager_team_id) {
    $registration->set('team', $manager_team_id);
  }
}
```

### **Group Link Target Change**

**Decision:** Group link in Roster Builder now goes to admin page, not player-facing page.

**Rationale:**
- Admin is already in admin context (Roster Builder)
- Admin needs to manage invitation statuses, not view player-facing UI
- Player-facing page doesn't show pending invitations with status controls

**Old URL:** `/my-group/{registration}` (player-facing)
**New URL:** `/admin/ccsoccer/group/{group_id}/invitations` (admin)

---

## **Testing the New Features**

### **Test Admin Group Invitations:**

1. Go to Roster Builder: `http://ccsoccer-d11.ddev.site/admin/ccsoccer/season/8/roster`
2. Find a group (yellow bordered container with multiple players)
3. Click the three dots (`⋮⋮⋮`) link on the group
4. Should open Group Invitations page showing:
   - Group Manager row (with "Manager" badge)
   - All invitations with status dropdowns
   - Accepted/Pending/Declined counts

### **Test Status Change:**

1. On Group Invitations page, change a "Pending" invitation to "Accepted"
2. Click "Save"
3. Click "Back to Roster Builder"
4. The newly accepted player should now appear IN the group container on the same team

### **Test Duplicate Prevention:**

1. Log in as a test user who has a group (e.g., testuser26)
2. Go to `/my-group/{registration}`
3. Try to invite someone who is already in the group
4. Should see error: "This player is already a member of your group."
5. Try to invite someone who already has a pending invitation
6. Should see error: "An invitation has already been sent to this player."

### **Database Verification:**

```bash
# Check invitations for a group
ddev drush sqlq "SELECT id, invitee_email, status, group_id FROM ccsoccer_invitation WHERE group_id = 'YOUR_GROUP_ID'"

# Check registrations with group_id
ddev drush sqlq "SELECT r.id, u.name, r.group_id, r.team FROM ccsoccer_registration r JOIN users_field_data u ON r.player = u.uid WHERE r.group_id = 'YOUR_GROUP_ID'"
```

---

## **Known Issues / TODO**

### **Captain UI - Not Yet Built:**
**Status:** Access control complete, routes exist, controller methods are stubs

**What's Missing:**
- Team roster display with member details
- Invitation form and handler
- Remove player confirmation and logic
- Team notification form functionality

**Files with TODO Comments:**
- `src/Controller/TournamentController.php` - All methods have detailed TODO
- `src/Form/TournamentTeamNotificationForm.php` - Stub form

### **Schedule Builder - Not Yet Started:**
Route exists but form is stub:
- `/admin/ccsoccer/season/{season}/schedule`

---

## **Commands to Remember**

### **Daily Development:**
```bash
# Start DDEV
ddev start

# Clear cache (do often!)
ddev drush cr

# Fresh test data with users
ddev drush ccs-seed --test --users --force

# Enhance test users with gender/age/skill
ddev drush ccsoccer:enhance-test-data
```

### **Roster Builder:**
```bash
# Open roster builder UI
open http://ccsoccer-d11.ddev.site/admin/ccsoccer/season/8/roster

# Generate rosters via Drush
ddev drush ccsoccer:suggest-rosters 8 --apply

# View current state
ddev drush ccsoccer:roster-state 8

# Clear all assignments
ddev drush ccsoccer:suggest-rosters 8 --clear --apply
```

### **Database Queries:**
```bash
# Check team assignments (Registration.team)
ddev drush sqlq "SELECT r.id, r.player, r.team, t.name as team_name FROM ccsoccer_registration r LEFT JOIN team t ON r.team = t.id WHERE r.season = 8 AND r.team IS NOT NULL"

# Check group invitations
ddev drush sqlq "SELECT id, invitee_email, status, group_id FROM ccsoccer_invitation WHERE season = 8"

# Check players in a specific group
ddev drush sqlq "SELECT r.id, u.name, r.group_id, r.team FROM ccsoccer_registration r JOIN users_field_data u ON r.player = u.uid WHERE r.group_id IS NOT NULL AND r.season = 8"
```

---

## **Collaboration Notes**

**Team:**
- Caleb - Lead developer
- Andrew (abmeade@hotmail.com) - Roster building and schedule generation

**Git Workflow:**
- **ALWAYS** `git pull` before `git push` (Andrew may have pushed changes)
- Commit working states frequently
- Clear commit messages

**After Pulling Changes:**
```bash
# Clear cache
ddev drush cr

# If entity fields changed, may need database update
ddev drush updb

# Import any new config
ddev drush config:import --partial --source=modules/custom/ccsoccer/config/install -y
```

---

## **Test Data Quick Reference**

### **Season 8 (TEST: Coed League):**
- 121 players registered
- 26 teams available
- Team size target: 8 players
- Type: Coed (requires women on each team)

### **Test User Credentials:**

| Username | Password | Role | Notes |
|----------|----------|------|-------|
| `admin` | (existing) | Administrator | Full access |
| `testuser26` | `password` | Player | Has a group with TestUser27 |
| `testuser36` | `password` | Player | Has a group for testing |
| `board_test` | `password` | Board Member | View reports only |
| `slofriendly_test` | `password` | Slofriendly | Tournaments only |

---

## **Success Metrics**

**This Session:**
- ✅ Admin Group Invitations page with status management
- ✅ Group link in Roster Builder goes to admin page
- ✅ Accepting invitation moves player to group's team
- ✅ Bidirectional status changes (Pending ↔ Accepted ↔ Declined)
- ✅ Fixed duplicate invitation bug
- ✅ Appropriate error messages for duplicate scenarios

**Next Session Priorities:**
1. Schedule Builder UI
2. Captain team management UI
3. Test with real season data

---

## **Important Reminders**

- **Registration.team is source of truth** - not Team.players
- **Auto-save on drag/drop** - no Save button needed in Roster Builder
- **Groups drag as a unit** - can't separate grouped players in UI
- **Admin group link** - three dots on groups go to admin invitations page
- **Accepting moves to team** - newly accepted members auto-move to group's team
- **No notifications from admin** - status changes from admin page don't notify players

---

**End of Handoff - Admin Group Invitations Complete**

Current State: Admin can manage group invitation statuses from Roster Builder
Next Priority: Schedule Builder or Captain UI
Breaking Point: Clean - all group invitation management working
