From 8a94eb1785fc41629d919b057fc517617f6c4d01 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Sat, 15 Nov 2025 16:38:40 +0000 Subject: [PATCH] Prettier format pending files --- api/devlink/opportunities.ts | 6 +- api/devlink/profile.ts | 10 +- api/devlink/teams.ts | 6 +- api/foundation/courses.ts | 15 +- api/foundation/mentorships.ts | 21 +- api/foundation/progress.ts | 26 +- api/gameforge/sprint.ts | 6 +- api/gameforge/tasks.ts | 6 +- api/labs/bounties.ts | 6 +- api/labs/ip-portfolio.ts | 6 +- api/labs/publications.ts | 6 +- api/labs/research-tracks.ts | 6 +- api/nexus/client/applicants.ts | 13 +- api/nexus/client/contracts.ts | 17 +- api/nexus/client/opportunities.ts | 20 +- api/nexus/creator/applications.ts | 19 +- api/nexus/creator/contracts.ts | 19 +- api/nexus/creator/payouts.ts | 21 +- api/nexus/creator/profile.ts | 7 +- api/staff/directory.ts | 6 +- api/staff/invoices.ts | 6 +- api/staff/me.ts | 6 +- api/staff/okrs.ts | 6 +- api/user/arm-affiliations.ts | 31 +- api/user/profile-update.ts | 58 ++- client/App.tsx | 25 +- client/components/AchievementsWidget.tsx | 36 +- client/components/ApplicantTrackerWidget.tsx | 45 ++- client/components/ApplicationsWidget.tsx | 93 +++-- client/components/CTAButtonGroup.tsx | 23 +- client/components/ContractsWidget.tsx | 39 +- client/components/CoursesWidget.tsx | 74 +++- client/components/DashboardTheme.tsx | 33 +- client/components/DirectoryWidget.tsx | 28 +- client/components/EthosStorefrontWidget.tsx | 32 +- client/components/KanbanBoard.tsx | 51 ++- client/components/MentorshipWidget.tsx | 48 ++- client/components/OpportunitiesWidget.tsx | 21 +- client/components/PayoutsWidget.tsx | 62 ++- .../components/PostedOpportunitiesWidget.tsx | 49 ++- client/components/ProfileEditor.tsx | 136 +++++-- client/components/ProjectStatusWidget.tsx | 81 +++- client/components/ResearchWidget.tsx | 64 ++- client/components/SprintWidget.tsx | 60 ++- client/components/TeamWidget.tsx | 16 +- client/lib/arm-affiliation-service.ts | 93 +++-- client/pages/Dashboard.tsx | 89 +++- client/pages/dashboards/DevLinkDashboard.tsx | 183 +++++++-- .../pages/dashboards/FoundationDashboard.tsx | 114 ++++-- .../pages/dashboards/GameForgeDashboard.tsx | 201 +++++++--- client/pages/dashboards/LabsDashboard.tsx | 187 +++++++-- client/pages/dashboards/NexusDashboard.tsx | 368 ++++++++++++----- client/pages/dashboards/StaffDashboard.tsx | 209 +++++++--- client/pages/hub/ClientHub.tsx | 379 +++++++++++++----- 54 files changed, 2409 insertions(+), 779 deletions(-) diff --git a/api/devlink/opportunities.ts b/api/devlink/opportunities.ts index 52a42a54..db79b68a 100644 --- a/api/devlink/opportunities.ts +++ b/api/devlink/opportunities.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: opportunities, error } = await supabase .from("devlink_opportunities") - .select(` + .select( + ` id, title, description, @@ -27,7 +28,8 @@ export default async (req: Request) => { status, skills_required, created_at - `) + `, + ) .eq("status", "open") .eq("type", "roblox") .order("created_at", { ascending: false }); diff --git a/api/devlink/profile.ts b/api/devlink/profile.ts index 9eb80d05..7ce5150e 100644 --- a/api/devlink/profile.ts +++ b/api/devlink/profile.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: profile, error } = await supabase .from("devlink_profiles") - .select(` + .select( + ` id, user_id, username, @@ -28,7 +29,8 @@ export default async (req: Request) => { certifications, created_at, updated_at - `) + `, + ) .eq("user_id", userData.user.id) .single(); @@ -46,7 +48,9 @@ export default async (req: Request) => { .insert([ { user_id: userData.user.id, - username: userData.user.user_metadata?.username || userData.user.email?.split("@")[0], + username: + userData.user.user_metadata?.username || + userData.user.email?.split("@")[0], profile_views: 0, }, ]) diff --git a/api/devlink/teams.ts b/api/devlink/teams.ts index e4400f72..a25d24d1 100644 --- a/api/devlink/teams.ts +++ b/api/devlink/teams.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: teams, error } = await supabase .from("devlink_teams") - .select(` + .select( + ` id, name, description, @@ -31,7 +32,8 @@ export default async (req: Request) => { full_name, avatar_url ) - `) + `, + ) .contains("members", [{ user_id: userData.user.id }]) .order("created_at", { ascending: false }); diff --git a/api/foundation/courses.ts b/api/foundation/courses.ts index 886e7879..0f950a4d 100644 --- a/api/foundation/courses.ts +++ b/api/foundation/courses.ts @@ -10,7 +10,10 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { if (authHeader) { const token = authHeader.replace("Bearer ", ""); - const { data: { user }, error: authError } = await admin.auth.getUser(token); + const { + data: { user }, + error: authError, + } = await admin.auth.getUser(token); if (!authError && user) { userId = user.id; } @@ -21,10 +24,12 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { // List all published courses const { data: courses, error: coursesError } = await admin .from("foundation_courses") - .select(` + .select( + ` *, instructor:user_profiles(id, full_name, avatar_url) - `) + `, + ) .eq("is_published", true) .order("order_index", { ascending: true }); @@ -42,7 +47,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { if (userEnrollments) { enrollments = Object.fromEntries( - userEnrollments.map((e: any) => [e.course_id, e]) + userEnrollments.map((e: any) => [e.course_id, e]), ); } } @@ -76,7 +81,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { status: "in_progress", enrolled_at: new Date().toISOString(), }, - { onConflict: "user_id,course_id" } + { onConflict: "user_id,course_id" }, ) .select() .single(); diff --git a/api/foundation/mentorships.ts b/api/foundation/mentorships.ts index 34bd55f3..40665d92 100644 --- a/api/foundation/mentorships.ts +++ b/api/foundation/mentorships.ts @@ -11,7 +11,10 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const token = authHeader.replace("Bearer ", ""); - const { data: { user }, error: authError } = await admin.auth.getUser(token); + const { + data: { user }, + error: authError, + } = await admin.auth.getUser(token); if (authError || !user) { return res.status(401).json({ error: "Invalid token" }); @@ -26,20 +29,24 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { if (role === "mentor") { const { data: m } = await admin .from("foundation_mentorships") - .select(` + .select( + ` *, mentee:user_profiles!mentee_id(id, full_name, avatar_url, email) - `) + `, + ) .eq("mentor_id", user.id) .order("created_at", { ascending: false }); mentorships = m; } else if (role === "mentee") { const { data: m } = await admin .from("foundation_mentorships") - .select(` + .select( + ` *, mentor:user_profiles!mentor_id(id, full_name, avatar_url, email) - `) + `, + ) .eq("mentee_id", user.id) .order("created_at", { ascending: false }); mentorships = m; @@ -49,7 +56,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { .from("foundation_mentorships") .select( `*, - mentee:user_profiles!mentee_id(id, full_name, avatar_url, email)` + mentee:user_profiles!mentee_id(id, full_name, avatar_url, email)`, ) .eq("mentor_id", user.id); @@ -57,7 +64,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { .from("foundation_mentorships") .select( `*, - mentor:user_profiles!mentor_id(id, full_name, avatar_url, email)` + mentor:user_profiles!mentor_id(id, full_name, avatar_url, email)`, ) .eq("mentee_id", user.id); diff --git a/api/foundation/progress.ts b/api/foundation/progress.ts index 574189ad..2f87f6b0 100644 --- a/api/foundation/progress.ts +++ b/api/foundation/progress.ts @@ -11,7 +11,10 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const token = authHeader.replace("Bearer ", ""); - const { data: { user }, error: authError } = await admin.auth.getUser(token); + const { + data: { user }, + error: authError, + } = await admin.auth.getUser(token); if (authError || !user) { return res.status(401).json({ error: "Invalid token" }); @@ -41,18 +44,21 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { // Get lesson progress const { data: lessonProgress } = await admin .from("foundation_lesson_progress") - .select(` + .select( + ` *, lesson:foundation_course_lessons(id, title, order_index) - `) + `, + ) .eq("user_id", user.id) - .in("lesson_id", + .in( + "lesson_id", // Get lesson IDs for this course - (await admin + await admin .from("foundation_course_lessons") .select("id") .eq("course_id", courseId) - .then(r => r.data?.map((l: any) => l.id) || [])) + .then((r) => r.data?.map((l: any) => l.id) || []), ); return res.status(200).json({ @@ -66,7 +72,9 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { const { lesson_id, course_id, completed } = req.body; if (!lesson_id || !course_id) { - return res.status(400).json({ error: "lesson_id and course_id required" }); + return res + .status(400) + .json({ error: "lesson_id and course_id required" }); } if (completed) { @@ -103,7 +111,9 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { .in("lesson_id", lessonsData?.map((l: any) => l.id) || []); const completedCount = completedData?.length || 0; - const progressPercent = Math.round((completedCount / totalLessons) * 100); + const progressPercent = Math.round( + (completedCount / totalLessons) * 100, + ); // Update enrollment progress await admin diff --git a/api/gameforge/sprint.ts b/api/gameforge/sprint.ts index 232da135..e7f0936b 100644 --- a/api/gameforge/sprint.ts +++ b/api/gameforge/sprint.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: sprint, error } = await supabase .from("gameforge_sprints") - .select(` + .select( + ` id, project_id, title, @@ -29,7 +30,8 @@ export default async (req: Request) => { deadline, gdd, scope - `) + `, + ) .eq("user_id", userData.user.id) .order("created_at", { ascending: false }) .limit(1) diff --git a/api/gameforge/tasks.ts b/api/gameforge/tasks.ts index be8a14c6..140cb8c0 100644 --- a/api/gameforge/tasks.ts +++ b/api/gameforge/tasks.ts @@ -21,7 +21,8 @@ export default async (req: Request) => { let query = supabase .from("gameforge_tasks") - .select(` + .select( + ` id, title, description, @@ -34,7 +35,8 @@ export default async (req: Request) => { priority, due_date, created_at - `) + `, + ) .eq("created_by_id", userData.user.id); if (sprintId) { diff --git a/api/labs/bounties.ts b/api/labs/bounties.ts index 9ffd8fb3..20dda45f 100644 --- a/api/labs/bounties.ts +++ b/api/labs/bounties.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: bounties, error } = await supabase .from("labs_bounties") - .select(` + .select( + ` id, title, description, @@ -27,7 +28,8 @@ export default async (req: Request) => { status, research_track_id, created_at - `) + `, + ) .eq("status", "available") .order("reward", { ascending: false }); diff --git a/api/labs/ip-portfolio.ts b/api/labs/ip-portfolio.ts index 6e5c390c..4fdb3e2c 100644 --- a/api/labs/ip-portfolio.ts +++ b/api/labs/ip-portfolio.ts @@ -32,7 +32,8 @@ export default async (req: Request) => { // Fetch IP portfolio (all projects' IP counts) const { data: portfolio, error } = await supabase .from("labs_ip_portfolio") - .select(` + .select( + ` id, patents_count, trademarks_count, @@ -40,7 +41,8 @@ export default async (req: Request) => { copyrights_count, created_at, updated_at - `) + `, + ) .single(); if (error && error.code !== "PGRST116") { diff --git a/api/labs/publications.ts b/api/labs/publications.ts index 631eb36a..8d7350a6 100644 --- a/api/labs/publications.ts +++ b/api/labs/publications.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: publications, error } = await supabase .from("labs_publications") - .select(` + .select( + ` id, title, description, @@ -27,7 +28,8 @@ export default async (req: Request) => { published_date, research_track_id, created_at - `) + `, + ) .order("published_date", { ascending: false }); if (error) { diff --git a/api/labs/research-tracks.ts b/api/labs/research-tracks.ts index 172e370d..be7ede52 100644 --- a/api/labs/research-tracks.ts +++ b/api/labs/research-tracks.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: tracks, error } = await supabase .from("labs_research_tracks") - .select(` + .select( + ` id, title, description, @@ -33,7 +34,8 @@ export default async (req: Request) => { publications, whitepaper_url, created_at - `) + `, + ) .order("created_at", { ascending: false }); if (error) { diff --git a/api/nexus/client/applicants.ts b/api/nexus/client/applicants.ts index 8561df42..4ccdb5c3 100644 --- a/api/nexus/client/applicants.ts +++ b/api/nexus/client/applicants.ts @@ -15,7 +15,10 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const token = authHeader.replace("Bearer ", ""); - const { data: { user }, error: authError } = await admin.auth.getUser(token); + const { + data: { user }, + error: authError, + } = await admin.auth.getUser(token); if (authError || !user) { return res.status(401).json({ error: "Invalid token" }); @@ -49,7 +52,8 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { // Get applicants let query = admin .from("nexus_applications") - .select(` + .select( + ` *, creator:user_profiles( id, @@ -64,7 +68,8 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { rating, review_count ) - `) + `, + ) .eq("opportunity_id", opportunityId) .order("created_at", { ascending: false }); @@ -74,7 +79,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { const { data: applications, error: appError } = await query.range( offset, - offset + limit - 1 + offset + limit - 1, ); if (appError) { diff --git a/api/nexus/client/contracts.ts b/api/nexus/client/contracts.ts index df354598..02dfb059 100644 --- a/api/nexus/client/contracts.ts +++ b/api/nexus/client/contracts.ts @@ -15,7 +15,10 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const token = authHeader.replace("Bearer ", ""); - const { data: { user }, error: authError } = await admin.auth.getUser(token); + const { + data: { user }, + error: authError, + } = await admin.auth.getUser(token); if (authError || !user) { return res.status(401).json({ error: "Invalid token" }); @@ -28,7 +31,8 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { let query = admin .from("nexus_contracts") - .select(` + .select( + ` *, creator:user_profiles( id, @@ -38,7 +42,8 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { ), milestones:nexus_milestones(*), payments:nexus_payments(*) - `) + `, + ) .eq("client_id", user.id) .order("created_at", { ascending: false }); @@ -48,7 +53,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { const { data: contracts, error: contractsError } = await query.range( offset, - offset + limit - 1 + offset + limit - 1, ); if (contractsError) { @@ -63,11 +68,11 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { const totalSpent = (allContracts || []).reduce( (sum: number, c: any) => sum + (c.total_amount || 0), - 0 + 0, ); const activeContracts = (allContracts || []).filter( - (c: any) => c.status === "active" + (c: any) => c.status === "active", ).length; return res.status(200).json({ diff --git a/api/nexus/client/opportunities.ts b/api/nexus/client/opportunities.ts index 3b1d91bd..62b870c3 100644 --- a/api/nexus/client/opportunities.ts +++ b/api/nexus/client/opportunities.ts @@ -11,7 +11,10 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const token = authHeader.replace("Bearer ", ""); - const { data: { user }, error: authError } = await admin.auth.getUser(token); + const { + data: { user }, + error: authError, + } = await admin.auth.getUser(token); if (authError || !user) { return res.status(401).json({ error: "Invalid token" }); @@ -26,10 +29,12 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { let query = admin .from("nexus_opportunities") - .select(` + .select( + ` *, applications:nexus_applications(id, status, creator_id) - `) + `, + ) .eq("posted_by", user.id) .order("created_at", { ascending: false }); @@ -39,7 +44,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { const { data: opportunities, error: oppError } = await query.range( offset, - offset + limit - 1 + offset + limit - 1, ); if (oppError) { @@ -72,7 +77,8 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { if (!title || !description || !category || !budget_type) { return res.status(400).json({ - error: "Missing required fields: title, description, category, budget_type", + error: + "Missing required fields: title, description, category, budget_type", }); } @@ -83,7 +89,9 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { title, description, category, - required_skills: Array.isArray(required_skills) ? required_skills : [], + required_skills: Array.isArray(required_skills) + ? required_skills + : [], budget_type, budget_min: budget_min || null, budget_max: budget_max || null, diff --git a/api/nexus/creator/applications.ts b/api/nexus/creator/applications.ts index e598d0b1..9431ed28 100644 --- a/api/nexus/creator/applications.ts +++ b/api/nexus/creator/applications.ts @@ -15,7 +15,10 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const token = authHeader.replace("Bearer ", ""); - const { data: { user }, error: authError } = await admin.auth.getUser(token); + const { + data: { user }, + error: authError, + } = await admin.auth.getUser(token); if (authError || !user) { return res.status(401).json({ error: "Invalid token" }); @@ -28,7 +31,8 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { let query = admin .from("nexus_applications") - .select(` + .select( + ` *, opportunity:nexus_opportunities( id, @@ -43,7 +47,8 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { posted_by, created_at ) - `) + `, + ) .eq("creator_id", user.id) .order("created_at", { ascending: false }); @@ -51,9 +56,13 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { query = query.eq("status", status); } - const { data: applications, error: applicationsError, count } = await query + const { + data: applications, + error: applicationsError, + count, + } = await query .range(offset, offset + limit - 1) - .then(result => ({ ...result, count: result.data?.length || 0 })); + .then((result) => ({ ...result, count: result.data?.length || 0 })); if (applicationsError) { return res.status(500).json({ error: applicationsError.message }); diff --git a/api/nexus/creator/contracts.ts b/api/nexus/creator/contracts.ts index 17e529ab..e63c209e 100644 --- a/api/nexus/creator/contracts.ts +++ b/api/nexus/creator/contracts.ts @@ -15,7 +15,10 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const token = authHeader.replace("Bearer ", ""); - const { data: { user }, error: authError } = await admin.auth.getUser(token); + const { + data: { user }, + error: authError, + } = await admin.auth.getUser(token); if (authError || !user) { return res.status(401).json({ error: "Invalid token" }); @@ -28,12 +31,14 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { let query = admin .from("nexus_contracts") - .select(` + .select( + ` *, client:user_profiles(id, full_name, avatar_url), milestones:nexus_milestones(*), payments:nexus_payments(*) - `) + `, + ) .eq("creator_id", user.id) .order("created_at", { ascending: false }); @@ -41,9 +46,13 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { query = query.eq("status", status); } - const { data: contracts, error: contractsError, count } = await query + const { + data: contracts, + error: contractsError, + count, + } = await query .range(offset, offset + limit - 1) - .then(result => ({ ...result, count: result.data?.length || 0 })); + .then((result) => ({ ...result, count: result.data?.length || 0 })); if (contractsError) { return res.status(500).json({ error: contractsError.message }); diff --git a/api/nexus/creator/payouts.ts b/api/nexus/creator/payouts.ts index 20168e87..097816db 100644 --- a/api/nexus/creator/payouts.ts +++ b/api/nexus/creator/payouts.ts @@ -15,7 +15,10 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const token = authHeader.replace("Bearer ", ""); - const { data: { user }, error: authError } = await admin.auth.getUser(token); + const { + data: { user }, + error: authError, + } = await admin.auth.getUser(token); if (authError || !user) { return res.status(401).json({ error: "Invalid token" }); @@ -29,7 +32,8 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { // Get payments for creator's contracts let query = admin .from("nexus_payments") - .select(` + .select( + ` *, contract:nexus_contracts( id, @@ -40,7 +44,8 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { created_at ), milestone:nexus_milestones(id, description, amount, status) - `) + `, + ) .eq("contract.creator_id", user.id) .order("created_at", { ascending: false }); @@ -50,7 +55,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { const { data: payments, error: paymentsError } = await query.range( offset, - offset + limit - 1 + offset + limit - 1, ); if (paymentsError) { @@ -63,11 +68,13 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { .select("total_amount, creator_payout_amount, status") .eq("creator_id", user.id); - const totalEarnings = (contracts || []) - .reduce((sum: number, c: any) => sum + (c.creator_payout_amount || 0), 0); + const totalEarnings = (contracts || []).reduce( + (sum: number, c: any) => sum + (c.creator_payout_amount || 0), + 0, + ); const completedContracts = (contracts || []).filter( - (c: any) => c.status === "completed" + (c: any) => c.status === "completed", ).length; const pendingPayouts = (payments || []) diff --git a/api/nexus/creator/profile.ts b/api/nexus/creator/profile.ts index 0274894b..dd879ee4 100644 --- a/api/nexus/creator/profile.ts +++ b/api/nexus/creator/profile.ts @@ -11,7 +11,10 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { } const token = authHeader.replace("Bearer ", ""); - const { data: { user }, error: authError } = await admin.auth.getUser(token); + const { + data: { user }, + error: authError, + } = await admin.auth.getUser(token); if (authError || !user) { return res.status(401).json({ error: "Invalid token" }); @@ -84,7 +87,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { availability_status: availability_status || "available", availability_hours_per_week: availability_hours_per_week || null, }, - { onConflict: "user_id" } + { onConflict: "user_id" }, ) .select() .single(); diff --git a/api/staff/directory.ts b/api/staff/directory.ts index 8c126cb3..234125c7 100644 --- a/api/staff/directory.ts +++ b/api/staff/directory.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: directory, error } = await supabase .from("staff_members") - .select(` + .select( + ` id, user_id, full_name, @@ -31,7 +32,8 @@ export default async (req: Request) => { location, username, created_at - `) + `, + ) .order("full_name", { ascending: true }); if (error) { diff --git a/api/staff/invoices.ts b/api/staff/invoices.ts index 4cf72b3f..2c98eae2 100644 --- a/api/staff/invoices.ts +++ b/api/staff/invoices.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: invoices, error } = await supabase .from("contractor_invoices") - .select(` + .select( + ` id, user_id, invoice_number, @@ -28,7 +29,8 @@ export default async (req: Request) => { due_date, description, created_at - `) + `, + ) .eq("user_id", userData.user.id) .order("date", { ascending: false }); diff --git a/api/staff/me.ts b/api/staff/me.ts index 0dd19ec8..077e2223 100644 --- a/api/staff/me.ts +++ b/api/staff/me.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: staffMember, error } = await supabase .from("staff_members") - .select(` + .select( + ` id, user_id, full_name, @@ -30,7 +31,8 @@ export default async (req: Request) => { salary, avatar_url, created_at - `) + `, + ) .eq("user_id", userData.user.id) .single(); diff --git a/api/staff/okrs.ts b/api/staff/okrs.ts index 8bd6b3ee..d86a62aa 100644 --- a/api/staff/okrs.ts +++ b/api/staff/okrs.ts @@ -18,7 +18,8 @@ export default async (req: Request) => { const { data: okrs, error } = await supabase .from("staff_okrs") - .select(` + .select( + ` id, user_id, objective, @@ -33,7 +34,8 @@ export default async (req: Request) => { target_value ), created_at - `) + `, + ) .eq("user_id", userData.user.id) .order("created_at", { ascending: false }); diff --git a/api/user/arm-affiliations.ts b/api/user/arm-affiliations.ts index 828f3da8..cbe0d772 100644 --- a/api/user/arm-affiliations.ts +++ b/api/user/arm-affiliations.ts @@ -1,7 +1,13 @@ import { supabase } from "../_supabase"; const VALID_ARMS = ["foundation", "gameforge", "labs", "corp", "devlink"]; -const VALID_TYPES = ["courses", "projects", "research", "opportunities", "manual"]; +const VALID_TYPES = [ + "courses", + "projects", + "research", + "opportunities", + "manual", +]; export default async (req: Request) => { try { @@ -28,7 +34,9 @@ export default async (req: Request) => { .order("created_at", { ascending: false }); if (error) { - return new Response(JSON.stringify({ error: error.message }), { status: 500 }); + return new Response(JSON.stringify({ error: error.message }), { + status: 500, + }); } return new Response(JSON.stringify(data), { @@ -42,7 +50,10 @@ export default async (req: Request) => { const body = await req.json(); const { arm, affiliation_type, affiliation_data, confirmed } = body; - if (!VALID_ARMS.includes(arm) || !VALID_TYPES.includes(affiliation_type)) { + if ( + !VALID_ARMS.includes(arm) || + !VALID_TYPES.includes(affiliation_type) + ) { return new Response("Invalid arm or affiliation type", { status: 400 }); } @@ -57,13 +68,15 @@ export default async (req: Request) => { affiliation_data: affiliation_data || {}, confirmed: confirmed === true, }, - { onConflict: "user_id,arm,affiliation_type" } + { onConflict: "user_id,arm,affiliation_type" }, ) .select() .single(); if (error) { - return new Response(JSON.stringify({ error: error.message }), { status: 500 }); + return new Response(JSON.stringify({ error: error.message }), { + status: 500, + }); } return new Response(JSON.stringify(data), { @@ -89,7 +102,9 @@ export default async (req: Request) => { .eq("affiliation_type", affiliation_type || null); if (error) { - return new Response(JSON.stringify({ error: error.message }), { status: 500 }); + return new Response(JSON.stringify({ error: error.message }), { + status: 500, + }); } return new Response(JSON.stringify({ success: true }), { @@ -101,6 +116,8 @@ export default async (req: Request) => { return new Response("Method not allowed", { status: 405 }); } catch (error: any) { console.error("Arm affiliations error:", error); - return new Response(JSON.stringify({ error: error.message }), { status: 500 }); + return new Response(JSON.stringify({ error: error.message }), { + status: 500, + }); } }; diff --git a/api/user/profile-update.ts b/api/user/profile-update.ts index 95ff48f7..839babce 100644 --- a/api/user/profile-update.ts +++ b/api/user/profile-update.ts @@ -25,21 +25,30 @@ export default async (req: Request) => { const updates: any = {}; // Profile fields - if ("bio_detailed" in body) updates.bio_detailed = body.bio_detailed || null; + if ("bio_detailed" in body) + updates.bio_detailed = body.bio_detailed || null; if ("twitter_url" in body) updates.twitter_url = body.twitter_url || null; - if ("linkedin_url" in body) updates.linkedin_url = body.linkedin_url || null; + if ("linkedin_url" in body) + updates.linkedin_url = body.linkedin_url || null; if ("github_url" in body) updates.github_url = body.github_url || null; - if ("portfolio_url" in body) updates.portfolio_url = body.portfolio_url || null; + if ("portfolio_url" in body) + updates.portfolio_url = body.portfolio_url || null; if ("youtube_url" in body) updates.youtube_url = body.youtube_url || null; if ("twitch_url" in body) updates.twitch_url = body.twitch_url || null; // Professional info if ("hourly_rate" in body) - updates.hourly_rate = body.hourly_rate ? parseFloat(body.hourly_rate) : null; + updates.hourly_rate = body.hourly_rate + ? parseFloat(body.hourly_rate) + : null; if ("availability_status" in body) - updates.availability_status = - ["available", "limited", "unavailable"].includes(body.availability_status) ? - body.availability_status : "available"; + updates.availability_status = [ + "available", + "limited", + "unavailable", + ].includes(body.availability_status) + ? body.availability_status + : "available"; if ("timezone" in body) updates.timezone = body.timezone || null; if ("location" in body) updates.location = body.location || null; @@ -48,25 +57,36 @@ export default async (req: Request) => { updates.languages = Array.isArray(body.languages) ? body.languages : []; } if ("skills_detailed" in body) { - updates.skills_detailed = Array.isArray(body.skills_detailed) ? body.skills_detailed : []; + updates.skills_detailed = Array.isArray(body.skills_detailed) + ? body.skills_detailed + : []; } if ("work_experience" in body) { - updates.work_experience = Array.isArray(body.work_experience) ? body.work_experience : []; + updates.work_experience = Array.isArray(body.work_experience) + ? body.work_experience + : []; } if ("portfolio_items" in body) { - updates.portfolio_items = Array.isArray(body.portfolio_items) ? body.portfolio_items : []; + updates.portfolio_items = Array.isArray(body.portfolio_items) + ? body.portfolio_items + : []; } if ("arm_affiliations" in body) { const validArms = ["foundation", "gameforge", "labs", "corp", "devlink"]; - updates.arm_affiliations = Array.isArray(body.arm_affiliations) ? - body.arm_affiliations.filter((a: string) => validArms.includes(a)) : []; + updates.arm_affiliations = Array.isArray(body.arm_affiliations) + ? body.arm_affiliations.filter((a: string) => validArms.includes(a)) + : []; } // Nexus specific - if ("nexus_profile_complete" in body) updates.nexus_profile_complete = body.nexus_profile_complete === true; - if ("nexus_headline" in body) updates.nexus_headline = body.nexus_headline || null; + if ("nexus_profile_complete" in body) + updates.nexus_profile_complete = body.nexus_profile_complete === true; + if ("nexus_headline" in body) + updates.nexus_headline = body.nexus_headline || null; if ("nexus_categories" in body) { - updates.nexus_categories = Array.isArray(body.nexus_categories) ? body.nexus_categories : []; + updates.nexus_categories = Array.isArray(body.nexus_categories) + ? body.nexus_categories + : []; } // Update the profile @@ -79,7 +99,9 @@ export default async (req: Request) => { if (error) { console.error("Profile update error:", error); - return new Response(JSON.stringify({ error: error.message }), { status: 500 }); + return new Response(JSON.stringify({ error: error.message }), { + status: 500, + }); } return new Response(JSON.stringify(data), { @@ -88,6 +110,8 @@ export default async (req: Request) => { }); } catch (error: any) { console.error("Profile update error:", error); - return new Response(JSON.stringify({ error: error.message }), { status: 500 }); + return new Response(JSON.stringify({ error: error.message }), { + status: 500, + }); } }; diff --git a/client/App.tsx b/client/App.tsx index 11a73e88..901ee7f3 100644 --- a/client/App.tsx +++ b/client/App.tsx @@ -192,11 +192,26 @@ const App = () => ( } /> } /> } /> - } /> - } /> - } /> - } /> - } /> + } + /> + } + /> + } + /> + } + /> + } + />

No achievements yet

-

Complete courses and challenges to earn badges

+

+ Complete courses and challenges to earn badges +

) : (
@@ -144,9 +164,7 @@ export function AchievementsWidget({ {/* Locked Achievements Placeholder */} {hasMore && ( -
+
diff --git a/client/components/ApplicantTrackerWidget.tsx b/client/components/ApplicantTrackerWidget.tsx index 07afb8c7..2573e948 100644 --- a/client/components/ApplicantTrackerWidget.tsx +++ b/client/components/ApplicantTrackerWidget.tsx @@ -1,8 +1,20 @@ import { useState } from "react"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { Users, MessageCircle, CheckCircle, Clock, ArrowRight } from "lucide-react"; +import { + Users, + MessageCircle, + CheckCircle, + Clock, + ArrowRight, +} from "lucide-react"; export interface Applicant { id: string; @@ -27,7 +39,10 @@ interface ApplicantTrackerWidgetProps { description?: string; onViewProfile?: (applicantId: string) => void; onMessage?: (applicantId: string) => void; - onUpdateStatus?: (applicantId: string, newStatus: "applied" | "interviewing" | "hired") => void; + onUpdateStatus?: ( + applicantId: string, + newStatus: "applied" | "interviewing" | "hired", + ) => void; accentColor?: "blue" | "purple" | "cyan" | "green"; } @@ -73,12 +88,16 @@ export function ApplicantTrackerWidget({ const [draggedApplicant, setDraggedApplicant] = useState(null); const statusCounts = { - applied: applicants.filter(a => a.status === "applied").length, - interviewing: applicants.filter(a => a.status === "interviewing").length, - hired: applicants.filter(a => a.status === "hired").length, + applied: applicants.filter((a) => a.status === "applied").length, + interviewing: applicants.filter((a) => a.status === "interviewing").length, + hired: applicants.filter((a) => a.status === "hired").length, }; - const allStatuses: Array<"applied" | "interviewing" | "hired"> = ["applied", "interviewing", "hired"]; + const allStatuses: Array<"applied" | "interviewing" | "hired"> = [ + "applied", + "interviewing", + "hired", + ]; const handleDragStart = (applicantId: string) => { setDraggedApplicant(applicantId); @@ -115,7 +134,9 @@ export function ApplicantTrackerWidget({ {allStatuses.map((status) => { const statusInfo = statusColors[status]; const StatusIcon = statusInfo.icon; - const statusApplicants = applicants.filter(a => a.status === status); + const statusApplicants = applicants.filter( + (a) => a.status === status, + ); return (
- {statusInfo.label} + + {statusInfo.label} +
-

{statusApplicants.length}

+

+ {statusApplicants.length} +

{/* Applicants List */} diff --git a/client/components/ApplicationsWidget.tsx b/client/components/ApplicationsWidget.tsx index b7524aea..45e23c3d 100644 --- a/client/components/ApplicationsWidget.tsx +++ b/client/components/ApplicationsWidget.tsx @@ -1,6 +1,18 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; -import { Briefcase, AlertCircle, CheckCircle, Clock, ArrowRight } from "lucide-react"; +import { + Briefcase, + AlertCircle, + CheckCircle, + Clock, + ArrowRight, +} from "lucide-react"; import { Button } from "@/components/ui/button"; export interface Application { @@ -70,11 +82,31 @@ const colorMap = { }; const statusMap = { - submitted: { color: "bg-blue-600/50 text-blue-100", icon: Clock, label: "Submitted" }, - pending: { color: "bg-yellow-600/50 text-yellow-100", icon: Clock, label: "Pending" }, - accepted: { color: "bg-green-600/50 text-green-100", icon: CheckCircle, label: "Accepted" }, - rejected: { color: "bg-red-600/50 text-red-100", icon: AlertCircle, label: "Rejected" }, - interview: { color: "bg-purple-600/50 text-purple-100", icon: Briefcase, label: "Interview" }, + submitted: { + color: "bg-blue-600/50 text-blue-100", + icon: Clock, + label: "Submitted", + }, + pending: { + color: "bg-yellow-600/50 text-yellow-100", + icon: Clock, + label: "Pending", + }, + accepted: { + color: "bg-green-600/50 text-green-100", + icon: CheckCircle, + label: "Accepted", + }, + rejected: { + color: "bg-red-600/50 text-red-100", + icon: AlertCircle, + label: "Rejected", + }, + interview: { + color: "bg-purple-600/50 text-purple-100", + icon: Briefcase, + label: "Interview", + }, }; export function ApplicationsWidget({ @@ -89,11 +121,11 @@ export function ApplicationsWidget({ }: ApplicationsWidgetProps) { const colors = colorMap[accentColor]; const statusCounts = { - submitted: applications.filter(a => a.status === "submitted").length, - pending: applications.filter(a => a.status === "pending").length, - accepted: applications.filter(a => a.status === "accepted").length, - rejected: applications.filter(a => a.status === "rejected").length, - interview: applications.filter(a => a.status === "interview").length, + submitted: applications.filter((a) => a.status === "submitted").length, + pending: applications.filter((a) => a.status === "pending").length, + accepted: applications.filter((a) => a.status === "accepted").length, + rejected: applications.filter((a) => a.status === "rejected").length, + interview: applications.filter((a) => a.status === "interview").length, }; return ( @@ -123,36 +155,47 @@ export function ApplicationsWidget({ ) : (
{/* Status Summary */} - {Object.entries(statusCounts).filter(([_, count]) => count > 0).length > 0 && ( + {Object.entries(statusCounts).filter(([_, count]) => count > 0) + .length > 0 && (
{statusCounts.submitted > 0 && (

Submitted

-

{statusCounts.submitted}

+

+ {statusCounts.submitted} +

)} {statusCounts.interview > 0 && (

Interview

-

{statusCounts.interview}

+

+ {statusCounts.interview} +

)} {statusCounts.accepted > 0 && (

Accepted

-

{statusCounts.accepted}

+

+ {statusCounts.accepted} +

)} {statusCounts.pending > 0 && (

Pending

-

{statusCounts.pending}

+

+ {statusCounts.pending} +

)} {statusCounts.rejected > 0 && (

Rejected

-

{statusCounts.rejected}

+

+ {statusCounts.rejected} +

)}
@@ -176,10 +219,14 @@ export function ApplicationsWidget({

- {app.opportunity?.title || app.title || "Untitled Opportunity"} + {app.opportunity?.title || + app.title || + "Untitled Opportunity"}

{app.opportunity?.category && ( -

{app.opportunity.category}

+

+ {app.opportunity.category} +

)}
@@ -216,11 +263,7 @@ export function ApplicationsWidget({
{showCTA && onCTA && applications.length > 0 && ( - diff --git a/client/components/CTAButtonGroup.tsx b/client/components/CTAButtonGroup.tsx index 6010c7e0..c67baf29 100644 --- a/client/components/CTAButtonGroup.tsx +++ b/client/components/CTAButtonGroup.tsx @@ -46,15 +46,15 @@ export function CTAButtonGroup({ btn.size === "sm" ? "text-sm px-3 py-1" : btn.size === "lg" - ? "text-lg px-6 py-3" - : "px-4 py-2"; + ? "text-lg px-6 py-3" + : "px-4 py-2"; const variantClass = btn.variant === "outline" ? "border border-opacity-30 text-opacity-75 hover:bg-opacity-10" : btn.variant === "secondary" - ? "bg-opacity-50 hover:bg-opacity-75" - : ""; + ? "bg-opacity-50 hover:bg-opacity-75" + : ""; const widthClass = btn.fullWidth ? "w-full" : ""; @@ -66,11 +66,18 @@ export function CTAButtonGroup({ key: idx, className: `${sizeClass} ${variantClass} ${widthClass}`, onClick: btn.onClick, - ...(btn.href && { href: btn.href, target: "_blank", rel: "noopener noreferrer" }), + ...(btn.href && { + href: btn.href, + target: "_blank", + rel: "noopener noreferrer", + }), }; return ( - @@ -100,7 +107,9 @@ export function CTASection({ layout = "vertical", }: CTASectionProps) { return ( -
+

{title}

{subtitle &&

{subtitle}

} {children &&
{children}
} diff --git a/client/components/ContractsWidget.tsx b/client/components/ContractsWidget.tsx index a067af89..22fa8304 100644 --- a/client/components/ContractsWidget.tsx +++ b/client/components/ContractsWidget.tsx @@ -1,6 +1,18 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; -import { FileText, AlertCircle, CheckCircle, Clock, DollarSign } from "lucide-react"; +import { + FileText, + AlertCircle, + CheckCircle, + Clock, + DollarSign, +} from "lucide-react"; export interface Contract { id: string; @@ -79,7 +91,7 @@ export function ContractsWidget({ accentColor = "purple", }: ContractsWidgetProps) { const colors = colorMap[accentColor]; - const activeContracts = contracts.filter(c => c.status === "active"); + const activeContracts = contracts.filter((c) => c.status === "active"); return ( @@ -100,9 +112,12 @@ export function ContractsWidget({
{contracts.map((contract) => { const StatusIcon = statusMap[contract.status].icon; - const progress = contract.paid_amount && contract.total_amount - ? Math.round((contract.paid_amount / contract.total_amount) * 100) - : 0; + const progress = + contract.paid_amount && contract.total_amount + ? Math.round( + (contract.paid_amount / contract.total_amount) * 100, + ) + : 0; return (
{contract.description && ( -

{contract.description}

+

+ {contract.description} +

)}
@@ -150,7 +167,9 @@ export function ContractsWidget({ {contract.milestones && contract.milestones.length > 0 && (
-

Milestones

+

+ Milestones +

{contract.milestones.map((m) => (
diff --git a/client/components/CoursesWidget.tsx b/client/components/CoursesWidget.tsx index 8c72ef8c..f873a4e1 100644 --- a/client/components/CoursesWidget.tsx +++ b/client/components/CoursesWidget.tsx @@ -1,4 +1,10 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { BookOpen, CheckCircle, Clock, Lock, ArrowRight } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -45,9 +51,21 @@ const colorMap = { }; const statusMap = { - not_started: { label: "Not Started", color: "bg-gray-600/50 text-gray-100", icon: Lock }, - in_progress: { label: "In Progress", color: "bg-blue-600/50 text-blue-100", icon: Clock }, - completed: { label: "Completed", color: "bg-green-600/50 text-green-100", icon: CheckCircle }, + not_started: { + label: "Not Started", + color: "bg-gray-600/50 text-gray-100", + icon: Lock, + }, + in_progress: { + label: "In Progress", + color: "bg-blue-600/50 text-blue-100", + icon: Clock, + }, + completed: { + label: "Completed", + color: "bg-green-600/50 text-green-100", + icon: CheckCircle, + }, }; export function CoursesWidget({ @@ -58,8 +76,10 @@ export function CoursesWidget({ accentColor = "red", }: CoursesWidgetProps) { const colors = colorMap[accentColor]; - const completedCount = courses.filter(c => c.status === "completed").length; - const inProgressCount = courses.filter(c => c.status === "in_progress").length; + const completedCount = courses.filter((c) => c.status === "completed").length; + const inProgressCount = courses.filter( + (c) => c.status === "in_progress", + ).length; return ( @@ -75,7 +95,9 @@ export function CoursesWidget({

No courses yet

-

Start your learning journey today

+

+ Start your learning journey today +

) : (
@@ -87,11 +109,15 @@ export function CoursesWidget({

In Progress

-

{inProgressCount}

+

+ {inProgressCount} +

Completed

-

{completedCount}

+

+ {completedCount} +

@@ -111,25 +137,25 @@ export function CoursesWidget({ {/* Course Header */}
-

{course.title}

+

+ {course.title} +

{statusInfo.label}
{course.description && ( -

{course.description}

+

+ {course.description} +

)}
{/* Course Meta */}
- {course.instructor && ( - {course.instructor} - )} - {course.duration && ( - {course.duration} - )} + {course.instructor && {course.instructor}} + {course.duration && {course.duration}}
{/* Progress */} @@ -138,16 +164,18 @@ export function CoursesWidget({
Progress - {course.lessons_completed || 0}/{course.lessons_total} + {course.lessons_completed || 0}/ + {course.lessons_total}
0 - ? `${(((course.lessons_completed || 0) / course.lessons_total) * 100)}%` - : "0%" + width: + course.lessons_total > 0 + ? `${((course.lessons_completed || 0) / course.lessons_total) * 100}%` + : "0%", }} />
@@ -164,7 +192,9 @@ export function CoursesWidget({ onViewCourse?.(course.id); }} > - {course.status === "completed" ? "Review Course" : "Continue Learning"} + {course.status === "completed" + ? "Review Course" + : "Continue Learning"}
diff --git a/client/components/DashboardTheme.tsx b/client/components/DashboardTheme.tsx index ae694ede..9f14f536 100644 --- a/client/components/DashboardTheme.tsx +++ b/client/components/DashboardTheme.tsx @@ -1,6 +1,13 @@ import { ReactNode } from "react"; -export type ArmKey = "nexus" | "corp" | "foundation" | "gameforge" | "labs" | "devlink" | "staff"; +export type ArmKey = + | "nexus" + | "corp" + | "foundation" + | "gameforge" + | "labs" + | "devlink" + | "staff"; interface ThemeConfig { arm: ArmKey; @@ -105,11 +112,16 @@ interface DashboardThemeProviderProps { children: ReactNode; } -export function DashboardThemeProvider({ arm, children }: DashboardThemeProviderProps) { +export function DashboardThemeProvider({ + arm, + children, +}: DashboardThemeProviderProps) { const theme = getTheme(arm); return ( -
+
{children}
); @@ -121,13 +133,19 @@ interface DashboardHeaderProps { subtitle?: string; } -export function DashboardHeader({ arm, title, subtitle }: DashboardHeaderProps) { +export function DashboardHeader({ + arm, + title, + subtitle, +}: DashboardHeaderProps) { const theme = getTheme(arm); return (
-

+

{title}

{subtitle &&

{subtitle}

} @@ -141,7 +159,10 @@ interface ColorPaletteConfig { variant?: "default" | "alt"; } -export function getColorClasses(arm: ArmKey, variant: "default" | "alt" = "default") { +export function getColorClasses( + arm: ArmKey, + variant: "default" | "alt" = "default", +) { const configs: Record>> = { nexus: { default: { diff --git a/client/components/DirectoryWidget.tsx b/client/components/DirectoryWidget.tsx index 5557e458..c29596a3 100644 --- a/client/components/DirectoryWidget.tsx +++ b/client/components/DirectoryWidget.tsx @@ -1,5 +1,11 @@ import { useState } from "react"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Users, Search, Phone, Mail, MapPin } from "lucide-react"; @@ -48,8 +54,12 @@ export function DirectoryWidget({ return matchesSearch; }); - const employeeCount = members.filter(m => m.employment_type === "employee").length; - const contractorCount = members.filter(m => m.employment_type === "contractor").length; + const employeeCount = members.filter( + (m) => m.employment_type === "employee", + ).length; + const contractorCount = members.filter( + (m) => m.employment_type === "contractor", + ).length; return ( @@ -69,7 +79,9 @@ export function DirectoryWidget({

Contractors

-

{contractorCount}

+

+ {contractorCount} +

@@ -114,10 +126,14 @@ export function DirectoryWidget({ )}
-

{member.name}

+

+ {member.name} +

{member.role}

{member.department && ( -

{member.department}

+

+ {member.department} +

)}
diff --git a/client/components/EthosStorefrontWidget.tsx b/client/components/EthosStorefrontWidget.tsx index d7e7b868..0675ee74 100644 --- a/client/components/EthosStorefrontWidget.tsx +++ b/client/components/EthosStorefrontWidget.tsx @@ -1,8 +1,20 @@ import { useState } from "react"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; -import { Music, Toggle, ToggleLeft, ToggleRight, ExternalLink } from "lucide-react"; +import { + Music, + Toggle, + ToggleLeft, + ToggleRight, + ExternalLink, +} from "lucide-react"; export interface EthosStorefrontData { for_hire: boolean; @@ -92,7 +104,9 @@ export function EthosStorefrontWidget({ My ETHOS Storefront - Your marketplace presence for services and tracks + + Your marketplace presence for services and tracks + {/* Profile Header */} @@ -106,13 +120,17 @@ export function EthosStorefrontWidget({ )}
{data.headline && ( -

{data.headline}

+

+ {data.headline} +

)} {data.bio && (

{data.bio}

)} {data.verified && ( - ✓ Verified + + ✓ Verified + )}
@@ -121,7 +139,9 @@ export function EthosStorefrontWidget({

Available for Work

-

Is your profile visible to clients?

+

+ Is your profile visible to clients? +

@@ -130,7 +140,10 @@ export function PayoutsWidget({

Available for Payout

- ${data.available_for_payout.toLocaleString('en-US', { minimumFractionDigits: 2 })} + $ + {data.available_for_payout.toLocaleString("en-US", { + minimumFractionDigits: 2, + })}

@@ -158,10 +177,16 @@ export function PayoutsWidget({

Total Earned (All-Time)

- ${data.total_earned.toLocaleString('en-US', { minimumFractionDigits: 2 })} + $ + {data.total_earned.toLocaleString("en-US", { + minimumFractionDigits: 2, + })}

- Last payout: {data.last_payout_date ? new Date(data.last_payout_date).toLocaleDateString() : "Never"} + Last payout:{" "} + {data.last_payout_date + ? new Date(data.last_payout_date).toLocaleDateString() + : "Never"}

@@ -186,10 +211,15 @@ export function PayoutsWidget({ )}

- ${payout.amount.toLocaleString('en-US', { minimumFractionDigits: 2 })} + $ + {payout.amount.toLocaleString("en-US", { + minimumFractionDigits: 2, + })}

{payout.description && ( -

{payout.description}

+

+ {payout.description} +

)}

{new Date(payout.date).toLocaleDateString()} @@ -201,8 +231,8 @@ export function PayoutsWidget({ payout.status === "completed" ? "bg-green-600/50 text-green-100" : payout.status === "pending" - ? "bg-yellow-600/50 text-yellow-100" - : "bg-red-600/50 text-red-100" + ? "bg-yellow-600/50 text-yellow-100" + : "bg-red-600/50 text-red-100" } > {payout.status} diff --git a/client/components/PostedOpportunitiesWidget.tsx b/client/components/PostedOpportunitiesWidget.tsx index b08ccbcd..42785658 100644 --- a/client/components/PostedOpportunitiesWidget.tsx +++ b/client/components/PostedOpportunitiesWidget.tsx @@ -1,7 +1,21 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { Briefcase, AlertCircle, BarChart3, Clock, Users, DollarSign, ArrowRight } from "lucide-react"; +import { + Briefcase, + AlertCircle, + BarChart3, + Clock, + Users, + DollarSign, + ArrowRight, +} from "lucide-react"; export interface PostedOpportunity { id: string; @@ -96,24 +110,32 @@ export function PostedOpportunitiesWidget({

Total Posted

-

{opportunities.length}

+

+ {opportunities.length} +

Open

- {opportunities.filter(o => o.status === "open").length} + {opportunities.filter((o) => o.status === "open").length}

In Progress

- {opportunities.filter(o => o.status === "in_progress").length} + { + opportunities.filter((o) => o.status === "in_progress") + .length + }

Total Applicants

- {opportunities.reduce((sum, o) => sum + (o.applications_count || 0), 0)} + {opportunities.reduce( + (sum, o) => sum + (o.applications_count || 0), + 0, + )}

@@ -132,7 +154,9 @@ export function PostedOpportunitiesWidget({ {opp.title} {opp.category && ( -

{opp.category}

+

+ {opp.category} +

)}
@@ -183,13 +207,20 @@ export function PostedOpportunitiesWidget({ {opp.deadline && (
- Due {new Date(opp.deadline).toLocaleDateString()} + + Due {new Date(opp.deadline).toLocaleDateString()} +
)} {opp.applications_count !== undefined && (
- {opp.applications_count} {opp.applications_count === 1 ? "application" : "applications"} + + {opp.applications_count}{" "} + {opp.applications_count === 1 + ? "application" + : "applications"} +
)}
diff --git a/client/components/ProfileEditor.tsx b/client/components/ProfileEditor.tsx index 60048f43..0f57653c 100644 --- a/client/components/ProfileEditor.tsx +++ b/client/components/ProfileEditor.tsx @@ -1,7 +1,13 @@ import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { @@ -77,9 +83,16 @@ export function ProfileEditor({ arm_affiliations: (profile.arm_affiliations as string[]) || [], }); - const [newSkill, setNewSkill] = useState({ name: "", level: "intermediate" as const }); + const [newSkill, setNewSkill] = useState({ + name: "", + level: "intermediate" as const, + }); const [newLanguage, setNewLanguage] = useState(""); - const [newWorkExp, setNewWorkExp] = useState({ company: "", title: "", duration: "" }); + const [newWorkExp, setNewWorkExp] = useState({ + company: "", + title: "", + duration: "", + }); const [newPortfolio, setNewPortfolio] = useState({ title: "", url: "" }); const [copied, setCopied] = useState(false); @@ -88,7 +101,9 @@ export function ProfileEditor({ const handleSubmit = async () => { await onSave({ ...formData, - hourly_rate: formData.hourly_rate ? parseFloat(formData.hourly_rate) : undefined, + hourly_rate: formData.hourly_rate + ? parseFloat(formData.hourly_rate) + : undefined, skills_detailed: formData.skills_detailed, languages: formData.languages, work_experience: formData.work_experience, @@ -206,7 +221,11 @@ export function ProfileEditor({ onClick={copyProfileUrl} title={copied ? "Copied!" : "Copy"} > - {copied ? : } + {copied ? ( + + ) : ( + + )}
@@ -221,7 +240,9 @@ export function ProfileEditor({