Commit Graph

101 Commits

Author SHA1 Message Date
Radosław Gierwiało
fb4e0bea99 refactor(profile): remove Matches count from public profile stats
- Remove Matches stat display from public profile
- Keep only Rating and Reviews stats visible
- Remove unused Users icon import
2025-12-05 18:38:14 +01:00
Radosław Gierwiało
d4dd7bac30 feat(navbar): make username clickable link to public profile
- Desktop: username and avatar link to /u/{username}
- Mobile: username section in dropdown links to public profile
- Adds hover effect to indicate clickability
2025-12-05 18:36:51 +01:00
Radosław Gierwiało
1f763d4558 refactor(footer): remove Events link from Product section 2025-12-05 18:34:51 +01:00
Radosław Gierwiało
c4372930dd feat(content): add How It Works page with markdown support
- Create HowItWorksPage component with markdown rendering
- Add how-it-works.md with Lorem Ipsum placeholder content
- Add /how-it-works route in App.jsx
- Add How It Works link to homepage footer (Product section)
2025-12-05 18:33:25 +01:00
Radosław Gierwiało
2c5689ac8e feat(content): add About Us page with markdown content support
- Create AboutUsPage component with markdown rendering
- Add react-markdown library for content rendering
- Create public/content directory for editable markdown files
- Add about-us.md with Lorem Ipsum placeholder content
- Create public/images/about directory for page images
- Add /about-us route in App.jsx
- Add About Us link to homepage footer
- Support for external links (open in new tab) and internal links
- Responsive image rendering with rounded corners and shadow
2025-12-05 18:30:44 +01:00
Radosław Gierwiało
d8085f828f feat(security): add Cloudflare Turnstile CAPTCHA to registration form
- Add Turnstile widget rendering in RegisterPage on step 2
- Implement programmatic widget initialization with callbacks
- Add token validation before form submission
- Update AuthContext and API service to pass turnstileToken
- Add backend verification via Cloudflare API in register controller
- Include client IP in verification request
- Add validation rule for turnstileToken
- Reset widget on registration error
2025-12-05 18:20:26 +01:00
Radosław Gierwiało
f3b8156557 feat(security): implement Cloudflare Turnstile CAPTCHA on contact form
- Add Turnstile script to frontend/index.html
- Implement programmatic widget rendering in ContactPage
- Add backend verification via Cloudflare API
- Include client IP in verification request
- Update CSP headers to allow Cloudflare resources
- Add environment variable configuration for site and secret keys
- Pass VITE_TURNSTILE_SITE_KEY to frontend container
- Add validation and error handling for CAPTCHA tokens
2025-12-05 18:08:05 +01:00
Radosław Gierwiało
25042d0fec feat(home): adapt homepage for authenticated users
Changes for logged-in users:
- Top navigation: Show "Dashboard" and "Logout" buttons instead of "Sign In" and "Get Started"
- Hero CTA: Change main button to "Go to Dashboard" instead of "Start Collaborating"
- Hide bottom CTA section (registration prompt) for authenticated users
- Footer Account section: Show "Dashboard" and "Logout" instead of "Sign In" and "Register"

Other improvements:
- Removed "Explore Events" button from hero section
- Cleaned up footer: removed empty placeholder links (Features, How It Works, About, Privacy, Terms)
- Added "Support" section in footer with "Contact Us" link to /contact
- Simplified footer to 3 columns: Product (Events), Support (Contact Us), Account (dynamic based on auth)
2025-12-05 17:21:55 +01:00
Radosław Gierwiało
34f18b3b50 feat(contact): add contact form with admin panel and navbar dropdown
Database changes:
- Added ContactMessage model to Prisma schema
- Fields: userId, username, firstName, lastName, email, subject, message, status, ipAddress
- Status enum: new, read, resolved
- Relation to User model

Backend changes:
- Added POST /api/public/contact endpoint for form submissions
- Works for both authenticated and non-authenticated users
- Validation for email, subject (3-255 chars), message (10-5000 chars)
- Activity logging for submissions
- Added admin endpoints:
  - GET /api/admin/contact-messages - list with filtering by status
  - GET /api/admin/contact-messages/:id - view single message (auto-marks as read)
  - PATCH /api/admin/contact-messages/:id/status - update status
  - DELETE /api/admin/contact-messages/:id - delete message

