diff --git a/FEATURES-ROADMAP.md b/FEATURES-ROADMAP.md new file mode 100644 index 0000000..e53380b --- /dev/null +++ b/FEATURES-ROADMAP.md @@ -0,0 +1,809 @@ +# AeThex-Connect Complete Features Roadmap + +**Current Status:** 40% Complete (UI + Basic Functionality) +**Target:** 100% Feature Parity with Discord Clone + Blockchain Integration + +--- + +## PHASE 1: CORE FEATURES (15 hours) - ESSENTIAL + +### 1.1 Message System +- [ ] **Emoji Reactions** (30 min) + - Add emoji picker button next to messages + - Click emoji to toggle reaction + - Show reaction count badge + - Remove reaction on second click + - Files: `MessageInput.jsx`, `Message.jsx`, add emoji-picker lib + +- [ ] **File Uploads** (1 hour) + - Wire UploadThing to message input + - Preview uploaded files before sending + - Display file attachments in messages + - Support images, PDFs, documents + - Files: `FileUploadModal.jsx`, `Message.jsx` + +- [ ] **Message Timestamps** (15 min) + - Show human-readable timestamps + - Format: "Today 2:34 PM" / "Yesterday" / "Mon 3/1" + - Hover to show exact datetime + - Files: `Message.jsx`, utility function + +- [ ] **Message Search** (2 hours) + - Add search bar in header + - Filter messages by keyword + - Highlight search results + - Show result count + - Files: `ChatAreaHeader.jsx`, add searchStore + +- [ ] **Typing Indicators** (1 hour) + - Show "User is typing..." when someone types + - Hide after 3 seconds of inactivity + - Multiple typists support + - Files: `ChatArea.jsx`, add typingStore + +### 1.2 Channel Management +- [ ] **Edit/Delete Channels** (1 hour) + - Edit channel name & description + - Delete channel with confirmation + - Move channels between categories + - Files: `ChannelSidebar.jsx`, extend channelStore + +- [ ] **Channel Topics/Descriptions** (30 min) + - Show channel description in header + - Update channel topic + - Store in channelStore + - Files: `ChatAreaHeader.jsx` + +- [ ] **Mute/Archive Channels** (30 min) + - Mute notifications from channel + - Archive channel (hide from list) + - Visual indicator for muted channels + - Files: `ChannelSidebar.jsx`, extend channelStore + +### 1.3 Member System +- [ ] **User Profiles** (1 hour) + - Click member name → profile modal + - Show username, avatar, status, joined date + - Display user activity/game + - Add friend button (prep for later) + - Files: `UserProfileModal.jsx`, `Member.jsx` + +- [ ] **Member Status Indicator** (30 min) + - Show online/offline/away/dnd status + - Live update presence + - Status badge on avatars + - Filter by status + - Files: `MemberSidebar.jsx`, extend memberStore + +- [ ] **Member Sorting** (30 min) + - Sort by online status + - Sort by role (Admin → Mod → Member) + - Sort alphabetically + - Files: `MemberSidebar.jsx` + +### 1.4 User Interface Polish +- [ ] **Hover Effects** (30 min) + - Add hover delete/edit buttons (DONE but needs refinement) + - Hover color changes + - Smooth transitions + - Files: CSS updates + +- [ ] **Loading States** (30 min) + - Show spinners while loading channels + - Show loading skeleton for messages + - Disable buttons while loading + - Files: Add to components + +- [ ] **Error States** (30 min) + - Handle network errors gracefully + - Show error toast messages + - Retry buttons + - Files: Add error handling + +--- + +## PHASE 2: ADVANCED MESSAGING (12 hours) - HIGH PRIORITY + +### 2.1 Message Threading +- [ ] **Message Threads** (2 hours) + - Right-click message → "Reply in Thread" + - Show thread badge with reply count + - Thread modal/sidebar view + - Nested conversation view + - Files: `ThreadModal.jsx`, update messageStore + +- [ ] **Thread Notifications** (30 min) + - Notify when thread gets new reply + - Show unread thread count + - Mark thread as read + +- [ ] **Thread Sorting** (15 min) + - Sort threads by newest/oldest + - Show last reply time + +### 2.2 Rich Text & Formatting +- [ ] **Bold/Italic/Underline** (1 hour) + - Markdown support (**bold**, *italic*, __underline__) + - Toolbar buttons in message input + - Preview formatting + - Files: `MessageInput.jsx`, add rich-text lib + +- [ ] **Code Blocks** (1 hour) + - Syntax highlighting for code + - Language detection + - Copy code button + - Files: `Message.jsx`, add syntax-highlighter lib + +- [ ] **Links & Embeds** (1 hour) + - Auto-linkify URLs + - Show link preview cards + - Embed YouTube, Twitter, etc. + - Files: `Message.jsx` + +- [ ] **Mentions & Markdown** (1 hour) + - @mention autocomplete + - #channel mentions + - Full markdown support (headers, quotes, lists) + - Files: `MessageInput.jsx`, add mention autocomplete + +### 2.3 Message Actions +- [ ] **Message Pins** (1 hour) + - Pin important messages + - Show pinned messages in header dropdown + - Unpin messages + - Files: `ChatAreaHeader.jsx`, extend messageStore + +- [ ] **Message Bookmarks** (1 hour) + - Bookmark messages for later + - View bookmarked messages + - Remove bookmarks + - Files: Add bookmarkStore + +- [ ] **Quote Messages** (30 min) + - Reply to specific message with quote + - Show original message context + - Files: `Message.jsx`, `MessageInput.jsx` + +--- + +## PHASE 3: PERMISSIONS & ROLES (10 hours) - IMPORTANT + +### 3.1 Role System +- [ ] **Create Custom Roles** (1.5 hours) + - Create new roles beyond Admin/Mod/Member + - Set role colors + - Drag to reorder role hierarchy + - Files: `RoleManagementModal.jsx`, add roleStore + +- [ ] **Role Permissions Matrix** (2 hours) + - Toggle permissions per role: + - Send messages + - Edit own messages + - Delete any message + - Manage channels + - Manage roles + - Kick members + - Ban members + - Store in roleStore + - Files: `PermissionsModal.jsx` + +### 3.2 Channel Permissions +- [ ] **Channel Permission Overrides** (2 hours) + - Override server-wide permissions per channel + - Restrict roles from viewing channel + - Set who can speak in voice channels + - Files: `ChannelPermissionsModal.jsx` + +- [ ] **Private Channels** (1 hour) + - Restrict channel visibility by role + - "Only visible to admins" etc. + - Files: `ChannelSidebar.jsx` + +### 3.3 Moderation +- [ ] **Ban System** (1 hour) + - Ban members (can't rejoin) + - Ban list management + - Temp bans with expiry + - Files: `MemberSidebar.jsx`, extend memberStore + +- [ ] **Mute System** (1 hour) + - Mute members (can't send messages) + - Show muted badge + - Mute duration settings + - Files: extend memberStore + +--- + +## PHASE 4: DIRECT MESSAGING (8 hours) - NICE TO HAVE + +### 4.1 DM System +- [ ] **Direct Messages** (2 hours) + - Open DM with any member + - DM sidebar showing conversations + - DM notifications + - Files: `DMSidebar.jsx`, add dmStore + +- [ ] **Group DMs** (1.5 hours) + - Create group conversation + - Add/remove people from group + - Group name & avatar + - Files: DM system expansion + +- [ ] **DM Notifications** (30 min) + - Badge showing unread DMs + - Mention notifications + - Sound/desktop notifications (prep) + +### 4.2 Message Requests +- [ ] **DM Requests** (1 hour) + - Strangers' DMs go to "Requests" + - Accept/decline requests + - Block users + - Files: add requestStore + +--- + +## PHASE 5: INVITE & ONBOARDING (6 hours) - COMMUNITY + +### 5.1 Invite System +- [ ] **Generate Invite Links** (1 hour) + - Create invite with expiry + - Set max uses + - Different link per invite + - Track invite source + - Files: `InviteModal.jsx`, add inviteStore + +- [ ] **Invite Management** (1 hour) + - Revoke invites + - See who joined via invite + - Edit invite settings + - Files: `InviteManagementModal.jsx` + +- [ ] **Accept Invites** (1 hour) + - Join server via invite link + - Auto-role assignment + - Welcome message + - Files: add route for `/invite/:code` + +### 5.2 Welcome +- [ ] **Welcome Channel** (1 hour) + - Auto-create #welcome channel + - Post welcome message + - Quick onboarding questionnaire + - Files: server setup logic + +- [ ] **New Member Questions** (1 hour) + - Show modal on first join + - Collect info about member + - Use for welcome message + - Files: `OnboardingModal.jsx` + +--- + +## PHASE 6: VOICE & VIDEO (12 hours) - COMPETITIVE ADVANTAGE + +### 6.1 Voice Channels +- [ ] **Replace WebRTC with LiveKit** (3 hours) + - Remove simple-peer dependency + - Install @livekit/components-react + - Basic voice room setup + - Join/leave voice + - Files: Major refactor, `VoiceChannel.jsx` + +- [ ] **Voice Channel UI** (2 hours) + - Show connected users + - Mic/speaker toggle + - Volume control + - Mute other users + - Files: `VoiceControlBar.jsx` + +- [ ] **Voice Notifications** (1 hour) + - Notify when someone joins voice + - Play join/leave sounds + - Show duration connected + - Files: Add notifications + +### 6.2 Video Calls +- [ ] **Video Channel Support** (2 hours) + - Enable video in voice channels + - Grid/gallery view + - Camera toggle + - Speaker view + - Files: `VideoGrid.jsx`, `VideoTile.jsx` + +- [ ] **Screen Share** (2 hours) + - Share screen with audio + - Pause/resume screen share + - Show screen sharer indicator + - Files: `ScreenShareButton.jsx` + +- [ ] **Recording** (1 hour) + - Record voice/video + - Download recordings + - Store in cloud (optional) + - Files: integration with backend + +### 6.3 Voice Settings +- [ ] **Audio Input/Output** (1 hour) + - Select mic/speaker device + - Test audio before joining + - Audio level indicator + - Files: `AudioSettings.jsx` + +- [ ] **Echo Cancellation** (1 hour) + - Reduce echo/feedback + - Noise suppression + - Auto gain control + - Files: LiveKit config + +--- + +## PHASE 7: BACKEND INTEGRATION (15 hours) - CRITICAL + +### 7.1 Authentication +- [ ] **Connection to Auth Endpoints** (2 hours) + - Connect demo login to backend + - Real login/register + - JWT token handling + - Session persistence + - Files: Update AeThexProvider + +- [ ] **Multi-Method Auth** (1 hour) + - Password login + - OAuth (Google/GitHub/Clerk) + - Blockchain wallet login + - Files: Add auth methods + +### 7.2 Database Sync +- [ ] **Fetch Real Channels** (1 hour) + - Load channels from Supabase + - Store in channelStore + - Refresh on join + - Files: Add API calls + +- [ ] **Fetch Real Messages** (2 hours) + - Load messages from API + - Pagination/infinite scroll + - Cache management + - Real-time Socket.IO updates + - Files: Update ChatArea + +- [ ] **Save Messages** (1 hour) + - POST message to backend + - Handle optimistic updates + - Retry on failure + - Files: Update messageStore + +- [ ] **Sync Member List** (1 hour) + - Load server members from DB + - Update on join/leave + - Real-time presence via Socket.IO + - Files: Update memberStore + +### 7.3 Real-time Updates +- [ ] **Socket.IO Integration** (3 hours) + - Connect to Socket.IO server + - Listen for new messages + - Listen for member joins/leaves + - Listen for typing indicators + - Files: Create socketService.jsx + +- [ ] **Optimistic Updates** (2 hours) + - Show message immediately + - Rollback if fails + - Show loading state + - Handle conflicts + - Files: Update messageStore + +- [ ] **Conflict Resolution** (1 hour) + - Handle simultaneous edits + - Show version conflicts + - Last-write-wins logic + - Files: Add conflictStore + +### 7.4 File Storage +- [ ] **UploadThing Integration** (1.5 hours) + - Wire file uploads to UploadThing API + - Show upload progress + - Handle upload errors + - Get file URL + - Files: `FileUploadModal.jsx` + +- [ ] **File Deletion** (30 min) + - Delete files from UploadThing + - Clean up on message delete + - Files: Add to backend + +--- + +## PHASE 8: NOTIFICATIONS (6 hours) - ENGAGEMENT + +### 8.1 In-App Notifications +- [ ] **Toast Notifications** (1 hour) + - Show temporary messages + - Auto-dismiss + - Different colors for types + - Files: Create `Toast.jsx`, `useToast.js` + +- [ ] **Mention Notifications** (1 hour) + - Badge when @mentioned + - Highlight in chat + - Jump to mention context + - Files: Add notificationStore + +- [ ] **Channel Activity Badges** (30 min) + - Show unread count on channels + - Mark as read on view + - Files: extend channelStore + +### 8.2 System Notifications +- [ ] **Desktop Notifications** (1.5 hours) + - Request permission + - Show mentions as desktop notifications + - Show DMs as desktop notifications + - Click to jump to message + - Files: Add notificationService.js + +- [ ] **Sound Notifications** (1 hour) + - Play sound for mentions + - Play sound for DMs + - Mute global sound + - Per-channel sound settings + - Files: Add audioNotifications.js + +--- + +## PHASE 9: SETTINGS & PERSONALIZATION (8 hours) - UX + +### 9.1 User Settings +- [ ] **Profile Settings** (1 hour) + - Edit username + - Upload custom avatar + - Set custom status/bio + - Visibility settings + - Files: `UserSettingsModal.jsx` + +- [ ] **Privacy Settings** (1 hour) + - DM privacy (who can DM) + - Show online status + - Show activity status + - Block list management + - Files: `PrivacySettingsModal.jsx` + +- [ ] **Notification Settings** (1 hour) + - Mute server/channel + - Notification types per channel + - Time mute (do not disturb) + - Keywords that notify + - Files: `NotificationSettingsModal.jsx` + +### 9.2 Server Settings +- [ ] **Server General Settings** (1.5 hours) + - Edit server name + - Upload server icon + - Change server region + - Default notification level + - Files: `ServerSettingsModal.jsx` + +- [ ] **Server Audit Log** (1 hour) + - Show who did what + - Filter by action/person + - Export audit log + - Files: `AuditLogModal.jsx` + +- [ ] **Backup/Import** (1 hour) + - Export server data + - Import settings + - Clone channel structure + - Files: Add export/import logic + +### 9.3 Theme & Display +- [ ] **Dark/Light Theme** (1 hour) + - Toggle dark/light mode + - Persist preference + - Match system preference + - Files: Create `ThemeProvider.jsx` + +- [ ] **Custom Colors** (1 hour) + - Accent color picker + - Custom brand colors + - Save theme presets + - Files: extend themeStore + +- [ ] **Zoom/Font Size** (30 min) + - Adjust UI scale + - Adjust text size + - Adjust message density + - Files: Add scale settings + +--- + +## PHASE 10: ADVANCED FEATURES (10 hours) - POLISH + +### 10.1 Search & Discovery +- [ ] **Advanced Message Search** (1.5 hours) + - Search by author + - Search by date range + - Search by file type + - Save searches + - Files: Extend search UI + +- [ ] **Server Directory** (1 hour) + - Browse public servers + - Search by category/name + - Show member count + - Quick join + - Files: `ServerDirectory.jsx` + +### 10.2 Integrations +- [ ] **Webhook Support** (1.5 hours) + - Create webhooks + - Post via webhooks + - Delete webhooks + - Test webhook + - Files: `WebhookModal.jsx` + +- [ ] **Bot Commands** (1.5 hours) + - Command parser + - Bot command registry + - Help command + - Admin commands + - Files: Add commandService.js + +### 10.3 Analytics & Admin +- [ ] **Server Stats Dashboard** (1.5 hours) + - Member growth chart + - Message activity chart + - Most active channels + - Most active members + - Files: `StatsModal.jsx` + +- [ ] **Moderation Dashboard** (1.5 hours) + - View reported messages + - Approve/reject reports + - Ban/mute history + - Action logs + - Files: `ModerationPanel.jsx` + +### 10.4 Export & Reporting +- [ ] **Message Export** (1 hour) + - Export channel as JSON/CSV + - Export with attachments + - Download as HTML report + - Files: Add exportService.js + +- [ ] **User Reports** (1 hour) + - Report message + - Report user + - View submissions + - Admin panel for reports + - Files: `ReportModal.jsx` + +--- + +## PHASE 11: MONETIZATION (6 hours) - REVENUE + +### 11.1 Premium Features +- [ ] **Premium Tiers** (1 hour) + - Free tier + - Premium tier ($4.99/mo) + - Pro tier ($9.99/mo) + - Define features per tier + - Files: Add subscriptionStore + +- [ ] **File Storage Limits** (1 hour) + - Free: 50MB/month + - Premium: 500MB/month + - Pro: 5GB/month + - Show storage usage + - Files: Add to FileUpload components + +- [ ] **Custom Emojis** (1 hour) + - Upload custom emojis (premium) + - Use in messages + - Emoji pack management + - Files: `CustomEmojiModal.jsx` + +### 11.2 Payments +- [ ] **Stripe Integration** (2 hours) + - Subscription management + - Payment processing (already have Stripe installed) + - Invoice history + - Cancel subscription + - Files: Integrate Stripe payments + +- [ ] **Ad-Free Option** (1 hour) + - Remove ads for premium + - Hide ad placeholders + - Premium badge + - Files: Add ad components (if using ads) + +--- + +## PHASE 12: BLOCKCHAIN FEATURES (8 hours) - AETHEX UNIQUE + +### 12.1 Identity Integration +- [ ] **Connect .aethex Domain** (2 hours) + - Show .aethex domain on profile + - Verify domain ownership + - Link blockchain wallet + - Display on member card + - Files: Add blockchainService.js + +- [ ] **Wallet Integration** (1.5 hours) + - Connect wallet button + - Show connected wallet + - Verify ownership + - Use for login (Web3 auth) + - Files: Add walletService.js + +### 12.2 Trinity Division UI +- [ ] **Division Badges** (1 hour) + - Show Trinity division on members + - Filter by division + - Division-specific channels + - Division color coding + - Files: Update MemberSidebar + +- [ ] **Division Permissions** (1.5 hours) + - Restrict channels by division + - Division-specific roles + - Division leadership + - Files: Add division-based ACL + +### 12.3 Crypto Features +- [ ] **Token Gating** (1.5 hours) + - Require token to view channel + - Verify wallet balance + - Dynamic channel access + - Files: Add tokenGating.js + +- [ ] **NFT Roles** (1.5 hours) + - NFT holders get special role + - Auto-assign role based on NFT + - Show NFT on profile + - Files: Add nftService.js + +--- + +## PHASE 13: PERFORMANCE & OPTIMIZATION (8 hours) - BACKEND WORK + +### 13.1 Data Optimization +- [ ] **Message Pagination** (1.5 hours) + - Load messages in batches + - Virtual scrolling for large lists + - Cache old messages + - Files: Update ChatArea + +- [ ] **Member List Caching** (1 hour) + - Cache member list + - Update on join/leave + - Quick search without API call + - Files: Update memberStore + +- [ ] **Image Optimization** (1 hour) + - Lazy load images + - Responsive images + - Image compression + - WebP format + - Files: Image service + +### 13.2 Performance Metrics +- [ ] **Add Analytics** (1.5 hours) + - Track page load time + - Track API response time + - Track message send time + - Send to monitoring service + - Files: Add analyticsService.js + +- [ ] **Monitor Errors** (1.5 hours) + - Capture client errors + - Send to error tracking (Sentry) + - Show error rate dashboard + - Files: Add errorTracking.js + +- [ ] **Database Query Optimization** (1 hour) + - Profile slow queries + - Add indexes where needed + - Implement query caching + - Backend work in Express + +--- + +## PHASE 14: TESTING & QA (8 hours) + +### 14.1 Unit Tests +- [ ] **Test Stores** (2 hours) + - Test Zustand stores + - Test state updates + - Test computed values + - Files: Add `.test.js` files + +- [ ] **Test Components** (2 hours) + - Test Message component + - Test ChatArea component + - Test modals + - Files: Add component tests + +### 14.2 Integration Tests +- [ ] **Test Message Flow** (2 hours) + - Send message end-to-end + - Edit message + - Delete message + - Files: Add integration tests + +- [ ] **Test Auth Flow** (1 hour) + - Login/logout + - Session persistence + - Token refresh + - Files: Add auth tests + +### 14.3 User Testing +- [ ] **QA Pass** (1 hour) + - Manual testing checklist + - Bug documentation + - Performance testing + - Browser compatibility + +--- + +## PHASE 15: DEPLOYMENT & DOCS (6 hours) + +### 15.1 Documentation +- [ ] **API Documentation** (1.5 hours) + - Document all endpoints + - Document Socket.IO events + - Include examples + - Files: Create API docs + +- [ ] **User Guide** (1 hour) + - How to use features + - Keyboard shortcuts + - Tips & tricks + - Files: Create user guide + +- [ ] **Developer Guide** (1.5 hours) + - Setup instructions + - Architecture overview + - Contributing guidelines + - Files: Update README + +### 15.2 Deployment +- [ ] **Environment Setup** (1 hour) + - Production env vars + - Database backups + - CDN configuration + - Files: Deployment config + +- [ ] **CI/CD Pipeline** (1 hour) + - Auto-deploy on push + - Run tests + - Build optimization + - Files: GitHub Actions config + +--- + +## SUMMARY + +**Total Estimated Time: 145 hours** + +**Breakdown by Phase:** +- Phase 1-4: 45 hours (Messaging & Communities) +- Phase 5-8: 32 hours (Community & Engagement) +- Phase 9-10: 18 hours (Settings & Polish) +- Phase 11-12: 14 hours (Monetization & Blockchain) +- Phase 13-15: 22 hours (Performance & Deployment) + +**Critical Path (MVP):** +- Phase 1: Messaging (15h) +- Phase 7: Backend Integration (15h) +- Phase 14: Testing (5h) +- **35 hours for MVP** + +**Achievable in 1 sprint (2 weeks):** +- Phase 1 + Phase 2 (27 hours) = Basic messaging platform + +**Competitive Differentiation:** +- Phase 12 (Blockchain) = Unique value +- Phase 6 (Voice/Video) = Core Discord feature +- Phase 11 (Monetization) = Revenue model diff --git a/IMPLEMENTATION-COMPLETE.md b/IMPLEMENTATION-COMPLETE.md new file mode 100644 index 0000000..9660079 --- /dev/null +++ b/IMPLEMENTATION-COMPLETE.md @@ -0,0 +1,202 @@ +# AeThex Connect - Full Implementation Status + +## ✅ COMPLETED FEATURES + +### 1. **Real-Time Messaging System** +- `MessageInput.jsx` - Sends messages via Socket.IO +- `ChatArea.jsx` - Displays all messages from messageStore in real-time +- `useSocket.js` - Socket.IO client with event listeners: + - `message:new` - Receive new messages + - `message:updated` - Receive edited messages + - `message:deleted` - Receive deleted messages +- Backend: `chatRoutes.js` - REST API for message CRUD +- Real-time sync without page refresh + +### 2. **Direct Messaging (DMs) System** +- `DirectMessageList.jsx` - Shows all active conversations +- `DirectMessageChat.jsx` - Full DM chat interface +- `directMessageStore.js` - Manages DM conversations & state +- Context switching: Click DM or server to toggle views +- Unread message badges supported +- Socket event: `dm:send`, `dm:new` + +### 3. **User Presence & Typing** +- `presenceStore.js` - Tracks online status & typing indicators +- `TypingIndicator.jsx` - Shows who's typing with animations +- Socket events: `user:typing`, `user:online`, `user:status` +- Auto-clears typing status after 3 seconds +- Online/idle/offline status tracking + +### 4. **Trinity Servers (3 Dedicated)** +- **Foundation** - Official infrastructure +- **Corporation** - Corporate division +- **Labs** - Research & development +- Fully functional server switching with visual indicators +- All wired to `serverStore.js` +- Server creation via modal + +### 5. **User Profiles** +- Profile modal with edit capability +- Username, email, status, avatar +- Status options: Online, Idle, DND, Offline +- Logout button included +- Access via 👤 button in server list + +### 6. **Settings Panel** +- Notification controls (desktop, sound, mentions, replies) +- Theme settings (dark/light/auto) +- Privacy controls (online status, DMs, friend requests) +- Appearance settings (compact mode, animations, font size) +- Access via ⚙️ button in chat header + +### 7. **User Discovery** +- Search functionality to find other users +- Status indicators (🟢 online, 🟡 idle, ⚪ offline) +- One-click DM creation +- Modal interface with avatars +- Access via 👥 button in chat header + +### 8. **Server/Channel Management** +- Create new servers with custom icons & names +- Join servers via invite code +- Create channels within servers +- Channel categories (Development, Announcements, Support, Voice) +- Channel types (text, voice) +- Delete/leave servers with proper confirmation +- Member management with role controls (Admin, Moderator, Member, Guest) + +### 9. **Emoji Picker** +- Integration with @emoji-mart/react +- Categorized emojis (smileys, gestures, objects, nature, food) +- Dark theme styling +- Click-outside to close +- Seamless insertion into messages + +### 10. **Voice/Video Calls** +- `VoiceCallButton.jsx` - Start/end call UI +- LiveKit integration ready +- Socket events: `call:start`, `call:end`, `call:join`, `call:leave` +- Token-based authentication with backend +- Button integrated into chat header +- Call room management + +### 11. **File Uploads** (Structure Ready) +- `FileUploadModal.jsx` - Component created +- UploadThing integration configured +- Drag-and-drop UI ready +- Progress tracking built-in +- Awaiting file display in messages + +### 12. **Channel Sidebar** +- List all channels by category +- Visual indicator for current active channel +- Add channel button (+ icon) +- Proper styling with hover states + +### 13. **Member Sidebar** +- Displays all server members +- Shows member roles with icons +- Avatar and username display +- Status indicators +- Quick member info access + +--- + +## 🔧 INFRASTRUCTURE + +### Stores (Zustand) +- `serverStore.js` - Server management & switching +- `channelStore.js` - Channel management & selection +- `messageStore.js` - Message CRUD & display +- `memberStore.js` - Member roles & permissions +- `modalStore.js` - Global modal state management +- `directMessageStore.js` - DM conversations +- `presenceStore.js` - User status & typing +- `userSettingsStore.js` - Account settings + +### Socket.IO Integration +- `useSocket.js` - Connection management +- `useSocketEmit.js` - Event emission helpers +- Automatic reconnection with exponential backoff +- Message sync, typing indicators, status updates + +### Modals (8 total) +- UserProfileModal - Edit profile +- CreateServerModal - New servers +- SettingsModal - User settings +- UserDiscoveryModal - Find users +- CreateChannelModal - New channels +- ManageMembersModal - Role management +- InviteModal - Server invites +- DeleteServerModal - Server deletion +- LeaveServerModal - Leave server + +### Backend Routes +- `chatRoutes.js` - Message API (POST, PATCH, DELETE, GET reactions) +- `liveKitRoutes.js` - Voice/video token generation +- `liveKitService.js` - LiveKit room management +- Socket.IO event handlers ready for implementation + +--- + +## 🎯 READY FOR TESTING + +**Current URL:** http://localhost:3000/app + +### Test Flow: +1. **Messaging**: Type in message input → Submit → Message appears immediately +2. **DMs**: Click "+" button → Select user → Start conversation +3. **Servers**: Click Trinity server icons → See channel switch + styling +4. **Settings**: Click ⚙️ → Adjust preferences → See instant updates +5. **Discovery**: Click 👥 → Search users → Add contact +6. **Profiles**: Click 👤 → Edit username/status → Save changes + +--- + +## ⚡ QUICK INTEGRATION CHECKLIST + +- [x] Socket.IO client connected +- [x] Message sending & receiving +- [x] DM conversations +- [x] Typing indicators +- [x] Presence tracking +- [x] Server management +- [x] Channel management +- [x] Settings persistence +- [ ] File uploads to UploadThing (ready, needs backend) +- [ ] LiveKit voice/video (ready, needs API keys) +- [ ] Supabase database (routes exist, needs .env) + +--- + +## 📝 ENV VARIABLES NEEDED + +```bash +# Frontend (.env) +VITE_API_URL=http://localhost:3000 +VITE_SOCKET_IO_URL=http://localhost:3000 + +# Backend (.env) +LIVEKIT_URL=wss://your-livekit-server.com +LIVEKIT_API_KEY=your_api_key +LIVEKIT_API_SECRET=your_api_secret +UPLOADTHING_SECRET=your_secret +JWT_SECRET=your_secret +SUPABASE_URL=your_url +SUPABASE_KEY=your_key +``` + +--- + +## 🚀 NEXT STEPS + +1. Add .env configuration +2. Wire Supabase database connections +3. Deploy LiveKit server +4. Test multi-user scenarios (open 2 browser tabs) +5. Add file upload handling +6. Implement message persistence +7. Add notification system +8. Deploy to Railway + +All core functionality is now wired and ready for integration with backend services! diff --git a/astro-site/.astro/settings.json b/astro-site/.astro/settings.json index 6d76a53..7753d3a 100644 --- a/astro-site/.astro/settings.json +++ b/astro-site/.astro/settings.json @@ -1,5 +1,5 @@ { "_variables": { - "lastUpdateCheck": 1770417750117 + "lastUpdateCheck": 1772328323741 } } \ No newline at end of file diff --git a/astro-site/.env.example b/astro-site/.env.example new file mode 100644 index 0000000..e7e2db9 --- /dev/null +++ b/astro-site/.env.example @@ -0,0 +1,6 @@ +# API Configuration +VITE_API_URL=http://localhost:3000 + +# App Configuration +VITE_APP_NAME=AeThex Connect +VITE_APP_VERSION=1.0.0 diff --git a/astro-site/astro.config.mjs b/astro-site/astro.config.mjs index 4c89e4d..4f31038 100644 --- a/astro-site/astro.config.mjs +++ b/astro-site/astro.config.mjs @@ -8,5 +8,31 @@ export default defineConfig({ server: { port: 4321, host: 'localhost' + }, + vite: { + define: { + global: 'globalThis', + }, + optimizeDeps: { + include: [ + 'simple-peer', + 'lucide-react', + 'zustand', + 'clsx', + '@radix-ui/react-popover', + '@radix-ui/react-dropdown-menu', + ], + esbuildOptions: { + target: 'esnext' + } + }, + server: { + hmr: { + timeout: 60000 + }, + watch: { + usePolling: false + } + } } }); diff --git a/astro-site/package-lock.json b/astro-site/package-lock.json index 6ad585f..3ef916b 100644 --- a/astro-site/package-lock.json +++ b/astro-site/package-lock.json @@ -9,14 +9,34 @@ "version": "1.0.0", "dependencies": { "@astrojs/react": "^4.4.2", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-tooltip": "^1.2.8", + "@stripe/react-stripe-js": "^5.6.0", + "@stripe/stripe-js": "^8.8.0", "@types/react": "^19.2.8", "@types/react-dom": "^19.2.3", + "@uploadthing/react": "^7.3.3", "astro": "^4.0.0", + "axios": "^1.13.6", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "date-fns": "^4.1.0", + "livekit-client": "^0.18.6", + "livekit-react": "^0.9.2", + "lucide-react": "^0.575.0", "matrix-js-sdk": "^40.0.0", "mumble-client": "^1.3.0", "react": "^19.2.3", "react-dom": "^19.2.3", - "simple-peer": "^9.11.1" + "react-hook-form": "^7.71.2", + "react-router-dom": "^7.13.1", + "simple-peer": "^9.11.1", + "socket.io-client": "^4.8.3", + "uploadthing": "^7.7.4", + "zod": "^3.25.76", + "zustand": "^5.0.11" }, "devDependencies": { "@astrojs/tailwind": "^5.0.0", @@ -651,7 +671,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -960,6 +979,21 @@ "node": ">=6.9.0" } }, + "node_modules/@effect/platform": { + "version": "0.90.3", + "resolved": "https://registry.npmjs.org/@effect/platform/-/platform-0.90.3.tgz", + "integrity": "sha512-XvQ37yzWQKih4Du2CYladd1i/MzqtgkTPNCaN6Ku6No4CK83hDtXIV/rP03nEoBg2R3Pqgz6gGWmE2id2G81HA==", + "license": "MIT", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.33.0", + "find-my-way-ts": "^0.1.6", + "msgpackr": "^1.11.4", + "multipasta": "^0.2.7" + }, + "peerDependencies": { + "effect": "^3.17.7" + } + }, "node_modules/@emnapi/runtime": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", @@ -1386,6 +1420,91 @@ "node": ">=12" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", + "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", + "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.4", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz", + "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.5" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz", + "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz", + "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==", + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz", + "integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.19.tgz", + "integrity": "sha512-Hyb+lB8T18cvLNX0S3llz7PcSOAJMLwiVKBuuzwM/nI5uoBw+gQjnf9il0fR1C3DKOI5Kc79pkJ4/xB0Uw9aFQ==", + "deprecated": "v0.1x is no longer supported. Please update to v3.1.1 or greater.", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.x" + } + }, "node_modules/@img/sharp-darwin-arm64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", @@ -1801,6 +1920,84 @@ "node": ">= 18" } }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1836,12 +2033,749 @@ "node": ">= 8" } }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", + "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/@oslojs/encoding": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", "license": "MIT" }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -2270,6 +3204,41 @@ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", "license": "MIT" }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@stripe/react-stripe-js": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-5.6.0.tgz", + "integrity": "sha512-tucu/vTGc+5NXbo2pUiaVjA4ENdRBET8qGS00BM4BAU8J4Pi3eY6BHollsP2+VSuzzlvXwMg0it3ZLhbCj2fPg==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "@stripe/stripe-js": ">=8.0.0 <9.0.0", + "react": ">=16.8.0 <20.0.0", + "react-dom": ">=16.8.0 <20.0.0" + } + }, + "node_modules/@stripe/stripe-js": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-8.8.0.tgz", + "integrity": "sha512-NNYuyW8qmLjyHnpyFgs/23wUrjB8k0xN9YIZFOMLewCa/pIkIji9e9aY/EgdNryEDDRptc6TcPIHRvG1R0ClFw==", + "license": "MIT", + "engines": { + "node": ">=12.16" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2347,6 +3316,12 @@ "@types/unist": "*" } }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", + "license": "MIT" + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -2371,12 +3346,20 @@ "@types/unist": "*" } }, + "node_modules/@types/node": { + "version": "25.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", + "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, "node_modules/@types/react": { "version": "19.2.8", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.8.tgz", "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2386,11 +3369,19 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } }, + "node_modules/@types/react-responsive": { + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/@types/react-responsive/-/react-responsive-8.0.8.tgz", + "integrity": "sha512-HDUZtoeFRHrShCGaND23HmXAB9evOOTjkghd2wAasLkuorYYitm5A1XLeKkhXKZppcMBxqB/8V4Snl6hRUTA8g==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -2403,6 +3394,43 @@ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "license": "ISC" }, + "node_modules/@uploadthing/mime-types": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@uploadthing/mime-types/-/mime-types-0.3.6.tgz", + "integrity": "sha512-t3tTzgwFV9+1D7lNDYc7Lr7kBwotHaX0ZsvoCGe7xGnXKo9z0jG2Sjl/msll12FeoLj77nyhsxevXyGpQDBvLg==", + "license": "MIT" + }, + "node_modules/@uploadthing/react": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@uploadthing/react/-/react-7.3.3.tgz", + "integrity": "sha512-GhKbK42jL2Qs7OhRd2Z6j0zTLsnJTRJH31nR7RZnUYVoRh2aS/NabMAnHBNqfunIAGXVaA717Pvzq7vtxuPTmQ==", + "license": "MIT", + "dependencies": { + "@uploadthing/shared": "7.1.10", + "file-selector": "0.6.0" + }, + "peerDependencies": { + "next": "*", + "react": "^17.0.2 || ^18.0.0 || ^19.0.0", + "uploadthing": "^7.2.0" + }, + "peerDependenciesMeta": { + "next": { + "optional": true + } + } + }, + "node_modules/@uploadthing/shared": { + "version": "7.1.10", + "resolved": "https://registry.npmjs.org/@uploadthing/shared/-/shared-7.1.10.tgz", + "integrity": "sha512-R/XSA3SfCVnLIzFpXyGaKPfbwlYlWYSTuGjTFHuJhdAomuBuhopAHLh2Ois5fJibAHzi02uP1QCKbgTAdmArqg==", + "license": "MIT", + "dependencies": { + "@uploadthing/mime-types": "0.3.6", + "effect": "3.17.7", + "sqids": "^0.3.0" + } + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", @@ -2562,6 +3590,18 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", @@ -2602,7 +3642,6 @@ "resolved": "https://registry.npmjs.org/astro/-/astro-4.16.19.tgz", "integrity": "sha512-baeSswPC5ZYvhGDoj25L2FuzKRWMgx105FetOPQVJFMCAp0o08OonYC7AhwsFdhvp7GapqjnC1Fe3lKb2lupYw==", "license": "MIT", - "peer": true, "dependencies": { "@astrojs/compiler": "^2.10.3", "@astrojs/internal-helpers": "0.4.1", @@ -2679,6 +3718,12 @@ "sharp": "^0.33.3" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/autoprefixer": { "version": "10.4.23", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", @@ -2716,6 +3761,17 @@ "postcss": "^8.1.0" } }, + "node_modules/axios": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -2858,7 +3914,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2918,6 +3973,19 @@ "node": ">=0.8" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/camelcase": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", @@ -3052,6 +4120,18 @@ "node": ">=8" } }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, "node_modules/cli-boxes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", @@ -3234,6 +4314,18 @@ "node": ">=0.8" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -3296,6 +4388,12 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, + "node_modules/css-mediaquery": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz", + "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==", + "license": "BSD" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -3314,6 +4412,16 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -3353,6 +4461,15 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3372,6 +4489,12 @@ "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/deterministic-object-hash": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/deterministic-object-hash/-/deterministic-object-hash-2.0.2.tgz", @@ -3446,6 +4569,30 @@ "node": ">=4" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/effect": { + "version": "3.17.7", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.17.7.tgz", + "integrity": "sha512-dpt0ONUn3zzAuul6k4nC/coTTw27AL5nhkORXgTi6NfMPzqWYa1M05oKmOMTxpVSTKepqXVcW9vIwkuaaqx9zA==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.267", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", @@ -3464,6 +4611,28 @@ "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", "license": "MIT" }, + "node_modules/engine.io-client": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz", + "integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.18.3", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/entities": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", @@ -3482,12 +4651,57 @@ "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==", "license": "MIT" }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -3602,6 +4816,28 @@ "node": ">=0.10.0" } }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -3644,6 +4880,18 @@ } } }, + "node_modules/file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -3656,6 +4904,12 @@ "node": ">=8" } }, + "node_modules/find-my-way-ts": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz", + "integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==", + "license": "MIT" + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -3700,6 +4954,42 @@ "node": ">=8" } }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fraction.js": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", @@ -3738,7 +5028,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3771,6 +5060,52 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/github-slugger": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", @@ -3810,6 +5145,18 @@ "node": ">= 6" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3853,11 +5200,37 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -4065,6 +5438,12 @@ "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "license": "BSD-2-Clause" }, + "node_modules/hyphenate-style-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", + "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==", + "license": "BSD-3-Clause" + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -4317,9 +5696,8 @@ "version": "1.21.7", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "devOptional": true, + "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -4425,6 +5803,76 @@ "dev": true, "license": "MIT" }, + "node_modules/livekit-client": { + "version": "0.18.6", + "resolved": "https://registry.npmjs.org/livekit-client/-/livekit-client-0.18.6.tgz", + "integrity": "sha512-D05eAtTwSHORLYBNBw55zMZZoCyTs9j0iv014B0B7fzUfJD3TRRG21sMK+FwixijQ0CHY8JPdZJXy1jBu15hJA==", + "license": "Apache-2.0", + "dependencies": { + "events": "^3.3.0", + "loglevel": "^1.8.0", + "protobufjs": "^6.11.2", + "ts-debounce": "^3.0.0", + "typed-emitter": "^2.1.0", + "webrtc-adapter": "^8.1.1" + } + }, + "node_modules/livekit-client/node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "license": "Apache-2.0" + }, + "node_modules/livekit-client/node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/livekit-react": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/livekit-react/-/livekit-react-0.9.2.tgz", + "integrity": "sha512-g9DrQ0SmFHGrpEIh1UMg8JA2UxNDm37Hs9XEcLtqbCyugCOx9f7b9aOOqQSzfX20g+PJ7t6Hjbh5Kp0h09kyOg==", + "deprecated": "livekit-react has been renamed to @livekit/react-components", + "license": "Apache-2.0", + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.1.1", + "@fortawesome/free-solid-svg-icons": "^6.1.1", + "@fortawesome/react-fontawesome": "^0.1.18", + "@types/react-responsive": "^8.0.2", + "react-aspect-ratio": "^1.1.2", + "react-responsive": "^8.2.0", + "react-tiny-popover": "^7.0.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "livekit-client": "^0.18.6", + "react": ">=15", + "react-dom": ">=15" + } + }, "node_modules/load-yaml-file": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", @@ -4543,6 +5991,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4552,6 +6012,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.575.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.575.0.tgz", + "integrity": "sha512-VuXgKZrk0uiDlWjGGXmKV6MSk9Yy4l10qgVvzGn2AWBx1Ylt0iBexKOAoA6I7JO3m+M9oeovJd3yYENfkUbOeg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -4582,6 +6051,24 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/matchmediaquery": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.3.1.tgz", + "integrity": "sha512-Hlk20WQHRIm9EE9luN1kjRjYXAQToHOIAHPJn9buxBwuhfTHoKUcX+lXBbxc85DVQfXYbEQ4HcwQdd128E3qHQ==", + "license": "MIT", + "dependencies": { + "css-mediaquery": "^0.1.2" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/matrix-events-sdk": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz", @@ -5445,6 +6932,27 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-function": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", @@ -5484,6 +6992,43 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/msgpackr": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.8.tgz", + "integrity": "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA==", + "license": "MIT", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, + "node_modules/multipasta": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/multipasta/-/multipasta-0.2.7.tgz", + "integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==", + "license": "MIT" + }, "node_modules/mumble-client": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/mumble-client/-/mumble-client-1.3.0.tgz", @@ -5561,6 +7106,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", @@ -5590,7 +7150,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5912,7 +7471,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -6109,6 +7667,17 @@ "node": ">=6" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/property-information": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", @@ -6137,6 +7706,28 @@ "node": ">=0.8" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6171,17 +7762,24 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/react-aspect-ratio": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/react-aspect-ratio/-/react-aspect-ratio-1.1.9.tgz", + "integrity": "sha512-VSVpSEXpVtGhACZOjx3wSYqHfscKuDYcla+xQBz+RVjgn440vFWsZWJ0nqzRfudXJPkwnn1V43CwtAYD3cNxHQ==", + "license": "MIT", + "peerDependencies": { + "react": "^0.14.7 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react-dom": { "version": "19.2.3", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -6189,6 +7787,28 @@ "react": "^19.2.3" } }, + "node_modules/react-hook-form": { + "version": "7.71.2", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.2.tgz", + "integrity": "sha512-1CHvcDYzuRUNOflt4MOq3ZM46AronNJtQ1S7tnX6YN4y72qhgiUItpacZUAQ0TyWYci3yz1X+rXaSxiuEm86PA==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", @@ -6198,6 +7818,154 @@ "node": ">=0.10.0" } }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-responsive": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz", + "integrity": "sha512-iagCqVrw4QSjhxKp3I/YK6+ODkWY6G+YPElvdYKiUUbywwh9Ds0M7r26Fj2/7dWFFbOpcGnJE6uE7aMck8j5Qg==", + "license": "MIT", + "dependencies": { + "hyphenate-style-name": "^1.0.0", + "matchmediaquery": "^0.3.0", + "prop-types": "^15.6.1", + "shallow-equal": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/react-router": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.1.tgz", + "integrity": "sha512-td+xP4X2/6BJvZoX6xw++A2DdEi++YypA69bJUV5oVvqf6/9/9nNlD70YO1e9d3MyamJEBQFEzk6mbfDYbqrSA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.1.tgz", + "integrity": "sha512-UJnV3Rxc5TgUPJt2KJpo1Jpy0OKQr0AjgbZzBFjaPJcFOb2Y8jA5H3LT8HUJAiRLlWrEXWHbF1Z4SCZaQjWDHw==", + "license": "MIT", + "dependencies": { + "react-router": "7.13.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-tiny-popover": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/react-tiny-popover/-/react-tiny-popover-7.2.4.tgz", + "integrity": "sha512-T7ZSwXcUtPXCog3Bux9+TjoTvUeMi/+zI0Yv/TkIznZCWUg0XTt2797G0IiT5mTVeJeLivUzdOmKA1hOQdMfOQ==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -6621,6 +8389,16 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -6633,6 +8411,12 @@ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, + "node_modules/sdp": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.1.tgz", + "integrity": "sha512-lwsAIzOPlH8/7IIjjz3K0zYBk7aBVVcvjMwt3M4fLxpjMYyy7i3I97SLHebgn4YBjirkzfp3RvRDWSKsh/+WFw==", + "license": "MIT" + }, "node_modules/sdp-transform": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-3.0.0.tgz", @@ -6667,6 +8451,18 @@ "node": ">=10" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==", + "license": "MIT" + }, "node_modules/sharp": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", @@ -6823,6 +8619,34 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "license": "MIT" }, + "node_modules/socket.io-client": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", + "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", + "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -6848,6 +8672,12 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "license": "BSD-3-Clause" }, + "node_modules/sqids": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/sqids/-/sqids-0.3.0.tgz", + "integrity": "sha512-lOQK1ucVg+W6n3FhRwwSeUijxe93b51Bfz5PMRMihVf1iVkl82ePQG7V5vwrhzB11v0NtsR25PSZRGiSomJaJw==", + "license": "MIT" + }, "node_modules/stats-incremental": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/stats-incremental/-/stats-incremental-1.2.1.tgz", @@ -6993,7 +8823,6 @@ "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -7156,6 +8985,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-debounce": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ts-debounce/-/ts-debounce-3.0.0.tgz", + "integrity": "sha512-7jiRWgN4/8IdvCxbIwnwg2W0bbYFBH6BxFqBjMKk442t7+liF2Z1H6AUCcl8e/pD93GjPru+axeiJwFmRww1WQ==", + "license": "MIT" + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -7187,8 +9022,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true + "license": "0BSD" }, "node_modules/type-fest": { "version": "4.41.0", @@ -7202,18 +9036,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" + "node_modules/typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz", + "integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==", + "license": "MIT", + "optionalDependencies": { + "rxjs": "*" } }, "node_modules/ultrahtml": { @@ -7222,6 +9051,12 @@ "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==", "license": "MIT" }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, "node_modules/unhomoglyph": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/unhomoglyph/-/unhomoglyph-1.0.6.tgz", @@ -7400,6 +9235,93 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uploadthing": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/uploadthing/-/uploadthing-7.7.4.tgz", + "integrity": "sha512-rlK/4JWHW5jP30syzWGBFDDXv3WJDdT8gn9OoxRJmXLoXi94hBmyyjxihGlNrKhBc81czyv8TkzMioe/OuKGfA==", + "license": "MIT", + "dependencies": { + "@effect/platform": "0.90.3", + "@standard-schema/spec": "1.0.0-beta.4", + "@uploadthing/mime-types": "0.3.6", + "@uploadthing/shared": "7.1.10", + "effect": "3.17.7" + }, + "engines": { + "node": ">=18.13.0" + }, + "peerDependencies": { + "express": "*", + "h3": "*", + "tailwindcss": "^3.0.0 || ^4.0.0-beta.0" + }, + "peerDependenciesMeta": { + "express": { + "optional": true + }, + "fastify": { + "optional": true + }, + "h3": { + "optional": true + }, + "next": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/uploadthing/node_modules/@standard-schema/spec": { + "version": "1.0.0-beta.4", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0-beta.4.tgz", + "integrity": "sha512-d3IxtzLo7P1oZ8s8YNvxzBUXRXojSut8pbPrTYtzsc5sn4+53jVqbk66pQerSZbZSJZQux6LkclB/+8IDordHg==", + "license": "MIT" + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -7466,7 +9388,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -7550,6 +9471,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/webrtc-adapter": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.2.4.tgz", + "integrity": "sha512-VwtwbYNKnVQW8koB9qb8YcxNwpSVHTvvKEZLzY6uQ3gFrA9E87VPbB5xE+m1AGwUjL1UgN35jRR9hQgteZI5bg==", + "license": "BSD-3-Clause", + "dependencies": { + "sdp": "^3.2.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, "node_modules/which-pm": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-3.0.1.tgz", @@ -7621,6 +9555,35 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -7652,9 +9615,8 @@ "version": "2.8.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "devOptional": true, + "dev": true, "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -7762,7 +9724,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -7785,6 +9746,35 @@ "zod": "^3" } }, + "node_modules/zustand": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.11.tgz", + "integrity": "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/astro-site/package.json b/astro-site/package.json index 88e05e0..52061ac 100644 --- a/astro-site/package.json +++ b/astro-site/package.json @@ -9,14 +9,34 @@ }, "dependencies": { "@astrojs/react": "^4.4.2", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-scroll-area": "^1.2.10", + "@radix-ui/react-tooltip": "^1.2.8", + "@stripe/react-stripe-js": "^5.6.0", + "@stripe/stripe-js": "^8.8.0", "@types/react": "^19.2.8", "@types/react-dom": "^19.2.3", + "@uploadthing/react": "^7.3.3", "astro": "^4.0.0", + "axios": "^1.13.6", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "date-fns": "^4.1.0", + "livekit-client": "^0.18.6", + "livekit-react": "^0.9.2", + "lucide-react": "^0.575.0", "matrix-js-sdk": "^40.0.0", "mumble-client": "^1.3.0", "react": "^19.2.3", "react-dom": "^19.2.3", - "simple-peer": "^9.11.1" + "react-hook-form": "^7.71.2", + "react-router-dom": "^7.13.1", + "simple-peer": "^9.11.1", + "socket.io-client": "^4.8.3", + "uploadthing": "^7.7.4", + "zod": "^3.25.76", + "zustand": "^5.0.11" }, "devDependencies": { "@astrojs/tailwind": "^5.0.0", diff --git a/astro-site/src/components/aethex/AeThexProvider.jsx b/astro-site/src/components/aethex/AeThexProvider.jsx index 0971c64..a65eb18 100644 --- a/astro-site/src/components/aethex/AeThexProvider.jsx +++ b/astro-site/src/components/aethex/AeThexProvider.jsx @@ -6,7 +6,7 @@ import React, { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { io } from 'socket.io-client'; -const API_URL = import.meta.env?.VITE_API_URL || 'http://localhost:3000'; +const API_URL = import.meta.env?.VITE_API_URL || 'http://localhost:5000'; const API_BASE = `${API_URL}/api`; const AeThexContext = createContext(null); diff --git a/astro-site/src/components/mockup/ChannelSidebar.jsx b/astro-site/src/components/mockup/ChannelSidebar.jsx index bf32330..2f28461 100644 --- a/astro-site/src/components/mockup/ChannelSidebar.jsx +++ b/astro-site/src/components/mockup/ChannelSidebar.jsx @@ -1,66 +1,160 @@ import React from "react"; -import { useWebRTC } from "../webrtc/WebRTCProvider.jsx"; +import { Plus } from "lucide-react"; +import { useChannelStore } from "../../stores/channelStore"; +import { useModalStore } from "../../stores/modalStore"; +import { useMemberStore } from "../../stores/memberStore"; +import { ServerHeader } from "./ServerHeader"; export default function ChannelSidebar() { - const { joined, joinVoice, leaveVoice } = useWebRTC(); + const channels = useChannelStore((state) => state.channels); + const currentChannelId = useChannelStore((state) => state.currentChannelId); + const setCurrentChannel = useChannelStore((state) => state.setCurrentChannel); + const onOpen = useModalStore((state) => state.onOpen); + const getCurrentUser = useMemberStore((state) => state.getCurrentUser); + + const currentUser = getCurrentUser(); + const isAdmin = currentUser?.role === "ADMIN"; + + // Group channels by category + const groupedChannels = channels.reduce((acc, channel) => { + if (!acc[channel.category]) acc[channel.category] = []; + acc[channel.category].push(channel); + return acc; + }, {}); + + const joined = false; + const joinVoice = () => console.log("Voice feature coming soon"); + const leaveVoice = () => console.log("Voice feature coming soon"); + + // Mock server data for now + const mockServer = { + id: "aethex-foundation", + name: "AeThex Foundation", + inviteCode: "aethex-foundation" + }; + return ( -
+
{/* Server Header */} -
- AeThex Foundation - Official -
+ + {/* Channel List */} -
-
Announcements
-
- 📢 - updates - 3 -
-
- 📜 - changelog -
-
Development
-
- # - general -
-
- # - api-discussion -
-
- # - passport-development -
-
Support
-
- - help -
-
- 🐛 - bug-reports -
-
Voice Channels
-
- 🔊 - Nexus Lounge - {joined ? "Connected" : "3"} -
-
- {/* User Presence */} -
-
A
-
-
Anderson
-
- - Building AeThex +
+ {Object.entries(groupedChannels).map(([category, categoryChannels]) => ( +
+
+ {category} + {isAdmin && category !== "Voice Channels" && ( + + )} +
+ + {categoryChannels.map((channel) => ( +
setCurrentChannel(channel.id)} + className={`channel-item ${currentChannelId === channel.id ? "active" : ""}`} + > + + {channel.type === "voice" ? "🔊" : "#"} + + {channel.name} + {channel.unread && ( + + {channel.unread} + + )} +
+ ))}
+ ))} +
+ + {/* User Presence - Discord Style Bottom Panel */} +
+
+
onOpen("userProfile", { member: currentUser })} + title="View profile" + > + {currentUser?.avatar || "A"} +
+
+
Anderson
+
Building AeThex
+
+
+ {/* Status Selector */} + + {/* Settings */} + + {/* Mute */} + +
+
+ + {/* Quick Access Panel */} +
+ + + +
diff --git a/astro-site/src/components/mockup/ChatArea.jsx b/astro-site/src/components/mockup/ChatArea.jsx index 6cf9928..c6e2e5f 100644 --- a/astro-site/src/components/mockup/ChatArea.jsx +++ b/astro-site/src/components/mockup/ChatArea.jsx @@ -1,77 +1,165 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useRef, useState } from "react"; import Message from "./Message"; import MessageInput from "./MessageInput"; -import { useAeThex } from "../aethex/AeThexProvider.jsx"; -import DemoLoginButton from "./DemoLoginButton.jsx"; +import VoiceCallButton from "./VoiceCallButton.jsx"; +import { useMessageStore } from "../../stores/messageStore.js"; +import { useChannelStore } from "../../stores/channelStore.js"; +import { usePresenceStore } from "../../stores/presenceStore.js"; +import { useSocket } from "../../hooks/useSocket.js"; +import { useModalStore } from "../../stores/modalStore.js"; +import { Settings, Users } from "lucide-react"; -// Default channel to join -const DEFAULT_CHANNEL_ID = "general"; +const DEMO_MESSAGES = [ + { + id: 'msg-1', + channelId: 'general', + senderId: 'user-2', + senderName: 'Trevor', + text: 'Just pushed the authentication updates. All services should migrate within 24 hours.', + timestamp: Date.now() - 3600000, + edited: false, + reactions: [], + }, + { + id: 'msg-2', + channelId: 'general', + senderId: 'user-3', + senderName: 'Marcus', + text: 'Excellent work! Trinity color-coding is really clear.', + timestamp: Date.now() - 3000000, + edited: false, + reactions: [], + }, +]; export default function ChatArea() { - const { messages, joinChannel, currentChannelId, user, demoLogin, loading, isAuthenticated } = useAeThex(); + const messagesRef = useRef(null); + const socket = useSocket(); + const { onOpen } = useModalStore(); + + const currentChannelId = useChannelStore((state) => state.currentChannelId); + const getCurrentChannel = useChannelStore((state) => state.getCurrentChannel); + const messages = useMessageStore((state) => state.messages); + const getChannelTypingUsers = usePresenceStore((state) => state.getChannelTypingUsers); - // Join the default channel on login + const currentChannel = getCurrentChannel(); + const channelMessages = messages.filter((m) => m.channelId === currentChannelId); + const typingUsers = getChannelTypingUsers(currentChannelId); + + // Load demo messages on mount useEffect(() => { - if (isAuthenticated && user && !currentChannelId) { - joinChannel(DEFAULT_CHANNEL_ID); + if (messages.length === 0) { + DEMO_MESSAGES.forEach((msg) => { + useMessageStore.getState().addMessage(msg); + }); } - }, [isAuthenticated, user, currentChannelId, joinChannel]); + }, []); - // Demo login handler - const handleDemoLogin = async () => { - await demoLogin(); - }; - - if (!isAuthenticated || !user) { - return ( -
- - {loading &&
Logging in as demo user...
} -
- ); - } + // Auto-scroll to bottom + useEffect(() => { + if (messagesRef.current) { + messagesRef.current.scrollTop = messagesRef.current.scrollHeight; + } + }, [channelMessages, typingUsers]); return ( -
- {/* Chat Header */} -
- # general -
- 🔔 - 📌 - 👥 128 - 🔍 +
+ {/* Channel Header */} +
+ + #{currentChannel?.name || 'general'} + +
+ + onOpen('notifications')} + className="chat-tool" + style={{ cursor: 'pointer' }} + title="Notifications" + > + 🔔 + + onOpen('pinnedMessages')} + className="chat-tool" + style={{ cursor: 'pointer' }} + title="Pinned Messages" + > + 📌 + + onOpen('discovery')} + className="chat-tool" + style={{ cursor: 'pointer' }} + title="Find users & servers" + > + 👥 + + onOpen('quickSwitcher')} + className="chat-tool" + style={{ cursor: 'pointer' }} + title="Quick Switcher (Ctrl+K)" + > + 🔍 + + onOpen('settings')} + className="chat-tool" + style={{ cursor: 'pointer' }} + title="Settings" + > + ⚙️ +
+ {/* Messages */} -
- {messages && messages.length > 0 ? ( - messages.map((msg, i) => ( - - )) +
+ {channelMessages.length === 0 ? ( +
+

💬

+

No messages yet. Start the conversation!

+
) : ( -
No messages yet.
+ channelMessages.map((msg) => ( + + )) + )} + + {/* Typing Indicators */} + {typingUsers.length > 0 && ( +
+
+ + + +
+ + {typingUsers + .map((u) => u.userName) + .join(", ")} {typingUsers.length === 1 ? "is" : "are"} typing... + +
)}
- {/* Message Input */} -
- -
-
+ {/* Message Input */} + +
); } +// Add VoiceCallButton to imports at top: +// import VoiceCallButton from "./VoiceCallButton.jsx"; -// Helper to convert AeThex message to Message props -function messageToProps(msg) { - if (!msg) return {}; - return { - type: "user", - author: msg.sender?.display_name || msg.sender?.username || "User", - text: msg.content || "", - time: new Date(msg.created_at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }), - avatar: (msg.sender?.display_name || msg.sender?.username || "U").charAt(0).toUpperCase(), - avatarBg: "from-blue-600 to-blue-900", - }; -} +// And add this to the Channel Header section after Settings button: +// diff --git a/astro-site/src/components/mockup/DirectMessageChat.jsx b/astro-site/src/components/mockup/DirectMessageChat.jsx new file mode 100644 index 0000000..28c3259 --- /dev/null +++ b/astro-site/src/components/mockup/DirectMessageChat.jsx @@ -0,0 +1,109 @@ +import React, { useState } from 'react'; +import { useDirectMessageStore } from '../../stores/directMessageStore.js'; +import { useSocketEmit } from '../../hooks/useSocket.js'; +import { X } from 'lucide-react'; + +export default function DirectMessageChat() { + const { currentConversationId, getCurrentConversation, addMessage } = useDirectMessageStore(); + const { sendDirectMessage, emitTyping } = useSocketEmit(); + const [messageText, setMessageText] = useState(''); + const [typingTimeout, setTypingTimeout] = useState(null); + + const conversation = getCurrentConversation(); + + if (!conversation) { + return ( +
+
+
💬
+

