@burdenoff/microfe-proserviceworld 2026.525.1 → 2026.625.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.
Files changed (31) hide show
  1. package/dist/proserviceworld/pages/AdminReportsPage.js +368 -335
  2. package/dist/proserviceworld/pages/AdminReportsPage.js.map +1 -1
  3. package/dist/proserviceworld/pages/AdminUsersPage.js +262 -242
  4. package/dist/proserviceworld/pages/AdminUsersPage.js.map +1 -1
  5. package/dist/proserviceworld/pages/AnalyticsPage.js +346 -318
  6. package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
  7. package/dist/proserviceworld/pages/BookingsPage.js +202 -185
  8. package/dist/proserviceworld/pages/BookingsPage.js.map +1 -1
  9. package/dist/proserviceworld/pages/DashboardPage.js +400 -363
  10. package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
  11. package/dist/proserviceworld/pages/DocumentsPage.js +389 -324
  12. package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
  13. package/dist/proserviceworld/pages/MessagesPage.js +77 -82
  14. package/dist/proserviceworld/pages/MessagesPage.js.map +1 -1
  15. package/dist/proserviceworld/pages/PaymentsPage.js +373 -346
  16. package/dist/proserviceworld/pages/PaymentsPage.js.map +1 -1
  17. package/dist/proserviceworld/pages/ProjectsPage.js +432 -385
  18. package/dist/proserviceworld/pages/ProjectsPage.js.map +1 -1
  19. package/dist/proserviceworld/pages/ProviderDetailPage.js +396 -352
  20. package/dist/proserviceworld/pages/ProviderDetailPage.js.map +1 -1
  21. package/dist/proserviceworld/pages/ProvidersPage.js +245 -244
  22. package/dist/proserviceworld/pages/ProvidersPage.js.map +1 -1
  23. package/dist/proserviceworld/pages/ReviewsPage.js +31 -31
  24. package/dist/proserviceworld/pages/ReviewsPage.js.map +1 -1
  25. package/dist/proserviceworld/pages/ServiceDetailsPage.js +349 -316
  26. package/dist/proserviceworld/pages/ServiceDetailsPage.js.map +1 -1
  27. package/dist/proserviceworld/pages/ServicesPage.js +163 -160
  28. package/dist/proserviceworld/pages/ServicesPage.js.map +1 -1
  29. package/dist/proserviceworld/pages/VerificationPage.js +265 -256
  30. package/dist/proserviceworld/pages/VerificationPage.js.map +1 -1
  31. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"ProvidersPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ProvidersPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { Card, CardContent, Button, Badge, Input } from '@burdenoff/fe-libs/ui';\nimport { Search, Filter, Star, Users, MapPin, CheckCircle, Clock, Briefcase } from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\nimport type { ServiceCategory } from '../types';\nimport { tWithFallback } from '../utils/i18n';\n\nconst categoryOptions: { value: ServiceCategory | ''; key: string; fallback: string }[] = [\n {\n value: '',\n key: 'proserviceworld.shared.filters.allCategories',\n fallback: 'All Categories',\n },\n {\n value: 'business_consulting',\n key: 'proserviceworld.shared.categories.businessConsulting',\n fallback: 'Business Consulting',\n },\n {\n value: 'financial_services',\n key: 'proserviceworld.shared.categories.financialServices',\n fallback: 'Financial Services',\n },\n {\n value: 'legal_services',\n key: 'proserviceworld.shared.categories.legalServices',\n fallback: 'Legal Services',\n },\n {\n value: 'accounting_bookkeeping',\n key: 'proserviceworld.shared.categories.accountingBookkeeping',\n fallback: 'Accounting & Bookkeeping',\n },\n {\n value: 'marketing_advertising',\n key: 'proserviceworld.shared.categories.marketingAdvertising',\n fallback: 'Marketing & Advertising',\n },\n {\n value: 'it_technology',\n key: 'proserviceworld.shared.categories.itTechnology',\n fallback: 'IT & Technology',\n },\n {\n value: 'human_resources',\n key: 'proserviceworld.shared.categories.humanResources',\n fallback: 'Human Resources',\n },\n {\n value: 'creative_design',\n key: 'proserviceworld.shared.categories.creativeDesign',\n fallback: 'Creative & Design',\n },\n {\n value: 'education_training',\n key: 'proserviceworld.shared.categories.educationTraining',\n fallback: 'Education & Training',\n },\n];\n\nexport function ProvidersPage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string, params?: Record<string, string | number>): string =>\n tWithFallback(t, key, fallback, params);\n const { providers } = useProServiceWorldStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedCategory, setSelectedCategory] = useState<ServiceCategory | ''>('');\n const [minRating, setMinRating] = useState<number | ''>('');\n const [showFilters, setShowFilters] = useState(false);\n\n const filteredProviders = useMemo(() => {\n let result = [...providers];\n\n if (searchQuery) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (p) =>\n p.name.toLowerCase().includes(q) ||\n p.businessName.toLowerCase().includes(q) ||\n p.tagline.toLowerCase().includes(q) ||\n p.specializations.some((s) => s.toLowerCase().includes(q))\n );\n }\n\n if (selectedCategory) {\n result = result.filter((p) => p.category === selectedCategory);\n }\n\n if (minRating) {\n result = result.filter((p) => p.rating >= minRating);\n }\n\n result.sort((a, b) => b.rating - a.rating);\n return result;\n }, [providers, searchQuery, selectedCategory, minRating]);\n\n const avgRating =\n filteredProviders.length > 0\n ? (\n filteredProviders.reduce((sum, p) => sum + p.rating, 0) / filteredProviders.length\n ).toFixed(1)\n : '0';\n\n const countries = new Set(filteredProviders.map((p) => p.country)).size;\n\n const clearFilters = () => {\n setSearchQuery('');\n setSelectedCategory('');\n setMinRating('');\n };\n const subtitle = searchQuery\n ? tr(\n 'proserviceworld.providers.subtitleWithQuery',\n '{{count}} providers found for \"{{query}}\"',\n {\n count: filteredProviders.length,\n query: searchQuery,\n }\n )\n : tr('proserviceworld.providers.subtitle', '{{count}} providers found', {\n count: filteredProviders.length,\n });\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Page Header */}\n <div className=\"flex flex-col md:flex-row md:items-center md:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">\n {tr('proserviceworld.providers.title', 'Service Providers')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">{subtitle}</p>\n </div>\n <Button variant=\"outline\" onClick={() => setShowFilters(!showFilters)}>\n <Filter className=\"h-4 w-4 mr-2\" />\n {tr('proserviceworld.providers.actions.filters', 'Filters')}\n </Button>\n </div>\n\n {/* Search Bar */}\n <div className=\"flex gap-4\">\n <div className=\"flex-1 relative\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-muted-foreground\" />\n <Input\n type=\"text\"\n placeholder={tr(\n 'proserviceworld.providers.search.placeholder',\n 'Search providers by name, business, or specialization...'\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10 h-12\"\n />\n </div>\n </div>\n\n {/* Filters Panel */}\n {showFilters && (\n <Card>\n <CardContent className=\"p-6\">\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('proserviceworld.providers.filters.category', 'Category')}\n </label>\n <select\n value={selectedCategory}\n onChange={(e) => setSelectedCategory(e.target.value as ServiceCategory | '')}\n className=\"w-full p-2 border border-input rounded-md bg-background text-foreground\"\n >\n {categoryOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {tr(opt.key, opt.fallback)}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('proserviceworld.providers.filters.minimumRating', 'Minimum Rating')}\n </label>\n <select\n value={minRating}\n onChange={(e) => setMinRating(e.target.value ? Number(e.target.value) : '')}\n className=\"w-full p-2 border border-input rounded-md bg-background text-foreground\"\n >\n <option value=\"\">\n {tr('proserviceworld.providers.filters.anyRating', 'Any Rating')}\n </option>\n <option value=\"4\">\n {tr('proserviceworld.providers.filters.rating4', '4+ Stars')}\n </option>\n <option value=\"4.5\">\n {tr('proserviceworld.providers.filters.rating45', '4.5+ Stars')}\n </option>\n <option value=\"4.8\">\n {tr('proserviceworld.providers.filters.rating48', '4.8+ Stars')}\n </option>\n </select>\n </div>\n <div className=\"flex items-end\">\n <Button variant=\"outline\" onClick={clearFilters} className=\"w-full\">\n {tr('proserviceworld.providers.filters.clear', 'Clear Filters')}\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Provider Grid */}\n {filteredProviders.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6\">\n {filteredProviders.map((provider) => (\n <Card key={provider.id} className=\"hover:shadow-md transition-shadow\">\n <CardContent className=\"p-6\">\n <div className=\"flex items-center space-x-4 mb-4\">\n <div className=\"h-12 w-12 rounded-full bg-primary/10 flex items-center justify-center\">\n <span className=\"text-primary font-bold\">{provider.name.charAt(0)}</span>\n </div>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-semibold truncate\">{provider.businessName}</h3>\n <p className=\"text-sm text-muted-foreground truncate\">{provider.name}</p>\n </div>\n {provider.verified && <CheckCircle className=\"h-5 w-5 text-blue-600 shrink-0\" />}\n </div>\n\n <p className=\"text-sm text-muted-foreground mb-3 line-clamp-2\">\n {provider.tagline}\n </p>\n\n <div className=\"flex flex-wrap gap-1 mb-3\">\n {provider.specializations.slice(0, 2).map((spec) => (\n <Badge key={spec} variant=\"secondary\" className=\"text-xs\">\n {spec}\n </Badge>\n ))}\n {provider.specializations.length > 2 && (\n <Badge variant=\"outline\" className=\"text-xs\">\n +{provider.specializations.length - 2}\n </Badge>\n )}\n </div>\n\n <div className=\"flex items-center justify-between text-sm mb-3\">\n <div className=\"flex items-center\">\n <Star className=\"h-4 w-4 text-yellow-400 fill-current mr-1\" />\n <span className=\"font-medium\">{provider.rating.toFixed(1)}</span>\n <span className=\"text-muted-foreground ml-1\">({provider.totalReviews})</span>\n </div>\n <div className=\"flex items-center text-muted-foreground\">\n <MapPin className=\"h-3 w-3 mr-1\" />\n <span>{provider.location}</span>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2 text-xs text-muted-foreground border-t pt-3\">\n <div className=\"flex items-center\">\n <Clock className=\"h-3 w-3 mr-1\" />\n {tr('proserviceworld.providers.card.responseTime', '{{count}}h response', {\n count: provider.responseTime,\n })}\n </div>\n <div className=\"flex items-center\">\n <Briefcase className=\"h-3 w-3 mr-1\" />\n {tr('proserviceworld.providers.card.projects', '{{count}} projects', {\n count: provider.projectsCompleted,\n })}\n </div>\n </div>\n\n <Button variant=\"outline\" size=\"sm\" className=\"w-full mt-4\">\n {tr('proserviceworld.providers.actions.viewProfile', 'View Profile')}\n </Button>\n </CardContent>\n </Card>\n ))}\n </div>\n ) : (\n <div className=\"text-center py-12\">\n <Users className=\"h-12 w-12 mx-auto text-muted-foreground mb-4\" />\n <h3 className=\"text-lg font-medium mb-2\">\n {tr('proserviceworld.providers.empty.title', 'No providers found')}\n </h3>\n <p className=\"text-muted-foreground\">\n {tr(\n 'proserviceworld.shared.empty.adjustFilters',\n 'Try adjusting your search criteria or filters.'\n )}\n </p>\n </div>\n )}\n\n {/* Provider Statistics */}\n {filteredProviders.length > 0 && (\n <Card className=\"bg-primary/5\">\n <CardContent className=\"p-8\">\n <div className=\"text-center mb-8\">\n <h2 className=\"text-xl font-bold\">\n {tr('proserviceworld.providers.stats.title', 'Provider Statistics')}\n </h2>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-8\">\n <div className=\"text-center\">\n <div className=\"flex items-center justify-center w-12 h-12 mx-auto bg-primary/10 rounded-lg mb-4\">\n <Star className=\"h-6 w-6 text-primary\" />\n </div>\n <div className=\"text-2xl font-bold\">{avgRating}</div>\n <div className=\"text-sm text-muted-foreground\">\n {tr('proserviceworld.providers.stats.averageRating', 'Average Rating')}\n </div>\n </div>\n <div className=\"text-center\">\n <div className=\"flex items-center justify-center w-12 h-12 mx-auto bg-primary/10 rounded-lg mb-4\">\n <Users className=\"h-6 w-6 text-primary\" />\n </div>\n <div className=\"text-2xl font-bold\">{filteredProviders.length}</div>\n <div className=\"text-sm text-muted-foreground\">\n {tr('proserviceworld.providers.stats.expertProviders', 'Expert Providers')}\n </div>\n </div>\n <div className=\"text-center\">\n <div className=\"flex items-center justify-center w-12 h-12 mx-auto bg-primary/10 rounded-lg mb-4\">\n <MapPin className=\"h-6 w-6 text-primary\" />\n </div>\n <div className=\"text-2xl font-bold\">{countries}</div>\n <div className=\"text-sm text-muted-foreground\">\n {tr('proserviceworld.providers.stats.countries', 'Countries')}\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAQA,IAAM,IAAoF;CACxF;EACE,OAAO;EACP,KAAK;EACL,UAAU;EACX;CACD;EACE,OAAO;EACP,KAAK;EACL,UAAU;EACX;CACD;EACE,OAAO;EACP,KAAK;EACL,UAAU;EACX;CACD;EACE,OAAO;EACP,KAAK;EACL,UAAU;EACX;CACD;EACE,OAAO;EACP,KAAK;EACL,UAAU;EACX;CACD;EACE,OAAO;EACP,KAAK;EACL,UAAU;EACX;CACD;EACE,OAAO;EACP,KAAK;EACL,UAAU;EACX;CACD;EACE,OAAO;EACP,KAAK;EACL,UAAU;EACX;CACD;EACE,OAAO;EACP,KAAK;EACL,UAAU;EACX;CACD;EACE,OAAO;EACP,KAAK;EACL,UAAU;EACX;CACF;AAED,SAAgB,IAAgB;CAC9B,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,GAAkB,MACzC,EAAc,GAAG,GAAK,GAAU,EAAO,EACnC,EAAE,iBAAc,GAAyB,EACzC,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAkB,KAAuB,EAA+B,GAAG,EAC5E,CAAC,GAAW,KAAgB,EAAsB,GAAG,EACrD,CAAC,GAAa,KAAkB,EAAS,GAAM,EAE/C,IAAoB,QAAc;EACtC,IAAI,IAAS,CAAC,GAAG,EAAU;AAE3B,MAAI,GAAa;GACf,IAAM,IAAI,EAAY,aAAa;AACnC,OAAS,EAAO,QACb,MACC,EAAE,KAAK,aAAa,CAAC,SAAS,EAAE,IAChC,EAAE,aAAa,aAAa,CAAC,SAAS,EAAE,IACxC,EAAE,QAAQ,aAAa,CAAC,SAAS,EAAE,IACnC,EAAE,gBAAgB,MAAM,MAAM,EAAE,aAAa,CAAC,SAAS,EAAE,CAAC,CAC7D;;AAYH,SATI,MACF,IAAS,EAAO,QAAQ,MAAM,EAAE,aAAa,EAAiB,GAG5D,MACF,IAAS,EAAO,QAAQ,MAAM,EAAE,UAAU,EAAU,GAGtD,EAAO,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,OAAO,EACnC;IACN;EAAC;EAAW;EAAa;EAAkB;EAAU,CAAC,EAEnD,IACJ,EAAkB,SAAS,KAErB,EAAkB,QAAQ,GAAK,MAAM,IAAM,EAAE,QAAQ,EAAE,GAAG,EAAkB,QAC5E,QAAQ,EAAE,GACZ,KAEA,IAAY,IAAI,IAAI,EAAkB,KAAK,MAAM,EAAE,QAAQ,CAAC,CAAC,MAE7D,UAAqB;AAGzB,EAFA,EAAe,GAAG,EAClB,EAAoB,GAAG,EACvB,EAAa,GAAG;IAEZ,IAAW,IACb,EACE,+CACA,+CACA;EACE,OAAO,EAAkB;EACzB,OAAO;EACR,CACF,GACD,EAAG,sCAAsC,6BAA6B,EACpE,OAAO,EAAkB,QAC1B,CAAC;AAEN,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,mCAAmC,oBAAoB;KACxD,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eAAiC;KAAa,CAAA,CACvD,EAAA,CAAA,EACN,kBAAC,GAAD;KAAQ,SAAQ;KAAU,eAAe,EAAe,CAAC,EAAY;eAArE,CACE,kBAAC,GAAD,EAAQ,WAAU,gBAAiB,CAAA,EAClC,EAAG,6CAA6C,UAAU,CACpD;OACL;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,0EAA2E,CAAA,EAC7F,kBAAC,GAAD;MACE,MAAK;MACL,aAAa,EACX,gDACA,2DACD;MACD,OAAO;MACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;MAC/C,WAAU;MACV,CAAA,CACE;;IACF,CAAA;GAGL,KACC,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;IAAa,WAAU;cACrB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,WAAU;iBACd,EAAG,8CAA8C,WAAW;OACvD,CAAA,EACR,kBAAC,UAAD;OACE,OAAO;OACP,WAAW,MAAM,EAAoB,EAAE,OAAO,MAA8B;OAC5E,WAAU;iBAET,EAAgB,KAAK,MACpB,kBAAC,UAAD;QAAwB,OAAO,EAAI;kBAChC,EAAG,EAAI,KAAK,EAAI,SAAS;QACnB,EAFI,EAAI,MAER,CACT;OACK,CAAA,CACL,EAAA,CAAA;MACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;OAAO,WAAU;iBACd,EAAG,mDAAmD,iBAAiB;OAClE,CAAA,EACR,kBAAC,UAAD;OACE,OAAO;OACP,WAAW,MAAM,EAAa,EAAE,OAAO,QAAQ,OAAO,EAAE,OAAO,MAAM,GAAG,GAAG;OAC3E,WAAU;iBAHZ;QAKE,kBAAC,UAAD;SAAQ,OAAM;mBACX,EAAG,+CAA+C,aAAa;SACzD,CAAA;QACT,kBAAC,UAAD;SAAQ,OAAM;mBACX,EAAG,6CAA6C,WAAW;SACrD,CAAA;QACT,kBAAC,UAAD;SAAQ,OAAM;mBACX,EAAG,8CAA8C,aAAa;SACxD,CAAA;QACT,kBAAC,UAAD;SAAQ,OAAM;mBACX,EAAG,8CAA8C,aAAa;SACxD,CAAA;QACF;SACL,EAAA,CAAA;MACN,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD;QAAQ,SAAQ;QAAU,SAAS;QAAc,WAAU;kBACxD,EAAG,2CAA2C,gBAAgB;QACxD,CAAA;OACL,CAAA;MACF;;IACM,CAAA,EACT,CAAA;GAIR,EAAkB,SAAS,IAC1B,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAkB,KAAK,MACtB,kBAAC,GAAD;KAAwB,WAAU;eAChC,kBAAC,GAAD;MAAa,WAAU;gBAAvB;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,QAAD;WAAM,WAAU;qBAA0B,EAAS,KAAK,OAAO,EAAE;WAAQ,CAAA;UACrE,CAAA;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,MAAD;WAAI,WAAU;qBAA0B,EAAS;WAAkB,CAAA,EACnE,kBAAC,KAAD;WAAG,WAAU;qBAA0C,EAAS;WAAS,CAAA,CACrE;;SACL,EAAS,YAAY,kBAAC,GAAD,EAAa,WAAU,kCAAmC,CAAA;SAC5E;;OAEN,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAS;QACR,CAAA;OAEJ,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACG,EAAS,gBAAgB,MAAM,GAAG,EAAE,CAAC,KAAK,MACzC,kBAAC,GAAD;SAAkB,SAAQ;SAAY,WAAU;mBAC7C;SACK,EAFI,EAEJ,CACR,EACD,EAAS,gBAAgB,SAAS,KACjC,kBAAC,GAAD;SAAO,SAAQ;SAAU,WAAU;mBAAnC,CAA6C,KACzC,EAAS,gBAAgB,SAAS,EAC9B;WAEN;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,GAAD,EAAM,WAAU,6CAA8C,CAAA;UAC9D,kBAAC,QAAD;WAAM,WAAU;qBAAe,EAAS,OAAO,QAAQ,EAAE;WAAQ,CAAA;UACjE,kBAAC,QAAD;WAAM,WAAU;qBAAhB;YAA6C;YAAE,EAAS;YAAa;YAAQ;;UACzE;YACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,gBAAiB,CAAA,EACnC,kBAAC,QAAD,EAAA,UAAO,EAAS,UAAgB,CAAA,CAC5B;WACF;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAO,WAAU,gBAAiB,CAAA,EACjC,EAAG,+CAA+C,uBAAuB,EACxE,OAAO,EAAS,cACjB,CAAC,CACE;YACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAW,WAAU,gBAAiB,CAAA,EACrC,EAAG,2CAA2C,sBAAsB,EACnE,OAAO,EAAS,mBACjB,CAAC,CACE;WACF;;OAEN,kBAAC,GAAD;QAAQ,SAAQ;QAAU,MAAK;QAAK,WAAU;kBAC3C,EAAG,iDAAiD,eAAe;QAC7D,CAAA;OACG;;KACT,EA7DI,EAAS,GA6Db,CACP;IACE,CAAA,GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAO,WAAU,gDAAiD,CAAA;KAClE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,yCAAyC,qBAAqB;MAC/D,CAAA;KACL,kBAAC,KAAD;MAAG,WAAU;gBACV,EACC,8CACA,iDACD;MACC,CAAA;KACA;;GAIP,EAAkB,SAAS,KAC1B,kBAAC,GAAD;IAAM,WAAU;cACd,kBAAC,GAAD;KAAa,WAAU;eAAvB,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,yCAAyC,sBAAsB;OAChE,CAAA;MACD,CAAA,EACN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,GAAD,EAAM,WAAU,wBAAyB,CAAA;UACrC,CAAA;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAsB;UAAgB,CAAA;SACrD,kBAAC,OAAD;UAAK,WAAU;oBACZ,EAAG,iDAAiD,iBAAiB;UAClE,CAAA;SACF;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,GAAD,EAAO,WAAU,wBAAyB,CAAA;UACtC,CAAA;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAsB,EAAkB;UAAa,CAAA;SACpE,kBAAC,OAAD;UAAK,WAAU;oBACZ,EAAG,mDAAmD,mBAAmB;UACtE,CAAA;SACF;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBACb,kBAAC,GAAD,EAAQ,WAAU,wBAAyB,CAAA;UACvC,CAAA;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAsB;UAAgB,CAAA;SACrD,kBAAC,OAAD;UAAK,WAAU;oBACZ,EAAG,6CAA6C,YAAY;UACzD,CAAA;SACF;;OACF;QACM;;IACT,CAAA;GAEL"}