Frontend changes:
- Created ContactPage at /contact route
- For non-logged-in users: firstName, lastName, email, subject, message fields
- For logged-in users: auto-fills username, shows only email, subject, message
- Character counter for message (max 5000)
- Success screen with auto-redirect to homepage
- Created ContactMessagesPage at /admin/contact-messages
- Two-column layout: message list + detail view
- Filter by status (all, new, read, resolved)
- View message details with sender info and IP address
- Update status and delete messages
- Added admin dropdown menu to Navbar
  - Desktop: dropdown with Activity Logs and Contact Messages
  - Mobile: expandable submenu
  - Click outside to close on desktop
  - ChevronDown icon rotates when open

Note: CAPTCHA integration planned for future enhancement
2025-12-05 17:15:25 +01:00
Radosław Gierwiało
f90945aa47 fix(profiles): make public profiles accessible without authentication and unify 404 behavior
Backend changes:
- Removed authentication requirement from GET /api/users/:username endpoint
- Removed authentication requirement from GET /api/users/:username/ratings endpoint
- These are public profile endpoints and should be accessible to all users

Frontend changes:
- PublicProfilePage now shows NotFoundPage component when user doesn't exist
- Unified 404 behavior: both invalid URLs and non-existent users show the same 404 page
- NotFoundPage "Requested URL" box now only shows in dev mode (import.meta.env.DEV)
- Removed unused AlertCircle icon import from PublicProfilePage
2025-12-05 16:54:38 +01:00
Radosław Gierwiało
948c694ed6 feat(system): implement 404 page with activity logging and change profile route format
Backend Changes:
- Added public API endpoint /api/public/log-404 (no auth required)
- Created backend/src/routes/public.js for public endpoints
- Added ACTIONS.SYSTEM_404 and CATEGORIES.system to activity log service
- Registered public routes in app.js

Frontend Changes:
- Created NotFoundPage.jsx with standalone layout (no auth required)
- Added publicAPI.log404() to log 404 access attempts
- Logs both authenticated and anonymous users
- Changed profile route from /@:username to /u/:username
- Made profile route public (removed ProtectedRoute wrapper)
- Updated all profile links from /@${username} to /u/${username} in:
  - ChatMessage.jsx
  - DashboardMatchCard.jsx
  - MatchRequestCards.jsx
  - MatchCard.jsx
  - UserListItem.jsx
  - MatchChatPage.jsx
  - PublicProfilePage.jsx

Fixes:
- React Router doesn't support @ in path segments
- 404 page now accessible to non-authenticated users without redirect
- Profile route no longer catches all unmatched routes
2025-12-03 20:27:51 +01:00
Radosław Gierwiało
eb5aacd797 refactor(admin): move event details page to admin section
- Moved EventDetailsPage from /events/:slug/details to /admin/events/:slug/details
- Added admin authentication check with redirect to login/home
- Updated all navigation links across the app:
  - EventsPage: "View details (admin)" button
  - EventChatPage: "View QR Code (admin)" link
  - EventCard: handleViewDetails navigation
- Fixed relative imports after moving to admin folder

This page contains admin-only features (QR codes, participants list,
matching config, scheduler config, matching runs) and should only be
accessible to administrators.
2025-12-03 19:52:00 +01:00
Radosław Gierwiało
179aaa8f16 fix(admin): activity logs empty success filter showing no results
- Fixed issue where empty string success filter was interpreted as false
- Backend was filtering for only failed logs when success='' was sent
- Added check to skip sending success parameter when empty string
- Activity logs page now shows all logs when filters are set to 'All'

Bug: When user selected 'All' for success filter, frontend sent success='',
backend parsed this as success=false, showing only failed logs (usually none).
2025-12-03 19:39:16 +01:00
Radosław Gierwiało
4a91a10aff feat(chat): add 2000 character limit for messages
Added message length validation to prevent spam and improve UX with
character counter feedback.

Backend:
- Added MESSAGE_MAX_LENGTH constant (2000 characters)
- Validation in send_event_message handler:
  - Check if content is string
  - Check if not empty after trim
  - Check if not exceeding max length
