diff --git a/api/_notifications.ts b/api/_notifications.ts index bae5517a..5c9c32f3 100644 --- a/api/_notifications.ts +++ b/api/_notifications.ts @@ -20,7 +20,10 @@ export async function createNotification( } } -export async function notifyAccountLinked(userId: string, provider: string): Promise { +export async function notifyAccountLinked( + userId: string, + provider: string, +): Promise { await createNotification( userId, "success", diff --git a/client/lib/aethex-database-adapter.ts b/client/lib/aethex-database-adapter.ts index 94c3bcd4..865e4ad8 100644 --- a/client/lib/aethex-database-adapter.ts +++ b/client/lib/aethex-database-adapter.ts @@ -141,11 +141,18 @@ const ensureDailyStreakForProfile = async ( }; }; -export function checkProfileComplete(p?: AethexUserProfile | null, roles?: string[]): boolean { +export function checkProfileComplete( + p?: AethexUserProfile | null, + roles?: string[], +): boolean { if (!p) return false; // Admins/owners are always considered complete - if (roles?.some((r) => ["owner", "admin", "founder", "staff"].includes(r.toLowerCase()))) { + if ( + roles?.some((r) => + ["owner", "admin", "founder", "staff"].includes(r.toLowerCase()), + ) + ) { return true; } @@ -542,7 +549,10 @@ export const aethexUserService = { "You've completed your profile setup. Let's get started!", ); } catch (notifError) { - console.warn("Failed to create onboarding notification:", notifError); + console.warn( + "Failed to create onboarding notification:", + notifError, + ); } } @@ -757,7 +767,10 @@ export const aethexProjectService = { ); } } catch (notifError) { - console.warn("Failed to create project status notification:", notifError); + console.warn( + "Failed to create project status notification:", + notifError, + ); } } diff --git a/client/lib/notification-triggers.ts b/client/lib/notification-triggers.ts index 0e207d05..9227d573 100644 --- a/client/lib/notification-triggers.ts +++ b/client/lib/notification-triggers.ts @@ -31,7 +31,11 @@ export const notificationTriggers = { } }, - async addedToTeam(userId: string, teamName: string, role: string): Promise { + async addedToTeam( + userId: string, + teamName: string, + role: string, + ): Promise { try { await aethexNotificationService.createNotification( userId, @@ -57,7 +61,11 @@ export const notificationTriggers = { } }, - async addedToProject(userId: string, projectName: string, role: string): Promise { + async addedToProject( + userId: string, + projectName: string, + role: string, + ): Promise { try { await aethexNotificationService.createNotification( userId, @@ -155,13 +163,22 @@ export const notificationTriggers = { message: string, ): Promise { try { - await aethexNotificationService.createNotification(userId, type, title, message); + await aethexNotificationService.createNotification( + userId, + type, + title, + message, + ); } catch (error) { console.warn("Failed to create custom notification:", error); } }, - async taskAssigned(userId: string, taskTitle: string, assignerName: string): Promise { + async taskAssigned( + userId: string, + taskTitle: string, + assignerName: string, + ): Promise { try { await aethexNotificationService.createNotification( userId, @@ -187,7 +204,11 @@ export const notificationTriggers = { } }, - async postCommented(userId: string, commenterName: string, preview: string): Promise { + async postCommented( + userId: string, + commenterName: string, + preview: string, + ): Promise { try { await aethexNotificationService.createNotification( userId, @@ -200,7 +221,11 @@ export const notificationTriggers = { } }, - async applicationReceived(userId: string, creatorName: string, opportunityTitle: string): Promise { + async applicationReceived( + userId: string, + creatorName: string, + opportunityTitle: string, + ): Promise { try { await aethexNotificationService.createNotification( userId, @@ -218,13 +243,23 @@ export const notificationTriggers = { status: "accepted" | "rejected" | "reviewed", message?: string, ): Promise { - const statusEmoji = status === "accepted" ? "✅" : status === "rejected" ? "❌" : "📝"; - const statusMessage = status === "accepted" ? "accepted" : status === "rejected" ? "rejected" : "reviewed"; + const statusEmoji = + status === "accepted" ? "✅" : status === "rejected" ? "❌" : "📝"; + const statusMessage = + status === "accepted" + ? "accepted" + : status === "rejected" + ? "rejected" + : "reviewed"; try { await aethexNotificationService.createNotification( userId, - status === "accepted" ? "success" : status === "rejected" ? "error" : "info", + status === "accepted" + ? "success" + : status === "rejected" + ? "error" + : "info", `${statusEmoji} Application ${statusMessage}`, message || `Your application has been ${statusMessage}.`, ); @@ -233,7 +268,11 @@ export const notificationTriggers = { } }, - async newDeviceLogin(userId: string, deviceName: string, location?: string): Promise { + async newDeviceLogin( + userId: string, + deviceName: string, + location?: string, + ): Promise { try { await aethexNotificationService.createNotification( userId, @@ -246,7 +285,10 @@ export const notificationTriggers = { } }, - async moderationReportSubmitted(userId: string, reportType: string): Promise { + async moderationReportSubmitted( + userId: string, + reportType: string, + ): Promise { try { await aethexNotificationService.createNotification( userId, diff --git a/docs/COMPLETE-NOTIFICATION-FLOWS.md b/docs/COMPLETE-NOTIFICATION-FLOWS.md index c123b1fe..7888358d 100644 --- a/docs/COMPLETE-NOTIFICATION-FLOWS.md +++ b/docs/COMPLETE-NOTIFICATION-FLOWS.md @@ -7,72 +7,84 @@ A comprehensive notification system covering 15+ user interactions across social ## All Notification Flows ### 1. Achievements (✅ Success) + **When:** User earns an achievement **Who Notified:** Achievement earner **Format:** `🏆 Achievement Unlocked: {name}` - "{xp} XP awarded" **Service:** `aethexAchievementService.awardAchievement()` ### 2. Team Creation (✅ Success) + **When:** Team is created **Who Notified:** Team creator **Format:** `đŸŽ¯ Team Created: {name}` - "Your team is ready to go!" **Service:** `aethexCollabService.createTeam()` ### 3. Added to Team (â„šī¸ Info) + **When:** User is added to a team **Who Notified:** New team member **Format:** `đŸ‘Ĩ Added to Team: {name}` - "You've been added as a {role}" **Service:** `aethexCollabService.addTeamMember()` ### 4. Project Creation (✅ Success) + **When:** Project is created **Who Notified:** Project creator **Format:** `🚀 Project Created: {name}` - "Your project is ready to go!" **Service:** `aethexProjectService.createProject()` ### 5. Added to Project (â„šī¸ Info) + **When:** User is added to a project **Who Notified:** New project member **Format:** `📌 Added to Project: {name}` - "You've been added as a {role}" **Service:** `aethexCollabService.addProjectMember()` ### 6. Project Completed (✅ Success) + **When:** Project status changes to completed **Who Notified:** Project owner **Format:** `✅ Project Completed: {name}` - "Congratulations!" **Service:** `aethexProjectService.updateProject(status: "completed")` ### 7. Project Started (â„šī¸ Info) + **When:** Project status changes to in_progress **Who Notified:** Project owner **Format:** `âąī¸ Project Started: {name}` - "You've started working on this" **Service:** `aethexProjectService.updateProject(status: "in_progress")` ### 8. Level Up (✅ Success) + **When:** User gains enough XP to level up **Who Notified:** User **Format:** `âŦ†ī¸ Level Up!` - "You've reached level {n}!" **Service:** `aethexAchievementService.updateUserXPAndLevel()` ### 9. Onboarding Complete (✅ Success) + **When:** User finishes onboarding **Who Notified:** User **Format:** `🎉 Welcome to AeThex!` - "Profile setup complete!" **Service:** `Onboarding.tsx -> finishOnboarding()` ### 10. Account Linked (✅ Success) + **When:** User links OAuth provider (Discord, GitHub, etc.) **Who Notified:** User **Format:** `🔗 Account Linked: {provider}` - "Successfully linked" **Service:** OAuth callback endpoints ### 11. Email Verified (✅ Success) + **When:** User verifies email **Who Notified:** User **Format:** `âœ‰ī¸ Email Verified` - "Your email has been verified" **Service:** Auth flow (future implementation) ### 12. Post Liked (â„šī¸ Info) + **When:** Someone likes a community post **Who Notified:** Post author **Format:** `â¤ī¸ Your post was liked` - "{liker} liked your post" @@ -80,6 +92,7 @@ A comprehensive notification system covering 15+ user interactions across social **Service:** `notificationTriggers.postLiked()` ### 13. Post Commented (â„šī¸ Info) + **When:** Someone comments on a community post **Who Notified:** Post author **Format:** `đŸ’Ŧ New comment on your post` - "{commenter} commented: {preview}" @@ -87,27 +100,32 @@ A comprehensive notification system covering 15+ user interactions across social **Service:** `notificationTriggers.postCommented()` ### 14. Endorsement Received (✅ Success) + **When:** User endorses another user's skill **Who Notified:** Endorsed user **Format:** `đŸŽ–ī¸ New endorsement` - "{endorser} endorsed you for {skill}" **Endpoint:** `POST /api/social/endorse` ### 15. New Follower (â„šī¸ Info) + **When:** Someone follows a user **Who Notified:** Followed user **Format:** `đŸ‘Ĩ New follower` - "{follower} started following you" **Endpoint:** `POST /api/social/follow` ### 16. Task Assigned (â„šī¸ Info) + **When:** Task is assigned to user **Who Notified:** Assignee **Format:** `📋 Task assigned to you` - "{assigner} assigned: {title}" **Endpoints:** + - `POST /api/tasks` (on create with assignee) - `PUT /api/tasks/:id/assign` -**Service:** `notificationTriggers.taskAssigned()` + **Service:** `notificationTriggers.taskAssigned()` ### 17. Application Received (â„šī¸ Info) + **When:** Creator applies for an opportunity **Who Notified:** Opportunity poster **Format:** `📋 New Application: {title}` - "{creator} applied" @@ -115,6 +133,7 @@ A comprehensive notification system covering 15+ user interactions across social **Service:** `notificationTriggers.applicationReceived()` ### 18. Application Status Changed (✅/❌ Success/Error) + **When:** Application is accepted/rejected **Who Notified:** Applicant **Format:** `✅/❌ Application {status}` - "{message}" @@ -122,6 +141,7 @@ A comprehensive notification system covering 15+ user interactions across social **Service:** `notificationTriggers.applicationStatusChanged()` ### 19. New Device Login (âš ī¸ Warning) + **When:** User logs in from new device **Who Notified:** User **Format:** `🔐 New device login detected` - "New login from {device}. If this wasn't you, secure your account." @@ -129,6 +149,7 @@ A comprehensive notification system covering 15+ user interactions across social **Service:** `notificationTriggers.newDeviceLogin()` ### 20. Moderation Report (âš ī¸ Warning) + **When:** User submits moderation report **Who Notified:** All staff/moderators **Format:** `🚨 New moderation report` - "A {type} report has been submitted" @@ -137,27 +158,30 @@ A comprehensive notification system covering 15+ user interactions across social ## Notification Types -| Type | Color | Icon | Use Cases | -|------|-------|------|-----------| -| `success` | đŸŸĸ Green | ✅ | Achievements, completion, account actions | -| `info` | đŸ”ĩ Blue | â„šī¸ | Team/project updates, social interactions | -| `warning` | 🟡 Yellow | âš ī¸ | Security alerts, moderation reports | -| `error` | 🔴 Red | ❌ | Rejections, failed actions, security issues | +| Type | Color | Icon | Use Cases | +| --------- | --------- | ---- | ------------------------------------------- | +| `success` | đŸŸĸ Green | ✅ | Achievements, completion, account actions | +| `info` | đŸ”ĩ Blue | â„šī¸ | Team/project updates, social interactions | +| `warning` | 🟡 Yellow | âš ī¸ | Security alerts, moderation reports | +| `error` | 🔴 Red | ❌ | Rejections, failed actions, security issues | ## Integration Points ### Client Services + - `code/client/lib/aethex-database-adapter.ts` - Project, achievement, profile notifications - `code/client/lib/aethex-collab-service.ts` - Team/project member notifications - `code/client/lib/notification-triggers.ts` - Centralized trigger utilities - `code/client/pages/Onboarding.tsx` - Onboarding completion notification ### Server Endpoints + - `code/server/index.ts` - Social, community, task, application, moderation, auth endpoints - `code/api/discord/oauth/callback.ts` - Account linking notifications - `code/api/_notifications.ts` - Backend notification helper utilities ### Database + - `notifications` table - Stores all notifications - `user_follows` - Follow notifications - `community_post_likes` - Like notifications @@ -179,6 +203,7 @@ A comprehensive notification system covering 15+ user interactions across social ## How Notifications Are Created ### Pattern 1: Direct Insert (Server Endpoints) + ```javascript await adminSupabase.from("notifications").insert({ user_id: targetUserId, @@ -189,16 +214,18 @@ await adminSupabase.from("notifications").insert({ ``` ### Pattern 2: Service Method (Client Services) + ```javascript await aethexNotificationService.createNotification( userId, "success", "Title", - "Message" + "Message", ); ``` ### Pattern 3: Trigger Utilities (Client) + ```javascript await notificationTriggers.postLiked(userId, likerName); ``` @@ -214,6 +241,7 @@ await notificationTriggers.postLiked(userId, likerName); ## Notification Display **NotificationBell Component** (`code/client/components/notifications/NotificationBell.tsx`) + - Bell icon with unread count badge - Dropdown showing latest notifications - Type-specific icons (emoji-based) @@ -221,6 +249,7 @@ await notificationTriggers.postLiked(userId, likerName); - Real-time update via Supabase subscription **Dashboard Tab** (`code/client/pages/Dashboard.tsx`) + - Full notification history - Type filtering options - Batch actions (mark as read) @@ -228,6 +257,7 @@ await notificationTriggers.postLiked(userId, likerName); ## Testing Notifications ### Manual Testing Checklist + - [ ] Create team/project → notification - [ ] Get added to team/project → notification - [ ] Like community post → post author notified @@ -242,18 +272,19 @@ await notificationTriggers.postLiked(userId, likerName); - [ ] Link Discord → user notified ### Database Verification + ```sql -- Check notifications for user -SELECT * FROM notifications -WHERE user_id = '...' -ORDER BY created_at DESC +SELECT * FROM notifications +WHERE user_id = '...' +ORDER BY created_at DESC LIMIT 20; -- Check notification types SELECT type, COUNT(*) FROM notifications GROUP BY type; -- Check unread count -SELECT COUNT(*) FROM notifications +SELECT COUNT(*) FROM notifications WHERE user_id = '...' AND read = false; ``` @@ -272,6 +303,7 @@ WHERE user_id = '...' AND read = false; ## Monitoring Check in Supabase dashboard: + 1. `notifications` table → see all notifications 2. Real-time → verify subscriptions active 3. Database stats → monitor table growth @@ -280,31 +312,34 @@ Check in Supabase dashboard: ## Support & Troubleshooting **Notifications not showing?** + 1. Check NotificationBell is rendered in Layout.tsx 2. Verify Supabase subscription in browser console 3. Check notifications table for entries 4. Clear browser cache and reload **Real-time not working?** + 1. Check Supabase realtime enabled 2. Verify WebSocket connection in browser DevTools 3. Check RLS policies allow reading notifications 4. Restart browser and clear session **Spam notifications?** + 1. Check for duplicate inserts 2. Verify notification triggers have `try-catch` 3. Add deduplication logic (check for recent identical notifications) ## Files Summary -| File | Purpose | Lines | -|------|---------|-------| -| `code/server/index.ts` | Server endpoints with notifications | 4800+ | -| `code/client/lib/notification-triggers.ts` | Trigger utilities | 250+ | -| `code/client/lib/aethex-database-adapter.ts` | Service notifications | 2000+ | -| `code/client/components/notifications/NotificationBell.tsx` | UI display | 300+ | -| `code/api/_notifications.ts` | Backend helpers | 40+ | +| File | Purpose | Lines | +| ----------------------------------------------------------- | ----------------------------------- | ----- | +| `code/server/index.ts` | Server endpoints with notifications | 4800+ | +| `code/client/lib/notification-triggers.ts` | Trigger utilities | 250+ | +| `code/client/lib/aethex-database-adapter.ts` | Service notifications | 2000+ | +| `code/client/components/notifications/NotificationBell.tsx` | UI display | 300+ | +| `code/api/_notifications.ts` | Backend helpers | 40+ | **Total Notification Triggers: 20+** **Notification Types: 4** (success, info, warning, error) diff --git a/docs/NOTIFICATION-SYSTEM-IMPLEMENTATION.md b/docs/NOTIFICATION-SYSTEM-IMPLEMENTATION.md index a94269c6..0d1b8dbe 100644 --- a/docs/NOTIFICATION-SYSTEM-IMPLEMENTATION.md +++ b/docs/NOTIFICATION-SYSTEM-IMPLEMENTATION.md @@ -14,51 +14,61 @@ The notification system has been comprehensively implemented to provide real-tim ### Client-Side Services #### 1. `code/client/lib/aethex-database-adapter.ts` + **Achievement Notifications** + - Modified `aethexAchievementService.awardAchievement()`: - Sends notification: `🏆 Achievement Unlocked: {name}` with XP reward - Type: "success" **Profile Update Notifications** + - Modified `aethexUserService.updateProfile()`: - Sends notification when `onboarded: true` - Message: `🎉 Welcome to AeThex! You've completed your profile setup. Let's get started!` - Type: "success" **Level Up Notifications** + - Modified `aethexAchievementService.updateUserXPAndLevel()`: - Sends notification when level increases - Message: `âŦ†ī¸ Level Up! You've reached level {newLevel}!` - Type: "success" **Project Notifications** + - Modified `aethexProjectService.createProject()`: - Sends notification: `🚀 Project Created: {name}` - Type: "success" - - Modified `aethexProjectService.updateProject()`: - Sends notification on completion: `✅ Project Completed: {name}` - Sends notification on start: `âąī¸ Project Started: {name}` - Type: "success" or "info" #### 2. `code/client/lib/aethex-collab-service.ts` + **Team Notifications** + - Modified `aethexCollabService.createTeam()`: - Sends notification: `đŸŽ¯ Team Created: {name}` - Type: "success" **Team Member Notifications** + - Modified `aethexCollabService.addTeamMember()`: - Sends notification: `đŸ‘Ĩ Added to Team: {name}` - Type: "info" **Project Member Notifications** + - Modified `aethexCollabService.addProjectMember()`: - Sends notification: `📌 Added to Project: {name}` - Type: "info" #### 3. `code/client/pages/Onboarding.tsx` + **Onboarding Notifications** + - Added notification on onboarding completion - Message: `🎉 Welcome to AeThex! You've completed your profile setup. Let's get started!` - Type: "success" @@ -66,13 +76,17 @@ The notification system has been comprehensively implemented to provide real-tim ### Backend API Endpoints #### 1. `code/api/_notifications.ts` (NEW) + Central notification utility for backend processes: + - `createNotification(userId, type, title, message)` - Generic notification creator - `notifyAccountLinked(userId, provider)` - For OAuth linking - `notifyOnboardingComplete(userId)` - For onboarding completion #### 2. `code/api/discord/oauth/callback.ts` + **Discord Account Linking** + - Added import: `notifyAccountLinked` from `_notifications` - Sends notification when Discord is linked (both linking and login flows) - Message: `🔗 Account Linked: Discord` @@ -81,26 +95,28 @@ Central notification utility for backend processes: ### Utility Module #### `code/client/lib/notification-triggers.ts` (NEW) + Centralized notification trigger utilities for consistent notification handling across the app: ```typescript -notificationTriggers.achievementUnlocked(userId, name, xp) -notificationTriggers.teamCreated(userId, teamName) -notificationTriggers.addedToTeam(userId, teamName, role) -notificationTriggers.projectCreated(userId, projectName) -notificationTriggers.addedToProject(userId, projectName, role) -notificationTriggers.projectCompleted(userId, projectName) -notificationTriggers.projectStarted(userId, projectName) -notificationTriggers.levelUp(userId, newLevel) -notificationTriggers.onboardingComplete(userId) -notificationTriggers.accountLinked(userId, provider) -notificationTriggers.emailVerified(userId) -notificationTriggers.customNotification(userId, type, title, message) +notificationTriggers.achievementUnlocked(userId, name, xp); +notificationTriggers.teamCreated(userId, teamName); +notificationTriggers.addedToTeam(userId, teamName, role); +notificationTriggers.projectCreated(userId, projectName); +notificationTriggers.addedToProject(userId, projectName, role); +notificationTriggers.projectCompleted(userId, projectName); +notificationTriggers.projectStarted(userId, projectName); +notificationTriggers.levelUp(userId, newLevel); +notificationTriggers.onboardingComplete(userId); +notificationTriggers.accountLinked(userId, provider); +notificationTriggers.emailVerified(userId); +notificationTriggers.customNotification(userId, type, title, message); ``` ## Notification Types ### Success (Green) đŸŸĸ + - Achievement unlocked - Team/project created - Project completed @@ -110,18 +126,22 @@ notificationTriggers.customNotification(userId, type, title, message) - Email verified ### Info (Blue) đŸ”ĩ + - Added to team/project - Project started ### Warning (Yellow) 🟡 + - (Available for future use) ### Error (Red) 🔴 + - (Available for future use) ## Real-Time Features All notifications are: + 1. **Real-time** - Delivered via Supabase realtime subscription (in NotificationBell component) 2. **Persistent** - Stored in `notifications` table with timestamps 3. **Readable** - Users can mark notifications as read @@ -130,7 +150,9 @@ All notifications are: ## Notification Display Notifications appear in: + 1. **NotificationBell Component** (`code/client/components/notifications/NotificationBell.tsx`) + - Dropdown with all notifications - Shows unread count badge - Real-time updates via subscription @@ -146,23 +168,24 @@ Notifications appear in: ### When Notifications Are Created -| Event | Service | Method | Type | -|-------|---------|--------|------| -| Achievement earned | AethexAchievementService | awardAchievement() | success | -| Team created | AethexCollabService | createTeam() | success | -| User added to team | AethexCollabService | addTeamMember() | info | -| Project created | AethexProjectService | createProject() | success | -| User added to project | AethexCollabService | addProjectMember() | info | -| Project status: completed | AethexProjectService | updateProject() | success | -| Project status: in_progress | AethexProjectService | updateProject() | info | -| Level increased | AethexAchievementService | updateUserXPAndLevel() | success | -| Onboarding completed | Onboarding page | finishOnboarding() | success | -| Discord linked | Discord OAuth | callback.ts | success | -| Profile updated (onboarded) | AethexUserService | updateProfile() | success | +| Event | Service | Method | Type | +| --------------------------- | ------------------------ | ---------------------- | ------- | +| Achievement earned | AethexAchievementService | awardAchievement() | success | +| Team created | AethexCollabService | createTeam() | success | +| User added to team | AethexCollabService | addTeamMember() | info | +| Project created | AethexProjectService | createProject() | success | +| User added to project | AethexCollabService | addProjectMember() | info | +| Project status: completed | AethexProjectService | updateProject() | success | +| Project status: in_progress | AethexProjectService | updateProject() | info | +| Level increased | AethexAchievementService | updateUserXPAndLevel() | success | +| Onboarding completed | Onboarding page | finishOnboarding() | success | +| Discord linked | Discord OAuth | callback.ts | success | +| Profile updated (onboarded) | AethexUserService | updateProfile() | success | ## Error Handling All notification creation is **non-blocking**: + - Wrapped in try-catch blocks - Logged to console if failures occur - Does not prevent main operation from completing @@ -173,16 +196,19 @@ All notification creation is **non-blocking**: Potential notification triggers for future implementation: 1. **Social Features** + - New follower - Post liked/commented - Mentioned in post 2. **Collaboration** + - Task assigned - Comment on project - Team invitation 3. **Notifications** + - Email verification needed - Session expiration warning - Security alerts @@ -197,20 +223,24 @@ Potential notification triggers for future implementation: ### Manual Testing Steps 1. **Achievement Notification** + - Go to Dashboard - Trigger an achievement (e.g., create first project for "Portfolio Creator") - Check NotificationBell for 🏆 icon 2. **Team Notification** + - Create a new team - Check NotificationBell for đŸŽ¯ icon 3. **Discord Linking** + - Go to Dashboard > Connections - Link Discord account - Check NotificationBell for 🔗 icon 4. **Onboarding Notification** + - Sign up new account - Complete onboarding - Should see 🎉 notification after finishing @@ -223,6 +253,7 @@ Potential notification triggers for future implementation: ### Monitoring Check Supabase dashboard: + - Navigate to `notifications` table - Filter by user_id to see all notifications for a user - Verify type, title, message fields are populated correctly @@ -276,6 +307,7 @@ CREATE INDEX notifications_user_created_idx ON notifications(user_id, created_at ## Support For issues or questions about the notification system: + 1. Check NotificationBell component for display issues 2. Check Supabase console for database errors 3. Check browser console for JavaScript errors diff --git a/server/index.ts b/server/index.ts index 32cfcda6..af88c5d5 100644 --- a/server/index.ts +++ b/server/index.ts @@ -2802,7 +2802,10 @@ export function createServer() { .eq("id", user_id) .single(); - const likerName = (liker as any)?.full_name || (liker as any)?.username || "Someone"; + const likerName = + (liker as any)?.full_name || + (liker as any)?.username || + "Someone"; await adminSupabase.from("notifications").insert({ user_id: post.user_id, type: "info", @@ -2917,8 +2920,12 @@ export function createServer() { .eq("id", user_id) .single(); - const commenterName = (commenter as any)?.full_name || (commenter as any)?.username || "Someone"; - const preview = content.substring(0, 50) + (content.length > 50 ? "..." : ""); + const commenterName = + (commenter as any)?.full_name || + (commenter as any)?.username || + "Someone"; + const preview = + content.substring(0, 50) + (content.length > 50 ? "..." : ""); await adminSupabase.from("notifications").insert({ user_id: post.user_id, type: "info", @@ -4334,7 +4341,10 @@ export function createServer() { message: `${creatorProfile?.full_name || "A creator"} applied for your opportunity.`, }); } catch (notifError) { - console.warn("Failed to create application notification:", notifError); + console.warn( + "Failed to create application notification:", + notifError, + ); } } @@ -4409,14 +4419,31 @@ export function createServer() { .single(); if (applicantProfile?.user_id) { - const statusEmoji = status === "accepted" ? "✅" : status === "rejected" ? "❌" : "📝"; - const statusMessage = status === "accepted" ? "accepted" : status === "rejected" ? "rejected" : "updated"; + const statusEmoji = + status === "accepted" + ? "✅" + : status === "rejected" + ? "❌" + : "📝"; + const statusMessage = + status === "accepted" + ? "accepted" + : status === "rejected" + ? "rejected" + : "updated"; await adminSupabase.from("notifications").insert({ user_id: applicantProfile.user_id, - type: status === "accepted" ? "success" : status === "rejected" ? "error" : "info", + type: + status === "accepted" + ? "success" + : status === "rejected" + ? "error" + : "info", title: `${statusEmoji} Application ${statusMessage}`, - message: response_message || `Your application has been ${statusMessage}.`, + message: + response_message || + `Your application has been ${statusMessage}.`, }); } } catch (notifError) { @@ -4646,10 +4673,19 @@ export function createServer() { // Task assignment with notification app.post("/api/tasks", async (req, res) => { try { - const { project_id, title, description, assignee_id, due_date, user_id } = req.body; + const { + project_id, + title, + description, + assignee_id, + due_date, + user_id, + } = req.body; if (!project_id || !title || !user_id) { - return res.status(400).json({ error: "project_id, title, and user_id required" }); + return res + .status(400) + .json({ error: "project_id, title, and user_id required" }); } const { data, error } = await adminSupabase @@ -4676,7 +4712,10 @@ export function createServer() { .eq("id", user_id) .single(); - const assignerName = (assigner as any)?.full_name || (assigner as any)?.username || "Someone"; + const assignerName = + (assigner as any)?.full_name || + (assigner as any)?.username || + "Someone"; await adminSupabase.from("notifications").insert({ user_id: assignee_id, type: "info", @@ -4702,7 +4741,9 @@ export function createServer() { const { assignee_id, user_id } = req.body; if (!taskId || !assignee_id || !user_id) { - return res.status(400).json({ error: "task id, assignee_id, and user_id required" }); + return res + .status(400) + .json({ error: "task id, assignee_id, and user_id required" }); } const { data: task } = await adminSupabase @@ -4732,7 +4773,10 @@ export function createServer() { .eq("id", user_id) .single(); - const assignerName = (assigner as any)?.full_name || (assigner as any)?.username || "Someone"; + const assignerName = + (assigner as any)?.full_name || + (assigner as any)?.username || + "Someone"; await adminSupabase.from("notifications").insert({ user_id: assignee_id, type: "info", @@ -4753,10 +4797,15 @@ export function createServer() { // Moderation report with staff notification app.post("/api/moderation/reports", async (req, res) => { try { - const { reported_user_id, report_type, description, reporter_id } = req.body; + const { reported_user_id, report_type, description, reporter_id } = + req.body; if (!reported_user_id || !report_type || !reporter_id) { - return res.status(400).json({ error: "reported_user_id, report_type, and reporter_id required" }); + return res + .status(400) + .json({ + error: "reported_user_id, report_type, and reporter_id required", + }); } const { data, error } = await adminSupabase