1
+ {"version":3,"file":"ProvidersPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ProvidersPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n Card,\n CardContent,\n Button,\n Badge,\n Input,\n GlassCard,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { Search, Filter, Star, Users, MapPin, CheckCircle, Clock, Briefcase } from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\nimport type { ServiceCategory } from '../types';\nimport { tWithFallback } from '../utils/i18n';\n\nconst categoryOptions: { value: ServiceCategory | ''; key: string; fallback: string }[] = [\n {\n value: '',\n key: 'proserviceworld.shared.filters.allCategories',\n fallback: 'All Categories',\n },\n {\n value: 'business_consulting',\n key: 'proserviceworld.shared.categories.businessConsulting',\n fallback: 'Business Consulting',\n },\n {\n value: 'financial_services',\n key: 'proserviceworld.shared.categories.financialServices',\n fallback: 'Financial Services',\n },\n {\n value: 'legal_services',\n key: 'proserviceworld.shared.categories.legalServices',\n fallback: 'Legal Services',\n },\n {\n value: 'accounting_bookkeeping',\n key: 'proserviceworld.shared.categories.accountingBookkeeping',\n fallback: 'Accounting & Bookkeeping',\n },\n {\n value: 'marketing_advertising',\n key: 'proserviceworld.shared.categories.marketingAdvertising',\n fallback: 'Marketing & Advertising',\n },\n {\n value: 'it_technology',\n key: 'proserviceworld.shared.categories.itTechnology',\n fallback: 'IT & Technology',\n },\n {\n value: 'human_resources',\n key: 'proserviceworld.shared.categories.humanResources',\n fallback: 'Human Resources',\n },\n {\n value: 'creative_design',\n key: 'proserviceworld.shared.categories.creativeDesign',\n fallback: 'Creative & Design',\n },\n {\n value: 'education_training',\n key: 'proserviceworld.shared.categories.educationTraining',\n fallback: 'Education & Training',\n },\n];\n\nexport function ProvidersPage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string, params?: Record<string, string | number>): string =>\n tWithFallback(t, key, fallback, params);\n const { providers } = useProServiceWorldStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedCategory, setSelectedCategory] = useState<ServiceCategory | ''>('');\n const [minRating, setMinRating] = useState<number | ''>('');\n const [showFilters, setShowFilters] = useState(false);\n\n const filteredProviders = useMemo(() => {\n let result = [...providers];\n\n if (searchQuery) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (p) =>\n p.name.toLowerCase().includes(q) ||\n p.businessName.toLowerCase().includes(q) ||\n p.tagline.toLowerCase().includes(q) ||\n p.specializations.some((s) => s.toLowerCase().includes(q))\n );\n }\n\n if (selectedCategory) {\n result = result.filter((p) => p.category === selectedCategory);\n }\n\n if (minRating) {\n result = result.filter((p) => p.rating >= minRating);\n }\n\n result.sort((a, b) => b.rating - a.rating);\n return result;\n }, [providers, searchQuery, selectedCategory, minRating]);\n\n const avgRating =\n filteredProviders.length > 0\n ? (\n filteredProviders.reduce((sum, p) => sum + p.rating, 0) / filteredProviders.length\n ).toFixed(1)\n : '0';\n\n const countries = new Set(filteredProviders.map((p) => p.country)).size;\n\n const clearFilters = () => {\n setSearchQuery('');\n setSelectedCategory('');\n setMinRating('');\n };\n const subtitle = searchQuery\n ? tr('proserviceworld.providers.subtitleWithQuery', '{{count}} providers found for \"{{query}}\"', {\n count: filteredProviders.length,\n query: searchQuery,\n })\n : tr('proserviceworld.providers.subtitle', '{{count}} providers found', {\n count: filteredProviders.length,\n });\n\n return (\n <div className=\"space-y-6 p-6 bg-bg-canvas min-h-screen\">\n {/* Hero header — the ONE aurora backdrop for this MFE */}\n <div className=\"relative overflow-hidden rounded-card -mx-2 px-2 pt-1\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"flex flex-col md:flex-row md:items-center md:justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <GradientText>{tr('proserviceworld.providers.title', 'Service Providers')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{subtitle}</p>\n </div>\n <Button\n variant=\"outline\"\n onClick={() => setShowFilters(!showFilters)}\n aria-expanded={showFilters}\n >\n <Filter className=\"h-4 w-4 mr-2\" />\n {tr('proserviceworld.providers.actions.filters', 'Filters')}\n </Button>\n </div>\n </div>\n\n {/* Search Bar */}\n <div className=\"flex gap-4\">\n <div className=\"flex-1 relative\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-text-secondary\" />\n <Input\n type=\"text\"\n placeholder={tr(\n 'proserviceworld.providers.search.placeholder',\n 'Search providers by name, business, or specialization...'\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10 h-12\"\n />\n </div>\n </div>\n\n {/* Filters Panel */}\n {showFilters && (\n <Card className=\"border-border-seam\">\n <CardContent className=\"p-6\">\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-4\">\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('proserviceworld.providers.filters.category', 'Category')}\n </label>\n <select\n value={selectedCategory}\n onChange={(e) => setSelectedCategory(e.target.value as ServiceCategory | '')}\n className=\"w-full p-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\"\n >\n {categoryOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {tr(opt.key, opt.fallback)}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('proserviceworld.providers.filters.minimumRating', 'Minimum Rating')}\n </label>\n <select\n value={minRating}\n onChange={(e) => setMinRating(e.target.value ? Number(e.target.value) : '')}\n className=\"w-full p-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\"\n >\n <option value=\"\">\n {tr('proserviceworld.providers.filters.anyRating', 'Any Rating')}\n </option>\n <option value=\"4\">\n {tr('proserviceworld.providers.filters.rating4', '4+ Stars')}\n </option>\n <option value=\"4.5\">\n {tr('proserviceworld.providers.filters.rating45', '4.5+ Stars')}\n </option>\n <option value=\"4.8\">\n {tr('proserviceworld.providers.filters.rating48', '4.8+ Stars')}\n </option>\n </select>\n </div>\n <div className=\"flex items-end\">\n <Button variant=\"outline\" onClick={clearFilters} className=\"w-full\">\n {tr('proserviceworld.providers.filters.clear', 'Clear Filters')}\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Provider Grid */}\n {filteredProviders.length > 0 ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6\">\n {filteredProviders.map((provider) => (\n <GlassCard key={provider.id} treatment=\"glass\" className=\"border-border-seam transition-shadow hover:shadow-pop\">\n <div className=\"flex items-center space-x-4 mb-4\">\n <div className=\"h-12 w-12 rounded-full bg-accent-soft flex items-center justify-center\">\n <span className=\"text-text-primary font-bold\">{provider.name.charAt(0)}</span>\n </div>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-semibold truncate\">{provider.businessName}</h3>\n <p className=\"text-sm text-text-secondary truncate\">{provider.name}</p>\n </div>\n {provider.verified && (\n <CheckCircle className=\"h-5 w-5 text-accent-blue shrink-0\" aria-label=\"Verified\" />\n )}\n </div>\n\n <p className=\"text-sm text-text-secondary mb-3 line-clamp-2\">{provider.tagline}</p>\n\n <div className=\"flex flex-wrap gap-1 mb-3\">\n {provider.specializations.slice(0, 2).map((spec) => (\n <Badge key={spec} variant=\"secondary\" className=\"text-xs\">\n {spec}\n </Badge>\n ))}\n {provider.specializations.length > 2 && (\n <Badge variant=\"outline\" className=\"text-xs\">\n +{provider.specializations.length - 2}\n </Badge>\n )}\n </div>\n\n <div className=\"flex items-center justify-between text-sm mb-3\">\n <div className=\"flex items-center\">\n <Star className=\"h-4 w-4 text-status-warning-text fill-current mr-1\" />\n <span className=\"font-medium tabular-nums\">{provider.rating.toFixed(1)}</span>\n <span className=\"text-text-secondary ml-1 tabular-nums\">\n ({provider.totalReviews})\n </span>\n </div>\n <div className=\"flex items-center text-text-secondary\">\n <MapPin className=\"h-3 w-3 mr-1\" />\n <span>{provider.location}</span>\n </div>\n </div>\n\n <div className=\"grid grid-cols-2 gap-2 text-xs text-text-secondary border-t border-border-seam pt-3\">\n <div className=\"flex items-center\">\n <Clock className=\"h-3 w-3 mr-1\" />\n {tr('proserviceworld.providers.card.responseTime', '{{count}}h response', {\n count: provider.responseTime,\n })}\n </div>\n <div className=\"flex items-center\">\n <Briefcase className=\"h-3 w-3 mr-1\" />\n {tr('proserviceworld.providers.card.projects', '{{count}} projects', {\n count: provider.projectsCompleted,\n })}\n </div>\n </div>\n\n <Button variant=\"outline\" size=\"sm\" className=\"w-full mt-4\">\n {tr('proserviceworld.providers.actions.viewProfile', 'View Profile')}\n </Button>\n </GlassCard>\n ))}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title={tr('proserviceworld.providers.empty.title', 'No providers found')}\n description={tr(\n 'proserviceworld.shared.empty.adjustFilters',\n 'Try adjusting your search criteria or filters.'\n )}\n action={\n <Button variant=\"outline\" onClick={clearFilters}>\n {tr('proserviceworld.providers.filters.clear', 'Clear Filters')}\n </Button>\n }\n />\n )}\n\n {/* Provider Statistics — the single emphasised insight zone */}\n {filteredProviders.length > 0 && (\n <EmphasisPanel className=\"p-8\">\n <div className=\"text-center mb-8\">\n <h2 className=\"text-xl font-bold tracking-tight\">\n {tr('proserviceworld.providers.stats.title', 'Provider Statistics')}\n </h2>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-8\">\n <div className=\"text-center\">\n <div className=\"flex items-center justify-center w-12 h-12 mx-auto bg-accent-soft rounded-lg mb-4\">\n <Star className=\"h-6 w-6 text-text-primary\" />\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">{avgRating}</div>\n <div className=\"text-sm text-text-secondary\">\n {tr('proserviceworld.providers.stats.averageRating', 'Average Rating')}\n </div>\n </div>\n <div className=\"text-center\">\n <div className=\"flex items-center justify-center w-12 h-12 mx-auto bg-accent-soft rounded-lg mb-4\">\n <Users className=\"h-6 w-6 text-text-primary\" />\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">{filteredProviders.length}</div>\n <div className=\"text-sm text-text-secondary\">\n {tr('proserviceworld.providers.stats.expertProviders', 'Expert Providers')}\n </div>\n </div>\n <div className=\"text-center\">\n <div className=\"flex items-center justify-center w-12 h-12 mx-auto bg-accent-soft rounded-lg mb-4\">\n <MapPin className=\"h-6 w-6 text-text-primary\" />\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">{countries}</div>\n <div className=\"text-sm text-text-secondary\">\n {tr('proserviceworld.providers.stats.countries', 'Countries')}\n </div>\n </div>\n </div>\n </EmphasisPanel>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -27,7 +27,7 @@ function S() {
27
27
  T,
28
28
  D,
29
29
  k
30
- ]), z = (e) => Array.from({ length: 5 }, (t, n) => /* @__PURE__ */ p(l, { className: `h-4 w-4 ${n < e ? "fill-yellow-400 text-yellow-400" : "text-muted-foreground/30"}` }, n));
30
+ ]), z = (e) => Array.from({ length: 5 }, (t, n) => /* @__PURE__ */ p(l, { className: `h-4 w-4 ${n < e ? "fill-status-warning-text text-status-warning-text" : "text-text-secondary/30"}` }, n));
31
31
  return /* @__PURE__ */ m("div", {
32
32
  className: "space-y-6 p-6",
33
33
  children: [
@@ -37,7 +37,7 @@ function S() {
37
37
  className: "text-2xl font-semibold",
38
38
  children: "Reviews"
39
39
  }), /* @__PURE__ */ p("p", {
40
- className: "text-sm text-muted-foreground",
40
+ className: "text-sm text-text-secondary",
41
41
  children: "View and manage your service reviews and ratings."
42
42
  })] }), /* @__PURE__ */ m(g, {
43
43
  size: "sm",
@@ -53,13 +53,13 @@ function S() {
53
53
  children: /* @__PURE__ */ m("div", {
54
54
  className: "flex items-center gap-3",
55
55
  children: [/* @__PURE__ */ p("div", {
56
- className: "rounded-lg bg-yellow-100 p-2 dark:bg-yellow-950",
57
- children: /* @__PURE__ */ p(l, { className: "h-5 w-5 text-yellow-600" })
56
+ className: "rounded-lg bg-status-warning-bg-subtle p-2",
57
+ children: /* @__PURE__ */ p(l, { className: "h-5 w-5 text-status-warning-text" })
58
58
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
59
59
  className: "text-2xl font-bold",
60
60
  children: N
61
61
  }), /* @__PURE__ */ p("p", {
62
- className: "text-xs text-muted-foreground",
62
+ className: "text-xs text-text-secondary",
63
63
  children: "Average Rating"
64
64
  })] })]
65
65
  })