- Validation in send_match_message handler (same checks)
- Returns error message if validation fails

Frontend:
- Added MESSAGE_MAX_LENGTH constant (2000 characters)
- ChatInput component enhancements:
  - maxLength attribute on input (hard limit)
  - Character counter shows when >80% of limit
  - Counter turns red when at limit
  - Submit button disabled when at limit
  - Counter format: "X/2000"

UX:
- User sees counter at 1600+ characters (80% of limit)
- Hard limit prevents typing beyond 2000 chars
- Clear visual feedback (red text) when at limit
- Consistent validation on both event and match chats

Security:
- Prevents spam with extremely long messages
- Protects against potential DoS via message size
- Database already uses TEXT type (supports limit)
2025-12-02 23:46:54 +01:00
Radosław Gierwiało
dd3176196e fix(chat): real-time active users list updates
Fixed issue where active users list in event chat did not update in
real-time when new users joined. Users had to refresh the page to see
newly joined participants.

Root Cause:
- getAllDisplayUsers() used checkedInUsers (loaded once from API) as
  base list, with activeUsers (Socket.IO real-time) only for isOnline flag
- When new user joined chat, they appeared in activeUsers but not in
  checkedInUsers, so they were not displayed

Solution:
- Rewrote getAllDisplayUsers() to prioritize activeUsers (real-time data)
- Merges activeUsers (online) with checkedInUsers (offline checked-in users)
- Uses Socket.IO data as source of truth for online users
- Enriches with database data when available (firstName, lastName, etc)
- Sorts online users first, offline second

Changes:
- EventChatPage.jsx: Rewrote getAllDisplayUsers() to merge activeUsers
  with checkedInUsers, prioritizing real-time Socket.IO data
- useEventChat.js: Added debug logging for active_users events
- socket/index.js: Added debug logging for active_users emissions

Testing:
- User A in chat sees User B appear immediately when B joins
- No page refresh required
- Online/offline status updates in real-time
2025-12-02 23:38:46 +01:00
Radosław Gierwiało
1051cc6754 feat(admin): implement activity logs frontend page (Phase 6-7)
Complete implementation of admin activity logs dashboard with real-time
streaming capabilities. Admin users can now monitor all system activity
through a comprehensive web interface.

Features:
- Stats dashboard with 4 key metrics (total logs, unique users, failures, 24h activity)
- Category breakdown visualization with color-coded badges
- Advanced filtering (date range, category, action type, username, success/failure)
- Paginated log table (50 entries per page) with sort by timestamp
- Real-time streaming toggle using Socket.IO
- Color-coded action badges (blue=auth, green=event, purple=match, red=admin, yellow=chat)
- Admin-only access with automatic redirect for non-admin users
- Responsive design for mobile and desktop

Frontend Changes:
- Created ActivityLogsPage.jsx (600+ lines) with complete UI implementation
- Added 3 admin API methods to api.js (getActivityLogs, getActivityLogActions, getActivityLogStats)
- Added /admin/activity-logs route to App.jsx
- Added admin navigation link to Navbar (desktop & mobile) with Shield icon
- Only visible to users with isAdmin flag

Implementation Details:
- Uses getSocket() from socket service for real-time updates
- Joins 'admin_activity_logs' Socket.IO room on streaming enable
- Receives 'activity_log_entry' events and prepends to table (first page only)
- Comprehensive error handling and loading states
- Empty states for no data
- Clean disconnect handling when streaming disabled

Testing:
- Build successful (no errors)
- Ready for manual testing and verification

Phase 8 (Testing) remains for manual verification of all features.
2025-12-02 23:17:19 +01:00
Radosław Gierwiało
0466ef9e5c security(nginx): block access to sensitive files and directories
Added comprehensive security rules to all nginx configurations:

Dev proxy (nginx/conf.d/default.conf):
- Block dotfiles and .git directory
- Block .env* files and config files
- Block node_modules, docker configs, package files
- Block backup files (.bak, .swp, ~)

Prod proxy (nginx/conf.d.prod/default.conf):
- All dev security rules
- Added security headers (X-Frame-Options, CSP, etc.)
- Strict CSP with frame-ancestors 'none'

