@burdenoff/microfe-crewfoundry 2026.704.5 → 2026.704.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/dist/crewfoundry/CrewFoundryRoutes.js +51 -43
  2. package/dist/crewfoundry/CrewFoundryRoutes.js.map +1 -1
  3. package/dist/crewfoundry/components/forms/formValues.js +5 -2
  4. package/dist/crewfoundry/components/forms/formValues.js.map +1 -1
  5. package/dist/crewfoundry/components/viz/AllocationBar.js +68 -0
  6. package/dist/crewfoundry/components/viz/AllocationBar.js.map +1 -0
  7. package/dist/crewfoundry/components/viz/AreaChart.js +102 -0
  8. package/dist/crewfoundry/components/viz/AreaChart.js.map +1 -0
  9. package/dist/crewfoundry/components/viz/AvatarStack.js +36 -0
  10. package/dist/crewfoundry/components/viz/AvatarStack.js.map +1 -0
  11. package/dist/crewfoundry/components/viz/BarChart.js +83 -0
  12. package/dist/crewfoundry/components/viz/BarChart.js.map +1 -0
  13. package/dist/crewfoundry/components/viz/CertificateCard.js +118 -0
  14. package/dist/crewfoundry/components/viz/CertificateCard.js.map +1 -0
  15. package/dist/crewfoundry/components/viz/DonutChart.js +109 -0
  16. package/dist/crewfoundry/components/viz/DonutChart.js.map +1 -0
  17. package/dist/crewfoundry/components/viz/HBarFunnel.js +54 -0
  18. package/dist/crewfoundry/components/viz/HBarFunnel.js.map +1 -0
  19. package/dist/crewfoundry/components/viz/Heatmap.js +91 -0
  20. package/dist/crewfoundry/components/viz/Heatmap.js.map +1 -0
  21. package/dist/crewfoundry/components/viz/KanbanBoard.js +50 -0
  22. package/dist/crewfoundry/components/viz/KanbanBoard.js.map +1 -0
  23. package/dist/crewfoundry/components/viz/LineChart.js +123 -0
  24. package/dist/crewfoundry/components/viz/LineChart.js.map +1 -0
  25. package/dist/crewfoundry/components/viz/OrgTree.js +83 -0
  26. package/dist/crewfoundry/components/viz/OrgTree.js.map +1 -0
  27. package/dist/crewfoundry/components/viz/PathSteps.js +68 -0
  28. package/dist/crewfoundry/components/viz/PathSteps.js.map +1 -0
  29. package/dist/crewfoundry/components/viz/ProgressRing.js +68 -0
  30. package/dist/crewfoundry/components/viz/ProgressRing.js.map +1 -0
  31. package/dist/crewfoundry/components/viz/RatingStars.js +51 -0
  32. package/dist/crewfoundry/components/viz/RatingStars.js.map +1 -0
  33. package/dist/crewfoundry/components/viz/SegmentedTabs.js +69 -0
  34. package/dist/crewfoundry/components/viz/SegmentedTabs.js.map +1 -0
  35. package/dist/crewfoundry/components/viz/SkillBar.js +3 -0
  36. package/dist/crewfoundry/components/viz/Sparkline.js +74 -0
  37. package/dist/crewfoundry/components/viz/Sparkline.js.map +1 -0
  38. package/dist/crewfoundry/components/viz/StatCard.js +60 -0
  39. package/dist/crewfoundry/components/viz/StatCard.js.map +1 -0
  40. package/dist/crewfoundry/components/viz/StepProgress.js +3 -0
  41. package/dist/crewfoundry/components/viz/Timeline.js +66 -0
  42. package/dist/crewfoundry/components/viz/Timeline.js.map +1 -0
  43. package/dist/crewfoundry/components/viz/index.js +23 -0
  44. package/dist/crewfoundry/components/viz/lib/Avatar.js +30 -0
  45. package/dist/crewfoundry/components/viz/lib/Avatar.js.map +1 -0
  46. package/dist/crewfoundry/components/viz/lib/CartesianFrame.js +119 -0
  47. package/dist/crewfoundry/components/viz/lib/CartesianFrame.js.map +1 -0
  48. package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js +35 -0
  49. package/dist/crewfoundry/components/viz/lib/ResponsiveSvg.js.map +1 -0
  50. package/dist/crewfoundry/components/viz/lib/format.js +21 -0
  51. package/dist/crewfoundry/components/viz/lib/format.js.map +1 -0
  52. package/dist/crewfoundry/components/viz/lib/geometry.js +69 -0
  53. package/dist/crewfoundry/components/viz/lib/geometry.js.map +1 -0
  54. package/dist/crewfoundry/components/viz/lib/hooks.js +39 -0
  55. package/dist/crewfoundry/components/viz/lib/hooks.js.map +1 -0
  56. package/dist/crewfoundry/components/viz/lib/palette.js +27 -0
  57. package/dist/crewfoundry/components/viz/lib/palette.js.map +1 -0
  58. package/dist/crewfoundry/lib/analytics.js +323 -0
  59. package/dist/crewfoundry/lib/analytics.js.map +1 -0
  60. package/dist/crewfoundry/lib/companyFinance.js +16 -0
  61. package/dist/crewfoundry/lib/companyFinance.js.map +1 -0
  62. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js +226 -283
  63. package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  64. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js +107 -120
  65. package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
  66. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js +122 -162
  67. package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
  68. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js +121 -158
  69. package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
  70. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js +316 -211
  71. package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
  72. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js +75 -27
  73. package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
  74. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js +167 -165
  75. package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
  76. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js +168 -109
  77. package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
  78. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js +401 -290
  79. package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
  80. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js +84 -75
  81. package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
  82. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js +368 -174
  83. package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
  84. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js +236 -201
  85. package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
  86. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js +369 -196
  87. package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
  88. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js +252 -249
  89. package/dist/crewfoundry/pages/HiringJobDetailsPagePage.js.map +1 -1
  90. package/dist/crewfoundry/pages/HiringJobsPagePage.js +210 -110
  91. package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
  92. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js +216 -178
  93. package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
  94. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js +385 -0
  95. package/dist/crewfoundry/pages/HrEmployeeProfilePagePage.js.map +1 -0
  96. package/dist/crewfoundry/pages/HrEmployeesPagePage.js +189 -130
  97. package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
  98. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js +397 -241
  99. package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
  100. package/dist/crewfoundry/pages/HrPayrollPagePage.js +262 -147
  101. package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
  102. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js +345 -167
  103. package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
  104. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js +98 -24
  105. package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
  106. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js +35 -31
  107. package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
  108. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js +289 -108
  109. package/dist/crewfoundry/pages/LearningCourseLearningPagePage.js.map +1 -1
  110. package/dist/crewfoundry/pages/LearningCoursesPagePage.js +221 -114
  111. package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
  112. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js +136 -133
  113. package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
  114. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +148 -97
  115. package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
  116. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js +264 -157
  117. package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
  118. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
  119. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js +85 -93
  120. package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
  121. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js +211 -122
  122. package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
  123. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js +94 -54
  124. package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
  125. package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js +28 -25
  126. package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
  127. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js +290 -138
  128. package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
  129. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js +169 -79
  130. package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
  131. package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
  132. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js +65 -61
  133. package/dist/crewfoundry/pages/ProjectsProjectDetailsPagePage.js.map +1 -1
  134. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js +296 -125
  135. package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
  136. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js +187 -0
  137. package/dist/crewfoundry/pages/ProjectsResourcingPagePage.js.map +1 -0
  138. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js +142 -76
  139. package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
  140. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js +93 -43
  141. package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
  142. package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
  143. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js +250 -98
  144. package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
  145. package/dist/crewfoundry/store/crewfoundryStore.js +1 -1
  146. package/dist/crewfoundry/store/crewfoundryStore.js.map +1 -1
  147. package/dist/crewfoundry/utils/cn.js +10 -0
  148. package/dist/crewfoundry/utils/cn.js.map +1 -0
  149. package/dist/crewfoundry/utils/courseProgress.js +46 -0
  150. package/dist/crewfoundry/utils/courseProgress.js.map +1 -0
  151. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  152. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  153. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  154. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  155. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MarketplaceFreelancerProfilePageEnhancedPage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n Separator,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Briefcase,\n Calendar,\n DollarSign,\n MessageSquare,\n Star,\n TrendingUp,\n Video,\n} from 'lucide-react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nconst initialsOf = (name: string): string =>\n name\n .split(' ')\n .map((part) => part[0] ?? '')\n .join('')\n .slice(0, 2)\n .toUpperCase() || '—';\n\nexport function MarketplaceFreelancerProfilePageEnhancedPage() {\n const [selectedTab, setSelectedTab] = useState('overview');\n const navigate = useNavigate();\n const location = useLocation();\n const { marketplaceServices } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n\n const baseService =\n marketplaceServices.find((service) => service.id === selectedId) ?? marketplaceServices[0];\n const providerName = baseService?.provider ?? '';\n\n const providerServices = useMemo(\n () => marketplaceServices.filter((service) => service.provider === providerName),\n [marketplaceServices, providerName]\n );\n\n const skills = useMemo(\n () => Array.from(new Set(providerServices.flatMap((service) => service.skills))).slice(0, 20),\n [providerServices]\n );\n\n const categories = useMemo(\n () => Array.from(new Set(providerServices.map((service) => service.category))),\n [providerServices]\n );\n\n const services = useMemo(\n () =>\n providerServices.map((service) => ({\n id: service.id,\n title: service.title,\n price:\n service.priceType === 'hourly'\n ? `$${service.price}/hr`\n : service.priceType === 'monthly'\n ? `$${service.price}/mo`\n : `$${service.price}`,\n type: service.priceType,\n description: service.description,\n delivery: service.deliveryTime,\n rating: service.rating,\n reviews: service.reviews,\n })),\n [providerServices]\n );\n\n const avgRating =\n providerServices.length > 0\n ? (\n providerServices.reduce((sum, service) => sum + service.rating, 0) /\n providerServices.length\n ).toFixed(1)\n : '0.0';\n const totalReviews = providerServices.reduce((sum, service) => sum + service.reviews, 0);\n const startingRate =\n providerServices.length > 0 ? Math.min(...providerServices.map((service) => service.price)) : 0;\n const isTopRated = Number(avgRating) >= 4.5 && totalReviews > 0;\n\n const stats = [\n { label: 'Services', value: `${providerServices.length}` },\n { label: 'Avg Rating', value: avgRating },\n { label: 'Total Reviews', value: `${totalReviews}` },\n { label: 'Starting Rate', value: `$${startingRate.toLocaleString()}` },\n ];\n\n if (!baseService) {\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Provider not found\"\n description=\"This freelancer is no longer available on the marketplace.\"\n />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"pt-6\">\n <div className=\"flex items-start gap-6\">\n <div className=\"flex h-24 w-24 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-primary to-primary/60 text-action-primary-text text-3xl font-semibold\">\n {initialsOf(providerName)}\n </div>\n <div className=\"flex-1 space-y-2\">\n <div className=\"flex items-center gap-3 flex-wrap\">\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{providerName}</GradientText>\n </h1>\n {isTopRated ? <Badge>Top Rated</Badge> : null}\n </div>\n <p className=\"text-sm font-medium\">\n {categories.length > 0 ? categories.join(' · ') : 'Marketplace provider'}\n </p>\n <div className=\"flex flex-wrap items-center gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" /> {avgRating} ({totalReviews}{' '}\n reviews)\n </span>\n <span className=\"flex items-center gap-1\">\n <Briefcase className=\"h-3 w-3\" /> {providerServices.length} services\n </span>\n <span className=\"flex items-center gap-1\">\n <DollarSign className=\"h-3 w-3\" /> from ${startingRate.toLocaleString()}\n </span>\n </div>\n <div className=\"flex gap-2 pt-2 flex-wrap\">\n <Button size=\"sm\" onClick={() => navigate('../marketplace/messaging-page')}>\n <MessageSquare className=\"h-3 w-3 mr-1\" /> Send Proposal\n </Button>\n {/* No video-intro/call surface exists yet — honest disabled control. */}\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled\n title=\"Video intro is coming soon\"\n aria-label=\"Video intro — coming soon\"\n >\n <Video className=\"h-3 w-3 mr-1\" /> Video Intro · Coming soon\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={() => setSelectedTab('availability')}>\n <Calendar className=\"h-3 w-3 mr-1\" /> Schedule Call\n </Button>\n </div>\n <PagePurpose className=\"pt-2\">\n A freelancer&apos;s full profile — skills, listed services, and performance — so you\n can vet them thoroughly and decide whether to hire before you reach out.\n </PagePurpose>\n </div>\n </div>\n </CardContent>\n </GlassCard>\n\n <NextSteps\n storageKey=\"crewfoundry-freelancer-profile-enhanced\"\n steps={[\n {\n id: 'services',\n label: 'Review their services',\n description: 'See exactly what this freelancer offers and at what price.',\n icon: <Briefcase className=\"h-4 w-4\" />,\n onClick: () => setSelectedTab('services'),\n },\n {\n id: 'availability',\n label: 'Check availability',\n description: 'Find open slots before you schedule a call.',\n icon: <Calendar className=\"h-4 w-4\" />,\n onClick: () => setSelectedTab('availability'),\n },\n {\n id: 'performance',\n label: 'Inspect performance',\n description: 'Look at ratings and delivery history to reduce risk.',\n icon: <TrendingUp className=\"h-4 w-4\" />,\n onClick: () => setSelectedTab('analytics'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n {stats.map((stat) => (\n <Card key={stat.label}>\n <CardContent className=\"pt-6\">\n <p className=\"text-xs text-text-secondary\">{stat.label}</p>\n <p className=\"text-lg font-bold\">{stat.value}</p>\n </CardContent>\n </Card>\n ))}\n </div>\n\n <Tabs value={selectedTab} onValueChange={setSelectedTab}>\n <TabsList>\n <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n <TabsTrigger value=\"services\">Services</TabsTrigger>\n <TabsTrigger value=\"availability\">Availability</TabsTrigger>\n <TabsTrigger value=\"analytics\">Performance</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"overview\" className=\"space-y-6 mt-4\">\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Summary</CardTitle>\n </CardHeader>\n <CardContent className=\"text-sm text-text-secondary space-y-3\">\n <p>\n {providerName} offers {providerServices.length}{' '}\n {providerServices.length === 1 ? 'service' : 'services'} on the marketplace\n {categories.length > 0 ? ` across ${categories.join(', ')}` : ''}.\n </p>\n <p>\n Across all listings the provider holds an average rating of {avgRating} from{' '}\n {totalReviews} reviews, with rates starting at ${startingRate.toLocaleString()}.\n </p>\n </CardContent>\n </Card>\n </div>\n <div className=\"space-y-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">Expertise Areas</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-wrap gap-1.5\">\n {skills.length > 0 ? (\n skills.map((s) => (\n <Badge key={s} variant=\"secondary\" className=\"text-xs\">\n {s}\n </Badge>\n ))\n ) : (\n <p className=\"text-xs text-text-secondary\">No skills listed yet.</p>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </TabsContent>\n\n <TabsContent value=\"services\" className=\"mt-4\">\n {services.length > 0 ? (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {services.map((svc) => (\n <Card key={svc.id}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-sm\">{svc.title}</CardTitle>\n <Badge variant=\"outline\" className=\"text-xs\">\n {formatEnumLabel(svc.type)}\n </Badge>\n </div>\n <CardDescription className=\"text-xs\">{svc.description}</CardDescription>\n </CardHeader>\n <CardContent className=\"pt-0\">\n <Separator className=\"mb-3\" />\n <div className=\"flex items-center justify-between\">\n <div className=\"space-y-0.5\">\n <p className=\"text-sm font-semibold\">{svc.price}</p>\n <p className=\"text-[10px] text-text-secondary\">Delivery: {svc.delivery}</p>\n </div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() =>\n navigate(`../marketplace/service-details-page?id=${svc.id}`)\n }\n >\n View\n </Button>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No services listed\"\n description=\"This provider has not published any services yet.\"\n />\n )}\n </TabsContent>\n\n <TabsContent value=\"availability\" className=\"mt-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Availability</CardTitle>\n <CardDescription>Real-time scheduling with this provider</CardDescription>\n </CardHeader>\n <CardContent>\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"Scheduling is coming soon\"\n description=\"Live availability and consultation booking will appear here once the scheduling backend ships. In the meantime, send a message to arrange a time.\"\n action={\n <Button size=\"sm\" onClick={() => navigate('../marketplace/messaging-page')}>\n <MessageSquare className=\"h-3 w-3 mr-1\" /> Message provider\n </Button>\n }\n />\n </CardContent>\n </Card>\n </TabsContent>\n\n <TabsContent value=\"analytics\" className=\"mt-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Service Performance</CardTitle>\n <CardDescription>Ratings and reviews per listed service</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {providerServices.length > 0 ? (\n providerServices.map((service) => (\n <div key={service.id} className=\"flex items-center justify-between\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium truncate\">{service.title}</p>\n <p className=\"text-xs text-text-secondary\">{service.category}</p>\n </div>\n <div className=\"flex items-center gap-2 text-sm shrink-0\">\n <Star className=\"h-3.5 w-3.5 text-status-warning-text\" />\n <span className=\"font-semibold\">{service.rating}</span>\n <span className=\"text-xs text-text-secondary\">({service.reviews})</span>\n </div>\n </div>\n ))\n ) : (\n <p className=\"text-sm text-text-secondary\">No performance data yet.</p>\n )}\n </CardContent>\n </Card>\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAiCA,IAAM,KAAc,MAClB,EACG,MAAM,IAAI,CACV,KAAK,MAAS,EAAK,MAAM,GAAG,CAC5B,KAAK,GAAG,CACR,MAAM,GAAG,EAAE,CACX,aAAa,IAAI;AAEtB,SAAgB,IAA+C;CAC7D,IAAM,CAAC,GAAa,KAAkB,EAAS,WAAW,EACpD,IAAW,GAAa,EACxB,IAAW,GAAa,EACxB,EAAE,2BAAwB,GAAqB,EAC/C,IAAa,IAAI,gBAAgB,EAAS,OAAO,CAAC,IAAI,KAAK,EAE3D,IACJ,EAAoB,MAAM,MAAY,EAAQ,OAAO,EAAW,IAAI,EAAoB,IACpF,IAAe,GAAa,YAAY,IAExC,IAAmB,QACjB,EAAoB,QAAQ,MAAY,EAAQ,aAAa,EAAa,EAChF,CAAC,GAAqB,EAAa,CACpC,EAEK,IAAS,QACP,MAAM,KAAK,IAAI,IAAI,EAAiB,SAAS,MAAY,EAAQ,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,EAC7F,CAAC,EAAiB,CACnB,EAEK,IAAa,QACX,MAAM,KAAK,IAAI,IAAI,EAAiB,KAAK,MAAY,EAAQ,SAAS,CAAC,CAAC,EAC9E,CAAC,EAAiB,CACnB,EAEK,IAAW,QAEb,EAAiB,KAAK,OAAa;EACjC,IAAI,EAAQ;EACZ,OAAO,EAAQ;EACf,OACE,EAAQ,cAAc,WAClB,IAAI,EAAQ,MAAM,OAClB,EAAQ,cAAc,YACpB,IAAI,EAAQ,MAAM,OAClB,IAAI,EAAQ;EACpB,MAAM,EAAQ;EACd,aAAa,EAAQ;EACrB,UAAU,EAAQ;EAClB,QAAQ,EAAQ;EAChB,SAAS,EAAQ;EAClB,EAAE,EACL,CAAC,EAAiB,CACnB,EAEK,IACJ,EAAiB,SAAS,KAEpB,EAAiB,QAAQ,GAAK,MAAY,IAAM,EAAQ,QAAQ,EAAE,GAClE,EAAiB,QACjB,QAAQ,EAAE,GACZ,OACA,IAAe,EAAiB,QAAQ,GAAK,MAAY,IAAM,EAAQ,SAAS,EAAE,EAClF,IACJ,EAAiB,SAAS,IAAI,KAAK,IAAI,GAAG,EAAiB,KAAK,MAAY,EAAQ,MAAM,CAAC,GAAG,GAC1F,IAAa,OAAO,EAAU,IAAI,OAAO,IAAe,GAExD,IAAQ;EACZ;GAAE,OAAO;GAAY,OAAO,GAAG,EAAiB;GAAU;EAC1D;GAAE,OAAO;GAAc,OAAO;GAAW;EACzC;GAAE,OAAO;GAAiB,OAAO,GAAG;GAAgB;EACpD;GAAE,OAAO;GAAiB,OAAO,IAAI,EAAa,gBAAgB;GAAI;EACvE;AAcD,QAZK,IAaH,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IAAW,WAAU;IAAQ,MAAA;IAAK,WAAU;cAC1C,kBAAC,GAAD;KAAa,WAAU;eACrB,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAW,EAAa;OACrB,CAAA,EACN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBACZ,kBAAC,GAAD,EAAA,UAAe,GAA4B,CAAA;UACxC,CAAA,EACJ,IAAa,kBAAC,GAAD,EAAA,UAAO,aAAiB,CAAA,GAAG,KACrC;;QACN,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAW,SAAS,IAAI,EAAW,KAAK,MAAM,GAAG;SAChD,CAAA;QACJ,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,QAAD;WAAM,WAAU;qBAAhB;YACE,kBAAC,GAAD,EAAM,WAAU,oCAAqC,CAAA;;YAAE;YAAU;YAAG;YAAc;YAAI;YAEjF;;UACP,kBAAC,QAAD;WAAM,WAAU;qBAAhB;YACE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;;YAAE,EAAiB;YAAO;YACtD;;UACP,kBAAC,QAAD;WAAM,WAAU;qBAAhB;YACE,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;;YAAQ,EAAa,gBAAgB;YAClE;;UACH;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,GAAD;WAAQ,MAAK;WAAK,eAAe,EAAS,gCAAgC;qBAA1E,CACE,kBAAC,GAAD,EAAe,WAAU,gBAAiB,CAAA,EAAA,iBACnC;;UAET,kBAAC,GAAD;WACE,MAAK;WACL,SAAQ;WACR,UAAA;WACA,OAAM;WACN,cAAW;qBALb,CAOE,kBAAC,GAAD,EAAO,WAAU,gBAAiB,CAAA,EAAA,6BAC3B;;UACT,kBAAC,GAAD;WAAQ,MAAK;WAAK,SAAQ;WAAU,eAAe,EAAe,eAAe;qBAAjF,CACE,kBAAC,GAAD,EAAU,WAAU,gBAAiB,CAAA,EAAA,iBAC9B;;UACL;;QACN,kBAAC,GAAD;SAAa,WAAU;mBAAO;SAGhB,CAAA;QACV;SACF;;KACM,CAAA;IACJ,CAAA;GAEZ,kBAAC,GAAD;IACE,YAAW;IACX,OAAO;KACL;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;MACvC,eAAe,EAAe,WAAW;MAC1C;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;MACtC,eAAe,EAAe,eAAe;MAC9C;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;MACxC,eAAe,EAAe,YAAY;MAC3C;KACF;IACD,CAAA;GAEF,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAM,KAAK,MACV,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KAAa,WAAU;eAAvB,CACE,kBAAC,KAAD;MAAG,WAAU;gBAA+B,EAAK;MAAU,CAAA,EAC3D,kBAAC,KAAD;MAAG,WAAU;gBAAqB,EAAK;MAAU,CAAA,CACrC;QACT,EALI,EAAK,MAKT,CACP;IACE,CAAA;GAEN,kBAAC,GAAD;IAAM,OAAO;IAAa,eAAe;cAAzC;KACE,kBAAC,GAAD,EAAA,UAAA;MACE,kBAAC,GAAD;OAAa,OAAM;iBAAW;OAAsB,CAAA;MACpD,kBAAC,GAAD;OAAa,OAAM;iBAAW;OAAsB,CAAA;MACpD,kBAAC,GAAD;OAAa,OAAM;iBAAe;OAA0B,CAAA;MAC5D,kBAAC,GAAD;OAAa,OAAM;iBAAY;OAAyB,CAAA;MAC/C,EAAA,CAAA;KAEX,kBAAC,GAAD;MAAa,OAAM;MAAW,WAAU;gBACtC,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;SAAW,WAAU;mBAAY;SAAmB,CAAA,EACzC,CAAA,EACb,kBAAC,GAAD;SAAa,WAAU;mBAAvB,CACE,kBAAC,KAAD,EAAA,UAAA;UACG;UAAa;UAAS,EAAiB;UAAQ;UAC/C,EAAiB,WAAW,IAAI,YAAY;UAAW;UACvD,EAAW,SAAS,IAAI,WAAW,EAAW,KAAK,KAAK,KAAK;UAAG;UAC/D,EAAA,CAAA,EACJ,kBAAC,KAAD,EAAA,UAAA;UAAG;UAC4D;UAAU;UAAM;UAC5E;UAAa;UAAmC,EAAa,gBAAgB;UAAC;UAC7E,EAAA,CAAA,CACQ;WACT,EAAA,CAAA;QACH,CAAA,EACN,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;SAAW,WAAU;mBAAU;SAA2B,CAAA,EAC/C,CAAA,EACb,kBAAC,GAAD;SAAa,WAAU;mBACpB,EAAO,SAAS,IACf,EAAO,KAAK,MACV,kBAAC,GAAD;UAAe,SAAQ;UAAY,WAAU;oBAC1C;UACK,EAFI,EAEJ,CACR,GAEF,kBAAC,KAAD;UAAG,WAAU;oBAA8B;UAAyB,CAAA;SAE1D,CAAA,CACT,EAAA,CAAA;QACH,CAAA,CACF;;MACM,CAAA;KAEd,kBAAC,GAAD;MAAa,OAAM;MAAW,WAAU;gBACrC,EAAS,SAAS,IACjB,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAS,KAAK,MACb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAW,WAAU;mBAAW,EAAI;SAAkB,CAAA,EACtD,kBAAC,GAAD;SAAO,SAAQ;SAAU,WAAU;mBAChC,EAAgB,EAAI,KAAK;SACpB,CAAA,CACJ;WACN,kBAAC,GAAD;QAAiB,WAAU;kBAAW,EAAI;QAA8B,CAAA,CAC7D,EAAA,CAAA,EACb,kBAAC,GAAD;QAAa,WAAU;kBAAvB,CACE,kBAAC,GAAD,EAAW,WAAU,QAAS,CAAA,EAC9B,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,KAAD;WAAG,WAAU;qBAAyB,EAAI;WAAU,CAAA,EACpD,kBAAC,KAAD;WAAG,WAAU;qBAAb,CAA+C,cAAW,EAAI,SAAa;aACvE;aACN,kBAAC,GAAD;UACE,MAAK;UACL,SAAQ;UACR,eACE,EAAS,0CAA0C,EAAI,KAAK;oBAE/D;UAEQ,CAAA,CACL;WACM;UACT,EAAA,EA5BI,EAAI,GA4BR,CACP;OACE,CAAA,GAEN,kBAAC,GAAD;OACE,cAAa;OACb,OAAM;OACN,aAAY;OACZ,CAAA;MAEQ,CAAA;KAEd,kBAAC,GAAD;MAAa,OAAM;MAAe,WAAU;gBAC1C,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;OAAW,WAAU;iBAAY;OAAwB,CAAA,EACzD,kBAAC,GAAD,EAAA,UAAiB,2CAAyD,CAAA,CAC/D,EAAA,CAAA,EACb,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OACE,cAAa;OACb,OAAM;OACN,aAAY;OACZ,QACE,kBAAC,GAAD;QAAQ,MAAK;QAAK,eAAe,EAAS,gCAAgC;kBAA1E,CACE,kBAAC,GAAD,EAAe,WAAU,gBAAiB,CAAA,EAAA,oBACnC;;OAEX,CAAA,EACU,CAAA,CACT,EAAA,CAAA;MACK,CAAA;KAEd,kBAAC,GAAD;MAAa,OAAM;MAAY,WAAU;gBACvC,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;OAAW,WAAU;iBAAY;OAA+B,CAAA,EAChE,kBAAC,GAAD,EAAA,UAAiB,0CAAwD,CAAA,CAC9D,EAAA,CAAA,EACb,kBAAC,GAAD;OAAa,WAAU;iBACpB,EAAiB,SAAS,IACzB,EAAiB,KAAK,MACpB,kBAAC,OAAD;QAAsB,WAAU;kBAAhC,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAgC,EAAQ;UAAU,CAAA,EAC/D,kBAAC,KAAD;UAAG,WAAU;oBAA+B,EAAQ;UAAa,CAAA,CAC7D;YACN,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,GAAD,EAAM,WAAU,wCAAyC,CAAA;UACzD,kBAAC,QAAD;WAAM,WAAU;qBAAiB,EAAQ;WAAc,CAAA;UACvD,kBAAC,QAAD;WAAM,WAAU;qBAAhB;YAA8C;YAAE,EAAQ;YAAQ;YAAQ;;UACpE;WACF;UAVI,EAAQ,GAUZ,CACN,GAEF,kBAAC,KAAD;QAAG,WAAU;kBAA8B;QAA4B,CAAA;OAE7D,CAAA,CACT,EAAA,CAAA;MACK,CAAA;KACT;;GACH;MAvPJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,CAAA;EACE,CAAA"}