@@ -69,13 +69,13 @@ function S() {
69
69
  children: /* @__PURE__ */ m("div", {
70
70
  className: "flex items-center gap-3",
71
71
  children: [/* @__PURE__ */ p("div", {
72
- className: "rounded-lg bg-blue-100 p-2 dark:bg-blue-950",
73
- children: /* @__PURE__ */ p(a, { className: "h-5 w-5 text-blue-600" })
72
+ className: "rounded-lg bg-status-info-bg-subtle p-2",
73
+ children: /* @__PURE__ */ p(a, { className: "h-5 w-5 text-accent-blue" })
74
74
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
75
75
  className: "text-2xl font-bold",
76
76
  children: P
77
77
  }), /* @__PURE__ */ p("p", {
78
- className: "text-xs text-muted-foreground",
78
+ className: "text-xs text-text-secondary",
79
79
  children: "Total Reviews"
80
80
  })] })]
81
81
  })
@@ -85,13 +85,13 @@ function S() {
85
85
  children: /* @__PURE__ */ m("div", {
86
86
  className: "flex items-center gap-3",
87
87
  children: [/* @__PURE__ */ p("div", {
88
- className: "rounded-lg bg-green-100 p-2 dark:bg-green-950",
89
- children: /* @__PURE__ */ p(f, { className: "h-5 w-5 text-green-600" })
88
+ className: "rounded-lg bg-status-success-bg-subtle p-2",
89
+ children: /* @__PURE__ */ p(f, { className: "h-5 w-5 text-status-success-text" })
90
90
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
91
91
  className: "text-2xl font-bold",
92
92
  children: F
93
93
  }), /* @__PURE__ */ p("p", {
94
- className: "text-xs text-muted-foreground",
94
+ className: "text-xs text-text-secondary",
95
95
  children: "Positive (4-5 Stars)"
96
96
  })] })]