Frontend container (frontend/nginx.conf):
- Block dotfiles and sensitive config files
- Block node_modules and build configs
- Added security headers

All blocked paths return 404 and disable logging to avoid log spam.

Blocks: .env*, .git, node_modules, docker*, package*.json,
prisma, backup*, *.bak, *.swp, tsconfig.json, and more.
2025-12-02 19:55:08 +01:00
Radosław Gierwiało
f45cadae7d feat(matches): show both manual match requests and auto recording suggestions
Backend:
- Extend GET /api/matches to include RecordingSuggestions alongside Match objects
- Add 'type' field: 'manual' for user-created matches, 'auto' for algorithm suggestions
- Fetch suggestions where user is dancer (to be recorded) or recorder (recording others)
- Transform suggestions to match format with partner info
- Support status filtering for both types

Frontend:
- Display 'Auto' (purple) or 'Manual' (gray) badge on match cards
- For pending auto suggestions: show 'Go to Records' button instead of Accept/Reject
- For accepted auto suggestions without slug: show 'Chat not available yet'
- Only allow Accept/Reject actions on manual match requests
2025-11-30 15:30:49 +01:00
Radosław Gierwiało
d8799d03af feat(dashboard): add Recording Assignments section
- Extend dashboard API to include recordingSuggestions for each event
- Add toBeRecorded and toRecord arrays with heat and user details
- Export RecordingSummaryCard component
- Add Recording Assignments section to DashboardPage
- Filter and display events with recording suggestions
- Show up to 2 suggestions per event with View Details link
2025-11-30 15:14:06 +01:00
Radosław Gierwiało
6ce3111cdd feat(dashboard): improve RecordingSummaryCard styling and fix tab navigation
- Increase font size from xs to sm for better readability
- Reduce avatar size from xs to 24px for better proportions
- Add proper layout with heat names in separate line
- Add truncate for long usernames to prevent overflow
- Style status badges with colored backgrounds and icons (pending/accepted)
- Fix EventChatPage to read and handle ?tab=records URL parameter
- Map 'records' query param to 'recording' tab for proper navigation
2025-11-30 15:13:50 +01:00
Radosław Gierwiało
2e49fa5c62 feat(recordings): only recorder can accept/reject suggestions in MVP
Backend changes:
- Restrict suggestion status updates to recorder only
- Dancers can now only view who is assigned to record them
- Return 403 error if non-recorder tries to update status

Frontend changes:
- Remove Accept/Reject buttons from dancer view (TO_BE_RECORDED)
- Add "Pending" status badge with clock icon for pending suggestions
- Keep Accept/Reject buttons for recorder view (TO_RECORD)
- Dancers see only status badge and optional chat button

UX flow:
- Dancer sees: "Recording you: @username [Pending]"
- Recorder sees: "You record: @username [Accept] [Reject]"
- Only recorder's action creates the Match
2025-11-30 14:54:09 +01:00
Radosław Gierwiało
560ff1edc1 fix(scheduler): implement deadline-based matching with 5-run limit and fix security issues
Security fixes:
- Replace $queryRawUnsafe with parameterized $queryRaw in admin.js to prevent SQL injection
- Use PostgreSQL ANY() operator for safe array parameter handling

Scheduler improvements:
- Add registrationDeadline support - scheduler now waits until deadline before running
- Implement 5-run limit after deadline (runs exactly 5 times with 5-minute intervals)
- Add countScheduledRunsAfterDeadline() to track post-deadline runs
- Add environment variable validation with sensible min/max ranges
- Fix Prisma query syntax (remove invalid endDate null check for non-nullable field)

UI improvements:
- Fix colspan mismatch in MatchingRunsSection (6 → 8 columns)
- Remove duplicate "Uruchom Matching" button, keep only "Run now" with audit tracking
- Simplify MatchingConfigSection to focus on deadline configuration

