@burdenoff/microfe-proserviceworld 2026.624.1 → 2026.626.1
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/proserviceworld/pages/AdminReportsPage.js +396 -329
- package/dist/proserviceworld/pages/AdminReportsPage.js.map +1 -1
- package/dist/proserviceworld/pages/AdminUsersPage.js +261 -237
- package/dist/proserviceworld/pages/AdminUsersPage.js.map +1 -1
- package/dist/proserviceworld/pages/AnalyticsPage.js +373 -315
- package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
- package/dist/proserviceworld/pages/BookingsPage.js +221 -200
- package/dist/proserviceworld/pages/BookingsPage.js.map +1 -1
- package/dist/proserviceworld/pages/DashboardPage.js +474 -405
- package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.js +386 -317
- package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/MessagesPage.js +201 -192
- package/dist/proserviceworld/pages/MessagesPage.js.map +1 -1
- package/dist/proserviceworld/pages/PaymentsPage.js +398 -340
- package/dist/proserviceworld/pages/PaymentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ProjectsPage.js +543 -463
- package/dist/proserviceworld/pages/ProjectsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ProviderDetailPage.js +420 -346
- package/dist/proserviceworld/pages/ProviderDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/ProvidersPage.js +249 -244
- package/dist/proserviceworld/pages/ProvidersPage.js.map +1 -1
- package/dist/proserviceworld/pages/ReviewsPage.js +93 -76
- package/dist/proserviceworld/pages/ReviewsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ServiceDetailsPage.js +377 -309
- package/dist/proserviceworld/pages/ServiceDetailsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ServicesPage.js +116 -109
- package/dist/proserviceworld/pages/ServicesPage.js.map +1 -1
- package/dist/proserviceworld/pages/VerificationPage.js +264 -251
- package/dist/proserviceworld/pages/VerificationPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceDetailsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ServiceDetailsPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { Badge, Button, Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport {\n ArrowLeft,\n Star,\n Clock,\n CheckCircle2,\n ChevronDown,\n ChevronUp,\n Package,\n FileText,\n ClipboardList,\n Tag,\n Shield,\n Calendar,\n DollarSign,\n User,\n MessageSquare,\n BookOpen,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\n\ntype Tab = 'packages' | 'deliverables' | 'requirements' | 'faq';\n\nexport function ServiceDetailsPage() {\n const { services, providers } = useProServiceWorldStore();\n const [selectedServiceId, setSelectedServiceId] = useState(services[0]?.id ?? '');\n const [activeTab, setActiveTab] = useState<Tab>('packages');\n const [expandedFaq, setExpandedFaq] = useState<string | null>(null);\n const [showBookingModal, setShowBookingModal] = useState(false);\n const [selectedPackageId, setSelectedPackageId] = useState<string | null>(null);\n\n const service = services.find((s) => s.id === selectedServiceId) ?? services[0];\n const provider = service ? providers.find((p) => p.id === service.providerId) : null;\n\n if (!service) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <p className=\"text-text-secondary\">No services available.</p>\n </div>\n );\n }\n\n const tabs: { key: Tab; label: string; icon: typeof Package }[] = [\n { key: 'packages', label: 'Packages', icon: Package },\n { key: 'deliverables', label: 'Deliverables', icon: FileText },\n { key: 'requirements', label: 'Requirements', icon: ClipboardList },\n { key: 'faq', label: 'FAQ', icon: BookOpen },\n ];\n\n const pricingLabel =\n service.pricing.type === 'hourly'\n ? `$${service.pricing.hourlyRate}/hr`\n : service.pricing.type === 'fixed'\n ? `$${service.pricing.basePrice.toLocaleString()} fixed`\n : `From $${service.pricing.basePrice.toLocaleString()}`;\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Breadcrumb + Service selector */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setSelectedServiceId(services[0]?.id ?? '')}\n >\n <ArrowLeft className=\"mr-2 h-4 w-4\" /> Services\n </Button>\n <span className=\"text-text-secondary\">/</span>\n <select\n className=\"rounded border bg-bg-surface px-2 py-1 text-sm\"\n value={selectedServiceId}\n onChange={(e) => setSelectedServiceId(e.target.value)}\n >\n {services.map((s) => (\n <option key={s.id} value={s.id}>\n {s.title}\n </option>\n ))}\n </select>\n </div>\n <Button size=\"sm\" onClick={() => setShowBookingModal(true)}>\n <Calendar className=\"mr-2 h-4 w-4\" /> Book This Service\n </Button>\n </div>\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Main content — 2 columns */}\n <div className=\"space-y-6 lg:col-span-2\">\n {/* Service header */}\n <Card>\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n {service.featured && <Badge>Featured</Badge>}\n <Badge variant=\"secondary\">{service.category.replace(/_/g, ' ')}</Badge>\n <Badge variant=\"outline\">{service.subcategory}</Badge>\n </div>\n <h1 className=\"text-2xl font-bold\">{service.title}</h1>\n <p className=\"max-w-2xl text-text-secondary\">{service.description}</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-2xl font-bold text-primary\">{pricingLabel}</p>\n <p className=\"text-xs text-text-secondary\">{service.pricing.type} pricing</p>\n </div>\n </div>\n\n {/* Stats row */}\n <div className=\"mt-6 flex flex-wrap gap-6 border-t pt-4\">\n <div className=\"flex items-center gap-2\">\n <Star className=\"h-4 w-4 text-yellow-500\" />\n <span className=\"text-sm font-medium\">{service.rating}</span>\n <span className=\"text-xs text-text-secondary\">\n ({service.providerReviews} reviews)\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <Clock className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"text-sm\">{service.duration.typical} days typical</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <CheckCircle2 className=\"h-4 w-4 text-green-500\" />\n <span className=\"text-sm\">{service.totalBookings} bookings</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <Calendar className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"text-sm\">\n {service.duration.min}-{service.duration.max} days range\n </span>\n </div>\n </div>\n\n {/* Tags */}\n {service.tags.length > 0 && (\n <div className=\"mt-4 flex flex-wrap gap-2\">\n <Tag className=\"h-4 w-4 text-text-secondary\" />\n {service.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Tabs */}\n <div className=\"flex gap-1 border-b\">\n {tabs.map(({ key, label, icon: Icon }) => (\n <button\n key={key}\n onClick={() => setActiveTab(key)}\n className={`flex items-center gap-2 border-b-2 px-4 py-2 text-sm font-medium transition-colors ${\n activeTab === key\n ? 'border-primary text-primary'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n }`}\n >\n <Icon className=\"h-4 w-4\" />\n {label}\n </button>\n ))}\n </div>\n\n {/* Tab content */}\n {activeTab === 'packages' && (\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {service.packages.map((pkg) => (\n <Card\n key={pkg.id}\n className={`relative ${pkg.popular ? 'border-primary ring-1 ring-primary' : ''} ${\n selectedPackageId === pkg.id ? 'bg-action-primary-bg/5' : ''\n }`}\n >\n {pkg.popular && (\n <div className=\"absolute -top-3 left-1/2 -translate-x-1/2\">\n <Badge className=\"bg-action-primary-bg text-action-primary-text\">Most Popular</Badge>\n </div>\n )}\n <CardHeader className=\"pb-3\">\n <CardTitle className=\"text-lg\">{pkg.name}</CardTitle>\n <p className=\"text-sm text-text-secondary\">{pkg.description}</p>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <span className=\"text-3xl font-bold\">${pkg.price.toLocaleString()}</span>\n <span className=\"text-sm text-text-secondary\"> / {pkg.duration} days</span>\n </div>\n <ul className=\"space-y-2\">\n {pkg.features.map((feature, i) => (\n <li key={i} className=\"flex items-start gap-2 text-sm\">\n <CheckCircle2 className=\"mt-0.5 h-4 w-4 shrink-0 text-green-500\" />\n {feature}\n </li>\n ))}\n </ul>\n <Button\n className=\"w-full\"\n variant={pkg.popular ? 'default' : 'outline'}\n onClick={() => {\n setSelectedPackageId(pkg.id);\n setShowBookingModal(true);\n }}\n >\n Select Package\n </Button>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {activeTab === 'deliverables' && (\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">What You'll Receive</CardTitle>\n </CardHeader>\n <CardContent>\n <ul className=\"grid gap-3 sm:grid-cols-2\">\n {service.deliverables.map((item, i) => (\n <li key={i} className=\"flex items-center gap-3 rounded-lg border p-3\">\n <FileText className=\"h-5 w-5 text-primary\" />\n <span className=\"text-sm font-medium\">{item}</span>\n </li>\n ))}\n </ul>\n </CardContent>\n </Card>\n )}\n\n {activeTab === 'requirements' && (\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">What We Need From You</CardTitle>\n </CardHeader>\n <CardContent>\n <ul className=\"space-y-3\">\n {service.requirements.map((item, i) => (\n <li key={i} className=\"flex items-start gap-3 rounded-lg border p-3\">\n <ClipboardList className=\"mt-0.5 h-5 w-5 text-orange-500\" />\n <span className=\"text-sm\">{item}</span>\n </li>\n ))}\n </ul>\n </CardContent>\n </Card>\n )}\n\n {activeTab === 'faq' && (\n <div className=\"space-y-3\">\n {service.faq.length === 0 ? (\n <Card>\n <CardContent className=\"py-8 text-center text-text-secondary\">\n No FAQ items for this service yet.\n </CardContent>\n </Card>\n ) : (\n service.faq.map((item) => (\n <Card key={item.id}>\n <button\n className=\"flex w-full items-center justify-between p-4 text-left\"\n onClick={() => setExpandedFaq(expandedFaq === item.id ? null : item.id)}\n >\n <span className=\"font-medium\">{item.question}</span>\n {expandedFaq === item.id ? (\n <ChevronUp className=\"h-4 w-4 text-text-secondary\" />\n ) : (\n <ChevronDown className=\"h-4 w-4 text-text-secondary\" />\n )}\n </button>\n {expandedFaq === item.id && (\n <CardContent className=\"border-t pt-4\">\n <p className=\"text-sm text-text-secondary\">{item.answer}</p>\n </CardContent>\n )}\n </Card>\n ))\n )}\n </div>\n )}\n </div>\n\n {/* Provider sidebar */}\n <div className=\"space-y-4\">\n {provider && (\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Service Provider</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-action-primary-bg/10 text-primary font-semibold\">\n {provider.name.charAt(0)}\n </div>\n <div>\n <p className=\"font-medium\">{provider.name}</p>\n <p className=\"text-sm text-text-secondary\">{provider.businessName}</p>\n </div>\n </div>\n\n {provider.verified && (\n <div className=\"flex items-center gap-2 rounded-lg bg-green-50 p-2 dark:bg-green-950\">\n <Shield className=\"h-4 w-4 text-green-600\" />\n <span className=\"text-sm font-medium text-green-700 dark:text-green-400\">\n Verified Provider\n </span>\n </div>\n )}\n\n <div className=\"space-y-3 text-sm\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Rating</span>\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-4 w-4 text-yellow-500\" />\n <span className=\"font-medium\">{provider.rating}</span>\n <span className=\"text-text-secondary\">({provider.totalReviews})</span>\n </div>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Completion Rate</span>\n <span className=\"font-medium\">{provider.completionRate}%</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Response Time</span>\n <span className=\"font-medium\">{provider.responseTime}h avg</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Experience</span>\n <span className=\"font-medium\">{provider.yearsExperience} years</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Projects Done</span>\n <span className=\"font-medium\">{provider.projectsCompleted}</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Hourly Rate</span>\n <span className=\"font-medium\">${provider.hourlyRate}/hr</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Location</span>\n <span className=\"font-medium\">{provider.location}</span>\n </div>\n </div>\n\n <div className=\"space-y-2 border-t pt-3\">\n <p className=\"text-xs font-medium text-text-secondary\">Certifications</p>\n <div className=\"flex flex-wrap gap-1\">\n {provider.certifications.map((cert) => (\n <Badge key={cert} variant=\"secondary\" className=\"text-xs\">\n {cert}\n </Badge>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2 border-t pt-3\">\n <p className=\"text-xs font-medium text-text-secondary\">Languages</p>\n <div className=\"flex flex-wrap gap-1\">\n {provider.languages.map((lang) => (\n <Badge key={lang} variant=\"outline\" className=\"text-xs\">\n {lang}\n </Badge>\n ))}\n </div>\n </div>\n\n <div className=\"flex gap-2 border-t pt-3\">\n <Button className=\"flex-1\" size=\"sm\" variant=\"outline\">\n <User className=\"mr-2 h-4 w-4\" /> View Profile\n </Button>\n <Button className=\"flex-1\" size=\"sm\" variant=\"outline\">\n <MessageSquare className=\"mr-2 h-4 w-4\" /> Message\n </Button>\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Quick booking card */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Quick Book</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">Starting from</span>\n <span className=\"text-lg font-bold text-primary\">\n ${service.pricing.basePrice.toLocaleString()}\n </span>\n </div>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Clock className=\"h-4 w-4\" />\n <span>Typical duration: {service.duration.typical} days</span>\n </div>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <DollarSign className=\"h-4 w-4\" />\n <span>{service.pricing.type} pricing model</span>\n </div>\n <Button className=\"w-full\" onClick={() => setShowBookingModal(true)}>\n <Calendar className=\"mr-2 h-4 w-4\" /> Book Now\n </Button>\n </CardContent>\n </Card>\n </div>\n </div>\n\n {/* Booking Modal */}\n {showBookingModal && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\n <Card className=\"w-full max-w-lg mx-4\">\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle>Book Service</CardTitle>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowBookingModal(false)}>\n Close\n </Button>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <p className=\"font-medium\">{service.title}</p>\n <p className=\"text-sm text-text-secondary\">by {service.providerName}</p>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-sm font-medium\">Select Package</p>\n {service.packages.map((pkg) => (\n <button\n key={pkg.id}\n onClick={() => setSelectedPackageId(pkg.id)}\n className={`w-full rounded-lg border p-3 text-left transition-colors ${\n selectedPackageId === pkg.id\n ? 'border-primary bg-action-primary-bg/5'\n : 'hover:bg-bg-sunken/50'\n }`}\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"font-medium\">{pkg.name}</span>\n <span className=\"font-bold\">${pkg.price.toLocaleString()}</span>\n </div>\n <p className=\"text-xs text-text-secondary\">\n {pkg.description} - {pkg.duration} days\n </p>\n </button>\n ))}\n </div>\n\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n className=\"flex-1\"\n onClick={() => setShowBookingModal(false)}\n >\n Cancel\n </Button>\n <Button className=\"flex-1\" disabled={!selectedPackageId}>\n Confirm Booking\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;AAwBA,SAAgB,IAAqB;CACnC,IAAM,EAAE,aAAU,iBAAc,GAAyB,EACnD,CAAC,GAAmB,KAAwB,EAAS,EAAS,IAAI,MAAM,GAAG,EAC3E,CAAC,GAAW,KAAgB,EAAc,WAAW,EACrD,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAC7D,CAAC,GAAkB,KAAuB,EAAS,GAAM,EACzD,CAAC,GAAmB,KAAwB,EAAwB,KAAK,EAEzE,IAAU,EAAS,MAAM,MAAM,EAAE,OAAO,EAAkB,IAAI,EAAS,IACvE,IAAW,IAAU,EAAU,MAAM,MAAM,EAAE,OAAO,EAAQ,WAAW,GAAG;AAEhF,KAAI,CAAC,EACH,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,KAAD;GAAG,WAAU;aAAsB;GAA0B,CAAA;EACzD,CAAA;CAIV,IAAM,IAA4D;EAChE;GAAE,KAAK;GAAY,OAAO;GAAY,MAAM;GAAS;EACrD;GAAE,KAAK;GAAgB,OAAO;GAAgB,MAAM;GAAU;EAC9D;GAAE,KAAK;GAAgB,OAAO;GAAgB,MAAM;GAAe;EACnE;GAAE,KAAK;GAAO,OAAO;GAAO,MAAM;GAAU;EAC7C,EAEK,IACJ,EAAQ,QAAQ,SAAS,WACrB,IAAI,EAAQ,QAAQ,WAAW,OAC/B,EAAQ,QAAQ,SAAS,UACvB,IAAI,EAAQ,QAAQ,UAAU,gBAAgB,CAAC,UAC/C,SAAS,EAAQ,QAAQ,UAAU,gBAAgB;AAE3D,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OACE,SAAQ;OACR,MAAK;OACL,eAAe,EAAqB,EAAS,IAAI,MAAM,GAAG;iBAH5D,CAKE,kBAAC,GAAD,EAAW,WAAU,gBAAiB,CAAA,EAAA,YAC/B;;MACT,kBAAC,QAAD;OAAM,WAAU;iBAAsB;OAAQ,CAAA;MAC9C,kBAAC,UAAD;OACE,WAAU;OACV,OAAO;OACP,WAAW,MAAM,EAAqB,EAAE,OAAO,MAAM;iBAEpD,EAAS,KAAK,MACb,kBAAC,UAAD;QAAmB,OAAO,EAAE;kBACzB,EAAE;QACI,EAFI,EAAE,GAEN,CACT;OACK,CAAA;MACL;QACN,kBAAC,GAAD;KAAQ,MAAK;KAAK,eAAe,EAAoB,GAAK;eAA1D,CACE,kBAAC,GAAD,EAAU,WAAU,gBAAiB,CAAA,EAAA,qBAC9B;OACL;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,kBAAC,OAAD;KAAK,WAAU;eAAf;MAEE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OAAa,WAAU;iBAAvB;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf;WACE,kBAAC,OAAD;YAAK,WAAU;sBAAf;aACG,EAAQ,YAAY,kBAAC,GAAD,EAAA,UAAO,YAAgB,CAAA;aAC5C,kBAAC,GAAD;cAAO,SAAQ;wBAAa,EAAQ,SAAS,QAAQ,MAAM,IAAI;cAAS,CAAA;aACxE,kBAAC,GAAD;cAAO,SAAQ;wBAAW,EAAQ;cAAoB,CAAA;aAClD;;WACN,kBAAC,MAAD;YAAI,WAAU;sBAAsB,EAAQ;YAAW,CAAA;WACvD,kBAAC,KAAD;YAAG,WAAU;sBAAiC,EAAQ;YAAgB,CAAA;WAClE;aACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,KAAD;WAAG,WAAU;qBAAmC;WAAiB,CAAA,EACjE,kBAAC,KAAD;WAAG,WAAU;qBAAb,CAA4C,EAAQ,QAAQ,MAAK,WAAY;aACzE;YACF;;QAGN,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf;YACE,kBAAC,GAAD,EAAM,WAAU,2BAA4B,CAAA;YAC5C,kBAAC,QAAD;aAAM,WAAU;uBAAuB,EAAQ;aAAc,CAAA;YAC7D,kBAAC,QAAD;aAAM,WAAU;uBAAhB;cAA8C;cAC1C,EAAQ;cAAgB;cACrB;;YACH;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD,EAAO,WAAU,+BAAgC,CAAA,EACjD,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAA2B,EAAQ,SAAS,SAAQ,gBAAoB;cACpE;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD,EAAc,WAAU,0BAA2B,CAAA,EACnD,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAA2B,EAAQ,eAAc,YAAgB;cAC7D;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,+BAAgC,CAAA,EACpD,kBAAC,QAAD;YAAM,WAAU;sBAAhB;aACG,EAAQ,SAAS;aAAI;aAAE,EAAQ,SAAS;aAAI;aACxC;cACH;;UACF;;QAGL,EAAQ,KAAK,SAAS,KACrB,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAK,WAAU,+BAAgC,CAAA,EAC9C,EAAQ,KAAK,KAAK,MACjB,kBAAC,GAAD;UAAiB,SAAQ;UAAU,WAAU;oBAC1C;UACK,EAFI,EAEJ,CACR,CACE;;QAEI;UACT,CAAA;MAGP,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAK,KAAK,EAAE,QAAK,UAAO,MAAM,QAC7B,kBAAC,UAAD;QAEE,eAAe,EAAa,EAAI;QAChC,WAAW,sFACT,MAAc,IACV,gCACA;kBANR,CASE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC3B,EACM;UAVF,EAUE,CACT;OACE,CAAA;MAGL,MAAc,cACb,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAQ,SAAS,KAAK,MACrB,kBAAC,GAAD;QAEE,WAAW,YAAY,EAAI,UAAU,uCAAuC,GAAG,GAC7E,MAAsB,EAAI,KAAK,2BAA2B;kBAH9D;SAMG,EAAI,WACH,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,GAAD;WAAO,WAAU;qBAAgD;WAAoB,CAAA;UACjF,CAAA;SAER,kBAAC,GAAD;UAAY,WAAU;oBAAtB,CACE,kBAAC,GAAD;WAAW,WAAU;qBAAW,EAAI;WAAiB,CAAA,EACrD,kBAAC,KAAD;WAAG,WAAU;qBAA+B,EAAI;WAAgB,CAAA,CACrD;;SACb,kBAAC,GAAD;UAAa,WAAU;oBAAvB;WACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAAqC,KAAE,EAAI,MAAM,gBAAgB,CAAQ;eACzE,kBAAC,QAAD;YAAM,WAAU;sBAAhB;aAA8C;aAAI,EAAI;aAAS;aAAY;cACvE,EAAA,CAAA;WACN,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAI,SAAS,KAAK,GAAS,MAC1B,kBAAC,MAAD;aAAY,WAAU;uBAAtB,CACE,kBAAC,GAAD,EAAc,WAAU,0CAA2C,CAAA,EAClE,EACE;eAHI,EAGJ,CACL;YACC,CAAA;WACL,kBAAC,GAAD;YACE,WAAU;YACV,SAAS,EAAI,UAAU,YAAY;YACnC,eAAe;AAEb,aADA,EAAqB,EAAI,GAAG,EAC5B,EAAoB,GAAK;;sBAE5B;YAEQ,CAAA;WACG;;SACT;UAtCA,EAAI,GAsCJ,CACP;OACE,CAAA;MAGP,MAAc,kBACb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OAAW,WAAU;iBAAY;OAAoC,CAAA,EAC1D,CAAA,EACb,kBAAC,GAAD,EAAA,UACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAQ,aAAa,KAAK,GAAM,MAC/B,kBAAC,MAAD;QAAY,WAAU;kBAAtB,CACE,kBAAC,GAAD,EAAU,WAAU,wBAAyB,CAAA,EAC7C,kBAAC,QAAD;SAAM,WAAU;mBAAuB;SAAY,CAAA,CAChD;UAHI,EAGJ,CACL;OACC,CAAA,EACO,CAAA,CACT,EAAA,CAAA;MAGR,MAAc,kBACb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OAAW,WAAU;iBAAY;OAAiC,CAAA,EACvD,CAAA,EACb,kBAAC,GAAD,EAAA,UACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAQ,aAAa,KAAK,GAAM,MAC/B,kBAAC,MAAD;QAAY,WAAU;kBAAtB,CACE,kBAAC,GAAD,EAAe,WAAU,kCAAmC,CAAA,EAC5D,kBAAC,QAAD;SAAM,WAAU;mBAAW;SAAY,CAAA,CACpC;UAHI,EAGJ,CACL;OACC,CAAA,EACO,CAAA,CACT,EAAA,CAAA;MAGR,MAAc,SACb,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAQ,IAAI,WAAW,IACtB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;QAAa,WAAU;kBAAuC;QAEhD,CAAA,EACT,CAAA,GAEP,EAAQ,IAAI,KAAK,MACf,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,UAAD;QACE,WAAU;QACV,eAAe,EAAe,MAAgB,EAAK,KAAK,OAAO,EAAK,GAAG;kBAFzE,CAIE,kBAAC,QAAD;SAAM,WAAU;mBAAe,EAAK;SAAgB,CAAA,EACnD,MAAgB,EAAK,KACpB,kBAAC,GAAD,EAAW,WAAU,+BAAgC,CAAA,GAErD,kBAAC,GAAD,EAAa,WAAU,+BAAgC,CAAA,CAElD;WACR,MAAgB,EAAK,MACpB,kBAAC,GAAD;QAAa,WAAU;kBACrB,kBAAC,KAAD;SAAG,WAAU;mBAA+B,EAAK;SAAW,CAAA;QAChD,CAAA,CAEX,EAAA,EAjBI,EAAK,GAiBT,CACP;OAEA,CAAA;MAEJ;QAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,KACC,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAW,WAAU;gBAAY;MAA4B,CAAA,EAClD,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBACZ,EAAS,KAAK,OAAO,EAAE;SACpB,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAe,EAAS;SAAS,CAAA,EAC9C,kBAAC,KAAD;SAAG,WAAU;mBAA+B,EAAS;SAAiB,CAAA,CAClE,EAAA,CAAA,CACF;;OAEL,EAAS,YACR,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,0BAA2B,CAAA,EAC7C,kBAAC,QAAD;SAAM,WAAU;mBAAyD;SAElE,CAAA,CACH;;OAGR,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAsB;WAAa,CAAA,EACnD,kBAAC,OAAD;WAAK,WAAU;qBAAf;YACE,kBAAC,GAAD,EAAM,WAAU,2BAA4B,CAAA;YAC5C,kBAAC,QAAD;aAAM,WAAU;uBAAe,EAAS;aAAc,CAAA;YACtD,kBAAC,QAAD;aAAM,WAAU;uBAAhB;cAAsC;cAAE,EAAS;cAAa;cAAQ;;YAClE;aACF;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAsB;WAAsB,CAAA,EAC5D,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAA+B,EAAS,gBAAe,IAAQ;aAC3D;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAsB;WAAoB,CAAA,EAC1D,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAA+B,EAAS,cAAa,QAAY;aAC7D;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAsB;WAAiB,CAAA,EACvD,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAA+B,EAAS,iBAAgB,SAAa;aACjE;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAsB;WAAoB,CAAA,EAC1D,kBAAC,QAAD;WAAM,WAAU;qBAAe,EAAS;WAAyB,CAAA,CAC7D;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAsB;WAAkB,CAAA,EACxD,kBAAC,QAAD;WAAM,WAAU;qBAAhB;YAA8B;YAAE,EAAS;YAAW;YAAU;aAC1D;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAsB;WAAe,CAAA,EACrD,kBAAC,QAAD;WAAM,WAAU;qBAAe,EAAS;WAAgB,CAAA,CACpD;;SACF;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA0C;SAAkB,CAAA,EACzE,kBAAC,OAAD;SAAK,WAAU;mBACZ,EAAS,eAAe,KAAK,MAC5B,kBAAC,GAAD;UAAkB,SAAQ;UAAY,WAAU;oBAC7C;UACK,EAFI,EAEJ,CACR;SACE,CAAA,CACF;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA0C;SAAa,CAAA,EACpE,kBAAC,OAAD;SAAK,WAAU;mBACZ,EAAS,UAAU,KAAK,MACvB,kBAAC,GAAD;UAAkB,SAAQ;UAAU,WAAU;oBAC3C;UACK,EAFI,EAEJ,CACR;SACE,CAAA,CACF;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAQ,WAAU;SAAS,MAAK;SAAK,SAAQ;mBAA7C,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,gBAC1B;YACT,kBAAC,GAAD;SAAQ,WAAU;SAAS,MAAK;SAAK,SAAQ;mBAA7C,CACE,kBAAC,GAAD,EAAe,WAAU,gBAAiB,CAAA,EAAA,WACnC;WACL;;OACM;QACT,EAAA,CAAA,EAIT,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAW,WAAU;gBAAY;MAAsB,CAAA,EAC5C,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAsB;SAAoB,CAAA,EAC1D,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CAAiD,KAC7C,EAAQ,QAAQ,UAAU,gBAAgB,CACvC;WACH;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA,EAC7B,kBAAC,QAAD,EAAA,UAAA;SAAM;SAAmB,EAAQ,SAAS;SAAQ;SAAY,EAAA,CAAA,CAC1D;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA,EAClC,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAQ,QAAQ,MAAK,iBAAqB,EAAA,CAAA,CAC7C;;OACN,kBAAC,GAAD;QAAQ,WAAU;QAAS,eAAe,EAAoB,GAAK;kBAAnE,CACE,kBAAC,GAAD,EAAU,WAAU,gBAAiB,CAAA,EAAA,YAC9B;;OACG;QACT,EAAA,CAAA,CACH;OACF;;GAGL,KACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KAAM,WAAU;eAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAA,UAAW,gBAAwB,CAAA,EACnC,kBAAC,GAAD;OAAQ,SAAQ;OAAU,MAAK;OAAK,eAAe,EAAoB,GAAM;iBAAE;OAEtE,CAAA,CACL;SACK,CAAA,EACb,kBAAC,GAAD;MAAa,WAAU;gBAAvB;OACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAe,EAAQ;QAAU,CAAA,EAC9C,kBAAC,KAAD;QAAG,WAAU;kBAAb,CAA2C,OAAI,EAAQ,aAAiB;UACpE,EAAA,CAAA;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAsB;SAAkB,CAAA,EACpD,EAAQ,SAAS,KAAK,MACrB,kBAAC,UAAD;SAEE,eAAe,EAAqB,EAAI,GAAG;SAC3C,WAAW,4DACT,MAAsB,EAAI,KACtB,0CACA;mBANR,CASE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAe,EAAI;WAAY,CAAA,EAC/C,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAA4B,KAAE,EAAI,MAAM,gBAAgB,CAAQ;aAC5D;aACN,kBAAC,KAAD;UAAG,WAAU;oBAAb;WACG,EAAI;WAAY;WAAI,EAAI;WAAS;WAChC;YACG;WAfF,EAAI,GAeF,CACT,CACE;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SACE,SAAQ;SACR,WAAU;SACV,eAAe,EAAoB,GAAM;mBAC1C;SAEQ,CAAA,EACT,kBAAC,GAAD;SAAQ,WAAU;SAAS,UAAU,CAAC;mBAAmB;SAEhD,CAAA,CACL;;OACM;QACT;;IACH,CAAA;GAEJ"}
|
|
1
|
+
{"version":3,"file":"ServiceDetailsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ServiceDetailsPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n EmphasisPanel,\n ShowMore,\n CTAOverflowMenu,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport {\n ArrowLeft,\n Star,\n Clock,\n CheckCircle2,\n ChevronDown,\n ChevronUp,\n Package,\n FileText,\n ClipboardList,\n Tag,\n Shield,\n Calendar,\n DollarSign,\n User,\n MessageSquare,\n BookOpen,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\n\ntype Tab = 'packages' | 'deliverables' | 'requirements' | 'faq';\n\nexport function ServiceDetailsPage() {\n const { services, providers } = useProServiceWorldStore();\n const [selectedServiceId, setSelectedServiceId] = useState(services[0]?.id ?? '');\n const [activeTab, setActiveTab] = useState<Tab>('packages');\n const [expandedFaq, setExpandedFaq] = useState<string | null>(null);\n const [showBookingModal, setShowBookingModal] = useState(false);\n const [selectedPackageId, setSelectedPackageId] = useState<string | null>(null);\n\n const service = services.find((s) => s.id === selectedServiceId) ?? services[0];\n const provider = service ? providers.find((p) => p.id === service.providerId) : null;\n\n if (!service) {\n return (\n <div className=\"p-6 bg-bg-canvas min-h-screen\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No services available\"\n description=\"There are no services to display yet. Once services are published they will appear here with full package and provider details.\"\n />\n </div>\n );\n }\n\n const tabs: { key: Tab; label: string; icon: typeof Package }[] = [\n { key: 'packages', label: 'Packages', icon: Package },\n { key: 'deliverables', label: 'Deliverables', icon: FileText },\n { key: 'requirements', label: 'Requirements', icon: ClipboardList },\n { key: 'faq', label: 'FAQ', icon: BookOpen },\n ];\n\n const pricingLabel =\n service.pricing.type === 'hourly'\n ? `$${service.pricing.hourlyRate}/hr`\n : service.pricing.type === 'fixed'\n ? `$${service.pricing.basePrice.toLocaleString()} fixed`\n : `From $${service.pricing.basePrice.toLocaleString()}`;\n\n return (\n <div className=\"space-y-6 p-6 bg-bg-canvas min-h-screen\">\n {/* Breadcrumb + Service selector */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setSelectedServiceId(services[0]?.id ?? '')}\n >\n <ArrowLeft className=\"mr-2 h-4 w-4\" /> Services\n </Button>\n <span className=\"text-text-secondary\">/</span>\n <select\n aria-label=\"Select service\"\n className=\"rounded border border-border-seam bg-bg-surface px-2 py-1 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n value={selectedServiceId}\n onChange={(e) => setSelectedServiceId(e.target.value)}\n >\n {services.map((s) => (\n <option key={s.id} value={s.id}>\n {s.title}\n </option>\n ))}\n </select>\n </div>\n <Button size=\"sm\" onClick={() => setShowBookingModal(true)}>\n <Calendar className=\"mr-2 h-4 w-4\" /> Book This Service\n </Button>\n </div>\n\n <PagePurpose icon={<Package className=\"h-4 w-4\" />}>\n Everything you need to decide on this service. Compare packages and pricing, see exactly\n what you will receive and what is required from you, read the FAQ, and review the provider\n behind it — then book the package that fits your project.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"proserviceworld-service-details\"\n steps={[\n {\n id: 'packages',\n label: 'Compare packages',\n description: 'Review tiers, features, and pricing to pick the right fit.',\n icon: <Package className=\"h-4 w-4\" />,\n onClick: () => setActiveTab('packages'),\n },\n {\n id: 'requirements',\n label: 'Check what is required',\n description: 'See the deliverables and what the provider needs from you.',\n icon: <ClipboardList className=\"h-4 w-4\" />,\n onClick: () => setActiveTab('requirements'),\n },\n {\n id: 'book',\n label: 'Book this service',\n description: 'Select a package and confirm your booking.',\n icon: <Calendar className=\"h-4 w-4\" />,\n onClick: () => setShowBookingModal(true),\n },\n ]}\n />\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Main content — 2 columns */}\n <div className=\"space-y-6 lg:col-span-2\">\n {/* Service header — the single emphasised zone */}\n <EmphasisPanel className=\"relative overflow-hidden\">\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n {service.featured && <Badge>Featured</Badge>}\n <Badge variant=\"secondary\">{service.category.replace(/_/g, ' ')}</Badge>\n <Badge variant=\"outline\">{service.subcategory}</Badge>\n </div>\n <h1 className=\"text-2xl font-bold tracking-tight\">{service.title}</h1>\n <p className=\"max-w-2xl text-text-secondary\">{service.description}</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-2xl font-bold text-accent-blue tabular-nums\">{pricingLabel}</p>\n <p className=\"text-xs text-text-secondary\">{service.pricing.type} pricing</p>\n </div>\n </div>\n\n {/* Stats row */}\n <div className=\"mt-6 flex flex-wrap gap-6 border-t border-border-seam pt-4\">\n <div className=\"flex items-center gap-2\">\n <Star className=\"h-4 w-4 text-status-warning-text\" />\n <span className=\"text-sm font-medium tabular-nums\">{service.rating}</span>\n <span className=\"text-xs text-text-secondary\">\n ({service.providerReviews} reviews)\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <Clock className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"text-sm tabular-nums\">{service.duration.typical} days typical</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <CheckCircle2 className=\"h-4 w-4 text-status-success-text\" />\n <span className=\"text-sm tabular-nums\">{service.totalBookings} bookings</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <Calendar className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"text-sm tabular-nums\">\n {service.duration.min}-{service.duration.max} days range\n </span>\n </div>\n </div>\n\n {/* Tags */}\n {service.tags.length > 0 && (\n <div className=\"mt-4 flex flex-wrap items-center gap-2\">\n <Tag className=\"h-4 w-4 text-text-secondary\" />\n {service.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n )}\n </EmphasisPanel>\n\n {/* Tabs */}\n <div className=\"flex gap-1 border-b border-border-seam\">\n {tabs.map(({ key, label, icon: Icon }) => (\n <button\n key={key}\n onClick={() => setActiveTab(key)}\n aria-pressed={activeTab === key}\n className={`flex items-center gap-2 border-b-2 px-4 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus ${\n activeTab === key\n ? 'border-accent-blue text-accent-blue'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n }`}\n >\n <Icon className=\"h-4 w-4\" />\n {label}\n </button>\n ))}\n </div>\n\n {/* Tab content */}\n {activeTab === 'packages' && (\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {service.packages.map((pkg) => (\n <GlassCard\n key={pkg.id}\n treatment={pkg.popular ? 'glass' : 'plain'}\n glow={pkg.popular}\n className={`relative border-border-seam ${\n selectedPackageId === pkg.id ? 'ring-1 ring-accent-blue' : ''\n }`}\n >\n {pkg.popular && (\n <div className=\"absolute -top-3 left-1/2 -translate-x-1/2\">\n <Badge className=\"bg-accent-blue text-action-primary-text\">Most Popular</Badge>\n </div>\n )}\n <CardHeader className=\"pb-3\">\n <CardTitle className=\"text-lg\">{pkg.name}</CardTitle>\n <p className=\"text-sm text-text-secondary\">{pkg.description}</p>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <span className=\"text-3xl font-bold tabular-nums\">\n ${pkg.price.toLocaleString()}\n </span>\n <span className=\"text-sm text-text-secondary\"> / {pkg.duration} days</span>\n </div>\n <ul className=\"space-y-2\">\n {pkg.features.map((feature, i) => (\n <li key={i} className=\"flex items-start gap-2 text-sm\">\n <CheckCircle2 className=\"mt-0.5 h-4 w-4 shrink-0 text-status-success-text\" />\n {feature}\n </li>\n ))}\n </ul>\n <Button\n className=\"w-full\"\n variant={pkg.popular ? 'default' : 'outline'}\n onClick={() => {\n setSelectedPackageId(pkg.id);\n setShowBookingModal(true);\n }}\n >\n Select Package\n </Button>\n </CardContent>\n </GlassCard>\n ))}\n </div>\n )}\n\n {activeTab === 'deliverables' && (\n <Card className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"text-base\">What You'll Receive</CardTitle>\n </CardHeader>\n <CardContent>\n <ShowMore collapsedHeight={180}>\n <ul className=\"grid gap-3 sm:grid-cols-2\">\n {service.deliverables.map((item, i) => (\n <li\n key={i}\n className=\"flex items-center gap-3 rounded-lg border border-border-seam p-3\"\n >\n <FileText className=\"h-5 w-5 text-accent-blue\" />\n <span className=\"text-sm font-medium\">{item}</span>\n </li>\n ))}\n </ul>\n </ShowMore>\n </CardContent>\n </Card>\n )}\n\n {activeTab === 'requirements' && (\n <Card className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"text-base\">What We Need From You</CardTitle>\n </CardHeader>\n <CardContent>\n <ShowMore collapsedHeight={180}>\n <ul className=\"space-y-3\">\n {service.requirements.map((item, i) => (\n <li\n key={i}\n className=\"flex items-start gap-3 rounded-lg border border-border-seam p-3\"\n >\n <ClipboardList className=\"mt-0.5 h-5 w-5 text-status-warning-text\" />\n <span className=\"text-sm\">{item}</span>\n </li>\n ))}\n </ul>\n </ShowMore>\n </CardContent>\n </Card>\n )}\n\n {activeTab === 'faq' && (\n <div className=\"space-y-3\">\n {service.faq.length === 0 ? (\n <Card className=\"border-border-seam\">\n <CardContent className=\"py-6\">\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No FAQ items yet\"\n description=\"This service does not have any frequently asked questions yet. Message the provider if you have a question before booking.\"\n />\n </CardContent>\n </Card>\n ) : (\n service.faq.map((item) => (\n <Card key={item.id} className=\"border-border-seam\">\n <button\n className=\"flex w-full items-center justify-between p-4 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n aria-expanded={expandedFaq === item.id}\n onClick={() => setExpandedFaq(expandedFaq === item.id ? null : item.id)}\n >\n <span className=\"font-medium\">{item.question}</span>\n {expandedFaq === item.id ? (\n <ChevronUp className=\"h-4 w-4 text-text-secondary\" />\n ) : (\n <ChevronDown className=\"h-4 w-4 text-text-secondary\" />\n )}\n </button>\n {expandedFaq === item.id && (\n <CardContent className=\"border-t border-border-seam pt-4\">\n <p className=\"text-sm text-text-secondary\">{item.answer}</p>\n </CardContent>\n )}\n </Card>\n ))\n )}\n </div>\n )}\n </div>\n\n {/* Provider sidebar */}\n <div className=\"space-y-4\">\n {provider && (\n <Card className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"text-base\">Service Provider</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-accent-soft text-text-primary font-semibold\">\n {provider.name.charAt(0)}\n </div>\n <div>\n <p className=\"font-medium\">{provider.name}</p>\n <p className=\"text-sm text-text-secondary\">{provider.businessName}</p>\n </div>\n </div>\n\n {provider.verified && (\n <div className=\"flex items-center gap-2 rounded-lg bg-status-success-bg-subtle p-2\">\n <Shield className=\"h-4 w-4 text-status-success-text\" />\n <span className=\"text-sm font-medium text-status-success-text\">\n Verified Provider\n </span>\n </div>\n )}\n\n <div className=\"space-y-3 text-sm\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Rating</span>\n <div className=\"flex items-center gap-1\">\n <Star className=\"h-4 w-4 text-status-warning-text\" />\n <span className=\"font-medium tabular-nums\">{provider.rating}</span>\n <span className=\"text-text-secondary tabular-nums\">\n ({provider.totalReviews})\n </span>\n </div>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Completion Rate</span>\n <span className=\"font-medium tabular-nums\">{provider.completionRate}%</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Response Time</span>\n <span className=\"font-medium tabular-nums\">{provider.responseTime}h avg</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Experience</span>\n <span className=\"font-medium tabular-nums\">\n {provider.yearsExperience} years\n </span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Projects Done</span>\n <span className=\"font-medium tabular-nums\">{provider.projectsCompleted}</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Hourly Rate</span>\n <span className=\"font-medium tabular-nums\">${provider.hourlyRate}/hr</span>\n </div>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-text-secondary\">Location</span>\n <span className=\"font-medium\">{provider.location}</span>\n </div>\n </div>\n\n <div className=\"space-y-2 border-t border-border-seam pt-3\">\n <p className=\"text-xs font-medium text-text-secondary\">Certifications</p>\n <div className=\"flex flex-wrap gap-1\">\n {provider.certifications.map((cert) => (\n <Badge key={cert} variant=\"secondary\" className=\"text-xs\">\n {cert}\n </Badge>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2 border-t border-border-seam pt-3\">\n <p className=\"text-xs font-medium text-text-secondary\">Languages</p>\n <div className=\"flex flex-wrap gap-1\">\n {provider.languages.map((lang) => (\n <Badge key={lang} variant=\"outline\" className=\"text-xs\">\n {lang}\n </Badge>\n ))}\n </div>\n </div>\n\n <div className=\"flex gap-2 border-t border-border-seam pt-3\">\n <Button className=\"flex-1\" size=\"sm\" variant=\"outline\">\n <User className=\"mr-2 h-4 w-4\" /> View Profile\n </Button>\n <Button className=\"flex-1\" size=\"sm\" variant=\"outline\">\n <MessageSquare className=\"mr-2 h-4 w-4\" /> Message\n </Button>\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Quick booking card */}\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"text-base\">Quick Book</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">Starting from</span>\n <span className=\"text-lg font-bold text-accent-blue tabular-nums\">\n ${service.pricing.basePrice.toLocaleString()}\n </span>\n </div>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Clock className=\"h-4 w-4\" />\n <span>Typical duration: {service.duration.typical} days</span>\n </div>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <DollarSign className=\"h-4 w-4\" />\n <span>{service.pricing.type} pricing model</span>\n </div>\n <Button className=\"w-full\" onClick={() => setShowBookingModal(true)}>\n <Calendar className=\"mr-2 h-4 w-4\" /> Book Now\n </Button>\n </CardContent>\n </GlassCard>\n </div>\n </div>\n\n {/* Booking Modal */}\n {showBookingModal && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay\">\n <GlassCard treatment=\"glass\" className=\"w-full max-w-lg mx-4 border-border-seam\">\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle>Book Service</CardTitle>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowBookingModal(false)}>\n Close\n </Button>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <p className=\"font-medium\">{service.title}</p>\n <p className=\"text-sm text-text-secondary\">by {service.providerName}</p>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-sm font-medium\">Select Package</p>\n {service.packages.map((pkg) => (\n <button\n key={pkg.id}\n onClick={() => setSelectedPackageId(pkg.id)}\n aria-pressed={selectedPackageId === pkg.id}\n className={`w-full rounded-lg border p-3 text-left transition-shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus ${\n selectedPackageId === pkg.id\n ? 'border-accent-blue bg-accent-blue-subtle'\n : 'border-border-seam hover:shadow-pop'\n }`}\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"font-medium\">{pkg.name}</span>\n <span className=\"font-bold tabular-nums\">${pkg.price.toLocaleString()}</span>\n </div>\n <p className=\"text-xs text-text-secondary\">\n {pkg.description} - {pkg.duration} days\n </p>\n </button>\n ))}\n </div>\n\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n className=\"flex-1\"\n onClick={() => setShowBookingModal(false)}\n >\n Cancel\n </Button>\n <Button className=\"flex-1\" disabled={!selectedPackageId}>\n Confirm Booking\n </Button>\n </div>\n </CardContent>\n </GlassCard>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useProServiceWorldStore as e } from "../store/proserviceworldStore.js";
|
|
2
2
|
import { tWithFallback as t } from "../utils/i18n.js";
|
|
3
3
|
import { useMemo as n, useState as r } from "react";
|
|
4
|
-
import { Clock as i,
|
|
4
|
+
import { Clock as i, Compass as a, Grid as o, List as s, Search as c, Star as l, Tag as u } from "lucide-react";
|
|
5
5
|
import { useI18n as d } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
6
6
|
import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
7
|
-
import {
|
|
7
|
+
import { AuroraBackground as h, Badge as g, Button as _, GlassCard as v, GradientText as y, IllustratedEmptyState as b, Input as x, PagePurpose as S } from "@burdenoff/fe-libs/ui";
|
|
8
8
|
//#region src/proserviceworld/pages/ServicesPage.tsx
|
|
9
|
-
var
|
|
9
|
+
var C = {
|
|
10
10
|
accounting_bookkeeping: {
|
|
11
11
|
key: "proserviceworld.shared.categories.accountingBookkeeping",
|
|
12
12
|
fallback: "Accounting & Bookkeeping"
|
|
@@ -56,123 +56,133 @@ var b = {
|
|
|
56
56
|
fallback: "Real Estate"
|
|
57
57
|
}
|
|
58
58
|
};
|
|
59
|
-
function
|
|
60
|
-
let { t:
|
|
61
|
-
let e = [...
|
|
62
|
-
if (
|
|
63
|
-
let t =
|
|
59
|
+
function w() {
|
|
60
|
+
let { t: w } = d(), E = (e, n, r) => t(w, e, n, r), { services: D } = e(), [O, k] = r(""), [A, j] = r(""), [M, N] = r("grid"), [P, F] = r(1), I = n(() => {
|
|
61
|
+
let e = [...D];
|
|
62
|
+
if (O) {
|
|
63
|
+
let t = O.toLowerCase();
|
|
64
64
|
e = e.filter((e) => e.title.toLowerCase().includes(t) || e.description.toLowerCase().includes(t) || e.tags.some((e) => e.toLowerCase().includes(t)));
|
|
65
65
|
}
|
|
66
|
-
return
|
|
66
|
+
return A && (e = e.filter((e) => e.category === A)), e;
|
|
67
67
|
}, [
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
]),
|
|
72
|
-
count:
|
|
73
|
-
query:
|
|
74
|
-
}) :
|
|
75
|
-
let t =
|
|
76
|
-
return
|
|
68
|
+
D,
|
|
69
|
+
O,
|
|
70
|
+
A
|
|
71
|
+
]), L = Math.ceil(I.length / 12), R = I.slice((P - 1) * 12, P * 12), z = O ? E("proserviceworld.services.subtitleWithQuery", "{{count}} services found for \"{{query}}\"", {
|
|
72
|
+
count: I.length,
|
|
73
|
+
query: O
|
|
74
|
+
}) : E("proserviceworld.services.subtitle", "{{count}} services found", { count: I.length }), B = (e) => {
|
|
75
|
+
let t = C[e];
|
|
76
|
+
return E(t.key, t.fallback);
|
|
77
77
|
};
|
|
78
78
|
return /* @__PURE__ */ m("div", {
|
|
79
|
-
className: "space-y-6 p-6",
|
|
79
|
+
className: "space-y-6 p-6 bg-bg-canvas min-h-screen",
|
|
80
80
|
children: [
|
|
81
81
|
/* @__PURE__ */ m("div", {
|
|
82
|
-
className: "flex flex-col md:flex-row md:items-center md:justify-between",
|
|
83
|
-
children: [
|
|
84
|
-
|
|
85
|
-
children:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
82
|
+
className: "relative overflow-hidden rounded-card -mx-2 px-2 pt-1 flex flex-col md:flex-row md:items-center md:justify-between gap-4",
|
|
83
|
+
children: [
|
|
84
|
+
/* @__PURE__ */ p(h, { intensity: "subtle" }),
|
|
85
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("h1", {
|
|
86
|
+
className: "text-2xl font-semibold tracking-tight",
|
|
87
|
+
children: /* @__PURE__ */ p(y, { children: E("proserviceworld.services.title", "Services") })
|
|
88
|
+
}), /* @__PURE__ */ p("p", {
|
|
89
|
+
className: "text-sm text-text-secondary",
|
|
90
|
+
children: z
|
|
91
|
+
})] }),
|
|
92
|
+
/* @__PURE__ */ m("div", {
|
|
93
|
+
className: "flex items-center gap-2 mt-4 md:mt-0",
|
|
94
|
+
children: [/* @__PURE__ */ p(_, {
|
|
95
|
+
variant: M === "grid" ? "default" : "outline",
|
|
96
|
+
size: "sm",
|
|
97
|
+
onClick: () => N("grid"),
|
|
98
|
+
children: /* @__PURE__ */ p(o, { className: "h-4 w-4" })
|
|
99
|
+
}), /* @__PURE__ */ p(_, {
|
|
100
|
+
variant: M === "list" ? "default" : "outline",
|
|
101
|
+
size: "sm",
|
|
102
|
+
onClick: () => N("list"),
|
|
103
|
+
children: /* @__PURE__ */ p(s, { className: "h-4 w-4" })
|
|
104
|
+
})]
|
|
105
|
+
})
|
|
106
|
+
]
|
|
107
|
+
}),
|
|
108
|
+
/* @__PURE__ */ p(S, {
|
|
109
|
+
icon: /* @__PURE__ */ p(a, { className: "h-4 w-4" }),
|
|
110
|
+
children: E("proserviceworld.services.purpose", "Discover professional services from vetted providers. Search and filter by category to compare offerings, pricing, and ratings — then open a service to review packages and book the right fit for your project.")
|
|
103
111
|
}),
|
|
104
112
|
/* @__PURE__ */ m("div", {
|
|
105
113
|
className: "flex flex-col sm:flex-row gap-4",
|
|
106
114
|
children: [/* @__PURE__ */ m("div", {
|
|
107
115
|
className: "flex-1 relative",
|
|
108
|
-
children: [/* @__PURE__ */ p(c, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ p(
|
|
109
|
-
placeholder:
|
|
110
|
-
value:
|
|
116
|
+
children: [/* @__PURE__ */ p(c, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" }), /* @__PURE__ */ p(x, {
|
|
117
|
+
placeholder: E("proserviceworld.services.search.placeholder", "Search services..."),
|
|
118
|
+
value: O,
|
|
111
119
|
onChange: (e) => {
|
|
112
|
-
|
|
120
|
+
k(e.target.value), F(1);
|
|
113
121
|
},
|
|
114
122
|
className: "pl-10"
|
|
115
123
|
})]
|
|
116
124
|
}), /* @__PURE__ */ m("select", {
|
|
117
|
-
value:
|
|
125
|
+
value: A,
|
|
118
126
|
onChange: (e) => {
|
|
119
|
-
|
|
127
|
+
j(e.target.value), F(1);
|
|
120
128
|
},
|
|
121
|
-
className: "px-4 py-2 border border-border-
|
|
129
|
+
className: "px-4 py-2 border border-border-seam rounded-md bg-bg-surface text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
122
130
|
children: [
|
|
123
131
|
/* @__PURE__ */ p("option", {
|
|
124
132
|
value: "",
|
|
125
|
-
children:
|
|
133
|
+
children: E("proserviceworld.shared.filters.allCategories", "All Categories")
|
|
126
134
|
}),
|
|
127
135
|
/* @__PURE__ */ p("option", {
|
|
128
136
|
value: "financial_services",
|
|
129
|
-
children:
|
|
137
|
+
children: B("financial_services")
|
|
130
138
|
}),
|
|
131
139
|
/* @__PURE__ */ p("option", {
|
|
132
140
|
value: "legal_services",
|
|
133
|
-
children:
|
|
141
|
+
children: B("legal_services")
|
|
134
142
|
}),
|
|
135
143
|
/* @__PURE__ */ p("option", {
|
|
136
144
|
value: "marketing_advertising",
|
|
137
|
-
children:
|
|
145
|
+
children: B("marketing_advertising")
|
|
138
146
|
}),
|
|
139
147
|
/* @__PURE__ */ p("option", {
|
|
140
148
|
value: "it_technology",
|
|
141
|
-
children:
|
|
149
|
+
children: B("it_technology")
|
|
142
150
|
}),
|
|
143
151
|
/* @__PURE__ */ p("option", {
|
|
144
152
|
value: "human_resources",
|
|
145
|
-
children:
|
|
153
|
+
children: B("human_resources")
|
|
146
154
|
}),
|
|
147
155
|
/* @__PURE__ */ p("option", {
|
|
148
156
|
value: "accounting_bookkeeping",
|
|
149
|
-
children:
|
|
157
|
+
children: B("accounting_bookkeeping")
|
|
150
158
|
}),
|
|
151
159
|
/* @__PURE__ */ p("option", {
|
|
152
160
|
value: "creative_design",
|
|
153
|
-
children:
|
|
161
|
+
children: B("creative_design")
|
|
154
162
|
}),
|
|
155
163
|
/* @__PURE__ */ p("option", {
|
|
156
164
|
value: "education_training",
|
|
157
|
-
children:
|
|
165
|
+
children: B("education_training")
|
|
158
166
|
})
|
|
159
167
|
]
|
|
160
168
|
})]
|
|
161
169
|
}),
|
|
162
|
-
|
|
163
|
-
className:
|
|
164
|
-
children:
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
170
|
+
R.length > 0 ? /* @__PURE__ */ p("div", {
|
|
171
|
+
className: M === "grid" ? "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" : "space-y-4",
|
|
172
|
+
children: R.map((e) => /* @__PURE__ */ p(v, {
|
|
173
|
+
treatment: "glass",
|
|
174
|
+
glow: e.featured,
|
|
175
|
+
className: "border-border-seam p-0 transition-shadow hover:shadow-pop",
|
|
176
|
+
children: /* @__PURE__ */ p("div", {
|
|
177
|
+
className: M === "grid" ? "p-6" : "p-4 flex items-center gap-6",
|
|
178
|
+
children: M === "grid" ? /* @__PURE__ */ m(f, { children: [
|
|
169
179
|
/* @__PURE__ */ m("div", {
|
|
170
180
|
className: "flex items-center justify-between mb-3",
|
|
171
|
-
children: [/* @__PURE__ */ p(
|
|
181
|
+
children: [/* @__PURE__ */ p(g, {
|
|
172
182
|
variant: "outline",
|
|
173
183
|
className: "text-xs capitalize",
|
|
174
|
-
children:
|
|
175
|
-
}), e.featured && /* @__PURE__ */ p(
|
|
184
|
+
children: B(e.category)
|
|
185
|
+
}), e.featured && /* @__PURE__ */ p(g, { children: E("proserviceworld.services.badges.featured", "Featured") })]
|
|
176
186
|
}),
|
|
177
187
|
/* @__PURE__ */ p("h3", {
|
|
178
188
|
className: "font-semibold mb-2",
|
|
@@ -193,7 +203,7 @@ function x() {
|
|
|
193
203
|
className: "text-text-secondary",
|
|
194
204
|
children: e.providerName
|
|
195
205
|
}),
|
|
196
|
-
e.providerVerified && /* @__PURE__ */ p(
|
|
206
|
+
e.providerVerified && /* @__PURE__ */ p(T, {})
|
|
197
207
|
]
|
|
198
208
|
}),
|
|
199
209
|
/* @__PURE__ */ m("div", {
|
|
@@ -201,10 +211,13 @@ function x() {
|
|
|
201
211
|
children: [/* @__PURE__ */ m("div", {
|
|
202
212
|
className: "flex items-center",
|
|
203
213
|
children: [
|
|
204
|
-
/* @__PURE__ */ p(l, { className: "h-4 w-4 text-
|
|
205
|
-
|
|
214
|
+
/* @__PURE__ */ p(l, { className: "h-4 w-4 text-status-warning-text fill-current mr-1" }),
|
|
215
|
+
/* @__PURE__ */ p("span", {
|
|
216
|
+
className: "tabular-nums",
|
|
217
|
+
children: e.providerRating.toFixed(1)
|
|
218
|
+
}),
|
|
206
219
|
/* @__PURE__ */ m("span", {
|
|
207
|
-
className: "text-text-secondary ml-1",
|
|
220
|
+
className: "text-text-secondary ml-1 tabular-nums",
|
|
208
221
|
children: [
|
|
209
222
|
"(",
|
|
210
223
|
e.providerReviews,
|
|
@@ -213,8 +226,8 @@ function x() {
|
|
|
213
226
|
})
|
|
214
227
|
]
|
|
215
228
|
}), /* @__PURE__ */ p("span", {
|
|
216
|
-
className: "font-medium",
|
|
217
|
-
children:
|
|
229
|
+
className: "font-medium tabular-nums",
|
|
230
|
+
children: E("proserviceworld.services.card.pricing.from", "From ${{amount}}", { amount: e.pricing.basePrice.toLocaleString() })
|
|
218
231
|
})]
|
|
219
232
|
}),
|
|
220
233
|
/* @__PURE__ */ p("div", {
|
|
@@ -225,13 +238,13 @@ function x() {
|
|
|
225
238
|
}, e))
|
|
226
239
|
}),
|
|
227
240
|
/* @__PURE__ */ m("div", {
|
|
228
|
-
className: "flex items-center gap-4 mt-3 pt-3 border-t text-xs text-text-secondary",
|
|
241
|
+
className: "flex items-center gap-4 mt-3 pt-3 border-t border-border-seam text-xs text-text-secondary",
|
|
229
242
|
children: [/* @__PURE__ */ m("span", {
|
|
230
243
|
className: "flex items-center",
|
|
231
|
-
children: [/* @__PURE__ */ p(i, { className: "h-3 w-3 mr-1" }),
|
|
244
|
+
children: [/* @__PURE__ */ p(i, { className: "h-3 w-3 mr-1" }), E("proserviceworld.services.card.meta.days", "{{count}} days", { count: e.duration.typical })]
|
|
232
245
|
}), /* @__PURE__ */ m("span", {
|
|
233
246
|
className: "flex items-center",
|
|
234
|
-
children: [/* @__PURE__ */ p(u, { className: "h-3 w-3 mr-1" }),
|
|
247
|
+
children: [/* @__PURE__ */ p(u, { className: "h-3 w-3 mr-1" }), E("proserviceworld.services.card.meta.bookings", "{{count}} bookings", { count: e.totalBookings })]
|
|
235
248
|
})]
|
|
236
249
|
})
|
|
237
250
|
] }) : /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ m("div", {
|
|
@@ -242,9 +255,9 @@ function x() {
|
|
|
242
255
|
children: [/* @__PURE__ */ p("h3", {
|
|
243
256
|
className: "font-semibold",
|
|
244
257
|
children: e.title
|
|
245
|
-
}), e.featured && /* @__PURE__ */ p(
|
|
258
|
+
}), e.featured && /* @__PURE__ */ p(g, {
|
|
246
259
|
className: "text-xs",
|
|
247
|
-
children:
|
|
260
|
+
children: E("proserviceworld.services.badges.featured", "Featured")
|
|
248
261
|
})]
|
|
249
262
|
}),
|
|
250
263
|
/* @__PURE__ */ p("p", {
|
|
@@ -257,11 +270,14 @@ function x() {
|
|
|
257
270
|
/* @__PURE__ */ p("span", { children: e.providerName }),
|
|
258
271
|
/* @__PURE__ */ m("span", {
|
|
259
272
|
className: "flex items-center",
|
|
260
|
-
children: [/* @__PURE__ */ p(l, { className: "h-3 w-3 text-
|
|
273
|
+
children: [/* @__PURE__ */ p(l, { className: "h-3 w-3 text-status-warning-text fill-current mr-0.5" }), /* @__PURE__ */ p("span", {
|
|
274
|
+
className: "tabular-nums",
|
|
275
|
+
children: e.providerRating.toFixed(1)
|
|
276
|
+
})]
|
|
261
277
|
}),
|
|
262
278
|
/* @__PURE__ */ p("span", {
|
|
263
279
|
className: "capitalize",
|
|
264
|
-
children:
|
|
280
|
+
children: B(e.category)
|
|
265
281
|
})
|
|
266
282
|
]
|
|
267
283
|
})
|
|
@@ -270,58 +286,49 @@ function x() {
|
|
|
270
286
|
className: "text-right shrink-0",
|
|
271
287
|
children: [/* @__PURE__ */ p("div", {
|
|
272
288
|
className: "font-medium",
|
|
273
|
-
children:
|
|
289
|
+
children: E("proserviceworld.services.card.pricing.from", "From ${{amount}}", { amount: e.pricing.basePrice.toLocaleString() })
|
|
274
290
|
}), /* @__PURE__ */ p("div", {
|
|
275
291
|
className: "text-sm text-text-secondary",
|
|
276
|
-
children:
|
|
292
|
+
children: E("proserviceworld.services.card.meta.days", "{{count}} days", { count: e.duration.typical })
|
|
277
293
|
})]
|
|
278
294
|
})] })
|
|
279
295
|
})
|
|
280
296
|
}, e.id))
|
|
281
|
-
}) : /* @__PURE__ */
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
/* @__PURE__ */ p("h3", {
|
|
286
|
-
className: "text-lg font-medium mb-2",
|
|
287
|
-
children: C("proserviceworld.services.empty.title", "No services found")
|
|
288
|
-
}),
|
|
289
|
-
/* @__PURE__ */ p("p", {
|
|
290
|
-
className: "text-text-secondary",
|
|
291
|
-
children: C("proserviceworld.shared.empty.adjustFilters", "Try adjusting your search criteria or filters.")
|
|
292
|
-
})
|
|
293
|
-
]
|
|
297
|
+
}) : /* @__PURE__ */ p(b, {
|
|
298
|
+
illustration: "empty-search",
|
|
299
|
+
title: E("proserviceworld.services.empty.title", "No services found"),
|
|
300
|
+
description: E("proserviceworld.shared.empty.adjustFilters", "Try adjusting your search criteria or filters.")
|
|
294
301
|
}),
|
|
295
|
-
|
|
302
|
+
L > 1 && /* @__PURE__ */ m("div", {
|
|
296
303
|
className: "flex justify-center gap-2",
|
|
297
304
|
children: [
|
|
298
|
-
/* @__PURE__ */ p(
|
|
305
|
+
/* @__PURE__ */ p(_, {
|
|
299
306
|
variant: "outline",
|
|
300
|
-
disabled:
|
|
301
|
-
onClick: () =>
|
|
302
|
-
children:
|
|
307
|
+
disabled: P === 1,
|
|
308
|
+
onClick: () => F((e) => e - 1),
|
|
309
|
+
children: E("proserviceworld.shared.pagination.previous", "Previous")
|
|
303
310
|
}),
|
|
304
311
|
/* @__PURE__ */ p("span", {
|
|
305
312
|
className: "flex items-center px-4 text-sm",
|
|
306
|
-
children:
|
|
307
|
-
page:
|
|
308
|
-
total:
|
|
313
|
+
children: E("proserviceworld.shared.pagination.pageInfo", "Page {{page}} of {{total}}", {
|
|
314
|
+
page: P,
|
|
315
|
+
total: L
|
|
309
316
|
})
|
|
310
317
|
}),
|
|
311
|
-
/* @__PURE__ */ p(
|
|
318
|
+
/* @__PURE__ */ p(_, {
|
|
312
319
|
variant: "outline",
|
|
313
|
-
disabled:
|
|
314
|
-
onClick: () =>
|
|
315
|
-
children:
|
|
320
|
+
disabled: P >= L,
|
|
321
|
+
onClick: () => F((e) => e + 1),
|
|
322
|
+
children: E("proserviceworld.shared.pagination.next", "Next")
|
|
316
323
|
})
|
|
317
324
|
]
|
|
318
325
|
})
|
|
319
326
|
]
|
|
320
327
|
});
|
|
321
328
|
}
|
|
322
|
-
function
|
|
329
|
+
function T() {
|
|
323
330
|
return /* @__PURE__ */ p("svg", {
|
|
324
|
-
className: "h-4 w-4 text-blue
|
|
331
|
+
className: "h-4 w-4 text-accent-blue",
|
|
325
332
|
viewBox: "0 0 20 20",
|
|
326
333
|
fill: "currentColor",
|
|
327
334
|
children: /* @__PURE__ */ p("path", {
|
|
@@ -332,6 +339,6 @@ function S() {
|
|
|
332
339
|
});
|
|
333
340
|
}
|
|
334
341
|
//#endregion
|
|
335
|
-
export {
|
|
342
|
+
export { w as ServicesPage };
|
|
336
343
|
|
|
337
344
|
//# sourceMappingURL=ServicesPage.js.map
|