1
+ {"version":3,"file":"MarketplaceFreelancerProfilePageEnhancedPage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n Separator,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Briefcase,\n Calendar,\n DollarSign,\n MessageSquare,\n Star,\n TrendingUp,\n Video,\n} from 'lucide-react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { formatEnumLabel } from '../utils/formatEnumLabel';\n\nconst initialsOf = (name: string): string =>\n name\n .split(' ')\n .map((part) => part[0] ?? '')\n .join('')\n .slice(0, 2)\n .toUpperCase() || '—';\n\nexport function MarketplaceFreelancerProfilePageEnhancedPage() {\n const [selectedTab, setSelectedTab] = useState('overview');\n const navigate = useNavigate();\n const location = useLocation();\n const { marketplaceServices } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n\n const baseService =\n marketplaceServices.find((service) => service.id === selectedId) ?? marketplaceServices[0];\n const providerName = baseService?.provider ?? '';\n\n const providerServices = useMemo(\n () => marketplaceServices.filter((service) => service.provider === providerName),\n [marketplaceServices, providerName]\n );\n\n const skills = useMemo(\n () => Array.from(new Set(providerServices.flatMap((service) => service.skills))).slice(0, 20),\n [providerServices]\n );\n\n const categories = useMemo(\n () => Array.from(new Set(providerServices.map((service) => service.category))),\n [providerServices]\n );\n\n const services = useMemo(\n () =>\n providerServices.map((service) => ({\n id: service.id,\n title: service.title,\n price:\n service.priceType === 'hourly'\n ? `$${service.price}/hr`\n : service.priceType === 'monthly'\n ? `$${service.price}/mo`\n : `$${service.price}`,\n type: service.priceType,\n description: service.description,\n delivery: service.deliveryTime,\n rating: service.rating,\n reviews: service.reviews,\n })),\n [providerServices]\n );\n\n const avgRating =\n providerServices.length > 0\n ? (\n providerServices.reduce((sum, service) => sum + service.rating, 0) /\n providerServices.length\n ).toFixed(1)\n : '0.0';\n const totalReviews = providerServices.reduce((sum, service) => sum + service.reviews, 0);\n const startingRate =\n providerServices.length > 0 ? Math.min(...providerServices.map((service) => service.price)) : 0;\n const isTopRated = Number(avgRating) >= 4.5 && totalReviews > 0;\n\n const stats = [\n { label: 'Services', value: `${providerServices.length}` },\n { label: 'Avg Rating', value: avgRating },\n { label: 'Total Reviews', value: `${totalReviews}` },\n { label: 'Starting Rate', value: `$${startingRate.toLocaleString()}` },\n ];\n\n if (!baseService) {\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Provider not found\"\n description=\"This freelancer is no longer available on the marketplace.\"\n />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"pt-6\">\n <div className=\"flex items-start gap-6\">\n <div className=\"flex h-24 w-24 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-primary to-primary/60 text-action-primary-text text-3xl font-semibold\">\n {initialsOf(providerName)}\n </div>\n <div className=\"flex-1 space-y-2\">\n <div className=\"flex items-center gap-3 flex-wrap\">\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{providerName}</GradientText>\n </h1>\n {isTopRated ? <Badge>Top Rated</Badge> : null}\n </div>\n <p className=\"text-sm font-medium\">\n {categories.length > 0 ? categories.join(' · ') : 'Marketplace provider'}\n </p>\n <div className=\"flex flex-wrap items-center gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" /> {avgRating} ({totalReviews}{' '}\n reviews)\n </span>\n <span className=\"flex items-center gap-1\">\n <Briefcase className=\"h-3 w-3\" /> {providerServices.length} services\n </span>\n <span className=\"flex items-center gap-1\">\n <DollarSign className=\"h-3 w-3\" /> from ${startingRate.toLocaleString()}\n </span>\n </div>\n <div className=\"flex gap-2 pt-2 flex-wrap\">\n <Button size=\"sm\" onClick={() => navigate('../marketplace/messaging-page')}>\n <MessageSquare className=\"h-3 w-3 mr-1\" /> Send Proposal\n </Button>\n {/* No video-intro/call surface exists yet — honest disabled control. */}\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled\n title=\"Video intro is coming soon\"\n aria-label=\"Video intro — coming soon\"\n >\n <Video className=\"h-3 w-3 mr-1\" /> Video Intro · Coming soon\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={() => setSelectedTab('availability')}>\n <Calendar className=\"h-3 w-3 mr-1\" /> Schedule Call\n </Button>\n </div>\n <PagePurpose className=\"pt-2\">\n A freelancer&apos;s full profile — skills, listed services, and performance — so you\n can vet them thoroughly and decide whether to hire before you reach out.\n </PagePurpose>\n </div>\n </div>\n </CardContent>\n </GlassCard>\n\n <NextSteps\n storageKey=\"crewfoundry-freelancer-profile-enhanced\"\n steps={[\n {\n id: 'services',\n label: 'Review their services',\n description: 'See exactly what this freelancer offers and at what price.',\n icon: <Briefcase className=\"h-4 w-4\" />,\n onClick: () => setSelectedTab('services'),\n },\n {\n id: 'availability',\n label: 'Check availability',\n description: 'Find open slots before you schedule a call.',\n icon: <Calendar className=\"h-4 w-4\" />,\n onClick: () => setSelectedTab('availability'),\n },\n {\n id: 'performance',\n label: 'Inspect performance',\n description: 'Look at ratings and delivery history to reduce risk.',\n icon: <TrendingUp className=\"h-4 w-4\" />,\n onClick: () => setSelectedTab('analytics'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n {stats.map((stat) => (\n <Card key={stat.label}>\n <CardContent className=\"pt-6\">\n <p className=\"text-xs text-text-secondary\">{stat.label}</p>\n <p className=\"text-lg font-bold\">{stat.value}</p>\n </CardContent>\n </Card>\n ))}\n </div>\n\n <Tabs value={selectedTab} onValueChange={setSelectedTab}>\n <TabsList>\n <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n <TabsTrigger value=\"services\">Services</TabsTrigger>\n <TabsTrigger value=\"availability\">Availability</TabsTrigger>\n <TabsTrigger value=\"analytics\">Performance</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"overview\" className=\"space-y-6 mt-4\">\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Summary</CardTitle>\n </CardHeader>\n <CardContent className=\"text-sm text-text-secondary space-y-3\">\n <p>\n {providerName} offers {providerServices.length}{' '}\n {providerServices.length === 1 ? 'service' : 'services'} on the marketplace\n {categories.length > 0 ? ` across ${categories.join(', ')}` : ''}.\n </p>\n <p>\n Across all listings the provider holds an average rating of {avgRating} from{' '}\n {totalReviews} reviews, with rates starting at ${startingRate.toLocaleString()}.\n </p>\n </CardContent>\n </Card>\n </div>\n <div className=\"space-y-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">Expertise Areas</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-wrap gap-1.5\">\n {skills.length > 0 ? (\n skills.map((s) => (\n <Badge key={s} variant=\"secondary\" className=\"text-xs\">\n {s}\n </Badge>\n ))\n ) : (\n <p className=\"text-xs text-text-secondary\">No skills listed yet.</p>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </TabsContent>\n\n <TabsContent value=\"services\" className=\"mt-4\">\n {services.length > 0 ? (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {services.map((svc) => (\n <Card key={svc.id}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-sm\">{svc.title}</CardTitle>\n <Badge variant=\"outline\" className=\"text-xs\">\n {formatEnumLabel(svc.type)}\n </Badge>\n </div>\n <CardDescription className=\"text-xs\">{svc.description}</CardDescription>\n </CardHeader>\n <CardContent className=\"pt-0\">\n <Separator className=\"mb-3\" />\n <div className=\"flex items-center justify-between\">\n <div className=\"space-y-0.5\">\n <p className=\"text-sm font-semibold\">{svc.price}</p>\n <p className=\"text-[10px] text-text-secondary\">Delivery: {svc.delivery}</p>\n </div>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => navigate(`../marketplace/service-details-page?id=${svc.id}`)}\n >\n View\n </Button>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No services listed\"\n description=\"This provider has not published any services yet.\"\n />\n )}\n </TabsContent>\n\n <TabsContent value=\"availability\" className=\"mt-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Availability</CardTitle>\n <CardDescription>Real-time scheduling with this provider</CardDescription>\n </CardHeader>\n <CardContent>\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"Scheduling is coming soon\"\n description=\"Live availability and consultation booking will appear here once the scheduling backend ships. In the meantime, send a message to arrange a time.\"\n action={\n <Button size=\"sm\" onClick={() => navigate('../marketplace/messaging-page')}>\n <MessageSquare className=\"h-3 w-3 mr-1\" /> Message provider\n </Button>\n }\n />\n </CardContent>\n </Card>\n </TabsContent>\n\n <TabsContent value=\"analytics\" className=\"mt-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Service Performance</CardTitle>\n <CardDescription>Ratings and reviews per listed service</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {providerServices.length > 0 ? (\n providerServices.map((service) => (\n <div key={service.id} className=\"flex items-center justify-between\">\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium truncate\">{service.title}</p>\n <p className=\"text-xs text-text-secondary\">{service.category}</p>\n </div>\n <div className=\"flex items-center gap-2 text-sm shrink-0\">\n <Star className=\"h-3.5 w-3.5 text-status-warning-text\" />\n <span className=\"font-semibold\">{service.rating}</span>\n <span className=\"text-xs text-text-secondary\">({service.reviews})</span>\n </div>\n </div>\n ))\n ) : (\n <p className=\"text-sm text-text-secondary\">No performance data yet.</p>\n )}\n </CardContent>\n </Card>\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,69 +1,66 @@
1
1
  import { useCrewFoundryStore as e } from "../store/crewfoundryStore.js";
2
- import { useMemo as t } from "react";
3
- import { Award as n, Briefcase as r, DollarSign as i, MessageSquare as a, Star as o } from "lucide-react";
4
- import { useLocation as s, useNavigate as c } from "react-router-dom";
5
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
6
- import { Badge as d, Button as f, Card as p, CardContent as m, CardHeader as h, CardTitle as g, EmphasisPanel as _, GradientText as v, IllustratedEmptyState as y, PagePurpose as b } from "@burdenoff/fe-libs/ui";
2
+ import { getInitials as t } from "../components/viz/lib/format.js";
3
+ import { RatingStars as n } from "../components/viz/RatingStars.js";
4
+ import "../components/viz/index.js";
5
+ import { useMemo as r } from "react";
6
+ import { Award as i, Briefcase as a, DollarSign as o, MessageSquare as s, Star as c } from "lucide-react";
7
+ import { useLocation as l, useNavigate as u } from "react-router-dom";
8
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
9
+ import { Badge as p, Button as m, Card as h, CardContent as g, CardHeader as _, CardTitle as v, EmphasisPanel as y, GradientText as b, IllustratedEmptyState as x, PagePurpose as S } from "@burdenoff/fe-libs/ui";
7
10
  //#region src/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.tsx
8
- var x = (e) => e.split(" ").map((e) => e[0] ?? "").join("").slice(0, 2).toUpperCase() || "—";
9
- function S() {
10
- let S = c(), C = s(), { marketplaceServices: w } = e(), T = new URLSearchParams(C.search).get("id"), E = w.find((e) => e.id === T) ?? w[0], D = E?.provider ?? "", O = t(() => w.filter((e) => e.provider === D), [w, D]), k = t(() => Array.from(new Set(O.flatMap((e) => e.skills))).slice(0, 20), [O]), A = t(() => Array.from(new Set(O.map((e) => e.category))), [O]), j = O.length > 0 ? (O.reduce((e, t) => e + t.rating, 0) / O.length).toFixed(1) : "0.0", M = O.reduce((e, t) => e + t.reviews, 0), N = O.length > 0 ? Math.min(...O.map((e) => e.price)) : 0, P = Number(j) >= 4.5 && M > 0;
11
- return E ? /* @__PURE__ */ u("div", {
11
+ var C = (e) => t(e);
12
+ function w() {
13
+ let t = u(), w = l(), { marketplaceServices: T } = e(), E = new URLSearchParams(w.search).get("id"), D = T.find((e) => e.id === E) ?? T[0], O = D?.provider ?? "", k = r(() => T.filter((e) => e.provider === O), [T, O]), A = r(() => Array.from(new Set(k.flatMap((e) => e.skills))).slice(0, 20), [k]), j = r(() => Array.from(new Set(k.map((e) => e.category))), [k]), M = k.length > 0 ? (k.reduce((e, t) => e + t.rating, 0) / k.length).toFixed(1) : "0.0", N = k.reduce((e, t) => e + t.reviews, 0), P = k.length > 0 ? Math.min(...k.map((e) => e.price)) : 0, F = Number(M) >= 4.5 && N > 0;
14
+ return D ? /* @__PURE__ */ f("div", {
12
15
  className: "space-y-6 p-6",
13
16
  children: [
14
- /* @__PURE__ */ u("div", {
17
+ /* @__PURE__ */ f("div", {
15
18
  className: "flex items-start gap-6",
16
- children: [/* @__PURE__ */ l("div", {
19
+ children: [/* @__PURE__ */ d("div", {
17
20
  className: "flex h-20 w-20 shrink-0 items-center justify-center rounded-full bg-action-primary-bg text-action-primary-text text-2xl font-semibold",
18
- children: x(D)
19
- }), /* @__PURE__ */ u("div", {
21
+ children: C(O)
22
+ }), /* @__PURE__ */ f("div", {
20
23
  className: "flex-1 space-y-2",
21
24
  children: [
22
- /* @__PURE__ */ u("div", {
25
+ /* @__PURE__ */ f("div", {
23
26
  className: "flex items-center gap-3",
24
- children: [/* @__PURE__ */ l("h1", {
27
+ children: [/* @__PURE__ */ d("h1", {
25
28
  className: "text-2xl font-semibold",
26
- children: /* @__PURE__ */ l(v, { children: D })
27
- }), P ? /* @__PURE__ */ l(d, { children: "Top Rated" }) : null]
29
+ children: /* @__PURE__ */ d(b, { children: O })
30
+ }), F ? /* @__PURE__ */ d(p, { children: "Top Rated" }) : null]
28
31
  }),
29
- /* @__PURE__ */ l("p", {
32
+ /* @__PURE__ */ d("p", {
30
33
  className: "text-sm text-text-secondary",
31
- children: A.length > 0 ? `Provider · ${A.join(", ")}` : "Marketplace provider"
34
+ children: j.length > 0 ? `Provider · ${j.join(", ")}` : "Marketplace provider"
32
35
  }),
33
- /* @__PURE__ */ l(b, {
36
+ /* @__PURE__ */ d(S, {
34
37
  className: "mt-1",
35
38
  children: "Review a freelancer's full profile — skills, listed services, and ratings — to decide if they're the right fit before you hire."
36
39
  }),
37
- /* @__PURE__ */ u("div", {
40
+ /* @__PURE__ */ f("div", {
38
41
  className: "flex flex-wrap items-center gap-4 text-xs text-text-secondary",
39
- children: [/* @__PURE__ */ u("span", {
42
+ children: [/* @__PURE__ */ d(n, {
43
+ value: Number(M),
44
+ count: N,
45
+ showValue: !0,
46
+ size: 14
47
+ }), /* @__PURE__ */ f("span", {
40
48
  className: "flex items-center gap-1",
41
49
  children: [
42
- /* @__PURE__ */ l(o, { className: "h-3 w-3 text-status-warning-text" }),
50
+ /* @__PURE__ */ d(a, { className: "h-3 w-3" }),
43
51
  " ",
44
- j,
45
- " (",
46
- M,
47
- " ",
48
- "reviews)"
49
- ]
50
- }), /* @__PURE__ */ u("span", {
51
- className: "flex items-center gap-1",
52
- children: [
53
- /* @__PURE__ */ l(r, { className: "h-3 w-3" }),
54
- " ",
55
- O.length,
52
+ k.length,
56
53
  " services"
57
54
  ]
58
55
  })]
59
56
  }),
60
- /* @__PURE__ */ u("div", {
57
+ /* @__PURE__ */ f("div", {
61
58
  className: "flex gap-2 pt-1",
62
- children: [/* @__PURE__ */ u(f, {
59
+ children: [/* @__PURE__ */ f(m, {
63
60
  size: "sm",
64
- onClick: () => S("../marketplace/messaging-page"),
65
- children: [/* @__PURE__ */ l(a, { className: "h-3 w-3 mr-1" }), " Message"]
66
- }), /* @__PURE__ */ l(f, {
61
+ onClick: () => t("../marketplace/messaging-page"),
62
+ children: [/* @__PURE__ */ d(s, { className: "h-3 w-3 mr-1" }), " Message"]
63
+ }), /* @__PURE__ */ d(m, {
67
64
  size: "sm",
68
65
  variant: "outline",
69
66
  disabled: !0,
@@ -75,95 +72,95 @@ function S() {
75
72
  ]
76
73
  })]
77
74
  }),
78
- /* @__PURE__ */ l("div", {
75
+ /* @__PURE__ */ d("div", {
79
76
  className: "grid gap-4 md:grid-cols-4",
80
77
  children: [
81
78
  {
82
- icon: r,
79
+ icon: a,
83
80
  label: "Services",
84
- value: `${O.length}`,
81
+ value: `${k.length}`,
85
82
  color: "text-status-info-text"
86
83
  },
87
84
  {
88
- icon: o,
85
+ icon: c,
89
86
  label: "Avg Rating",
90
- value: `${j}`,
87
+ value: `${M}`,
91
88
  color: "text-status-warning-text"
92
89
  },
93
90
  {
94
- icon: n,
91
+ icon: i,
95
92
  label: "Total Reviews",
96
- value: `${M}`,
93
+ value: `${N}`,
97
94
  color: "text-status-success-text"
98
95
  },
99
96
  {
100
- icon: i,
97
+ icon: o,
101
98
  label: "Starting Rate",
102
- value: `$${N.toLocaleString()}`,
99
+ value: `$${P.toLocaleString()}`,
103
100
  color: "text-action-primary-bg"
104
101
  }
105
- ].map((e) => /* @__PURE__ */ l(p, { children: /* @__PURE__ */ u(m, {
102
+ ].map((e) => /* @__PURE__ */ d(h, { children: /* @__PURE__ */ f(g, {
106
103
  className: "flex items-center gap-3 pt-6",
107
- children: [/* @__PURE__ */ l(e.icon, { className: `h-5 w-5 ${e.color}` }), /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("p", {
104
+ children: [/* @__PURE__ */ d(e.icon, { className: `h-5 w-5 ${e.color}` }), /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("p", {
108
105
  className: "text-xs text-text-secondary",
109
106
  children: e.label
110
- }), /* @__PURE__ */ l("p", {
107
+ }), /* @__PURE__ */ d("p", {
111
108
  className: "text-lg font-bold",
112
109
  children: e.value
113
110
  })] })]
114
111
  }) }, e.label))
115
112
  }),
116
- /* @__PURE__ */ u("div", {
113
+ /* @__PURE__ */ f("div", {
117
114
  className: "grid gap-6 lg:grid-cols-3",
118
- children: [/* @__PURE__ */ u("div", {
115
+ children: [/* @__PURE__ */ f("div", {
119
116
  className: "lg:col-span-2 space-y-6",
120
- children: [/* @__PURE__ */ u(_, { children: [/* @__PURE__ */ l("div", {
117
+ children: [/* @__PURE__ */ f(y, { children: [/* @__PURE__ */ d("div", {
121
118
  className: "mb-2 text-base font-semibold",
122
119
  children: "Overview"
123
- }), /* @__PURE__ */ u("p", {
120
+ }), /* @__PURE__ */ f("p", {
124
121
  className: "text-sm text-text-secondary",
125
122
  children: [
126
- D,
123
+ O,
127
124
  " offers ",
128
- O.length,
125
+ k.length,
129
126
  " ",
130
- O.length === 1 ? "service" : "services",
127
+ k.length === 1 ? "service" : "services",
131
128
  " on the marketplace",
132
- A.length > 0 ? ` across ${A.join(", ")}` : "",
129
+ j.length > 0 ? ` across ${j.join(", ")}` : "",
133
130
  ", with an average rating of ",
134
- j,
135
- " from ",
136
131
  M,
132
+ " from ",
133
+ N,
137
134
  " reviews."
138
135
  ]
139
- })] }), /* @__PURE__ */ u(p, { children: [/* @__PURE__ */ l(h, { children: /* @__PURE__ */ l(g, {
136
+ })] }), /* @__PURE__ */ f(h, { children: [/* @__PURE__ */ d(_, { children: /* @__PURE__ */ d(v, {
140
137
  className: "text-base",
141
138
  children: "Listed Services"
142
- }) }), /* @__PURE__ */ l(m, {
139
+ }) }), /* @__PURE__ */ d(g, {
143
140
  className: "space-y-4",
144
- children: O.map((e) => /* @__PURE__ */ u("button", {
141
+ children: k.map((e) => /* @__PURE__ */ f("button", {
145
142
  type: "button",
146
- onClick: () => S(`../marketplace/service-details-page?id=${e.id}`),
143
+ onClick: () => t(`../marketplace/service-details-page?id=${e.id}`),
147
144
  className: "w-full rounded-lg border p-4 space-y-2 text-left hover:bg-bg-sunken/50 focus:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg",
148
145
  children: [
149
- /* @__PURE__ */ u("div", {
146
+ /* @__PURE__ */ f("div", {
150
147
  className: "flex items-center justify-between",
151
- children: [/* @__PURE__ */ l("p", {
148
+ children: [/* @__PURE__ */ d("p", {
152
149
  className: "font-medium text-sm",
153
150
  children: e.title
154
- }), /* @__PURE__ */ l(d, {
151
+ }), /* @__PURE__ */ d(p, {
155
152
  variant: "secondary",
156
153
  className: "text-[10px]",
157
154
  children: e.deliveryTime
158
155
  })]
159
156
  }),
160
- /* @__PURE__ */ l("p", {
157
+ /* @__PURE__ */ d("p", {
161
158
  className: "text-xs text-text-secondary",
162
159
  children: e.description
163
160
  }),
164
- /* @__PURE__ */ u("div", {
161
+ /* @__PURE__ */ f("div", {
165
162
  className: "flex items-center gap-3 text-xs",
166
- children: [/* @__PURE__ */ u("span", {
163
+ children: [/* @__PURE__ */ f("span", {
167
164
  className: "font-medium",
168
165
  children: [
169
166
  "$",
@@ -171,45 +168,40 @@ function S() {
171
168
  "/",
172
169
  e.priceType
173
170
  ]
174
- }), /* @__PURE__ */ u("span", {
175
- className: "flex items-center gap-1",
176
- children: [
177
- /* @__PURE__ */ l(o, { className: "h-3 w-3 text-status-warning-text" }),
178
- e.rating,
179
- " (",
180
- e.reviews,
181
- ")"
182
- ]
171
+ }), /* @__PURE__ */ d(n, {
172
+ value: e.rating,
173
+ count: e.reviews,
174
+ size: 12
183
175
  })]
184
176
  })
185
177
  ]
186
178
  }, e.id))
187
179
  })] })]
188
- }), /* @__PURE__ */ u("div", {
180
+ }), /* @__PURE__ */ f("div", {
189
181
  className: "space-y-4",
190
- children: [/* @__PURE__ */ u(p, { children: [/* @__PURE__ */ l(h, { children: /* @__PURE__ */ l(g, {
182
+ children: [/* @__PURE__ */ f(h, { children: [/* @__PURE__ */ d(_, { children: /* @__PURE__ */ d(v, {
191
183
  className: "text-sm",
192
184
  children: "Skills & Expertise"
193
- }) }), /* @__PURE__ */ l(m, {
185
+ }) }), /* @__PURE__ */ d(g, {
194
186
  className: "flex flex-wrap gap-1.5",
195
- children: k.length > 0 ? k.map((e) => /* @__PURE__ */ l(d, {
187
+ children: A.length > 0 ? A.map((e) => /* @__PURE__ */ d(p, {
196
188
  variant: "secondary",
197
189
  className: "text-xs",
198
190
  children: e
199
- }, e)) : /* @__PURE__ */ l("p", {
191
+ }, e)) : /* @__PURE__ */ d("p", {
200
192
  className: "text-xs text-text-secondary",
201
193
  children: "No skills listed yet."
202
194
  })
203
- })] }), /* @__PURE__ */ u(p, { children: [/* @__PURE__ */ l(h, { children: /* @__PURE__ */ l(g, {
195
+ })] }), /* @__PURE__ */ f(h, { children: [/* @__PURE__ */ d(_, { children: /* @__PURE__ */ d(v, {
204
196
  className: "text-sm",
205
197
  children: "Service Categories"
206
- }) }), /* @__PURE__ */ l(m, {
198
+ }) }), /* @__PURE__ */ d(g, {
207
199
  className: "flex flex-wrap gap-1.5",
208
- children: A.length > 0 ? A.map((e) => /* @__PURE__ */ l(d, {
200
+ children: j.length > 0 ? j.map((e) => /* @__PURE__ */ d(p, {
209
201
  variant: "outline",
210
202
  className: "text-xs",
211
203
  children: e
212
- }, e)) : /* @__PURE__ */ l("p", {
204
+ }, e)) : /* @__PURE__ */ d("p", {
213
205
  className: "text-xs text-text-secondary",
214
206
  children: "No categories listed yet."
215
207
  })
@@ -217,9 +209,9 @@ function S() {
217
209
  })]
218
210
  })
219
211
  ]
220
- }) : /* @__PURE__ */ l("div", {
212
+ }) : /* @__PURE__ */ d("div", {
221
213
  className: "p-6",
222
- children: /* @__PURE__ */ l(y, {
214
+ children: /* @__PURE__ */ d(x, {
223
215
  illustration: "empty-search",
224
216
  title: "Provider not found",
225
217
  description: "This freelancer is no longer available on the marketplace."
@@ -227,6 +219,6 @@ function S() {
227
219
  });
228
220
  }
229
221
  //#endregion
230
- export { S as MarketplaceFreelancerProfilePagePage };
222
+ export { w as MarketplaceFreelancerProfilePagePage };
231
223
 
232
224
  //# sourceMappingURL=MarketplaceFreelancerProfilePagePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MarketplaceFreelancerProfilePagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Award, Briefcase, DollarSign, MessageSquare, Star } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nconst initialsOf = (name: string): string =>\n name\n .split(' ')\n .map((part) => part[0] ?? '')\n .join('')\n .slice(0, 2)\n .toUpperCase() || '—';\n\nexport function MarketplaceFreelancerProfilePagePage() {\n const navigate = useNavigate();\n const location = useLocation();\n const { marketplaceServices } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n\n const baseService =\n marketplaceServices.find((service) => service.id === selectedId) ?? marketplaceServices[0];\n const providerName = baseService?.provider ?? '';\n\n const providerServices = useMemo(\n () => marketplaceServices.filter((service) => service.provider === providerName),\n [marketplaceServices, providerName]\n );\n\n const skills = useMemo(\n () => Array.from(new Set(providerServices.flatMap((service) => service.skills))).slice(0, 20),\n [providerServices]\n );\n\n const categories = useMemo(\n () => Array.from(new Set(providerServices.map((service) => service.category))),\n [providerServices]\n );\n\n const avgRating =\n providerServices.length > 0\n ? (\n providerServices.reduce((sum, service) => sum + service.rating, 0) /\n providerServices.length\n ).toFixed(1)\n : '0.0';\n const totalReviews = providerServices.reduce((sum, service) => sum + service.reviews, 0);\n const startingRate =\n providerServices.length > 0 ? Math.min(...providerServices.map((service) => service.price)) : 0;\n const isTopRated = Number(avgRating) >= 4.5 && totalReviews > 0;\n\n if (!baseService) {\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Provider not found\"\n description=\"This freelancer is no longer available on the marketplace.\"\n />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start gap-6\">\n <div className=\"flex h-20 w-20 shrink-0 items-center justify-center rounded-full bg-action-primary-bg text-action-primary-text text-2xl font-semibold\">\n {initialsOf(providerName)}\n </div>\n <div className=\"flex-1 space-y-2\">\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{providerName}</GradientText>\n </h1>\n {isTopRated ? <Badge>Top Rated</Badge> : null}\n </div>\n <p className=\"text-sm text-text-secondary\">\n {categories.length > 0 ? `Provider · ${categories.join(', ')}` : 'Marketplace provider'}\n </p>\n <PagePurpose className=\"mt-1\">\n Review a freelancer&apos;s full profile — skills, listed services, and ratings — to\n decide if they&apos;re the right fit before you hire.\n </PagePurpose>\n <div className=\"flex flex-wrap items-center gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" /> {avgRating} ({totalReviews}{' '}\n reviews)\n </span>\n <span className=\"flex items-center gap-1\">\n <Briefcase className=\"h-3 w-3\" /> {providerServices.length} services\n </span>\n </div>\n <div className=\"flex gap-2 pt-1\">\n <Button size=\"sm\" onClick={() => navigate('../marketplace/messaging-page')}>\n <MessageSquare className=\"h-3 w-3 mr-1\" /> Message\n </Button>\n {/* No consultation-booking mutation exists yet — honest disabled control. */}\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled\n title=\"Consultation booking is coming soon\"\n aria-label=\"Book consultation — coming soon\"\n >\n Book Consultation · Coming soon\n </Button>\n </div>\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n {[\n {\n icon: Briefcase,\n label: 'Services',\n value: `${providerServices.length}`,\n color: 'text-status-info-text',\n },\n {\n icon: Star,\n label: 'Avg Rating',\n value: `${avgRating}`,\n color: 'text-status-warning-text',\n },\n {\n icon: Award,\n label: 'Total Reviews',\n value: `${totalReviews}`,\n color: 'text-status-success-text',\n },\n {\n icon: DollarSign,\n label: 'Starting Rate',\n value: `$${startingRate.toLocaleString()}`,\n color: 'text-action-primary-bg',\n },\n ].map((stat) => (\n <Card key={stat.label}>\n <CardContent className=\"flex items-center gap-3 pt-6\">\n <stat.icon className={`h-5 w-5 ${stat.color}`} />\n <div>\n <p className=\"text-xs text-text-secondary\">{stat.label}</p>\n <p className=\"text-lg font-bold\">{stat.value}</p>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-6\">\n <EmphasisPanel>\n <div className=\"mb-2 text-base font-semibold\">Overview</div>\n <p className=\"text-sm text-text-secondary\">\n {providerName} offers {providerServices.length}{' '}\n {providerServices.length === 1 ? 'service' : 'services'} on the marketplace\n {categories.length > 0 ? ` across ${categories.join(', ')}` : ''}, with an average\n rating of {avgRating} from {totalReviews} reviews.\n </p>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Listed Services</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {providerServices.map((service) => (\n <button\n key={service.id}\n type=\"button\"\n onClick={() =>\n navigate(`../marketplace/service-details-page?id=${service.id}`)\n }\n className=\"w-full rounded-lg border p-4 space-y-2 text-left hover:bg-bg-sunken/50 focus:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg\"\n >\n <div className=\"flex items-center justify-between\">\n <p className=\"font-medium text-sm\">{service.title}</p>\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n {service.deliveryTime}\n </Badge>\n </div>\n <p className=\"text-xs text-text-secondary\">{service.description}</p>\n <div className=\"flex items-center gap-3 text-xs\">\n <span className=\"font-medium\">\n ${service.price.toLocaleString()}/{service.priceType}\n </span>\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {service.rating} ({service.reviews})\n </span>\n </div>\n </button>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"space-y-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">Skills &amp; Expertise</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-wrap gap-1.5\">\n {skills.length > 0 ? (\n skills.map((skill) => (\n <Badge key={skill} variant=\"secondary\" className=\"text-xs\">\n {skill}\n </Badge>\n ))\n ) : (\n <p className=\"text-xs text-text-secondary\">No skills listed yet.</p>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">Service Categories</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-wrap gap-1.5\">\n {categories.length > 0 ? (\n categories.map((category) => (\n <Badge key={category} variant=\"outline\" className=\"text-xs\">\n {category}\n </Badge>\n ))\n ) : (\n <p className=\"text-xs text-text-secondary\">No categories listed yet.</p>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MarketplaceFreelancerProfilePagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Award, Briefcase, DollarSign, MessageSquare, Star } from 'lucide-react';\nimport { useMemo } from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\nimport { RatingStars, getInitials } from '../components/viz';\n\nconst initialsOf = (name: string): string => getInitials(name);\n\nexport function MarketplaceFreelancerProfilePagePage() {\n const navigate = useNavigate();\n const location = useLocation();\n const { marketplaceServices } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n\n const baseService =\n marketplaceServices.find((service) => service.id === selectedId) ?? marketplaceServices[0];\n const providerName = baseService?.provider ?? '';\n\n const providerServices = useMemo(\n () => marketplaceServices.filter((service) => service.provider === providerName),\n [marketplaceServices, providerName]\n );\n\n const skills = useMemo(\n () => Array.from(new Set(providerServices.flatMap((service) => service.skills))).slice(0, 20),\n [providerServices]\n );\n\n const categories = useMemo(\n () => Array.from(new Set(providerServices.map((service) => service.category))),\n [providerServices]\n );\n\n const avgRating =\n providerServices.length > 0\n ? (\n providerServices.reduce((sum, service) => sum + service.rating, 0) /\n providerServices.length\n ).toFixed(1)\n : '0.0';\n const totalReviews = providerServices.reduce((sum, service) => sum + service.reviews, 0);\n const startingRate =\n providerServices.length > 0 ? Math.min(...providerServices.map((service) => service.price)) : 0;\n const isTopRated = Number(avgRating) >= 4.5 && totalReviews > 0;\n\n if (!baseService) {\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Provider not found\"\n description=\"This freelancer is no longer available on the marketplace.\"\n />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-start gap-6\">\n <div className=\"flex h-20 w-20 shrink-0 items-center justify-center rounded-full bg-action-primary-bg text-action-primary-text text-2xl font-semibold\">\n {initialsOf(providerName)}\n </div>\n <div className=\"flex-1 space-y-2\">\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{providerName}</GradientText>\n </h1>\n {isTopRated ? <Badge>Top Rated</Badge> : null}\n </div>\n <p className=\"text-sm text-text-secondary\">\n {categories.length > 0 ? `Provider · ${categories.join(', ')}` : 'Marketplace provider'}\n </p>\n <PagePurpose className=\"mt-1\">\n Review a freelancer&apos;s full profile — skills, listed services, and ratings — to\n decide if they&apos;re the right fit before you hire.\n </PagePurpose>\n <div className=\"flex flex-wrap items-center gap-4 text-xs text-text-secondary\">\n <RatingStars value={Number(avgRating)} count={totalReviews} showValue size={14} />\n <span className=\"flex items-center gap-1\">\n <Briefcase className=\"h-3 w-3\" /> {providerServices.length} services\n </span>\n </div>\n <div className=\"flex gap-2 pt-1\">\n <Button size=\"sm\" onClick={() => navigate('../marketplace/messaging-page')}>\n <MessageSquare className=\"h-3 w-3 mr-1\" /> Message\n </Button>\n {/* No consultation-booking mutation exists yet — honest disabled control. */}\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled\n title=\"Consultation booking is coming soon\"\n aria-label=\"Book consultation — coming soon\"\n >\n Book Consultation · Coming soon\n </Button>\n </div>\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n {[\n {\n icon: Briefcase,\n label: 'Services',\n value: `${providerServices.length}`,\n color: 'text-status-info-text',\n },\n {\n icon: Star,\n label: 'Avg Rating',\n value: `${avgRating}`,\n color: 'text-status-warning-text',\n },\n {\n icon: Award,\n label: 'Total Reviews',\n value: `${totalReviews}`,\n color: 'text-status-success-text',\n },\n {\n icon: DollarSign,\n label: 'Starting Rate',\n value: `$${startingRate.toLocaleString()}`,\n color: 'text-action-primary-bg',\n },\n ].map((stat) => (\n <Card key={stat.label}>\n <CardContent className=\"flex items-center gap-3 pt-6\">\n <stat.icon className={`h-5 w-5 ${stat.color}`} />\n <div>\n <p className=\"text-xs text-text-secondary\">{stat.label}</p>\n <p className=\"text-lg font-bold\">{stat.value}</p>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2 space-y-6\">\n <EmphasisPanel>\n <div className=\"mb-2 text-base font-semibold\">Overview</div>\n <p className=\"text-sm text-text-secondary\">\n {providerName} offers {providerServices.length}{' '}\n {providerServices.length === 1 ? 'service' : 'services'} on the marketplace\n {categories.length > 0 ? ` across ${categories.join(', ')}` : ''}, with an average\n rating of {avgRating} from {totalReviews} reviews.\n </p>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Listed Services</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n {providerServices.map((service) => (\n <button\n key={service.id}\n type=\"button\"\n onClick={() => navigate(`../marketplace/service-details-page?id=${service.id}`)}\n className=\"w-full rounded-lg border p-4 space-y-2 text-left hover:bg-bg-sunken/50 focus:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg\"\n >\n <div className=\"flex items-center justify-between\">\n <p className=\"font-medium text-sm\">{service.title}</p>\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n {service.deliveryTime}\n </Badge>\n </div>\n <p className=\"text-xs text-text-secondary\">{service.description}</p>\n <div className=\"flex items-center gap-3 text-xs\">\n <span className=\"font-medium\">\n ${service.price.toLocaleString()}/{service.priceType}\n </span>\n <RatingStars value={service.rating} count={service.reviews} size={12} />\n </div>\n </button>\n ))}\n </CardContent>\n </Card>\n </div>\n\n <div className=\"space-y-4\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">Skills &amp; Expertise</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-wrap gap-1.5\">\n {skills.length > 0 ? (\n skills.map((skill) => (\n <Badge key={skill} variant=\"secondary\" className=\"text-xs\">\n {skill}\n </Badge>\n ))\n ) : (\n <p className=\"text-xs text-text-secondary\">No skills listed yet.</p>\n )}\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-sm\">Service Categories</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-wrap gap-1.5\">\n {categories.length > 0 ? (\n categories.map((category) => (\n <Badge key={category} variant=\"outline\" className=\"text-xs\">\n {category}\n </Badge>\n ))\n ) : (\n <p className=\"text-xs text-text-secondary\">No categories listed yet.</p>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}