Logging enhancements:
- Add detailed scheduler logs showing run progress (e.g., "Running post-deadline matching (3/5)")
- Log wait times before deadline and between runs
- Show completion status after 5 runs
2025-11-30 14:42:08 +01:00
Radosław Gierwiało
752d65035a fix(scheduler): use equals: null filter for endDate to satisfy Prisma where syntax and stop log spam 2025-11-30 13:50:48 +01:00
Radosław Gierwiało
621511fccf feat(matching-runs): add per-run aggregate stats and UI display
- Admin list endpoint returns totalSuggestions, assignedCount, aggregatedNotFoundCount per run
- UI: show Total/Matched/Not found columns using fresh aggregates
- Add anchor link Run #ID and wording 'Pairs created in this run'
2025-11-30 13:43:05 +01:00
Radosław Gierwiało
a9ad25eb38 feat(matching-runs): attach origin_run_id to new suggestions and expose pairs-per-run API
- Extend saveMatchingResults(eventId, suggestions, runId) and set originRunId
- Scheduler/Admin run-now: always pass runId
- Admin API: GET /api/admin/events/:slug/matching-runs/:runId/suggestions
- Prisma: add compound index on (origin_run_id, status)
- Frontend: add getRunSuggestions, expand row in MatchingRunsSection with 'Pairs created in this run' wording
2025-11-30 13:37:32 +01:00
Radosław Gierwiało
7e2a196f99 feat(frontend): add Run now button and matching runs list on event details page
- New adminAPI for run-now and runs listing
- MatchingRunsSection with refresh and run controls
- Integrate into EventDetailsPage under matching configuration
2025-11-30 13:20:33 +01:00
Radosław Gierwiało
8c753a7148 feat: add match data to suggestions and chat link for accepted recordings
Backend changes:
- Modified getUserSuggestions to include match data (id, slug, status)
- Returns match info for both toBeRecorded and toRecord suggestions

Frontend changes:
- Added useNavigate hook to RecordingTab
- Capture match data from updateSuggestionStatus response
- Added MessageCircle icon and chat button to SuggestionCard
- Show "Open Chat" button for accepted suggestions with active matches
- Navigate to /matches/{matchSlug}/chat when clicked

This completes the recording stats flow by allowing users to easily
access the match chat after accepting a recording suggestion.
2025-11-30 11:03:29 +01:00
Radosław Gierwiało
a9c46f552f feat: add @ prefix to profile URLs and make usernames clickable
- Updated all profile links to use /@username format
- Made usernames clickable in chat messages
- Added URL parameter sanitization to strip @ when fetching user data
- Ensures consistent profile URL format across the application
2025-11-29 20:57:17 +01:00
Radosław Gierwiało
4e9557bd29 feat(chat): add country flags and competitor numbers with normalized data architecture
Implemented display of country flags and competitor numbers in event chat messages:
- Country flags displayed as emoji (🇸🇪, 🇵🇱, etc.) with proper emoji font support
- Competitor numbers shown in #123 format next to usernames
- Normalized data architecture with user and participant caches on frontend
- User data (username, avatar, country) and participant data (competitorNumber) cached separately
- Messages store only core data (id, content, userId, createdAt)
- Prevents data inconsistency when users update profile information
- Fixed duplicate message keys React warning with deduplication logic
- Backend sends nested user/participant objects for cache population
- Auto-updates across all messages when user changes avatar or country

Backend changes:
- Socket.IO event_message and message_history include nested user/participant data
- API /events/:slug/messages endpoint restructured with same nested format
- Batch lookup of competitor numbers for efficiency

Frontend changes:
- useEventChat hook maintains userCache and participantCache
- ChatMessage component accepts separate user/participant props
- ChatMessageList performs cache lookups during render
- Emoji font family support for cross-platform flag rendering
2025-11-29 19:49:06 +01:00
Radosław Gierwiało
c575ef6dc1 feat(frontend): add page titles to navbar on mobile
- Save vertical space on mobile by showing page title in navbar
- Mobile: "spotlight.cam - {PageTitle}" instead of separate h1
- Desktop: unchanged - page titles remain as separate headings
- Saves ~60-80px vertical space on mobile devices

