Skip to content

Commit 07aa92c

Browse files
authored
Merge pull request #54 from paulhenry46/copilot/fix-7d7d9a76-5542-491f-a78f-23307b8f35f9
Add Team Contests, Categories, and Route Selection per Contest Step
2 parents 7d9f5a0 + f45c275 commit 07aa92c

20 files changed

+1992
-11
lines changed

CONTEST_ENHANCEMENTS.md

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
# Contest Enhancement Features
2+
3+
This document describes the three major enhancements added to the contest system: Team Contests, Categories, and Route Selection per Contest Step.
4+
5+
## Overview
6+
7+
The contest system has been enhanced with the following features:
8+
1. **Team Contests** - Users can form teams and compete together
9+
2. **Categories** - Contest rankings can be organized by age, gender, or custom criteria
10+
3. **Route Selection per Step** - Each contest step can have its own specific routes
11+
12+
## 1. Team Contests
13+
14+
### Features
15+
- Enable team mode for any contest
16+
- Create and manage multiple teams per contest
17+
- Users can join/leave teams
18+
- Two team scoring modes:
19+
- **Unique Routes**: Each route counts once, even if multiple team members climb it
20+
- **All Climbs**: Count all climbs by team members (route climbed by 3 members = 3x points)
21+
- Users can only be in one team per contest
22+
23+
### Admin Usage
24+
25+
1. **Enable Team Mode**
26+
- When creating or editing a contest, check "Enable Team Mode"
27+
- This activates team features for the contest
28+
29+
2. **Choose Team Points Calculation**
30+
- When team mode is enabled, select the scoring mode:
31+
- **Unique Routes Only**: Each route counts once for the team (default)
32+
- **All Climbs**: Each team member's climb counts separately
33+
- Example with "All Climbs": Route 1 climbed by 3 members = 3× points, Route 2 climbed by 2 members = 2× points
34+
35+
3. **Manage Teams**
36+
- Navigate to Admin > Site > Contests
37+
- Click the team icon (👥) for a contest with team mode enabled
38+
- Create teams by clicking "Create Team"
39+
- Add/remove team members
40+
- Delete teams as needed
41+
42+
### User Experience
43+
44+
1. **Joining a Team**
45+
- Visit the contest public page
46+
- Switch to "Team" view mode
47+
- Browse available teams
48+
- Click "Join Team" to join
49+
- Only one team membership per contest is allowed
50+
51+
2. **Viewing Team Rankings**
52+
- Team rankings show all teams sorted by total points
53+
- Points calculation depends on the contest's team points mode:
54+
- **Unique mode**: Points from unique routes climbed by any team member
55+
- **All mode**: Sum of points from all climbs by all team members
56+
- In unique mode, if two team members climb the same route, points are only counted once
57+
- In all mode, each member's climb contributes to the team total
58+
59+
### Database Schema
60+
61+
**teams table:**
62+
- `id` - Primary key
63+
- `contest_id` - Foreign key to contests
64+
- `name` - Team name
65+
- `timestamps`
66+
67+
**team_user pivot table:**
68+
- `team_id` - Foreign key to teams
69+
- `user_id` - Foreign key to users
70+
- Unique constraint on (team_id, user_id)
71+
72+
**contests table (team-related fields):**
73+
- `team_mode` - Boolean, enables team features
74+
- `team_points_mode` - String ('unique' or 'all'), determines scoring method
75+
76+
## 2. Categories
77+
78+
### Features
79+
- Create unlimited categories per contest
80+
- Categories can be based on age, gender, or custom criteria
81+
- Users can join multiple categories
82+
- Separate rankings for each category
83+
- Category membership is optional
84+
85+
### Admin Usage
86+
87+
1. **Create Categories**
88+
- Navigate to Admin > Site > Contests
89+
- Click the categories icon (◆) for any contest
90+
- Click "Create Category"
91+
- Fill in:
92+
- **Name**: e.g., "Men 18-25", "Women Elite", "Youth"
93+
- **Type**: Age, Gender, or Custom (optional)
94+
- **Criteria**: Additional information (optional)
95+
96+
2. **Manage Categories**
97+
- View category participants
98+
- Edit category details
99+
- Delete categories
100+
101+
### User Experience
102+
103+
1. **Joining Categories**
104+
- Visit the contest public page
105+
- Switch to "Categories" view mode
106+
- Browse available categories
107+
- Click "Join" on categories you want to participate in
108+
- You can join multiple categories
109+
110+
2. **Viewing Category Rankings**
111+
- Select a category from the tabs
112+
- Rankings show only participants in that category
113+
- Rankings are re-calculated specifically for category members
114+
115+
### Database Schema
116+
117+
**contest_categories table:**
118+
- `id` - Primary key
119+
- `contest_id` - Foreign key to contests
120+
- `name` - Category name
121+
- `type` - Type: 'age', 'gender', or 'custom'
122+
- `criteria` - Additional criteria description
123+
- `timestamps`
124+
125+
**contest_category_user pivot table:**
126+
- `contest_category_id` - Foreign key to contest_categories
127+
- `user_id` - Foreign key to users
128+
- Unique constraint on (contest_category_id, user_id)
129+
130+
## 3. Route Selection per Contest Step
131+
132+
### Features
133+
- Each contest step can have specific routes assigned
134+
- Routes are optional - steps use all contest routes if none assigned
135+
- Easy route selection with hierarchical view (Area > Sector > Line > Routes)
136+
- Route count shown for each step
137+
138+
### Admin Usage
139+
140+
1. **Manage Contest Steps**
141+
- Navigate to Admin > Site > Contests
142+
- Click the steps icon (≡) for any contest
143+
- Create steps with name, order, and time period
144+
145+
2. **Assign Routes to a Step**
146+
- In the steps list, click "Manage Routes" for a step
147+
- A modal shows all contest routes organized by Area > Sector > Line
148+
- Check/uncheck routes to assign them to the step
149+
- Changes are saved automatically
150+
151+
3. **Route Assignment Behavior**
152+
- If a step has routes assigned, only those routes count for that step's ranking
153+
- If a step has no routes assigned, all contest routes are used
154+
- This allows flexibility for different contest formats
155+
156+
### User Experience
157+
158+
1. **Viewing Step Information**
159+
- Contest steps are shown as tabs on the contest page
160+
- Each step shows its name and status (Active/Upcoming/Past)
161+
- The route count displayed updates based on step-specific routes
162+
163+
2. **Rankings per Step**
164+
- Rankings are calculated only for routes assigned to that step
165+
- Time period is based on the step's start and end times
166+
- Overall ranking uses all contest routes and the full contest period
167+
168+
### Database Schema
169+
170+
**contest_step_route pivot table:**
171+
- `id` - Primary key
172+
- `contest_step_id` - Foreign key to contest_steps
173+
- `route_id` - Foreign key to routes
174+
- Unique constraint on (contest_step_id, route_id)
175+
- `timestamps`
176+
177+
## Combined Usage Examples
178+
179+
### Example 1: Youth Team Competition
180+
1. Create contest with team mode enabled
181+
2. Create age category "Youth Under 16"
182+
3. Create teams for different climbing gyms
183+
4. Students join teams and the youth category
184+
5. View rankings in:
185+
- Team mode: See which gym team is winning
186+
- Category mode: See youth rankings
187+
- Individual mode: See all participants
188+
189+
### Example 2: Multi-Stage Contest
190+
1. Create contest with multiple steps:
191+
- "Qualification" (first 50 routes)
192+
- "Semi-Finals" (25 harder routes)
193+
- "Finals" (10 hardest routes)
194+
2. Assign specific routes to each step
195+
3. Create categories: "Men", "Women", "Youth"
196+
4. Participants can:
197+
- See their qualification ranking
198+
- Advance to semi-finals based on qualification
199+
- View separate men/women/youth rankings
200+
201+
### Example 3: Age Group Competition
202+
1. Create contest without team mode
203+
2. Create categories:
204+
- "Under 14"
205+
- "14-17"
206+
- "18-29"
207+
- "30-44"
208+
- "45+"
209+
3. Users join their appropriate age category
210+
4. View separate rankings for each age group
211+
212+
## Technical Details
213+
214+
### Ranking Calculations
215+
216+
**Individual Rankings:**
217+
- Sum of points from unique routes climbed
218+
- Filtered by contest or step time period
219+
- Filtered by official/free mode
220+
- Sorted by total points descending
221+
222+
**Team Rankings:**
223+
- **Unique mode (default)**: Sum of points from unique routes climbed by any team member
224+
- If multiple team members climb the same route, points counted once
225+
- **All mode**: Sum of points from all routes climbed by all team members
226+
- Each team member's climb counted separately
227+
- Route climbed by N members = N × route points
228+
- Filtered by contest time period and mode
229+
- Sorted by total points descending
230+
231+
**Category Rankings:**
232+
- Individual rankings filtered to only include category members
233+
- Re-ranked within the category
234+
- Same point calculation as individual rankings
235+
- Same point calculation as individual rankings
236+
237+
### Step-Specific Routes
238+
The ranking logic checks if a step has routes assigned:
239+
```php
240+
$routeIds = $step->routes->count() > 0
241+
? $step->routes->pluck('id') // Use step routes
242+
: $this->contest->routes->pluck('id'); // Use all contest routes
243+
```
244+
245+
## API/Livewire Methods
246+
247+
### Contest Model
248+
- `getTeamRankingForStep($stepId = null)` - Get team rankings
249+
- `getCategoryRankings($categoryId, $stepId = null)` - Get category-specific rankings
250+
- `getRankingForStep($stepId = null)` - Enhanced to use step-specific routes
251+
252+
### Team Model
253+
- `getTotalPoints()` - Calculate team's total points based on contest's team_points_mode
254+
- Returns sum of unique routes (default) or all climbs (when team_points_mode = 'all')
255+
256+
### Public View Component
257+
- `setViewMode($mode)` - Switch between 'individual', 'team', 'category'
258+
- `joinTeam($teamId)` - Join a team
259+
- `leaveTeam($teamId)` - Leave a team
260+
- `joinCategory($categoryId)` - Join a category
261+
- `leaveCategory($categoryId)` - Leave a category
262+
263+
## Testing
264+
265+
Comprehensive test suite included in `tests/Feature/ContestEnhancementsTest.php`:
266+
- Team mode functionality
267+
- Team creation and user membership
268+
- Team ranking calculations (unique mode)
269+
- Team ranking calculations (all mode with duplicates)
270+
- Category creation and user membership
271+
- Category creation and user membership
272+
- Route assignment to steps
273+
- Team ranking calculations
274+
- Category ranking filtering
275+
276+
Run tests with:
277+
```bash
278+
php artisan test --filter ContestEnhancementsTest
279+
```
280+
281+
## Migration
282+
283+
All features are backward compatible. Existing contests will:
284+
- Have `team_mode` set to `false` by default
285+
- Have no teams or categories
286+
- Have steps with no specific routes (use all contest routes)
287+
288+
To enable new features on existing contests:
289+
1. Edit the contest and enable team mode if desired
290+
2. Create categories through the categories manager
291+
3. Assign routes to existing steps through the steps manager

0 commit comments

Comments
 (0)