97
97
  })
@@ -101,13 +101,13 @@ function S() {
101
101
  children: /* @__PURE__ */ m("div", {
102
102
  className: "flex items-center gap-3",
103
103
  children: [/* @__PURE__ */ p("div", {
104
- className: "rounded-lg bg-purple-100 p-2 dark:bg-purple-950",
105
- children: /* @__PURE__ */ p(i, { className: "h-5 w-5 text-purple-600" })
104
+ className: "rounded-lg bg-accent-purple-subtle p-2",
105
+ children: /* @__PURE__ */ p(i, { className: "h-5 w-5 text-accent-purple" })
106
106
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
107
107
  className: "text-2xl font-bold",
108
108
  children: I
109
109
  }), /* @__PURE__ */ p("p", {
110
- className: "text-xs text-muted-foreground",
110
+ className: "text-xs text-text-secondary",
111
111
  children: "5-Star Reviews"
112
112
  })] })]
113
113
  })
@@ -129,21 +129,21 @@ function S() {
129
129
  let t = L[e] ?? 0, n = P > 0 ? Math.round(t / P * 100) : 0;
130
130
  return /* @__PURE__ */ m("button", {
131
131
  onClick: () => O(D === e ? null : e),
132
- className: `flex w-full items-center gap-3 rounded px-2 py-1 transition-colors ${D === e ? "bg-primary/10" : "hover:bg-muted/50"}`,
132
+ className: `flex w-full items-center gap-3 rounded px-2 py-1 transition-colors ${D === e ? "bg-action-primary-bg/10" : "hover:bg-bg-sunken/50"}`,
133
133
  children: [
134
134
  /* @__PURE__ */ m("span", {
135
135
  className: "w-12 text-sm font-medium",
136
136
  children: [e, " star"]
137
137
  }),
138
138
  /* @__PURE__ */ p("div", {
139
- className: "flex-1 h-3 overflow-hidden rounded-full bg-muted",
139
+ className: "flex-1 h-3 overflow-hidden rounded-full bg-bg-sunken",
140
140
  children: /* @__PURE__ */ p("div", {
141
- className: "h-3 rounded-full bg-yellow-400 transition-all",
141
+ className: "h-3 rounded-full bg-status-warning-text transition-all",
142
142
  style: { width: `${n}%` }
143
143
  })
144
144
  }),
145
145
  /* @__PURE__ */ m("span", {
146
- className: "w-16 text-right text-sm text-muted-foreground",
146
+ className: "w-16 text-right text-sm text-text-secondary",
147
147
  children: [
148
148
  t,
149
149
  " (",
@@ -162,13 +162,13 @@ function S() {
162
162
  className: "flex rounded-lg border",
163
163
  children: ["received", "given"].map((e) => /* @__PURE__ */ p("button", {
164
164
  onClick: () => w(e),
165
- className: `px-4 py-2 text-sm font-medium transition-colors ${C === e ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted/50"}`,
165
+ className: `px-4 py-2 text-sm font-medium transition-colors ${C === e ? "bg-action-primary-bg text-action-primary-text" : "text-text-secondary hover:bg-bg-sunken/50"}`,
166
166
  children: e === "received" ? "Reviews Received" : "Reviews Given"
167
167
  }, e))
168
168
  }),
169
169
  /* @__PURE__ */ m("div", {
170
170
  className: "relative flex-1",
171
- children: [/* @__PURE__ */ p(c, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), /* @__PURE__ */ p(x, {
171
+ children: [/* @__PURE__ */ p(c, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ p(x, {
172
172
  placeholder: "Search reviews...",
173
173
  value: T,
174
174
  onChange: (e) => E(e.target.value),
@@ -177,7 +177,7 @@ function S() {
177
177
  }),
178
178
  /* @__PURE__ */ m("div", {
179
179
  className: "flex items-center gap-2",
180
- children: [/* @__PURE__ */ p(o, { className: "h-4 w-4 text-muted-foreground" }), [
180
+ children: [/* @__PURE__ */ p(o, { className: "h-4 w-4 text-text-secondary" }), [
181
181
  {
182
182
  field: "date",
183
183
  label: "Newest"
@@ -192,7 +192,7 @@ function S() {
192
192
  }
193
193
  ].map(({ field: e, label: t }) => /* @__PURE__ */ m("button", {
194
194
  onClick: () => A(e),
195
- className: `flex items-center gap-1 rounded border px-3 py-1 text-xs ${k === e ? "border-primary bg-primary/5 text-primary" : "text-muted-foreground hover:bg-muted/50"}`,
195
+ className: `flex items-center gap-1 rounded border px-3 py-1 text-xs ${k === e ? "border-primary bg-action-primary-bg/5 text-primary" : "text-text-secondary hover:bg-bg-sunken/50"}`,
196
196
  children: [/* @__PURE__ */ p(r, { className: "h-3 w-3" }), t]
197
197
  }, e))]
198
198
  })
@@ -201,7 +201,7 @@ function S() {
201
201
  /* @__PURE__ */ p("div", {
202
202
  className: "space-y-4",
203
203
  children: R.length === 0 ? /* @__PURE__ */ p(_, { children: /* @__PURE__ */ p(v, {
204
- className: "py-12 text-center text-muted-foreground",
204
+ className: "py-12 text-center text-text-secondary",
205
205
  children: "No reviews match your filters."
206
206
  }) }) : R.map((e) => /* @__PURE__ */ p(_, { children: /* @__PURE__ */ p(v, {
207
207
  className: "pt-6",
@@ -213,13 +213,13 @@ function S() {
213
213
  /* @__PURE__ */ m("div", {
214
214
  className: "flex items-center gap-3",
215
215
  children: [/* @__PURE__ */ p("div", {
216
- className: "flex h-10 w-10 items-center justify-center rounded-full bg-primary/10 font-semibold text-primary",
216
+ className: "flex h-10 w-10 items-center justify-center rounded-full bg-accent-soft font-semibold text-text-primary",
217
217
  children: e.clientName.charAt(0)
218
218
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
219
219
  className: "font-medium",
220
220
  children: e.clientName
221
221
  }), /* @__PURE__ */ m("p", {
222
- className: "text-xs text-muted-foreground",
222
+ className: "text-xs text-text-secondary",
223
223
  children: [
224
224
  e.serviceName,
225
225
  " - ",
@@ -246,11 +246,11 @@ function S() {
246
246
  ]
247
247
  }),
248
248
  /* @__PURE__ */ p("p", {
249
- className: "text-sm text-muted-foreground leading-relaxed",
249
+ className: "text-sm text-text-secondary leading-relaxed",
250
250
  children: e.comment
251
251
  }),
252
252
  /* @__PURE__ */ m("div", {
253
- className: "flex flex-wrap gap-4 text-xs text-muted-foreground",
253
+ className: "flex flex-wrap gap-4 text-xs text-text-secondary",
254
254
  children: [
255
255
  /* @__PURE__ */ m("span", { children: ["Project Value: $", e.projectValue.toLocaleString()] }),
256
256
  /* @__PURE__ */ m("span", { children: [
@@ -265,10 +265,10 @@ function S() {
265
265
  }), /* @__PURE__ */ m("div", {
266
266
  className: "flex items-center gap-4 text-sm",
267
267
  children: [/* @__PURE__ */ m("button", {
268
- className: "flex items-center gap-1 text-muted-foreground hover:text-green-600",
268
+ className: "flex items-center gap-1 text-text-secondary hover:text-status-success-text",
269
269
  children: [/* @__PURE__ */ p(d, { className: "h-4 w-4" }), /* @__PURE__ */ p("span", { children: e.helpful })]
270
270
  }), /* @__PURE__ */ m("button", {
271
- className: "flex items-center gap-1 text-muted-foreground hover:text-red-600",
271
+ className: "flex items-center gap-1 text-text-secondary hover:text-status-error-text",
272
272
  children: [/* @__PURE__ */ p(u, { className: "h-4 w-4" }), /* @__PURE__ */ p("span", { children: e.notHelpful })]
273
273
  })]
274
274
  })]
@@ -298,7 +298,7 @@ function S() {
298
298
  }), /* @__PURE__ */ p("div", {
299
299
  className: "flex gap-1",
300
300
  children: Array.from({ length: 5 }, (e, t) => /* @__PURE__ */ p("button", {
301
- className: "text-muted-foreground hover:text-yellow-400",
301
+ className: "text-text-secondary hover:text-status-warning-text",
302
302
  children: /* @__PURE__ */ p(l, { className: "h-8 w-8" })
303
303
  }, t))
304
304
  })]
@@ -309,7 +309,7 @@ function S() {
309
309
  className: "text-sm font-medium",
310
310
  children: "Your Review"
311
311
  }), /* @__PURE__ */ p("textarea", {
312
- className: "w-full rounded-md border bg-background px-3 py-2 text-sm",
312
+ className: "w-full rounded-md border bg-bg-surface px-3 py-2 text-sm",
313
313
  rows: 4,
314
314
  placeholder: "Share your experience with this service..."
315
315
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"ReviewsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ReviewsPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Star,\n Search,\n ThumbsUp,\n ThumbsDown,\n Filter,\n ArrowUpDown,\n MessageSquare,\n TrendingUp,\n Award,\n BarChart3,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\n\ntype ViewMode = 'received' | 'given';\ntype SortBy = 'date' | 'rating' | 'helpful';\n\nexport function ReviewsPage() {\n const { reviews } = useProServiceWorldStore();\n const [viewMode, setViewMode] = useState<ViewMode>('received');\n const [searchQuery, setSearchQuery] = useState('');\n const [ratingFilter, setRatingFilter] = useState<number | null>(null);\n const [sortBy, setSortBy] = useState<SortBy>('date');\n const [showWriteModal, setShowWriteModal] = useState(false);\n\n // Stats\n const avgRating =\n reviews.length > 0\n ? (reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length).toFixed(1)\n : '0';\n const totalReviews = reviews.length;\n const positiveReviews = reviews.filter((r) => r.rating >= 4).length;\n const fiveStarCount = reviews.filter((r) => r.rating === 5).length;\n\n // Rating distribution\n const ratingDistribution = useMemo(() => {\n const dist: Record<number, number> = { 5: 0, 4: 0, 3: 0, 2: 0, 1: 0 };\n for (const r of reviews) {\n dist[r.rating] = (dist[r.rating] ?? 0) + 1;\n }\n return dist;\n }, [reviews]);\n\n const filtered = useMemo(() => {\n let result = [...reviews];\n\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (r) =>\n r.comment.toLowerCase().includes(q) ||\n r.clientName.toLowerCase().includes(q) ||\n r.serviceName.toLowerCase().includes(q) ||\n r.providerName.toLowerCase().includes(q)\n );\n }\n\n if (ratingFilter !== null) {\n result = result.filter((r) => r.rating === ratingFilter);\n }\n\n result.sort((a, b) => {\n if (sortBy === 'date')\n return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();\n if (sortBy === 'rating') return b.rating - a.rating;\n return b.helpful - a.helpful;\n });\n\n return result;\n }, [reviews, searchQuery, ratingFilter, sortBy]);\n\n const renderStars = (rating: number) => {\n return Array.from({ length: 5 }, (_, i) => (\n <Star\n key={i}\n className={`h-4 w-4 ${i < rating ? 'fill-yellow-400 text-yellow-400' : 'text-muted-foreground/30'}`}\n />\n ));\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Reviews</h1>\n <p className=\"text-sm text-muted-foreground\">\n View and manage your service reviews and ratings.\n </p>\n </div>\n <Button size=\"sm\" onClick={() => setShowWriteModal(true)}>\n <MessageSquare className=\"mr-2 h-4 w-4\" /> Write Review\n </Button>\n </div>\n\n {/* Stats Overview */}\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-yellow-100 p-2 dark:bg-yellow-950\">\n <Star className=\"h-5 w-5 text-yellow-600\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{avgRating}</p>\n <p className=\"text-xs text-muted-foreground\">Average Rating</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-blue-100 p-2 dark:bg-blue-950\">\n <BarChart3 className=\"h-5 w-5 text-blue-600\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{totalReviews}</p>\n <p className=\"text-xs text-muted-foreground\">Total Reviews</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-green-100 p-2 dark:bg-green-950\">\n <TrendingUp className=\"h-5 w-5 text-green-600\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{positiveReviews}</p>\n <p className=\"text-xs text-muted-foreground\">Positive (4-5 Stars)</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-purple-100 p-2 dark:bg-purple-950\">\n <Award className=\"h-5 w-5 text-purple-600\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{fiveStarCount}</p>\n <p className=\"text-xs text-muted-foreground\">5-Star Reviews</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Rating Distribution */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Rating Distribution</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2\">\n {[5, 4, 3, 2, 1].map((star) => {\n const count = ratingDistribution[star] ?? 0;\n const pct = totalReviews > 0 ? Math.round((count / totalReviews) * 100) : 0;\n return (\n <button\n key={star}\n onClick={() => setRatingFilter(ratingFilter === star ? null : star)}\n className={`flex w-full items-center gap-3 rounded px-2 py-1 transition-colors ${\n ratingFilter === star ? 'bg-primary/10' : 'hover:bg-muted/50'\n }`}\n >\n <span className=\"w-12 text-sm font-medium\">{star} star</span>\n <div className=\"flex-1 h-3 overflow-hidden rounded-full bg-muted\">\n <div\n className=\"h-3 rounded-full bg-yellow-400 transition-all\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <span className=\"w-16 text-right text-sm text-muted-foreground\">\n {count} ({pct}%)\n </span>\n </button>\n );\n })}\n </div>\n </CardContent>\n </Card>\n\n {/* View Toggle + Filters */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\n <div className=\"flex rounded-lg border\">\n {(['received', 'given'] as const).map((mode) => (\n <button\n key={mode}\n onClick={() => setViewMode(mode)}\n className={`px-4 py-2 text-sm font-medium transition-colors ${\n viewMode === mode\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted/50'\n }`}\n >\n {mode === 'received' ? 'Reviews Received' : 'Reviews Given'}\n </button>\n ))}\n </div>\n\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n placeholder=\"Search reviews...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n\n <div className=\"flex items-center gap-2\">\n <Filter className=\"h-4 w-4 text-muted-foreground\" />\n {[\n { field: 'date' as SortBy, label: 'Newest' },\n { field: 'rating' as SortBy, label: 'Highest Rated' },\n { field: 'helpful' as SortBy, label: 'Most Helpful' },\n ].map(({ field, label }) => (\n <button\n key={field}\n onClick={() => setSortBy(field)}\n className={`flex items-center gap-1 rounded border px-3 py-1 text-xs ${\n sortBy === field\n ? 'border-primary bg-primary/5 text-primary'\n : 'text-muted-foreground hover:bg-muted/50'\n }`}\n >\n <ArrowUpDown className=\"h-3 w-3\" />\n {label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Review List */}\n <div className=\"space-y-4\">\n {filtered.length === 0 ? (\n <Card>\n <CardContent className=\"py-12 text-center text-muted-foreground\">\n No reviews match your filters.\n </CardContent>\n </Card>\n ) : (\n filtered.map((review) => (\n <Card key={review.id}>\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex-1 space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-primary/10 font-semibold text-primary\">\n {review.clientName.charAt(0)}\n </div>\n <div>\n <p className=\"font-medium\">{review.clientName}</p>\n <p className=\"text-xs text-muted-foreground\">\n {review.serviceName} - {review.providerName}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <div className=\"flex\">{renderStars(review.rating)}</div>\n <span className=\"text-sm font-medium\">{review.rating}.0</span>\n {review.recommended && (\n <Badge variant=\"secondary\" className=\"text-xs\">\n Recommended\n </Badge>\n )}\n </div>\n\n <p className=\"text-sm text-muted-foreground leading-relaxed\">\n {review.comment}\n </p>\n\n <div className=\"flex flex-wrap gap-4 text-xs text-muted-foreground\">\n <span>Project Value: ${review.projectValue.toLocaleString()}</span>\n <span>Duration: {review.projectDuration} days</span>\n <span>{new Date(review.createdAt).toLocaleDateString()}</span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-4 text-sm\">\n <button className=\"flex items-center gap-1 text-muted-foreground hover:text-green-600\">\n <ThumbsUp className=\"h-4 w-4\" />\n <span>{review.helpful}</span>\n </button>\n <button className=\"flex items-center gap-1 text-muted-foreground hover:text-red-600\">\n <ThumbsDown className=\"h-4 w-4\" />\n <span>{review.notHelpful}</span>\n </button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))\n )}\n </div>\n\n {/* Write Review Modal */}\n {showWriteModal && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\n <Card className=\"mx-4 w-full max-w-lg\">\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle>Write a Review</CardTitle>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowWriteModal(false)}>\n Close\n </Button>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Rating</label>\n <div className=\"flex gap-1\">\n {Array.from({ length: 5 }, (_, i) => (\n <button key={i} className=\"text-muted-foreground hover:text-yellow-400\">\n <Star className=\"h-8 w-8\" />\n </button>\n ))}\n </div>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Your Review</label>\n <textarea\n className=\"w-full rounded-md border bg-background px-3 py-2 text-sm\"\n rows={4}\n placeholder=\"Share your experience with this service...\"\n />\n </div>\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n className=\"flex-1\"\n onClick={() => setShowWriteModal(false)}\n >\n Cancel\n </Button>\n <Button className=\"flex-1\">Submit Review</Button>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ReviewsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ReviewsPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Star,\n Search,\n ThumbsUp,\n ThumbsDown,\n Filter,\n ArrowUpDown,\n MessageSquare,\n TrendingUp,\n Award,\n BarChart3,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\n\ntype ViewMode = 'received' | 'given';\ntype SortBy = 'date' | 'rating' | 'helpful';\n\nexport function ReviewsPage() {\n const { reviews } = useProServiceWorldStore();\n const [viewMode, setViewMode] = useState<ViewMode>('received');\n const [searchQuery, setSearchQuery] = useState('');\n const [ratingFilter, setRatingFilter] = useState<number | null>(null);\n const [sortBy, setSortBy] = useState<SortBy>('date');\n const [showWriteModal, setShowWriteModal] = useState(false);\n\n // Stats\n const avgRating =\n reviews.length > 0\n ? (reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length).toFixed(1)\n : '0';\n const totalReviews = reviews.length;\n const positiveReviews = reviews.filter((r) => r.rating >= 4).length;\n const fiveStarCount = reviews.filter((r) => r.rating === 5).length;\n\n // Rating distribution\n const ratingDistribution = useMemo(() => {\n const dist: Record<number, number> = { 5: 0, 4: 0, 3: 0, 2: 0, 1: 0 };\n for (const r of reviews) {\n dist[r.rating] = (dist[r.rating] ?? 0) + 1;\n }\n return dist;\n }, [reviews]);\n\n const filtered = useMemo(() => {\n let result = [...reviews];\n\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (r) =>\n r.comment.toLowerCase().includes(q) ||\n r.clientName.toLowerCase().includes(q) ||\n r.serviceName.toLowerCase().includes(q) ||\n r.providerName.toLowerCase().includes(q)\n );\n }\n\n if (ratingFilter !== null) {\n result = result.filter((r) => r.rating === ratingFilter);\n }\n\n result.sort((a, b) => {\n if (sortBy === 'date')\n return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();\n if (sortBy === 'rating') return b.rating - a.rating;\n return b.helpful - a.helpful;\n });\n\n return result;\n }, [reviews, searchQuery, ratingFilter, sortBy]);\n\n const renderStars = (rating: number) => {\n return Array.from({ length: 5 }, (_, i) => (\n <Star\n key={i}\n className={`h-4 w-4 ${i < rating ? 'fill-status-warning-text text-status-warning-text' : 'text-text-secondary/30'}`}\n />\n ));\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Reviews</h1>\n <p className=\"text-sm text-text-secondary\">\n View and manage your service reviews and ratings.\n </p>\n </div>\n <Button size=\"sm\" onClick={() => setShowWriteModal(true)}>\n <MessageSquare className=\"mr-2 h-4 w-4\" /> Write Review\n </Button>\n </div>\n\n {/* Stats Overview */}\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-warning-bg-subtle p-2\">\n <Star className=\"h-5 w-5 text-status-warning-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{avgRating}</p>\n <p className=\"text-xs text-text-secondary\">Average Rating</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-info-bg-subtle p-2\">\n <BarChart3 className=\"h-5 w-5 text-accent-blue\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{totalReviews}</p>\n <p className=\"text-xs text-text-secondary\">Total Reviews</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-success-bg-subtle p-2\">\n <TrendingUp className=\"h-5 w-5 text-status-success-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{positiveReviews}</p>\n <p className=\"text-xs text-text-secondary\">Positive (4-5 Stars)</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-accent-purple-subtle p-2\">\n <Award className=\"h-5 w-5 text-accent-purple\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{fiveStarCount}</p>\n <p className=\"text-xs text-text-secondary\">5-Star Reviews</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Rating Distribution */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Rating Distribution</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2\">\n {[5, 4, 3, 2, 1].map((star) => {\n const count = ratingDistribution[star] ?? 0;\n const pct = totalReviews > 0 ? Math.round((count / totalReviews) * 100) : 0;\n return (\n <button\n key={star}\n onClick={() => setRatingFilter(ratingFilter === star ? null : star)}\n className={`flex w-full items-center gap-3 rounded px-2 py-1 transition-colors ${\n ratingFilter === star ? 'bg-action-primary-bg/10' : 'hover:bg-bg-sunken/50'\n }`}\n >\n <span className=\"w-12 text-sm font-medium\">{star} star</span>\n <div className=\"flex-1 h-3 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-3 rounded-full bg-status-warning-text transition-all\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <span className=\"w-16 text-right text-sm text-text-secondary\">\n {count} ({pct}%)\n </span>\n </button>\n );\n })}\n </div>\n </CardContent>\n </Card>\n\n {/* View Toggle + Filters */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\n <div className=\"flex rounded-lg border\">\n {(['received', 'given'] as const).map((mode) => (\n <button\n key={mode}\n onClick={() => setViewMode(mode)}\n className={`px-4 py-2 text-sm font-medium transition-colors ${\n viewMode === mode\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken/50'\n }`}\n >\n {mode === 'received' ? 'Reviews Received' : 'Reviews Given'}\n </button>\n ))}\n </div>\n\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search reviews...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n\n <div className=\"flex items-center gap-2\">\n <Filter className=\"h-4 w-4 text-text-secondary\" />\n {[\n { field: 'date' as SortBy, label: 'Newest' },\n { field: 'rating' as SortBy, label: 'Highest Rated' },\n { field: 'helpful' as SortBy, label: 'Most Helpful' },\n ].map(({ field, label }) => (\n <button\n key={field}\n onClick={() => setSortBy(field)}\n className={`flex items-center gap-1 rounded border px-3 py-1 text-xs ${\n sortBy === field\n ? 'border-primary bg-action-primary-bg/5 text-primary'\n : 'text-text-secondary hover:bg-bg-sunken/50'\n }`}\n >\n <ArrowUpDown className=\"h-3 w-3\" />\n {label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Review List */}\n <div className=\"space-y-4\">\n {filtered.length === 0 ? (\n <Card>\n <CardContent className=\"py-12 text-center text-text-secondary\">\n No reviews match your filters.\n </CardContent>\n </Card>\n ) : (\n filtered.map((review) => (\n <Card key={review.id}>\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex-1 space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-accent-soft font-semibold text-text-primary\">\n {review.clientName.charAt(0)}\n </div>\n <div>\n <p className=\"font-medium\">{review.clientName}</p>\n <p className=\"text-xs text-text-secondary\">\n {review.serviceName} - {review.providerName}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <div className=\"flex\">{renderStars(review.rating)}</div>\n <span className=\"text-sm font-medium\">{review.rating}.0</span>\n {review.recommended && (\n <Badge variant=\"secondary\" className=\"text-xs\">\n Recommended\n </Badge>\n )}\n </div>\n\n <p className=\"text-sm text-text-secondary leading-relaxed\">\n {review.comment}\n </p>\n\n <div className=\"flex flex-wrap gap-4 text-xs text-text-secondary\">\n <span>Project Value: ${review.projectValue.toLocaleString()}</span>\n <span>Duration: {review.projectDuration} days</span>\n <span>{new Date(review.createdAt).toLocaleDateString()}</span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-4 text-sm\">\n <button className=\"flex items-center gap-1 text-text-secondary hover:text-status-success-text\">\n <ThumbsUp className=\"h-4 w-4\" />\n <span>{review.helpful}</span>\n </button>\n <button className=\"flex items-center gap-1 text-text-secondary hover:text-status-error-text\">\n <ThumbsDown className=\"h-4 w-4\" />\n <span>{review.notHelpful}</span>\n </button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))\n )}\n </div>\n\n {/* Write Review Modal */}\n {showWriteModal && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\n <Card className=\"mx-4 w-full max-w-lg\">\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle>Write a Review</CardTitle>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowWriteModal(false)}>\n Close\n </Button>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Rating</label>\n <div className=\"flex gap-1\">\n {Array.from({ length: 5 }, (_, i) => (\n <button key={i} className=\"text-text-secondary hover:text-status-warning-text\">\n <Star className=\"h-8 w-8\" />\n </button>\n ))}\n </div>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Your Review</label>\n <textarea\n className=\"w-full rounded-md border bg-bg-surface px-3 py-2 text-sm\"\n rows={4}\n placeholder=\"Share your experience with this service...\"\n />\n </div>\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n className=\"flex-1\"\n onClick={() => setShowWriteModal(false)}\n >\n Cancel\n </Button>\n <Button className=\"flex-1\">Submit Review</Button>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}