Pages updated:
- Dashboard, Events, Matches, History, Profile
2025-11-29 16:12:47 +01:00
Radosław Gierwiało
58044e1d02 fix(frontend): ensure consistent width across all matches tabs
- Add w-full to MatchCard for consistent card width
- Use Layout noPadding to avoid padding conflicts
- Add explicit padding and width control to main container
- Ensure All, Pending, and Active tabs have identical width
2025-11-29 15:56:12 +01:00
Radosław Gierwiało
420209c037 fix(frontend): add error message display on login page
- Show error alert when login fails instead of console-only logging
- Display user-friendly error message: "Invalid email or password"
- Clear error state before new login attempt
- Use existing Alert component for consistency with RegisterPage
2025-11-29 15:26:40 +01:00
Radosław Gierwiało
634cd97032 refactor(frontend): simplify event chat UI
- Replace "Edit heats" button with icon-only version
- Remove connection status indicator (show "Disconnected" warning only when offline)
- Remove event location from header
- Hide Participants tab on desktop (sidebar already visible)
- Remove "Participants" header from sidebar on desktop
2025-11-29 15:18:22 +01:00
Radosław Gierwiało
dfb5313f9a refactor(frontend): implement mobile-first layout for chat pages
- Add fullWidth prop to Layout component for chat pages
- Redesign EventChatPage and MatchChatPage with fixed layout:
  - Navbar sticky to top (no gaps)
  - Event/partner header directly below navbar
  - Chat content fills available space (flex-1)
  - Input area fixed to bottom
  - Full screen width on mobile (no margins)
- Translate RecordingTab UI strings to English
- Move Leave Event button to header
- Remove unnecessary margins and max-width constraints

This provides a better mobile experience with full-screen chat
interface similar to native messaging apps.
2025-11-29 15:04:41 +01:00
Radosław Gierwiało
408317b974 refactor(frontend): add CONNECTION_STATE and SUGGESTION_TYPE constants
- Add CONNECTION_STATE (disconnected, connecting, connected, failed)
- Add SUGGESTION_TYPE (toBeRecorded, toRecord)
- Update useWebRTC.js to use CONNECTION_STATE
- Update MatchChatPage.jsx to use CONNECTION_STATE
- Update RecordingTab.jsx to use SUGGESTION_TYPE
2025-11-23 22:28:54 +01:00
Radosław Gierwiało
b3a6d39d7a refactor(frontend): replace status string literals with constants
- Create constants/statuses.js with MATCH_STATUS, SUGGESTION_STATUS, MATCH_FILTER
- Update MatchCard, MatchesPage, HistoryPage, RatePartnerPage to use MATCH_STATUS
- Update RecordingTab to use SUGGESTION_STATUS
- Update Navbar to use MATCH_STATUS for API calls
2025-11-23 22:21:12 +01:00
Radosław Gierwiało
93ff331bfb refactor(frontend): extract ProfileForm and PasswordChangeForm from ProfilePage
- Create components/profile/ProfileForm.jsx (192 lines)
- Create components/profile/PasswordChangeForm.jsx (99 lines)
- Create components/profile/index.js barrel export
- Reduce ProfilePage.jsx from 394 → 84 lines (-79%)
2025-11-23 22:13:56 +01:00
Radosław Gierwiało
185c485ec7 refactor(frontend): extract MatchCard component from MatchesPage
- Create components/matches/MatchCard.jsx (119 lines)
- Create components/matches/index.js barrel export
- Reduce MatchesPage.jsx from 349 → 240 lines (-31%)
2025-11-23 22:11:43 +01:00
Radosław Gierwiało
8e17c10353 refactor(frontend): extract DashboardPage into components
Split DashboardPage (578 lines) into focused components:
- DashboardEventCard: event card with chat access
- DashboardMatchCard: match card with status indicators
- MatchRequestCards: incoming/outgoing request cards
- EmptyState: reusable empty state component (in common/)

DashboardPage now 295 lines (-49%)
2025-11-23 22:08:16 +01:00
Radosław Gierwiało
bddcf5f4f9 refactor(frontend): extract EventDetailsPage into components
Split large EventDetailsPage (545 lines) into smaller, focused components:
- QRCodeSection: QR code display and copy link functionality
- ParticipantsSection: participants list with avatars
- MatchingConfigSection: deadline and matching controls
- ScheduleConfigSection: division slot configuration

