@burdenoff/microfe-proserviceworld 2026.625.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 +102 -68
- package/dist/proserviceworld/pages/AdminReportsPage.js.map +1 -1
- package/dist/proserviceworld/pages/AdminUsersPage.js +37 -33
- package/dist/proserviceworld/pages/AdminUsersPage.js.map +1 -1
- package/dist/proserviceworld/pages/AnalyticsPage.js +66 -36
- package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
- package/dist/proserviceworld/pages/BookingsPage.js +52 -48
- package/dist/proserviceworld/pages/BookingsPage.js.map +1 -1
- package/dist/proserviceworld/pages/DashboardPage.js +275 -243
- package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.js +204 -200
- package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/MessagesPage.js +200 -186
- package/dist/proserviceworld/pages/MessagesPage.js.map +1 -1
- package/dist/proserviceworld/pages/PaymentsPage.js +70 -39
- package/dist/proserviceworld/pages/PaymentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ProjectsPage.js +510 -477
- package/dist/proserviceworld/pages/ProjectsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ProviderDetailPage.js +71 -41
- package/dist/proserviceworld/pages/ProviderDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/ProvidersPage.js +62 -58
- package/dist/proserviceworld/pages/ProvidersPage.js.map +1 -1
- package/dist/proserviceworld/pages/ReviewsPage.js +80 -63
- package/dist/proserviceworld/pages/ReviewsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ServiceDetailsPage.js +118 -83
- package/dist/proserviceworld/pages/ServiceDetailsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ServicesPage.js +134 -130
- package/dist/proserviceworld/pages/ServicesPage.js.map +1 -1
- package/dist/proserviceworld/pages/VerificationPage.js +23 -19
- 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 {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n GlassCard,\n EmphasisPanel,\n ShowMore,\n CTAOverflowMenu,\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=\"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 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 <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-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} 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
|
+
{"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":";;;;;;AAsCA,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,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,CAAA;EACE,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,cAAW;OACX,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,GAAD;IAAa,MAAM,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA;cAAE;IAItC,CAAA;GAEd,kBAAC,GAAD;IACE,YAAW;IACX,OAAO;KACL;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA;MACrC,eAAe,EAAa,WAAW;MACxC;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAe,WAAU,WAAY,CAAA;MAC3C,eAAe,EAAa,eAAe;MAC5C;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;MACtC,eAAe,EAAoB,GAAK;MACzC;KACF;IACD,CAAA;GAEF,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,kBAAC,OAAD;KAAK,WAAU;eAAf;MAEE,kBAAC,GAAD;OAAe,WAAU;iBAAzB;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;sBAAqC,EAAQ;YAAW,CAAA;WACtE,kBAAC,KAAD;YAAG,WAAU;sBAAiC,EAAQ;YAAgB,CAAA;WAClE;aACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,KAAD;WAAG,WAAU;qBAAoD;WAAiB,CAAA,EAClF,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,oCAAqC,CAAA;YACrD,kBAAC,QAAD;aAAM,WAAU;uBAAoC,EAAQ;aAAc,CAAA;YAC1E,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,CAAwC,EAAQ,SAAS,SAAQ,gBAAoB;cACjF;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD,EAAc,WAAU,oCAAqC,CAAA,EAC7D,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAAwC,EAAQ,eAAc,YAAgB;cAC1E;;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;;QAEM;;MAGhB,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAK,KAAK,EAAE,QAAK,UAAO,MAAM,QAC7B,kBAAC,UAAD;QAEE,eAAe,EAAa,EAAI;QAChC,gBAAc,MAAc;QAC5B,WAAW,sKACT,MAAc,IACV,wCACA;kBAPR,CAUE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC3B,EACM;UAXF,EAWE,CACT;OACE,CAAA;MAGL,MAAc,cACb,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAQ,SAAS,KAAK,MACrB,kBAAC,GAAD;QAEE,WAAW,EAAI,UAAU,UAAU;QACnC,MAAM,EAAI;QACV,WAAW,+BACT,MAAsB,EAAI,KAAK,4BAA4B;kBAL/D;SAQG,EAAI,WACH,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,GAAD;WAAO,WAAU;qBAA0C;WAAoB,CAAA;UAC3E,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,CAAkD,KAC9C,EAAI,MAAM,gBAAgB,CACvB;eACP,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,oDAAqD,CAAA,EAC5E,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;;SACJ;UA1CL,EAAI,GA0CC,CACZ;OACE,CAAA;MAGP,MAAc,kBACb,kBAAC,GAAD;OAAM,WAAU;iBAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;QAAW,WAAU;kBAAY;QAAoC,CAAA,EAC1D,CAAA,EACb,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;QAAU,iBAAiB;kBACzB,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAQ,aAAa,KAAK,GAAM,MAC/B,kBAAC,MAAD;UAEE,WAAU;oBAFZ,CAIE,kBAAC,GAAD,EAAU,WAAU,4BAA6B,CAAA,EACjD,kBAAC,QAAD;WAAM,WAAU;qBAAuB;WAAY,CAAA,CAChD;YALE,EAKF,CACL;SACC,CAAA;QACI,CAAA,EACC,CAAA,CACT;;MAGR,MAAc,kBACb,kBAAC,GAAD;OAAM,WAAU;iBAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;QAAW,WAAU;kBAAY;QAAiC,CAAA,EACvD,CAAA,EACb,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;QAAU,iBAAiB;kBACzB,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAQ,aAAa,KAAK,GAAM,MAC/B,kBAAC,MAAD;UAEE,WAAU;oBAFZ,CAIE,kBAAC,GAAD,EAAe,WAAU,2CAA4C,CAAA,EACrE,kBAAC,QAAD;WAAM,WAAU;qBAAW;WAAY,CAAA,CACpC;YALE,EAKF,CACL;SACC,CAAA;QACI,CAAA,EACC,CAAA,CACT;;MAGR,MAAc,SACb,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAQ,IAAI,WAAW,IACtB,kBAAC,GAAD;QAAM,WAAU;kBACd,kBAAC,GAAD;SAAa,WAAU;mBACrB,kBAAC,GAAD;UACE,cAAa;UACb,OAAM;UACN,aAAY;UACZ,CAAA;SACU,CAAA;QACT,CAAA,GAEP,EAAQ,IAAI,KAAK,MACf,kBAAC,GAAD;QAAoB,WAAU;kBAA9B,CACE,kBAAC,UAAD;SACE,WAAU;SACV,iBAAe,MAAgB,EAAK;SACpC,eAAe,EAAe,MAAgB,EAAK,KAAK,OAAO,EAAK,GAAG;mBAHzE,CAKE,kBAAC,QAAD;UAAM,WAAU;oBAAe,EAAK;UAAgB,CAAA,EACnD,MAAgB,EAAK,KACpB,kBAAC,GAAD,EAAW,WAAU,+BAAgC,CAAA,GAErD,kBAAC,GAAD,EAAa,WAAU,+BAAgC,CAAA,CAElD;YACR,MAAgB,EAAK,MACpB,kBAAC,GAAD;SAAa,WAAU;mBACrB,kBAAC,KAAD;UAAG,WAAU;oBAA+B,EAAK;UAAW,CAAA;SAChD,CAAA,CAEX;UAlBI,EAAK,GAkBT,CACP;OAEA,CAAA;MAEJ;QAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,KACC,kBAAC,GAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OAAW,WAAU;iBAAY;OAA4B,CAAA,EAClD,CAAA,EACb,kBAAC,GAAD;OAAa,WAAU;iBAAvB;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBACZ,EAAS,KAAK,OAAO,EAAE;UACpB,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAe,EAAS;UAAS,CAAA,EAC9C,kBAAC,KAAD;UAAG,WAAU;oBAA+B,EAAS;UAAiB,CAAA,CAClE,EAAA,CAAA,CACF;;QAEL,EAAS,YACR,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,oCAAqC,CAAA,EACvD,kBAAC,QAAD;UAAM,WAAU;oBAA+C;UAExD,CAAA,CACH;;QAGR,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsB;YAAa,CAAA,EACnD,kBAAC,OAAD;YAAK,WAAU;sBAAf;aACE,kBAAC,GAAD,EAAM,WAAU,oCAAqC,CAAA;aACrD,kBAAC,QAAD;cAAM,WAAU;wBAA4B,EAAS;cAAc,CAAA;aACnE,kBAAC,QAAD;cAAM,WAAU;wBAAhB;eAAmD;eAC/C,EAAS;eAAa;eACnB;;aACH;cACF;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsB;YAAsB,CAAA,EAC5D,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAA4C,EAAS,gBAAe,IAAQ;cACxE;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsB;YAAoB,CAAA,EAC1D,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAA4C,EAAS,cAAa,QAAY;cAC1E;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsB;YAAiB,CAAA,EACvD,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CACG,EAAS,iBAAgB,SACrB;cACH;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsB;YAAoB,CAAA,EAC1D,kBAAC,QAAD;YAAM,WAAU;sBAA4B,EAAS;YAAyB,CAAA,CAC1E;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsB;YAAkB,CAAA,EACxD,kBAAC,QAAD;YAAM,WAAU;sBAAhB;aAA2C;aAAE,EAAS;aAAW;aAAU;cACvE;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsB;YAAe,CAAA,EACrD,kBAAC,QAAD;YAAM,WAAU;sBAAe,EAAS;YAAgB,CAAA,CACpD;;UACF;;QAEN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA0C;UAAkB,CAAA,EACzE,kBAAC,OAAD;UAAK,WAAU;oBACZ,EAAS,eAAe,KAAK,MAC5B,kBAAC,GAAD;WAAkB,SAAQ;WAAY,WAAU;qBAC7C;WACK,EAFI,EAEJ,CACR;UACE,CAAA,CACF;;QAEN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAA0C;UAAa,CAAA,EACpE,kBAAC,OAAD;UAAK,WAAU;oBACZ,EAAS,UAAU,KAAK,MACvB,kBAAC,GAAD;WAAkB,SAAQ;WAAU,WAAU;qBAC3C;WACK,EAFI,EAEJ,CACR;UACE,CAAA,CACF;;QAEN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAQ,WAAU;UAAS,MAAK;UAAK,SAAQ;oBAA7C,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,gBAC1B;aACT,kBAAC,GAAD;UAAQ,WAAU;UAAS,MAAK;UAAK,SAAQ;oBAA7C,CACE,kBAAC,GAAD,EAAe,WAAU,gBAAiB,CAAA,EAAA,WACnC;YACL;;QACM;SACT;SAIT,kBAAC,GAAD;MAAW,WAAU;MAAQ,MAAA;MAAK,WAAU;gBAA5C,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OAAW,WAAU;iBAAY;OAAsB,CAAA,EAC5C,CAAA,EACb,kBAAC,GAAD;OAAa,WAAU;iBAAvB;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAsB;UAAoB,CAAA,EAC1D,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CAAkE,KAC9D,EAAQ,QAAQ,UAAU,gBAAgB,CACvC;YACH;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA,EAC7B,kBAAC,QAAD,EAAA,UAAA;UAAM;UAAmB,EAAQ,SAAS;UAAQ;UAAY,EAAA,CAAA,CAC1D;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA,EAClC,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAQ,QAAQ,MAAK,iBAAqB,EAAA,CAAA,CAC7C;;QACN,kBAAC,GAAD;SAAQ,WAAU;SAAS,eAAe,EAAoB,GAAK;mBAAnE,CACE,kBAAC,GAAD,EAAU,WAAU,gBAAiB,CAAA,EAAA,YAC9B;;QACG;SACJ;QACR;OACF;;GAGL,KACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KAAW,WAAU;KAAQ,WAAU;eAAvC,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,gBAAc,MAAsB,EAAI;SACxC,WAAW,4IACT,MAAsB,EAAI,KACtB,6CACA;mBAPR,CAUE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAe,EAAI;WAAY,CAAA,EAC/C,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CAAyC,KAAE,EAAI,MAAM,gBAAgB,CAAQ;aACzE;aACN,kBAAC,KAAD;UAAG,WAAU;oBAAb;WACG,EAAI;WAAY;WAAI,EAAI;WAAS;WAChC;YACG;WAhBF,EAAI,GAgBF,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;QACJ;;IACR,CAAA;GAEJ"}
|
|
@@ -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,
|
|
5
|
-
import { useI18n as
|
|
6
|
-
import { Fragment as
|
|
7
|
-
import { AuroraBackground as
|
|
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
|
+
import { useI18n as d } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
6
|
+
import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
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,163 +56,167 @@ var x = {
|
|
|
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
|
-
return /* @__PURE__ */
|
|
78
|
+
return /* @__PURE__ */ m("div", {
|
|
79
79
|
className: "space-y-6 p-6 bg-bg-canvas min-h-screen",
|
|
80
80
|
children: [
|
|
81
|
-
/* @__PURE__ */
|
|
81
|
+
/* @__PURE__ */ m("div", {
|
|
82
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
83
|
children: [
|
|
84
|
-
/* @__PURE__ */
|
|
85
|
-
/* @__PURE__ */
|
|
84
|
+
/* @__PURE__ */ p(h, { intensity: "subtle" }),
|
|
85
|
+
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("h1", {
|
|
86
86
|
className: "text-2xl font-semibold tracking-tight",
|
|
87
|
-
children: /* @__PURE__ */
|
|
88
|
-
}), /* @__PURE__ */
|
|
87
|
+
children: /* @__PURE__ */ p(y, { children: E("proserviceworld.services.title", "Services") })
|
|
88
|
+
}), /* @__PURE__ */ p("p", {
|
|
89
89
|
className: "text-sm text-text-secondary",
|
|
90
|
-
children:
|
|
90
|
+
children: z
|
|
91
91
|
})] }),
|
|
92
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ m("div", {
|
|
93
93
|
className: "flex items-center gap-2 mt-4 md:mt-0",
|
|
94
|
-
children: [/* @__PURE__ */
|
|
95
|
-
variant:
|
|
94
|
+
children: [/* @__PURE__ */ p(_, {
|
|
95
|
+
variant: M === "grid" ? "default" : "outline",
|
|
96
96
|
size: "sm",
|
|
97
|
-
onClick: () =>
|
|
98
|
-
children: /* @__PURE__ */
|
|
99
|
-
}), /* @__PURE__ */
|
|
100
|
-
variant:
|
|
97
|
+
onClick: () => N("grid"),
|
|
98
|
+
children: /* @__PURE__ */ p(o, { className: "h-4 w-4" })
|
|
99
|
+
}), /* @__PURE__ */ p(_, {
|
|
100
|
+
variant: M === "list" ? "default" : "outline",
|
|
101
101
|
size: "sm",
|
|
102
|
-
onClick: () =>
|
|
103
|
-
children: /* @__PURE__ */
|
|
102
|
+
onClick: () => N("list"),
|
|
103
|
+
children: /* @__PURE__ */ p(s, { className: "h-4 w-4" })
|
|
104
104
|
})]
|
|
105
105
|
})
|
|
106
106
|
]
|
|
107
107
|
}),
|
|
108
|
-
/* @__PURE__ */ p(
|
|
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.")
|
|
111
|
+
}),
|
|
112
|
+
/* @__PURE__ */ m("div", {
|
|
109
113
|
className: "flex flex-col sm:flex-row gap-4",
|
|
110
|
-
children: [/* @__PURE__ */
|
|
114
|
+
children: [/* @__PURE__ */ m("div", {
|
|
111
115
|
className: "flex-1 relative",
|
|
112
|
-
children: [/* @__PURE__ */
|
|
113
|
-
placeholder:
|
|
114
|
-
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,
|
|
115
119
|
onChange: (e) => {
|
|
116
|
-
|
|
120
|
+
k(e.target.value), F(1);
|
|
117
121
|
},
|
|
118
122
|
className: "pl-10"
|
|
119
123
|
})]
|
|
120
|
-
}), /* @__PURE__ */
|
|
121
|
-
value:
|
|
124
|
+
}), /* @__PURE__ */ m("select", {
|
|
125
|
+
value: A,
|
|
122
126
|
onChange: (e) => {
|
|
123
|
-
|
|
127
|
+
j(e.target.value), F(1);
|
|
124
128
|
},
|
|
125
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",
|
|
126
130
|
children: [
|
|
127
|
-
/* @__PURE__ */
|
|
131
|
+
/* @__PURE__ */ p("option", {
|
|
128
132
|
value: "",
|
|
129
|
-
children:
|
|
133
|
+
children: E("proserviceworld.shared.filters.allCategories", "All Categories")
|
|
130
134
|
}),
|
|
131
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ p("option", {
|
|
132
136
|
value: "financial_services",
|
|
133
|
-
children:
|
|
137
|
+
children: B("financial_services")
|
|
134
138
|
}),
|
|
135
|
-
/* @__PURE__ */
|
|
139
|
+
/* @__PURE__ */ p("option", {
|
|
136
140
|
value: "legal_services",
|
|
137
|
-
children:
|
|
141
|
+
children: B("legal_services")
|
|
138
142
|
}),
|
|
139
|
-
/* @__PURE__ */
|
|
143
|
+
/* @__PURE__ */ p("option", {
|
|
140
144
|
value: "marketing_advertising",
|
|
141
|
-
children:
|
|
145
|
+
children: B("marketing_advertising")
|
|
142
146
|
}),
|
|
143
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ p("option", {
|
|
144
148
|
value: "it_technology",
|
|
145
|
-
children:
|
|
149
|
+
children: B("it_technology")
|
|
146
150
|
}),
|
|
147
|
-
/* @__PURE__ */
|
|
151
|
+
/* @__PURE__ */ p("option", {
|
|
148
152
|
value: "human_resources",
|
|
149
|
-
children:
|
|
153
|
+
children: B("human_resources")
|
|
150
154
|
}),
|
|
151
|
-
/* @__PURE__ */
|
|
155
|
+
/* @__PURE__ */ p("option", {
|
|
152
156
|
value: "accounting_bookkeeping",
|
|
153
|
-
children:
|
|
157
|
+
children: B("accounting_bookkeeping")
|
|
154
158
|
}),
|
|
155
|
-
/* @__PURE__ */
|
|
159
|
+
/* @__PURE__ */ p("option", {
|
|
156
160
|
value: "creative_design",
|
|
157
|
-
children:
|
|
161
|
+
children: B("creative_design")
|
|
158
162
|
}),
|
|
159
|
-
/* @__PURE__ */
|
|
163
|
+
/* @__PURE__ */ p("option", {
|
|
160
164
|
value: "education_training",
|
|
161
|
-
children:
|
|
165
|
+
children: B("education_training")
|
|
162
166
|
})
|
|
163
167
|
]
|
|
164
168
|
})]
|
|
165
169
|
}),
|
|
166
|
-
|
|
167
|
-
className:
|
|
168
|
-
children:
|
|
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, {
|
|
169
173
|
treatment: "glass",
|
|
170
174
|
glow: e.featured,
|
|
171
175
|
className: "border-border-seam p-0 transition-shadow hover:shadow-pop",
|
|
172
|
-
children: /* @__PURE__ */
|
|
173
|
-
className:
|
|
174
|
-
children:
|
|
175
|
-
/* @__PURE__ */
|
|
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: [
|
|
179
|
+
/* @__PURE__ */ m("div", {
|
|
176
180
|
className: "flex items-center justify-between mb-3",
|
|
177
|
-
children: [/* @__PURE__ */
|
|
181
|
+
children: [/* @__PURE__ */ p(g, {
|
|
178
182
|
variant: "outline",
|
|
179
183
|
className: "text-xs capitalize",
|
|
180
|
-
children:
|
|
181
|
-
}), e.featured && /* @__PURE__ */
|
|
184
|
+
children: B(e.category)
|
|
185
|
+
}), e.featured && /* @__PURE__ */ p(g, { children: E("proserviceworld.services.badges.featured", "Featured") })]
|
|
182
186
|
}),
|
|
183
|
-
/* @__PURE__ */
|
|
187
|
+
/* @__PURE__ */ p("h3", {
|
|
184
188
|
className: "font-semibold mb-2",
|
|
185
189
|
children: e.title
|
|
186
190
|
}),
|
|
187
|
-
/* @__PURE__ */
|
|
191
|
+
/* @__PURE__ */ p("p", {
|
|
188
192
|
className: "text-sm text-text-secondary mb-3 line-clamp-2",
|
|
189
193
|
children: e.description
|
|
190
194
|
}),
|
|
191
|
-
/* @__PURE__ */
|
|
195
|
+
/* @__PURE__ */ m("div", {
|
|
192
196
|
className: "flex items-center gap-2 mb-3 text-sm",
|
|
193
197
|
children: [
|
|
194
|
-
/* @__PURE__ */
|
|
198
|
+
/* @__PURE__ */ p("div", {
|
|
195
199
|
className: "h-6 w-6 rounded-full bg-bg-sunken flex items-center justify-center text-xs",
|
|
196
200
|
children: e.providerName.charAt(0)
|
|
197
201
|
}),
|
|
198
|
-
/* @__PURE__ */
|
|
202
|
+
/* @__PURE__ */ p("span", {
|
|
199
203
|
className: "text-text-secondary",
|
|
200
204
|
children: e.providerName
|
|
201
205
|
}),
|
|
202
|
-
e.providerVerified && /* @__PURE__ */
|
|
206
|
+
e.providerVerified && /* @__PURE__ */ p(T, {})
|
|
203
207
|
]
|
|
204
208
|
}),
|
|
205
|
-
/* @__PURE__ */
|
|
209
|
+
/* @__PURE__ */ m("div", {
|
|
206
210
|
className: "flex items-center justify-between text-sm",
|
|
207
|
-
children: [/* @__PURE__ */
|
|
211
|
+
children: [/* @__PURE__ */ m("div", {
|
|
208
212
|
className: "flex items-center",
|
|
209
213
|
children: [
|
|
210
|
-
/* @__PURE__ */
|
|
211
|
-
/* @__PURE__ */
|
|
214
|
+
/* @__PURE__ */ p(l, { className: "h-4 w-4 text-status-warning-text fill-current mr-1" }),
|
|
215
|
+
/* @__PURE__ */ p("span", {
|
|
212
216
|
className: "tabular-nums",
|
|
213
217
|
children: e.providerRating.toFixed(1)
|
|
214
218
|
}),
|
|
215
|
-
/* @__PURE__ */
|
|
219
|
+
/* @__PURE__ */ m("span", {
|
|
216
220
|
className: "text-text-secondary ml-1 tabular-nums",
|
|
217
221
|
children: [
|
|
218
222
|
"(",
|
|
@@ -221,113 +225,113 @@ function S() {
|
|
|
221
225
|
]
|
|
222
226
|
})
|
|
223
227
|
]
|
|
224
|
-
}), /* @__PURE__ */
|
|
228
|
+
}), /* @__PURE__ */ p("span", {
|
|
225
229
|
className: "font-medium tabular-nums",
|
|
226
|
-
children:
|
|
230
|
+
children: E("proserviceworld.services.card.pricing.from", "From ${{amount}}", { amount: e.pricing.basePrice.toLocaleString() })
|
|
227
231
|
})]
|
|
228
232
|
}),
|
|
229
|
-
/* @__PURE__ */
|
|
233
|
+
/* @__PURE__ */ p("div", {
|
|
230
234
|
className: "flex flex-wrap gap-1 mt-3",
|
|
231
|
-
children: e.tags.slice(0, 3).map((e) => /* @__PURE__ */
|
|
235
|
+
children: e.tags.slice(0, 3).map((e) => /* @__PURE__ */ p("span", {
|
|
232
236
|
className: "inline-block px-2 py-0.5 bg-bg-sunken text-xs rounded",
|
|
233
237
|
children: e
|
|
234
238
|
}, e))
|
|
235
239
|
}),
|
|
236
|
-
/* @__PURE__ */
|
|
240
|
+
/* @__PURE__ */ m("div", {
|
|
237
241
|
className: "flex items-center gap-4 mt-3 pt-3 border-t border-border-seam text-xs text-text-secondary",
|
|
238
|
-
children: [/* @__PURE__ */
|
|
242
|
+
children: [/* @__PURE__ */ m("span", {
|
|
239
243
|
className: "flex items-center",
|
|
240
|
-
children: [/* @__PURE__ */
|
|
241
|
-
}), /* @__PURE__ */
|
|
244
|
+
children: [/* @__PURE__ */ p(i, { className: "h-3 w-3 mr-1" }), E("proserviceworld.services.card.meta.days", "{{count}} days", { count: e.duration.typical })]
|
|
245
|
+
}), /* @__PURE__ */ m("span", {
|
|
242
246
|
className: "flex items-center",
|
|
243
|
-
children: [/* @__PURE__ */
|
|
247
|
+
children: [/* @__PURE__ */ p(u, { className: "h-3 w-3 mr-1" }), E("proserviceworld.services.card.meta.bookings", "{{count}} bookings", { count: e.totalBookings })]
|
|
244
248
|
})]
|
|
245
249
|
})
|
|
246
|
-
] }) : /* @__PURE__ */
|
|
250
|
+
] }) : /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ m("div", {
|
|
247
251
|
className: "flex-1 min-w-0",
|
|
248
252
|
children: [
|
|
249
|
-
/* @__PURE__ */
|
|
253
|
+
/* @__PURE__ */ m("div", {
|
|
250
254
|
className: "flex items-center gap-2 mb-1",
|
|
251
|
-
children: [/* @__PURE__ */
|
|
255
|
+
children: [/* @__PURE__ */ p("h3", {
|
|
252
256
|
className: "font-semibold",
|
|
253
257
|
children: e.title
|
|
254
|
-
}), e.featured && /* @__PURE__ */
|
|
258
|
+
}), e.featured && /* @__PURE__ */ p(g, {
|
|
255
259
|
className: "text-xs",
|
|
256
|
-
children:
|
|
260
|
+
children: E("proserviceworld.services.badges.featured", "Featured")
|
|
257
261
|
})]
|
|
258
262
|
}),
|
|
259
|
-
/* @__PURE__ */
|
|
263
|
+
/* @__PURE__ */ p("p", {
|
|
260
264
|
className: "text-sm text-text-secondary mb-2 line-clamp-1",
|
|
261
265
|
children: e.description
|
|
262
266
|
}),
|
|
263
|
-
/* @__PURE__ */
|
|
267
|
+
/* @__PURE__ */ m("div", {
|
|
264
268
|
className: "flex items-center gap-3 text-sm text-text-secondary",
|
|
265
269
|
children: [
|
|
266
|
-
/* @__PURE__ */
|
|
267
|
-
/* @__PURE__ */
|
|
270
|
+
/* @__PURE__ */ p("span", { children: e.providerName }),
|
|
271
|
+
/* @__PURE__ */ m("span", {
|
|
268
272
|
className: "flex items-center",
|
|
269
|
-
children: [/* @__PURE__ */
|
|
273
|
+
children: [/* @__PURE__ */ p(l, { className: "h-3 w-3 text-status-warning-text fill-current mr-0.5" }), /* @__PURE__ */ p("span", {
|
|
270
274
|
className: "tabular-nums",
|
|
271
275
|
children: e.providerRating.toFixed(1)
|
|
272
276
|
})]
|
|
273
277
|
}),
|
|
274
|
-
/* @__PURE__ */
|
|
278
|
+
/* @__PURE__ */ p("span", {
|
|
275
279
|
className: "capitalize",
|
|
276
|
-
children:
|
|
280
|
+
children: B(e.category)
|
|
277
281
|
})
|
|
278
282
|
]
|
|
279
283
|
})
|
|
280
284
|
]
|
|
281
|
-
}), /* @__PURE__ */
|
|
285
|
+
}), /* @__PURE__ */ m("div", {
|
|
282
286
|
className: "text-right shrink-0",
|
|
283
|
-
children: [/* @__PURE__ */
|
|
287
|
+
children: [/* @__PURE__ */ p("div", {
|
|
284
288
|
className: "font-medium",
|
|
285
|
-
children:
|
|
286
|
-
}), /* @__PURE__ */
|
|
289
|
+
children: E("proserviceworld.services.card.pricing.from", "From ${{amount}}", { amount: e.pricing.basePrice.toLocaleString() })
|
|
290
|
+
}), /* @__PURE__ */ p("div", {
|
|
287
291
|
className: "text-sm text-text-secondary",
|
|
288
|
-
children:
|
|
292
|
+
children: E("proserviceworld.services.card.meta.days", "{{count}} days", { count: e.duration.typical })
|
|
289
293
|
})]
|
|
290
294
|
})] })
|
|
291
295
|
})
|
|
292
296
|
}, e.id))
|
|
293
|
-
}) : /* @__PURE__ */
|
|
297
|
+
}) : /* @__PURE__ */ p(b, {
|
|
294
298
|
illustration: "empty-search",
|
|
295
|
-
title:
|
|
296
|
-
description:
|
|
299
|
+
title: E("proserviceworld.services.empty.title", "No services found"),
|
|
300
|
+
description: E("proserviceworld.shared.empty.adjustFilters", "Try adjusting your search criteria or filters.")
|
|
297
301
|
}),
|
|
298
|
-
|
|
302
|
+
L > 1 && /* @__PURE__ */ m("div", {
|
|
299
303
|
className: "flex justify-center gap-2",
|
|
300
304
|
children: [
|
|
301
|
-
/* @__PURE__ */
|
|
305
|
+
/* @__PURE__ */ p(_, {
|
|
302
306
|
variant: "outline",
|
|
303
|
-
disabled:
|
|
304
|
-
onClick: () =>
|
|
305
|
-
children:
|
|
307
|
+
disabled: P === 1,
|
|
308
|
+
onClick: () => F((e) => e - 1),
|
|
309
|
+
children: E("proserviceworld.shared.pagination.previous", "Previous")
|
|
306
310
|
}),
|
|
307
|
-
/* @__PURE__ */
|
|
311
|
+
/* @__PURE__ */ p("span", {
|
|
308
312
|
className: "flex items-center px-4 text-sm",
|
|
309
|
-
children:
|
|
310
|
-
page:
|
|
311
|
-
total:
|
|
313
|
+
children: E("proserviceworld.shared.pagination.pageInfo", "Page {{page}} of {{total}}", {
|
|
314
|
+
page: P,
|
|
315
|
+
total: L
|
|
312
316
|
})
|
|
313
317
|
}),
|
|
314
|
-
/* @__PURE__ */
|
|
318
|
+
/* @__PURE__ */ p(_, {
|
|
315
319
|
variant: "outline",
|
|
316
|
-
disabled:
|
|
317
|
-
onClick: () =>
|
|
318
|
-
children:
|
|
320
|
+
disabled: P >= L,
|
|
321
|
+
onClick: () => F((e) => e + 1),
|
|
322
|
+
children: E("proserviceworld.shared.pagination.next", "Next")
|
|
319
323
|
})
|
|
320
324
|
]
|
|
321
325
|
})
|
|
322
326
|
]
|
|
323
327
|
});
|
|
324
328
|
}
|
|
325
|
-
function
|
|
326
|
-
return /* @__PURE__ */
|
|
329
|
+
function T() {
|
|
330
|
+
return /* @__PURE__ */ p("svg", {
|
|
327
331
|
className: "h-4 w-4 text-accent-blue",
|
|
328
332
|
viewBox: "0 0 20 20",
|
|
329
333
|
fill: "currentColor",
|
|
330
|
-
children: /* @__PURE__ */
|
|
334
|
+
children: /* @__PURE__ */ p("path", {
|
|
331
335
|
fillRule: "evenodd",
|
|
332
336
|
d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",
|
|
333
337
|
clipRule: "evenodd"
|
|
@@ -335,6 +339,6 @@ function C() {
|
|
|
335
339
|
});
|
|
336
340
|
}
|
|
337
341
|
//#endregion
|
|
338
|
-
export {
|
|
342
|
+
export { w as ServicesPage };
|
|
339
343
|
|
|
340
344
|
//# sourceMappingURL=ServicesPage.js.map
|