@burdenoff/microfe-crewfoundry 2026.704.1 → 2026.704.2
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.
- package/dist/crewfoundry/components/forms/FormModal.js.map +1 -1
- package/dist/crewfoundry/pages/AdminAdminPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsEmployeeAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsFinancialAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/AnalyticsHiringAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsAnnouncementsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsFilesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsMessagesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsTeamsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CommunicationsVideoCallsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyClientManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyCompanyProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/CompanyVendorManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardEnhancedDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/DashboardExecutiveDashboardPage.js.map +1 -1
- package/dist/crewfoundry/pages/HelpApiDocumentationPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringApplicationsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCandidatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringCreateJobPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringInterviewsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js +1 -1
- package/dist/crewfoundry/pages/HiringJobsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrDepartmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrEmployeesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrLeaveManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrPayrollPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/HrTimeTrackingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningAssessmentsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCertificatesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCourseDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js +1 -1
- package/dist/crewfoundry/pages/LearningCoursesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js +1 -1
- package/dist/crewfoundry/pages/LearningLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js +1 -1
- package/dist/crewfoundry/pages/LearningLearningPathsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/LearningMyLearningPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceBookingManagementPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceEarningsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePageEnhancedPage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceFreelancerProfilePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplacePagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMessagingPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceMyServicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceProjectDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/MarketplaceServiceDetailsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsEscrowPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsInvoicesPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentDashboardPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsPaymentMethodsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/PaymentsSecurityPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsCreateProjectPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamAnalyticsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDetailPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamDirectoryPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamSettingsPagePage.js.map +1 -1
- package/dist/crewfoundry/pages/TeamsTeamsPagePage.js.map +1 -1
- 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';\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\n ? Math.min(...providerServices.map((service) => service.price))\n : 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\n size=\"sm\"\n variant=\"outline\"\n onClick={() => setSelectedTab('availability')}\n >\n <Calendar className=\"h-3 w-3 mr-1\" /> Schedule Call\n </Button>\n </div>\n <PagePurpose className=\"pt-2\">\n A freelancer'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 $\n {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 {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":";;;;;;;AAgCA,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,IACtB,KAAK,IAAI,GAAG,EAAiB,KAAK,MAAY,EAAQ,MAAM,CAAC,GAC7D,GACA,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,mCAAmC;qBAA7E,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;WACE,MAAK;WACL,SAAQ;WACR,eAAe,EAAe,eAAe;qBAH/C,CAKE,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;UACb,EAAa,gBAAgB;UAAC;UAC7B,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,EAAI;SACC,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,6CAA6C,EAAI,KAAK;oBAElE;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,mCAAmC;kBAA7E,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;MA5PJ,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';\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'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 {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":"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"}
|
|
@@ -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\n ? Math.min(...providerServices.map((service) => service.price))\n : 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\n ? `Provider · ${categories.join(', ')}`\n : 'Marketplace provider'}\n </p>\n <PagePurpose className=\"mt-1\">Review a freelancer's full profile — skills, listed services, and ratings — to decide if they're the right fit before you hire.</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 & 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';\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's full profile — skills, listed services, and ratings — to\n decide if they'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 & 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarketplaceMarketplacePagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceMarketplacePagePage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { ShoppingBag, Star, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function MarketplaceMarketplacePagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { marketplaceServices } = useCrewFoundryStore();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 9 });\n const avgRating =\n marketplaceServices.length > 0\n ? (\n marketplaceServices.reduce((s, m) => s + m.rating, 0) / marketplaceServices.length\n ).toFixed(1)\n : '0.0';\n const pagedServices = marketplaceServices.slice(offset, offset + pageSize);\n const openService = (id: string) => navigate(`../../marketplace/service-details-page?id=${id}`);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>\n {t('crewfoundry.marketplace.title', 'HR Services Marketplace')}\n </GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {t('crewfoundry.marketplace.subtitle', 'Find and hire professional HR service providers')}\n </p>\n <PagePurpose className=\"mt-1\"
|
|
1
|
+
{"version":3,"file":"MarketplaceMarketplacePagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceMarketplacePagePage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { ShoppingBag, Star, Users } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function MarketplaceMarketplacePagePage() {\n const { t: translate } = useI18n();\n const navigate = useNavigate();\n const { marketplaceServices } = useCrewFoundryStore();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 9 });\n const avgRating =\n marketplaceServices.length > 0\n ? (\n marketplaceServices.reduce((s, m) => s + m.rating, 0) / marketplaceServices.length\n ).toFixed(1)\n : '0.0';\n const pagedServices = marketplaceServices.slice(offset, offset + pageSize);\n const openService = (id: string) => navigate(`../../marketplace/service-details-page?id=${id}`);\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>\n {t('crewfoundry.marketplace.title', 'HR Services Marketplace')}\n </GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {t('crewfoundry.marketplace.subtitle', 'Find and hire professional HR service providers')}\n </p>\n <PagePurpose className=\"mt-1\">\n Discover freelancers and services for your projects — browse the marketplace to find and\n hire the right talent on demand.\n </PagePurpose>\n </div>\n <div className=\"grid gap-4 md:grid-cols-3\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">\n {t('crewfoundry.marketplace.stats.services', 'Services')}\n </CardTitle>\n <ShoppingBag className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{marketplaceServices.length}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">\n {t('crewfoundry.marketplace.stats.avgRating', 'Avg Rating')}\n </CardTitle>\n <Star className=\"h-4 w-4 text-status-warning-text\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">{avgRating}</div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">\n {t('crewfoundry.marketplace.stats.totalReviews', 'Total Reviews')}\n </CardTitle>\n <Users className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {marketplaceServices.reduce((s, m) => s + m.reviews, 0)}\n </div>\n </CardContent>\n </GlassCard>\n </div>\n <h2 className=\"text-lg font-medium\">\n {t('crewfoundry.marketplace.featured.title', 'Featured Services')}\n </h2>\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {pagedServices.map((svc) => (\n <Card\n key={svc.id}\n role=\"button\"\n tabIndex={0}\n aria-label={`View details for ${svc.title}`}\n onClick={() => openService(svc.id)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n openService(svc.id);\n }\n }}\n className=\"hover:shadow-md transition-shadow cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg\"\n >\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {svc.category}\n </Badge>\n <Badge\n variant={svc.status === 'active' ? 'default' : 'secondary'}\n className=\"text-[10px]\"\n >\n {svc.status}\n </Badge>\n </div>\n <CardTitle className=\"text-base mt-2\">{svc.title}</CardTitle>\n <CardDescription>{svc.provider}</CardDescription>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-text-secondary mb-3\">{svc.description}</p>\n <div className=\"flex flex-wrap gap-1 mb-3\">\n {svc.skills.map((s) => (\n <Badge key={s} variant=\"outline\" className=\"text-[9px]\">\n {s}\n </Badge>\n ))}\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-bold\">\n ${svc.price.toLocaleString()}\n <span className=\"text-xs font-normal text-text-secondary\">/{svc.priceType}</span>\n </span>\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {svc.rating} ({svc.reviews})\n </span>\n </div>\n <p className=\"text-xs text-text-secondary mt-1\">\n {t('crewfoundry.marketplace.card.delivery', 'Delivery')}: {svc.deliveryTime}\n </p>\n </CardContent>\n </Card>\n ))}\n </div>\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={marketplaceServices.length}\n onPageChange={setPage}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarketplaceMarketplaceServicesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n CardContent,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { Search, Star } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore, type MarketplaceService } from '../store/crewfoundryStore';\n\nexport function MarketplaceMarketplaceServicesPagePage() {\n const navigate = useNavigate();\n const { marketplaceServices } = useCrewFoundryStore();\n const [search, setSearch] = useState('');\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 10 });\n const filtered = marketplaceServices.filter((s) =>\n `${s.title} ${s.provider} ${s.category}`.toLowerCase().includes(search.toLowerCase())\n );\n const paged = filtered.slice(offset, offset + pageSize);\n\n const columns: ResponsiveTableColumn<MarketplaceService>[] = [\n {\n key: 'service',\n header: 'Service',\n priority: 'primary',\n cell: (svc) => (\n <div>\n <p className=\"font-medium\">{svc.title}</p>\n <p className=\"text-xs text-text-secondary truncate\">\n {svc.description.slice(0, 60)}\n {svc.description.length > 60 ? '…' : ''}\n </p>\n </div>\n ),\n },\n {\n key: 'provider',\n header: 'Provider',\n priority: 'secondary',\n cell: (svc) => <span className=\"text-text-secondary\">{svc.provider}</span>,\n },\n {\n key: 'category',\n header: 'Category',\n priority: 'secondary',\n cell: (svc) => (\n <Badge variant=\"outline\" className=\"w-fit h-fit text-[10px]\">\n {svc.category}\n </Badge>\n ),\n },\n {\n key: 'price',\n header: 'Price',\n priority: 'secondary',\n cell: (svc) => (\n <span className=\"font-medium\">\n ${svc.price.toLocaleString()}/{svc.priceType}\n </span>\n ),\n },\n {\n key: 'rating',\n header: 'Rating',\n priority: 'secondary',\n cell: (svc) => (\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {svc.rating} ({svc.reviews})\n </span>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'secondary',\n cell: (svc) => (\n <Badge variant={svc.status === 'active' ? 'default' : 'secondary'} className=\"text-[10px]\">\n {svc.status}\n </Badge>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Browse Services</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {marketplaceServices.length} services available\n </p>\n <PagePurpose className=\"mt-1\"
|
|
1
|
+
{"version":3,"file":"MarketplaceMarketplaceServicesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceMarketplaceServicesPagePage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n CardContent,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n Input,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { Search, Star } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore, type MarketplaceService } from '../store/crewfoundryStore';\n\nexport function MarketplaceMarketplaceServicesPagePage() {\n const navigate = useNavigate();\n const { marketplaceServices } = useCrewFoundryStore();\n const [search, setSearch] = useState('');\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 10 });\n const filtered = marketplaceServices.filter((s) =>\n `${s.title} ${s.provider} ${s.category}`.toLowerCase().includes(search.toLowerCase())\n );\n const paged = filtered.slice(offset, offset + pageSize);\n\n const columns: ResponsiveTableColumn<MarketplaceService>[] = [\n {\n key: 'service',\n header: 'Service',\n priority: 'primary',\n cell: (svc) => (\n <div>\n <p className=\"font-medium\">{svc.title}</p>\n <p className=\"text-xs text-text-secondary truncate\">\n {svc.description.slice(0, 60)}\n {svc.description.length > 60 ? '…' : ''}\n </p>\n </div>\n ),\n },\n {\n key: 'provider',\n header: 'Provider',\n priority: 'secondary',\n cell: (svc) => <span className=\"text-text-secondary\">{svc.provider}</span>,\n },\n {\n key: 'category',\n header: 'Category',\n priority: 'secondary',\n cell: (svc) => (\n <Badge variant=\"outline\" className=\"w-fit h-fit text-[10px]\">\n {svc.category}\n </Badge>\n ),\n },\n {\n key: 'price',\n header: 'Price',\n priority: 'secondary',\n cell: (svc) => (\n <span className=\"font-medium\">\n ${svc.price.toLocaleString()}/{svc.priceType}\n </span>\n ),\n },\n {\n key: 'rating',\n header: 'Rating',\n priority: 'secondary',\n cell: (svc) => (\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {svc.rating} ({svc.reviews})\n </span>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'secondary',\n cell: (svc) => (\n <Badge variant={svc.status === 'active' ? 'default' : 'secondary'} className=\"text-[10px]\">\n {svc.status}\n </Badge>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Browse Services</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {marketplaceServices.length} services available\n </p>\n <PagePurpose className=\"mt-1\">\n Explore services offered on the marketplace — search and compare offerings to find exactly\n the help your project needs.\n </PagePurpose>\n </div>\n <div className=\"relative max-w-sm\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder=\"Search services...\"\n className=\"pl-9\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n </div>\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"p-4\">\n <ResponsiveTable\n columns={columns}\n data={paged}\n rowKey={(svc) => svc.id}\n onRowClick={(svc) => navigate(`../../marketplace/service-details-page?id=${svc.id}`)}\n emptyState={\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No services found\"\n description=\"Try a different search term to find the help you need.\"\n />\n }\n />\n </CardContent>\n </GlassCard>\n {filtered.length > 0 ? (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={filtered.length}\n onPageChange={setPage}\n />\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAkBA,SAAgB,IAAyC;CACvD,IAAM,IAAW,GAAa,EACxB,EAAE,2BAAwB,GAAqB,EAC/C,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,EAAE,SAAM,aAAU,WAAQ,eAAY,EAAc,EAAE,iBAAiB,IAAI,CAAC,EAC5E,IAAW,EAAoB,QAAQ,MAC3C,GAAG,EAAE,MAAM,GAAG,EAAE,SAAS,GAAG,EAAE,WAAW,aAAa,CAAC,SAAS,EAAO,aAAa,CAAC,CACtF,EACK,IAAQ,EAAS,MAAM,GAAQ,IAAS,EAAS;AAkEvD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,MAAD;KAAI,WAAU;eACZ,kBAAC,GAAD,EAAA,UAAc,mBAA8B,CAAA;KACzC,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eAAb,CACG,EAAoB,QAAO,sBAC1B;;IACJ,kBAAC,GAAD;KAAa,WAAU;eAAO;KAGhB,CAAA;IACV,EAAA,CAAA;GACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,wEAAyE,CAAA,EAC3F,kBAAC,GAAD;KACE,aAAY;KACZ,WAAU;KACV,OAAO;KACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;KAC1C,CAAA,CACE;;GACN,kBAAC,GAAD;IAAW,WAAU;IAAQ,MAAA;IAAK,WAAU;cAC1C,kBAAC,GAAD;KAAa,WAAU;eACrB,kBAAC,GAAD;MACW,SA1F0C;OAC3D;QACE,KAAK;QACL,QAAQ;QACR,UAAU;QACV,OAAO,MACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAe,EAAI;SAAU,CAAA,EAC1C,kBAAC,KAAD;SAAG,WAAU;mBAAb,CACG,EAAI,YAAY,MAAM,GAAG,GAAG,EAC5B,EAAI,YAAY,SAAS,KAAK,MAAM,GACnC;WACA,EAAA,CAAA;QAET;OACD;QACE,KAAK;QACL,QAAQ;QACR,UAAU;QACV,OAAO,MAAQ,kBAAC,QAAD;SAAM,WAAU;mBAAuB,EAAI;SAAgB,CAAA;QAC3E;OACD;QACE,KAAK;QACL,QAAQ;QACR,UAAU;QACV,OAAO,MACL,kBAAC,GAAD;SAAO,SAAQ;SAAU,WAAU;mBAChC,EAAI;SACC,CAAA;QAEX;OACD;QACE,KAAK;QACL,QAAQ;QACR,UAAU;QACV,OAAO,MACL,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UAA8B;UAC1B,EAAI,MAAM,gBAAgB;UAAC;UAAE,EAAI;UAC9B;;QAEV;OACD;QACE,KAAK;QACL,QAAQ;QACR,UAAU;QACV,OAAO,MACL,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACE,kBAAC,GAAD,EAAM,WAAU,oCAAqC,CAAA;UACpD,EAAI;UAAO;UAAG,EAAI;UAAQ;UACtB;;QAEV;OACD;QACE,KAAK;QACL,QAAQ;QACR,UAAU;QACV,OAAO,MACL,kBAAC,GAAD;SAAO,SAAS,EAAI,WAAW,WAAW,YAAY;SAAa,WAAU;mBAC1E,EAAI;SACC,CAAA;QAEX;OACF;MA6BS,MAAM;MACN,SAAS,MAAQ,EAAI;MACrB,aAAa,MAAQ,EAAS,6CAA6C,EAAI,KAAK;MACpF,YACE,kBAAC,GAAD;OACE,cAAa;OACb,OAAM;OACN,aAAY;OACZ,CAAA;MAEJ,CAAA;KACU,CAAA;IACJ,CAAA;GACX,EAAS,SAAS,IACjB,kBAAC,GAAD;IACQ;IACI;IACV,YAAY,EAAS;IACrB,cAAc;IACd,CAAA,GACA;GACA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarketplaceMessagingPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceMessagingPagePage.tsx"],"sourcesContent":["import {\n CardContent,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\n\nexport function MarketplaceMessagingPagePage() {\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Service Messages</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Communication with service providers</p>\n <PagePurpose className=\"mt-1\"
|
|
1
|
+
{"version":3,"file":"MarketplaceMessagingPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceMessagingPagePage.tsx"],"sourcesContent":["import {\n CardContent,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\n\nexport function MarketplaceMessagingPagePage() {\n return (\n <div className=\"space-y-6 p-6\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Service Messages</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Communication with service providers</p>\n <PagePurpose className=\"mt-1\">\n Message freelancers and clients about your engagements — keep all marketplace\n conversations in one organized inbox.\n </PagePurpose>\n </div>\n\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"p-6\">\n {/* Direct marketplace messaging has no backend yet. We show an honest\n coming-soon empty state rather than synthesizing message threads\n from unrelated notification data. */}\n <IllustratedEmptyState\n illustration=\"empty-notifications\"\n title=\"Direct messaging is coming soon\"\n description=\"Conversations with providers and clients will appear here once marketplace messaging ships.\"\n />\n </CardContent>\n </GlassCard>\n </div>\n );\n}\n"],"mappings":";;;AAQA,SAAgB,IAA+B;AAC7C,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD,EAAA,UAAA;GACE,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,GAAD,EAAA,UAAc,oBAA+B,CAAA;IAC1C,CAAA;GACL,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAAwC,CAAA;GACnF,kBAAC,GAAD;IAAa,WAAU;cAAO;IAGhB,CAAA;GACV,EAAA,CAAA,EAEN,kBAAC,GAAD;GAAW,WAAU;GAAQ,MAAA;GAAK,WAAU;aAC1C,kBAAC,GAAD;IAAa,WAAU;cAIrB,kBAAC,GAAD;KACE,cAAa;KACb,OAAM;KACN,aAAY;KACZ,CAAA;IACU,CAAA;GACJ,CAAA,CACR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarketplaceMyServicesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceMyServicesPagePage.tsx"],"sourcesContent":["import { useNavigate } from 'react-router-dom';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n Badge,\n Button,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { Eye, Pencil, Plus, Star, Trash2 } from 'lucide-react';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { useCrewFoundryStore, type MarketplaceService } from '../store/crewfoundryStore';\n\nconst SERVICE_FIELDS: FieldConfig[] = [\n { name: 'title', label: 'Service title', type: 'text', required: true, colSpan: 2 },\n { name: 'provider', label: 'Provider', type: 'text', required: true },\n { name: 'category', label: 'Category', type: 'text', required: true },\n { name: 'price', label: 'Price', type: 'number', required: true },\n {\n name: 'priceType',\n label: 'Price type',\n type: 'select',\n required: true,\n options: [\n { label: 'Hourly', value: 'hourly' },\n { label: 'Fixed', value: 'fixed' },\n { label: 'Monthly', value: 'monthly' },\n ],\n },\n { name: 'deliveryTime', label: 'Delivery time', type: 'text', required: true, placeholder: 'e.g. 3 days' },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Paused', value: 'paused' },\n { label: 'Pending', value: 'pending' },\n ],\n },\n { name: 'description', label: 'Description', type: 'textarea', required: true, colSpan: 2 },\n { name: 'skills', label: 'Skills', type: 'tags', colSpan: 2 },\n];\n\nconst toInitialValues = (service: MarketplaceService): FormValues => ({\n title: service.title,\n provider: service.provider,\n category: service.category,\n price: service.price,\n priceType: service.priceType,\n deliveryTime: service.deliveryTime,\n status: service.status,\n description: service.description,\n skills: service.skills,\n});\n\nconst valuesToService = (\n values: FormValues,\n base?: MarketplaceService\n): MarketplaceService => ({\n id: base?.id ?? crypto.randomUUID(),\n title: String(values.title ?? ''),\n provider: String(values.provider ?? ''),\n category: String(values.category ?? ''),\n price: typeof values.price === 'number' ? values.price : Number(values.price) || 0,\n priceType: (values.priceType as MarketplaceService['priceType']) || 'hourly',\n rating: base?.rating ?? 0,\n reviews: base?.reviews ?? 0,\n description: String(values.description ?? ''),\n deliveryTime: String(values.deliveryTime ?? ''),\n status: (values.status as MarketplaceService['status']) || 'active',\n skills: Array.isArray(values.skills) ? values.skills : [],\n});\n\nexport function MarketplaceMyServicesPagePage() {\n const navigate = useNavigate();\n const { marketplaceServices, addMarketplaceService, updateMarketplaceService, removeMarketplaceService } =\n useCrewFoundryStore();\n const modal = useFormModal<MarketplaceService>();\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 9 });\n // Every marketplace service in this workspace is managed here as an owned listing.\n const myServices = marketplaceServices.slice(offset, offset + pageSize);\n\n const handleSubmit = async (values: FormValues) => {\n if (modal.context) {\n await updateMarketplaceService(modal.context.id, valuesToService(values, modal.context));\n } else {\n await addMarketplaceService(valuesToService(values));\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>My Services</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Manage your listed services</p>\n <PagePurpose className=\"mt-1\">Manage the services you offer to clients — list, edit, and showcase your offerings to win more work on the marketplace.</PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => modal.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Create Service\n </Button>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {marketplaceServices.length === 0 ? (\n <div className=\"col-span-full\">\n <IllustratedEmptyState illustration=\"empty-generic\" title=\"No services listed\" description=\"List a service to start winning work on the marketplace.\" />\n </div>\n ) : (\n myServices.map((svc, _idx) => (\n <GlassCard key={svc.id} treatment={_idx === 0 ? 'glass' : 'plain'} glow={_idx === 0}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{svc.title}</CardTitle>\n <Badge\n variant={svc.status === 'active' ? 'default' : 'secondary'}\n className=\"text-[10px]\"\n >\n {svc.status}\n </Badge>\n </div>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-text-secondary mb-3\">{svc.description}</p>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-bold\">\n ${svc.price}/{svc.priceType}\n </span>\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {svc.rating} ({svc.reviews})\n </span>\n </div>\n <div className=\"flex gap-2 mt-3\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"flex-1\"\n onClick={() => modal.openModal(svc)}\n >\n <Pencil className=\"h-3.5 w-3.5 mr-1\" />\n Edit\n </Button>\n <Button\n size=\"sm\"\n className=\"flex-1\"\n onClick={() =>\n navigate(`../../marketplace/service-details-page?id=${svc.id}`)\n }\n >\n <Eye className=\"h-3.5 w-3.5 mr-1\" />\n View\n </Button>\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label={`Delete ${svc.title}`}>\n <Trash2 className=\"h-4 w-4 text-status-error-text\" />\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete service?</AlertDialogTitle>\n <AlertDialogDescription>\n This removes “{svc.title}” from your marketplace listings. This action cannot be undone.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction onClick={() => void removeMarketplaceService(svc.id)}>\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n </CardContent>\n </GlassCard>\n )))}\n </div>\n {marketplaceServices.length > 0 ? (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={marketplaceServices.length}\n onPageChange={setPage}\n />\n ) : null}\n\n <FormModal\n open={modal.open}\n onOpenChange={modal.onOpenChange}\n title={modal.context ? 'Edit service' : 'Create service'}\n description=\"Describe the service you offer clients on the marketplace.\"\n fields={SERVICE_FIELDS}\n initialValues={modal.context ? toInitialValues(modal.context) : undefined}\n submitLabel={modal.context ? 'Save changes' : 'Create service'}\n onSubmit={handleSubmit}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MarketplaceMyServicesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceMyServicesPagePage.tsx"],"sourcesContent":["import { useNavigate } from 'react-router-dom';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n Badge,\n Button,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { Eye, Pencil, Plus, Star, Trash2 } from 'lucide-react';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { useCrewFoundryStore, type MarketplaceService } from '../store/crewfoundryStore';\n\nconst SERVICE_FIELDS: FieldConfig[] = [\n { name: 'title', label: 'Service title', type: 'text', required: true, colSpan: 2 },\n { name: 'provider', label: 'Provider', type: 'text', required: true },\n { name: 'category', label: 'Category', type: 'text', required: true },\n { name: 'price', label: 'Price', type: 'number', required: true },\n {\n name: 'priceType',\n label: 'Price type',\n type: 'select',\n required: true,\n options: [\n { label: 'Hourly', value: 'hourly' },\n { label: 'Fixed', value: 'fixed' },\n { label: 'Monthly', value: 'monthly' },\n ],\n },\n {\n name: 'deliveryTime',\n label: 'Delivery time',\n type: 'text',\n required: true,\n placeholder: 'e.g. 3 days',\n },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Paused', value: 'paused' },\n { label: 'Pending', value: 'pending' },\n ],\n },\n { name: 'description', label: 'Description', type: 'textarea', required: true, colSpan: 2 },\n { name: 'skills', label: 'Skills', type: 'tags', colSpan: 2 },\n];\n\nconst toInitialValues = (service: MarketplaceService): FormValues => ({\n title: service.title,\n provider: service.provider,\n category: service.category,\n price: service.price,\n priceType: service.priceType,\n deliveryTime: service.deliveryTime,\n status: service.status,\n description: service.description,\n skills: service.skills,\n});\n\nconst valuesToService = (values: FormValues, base?: MarketplaceService): MarketplaceService => ({\n id: base?.id ?? crypto.randomUUID(),\n title: String(values.title ?? ''),\n provider: String(values.provider ?? ''),\n category: String(values.category ?? ''),\n price: typeof values.price === 'number' ? values.price : Number(values.price) || 0,\n priceType: (values.priceType as MarketplaceService['priceType']) || 'hourly',\n rating: base?.rating ?? 0,\n reviews: base?.reviews ?? 0,\n description: String(values.description ?? ''),\n deliveryTime: String(values.deliveryTime ?? ''),\n status: (values.status as MarketplaceService['status']) || 'active',\n skills: Array.isArray(values.skills) ? values.skills : [],\n});\n\nexport function MarketplaceMyServicesPagePage() {\n const navigate = useNavigate();\n const {\n marketplaceServices,\n addMarketplaceService,\n updateMarketplaceService,\n removeMarketplaceService,\n } = useCrewFoundryStore();\n const modal = useFormModal<MarketplaceService>();\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 9 });\n // Every marketplace service in this workspace is managed here as an owned listing.\n const myServices = marketplaceServices.slice(offset, offset + pageSize);\n\n const handleSubmit = async (values: FormValues) => {\n if (modal.context) {\n await updateMarketplaceService(modal.context.id, valuesToService(values, modal.context));\n } else {\n await addMarketplaceService(valuesToService(values));\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>My Services</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Manage your listed services</p>\n <PagePurpose className=\"mt-1\">\n Manage the services you offer to clients — list, edit, and showcase your offerings to\n win more work on the marketplace.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => modal.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Create Service\n </Button>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {marketplaceServices.length === 0 ? (\n <div className=\"col-span-full\">\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No services listed\"\n description=\"List a service to start winning work on the marketplace.\"\n />\n </div>\n ) : (\n myServices.map((svc, _idx) => (\n <GlassCard key={svc.id} treatment={_idx === 0 ? 'glass' : 'plain'} glow={_idx === 0}>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{svc.title}</CardTitle>\n <Badge\n variant={svc.status === 'active' ? 'default' : 'secondary'}\n className=\"text-[10px]\"\n >\n {svc.status}\n </Badge>\n </div>\n </CardHeader>\n <CardContent>\n <p className=\"text-sm text-text-secondary mb-3\">{svc.description}</p>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-bold\">\n ${svc.price}/{svc.priceType}\n </span>\n <span className=\"flex items-center gap-1\">\n <Star className=\"h-3 w-3 text-status-warning-text\" />\n {svc.rating} ({svc.reviews})\n </span>\n </div>\n <div className=\"flex gap-2 mt-3\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"flex-1\"\n onClick={() => modal.openModal(svc)}\n >\n <Pencil className=\"h-3.5 w-3.5 mr-1\" />\n Edit\n </Button>\n <Button\n size=\"sm\"\n className=\"flex-1\"\n onClick={() => navigate(`../../marketplace/service-details-page?id=${svc.id}`)}\n >\n <Eye className=\"h-3.5 w-3.5 mr-1\" />\n View\n </Button>\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label={`Delete ${svc.title}`}>\n <Trash2 className=\"h-4 w-4 text-status-error-text\" />\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete service?</AlertDialogTitle>\n <AlertDialogDescription>\n This removes “{svc.title}” from your marketplace listings. This action\n cannot be undone.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction onClick={() => void removeMarketplaceService(svc.id)}>\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n </CardContent>\n </GlassCard>\n ))\n )}\n </div>\n {marketplaceServices.length > 0 ? (\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={marketplaceServices.length}\n onPageChange={setPage}\n />\n ) : null}\n\n <FormModal\n open={modal.open}\n onOpenChange={modal.onOpenChange}\n title={modal.context ? 'Edit service' : 'Create service'}\n description=\"Describe the service you offer clients on the marketplace.\"\n fields={SERVICE_FIELDS}\n initialValues={modal.context ? toInitialValues(modal.context) : undefined}\n submitLabel={modal.context ? 'Save changes' : 'Create service'}\n onSubmit={handleSubmit}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarketplaceProjectDetailsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceProjectDetailsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Calendar, DollarSign, MessageSquare, Users } from 'lucide-react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function MarketplaceProjectDetailsPagePage() {\n const navigate = useNavigate();\n const location = useLocation();\n const { projects } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n const project = projects.find((p) => p.id === selectedId) ?? projects[0];\n if (!project)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Project not found\"\n description=\"This project is no longer available.\"\n />\n </div>\n );\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{project.name}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{project.description}</p>\n <PagePurpose className=\"mt-2\">\n The full picture of a marketplace project — scope, budget, timeline, and progress — so\n you can track delivery and stay aligned with the team doing the work.\n </PagePurpose>\n </div>\n <Badge variant={project.status === 'active' ? 'default' : 'secondary'}>\n {project.status}\n </Badge>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-marketplace-project-details\"\n steps={[\n {\n id: 'message',\n label: 'Message the team',\n description: 'Coordinate on scope, blockers, and next milestones.',\n icon: <MessageSquare className=\"h-4 w-4\" />,\n onClick: () => navigate('../../marketplace/messaging-page'),\n },\n {\n id: 'bookings',\n label: 'Review bookings',\n description: 'Check the engagements tied to this project.',\n icon: <Calendar className=\"h-4 w-4\" />,\n onClick: () => navigate('../../marketplace/booking-management-page'),\n },\n {\n id: 'earnings',\n label: 'Track earnings',\n description: 'See payouts and balances connected to your work.',\n icon: <DollarSign className=\"h-4 w-4\" />,\n onClick: () => navigate('../../marketplace/earnings-page'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <Card>\n <CardContent className=\"p-4 text-center\">\n <DollarSign className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">${(project.budget / 1000).toFixed(0)}K</p>\n <p className=\"text-xs text-text-secondary\">Budget</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <DollarSign className=\"h-5 w-5 mx-auto text-status-success-text mb-1\" />\n <p className=\"text-lg font-bold\">${(project.spent / 1000).toFixed(0)}K</p>\n <p className=\"text-xs text-text-secondary\">Spent</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Users className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{project.teamName}</p>\n <p className=\"text-xs text-text-secondary\">Team</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Calendar className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{project.endDate}</p>\n <p className=\"text-xs text-text-secondary\">Deadline</p>\n </CardContent>\n </Card>\n </div>\n <EmphasisPanel>\n <div className=\"mb-2 text-lg font-semibold\">Progress</div>\n <div className=\"space-y-2\">\n <div className=\"flex justify-between text-sm\">\n <span>\n {project.completedTasks} of {project.tasks} tasks\n </span>\n <span className=\"font-medium\">{project.progress}%</span>\n </div>\n <div className=\"h-3 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-3 bg-action-primary-bg rounded\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4 mt-4\">\n
|
|
1
|
+
{"version":3,"file":"MarketplaceProjectDetailsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceProjectDetailsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Calendar, DollarSign, MessageSquare, Users } from 'lucide-react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function MarketplaceProjectDetailsPagePage() {\n const navigate = useNavigate();\n const location = useLocation();\n const { projects } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n const project = projects.find((p) => p.id === selectedId) ?? projects[0];\n if (!project)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Project not found\"\n description=\"This project is no longer available.\"\n />\n </div>\n );\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{project.name}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{project.description}</p>\n <PagePurpose className=\"mt-2\">\n The full picture of a marketplace project — scope, budget, timeline, and progress — so\n you can track delivery and stay aligned with the team doing the work.\n </PagePurpose>\n </div>\n <Badge variant={project.status === 'active' ? 'default' : 'secondary'}>\n {project.status}\n </Badge>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-marketplace-project-details\"\n steps={[\n {\n id: 'message',\n label: 'Message the team',\n description: 'Coordinate on scope, blockers, and next milestones.',\n icon: <MessageSquare className=\"h-4 w-4\" />,\n onClick: () => navigate('../../marketplace/messaging-page'),\n },\n {\n id: 'bookings',\n label: 'Review bookings',\n description: 'Check the engagements tied to this project.',\n icon: <Calendar className=\"h-4 w-4\" />,\n onClick: () => navigate('../../marketplace/booking-management-page'),\n },\n {\n id: 'earnings',\n label: 'Track earnings',\n description: 'See payouts and balances connected to your work.',\n icon: <DollarSign className=\"h-4 w-4\" />,\n onClick: () => navigate('../../marketplace/earnings-page'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <Card>\n <CardContent className=\"p-4 text-center\">\n <DollarSign className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">${(project.budget / 1000).toFixed(0)}K</p>\n <p className=\"text-xs text-text-secondary\">Budget</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <DollarSign className=\"h-5 w-5 mx-auto text-status-success-text mb-1\" />\n <p className=\"text-lg font-bold\">${(project.spent / 1000).toFixed(0)}K</p>\n <p className=\"text-xs text-text-secondary\">Spent</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Users className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{project.teamName}</p>\n <p className=\"text-xs text-text-secondary\">Team</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Calendar className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{project.endDate}</p>\n <p className=\"text-xs text-text-secondary\">Deadline</p>\n </CardContent>\n </Card>\n </div>\n <EmphasisPanel>\n <div className=\"mb-2 text-lg font-semibold\">Progress</div>\n <div className=\"space-y-2\">\n <div className=\"flex justify-between text-sm\">\n <span>\n {project.completedTasks} of {project.tasks} tasks\n </span>\n <span className=\"font-medium\">{project.progress}%</span>\n </div>\n <div className=\"h-3 bg-bg-sunken rounded overflow-hidden\">\n <div\n className=\"h-3 bg-action-primary-bg rounded\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4 mt-4\">\n <div>\n <p className=\"text-xs text-text-secondary\">Manager</p>\n <p className=\"text-sm font-medium\">{project.managerName}</p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Priority</p>\n <Badge\n variant={\n project.priority === 'critical'\n ? 'destructive'\n : project.priority === 'high'\n ? 'default'\n : 'secondary'\n }\n >\n {project.priority}\n </Badge>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">Start Date</p>\n <p className=\"text-sm\">{project.startDate}</p>\n </div>\n <div>\n <p className=\"text-xs text-text-secondary\">End Date</p>\n <p className=\"text-sm\">{project.endDate}</p>\n </div>\n </div>\n </EmphasisPanel>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarketplaceServiceDetailsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceServiceDetailsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Clock, DollarSign, MessageSquare, Star, Users } from 'lucide-react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function MarketplaceServiceDetailsPagePage() {\n const navigate = useNavigate();\n const location = useLocation();\n const { marketplaceServices } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n const svc = marketplaceServices.find((s) => s.id === selectedId) ?? marketplaceServices[0];\n if (!svc)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Service not found\"\n description=\"This service is no longer available.\"\n />\n </div>\n );\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{svc.title}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">by {svc.provider}</p>\n <PagePurpose className=\"mt-2\">\n See exactly what this service includes, what it costs, and how others rated it — use it\n to compare offerings and hire the right provider for your project.\n </PagePurpose>\n </div>\n <div className=\"flex gap-2\">\n <Button
|
|
1
|
+
{"version":3,"file":"MarketplaceServiceDetailsPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/MarketplaceServiceDetailsPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n EmphasisPanel,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Clock, DollarSign, MessageSquare, Star, Users } from 'lucide-react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useCrewFoundryStore } from '../store/crewfoundryStore';\n\nexport function MarketplaceServiceDetailsPagePage() {\n const navigate = useNavigate();\n const location = useLocation();\n const { marketplaceServices } = useCrewFoundryStore();\n const selectedId = new URLSearchParams(location.search).get('id');\n const svc = marketplaceServices.find((s) => s.id === selectedId) ?? marketplaceServices[0];\n if (!svc)\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Service not found\"\n description=\"This service is no longer available.\"\n />\n </div>\n );\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>{svc.title}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">by {svc.provider}</p>\n <PagePurpose className=\"mt-2\">\n See exactly what this service includes, what it costs, and how others rated it — use it\n to compare offerings and hire the right provider for your project.\n </PagePurpose>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" onClick={() => navigate('../../marketplace/messaging-page')}>\n <MessageSquare className=\"h-4 w-4 mr-1\" />\n Contact\n </Button>\n {/* No hire/engagement mutation exists yet, so this stays an honest\n disabled control rather than a silently-dead primary CTA. */}\n <Button disabled title=\"Hiring is coming soon\" aria-label=\"Hire now — coming soon\">\n Hire Now · Coming soon\n </Button>\n </div>\n </div>\n\n <NextSteps\n storageKey=\"crewfoundry-service-details\"\n steps={[\n {\n id: 'contact',\n label: 'Message the provider',\n description: 'Ask questions before you commit to hiring.',\n icon: <MessageSquare className=\"h-4 w-4\" />,\n onClick: () => navigate('../../marketplace/messaging-page'),\n },\n {\n id: 'compare',\n label: 'Compare other services',\n description: 'Browse similar offerings on the marketplace.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('../../marketplace/marketplace-services-page'),\n },\n {\n id: 'bookings',\n label: 'Manage your bookings',\n description: 'Track engagements you have already arranged.',\n icon: <Clock className=\"h-4 w-4\" />,\n onClick: () => navigate('../../marketplace/booking-management-page'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <Card>\n <CardContent className=\"p-4 text-center\">\n <DollarSign className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">${svc.price.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">per {svc.priceType}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Star className=\"h-5 w-5 mx-auto text-status-warning-text mb-1\" />\n <p className=\"text-lg font-bold\">{svc.rating}/5</p>\n <p className=\"text-xs text-text-secondary\">{svc.reviews} reviews</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Clock className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{svc.deliveryTime}</p>\n <p className=\"text-xs text-text-secondary\">Delivery</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"p-4 text-center\">\n <Users className=\"h-5 w-5 mx-auto text-text-secondary mb-1\" />\n <p className=\"text-lg font-bold\">{svc.category}</p>\n <p className=\"text-xs text-text-secondary\">Category</p>\n </CardContent>\n </Card>\n </div>\n <EmphasisPanel>\n <div className=\"mb-2 text-lg font-semibold\">About this Service</div>\n <p className=\"text-sm text-text-secondary\">{svc.description}</p>\n <div className=\"flex flex-wrap gap-1 mt-3\">\n {svc.skills.map((s) => (\n <Badge key={s} variant=\"outline\">\n {s}\n </Badge>\n ))}\n </div>\n </EmphasisPanel>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PaymentsEscrowPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/PaymentsEscrowPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n CardContent,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Lock } from 'lucide-react';\n\nexport function PaymentsEscrowPagePage() {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Escrow</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\"
|
|
1
|
+
{"version":3,"file":"PaymentsEscrowPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/PaymentsEscrowPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n CardContent,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Lock } from 'lucide-react';\n\nexport function PaymentsEscrowPagePage() {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Escrow</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Secure payment holding for service contracts\n </p>\n <PagePurpose className=\"mt-1\">\n Hold and release project funds safely in escrow — protect both sides until milestones\n are met and work is approved.\n </PagePurpose>\n </div>\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n Coming soon\n </Badge>\n <Button\n size=\"sm\"\n disabled\n aria-label=\"Fund escrow (coming soon)\"\n title=\"Escrow funding is coming soon\"\n >\n <Lock className=\"mr-1 h-4 w-4\" />\n Fund Escrow\n </Button>\n </div>\n </div>\n\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"Escrow is on the way\"\n description=\"Milestone-based escrow — funding, holding, and releasing project payments against approved work — isn't available yet. When it launches you'll be able to fund contracts, track held balances, and release funds as milestones are approved.\"\n />\n </CardContent>\n </GlassCard>\n </div>\n );\n}\n"],"mappings":";;;;AAWA,SAAgB,IAAyB;AACvC,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,MAAD;KAAI,WAAU;eACZ,kBAAC,GAAD,EAAA,UAAc,UAAqB,CAAA;KAChC,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAEvC,CAAA;IACJ,kBAAC,GAAD;KAAa,WAAU;eAAO;KAGhB,CAAA;IACV,EAAA,CAAA,EACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAO,SAAQ;KAAY,WAAU;eAAc;KAE3C,CAAA,EACR,kBAAC,GAAD;KACE,MAAK;KACL,UAAA;KACA,cAAW;KACX,OAAM;eAJR,CAME,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,cAE1B;OACL;MACF;MAEN,kBAAC,GAAD;GAAW,WAAU;GAAQ,MAAA;GAAK,WAAU;aAC1C,kBAAC,GAAD;IAAa,WAAU;cACrB,kBAAC,GAAD;KACE,cAAa;KACb,OAAM;KACN,aAAY;KACZ,CAAA;IACU,CAAA;GACJ,CAAA,CACR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PaymentsInvoicesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/PaymentsInvoicesPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n CardContent,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { CheckCircle2, Pencil, Plus } from 'lucide-react';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { useCrewFoundryStore, type Invoice } from '../store/crewfoundryStore';\n\nconst INVOICE_FIELDS: FieldConfig[] = [\n { name: 'number', label: 'Invoice number', type: 'text', required: true, placeholder: 'INV-0001' },\n { name: 'clientName', label: 'Client name', type: 'text', required: true },\n { name: 'amount', label: 'Amount (USD)', type: 'number', required: true },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Draft', value: 'draft' },\n { label: 'Sent', value: 'sent' },\n { label: 'Paid', value: 'paid' },\n { label: 'Overdue', value: 'overdue' },\n { label: 'Cancelled', value: 'cancelled' },\n ],\n },\n { name: 'issueDate', label: 'Issue date', type: 'date', required: true },\n { name: 'dueDate', label: 'Due date', type: 'date' },\n {\n name: 'lineItem',\n label: 'Line item description',\n type: 'text',\n colSpan: 2,\n placeholder: 'e.g. Consulting services',\n },\n];\n\nconst toInitialValues = (invoice: Invoice): FormValues => ({\n number: invoice.number,\n clientName: invoice.clientName,\n amount: invoice.amount,\n status: invoice.status,\n issueDate: invoice.issueDate ? invoice.issueDate.slice(0, 10) : '',\n dueDate: invoice.dueDate ? invoice.dueDate.slice(0, 10) : '',\n lineItem: invoice.items[0]?.description ?? '',\n});\n\nconst valuesToInvoice = (values: FormValues, base?: Invoice): Invoice => {\n const amount = typeof values.amount === 'number' ? values.amount : Number(values.amount) || 0;\n const description = String(values.lineItem ?? '').trim() || 'Services rendered';\n return {\n id: base?.id ?? crypto.randomUUID(),\n number: String(values.number ?? ''),\n clientName: String(values.clientName ?? ''),\n amount,\n status: (values.status as Invoice['status']) || 'draft',\n issueDate: String(values.issueDate ?? ''),\n dueDate: String(values.dueDate ?? ''),\n items: [{ description, amount }],\n };\n};\n\nconst statusVariant = (status: Invoice['status']) =>\n status === 'paid'\n ? 'default'\n : status === 'overdue'\n ? 'destructive'\n : status === 'draft'\n ? 'outline'\n : 'secondary';\n\nexport function PaymentsInvoicesPagePage() {\n const { invoices, addInvoice, updateInvoice } = useCrewFoundryStore();\n const modal = useFormModal<Invoice>();\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 25 });\n\n const sorted = [...invoices].sort((a, b) => (b.issueDate ?? '').localeCompare(a.issueDate ?? ''));\n const paged = sorted.slice(offset, offset + pageSize);\n\n const handleSubmit = async (values: FormValues) => {\n if (modal.context) {\n await updateInvoice(modal.context.id, valuesToInvoice(values, modal.context));\n } else {\n await addInvoice(valuesToInvoice(values));\n }\n };\n\n const columns: ResponsiveTableColumn<Invoice>[] = [\n {\n key: 'number',\n header: 'Invoice #',\n priority: 'primary',\n cell: (inv) => <span className=\"font-medium\">{inv.number}</span>,\n },\n {\n key: 'client',\n header: 'Client',\n priority: 'secondary',\n cell: (inv) => <span className=\"text-text-secondary\">{inv.clientName}</span>,\n },\n {\n key: 'items',\n header: 'Items',\n priority: 'hidden-on-mobile',\n cell: (inv) => (\n <span className=\"text-xs text-text-secondary\">\n {inv.items.map((i) => i.description).join(', ')}\n </span>\n ),\n },\n {\n key: 'amount',\n header: 'Amount',\n priority: 'secondary',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (inv) => <span className=\"font-medium\">${inv.amount.toLocaleString()}</span>,\n },\n {\n key: 'dueDate',\n header: 'Due Date',\n priority: 'secondary',\n cell: (inv) => <span className=\"text-text-secondary\">{inv.dueDate}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'secondary',\n cell: (inv) => (\n <Badge variant={statusVariant(inv.status)} className=\"text-[10px]\">\n {inv.status}\n </Badge>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Invoices</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{invoices.length} invoices</p>\n <PagePurpose className=\"mt-1\">Create, send, and track invoices — see what's paid, pending, or overdue so you stay on top of getting paid.</PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => modal.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Create Invoice\n </Button>\n </div>\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"p-4\">\n <ResponsiveTable\n data={paged}\n rowKey={(inv) => inv.id}\n columns={columns}\n emptyState={\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No invoices yet\"\n description=\"Create your first invoice to start getting paid.\"\n />\n }\n rowActions={(inv) => (\n <div className=\"flex items-center justify-end gap-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Edit invoice ${inv.number}`}\n onClick={() => modal.openModal(inv)}\n >\n <Pencil className=\"h-3.5 w-3.5\" />\n </Button>\n {inv.status === 'paid' ? (\n <span className=\"inline-flex items-center gap-1 text-xs text-status-success-text\">\n <CheckCircle2 className=\"h-3.5 w-3.5\" />\n Paid\n </span>\n ) : (\n <Button\n variant=\"outline\"\n size=\"sm\"\n aria-label={`Mark invoice ${inv.number} as paid`}\n onClick={() => void updateInvoice(inv.id, { status: 'paid' })}\n >\n <CheckCircle2 className=\"h-3.5 w-3.5 mr-1\" />\n Mark Paid\n </Button>\n )}\n </div>\n )}\n />\n {sorted.length > pageSize && (\n <div className=\"mt-4\">\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={sorted.length}\n onPageChange={setPage}\n />\n </div>\n )}\n </CardContent>\n </GlassCard>\n\n <FormModal\n open={modal.open}\n onOpenChange={modal.onOpenChange}\n title={modal.context ? 'Edit invoice' : 'Create invoice'}\n description=\"Issue a new invoice to a client and track its payment status.\"\n fields={INVOICE_FIELDS}\n initialValues={modal.context ? toInitialValues(modal.context) : undefined}\n submitLabel={modal.context ? 'Save changes' : 'Create invoice'}\n onSubmit={handleSubmit}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PaymentsInvoicesPagePage.js","names":[],"sources":["../../../src/crewfoundry/pages/PaymentsInvoicesPagePage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n CardContent,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n Pagination,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { usePagination } from '@burdenoff/fe-libs/shared/hooks';\nimport { CheckCircle2, Pencil, Plus } from 'lucide-react';\nimport {\n FormModal,\n useFormModal,\n type FieldConfig,\n type FormValues,\n} from '../components/forms/FormModal';\nimport { useCrewFoundryStore, type Invoice } from '../store/crewfoundryStore';\n\nconst INVOICE_FIELDS: FieldConfig[] = [\n {\n name: 'number',\n label: 'Invoice number',\n type: 'text',\n required: true,\n placeholder: 'INV-0001',\n },\n { name: 'clientName', label: 'Client name', type: 'text', required: true },\n { name: 'amount', label: 'Amount (USD)', type: 'number', required: true },\n {\n name: 'status',\n label: 'Status',\n type: 'select',\n options: [\n { label: 'Draft', value: 'draft' },\n { label: 'Sent', value: 'sent' },\n { label: 'Paid', value: 'paid' },\n { label: 'Overdue', value: 'overdue' },\n { label: 'Cancelled', value: 'cancelled' },\n ],\n },\n { name: 'issueDate', label: 'Issue date', type: 'date', required: true },\n { name: 'dueDate', label: 'Due date', type: 'date' },\n {\n name: 'lineItem',\n label: 'Line item description',\n type: 'text',\n colSpan: 2,\n placeholder: 'e.g. Consulting services',\n },\n];\n\nconst toInitialValues = (invoice: Invoice): FormValues => ({\n number: invoice.number,\n clientName: invoice.clientName,\n amount: invoice.amount,\n status: invoice.status,\n issueDate: invoice.issueDate ? invoice.issueDate.slice(0, 10) : '',\n dueDate: invoice.dueDate ? invoice.dueDate.slice(0, 10) : '',\n lineItem: invoice.items[0]?.description ?? '',\n});\n\nconst valuesToInvoice = (values: FormValues, base?: Invoice): Invoice => {\n const amount = typeof values.amount === 'number' ? values.amount : Number(values.amount) || 0;\n const description = String(values.lineItem ?? '').trim() || 'Services rendered';\n return {\n id: base?.id ?? crypto.randomUUID(),\n number: String(values.number ?? ''),\n clientName: String(values.clientName ?? ''),\n amount,\n status: (values.status as Invoice['status']) || 'draft',\n issueDate: String(values.issueDate ?? ''),\n dueDate: String(values.dueDate ?? ''),\n items: [{ description, amount }],\n };\n};\n\nconst statusVariant = (status: Invoice['status']) =>\n status === 'paid'\n ? 'default'\n : status === 'overdue'\n ? 'destructive'\n : status === 'draft'\n ? 'outline'\n : 'secondary';\n\nexport function PaymentsInvoicesPagePage() {\n const { invoices, addInvoice, updateInvoice } = useCrewFoundryStore();\n const modal = useFormModal<Invoice>();\n const { page, pageSize, offset, setPage } = usePagination({ initialPageSize: 25 });\n\n const sorted = [...invoices].sort((a, b) => (b.issueDate ?? '').localeCompare(a.issueDate ?? ''));\n const paged = sorted.slice(offset, offset + pageSize);\n\n const handleSubmit = async (values: FormValues) => {\n if (modal.context) {\n await updateInvoice(modal.context.id, valuesToInvoice(values, modal.context));\n } else {\n await addInvoice(valuesToInvoice(values));\n }\n };\n\n const columns: ResponsiveTableColumn<Invoice>[] = [\n {\n key: 'number',\n header: 'Invoice #',\n priority: 'primary',\n cell: (inv) => <span className=\"font-medium\">{inv.number}</span>,\n },\n {\n key: 'client',\n header: 'Client',\n priority: 'secondary',\n cell: (inv) => <span className=\"text-text-secondary\">{inv.clientName}</span>,\n },\n {\n key: 'items',\n header: 'Items',\n priority: 'hidden-on-mobile',\n cell: (inv) => (\n <span className=\"text-xs text-text-secondary\">\n {inv.items.map((i) => i.description).join(', ')}\n </span>\n ),\n },\n {\n key: 'amount',\n header: 'Amount',\n priority: 'secondary',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (inv) => <span className=\"font-medium\">${inv.amount.toLocaleString()}</span>,\n },\n {\n key: 'dueDate',\n header: 'Due Date',\n priority: 'secondary',\n cell: (inv) => <span className=\"text-text-secondary\">{inv.dueDate}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n priority: 'secondary',\n cell: (inv) => (\n <Badge variant={statusVariant(inv.status)} className=\"text-[10px]\">\n {inv.status}\n </Badge>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n <GradientText>Invoices</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{invoices.length} invoices</p>\n <PagePurpose className=\"mt-1\">\n Create, send, and track invoices — see what's paid, pending, or overdue so you stay\n on top of getting paid.\n </PagePurpose>\n </div>\n <Button size=\"sm\" onClick={() => modal.openModal()}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Create Invoice\n </Button>\n </div>\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardContent className=\"p-4\">\n <ResponsiveTable\n data={paged}\n rowKey={(inv) => inv.id}\n columns={columns}\n emptyState={\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No invoices yet\"\n description=\"Create your first invoice to start getting paid.\"\n />\n }\n rowActions={(inv) => (\n <div className=\"flex items-center justify-end gap-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Edit invoice ${inv.number}`}\n onClick={() => modal.openModal(inv)}\n >\n <Pencil className=\"h-3.5 w-3.5\" />\n </Button>\n {inv.status === 'paid' ? (\n <span className=\"inline-flex items-center gap-1 text-xs text-status-success-text\">\n <CheckCircle2 className=\"h-3.5 w-3.5\" />\n Paid\n </span>\n ) : (\n <Button\n variant=\"outline\"\n size=\"sm\"\n aria-label={`Mark invoice ${inv.number} as paid`}\n onClick={() => void updateInvoice(inv.id, { status: 'paid' })}\n >\n <CheckCircle2 className=\"h-3.5 w-3.5 mr-1\" />\n Mark Paid\n </Button>\n )}\n </div>\n )}\n />\n {sorted.length > pageSize && (\n <div className=\"mt-4\">\n <Pagination\n page={page}\n pageSize={pageSize}\n totalItems={sorted.length}\n onPageChange={setPage}\n />\n </div>\n )}\n </CardContent>\n </GlassCard>\n\n <FormModal\n open={modal.open}\n onOpenChange={modal.onOpenChange}\n title={modal.context ? 'Edit invoice' : 'Create invoice'}\n description=\"Issue a new invoice to a client and track its payment status.\"\n fields={INVOICE_FIELDS}\n initialValues={modal.context ? toInitialValues(modal.context) : undefined}\n submitLabel={modal.context ? 'Save changes' : 'Create invoice'}\n onSubmit={handleSubmit}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|