EventDetailsPage now 148 lines (-73%)
2025-11-23 22:02:09 +01:00
Radosław Gierwiało
4467c570b0 feat(matching): add schedule config for division collision groups
Allow event organizers to configure which divisions run in parallel
(same time slot) for accurate collision detection in the auto-matching
algorithm. Divisions in the same slot will collide with each other.

- Add scheduleConfig JSON field to Event model
- Add PUT /events/:slug/schedule-config API endpoint
- Update matching algorithm to use slot-based collision detection
- Add UI in EventDetailsPage for managing division slots
- Add unit tests for schedule-based collision detection
2025-11-23 19:05:25 +01:00
Radosław Gierwiało
a5a1296a4e feat(frontend): add recording matching UI
Add frontend components for auto-matching recording partners:

- RecordingTab component with suggestions list and opt-out toggle
- Tab navigation in EventChatPage (Chat, Uczestnicy, Nagrywanie)
- Matching configuration in EventDetailsPage (deadline, run matching)
- matchingAPI functions in api.js
- Return registrationDeadline and matchingRunAt in GET /events/:slug/details

UI allows users to:
- View who will record their heats
- View heats they need to record
- Accept/reject suggestions
- Opt-out from being a recorder
- Set registration deadline (admin)
- Manually trigger matching (admin)
2025-11-23 18:50:35 +01:00
Radosław Gierwiało
edf68f2489 feat(events): add competitor number (bib) support
Allow participants to set their bib/competitor number per event.
Display as badge next to username in participant lists.

- Add competitorNumber field to EventParticipant model
- Add PUT /events/:slug/competitor-number endpoint
- Include competitorNumber in heats/me and heats/all responses
- Add input field in HeatsBanner component
- Display badge in UserListItem component
- Add unit tests for competitor number feature
2025-11-23 17:55:25 +01:00
Radosław Gierwiało
8a369c1fc4 fix(socket): improve connection stability with heartbeat and auto-reconnect
- Backend: Add pingInterval (25s) and pingTimeout (60s) for better keep-alive
- Frontend: Increase reconnection attempts to Infinity (keep trying forever)
- Frontend: Add reconnect event handlers to rejoin rooms after reconnection
- Frontend: Check initial connection state when reusing socket instance
2025-11-21 21:53:51 +01:00
Radosław Gierwiało
78280ca8d8 feat(dashboard): add unread count for match chats
Track unread messages in match chats and display count badge:
- Schema: Add user1LastReadAt/user2LastReadAt to Match model
- Backend: Calculate unreadCount in dashboard API
- Socket: Update lastReadAt when user joins match room
- Frontend: Display red badge with unread count on match avatar
2025-11-21 21:46:00 +01:00
Radosław Gierwiało
2c0620db6a feat(dashboard): add online count for events
Show real-time count of users currently in each event chat room.
- Backend: Export getEventsOnlineCounts from socket module
- Dashboard API: Include onlineCount for each active event
- Frontend: Display online count with animated green dot indicator
2025-11-21 21:41:16 +01:00
Radosław Gierwiało
c15031db9f feat(frontend): add skeleton loading state for dashboard
Replace simple spinner with skeleton loading placeholders that match
the dashboard layout structure, providing better visual feedback during
data loading.
2025-11-21 21:37:05 +01:00
Radosław Gierwiało
87b0079b84 feat(frontend): add toast notifications for dashboard actions
- Install react-hot-toast library
- Add Toaster component to App.jsx
- Show success/error toasts for match accept/reject/cancel
- Show toasts for real-time match events
- Update tests with toast mocks
2025-11-21 21:27:03 +01:00
Radosław Gierwiało
4187157b94 feat(frontend): add Rate Partner button and dashboard tests
- Add Rate button to MatchCard (shows when video exchange complete & not rated)
- Add 15 comprehensive tests for DashboardPage component
- Tests cover: loading, empty states, events, matches, requests, navigation
2025-11-21 21:21:58 +01:00
Radosław Gierwiało
f3bd169dbf feat(frontend): implement dashboard page
- Create DashboardPage with active events, matches, and requests
- Add dashboardAPI.getData() to services/api.js
- Add /dashboard route as default landing after login
- Update Navbar with Dashboard and Events links
- Show video exchange and rating status for matches
- Handle match accept/reject/cancel actions
2025-11-21 21:12:25 +01:00