@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":"ProjectsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ProjectsPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n GlassCard,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Search,\n Plus,\n Calendar,\n DollarSign,\n Users,\n CheckCircle2,\n Clock,\n AlertTriangle,\n Target,\n Tag,\n ChevronRight,\n BarChart3,\n Flag,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\nimport type { ProjectStatus, Priority } from '../types';\n\ntype DetailTab = 'overview' | 'timeline' | 'milestones' | 'team';\n\nconst statusConfig: Record<ProjectStatus, { label: string; color: string; dot: string }> = {\n planning: { label: 'Planning', color: 'text-status-warning-text', dot: 'bg-status-warning-text' },\n active: { label: 'Active', color: 'text-accent-blue', dot: 'bg-accent-blue' },\n on_hold: { label: 'On Hold', color: 'text-status-warning-text', dot: 'bg-status-warning-text' },\n completed: {\n label: 'Completed',\n color: 'text-status-success-text',\n dot: 'bg-status-success-text',\n },\n cancelled: { label: 'Cancelled', color: 'text-status-error-text', dot: 'bg-status-error-text' },\n};\n\nconst priorityConfig: Record<\n Priority,\n { label: string; variant: 'default' | 'secondary' | 'outline' | 'destructive' }\n> = {\n low: { label: 'Low', variant: 'outline' },\n medium: { label: 'Medium', variant: 'secondary' },\n high: { label: 'High', variant: 'default' },\n critical: { label: 'Critical', variant: 'destructive' },\n};\n\nconst milestoneStatusDot: Record<string, string> = {\n completed: 'bg-status-success-text',\n in_progress: 'bg-accent-blue',\n pending: 'bg-bg-sunken',\n overdue: 'bg-status-error-text',\n};\n\nconst milestoneStatusColor: Record<string, string> = {\n completed: 'text-status-success-text',\n in_progress: 'text-accent-blue',\n pending: 'text-text-secondary',\n overdue: 'text-status-error-text',\n};\n\nexport function ProjectsPage() {\n const { projects } = useProServiceWorldStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState<ProjectStatus | 'all'>('all');\n const [selectedProjectId, setSelectedProjectId] = useState<string>(projects[0]?.id ?? '');\n const [detailTab, setDetailTab] = useState<DetailTab>('overview');\n\n const filteredProjects = useMemo(() => {\n let result = [...projects];\n if (statusFilter !== 'all') result = result.filter((p) => p.status === statusFilter);\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (p) => p.title.toLowerCase().includes(q) || p.category.toLowerCase().includes(q)\n );\n }\n return result;\n }, [projects, statusFilter, searchQuery]);\n\n const selectedProject = projects.find((p) => p.id === selectedProjectId);\n\n const detailTabs: { key: DetailTab; label: string }[] = [\n { key: 'overview', label: 'Overview' },\n { key: 'timeline', label: 'Timeline' },\n { key: 'milestones', label: 'Milestones' },\n { key: 'team', label: 'Team' },\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 page. */}\n <div className=\"relative overflow-hidden rounded-card -mx-2 px-2 pt-1\">\n <AuroraBackground intensity=\"subtle\" />\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 tracking-tight\">\n <GradientText>Projects</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Track progress and manage your professional service projects.\n </p>\n </div>\n <Button size=\"sm\">\n <Plus className=\"mr-2 h-4 w-4\" /> New Project\n </Button>\n </div>\n </div>\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Project sidebar */}\n <div className=\"space-y-4\">\n <div className=\"relative\">\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 projects...\"\n aria-label=\"Search projects\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n\n <div className=\"flex flex-wrap gap-1\">\n {(['all', 'active', 'planning', 'completed', 'on_hold', 'cancelled'] as const).map(\n (status) => (\n <button\n key={status}\n onClick={() => setStatusFilter(status)}\n aria-pressed={statusFilter === status}\n className={`rounded px-2 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus ${\n statusFilter === status\n ? 'bg-accent-blue text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n }`}\n >\n {status === 'all' ? 'All' : statusConfig[status].label}\n </button>\n )\n )}\n </div>\n\n <div className=\"space-y-2\">\n {filteredProjects.length === 0 ? (\n <IllustratedEmptyState\n illustration={searchQuery || statusFilter !== 'all' ? 'empty-search' : 'empty-data'}\n title=\"No projects found\"\n description=\"Try adjusting your search or filters.\"\n />\n ) : (\n filteredProjects.map((project) => {\n const cfg = statusConfig[project.status];\n return (\n <button\n key={project.id}\n onClick={() => {\n setSelectedProjectId(project.id);\n setDetailTab('overview');\n }}\n aria-pressed={selectedProjectId === project.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 selectedProjectId === project.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 <h3 className=\"font-medium text-sm truncate pr-2\">{project.title}</h3>\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n </div>\n <div className=\"mt-2 flex items-center gap-2\">\n <Badge variant={priorityConfig[project.priority].variant} className=\"text-xs\">\n {project.priority}\n </Badge>\n <span className={`flex items-center gap-1 text-xs ${cfg.color}`}>\n <span\n className={`h-1.5 w-1.5 rounded-full ${cfg.dot} ${project.status === 'active' ? 'motion-safe:animate-vc-glow-pulse' : ''}`}\n />\n {cfg.label}\n </span>\n </div>\n <div className=\"mt-2\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span>Progress</span>\n <span className=\"tabular-nums\">{project.progress}%</span>\n </div>\n <div className=\"mt-1 h-1.5 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-1.5 rounded-full bg-accent-blue transition-all\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n </div>\n </button>\n );\n })\n )}\n </div>\n </div>\n\n {/* Detail panel */}\n <div className=\"space-y-4 lg:col-span-2\">\n {selectedProject ? (\n <>\n {/* Project header card */}\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n <Badge variant={priorityConfig[selectedProject.priority].variant}>\n {selectedProject.priority} priority\n </Badge>\n <span\n className={`text-sm font-medium ${statusConfig[selectedProject.status].color}`}\n >\n {statusConfig[selectedProject.status].label}\n </span>\n </div>\n <h2 className=\"text-xl font-bold tracking-tight\">{selectedProject.title}</h2>\n <p className=\"text-sm text-text-secondary\">{selectedProject.description}</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-sm text-text-secondary\">Budget</p>\n <p className=\"text-xl font-bold tabular-nums\">\n ${selectedProject.budget.toLocaleString()}\n </p>\n <p className=\"text-xs text-text-secondary tabular-nums\">\n Spent: ${selectedProject.spent.toLocaleString()} (\n {Math.round((selectedProject.spent / selectedProject.budget) * 100)}%)\n </p>\n </div>\n </div>\n\n {/* Progress bar */}\n <div className=\"mt-4\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">Overall Progress</span>\n <span className=\"font-medium tabular-nums\">{selectedProject.progress}%</span>\n </div>\n <div className=\"mt-1 h-3 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-3 rounded-full bg-accent-blue transition-all\"\n style={{ width: `${selectedProject.progress}%` }}\n />\n </div>\n </div>\n\n {/* Quick stats */}\n <div className=\"mt-4 flex flex-wrap gap-4 text-sm\">\n <span className=\"flex items-center gap-1 text-text-secondary\">\n <Calendar className=\"h-4 w-4\" /> {selectedProject.startDate} -{' '}\n {selectedProject.endDate}\n </span>\n <span className=\"flex items-center gap-1 text-text-secondary\">\n <Users className=\"h-4 w-4\" />\n <span className=\"tabular-nums\">{selectedProject.teamMembers.length}</span>{' '}\n members\n </span>\n <span className=\"flex items-center gap-1 text-text-secondary\">\n <Target className=\"h-4 w-4\" />\n <span className=\"tabular-nums\">{selectedProject.milestones.length}</span>{' '}\n milestones\n </span>\n </div>\n\n {/* Tags */}\n {selectedProject.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap items-center gap-2\">\n <Tag className=\"h-4 w-4 text-text-secondary\" />\n {selectedProject.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n )}\n </CardContent>\n </GlassCard>\n\n {/* Detail tabs */}\n <div className=\"flex gap-1 border-b border-border-seam\">\n {detailTabs.map(({ key, label }) => (\n <button\n key={key}\n onClick={() => setDetailTab(key)}\n aria-pressed={detailTab === key}\n className={`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 detailTab === key\n ? 'border-accent-blue text-accent-blue'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n }`}\n >\n {label}\n </button>\n ))}\n </div>\n\n {/* Overview tab */}\n {detailTab === 'overview' && (\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"text-base flex items-center gap-2\">\n <DollarSign className=\"h-4 w-4\" /> Budget Overview\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Total Budget</span>\n <span className=\"font-medium tabular-nums\">\n ${selectedProject.budget.toLocaleString()}\n </span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Spent</span>\n <span className=\"font-medium tabular-nums\">\n ${selectedProject.spent.toLocaleString()}\n </span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Remaining</span>\n <span className=\"font-medium text-status-success-text tabular-nums\">\n ${(selectedProject.budget - selectedProject.spent).toLocaleString()}\n </span>\n </div>\n <div className=\"h-2 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-2 rounded-full bg-accent-blue\"\n style={{\n width: `${Math.round((selectedProject.spent / selectedProject.budget) * 100)}%`,\n }}\n />\n </div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"text-base flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4\" /> Milestone Summary\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {['completed', 'in_progress', 'pending', 'overdue'].map((status) => {\n const count = selectedProject.milestones.filter(\n (m) => m.status === status\n ).length;\n return (\n <div key={status} className=\"flex items-center justify-between text-sm\">\n <span className=\"flex items-center gap-2 text-text-secondary capitalize\">\n <span\n className={`h-1.5 w-1.5 rounded-full ${milestoneStatusDot[status]}`}\n />\n {status.replace('_', ' ')}\n </span>\n <span className=\"font-medium tabular-nums\">{count}</span>\n </div>\n );\n })}\n </CardContent>\n </GlassCard>\n </div>\n )}\n\n {/* Timeline tab */}\n {detailTab === 'timeline' && (\n <Card className=\"border-border-seam\">\n <CardContent className=\"pt-6\">\n <div className=\"relative space-y-0\">\n {selectedProject.milestones.map((milestone, idx) => {\n const isLast = idx === selectedProject.milestones.length - 1;\n return (\n <div key={milestone.id} className=\"relative flex gap-4 pb-8\">\n {/* Timeline line */}\n {!isLast && (\n <div className=\"absolute left-[11px] top-6 h-full w-0.5 bg-border-seam\" />\n )}\n {/* Dot */}\n <div\n className={`relative z-10 mt-1 h-6 w-6 shrink-0 rounded-full ${milestoneStatusDot[milestone.status]} flex items-center justify-center`}\n >\n {milestone.status === 'completed' && (\n <CheckCircle2 className=\"h-4 w-4 text-white\" />\n )}\n {milestone.status === 'in_progress' && (\n <Clock className=\"h-4 w-4 text-white\" />\n )}\n </div>\n {/* Content */}\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <h4 className=\"font-medium\">{milestone.title}</h4>\n <Badge\n variant={priorityConfig[milestone.priority].variant}\n className=\"text-xs\"\n >\n {milestone.priority}\n </Badge>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {milestone.description}\n </p>\n <div className=\"mt-2 flex flex-wrap gap-3 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" /> Due: {milestone.dueDate}\n </span>\n {milestone.completedAt && (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" /> Completed:{' '}\n {milestone.completedAt}\n </span>\n )}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Milestones tab */}\n {detailTab === 'milestones' && (\n <div className=\"space-y-3\">\n {selectedProject.milestones.map((milestone) => {\n const statusIcons: Record<string, typeof CheckCircle2> = {\n completed: CheckCircle2,\n in_progress: Clock,\n pending: Target,\n overdue: AlertTriangle,\n };\n const Icon = statusIcons[milestone.status] ?? Target;\n return (\n <Card key={milestone.id} className=\"border-border-seam\">\n <CardContent className=\"pt-4\">\n <div className=\"flex items-start gap-3\">\n <Icon\n className={`mt-0.5 h-5 w-5 ${milestoneStatusColor[milestone.status]}`}\n />\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <h4 className=\"font-medium\">{milestone.title}</h4>\n <Badge\n variant={priorityConfig[milestone.priority].variant}\n className=\"text-xs\"\n >\n {milestone.priority}\n </Badge>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {milestone.description}\n </p>\n\n {/* Deliverables */}\n {milestone.deliverables.length > 0 && (\n <div className=\"mt-3\">\n <p className=\"text-xs font-medium text-text-secondary\">\n Deliverables\n </p>\n <div className=\"mt-1 flex flex-wrap gap-1\">\n {milestone.deliverables.map((d) => (\n <Badge key={d} variant=\"outline\" className=\"text-xs\">\n {d}\n </Badge>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"mt-3 flex flex-wrap gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" /> Due: {milestone.dueDate}\n </span>\n {milestone.completedAt && (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" /> {milestone.completedAt}\n </span>\n )}\n {milestone.dependencies.length > 0 && (\n <span className=\"flex items-center gap-1\">\n <Flag className=\"h-3 w-3\" />\n <span className=\"tabular-nums\">\n {milestone.dependencies.length}\n </span>{' '}\n dependencies\n </span>\n )}\n </div>\n\n {milestone.notes && (\n <p className=\"mt-2 rounded bg-bg-sunken p-2 text-xs text-text-secondary italic\">\n {milestone.notes}\n </p>\n )}\n </div>\n </div>\n </CardContent>\n </Card>\n );\n })}\n </div>\n )}\n\n {/* Team tab */}\n {detailTab === 'team' && (\n <Card className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"text-base\">Team Members</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {selectedProject.teamMembers.map((member, idx) => (\n <div\n key={idx}\n className=\"flex items-center gap-3 rounded-lg border border-border-seam p-3\"\n >\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-accent-soft font-semibold text-text-primary\">\n {member.name.charAt(0)}\n </div>\n <div>\n <p className=\"font-medium\">{member.name}</p>\n <p className=\"text-sm text-text-secondary\">{member.role}</p>\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n )}\n </>\n ) : (\n <Card className=\"border-border-seam\">\n <CardContent className=\"py-6\">\n <IllustratedEmptyState\n illustration=\"onboarding\"\n title=\"Select a project\"\n description=\"Pick a project from the sidebar to view its details.\"\n />\n </CardContent>\n </Card>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProjectsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ProjectsPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n GlassCard,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n NextSteps,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Search,\n Plus,\n Calendar,\n DollarSign,\n Users,\n CheckCircle2,\n Clock,\n AlertTriangle,\n Target,\n Tag,\n ChevronRight,\n BarChart3,\n Flag,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\nimport type { ProjectStatus, Priority } from '../types';\n\ntype DetailTab = 'overview' | 'timeline' | 'milestones' | 'team';\n\nconst statusConfig: Record<ProjectStatus, { label: string; color: string; dot: string }> = {\n planning: { label: 'Planning', color: 'text-status-warning-text', dot: 'bg-status-warning-text' },\n active: { label: 'Active', color: 'text-accent-blue', dot: 'bg-accent-blue' },\n on_hold: { label: 'On Hold', color: 'text-status-warning-text', dot: 'bg-status-warning-text' },\n completed: {\n label: 'Completed',\n color: 'text-status-success-text',\n dot: 'bg-status-success-text',\n },\n cancelled: { label: 'Cancelled', color: 'text-status-error-text', dot: 'bg-status-error-text' },\n};\n\nconst priorityConfig: Record<\n Priority,\n { label: string; variant: 'default' | 'secondary' | 'outline' | 'destructive' }\n> = {\n low: { label: 'Low', variant: 'outline' },\n medium: { label: 'Medium', variant: 'secondary' },\n high: { label: 'High', variant: 'default' },\n critical: { label: 'Critical', variant: 'destructive' },\n};\n\nconst milestoneStatusDot: Record<string, string> = {\n completed: 'bg-status-success-text',\n in_progress: 'bg-accent-blue',\n pending: 'bg-bg-sunken',\n overdue: 'bg-status-error-text',\n};\n\nconst milestoneStatusColor: Record<string, string> = {\n completed: 'text-status-success-text',\n in_progress: 'text-accent-blue',\n pending: 'text-text-secondary',\n overdue: 'text-status-error-text',\n};\n\nexport function ProjectsPage() {\n const { projects } = useProServiceWorldStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState<ProjectStatus | 'all'>('all');\n const [selectedProjectId, setSelectedProjectId] = useState<string>(projects[0]?.id ?? '');\n const [detailTab, setDetailTab] = useState<DetailTab>('overview');\n\n const filteredProjects = useMemo(() => {\n let result = [...projects];\n if (statusFilter !== 'all') result = result.filter((p) => p.status === statusFilter);\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (p) => p.title.toLowerCase().includes(q) || p.category.toLowerCase().includes(q)\n );\n }\n return result;\n }, [projects, statusFilter, searchQuery]);\n\n const selectedProject = projects.find((p) => p.id === selectedProjectId);\n\n const detailTabs: { key: DetailTab; label: string }[] = [\n { key: 'overview', label: 'Overview' },\n { key: 'timeline', label: 'Timeline' },\n { key: 'milestones', label: 'Milestones' },\n { key: 'team', label: 'Team' },\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 page. */}\n <div className=\"relative overflow-hidden rounded-card -mx-2 px-2 pt-1\">\n <AuroraBackground intensity=\"subtle\" />\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 tracking-tight\">\n <GradientText>Projects</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Track progress and manage your professional service projects.\n </p>\n </div>\n <Button size=\"sm\">\n <Plus className=\"mr-2 h-4 w-4\" /> New Project\n </Button>\n </div>\n </div>\n\n <PagePurpose icon={<Target className=\"h-4 w-4\" />}>\n Run your engagements from kickoff to delivery. Pick a project to see its budget, progress,\n milestones, timeline, and team in one place — so you always know what is on track, what is\n at risk, and what is due next.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"proserviceworld-projects\"\n steps={[\n {\n id: 'timeline',\n label: 'Walk the timeline',\n description: 'See milestones in chronological order to gauge momentum.',\n icon: <Calendar className=\"h-4 w-4\" />,\n onClick: () => setDetailTab('timeline'),\n },\n {\n id: 'milestones',\n label: 'Drill into milestones',\n description: 'Review deliverables, dependencies, and due dates.',\n icon: <Flag className=\"h-4 w-4\" />,\n onClick: () => setDetailTab('milestones'),\n },\n {\n id: 'team',\n label: 'Check the team',\n description: 'See who is assigned and their roles.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => setDetailTab('team'),\n },\n ]}\n />\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Project sidebar */}\n <div className=\"space-y-4\">\n <div className=\"relative\">\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 projects...\"\n aria-label=\"Search projects\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n\n <div className=\"flex flex-wrap gap-1\">\n {(['all', 'active', 'planning', 'completed', 'on_hold', 'cancelled'] as const).map(\n (status) => (\n <button\n key={status}\n onClick={() => setStatusFilter(status)}\n aria-pressed={statusFilter === status}\n className={`rounded px-2 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus ${\n statusFilter === status\n ? 'bg-accent-blue text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n }`}\n >\n {status === 'all' ? 'All' : statusConfig[status].label}\n </button>\n )\n )}\n </div>\n\n <div className=\"space-y-2\">\n {filteredProjects.length === 0 ? (\n <IllustratedEmptyState\n illustration={searchQuery || statusFilter !== 'all' ? 'empty-search' : 'empty-data'}\n title=\"No projects found\"\n description=\"Try adjusting your search or filters.\"\n />\n ) : (\n filteredProjects.map((project) => {\n const cfg = statusConfig[project.status];\n return (\n <button\n key={project.id}\n onClick={() => {\n setSelectedProjectId(project.id);\n setDetailTab('overview');\n }}\n aria-pressed={selectedProjectId === project.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 selectedProjectId === project.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 <h3 className=\"font-medium text-sm truncate pr-2\">{project.title}</h3>\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n </div>\n <div className=\"mt-2 flex items-center gap-2\">\n <Badge variant={priorityConfig[project.priority].variant} className=\"text-xs\">\n {project.priority}\n </Badge>\n <span className={`flex items-center gap-1 text-xs ${cfg.color}`}>\n <span\n className={`h-1.5 w-1.5 rounded-full ${cfg.dot} ${project.status === 'active' ? 'motion-safe:animate-vc-glow-pulse' : ''}`}\n />\n {cfg.label}\n </span>\n </div>\n <div className=\"mt-2\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span>Progress</span>\n <span className=\"tabular-nums\">{project.progress}%</span>\n </div>\n <div className=\"mt-1 h-1.5 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-1.5 rounded-full bg-accent-blue transition-all\"\n style={{ width: `${project.progress}%` }}\n />\n </div>\n </div>\n </button>\n );\n })\n )}\n </div>\n </div>\n\n {/* Detail panel */}\n <div className=\"space-y-4 lg:col-span-2\">\n {selectedProject ? (\n <>\n {/* Project header card */}\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n <Badge variant={priorityConfig[selectedProject.priority].variant}>\n {selectedProject.priority} priority\n </Badge>\n <span\n className={`text-sm font-medium ${statusConfig[selectedProject.status].color}`}\n >\n {statusConfig[selectedProject.status].label}\n </span>\n </div>\n <h2 className=\"text-xl font-bold tracking-tight\">{selectedProject.title}</h2>\n <p className=\"text-sm text-text-secondary\">{selectedProject.description}</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-sm text-text-secondary\">Budget</p>\n <p className=\"text-xl font-bold tabular-nums\">\n ${selectedProject.budget.toLocaleString()}\n </p>\n <p className=\"text-xs text-text-secondary tabular-nums\">\n Spent: ${selectedProject.spent.toLocaleString()} (\n {Math.round((selectedProject.spent / selectedProject.budget) * 100)}%)\n </p>\n </div>\n </div>\n\n {/* Progress bar */}\n <div className=\"mt-4\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">Overall Progress</span>\n <span className=\"font-medium tabular-nums\">{selectedProject.progress}%</span>\n </div>\n <div className=\"mt-1 h-3 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-3 rounded-full bg-accent-blue transition-all\"\n style={{ width: `${selectedProject.progress}%` }}\n />\n </div>\n </div>\n\n {/* Quick stats */}\n <div className=\"mt-4 flex flex-wrap gap-4 text-sm\">\n <span className=\"flex items-center gap-1 text-text-secondary\">\n <Calendar className=\"h-4 w-4\" /> {selectedProject.startDate} -{' '}\n {selectedProject.endDate}\n </span>\n <span className=\"flex items-center gap-1 text-text-secondary\">\n <Users className=\"h-4 w-4\" />\n <span className=\"tabular-nums\">{selectedProject.teamMembers.length}</span>{' '}\n members\n </span>\n <span className=\"flex items-center gap-1 text-text-secondary\">\n <Target className=\"h-4 w-4\" />\n <span className=\"tabular-nums\">{selectedProject.milestones.length}</span>{' '}\n milestones\n </span>\n </div>\n\n {/* Tags */}\n {selectedProject.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap items-center gap-2\">\n <Tag className=\"h-4 w-4 text-text-secondary\" />\n {selectedProject.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n )}\n </CardContent>\n </GlassCard>\n\n {/* Detail tabs */}\n <div className=\"flex gap-1 border-b border-border-seam\">\n {detailTabs.map(({ key, label }) => (\n <button\n key={key}\n onClick={() => setDetailTab(key)}\n aria-pressed={detailTab === key}\n className={`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 detailTab === key\n ? 'border-accent-blue text-accent-blue'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n }`}\n >\n {label}\n </button>\n ))}\n </div>\n\n {/* Overview tab */}\n {detailTab === 'overview' && (\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"text-base flex items-center gap-2\">\n <DollarSign className=\"h-4 w-4\" /> Budget Overview\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Total Budget</span>\n <span className=\"font-medium tabular-nums\">\n ${selectedProject.budget.toLocaleString()}\n </span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Spent</span>\n <span className=\"font-medium tabular-nums\">\n ${selectedProject.spent.toLocaleString()}\n </span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Remaining</span>\n <span className=\"font-medium text-status-success-text tabular-nums\">\n ${(selectedProject.budget - selectedProject.spent).toLocaleString()}\n </span>\n </div>\n <div className=\"h-2 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-2 rounded-full bg-accent-blue\"\n style={{\n width: `${Math.round((selectedProject.spent / selectedProject.budget) * 100)}%`,\n }}\n />\n </div>\n </CardContent>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"text-base flex items-center gap-2\">\n <BarChart3 className=\"h-4 w-4\" /> Milestone Summary\n </CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n {['completed', 'in_progress', 'pending', 'overdue'].map((status) => {\n const count = selectedProject.milestones.filter(\n (m) => m.status === status\n ).length;\n return (\n <div key={status} className=\"flex items-center justify-between text-sm\">\n <span className=\"flex items-center gap-2 text-text-secondary capitalize\">\n <span\n className={`h-1.5 w-1.5 rounded-full ${milestoneStatusDot[status]}`}\n />\n {status.replace('_', ' ')}\n </span>\n <span className=\"font-medium tabular-nums\">{count}</span>\n </div>\n );\n })}\n </CardContent>\n </GlassCard>\n </div>\n )}\n\n {/* Timeline tab */}\n {detailTab === 'timeline' && (\n <Card className=\"border-border-seam\">\n <CardContent className=\"pt-6\">\n <div className=\"relative space-y-0\">\n {selectedProject.milestones.map((milestone, idx) => {\n const isLast = idx === selectedProject.milestones.length - 1;\n return (\n <div key={milestone.id} className=\"relative flex gap-4 pb-8\">\n {/* Timeline line */}\n {!isLast && (\n <div className=\"absolute left-[11px] top-6 h-full w-0.5 bg-border-seam\" />\n )}\n {/* Dot */}\n <div\n className={`relative z-10 mt-1 h-6 w-6 shrink-0 rounded-full ${milestoneStatusDot[milestone.status]} flex items-center justify-center`}\n >\n {milestone.status === 'completed' && (\n <CheckCircle2 className=\"h-4 w-4 text-white\" />\n )}\n {milestone.status === 'in_progress' && (\n <Clock className=\"h-4 w-4 text-white\" />\n )}\n </div>\n {/* Content */}\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <h4 className=\"font-medium\">{milestone.title}</h4>\n <Badge\n variant={priorityConfig[milestone.priority].variant}\n className=\"text-xs\"\n >\n {milestone.priority}\n </Badge>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {milestone.description}\n </p>\n <div className=\"mt-2 flex flex-wrap gap-3 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" /> Due: {milestone.dueDate}\n </span>\n {milestone.completedAt && (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" /> Completed:{' '}\n {milestone.completedAt}\n </span>\n )}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n </CardContent>\n </Card>\n )}\n\n {/* Milestones tab */}\n {detailTab === 'milestones' && (\n <div className=\"space-y-3\">\n {selectedProject.milestones.map((milestone) => {\n const statusIcons: Record<string, typeof CheckCircle2> = {\n completed: CheckCircle2,\n in_progress: Clock,\n pending: Target,\n overdue: AlertTriangle,\n };\n const Icon = statusIcons[milestone.status] ?? Target;\n return (\n <Card key={milestone.id} className=\"border-border-seam\">\n <CardContent className=\"pt-4\">\n <div className=\"flex items-start gap-3\">\n <Icon\n className={`mt-0.5 h-5 w-5 ${milestoneStatusColor[milestone.status]}`}\n />\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <h4 className=\"font-medium\">{milestone.title}</h4>\n <Badge\n variant={priorityConfig[milestone.priority].variant}\n className=\"text-xs\"\n >\n {milestone.priority}\n </Badge>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {milestone.description}\n </p>\n\n {/* Deliverables */}\n {milestone.deliverables.length > 0 && (\n <div className=\"mt-3\">\n <p className=\"text-xs font-medium text-text-secondary\">\n Deliverables\n </p>\n <div className=\"mt-1 flex flex-wrap gap-1\">\n {milestone.deliverables.map((d) => (\n <Badge key={d} variant=\"outline\" className=\"text-xs\">\n {d}\n </Badge>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"mt-3 flex flex-wrap gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" /> Due: {milestone.dueDate}\n </span>\n {milestone.completedAt && (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" /> {milestone.completedAt}\n </span>\n )}\n {milestone.dependencies.length > 0 && (\n <span className=\"flex items-center gap-1\">\n <Flag className=\"h-3 w-3\" />\n <span className=\"tabular-nums\">\n {milestone.dependencies.length}\n </span>{' '}\n dependencies\n </span>\n )}\n </div>\n\n {milestone.notes && (\n <p className=\"mt-2 rounded bg-bg-sunken p-2 text-xs text-text-secondary italic\">\n {milestone.notes}\n </p>\n )}\n </div>\n </div>\n </CardContent>\n </Card>\n );\n })}\n </div>\n )}\n\n {/* Team tab */}\n {detailTab === 'team' && (\n <Card className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"text-base\">Team Members</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {selectedProject.teamMembers.map((member, idx) => (\n <div\n key={idx}\n className=\"flex items-center gap-3 rounded-lg border border-border-seam p-3\"\n >\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-accent-soft font-semibold text-text-primary\">\n {member.name.charAt(0)}\n </div>\n <div>\n <p className=\"font-medium\">{member.name}</p>\n <p className=\"text-sm text-text-secondary\">{member.role}</p>\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n )}\n </>\n ) : (\n <Card className=\"border-border-seam\">\n <CardContent className=\"py-6\">\n <IllustratedEmptyState\n illustration=\"onboarding\"\n title=\"Select a project\"\n description=\"Pick a project from the sidebar to view its details.\"\n />\n </CardContent>\n </Card>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -2,26 +2,56 @@ import { useProServiceWorldStore as e } from "../store/proserviceworldStore.js";
|
|
|
2
2
|
import { useState as t } from "react";
|
|
3
3
|
import { Award as n, Briefcase as r, Calendar as i, CheckCircle as a, MapPin as o, MessageSquare as s, Share2 as c, Star as l, Users as u } from "lucide-react";
|
|
4
4
|
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
5
|
-
import { Badge as p, Button as m, CTAOverflowMenu as h, Card as g, CardContent as _, CardHeader as v, CardTitle as y, EmphasisPanel as b, GlassCard as x, IllustratedEmptyState as S } from "@burdenoff/fe-libs/ui";
|
|
5
|
+
import { Badge as p, Button as m, CTAOverflowMenu as h, Card as g, CardContent as _, CardHeader as v, CardTitle as y, EmphasisPanel as b, GlassCard as x, IllustratedEmptyState as S, NextSteps as C, PagePurpose as w } from "@burdenoff/fe-libs/ui";
|
|
6
6
|
//#region src/proserviceworld/pages/ProviderDetailPage.tsx
|
|
7
|
-
function
|
|
8
|
-
let { providers:
|
|
7
|
+
function T() {
|
|
8
|
+
let { providers: T, services: E, reviews: D } = e(), [O, k] = t("overview"), A = T[0], j = E.filter((e) => e.providerId === A.id), M = D.filter((e) => e.providerName === A.name), N = [
|
|
9
9
|
{
|
|
10
10
|
id: "overview",
|
|
11
11
|
label: "Overview"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
id: "services",
|
|
15
|
-
label: `Services (${
|
|
15
|
+
label: `Services (${j.length})`
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
id: "reviews",
|
|
19
|
-
label: `Reviews (${
|
|
19
|
+
label: `Reviews (${M.length})`
|
|
20
20
|
}
|
|
21
21
|
];
|
|
22
22
|
return /* @__PURE__ */ f("div", {
|
|
23
23
|
className: "space-y-6 p-6 bg-bg-canvas min-h-screen",
|
|
24
24
|
children: [
|
|
25
|
+
/* @__PURE__ */ d(w, {
|
|
26
|
+
icon: /* @__PURE__ */ d(r, { className: "h-4 w-4" }),
|
|
27
|
+
children: "A full picture of this provider before you engage. Review their background, specializations, certifications, and ratings, browse the services they offer, and read client reviews — then contact them or book a consultation with confidence."
|
|
28
|
+
}),
|
|
29
|
+
/* @__PURE__ */ d(C, {
|
|
30
|
+
storageKey: "proserviceworld-provider-detail",
|
|
31
|
+
steps: [
|
|
32
|
+
{
|
|
33
|
+
id: "services",
|
|
34
|
+
label: "Browse their services",
|
|
35
|
+
description: "See what this provider offers and starting prices.",
|
|
36
|
+
icon: /* @__PURE__ */ d(r, { className: "h-4 w-4" }),
|
|
37
|
+
onClick: () => k("services")
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "reviews",
|
|
41
|
+
label: "Read client reviews",
|
|
42
|
+
description: "Check ratings and feedback from past clients.",
|
|
43
|
+
icon: /* @__PURE__ */ d(l, { className: "h-4 w-4" }),
|
|
44
|
+
onClick: () => k("reviews")
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "contact",
|
|
48
|
+
label: "Contact the provider",
|
|
49
|
+
description: "Start a conversation or book a consultation.",
|
|
50
|
+
icon: /* @__PURE__ */ d(s, { className: "h-4 w-4" }),
|
|
51
|
+
onClick: () => k("overview")
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}),
|
|
25
55
|
/* @__PURE__ */ f("div", {
|
|
26
56
|
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
27
57
|
children: [/* @__PURE__ */ d("div", {
|
|
@@ -34,7 +64,7 @@ function C() {
|
|
|
34
64
|
className: "h-20 w-20 rounded-full bg-accent-soft flex items-center justify-center shrink-0",
|
|
35
65
|
children: /* @__PURE__ */ f("span", {
|
|
36
66
|
className: "text-text-primary text-2xl font-bold",
|
|
37
|
-
children: [
|
|
67
|
+
children: [A.name.charAt(0), A.name.split(" ")[1]?.charAt(0)]
|
|
38
68
|
})
|
|
39
69
|
}), /* @__PURE__ */ f("div", {
|
|
40
70
|
className: "flex-1",
|
|
@@ -43,19 +73,19 @@ function C() {
|
|
|
43
73
|
className: "flex items-center gap-3 mb-1",
|
|
44
74
|
children: [/* @__PURE__ */ d("h1", {
|
|
45
75
|
className: "text-2xl font-bold tracking-tight",
|
|
46
|
-
children:
|
|
47
|
-
}),
|
|
76
|
+
children: A.businessName
|
|
77
|
+
}), A.verified && /* @__PURE__ */ f(p, {
|
|
48
78
|
variant: "default",
|
|
49
79
|
children: [/* @__PURE__ */ d(a, { className: "h-3 w-3 mr-1" }), "Verified"]
|
|
50
80
|
})]
|
|
51
81
|
}),
|
|
52
82
|
/* @__PURE__ */ d("p", {
|
|
53
83
|
className: "text-text-secondary mb-2",
|
|
54
|
-
children:
|
|
84
|
+
children: A.name
|
|
55
85
|
}),
|
|
56
86
|
/* @__PURE__ */ d("p", {
|
|
57
87
|
className: "text-sm text-text-secondary mb-4",
|
|
58
|
-
children:
|
|
88
|
+
children: A.tagline
|
|
59
89
|
}),
|
|
60
90
|
/* @__PURE__ */ f("div", {
|
|
61
91
|
className: "flex flex-wrap items-center gap-4 text-sm",
|
|
@@ -66,13 +96,13 @@ function C() {
|
|
|
66
96
|
/* @__PURE__ */ d(l, { className: "h-4 w-4 text-status-warning-text fill-current mr-1" }),
|
|
67
97
|
/* @__PURE__ */ d("span", {
|
|
68
98
|
className: "font-medium tabular-nums",
|
|
69
|
-
children:
|
|
99
|
+
children: A.rating.toFixed(1)
|
|
70
100
|
}),
|
|
71
101
|
/* @__PURE__ */ f("span", {
|
|
72
102
|
className: "text-text-secondary ml-1",
|
|
73
103
|
children: [
|
|
74
104
|
"(",
|
|
75
|
-
|
|
105
|
+
A.totalReviews,
|
|
76
106
|
" reviews)"
|
|
77
107
|
]
|
|
78
108
|
})
|
|
@@ -80,13 +110,13 @@ function C() {
|
|
|
80
110
|
}),
|
|
81
111
|
/* @__PURE__ */ f("div", {
|
|
82
112
|
className: "flex items-center text-text-secondary",
|
|
83
|
-
children: [/* @__PURE__ */ d(o, { className: "h-4 w-4 mr-1" }),
|
|
113
|
+
children: [/* @__PURE__ */ d(o, { className: "h-4 w-4 mr-1" }), A.location]
|
|
84
114
|
}),
|
|
85
115
|
/* @__PURE__ */ f("div", {
|
|
86
116
|
className: "flex items-center text-text-secondary",
|
|
87
117
|
children: [
|
|
88
118
|
/* @__PURE__ */ d(r, { className: "h-4 w-4 mr-1" }),
|
|
89
|
-
|
|
119
|
+
A.yearsExperience,
|
|
90
120
|
" years"
|
|
91
121
|
]
|
|
92
122
|
})
|
|
@@ -109,7 +139,7 @@ function C() {
|
|
|
109
139
|
className: "text-2xl font-bold tabular-nums",
|
|
110
140
|
children: [
|
|
111
141
|
"$",
|
|
112
|
-
|
|
142
|
+
A.hourlyRate,
|
|
113
143
|
"/hr"
|
|
114
144
|
]
|
|
115
145
|
}), /* @__PURE__ */ d("p", {
|
|
@@ -140,7 +170,7 @@ function C() {
|
|
|
140
170
|
className: "text-center p-3 bg-bg-sunken rounded",
|
|
141
171
|
children: [/* @__PURE__ */ f("div", {
|
|
142
172
|
className: "font-semibold tabular-nums",
|
|
143
|
-
children: [
|
|
173
|
+
children: [A.responseTime, "h"]
|
|
144
174
|
}), /* @__PURE__ */ d("div", {
|
|
145
175
|
className: "text-text-secondary",
|
|
146
176
|
children: "Response"
|
|
@@ -150,7 +180,7 @@ function C() {
|
|
|
150
180
|
className: "text-center p-3 bg-bg-sunken rounded",
|
|
151
181
|
children: [/* @__PURE__ */ f("div", {
|
|
152
182
|
className: "font-semibold tabular-nums",
|
|
153
|
-
children: [
|
|
183
|
+
children: [A.completionRate, "%"]
|
|
154
184
|
}), /* @__PURE__ */ d("div", {
|
|
155
185
|
className: "text-text-secondary",
|
|
156
186
|
children: "Completion"
|
|
@@ -160,7 +190,7 @@ function C() {
|
|
|
160
190
|
className: "text-center p-3 bg-bg-sunken rounded",
|
|
161
191
|
children: [/* @__PURE__ */ d("div", {
|
|
162
192
|
className: "font-semibold tabular-nums",
|
|
163
|
-
children:
|
|
193
|
+
children: A.projectsCompleted
|
|
164
194
|
}), /* @__PURE__ */ d("div", {
|
|
165
195
|
className: "text-text-secondary",
|
|
166
196
|
children: "Projects"
|
|
@@ -170,7 +200,7 @@ function C() {
|
|
|
170
200
|
className: "text-center p-3 bg-bg-sunken rounded",
|
|
171
201
|
children: [/* @__PURE__ */ d("div", {
|
|
172
202
|
className: "font-semibold tabular-nums",
|
|
173
|
-
children:
|
|
203
|
+
children: A.activeProjects
|
|
174
204
|
}), /* @__PURE__ */ d("div", {
|
|
175
205
|
className: "text-text-secondary",
|
|
176
206
|
children: "Active"
|
|
@@ -186,15 +216,15 @@ function C() {
|
|
|
186
216
|
className: "border-b border-border-seam",
|
|
187
217
|
children: /* @__PURE__ */ d("nav", {
|
|
188
218
|
className: "-mb-px flex space-x-8",
|
|
189
|
-
children:
|
|
190
|
-
onClick: () =>
|
|
191
|
-
"aria-pressed":
|
|
192
|
-
className: `py-3 px-1 border-b-2 font-medium text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus ${
|
|
219
|
+
children: N.map((e) => /* @__PURE__ */ d("button", {
|
|
220
|
+
onClick: () => k(e.id),
|
|
221
|
+
"aria-pressed": O === e.id,
|
|
222
|
+
className: `py-3 px-1 border-b-2 font-medium text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus ${O === e.id ? "border-accent-blue text-accent-blue" : "border-transparent text-text-secondary hover:text-text-primary"}`,
|
|
193
223
|
children: e.label
|
|
194
224
|
}, e.id))
|
|
195
225
|
})
|
|
196
226
|
}),
|
|
197
|
-
|
|
227
|
+
O === "overview" && /* @__PURE__ */ f("div", {
|
|
198
228
|
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
199
229
|
children: [/* @__PURE__ */ f("div", {
|
|
200
230
|
className: "lg:col-span-2 space-y-6",
|
|
@@ -203,14 +233,14 @@ function C() {
|
|
|
203
233
|
className: "border-border-seam",
|
|
204
234
|
children: [/* @__PURE__ */ d(v, { children: /* @__PURE__ */ d(y, { children: "About" }) }), /* @__PURE__ */ d(_, { children: /* @__PURE__ */ d("p", {
|
|
205
235
|
className: "text-text-secondary",
|
|
206
|
-
children:
|
|
236
|
+
children: A.description
|
|
207
237
|
}) })]
|
|
208
238
|
}),
|
|
209
239
|
/* @__PURE__ */ f(g, {
|
|
210
240
|
className: "border-border-seam",
|
|
211
241
|
children: [/* @__PURE__ */ d(v, { children: /* @__PURE__ */ d(y, { children: "Specializations" }) }), /* @__PURE__ */ d(_, { children: /* @__PURE__ */ d("div", {
|
|
212
242
|
className: "flex flex-wrap gap-2",
|
|
213
|
-
children:
|
|
243
|
+
children: A.specializations.map((e) => /* @__PURE__ */ d(p, {
|
|
214
244
|
variant: "secondary",
|
|
215
245
|
children: e
|
|
216
246
|
}, e))
|
|
@@ -220,7 +250,7 @@ function C() {
|
|
|
220
250
|
className: "border-border-seam",
|
|
221
251
|
children: [/* @__PURE__ */ d(v, { children: /* @__PURE__ */ d(y, { children: "Certifications" }) }), /* @__PURE__ */ d(_, {
|
|
222
252
|
className: "space-y-3",
|
|
223
|
-
children:
|
|
253
|
+
children: A.certifications.map((e) => /* @__PURE__ */ f("div", {
|
|
224
254
|
className: "flex items-center gap-3",
|
|
225
255
|
children: [/* @__PURE__ */ d(n, { className: "h-5 w-5 text-accent-blue" }), /* @__PURE__ */ d("span", { children: e })]
|
|
226
256
|
}, e))
|
|
@@ -239,21 +269,21 @@ function C() {
|
|
|
239
269
|
children: [/* @__PURE__ */ d("span", {
|
|
240
270
|
className: "text-text-secondary",
|
|
241
271
|
children: "Location"
|
|
242
|
-
}), /* @__PURE__ */ d("span", { children:
|
|
272
|
+
}), /* @__PURE__ */ d("span", { children: A.location })]
|
|
243
273
|
}),
|
|
244
274
|
/* @__PURE__ */ f("div", {
|
|
245
275
|
className: "flex justify-between",
|
|
246
276
|
children: [/* @__PURE__ */ d("span", {
|
|
247
277
|
className: "text-text-secondary",
|
|
248
278
|
children: "Languages"
|
|
249
|
-
}), /* @__PURE__ */ d("span", { children:
|
|
279
|
+
}), /* @__PURE__ */ d("span", { children: A.languages.join(", ") })]
|
|
250
280
|
}),
|
|
251
281
|
/* @__PURE__ */ f("div", {
|
|
252
282
|
className: "flex justify-between",
|
|
253
283
|
children: [/* @__PURE__ */ d("span", {
|
|
254
284
|
className: "text-text-secondary",
|
|
255
285
|
children: "Member Since"
|
|
256
|
-
}), /* @__PURE__ */ d("span", { children: new Date(
|
|
286
|
+
}), /* @__PURE__ */ d("span", { children: new Date(A.joinedDate).toLocaleDateString("en-US", {
|
|
257
287
|
month: "short",
|
|
258
288
|
year: "numeric"
|
|
259
289
|
}) })]
|
|
@@ -265,7 +295,7 @@ function C() {
|
|
|
265
295
|
children: "Category"
|
|
266
296
|
}), /* @__PURE__ */ d("span", {
|
|
267
297
|
className: "capitalize",
|
|
268
|
-
children:
|
|
298
|
+
children: A.category.replace("_", " ")
|
|
269
299
|
})]
|
|
270
300
|
})
|
|
271
301
|
]
|
|
@@ -274,7 +304,7 @@ function C() {
|
|
|
274
304
|
className: "border-border-seam",
|
|
275
305
|
children: [/* @__PURE__ */ d(v, { children: /* @__PURE__ */ d(y, { children: "Similar Providers" }) }), /* @__PURE__ */ d(_, {
|
|
276
306
|
className: "space-y-3",
|
|
277
|
-
children:
|
|
307
|
+
children: T.filter((e) => e.id !== A.id).slice(0, 3).map((e) => /* @__PURE__ */ f("div", {
|
|
278
308
|
className: "flex items-center gap-3",
|
|
279
309
|
children: [
|
|
280
310
|
/* @__PURE__ */ d("div", {
|
|
@@ -304,9 +334,9 @@ function C() {
|
|
|
304
334
|
})]
|
|
305
335
|
})]
|
|
306
336
|
}),
|
|
307
|
-
|
|
337
|
+
O === "services" && /* @__PURE__ */ d("div", {
|
|
308
338
|
className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6",
|
|
309
|
-
children:
|
|
339
|
+
children: j.length > 0 ? j.map((e) => /* @__PURE__ */ d(x, {
|
|
310
340
|
treatment: "plain",
|
|
311
341
|
className: "border-border-seam transition-shadow hover:shadow-pop",
|
|
312
342
|
children: /* @__PURE__ */ f(_, {
|
|
@@ -355,7 +385,7 @@ function C() {
|
|
|
355
385
|
})
|
|
356
386
|
})
|
|
357
387
|
}),
|
|
358
|
-
|
|
388
|
+
O === "reviews" && /* @__PURE__ */ f("div", {
|
|
359
389
|
className: "space-y-4",
|
|
360
390
|
children: [/* @__PURE__ */ d(x, {
|
|
361
391
|
treatment: "metric",
|
|
@@ -369,7 +399,7 @@ function C() {
|
|
|
369
399
|
children: [
|
|
370
400
|
/* @__PURE__ */ d("div", {
|
|
371
401
|
className: "text-4xl font-bold tabular-nums",
|
|
372
|
-
children:
|
|
402
|
+
children: A.rating.toFixed(1)
|
|
373
403
|
}),
|
|
374
404
|
/* @__PURE__ */ d("div", {
|
|
375
405
|
className: "flex justify-center mt-1",
|
|
@@ -379,11 +409,11 @@ function C() {
|
|
|
379
409
|
3,
|
|
380
410
|
4,
|
|
381
411
|
5
|
|
382
|
-
].map((e) => /* @__PURE__ */ d(l, { className: `h-4 w-4 ${e <= Math.round(
|
|
412
|
+
].map((e) => /* @__PURE__ */ d(l, { className: `h-4 w-4 ${e <= Math.round(A.rating) ? "text-status-warning-text fill-current" : "text-text-secondary"}` }, e))
|
|
383
413
|
}),
|
|
384
414
|
/* @__PURE__ */ f("p", {
|
|
385
415
|
className: "text-sm text-text-secondary mt-1",
|
|
386
|
-
children: [
|
|
416
|
+
children: [A.totalReviews, " reviews"]
|
|
387
417
|
})
|
|
388
418
|
]
|
|
389
419
|
}), /* @__PURE__ */ d("div", {
|
|
@@ -395,7 +425,7 @@ function C() {
|
|
|
395
425
|
2,
|
|
396
426
|
1
|
|
397
427
|
].map((e) => {
|
|
398
|
-
let t =
|
|
428
|
+
let t = M.filter((t) => Math.round(t.rating) === e).length, n = M.length > 0 ? t / M.length * 100 : 0;
|
|
399
429
|
return /* @__PURE__ */ f("div", {
|
|
400
430
|
className: "flex items-center gap-2",
|
|
401
431
|
children: [
|
|
@@ -421,7 +451,7 @@ function C() {
|
|
|
421
451
|
})]
|
|
422
452
|
})
|
|
423
453
|
})
|
|
424
|
-
}),
|
|
454
|
+
}), M.map((e) => /* @__PURE__ */ d(g, {
|
|
425
455
|
className: "border-border-seam",
|
|
426
456
|
children: /* @__PURE__ */ f(_, {
|
|
427
457
|
className: "p-6",
|
|
@@ -503,6 +533,6 @@ function C() {
|
|
|
503
533
|
});
|
|
504
534
|
}
|
|
505
535
|
//#endregion
|
|
506
|
-
export {
|
|
536
|
+
export { T as ProviderDetailPage };
|
|
507
537
|
|
|
508
538
|
//# sourceMappingURL=ProviderDetailPage.js.map
|