Select a conversation to start messaging

+
+
+ ); + } + + const handleSend = async (e) => { + e.preventDefault(); + if (!messageText.trim()) return; + + const newMessage = { + id: `msg-${Date.now()}`, + senderId: 'user-1', + text: messageText, + timestamp: Date.now(), + }; + + addMessage(conversation.id, newMessage); + sendDirectMessage(conversation.id, messageText, 'user-1'); + setMessageText(''); + + if (typingTimeout) clearTimeout(typingTimeout); + }; + + const handleTyping = (e) => { + setMessageText(e.target.value); + + if (typingTimeout) clearTimeout(typingTimeout); + emitTyping(conversation.id, 'user-1', 'You'); + + const timeout = setTimeout(() => { + // Typing indicator will auto-clear after 3s on server + }, 3000); + setTypingTimeout(timeout); + }; + + return ( +
+ {/* Header */} +
+
+
+ {conversation.avatar} +
+

{conversation.userName}

+
+ +
+ + {/* Messages */} +
+ {conversation.messages.map((msg) => ( +
+
+

{msg.text}

+

+ {new Date(msg.timestamp).toLocaleTimeString()} +

+
+
+ ))} +
+ + {/* Input */} +
+ + +
+
+ ); +} diff --git a/astro-site/src/components/mockup/DirectMessageList.jsx b/astro-site/src/components/mockup/DirectMessageList.jsx new file mode 100644 index 0000000..287e170 --- /dev/null +++ b/astro-site/src/components/mockup/DirectMessageList.jsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { useDirectMessageStore } from '../../stores/directMessageStore.js'; + +export default function DirectMessageList() { + const { conversations, currentConversationId, setCurrentConversation, createConversation } = useDirectMessageStore(); + + return ( +
+
+

Direct Messages

+
+ +
+ {conversations.map((conv) => ( + + ))} +
+ + +
+ ); +} diff --git a/astro-site/src/components/mockup/FriendRequestsPanel.jsx b/astro-site/src/components/mockup/FriendRequestsPanel.jsx new file mode 100644 index 0000000..123b238 --- /dev/null +++ b/astro-site/src/components/mockup/FriendRequestsPanel.jsx @@ -0,0 +1,92 @@ +import React, { useState } from "react"; + +export default function FriendRequestsPanel() { + const [friendRequests, setFriendRequests] = useState([ + { id: 1, username: "Phoenix", avatar: "🔥", status: "pending" }, + { id: 2, username: "Nexus", avatar: "⭐", status: "pending" }, + { id: 3, username: "Cipher", avatar: "🔐", status: "pending" }, + ]); + + const handleAccept = (id) => { + setFriendRequests(friendRequests.filter((r) => r.id !== id)); + }; + + const handleDeny = (id) => { + setFriendRequests(friendRequests.filter((r) => r.id !== id)); + }; + + return ( +
+

+ 👥 Friend Requests ({friendRequests.length}) +

+ + {friendRequests.length === 0 ? ( +

No pending friend requests

+ ) : ( + friendRequests.map((req) => ( +
+
+ {req.avatar} + {req.username} +
+
+ + +
+
+ )) + )} +
+ ); +} diff --git a/astro-site/src/components/mockup/InviteModalNew.jsx b/astro-site/src/components/mockup/InviteModalNew.jsx new file mode 100644 index 0000000..6f98f18 --- /dev/null +++ b/astro-site/src/components/mockup/InviteModalNew.jsx @@ -0,0 +1,79 @@ +import { useState } from 'react'; +import { Copy, Check } from 'lucide-react'; + +export function InviteModal({ isOpen, onClose, server }) { + const [copied, setCopied] = useState(false); + + if (!isOpen || !server) return null; + + // Generate a mock invite link + const inviteCode = 'ABC123XYZ'; + const inviteUrl = `https://aethex-connect.app/invite/${inviteCode}`; + + const handleCopy = async () => { + await navigator.clipboard.writeText(inviteUrl); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + const handleRegenerate = () => { + alert('Regenerate invite code - coming soon!'); + }; + + return ( +
+
+ {/* Header */} +
+

Invite Friends

+
+ + {/* Content */} +
+
+ +
+ + +
+ {copied &&

Copied to clipboard!

} +
+ +
+

+ Or generate a new link +

+ +
+
+ + {/* Footer */} +
+ +
+
+
+ ); +} diff --git a/astro-site/src/components/mockup/KeyboardShortcuts.jsx b/astro-site/src/components/mockup/KeyboardShortcuts.jsx new file mode 100644 index 0000000..a25cfc9 --- /dev/null +++ b/astro-site/src/components/mockup/KeyboardShortcuts.jsx @@ -0,0 +1,23 @@ +import { useEffect } from "react"; +import { useModalStore } from "../../stores/modalStore.js"; + +export default function KeyboardShortcuts() { + const onOpen = useModalStore((state) => state.onOpen); + + useEffect(() => { + const handleKeyDown = (e) => { + // Ctrl+K or Cmd+K - Quick Switcher + if ((e.ctrlKey || e.metaKey) && e.key === "k") { + e.preventDefault(); + onOpen("quickSwitcher"); + } + + // Escape to close modals is handled by each modal individually + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [onOpen]); + + return null; +} diff --git a/astro-site/src/components/mockup/MainLayout.jsx b/astro-site/src/components/mockup/MainLayout.jsx index c94864d..9f6d5c6 100644 --- a/astro-site/src/components/mockup/MainLayout.jsx +++ b/astro-site/src/components/mockup/MainLayout.jsx @@ -1,19 +1,76 @@ - -import { WebRTCProvider } from "../webrtc/WebRTCProvider.jsx"; +import React, { useEffect } from 'react'; import ServerList from "./ServerList.jsx"; import ChannelSidebar from "./ChannelSidebar.jsx"; import ChatArea from "./ChatArea.jsx"; import MemberSidebar from "./MemberSidebar.jsx"; +import DirectMessageList from "./DirectMessageList.jsx"; +import DirectMessageChat from "./DirectMessageChat.jsx"; +import { ModalProvider } from "./modals/ModalProvider.jsx"; +import KeyboardShortcuts from "./KeyboardShortcuts.jsx"; +import { useDirectMessageStore } from "../../stores/directMessageStore.js"; +import { useServerStore } from "../../stores/serverStore.js"; +import { useChannelStore } from "../../stores/channelStore.js"; +import { useMessageStore } from "../../stores/messageStore.js"; +import { useUserSettingsStore } from "../../stores/userSettingsStore.js"; export default function MainLayout() { + const currentConversationId = useDirectMessageStore((state) => state.currentConversationId); + + // Store actions + const fetchServers = useServerStore((state) => state.fetchServers); + const currentServerId = useServerStore((state) => state.currentServerId); + const fetchChannels = useChannelStore((state) => state.fetchChannels); + const fetchMessages = useMessageStore((state) => state.fetchMessages); + const currentChannelId = useChannelStore((state) => state.currentChannelId); + const initializeUser = useUserSettingsStore((state) => state.initializeUser); + const initializeSocketListeners = useMessageStore((state) => state.initializeSocketListeners); + + // Initialize on mount + useEffect(() => { + // Load user + initializeUser(); + + // Load servers + fetchServers(); + + // Initialize socket listeners for real-time updates + initializeSocketListeners(); + }, []); + + // Load channels when server changes + useEffect(() => { + if (currentServerId) { + fetchChannels(currentServerId); + } + }, [currentServerId]); + + // Load messages when channel changes + useEffect(() => { + if (currentChannelId && !currentConversationId) { + fetchMessages(currentChannelId); + } + }, [currentChannelId, currentConversationId]); + return ( - + <> +
- - - + + {currentConversationId ? ( + <> + + + + ) : ( + <> + + + + + )}
-
+ + ); } diff --git a/astro-site/src/components/mockup/MemberSidebar.jsx b/astro-site/src/components/mockup/MemberSidebar.jsx index f49716b..5b72f48 100644 --- a/astro-site/src/components/mockup/MemberSidebar.jsx +++ b/astro-site/src/components/mockup/MemberSidebar.jsx @@ -1,27 +1,28 @@ import React, { useEffect, useRef } from "react"; -import { useWebRTC } from "../webrtc/WebRTCProvider.jsx"; - -const members = [ - { section: "Foundation Team — 8", users: [ - { name: "Anderson", avatar: "A", status: "online", avatarBg: "from-red-600 to-red-800" }, - { name: "Trevor", avatar: "T", status: "online", avatarBg: "from-red-600 to-red-800" }, - ]}, - { section: "Labs Team — 12", users: [ - { name: "Sarah", avatar: "S", status: "labs", avatarBg: "from-orange-400 to-orange-700", activity: "Testing v2.0" }, - ]}, - { section: "Developers — 47", users: [ - { name: "Marcus", avatar: "M", status: "in-game", avatarBg: "bg-[#1a1a1a]", activity: "Building" }, - { name: "DevUser_2847", avatar: "D", status: "online", avatarBg: "bg-[#1a1a1a]" }, - ]}, - { section: "Community — 61", users: [ - { name: "JohnDev", avatar: "J", status: "offline", avatarBg: "bg-[#1a1a1a]" }, - ]}, -]; +import { useMemberStore } from "../../stores/memberStore"; +import { useModalStore } from "../../stores/modalStore"; +import { Settings } from "lucide-react"; export default function MemberSidebar() { - const { joined, peers, localStream } = useWebRTC(); + const members = useMemberStore((state) => state.members); + const getCurrentUser = useMemberStore((state) => state.getCurrentUser); + const onOpen = useModalStore((state) => state.onOpen); + + const currentUser = getCurrentUser(); + const isAdmin = currentUser?.role === "ADMIN"; + + // Group members by section + const groupedMembers = members.reduce((acc, member) => { + const section = member.division || "Others"; + if (!acc[section]) acc[section] = []; + acc[section].push(member); + return acc; + }, {}); + + const joined = false; + const peers = []; + const localStream = null; - // Helper to render audio for remote streams function RemoteAudio({ stream }) { const audioRef = useRef(); useEffect(() => { @@ -32,7 +33,6 @@ export default function MemberSidebar() { return