@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":"MessagesPage.js","names":[],"sources":["../../../src/proserviceworld/pages/MessagesPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n Badge,\n Button,\n Input,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Search,\n Send,\n Circle,\n CheckCheck,\n Check,\n MessageSquare,\n Phone,\n Video,\n MoreHorizontal,\n Paperclip,\n Smile,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\nimport { tWithFallback } from '../utils/i18n';\n\nexport function MessagesPage() {\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 { conversations } = useProServiceWorldStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedConversationId, setSelectedConversationId] = useState<string>(\n conversations[0]?.id ?? ''\n );\n const [messageInput, setMessageInput] = useState('');\n\n const filteredConversations = useMemo(() => {\n if (!searchQuery.trim()) return conversations;\n const q = searchQuery.toLowerCase();\n return conversations.filter(\n (c) => c.participantName.toLowerCase().includes(q) || c.lastMessage.toLowerCase().includes(q)\n );\n }, [conversations, searchQuery]);\n\n const selectedConversation = conversations.find((c) => c.id === selectedConversationId);\n const totalUnread = conversations.reduce((sum, c) => sum + c.unreadCount, 0);\n const unreadSummary =\n totalUnread > 0\n ? tr('proserviceworld.messages.subtitle.unread', '{{count}} unread messages', {\n count: totalUnread,\n })\n : tr('proserviceworld.messages.subtitle.caughtUp', 'All caught up');\n\n const formatTime = (timestamp: string) => {\n const date = new Date(timestamp);\n const now = new Date();\n const diffDays = Math.floor((now.getTime() - date.getTime()) / (1000 * 60 * 60 * 24));\n if (diffDays === 0) {\n return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n }\n if (diffDays === 1) return tr('proserviceworld.messages.time.yesterday', 'Yesterday');\n if (diffDays < 7) return date.toLocaleDateString([], { weekday: 'short' });\n return date.toLocaleDateString([], { month: 'short', day: 'numeric' });\n };\n\n return (\n <div className=\"p-6 bg-bg-canvas min-h-screen\">\n <div className=\"relative overflow-hidden rounded-card -mx-2 px-2 pt-1 mb-6 flex items-center justify-between gap-4\">\n <AuroraBackground intensity=\"subtle\" />\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <GradientText>{tr('proserviceworld.messages.title', 'Messages')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{unreadSummary}</p>\n </div>\n <Button size=\"sm\">\n <MessageSquare className=\"mr-2 h-4 w-4\" />\n {tr('proserviceworld.messages.actions.newMessage', 'New Message')}\n </Button>\n </div>\n\n <div\n className=\"grid gap-0 overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-pop lg:grid-cols-3\"\n style={{ height: 'calc(100vh - 220px)', minHeight: '500px' }}\n >\n {/* Conversation sidebar */}\n <div className=\"flex flex-col border-r border-border-seam lg:col-span-1\">\n {/* Search */}\n <div className=\"border-b border-border-seam p-3\">\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={tr(\n 'proserviceworld.messages.search.placeholder',\n 'Search conversations...'\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n </div>\n\n {/* Conversation list */}\n <div className=\"flex-1 overflow-y-auto\">\n {filteredConversations.length === 0 ? (\n <div className=\"p-6 text-center text-sm text-text-secondary\">\n {tr('proserviceworld.messages.empty.list', 'No conversations found.')}\n </div>\n ) : (\n filteredConversations.map((conversation) => (\n <button\n key={conversation.id}\n onClick={() => setSelectedConversationId(conversation.id)}\n className={`w-full border-b border-border-seam p-3 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-border-focus ${\n selectedConversationId === conversation.id\n ? 'bg-accent-soft'\n : 'hover:bg-bg-sunken/50'\n }`}\n >\n <div className=\"flex items-start gap-3\">\n {/* Avatar */}\n <div className=\"relative shrink-0\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-accent-soft font-semibold text-text-primary\">\n {conversation.participantName.charAt(0)}\n </div>\n {conversation.online && (\n <Circle className=\"absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 fill-status-success-text text-status-success-text stroke-bg-surface motion-safe:animate-vc-glow-pulse\" />\n )}\n </div>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between\">\n <h3\n className={`truncate text-sm ${conversation.unreadCount > 0 ? 'font-bold' : 'font-medium'}`}\n >\n {conversation.participantName}\n </h3>\n <span className=\"shrink-0 text-xs text-text-secondary\">\n {formatTime(conversation.lastMessageTime)}\n </span>\n </div>\n <p className=\"text-xs text-text-secondary\">\n {conversation.participantRole}\n </p>\n <div className=\"mt-1 flex items-center justify-between\">\n <p\n className={`truncate text-xs ${conversation.unreadCount > 0 ? 'font-medium text-text-primary' : 'text-text-secondary'}`}\n >\n {conversation.lastMessage}\n </p>\n {conversation.unreadCount > 0 && (\n <Badge className=\"ml-2 h-5 w-5 shrink-0 rounded-full p-0 text-xs flex items-center justify-center\">\n {conversation.unreadCount}\n </Badge>\n )}\n </div>\n </div>\n </div>\n </button>\n ))\n )}\n </div>\n </div>\n\n {/* Chat area */}\n <div className=\"flex flex-col lg:col-span-2\">\n {selectedConversation ? (\n <>\n {/* Chat header */}\n <div className=\"flex items-center justify-between border-b border-border-seam p-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-accent-soft font-semibold text-text-primary\">\n {selectedConversation.participantName.charAt(0)}\n </div>\n {selectedConversation.online && (\n <Circle className=\"absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 fill-status-success-text text-status-success-text stroke-bg-surface motion-safe:animate-vc-glow-pulse\" />\n )}\n </div>\n <div>\n <h3 className=\"font-medium\">{selectedConversation.participantName}</h3>\n <p className=\"text-xs text-text-secondary\">\n {selectedConversation.online\n ? tr('proserviceworld.messages.presence.online', 'Online')\n : tr('proserviceworld.messages.presence.offline', 'Offline')}{' '}\n - {selectedConversation.participantRole}\n </p>\n </div>\n </div>\n <div className=\"flex gap-1\">\n <Button variant=\"outline\" size=\"sm\">\n <Phone className=\"h-4 w-4\" />\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n <Video className=\"h-4 w-4\" />\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n <MoreHorizontal className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n {/* Messages area */}\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n {selectedConversation.messages.map((message) => (\n <div\n key={message.id}\n className={`flex ${message.isOwn ? 'justify-end' : 'justify-start'}`}\n >\n <div\n className={`flex max-w-[75%] items-end gap-2 ${message.isOwn ? 'flex-row-reverse' : ''}`}\n >\n {!message.isOwn && (\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-accent-soft text-xs font-semibold text-text-primary\">\n {message.senderName.charAt(0)}\n </div>\n )}\n <div>\n <div\n className={`rounded-2xl px-4 py-2 ${\n message.isOwn\n ? 'bg-action-primary-bg text-action-primary-text rounded-br-md'\n : 'bg-bg-sunken rounded-bl-md'\n }`}\n >\n <p className=\"text-sm\">{message.content}</p>\n </div>\n <div\n className={`mt-1 flex items-center gap-1 text-xs text-text-secondary ${message.isOwn ? 'justify-end' : ''}`}\n >\n <span>{formatTime(message.timestamp)}</span>\n {message.isOwn &&\n (message.read ? (\n <CheckCheck className=\"h-3 w-3 text-accent-blue\" />\n ) : (\n <Check className=\"h-3 w-3\" />\n ))}\n </div>\n </div>\n </div>\n </div>\n ))}\n </div>\n\n {/* Message input */}\n <div className=\"border-t border-border-seam p-3\">\n <div className=\"flex items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\">\n <Paperclip className=\"h-4 w-4\" />\n </Button>\n <Input\n placeholder={tr(\n 'proserviceworld.messages.input.placeholder',\n 'Type a message...'\n )}\n value={messageInput}\n onChange={(e) => setMessageInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && messageInput.trim()) {\n setMessageInput('');\n }\n }}\n className=\"flex-1\"\n />\n <Button variant=\"outline\" size=\"sm\">\n <Smile className=\"h-4 w-4\" />\n </Button>\n <Button size=\"sm\" disabled={!messageInput.trim()}>\n <Send className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </>\n ) : (\n <div className=\"flex flex-1 items-center justify-center\">\n <IllustratedEmptyState\n illustration=\"empty-notifications\"\n title={tr('proserviceworld.messages.emptyConversation.title', 'Select a conversation')}\n description={tr(\n 'proserviceworld.messages.emptyConversation.description',\n 'Choose a conversation to start messaging.'\n )}\n />\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MessagesPage.js","names":[],"sources":["../../../src/proserviceworld/pages/MessagesPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n Badge,\n Button,\n Input,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Search,\n Send,\n Circle,\n CheckCheck,\n Check,\n MessageSquare,\n Phone,\n Video,\n MoreHorizontal,\n Paperclip,\n Smile,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\nimport { tWithFallback } from '../utils/i18n';\n\nexport function MessagesPage() {\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 { conversations } = useProServiceWorldStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedConversationId, setSelectedConversationId] = useState<string>(\n conversations[0]?.id ?? ''\n );\n const [messageInput, setMessageInput] = useState('');\n\n const filteredConversations = useMemo(() => {\n if (!searchQuery.trim()) return conversations;\n const q = searchQuery.toLowerCase();\n return conversations.filter(\n (c) => c.participantName.toLowerCase().includes(q) || c.lastMessage.toLowerCase().includes(q)\n );\n }, [conversations, searchQuery]);\n\n const selectedConversation = conversations.find((c) => c.id === selectedConversationId);\n const totalUnread = conversations.reduce((sum, c) => sum + c.unreadCount, 0);\n const unreadSummary =\n totalUnread > 0\n ? tr('proserviceworld.messages.subtitle.unread', '{{count}} unread messages', {\n count: totalUnread,\n })\n : tr('proserviceworld.messages.subtitle.caughtUp', 'All caught up');\n\n const formatTime = (timestamp: string) => {\n const date = new Date(timestamp);\n const now = new Date();\n const diffDays = Math.floor((now.getTime() - date.getTime()) / (1000 * 60 * 60 * 24));\n if (diffDays === 0) {\n return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n }\n if (diffDays === 1) return tr('proserviceworld.messages.time.yesterday', 'Yesterday');\n if (diffDays < 7) return date.toLocaleDateString([], { weekday: 'short' });\n return date.toLocaleDateString([], { month: 'short', day: 'numeric' });\n };\n\n return (\n <div className=\"p-6 bg-bg-canvas min-h-screen\">\n <div className=\"relative overflow-hidden rounded-card -mx-2 px-2 pt-1 mb-6 flex items-center justify-between gap-4\">\n <AuroraBackground intensity=\"subtle\" />\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <GradientText>{tr('proserviceworld.messages.title', 'Messages')}</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">{unreadSummary}</p>\n </div>\n <Button size=\"sm\">\n <MessageSquare className=\"mr-2 h-4 w-4\" />\n {tr('proserviceworld.messages.actions.newMessage', 'New Message')}\n </Button>\n </div>\n\n <div className=\"mb-6\">\n <PagePurpose icon={<MessageSquare className=\"h-4 w-4\" />}>\n {tr(\n 'proserviceworld.messages.purpose',\n 'Keep every client and provider conversation in one place. Discuss scope, share updates, and coordinate bookings in real time — pick a conversation on the left to read the full thread and reply.'\n )}\n </PagePurpose>\n </div>\n\n <div\n className=\"grid gap-0 overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-pop lg:grid-cols-3\"\n style={{ height: 'calc(100vh - 220px)', minHeight: '500px' }}\n >\n {/* Conversation sidebar */}\n <div className=\"flex flex-col border-r border-border-seam lg:col-span-1\">\n {/* Search */}\n <div className=\"border-b border-border-seam p-3\">\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={tr(\n 'proserviceworld.messages.search.placeholder',\n 'Search conversations...'\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n </div>\n\n {/* Conversation list */}\n <div className=\"flex-1 overflow-y-auto\">\n {filteredConversations.length === 0 ? (\n <div className=\"p-4\">\n <IllustratedEmptyState\n illustration={searchQuery ? 'empty-search' : 'empty-people'}\n title={tr('proserviceworld.messages.empty.list', 'No conversations found')}\n description={\n searchQuery\n ? tr(\n 'proserviceworld.messages.empty.listSearch',\n 'No conversations match your search.'\n )\n : tr(\n 'proserviceworld.messages.empty.listDescription',\n 'Conversations with clients and providers will appear here.'\n )\n }\n />\n </div>\n ) : (\n filteredConversations.map((conversation) => (\n <button\n key={conversation.id}\n onClick={() => setSelectedConversationId(conversation.id)}\n className={`w-full border-b border-border-seam p-3 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-border-focus ${\n selectedConversationId === conversation.id\n ? 'bg-accent-soft'\n : 'hover:bg-bg-sunken/50'\n }`}\n >\n <div className=\"flex items-start gap-3\">\n {/* Avatar */}\n <div className=\"relative shrink-0\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-accent-soft font-semibold text-text-primary\">\n {conversation.participantName.charAt(0)}\n </div>\n {conversation.online && (\n <Circle className=\"absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 fill-status-success-text text-status-success-text stroke-bg-surface motion-safe:animate-vc-glow-pulse\" />\n )}\n </div>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between\">\n <h3\n className={`truncate text-sm ${conversation.unreadCount > 0 ? 'font-bold' : 'font-medium'}`}\n >\n {conversation.participantName}\n </h3>\n <span className=\"shrink-0 text-xs text-text-secondary\">\n {formatTime(conversation.lastMessageTime)}\n </span>\n </div>\n <p className=\"text-xs text-text-secondary\">\n {conversation.participantRole}\n </p>\n <div className=\"mt-1 flex items-center justify-between\">\n <p\n className={`truncate text-xs ${conversation.unreadCount > 0 ? 'font-medium text-text-primary' : 'text-text-secondary'}`}\n >\n {conversation.lastMessage}\n </p>\n {conversation.unreadCount > 0 && (\n <Badge className=\"ml-2 h-5 w-5 shrink-0 rounded-full p-0 text-xs flex items-center justify-center\">\n {conversation.unreadCount}\n </Badge>\n )}\n </div>\n </div>\n </div>\n </button>\n ))\n )}\n </div>\n </div>\n\n {/* Chat area */}\n <div className=\"flex flex-col lg:col-span-2\">\n {selectedConversation ? (\n <>\n {/* Chat header */}\n <div className=\"flex items-center justify-between border-b border-border-seam p-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-accent-soft font-semibold text-text-primary\">\n {selectedConversation.participantName.charAt(0)}\n </div>\n {selectedConversation.online && (\n <Circle className=\"absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 fill-status-success-text text-status-success-text stroke-bg-surface motion-safe:animate-vc-glow-pulse\" />\n )}\n </div>\n <div>\n <h3 className=\"font-medium\">{selectedConversation.participantName}</h3>\n <p className=\"text-xs text-text-secondary\">\n {selectedConversation.online\n ? tr('proserviceworld.messages.presence.online', 'Online')\n : tr('proserviceworld.messages.presence.offline', 'Offline')}{' '}\n - {selectedConversation.participantRole}\n </p>\n </div>\n </div>\n <div className=\"flex gap-1\">\n <Button variant=\"outline\" size=\"sm\">\n <Phone className=\"h-4 w-4\" />\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n <Video className=\"h-4 w-4\" />\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n <MoreHorizontal className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n {/* Messages area */}\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n {selectedConversation.messages.map((message) => (\n <div\n key={message.id}\n className={`flex ${message.isOwn ? 'justify-end' : 'justify-start'}`}\n >\n <div\n className={`flex max-w-[75%] items-end gap-2 ${message.isOwn ? 'flex-row-reverse' : ''}`}\n >\n {!message.isOwn && (\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-accent-soft text-xs font-semibold text-text-primary\">\n {message.senderName.charAt(0)}\n </div>\n )}\n <div>\n <div\n className={`rounded-2xl px-4 py-2 ${\n message.isOwn\n ? 'bg-action-primary-bg text-action-primary-text rounded-br-md'\n : 'bg-bg-sunken rounded-bl-md'\n }`}\n >\n <p className=\"text-sm\">{message.content}</p>\n </div>\n <div\n className={`mt-1 flex items-center gap-1 text-xs text-text-secondary ${message.isOwn ? 'justify-end' : ''}`}\n >\n <span>{formatTime(message.timestamp)}</span>\n {message.isOwn &&\n (message.read ? (\n <CheckCheck className=\"h-3 w-3 text-accent-blue\" />\n ) : (\n <Check className=\"h-3 w-3\" />\n ))}\n </div>\n </div>\n </div>\n </div>\n ))}\n </div>\n\n {/* Message input */}\n <div className=\"border-t border-border-seam p-3\">\n <div className=\"flex items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\">\n <Paperclip className=\"h-4 w-4\" />\n </Button>\n <Input\n placeholder={tr(\n 'proserviceworld.messages.input.placeholder',\n 'Type a message...'\n )}\n value={messageInput}\n onChange={(e) => setMessageInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && messageInput.trim()) {\n setMessageInput('');\n }\n }}\n className=\"flex-1\"\n />\n <Button variant=\"outline\" size=\"sm\">\n <Smile className=\"h-4 w-4\" />\n </Button>\n <Button size=\"sm\" disabled={!messageInput.trim()}>\n <Send className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </>\n ) : (\n <div className=\"flex flex-1 items-center justify-center\">\n <IllustratedEmptyState\n illustration=\"empty-notifications\"\n title={tr('proserviceworld.messages.emptyConversation.title', 'Select a conversation')}\n description={tr(\n 'proserviceworld.messages.emptyConversation.description',\n 'Choose a conversation to start messaging.'\n )}\n />\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -2,21 +2,21 @@ import { useProServiceWorldStore as e } from "../store/proserviceworldStore.js";
|
|
|
2
2
|
import { useMemo as t, useState as n } from "react";
|
|
3
3
|
import { ArrowDownLeft as r, ArrowUpRight as i, Building2 as a, Clock as o, CreditCard as s, DollarSign as c, Download as l, FileText as u, Plus as d, RotateCcw as f, Search as p, Shield as m, Wallet as h } from "lucide-react";
|
|
4
4
|
import { jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
5
|
-
import { AuroraBackground as v, Badge as y, Button as b, Card as x, CardContent as S, CardHeader as C, CardTitle as w, GlassCard as T, GradientText as E, IllustratedEmptyState as D, Input as O } from "@burdenoff/fe-libs/ui";
|
|
5
|
+
import { AuroraBackground as v, Badge as y, Button as b, Card as x, CardContent as S, CardHeader as C, CardTitle as w, GlassCard as T, GradientText as E, IllustratedEmptyState as D, Input as O, NextSteps as k, PagePurpose as A } from "@burdenoff/fe-libs/ui";
|
|
6
6
|
//#region src/proserviceworld/pages/PaymentsPage.tsx
|
|
7
|
-
function
|
|
8
|
-
let { transactions:
|
|
9
|
-
let e = [...
|
|
10
|
-
if (
|
|
11
|
-
let t =
|
|
7
|
+
function j() {
|
|
8
|
+
let { transactions: j, paymentMethods: M, invoices: N } = e(), [P, F] = n("overview"), [I, L] = n(""), [R, z] = n("all"), B = j.filter((e) => e.type === "outgoing" && e.status === "completed").reduce((e, t) => e + t.amount, 0), V = j.filter((e) => e.status === "pending").reduce((e, t) => e + t.amount, 0), H = j.filter((e) => e.status === "completed").reduce((e, t) => e + t.fees, 0), U = j.filter((e) => e.type === "refund" && e.status === "completed").reduce((e, t) => e + t.amount, 0), W = t(() => {
|
|
9
|
+
let e = [...j];
|
|
10
|
+
if (R !== "all" && (e = e.filter((e) => e.status === R)), I.trim()) {
|
|
11
|
+
let t = I.toLowerCase();
|
|
12
12
|
e = e.filter((e) => e.description.toLowerCase().includes(t) || e.counterparty.toLowerCase().includes(t) || (e.serviceName?.toLowerCase().includes(t) ?? !1));
|
|
13
13
|
}
|
|
14
14
|
return e.sort((e, t) => new Date(t.createdAt).getTime() - new Date(e.createdAt).getTime());
|
|
15
15
|
}, [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
]),
|
|
16
|
+
j,
|
|
17
|
+
R,
|
|
18
|
+
I
|
|
19
|
+
]), G = (e) => e === "outgoing" ? /* @__PURE__ */ g(i, { className: "h-4 w-4 text-status-error-text" }) : e === "refund" ? /* @__PURE__ */ g(f, { className: "h-4 w-4 text-status-success-text" }) : /* @__PURE__ */ g(r, { className: "h-4 w-4 text-accent-blue" }), K = (e) => /* @__PURE__ */ g(y, {
|
|
20
20
|
variant: {
|
|
21
21
|
completed: "default",
|
|
22
22
|
pending: "secondary",
|
|
@@ -24,7 +24,7 @@ function k() {
|
|
|
24
24
|
cancelled: "outline"
|
|
25
25
|
}[e] ?? "secondary",
|
|
26
26
|
children: e
|
|
27
|
-
}),
|
|
27
|
+
}), q = (e) => g(e === "card" ? s : e === "bank" ? a : h, { className: "h-5 w-5" });
|
|
28
28
|
return /* @__PURE__ */ _("div", {
|
|
29
29
|
className: "space-y-6 p-6 bg-bg-canvas min-h-screen",
|
|
30
30
|
children: [
|
|
@@ -44,6 +44,37 @@ function k() {
|
|
|
44
44
|
})]
|
|
45
45
|
})]
|
|
46
46
|
}),
|
|
47
|
+
/* @__PURE__ */ g(A, {
|
|
48
|
+
icon: /* @__PURE__ */ g(c, { className: "h-4 w-4" }),
|
|
49
|
+
children: "Your money, end to end. See what you have spent, what is pending, and what has been refunded; search and reconcile individual transactions; manage the cards and bank accounts you pay with; and download invoices for your records."
|
|
50
|
+
}),
|
|
51
|
+
/* @__PURE__ */ g(k, {
|
|
52
|
+
storageKey: "proserviceworld-payments",
|
|
53
|
+
steps: [
|
|
54
|
+
{
|
|
55
|
+
id: "transactions",
|
|
56
|
+
label: "Review your transactions",
|
|
57
|
+
description: "Search and filter every payment, fee, and refund.",
|
|
58
|
+
icon: /* @__PURE__ */ g(p, { className: "h-4 w-4" }),
|
|
59
|
+
onClick: () => F("transactions")
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "methods",
|
|
63
|
+
label: "Manage payment methods",
|
|
64
|
+
description: "Add or set a default card, bank, or wallet.",
|
|
65
|
+
icon: /* @__PURE__ */ g(s, { className: "h-4 w-4" }),
|
|
66
|
+
onClick: () => F("methods"),
|
|
67
|
+
done: M.length > 0
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "invoices",
|
|
71
|
+
label: "Check your invoices",
|
|
72
|
+
description: "View and download invoices you create or receive.",
|
|
73
|
+
icon: /* @__PURE__ */ g(u, { className: "h-4 w-4" }),
|
|
74
|
+
onClick: () => F("invoices")
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}),
|
|
47
78
|
/* @__PURE__ */ g("div", {
|
|
48
79
|
className: "flex flex-wrap gap-1 border-b border-border-seam",
|
|
49
80
|
children: [
|
|
@@ -64,13 +95,13 @@ function k() {
|
|
|
64
95
|
label: "Invoices"
|
|
65
96
|
}
|
|
66
97
|
].map(({ key: e, label: t }) => /* @__PURE__ */ g("button", {
|
|
67
|
-
onClick: () =>
|
|
68
|
-
"aria-pressed":
|
|
69
|
-
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 ${
|
|
98
|
+
onClick: () => F(e),
|
|
99
|
+
"aria-pressed": P === e,
|
|
100
|
+
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 ${P === e ? "border-action-primary-bg text-text-primary" : "border-transparent text-text-secondary hover:text-text-primary"}`,
|
|
70
101
|
children: t
|
|
71
102
|
}, e))
|
|
72
103
|
}),
|
|
73
|
-
|
|
104
|
+
P === "overview" && /* @__PURE__ */ _("div", {
|
|
74
105
|
className: "space-y-6",
|
|
75
106
|
children: [/* @__PURE__ */ _("div", {
|
|
76
107
|
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
@@ -86,7 +117,7 @@ function k() {
|
|
|
86
117
|
children: /* @__PURE__ */ g(i, { className: "h-5 w-5 text-status-error-text" })
|
|
87
118
|
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ _("p", {
|
|
88
119
|
className: "text-2xl font-bold tabular-nums",
|
|
89
|
-
children: ["$",
|
|
120
|
+
children: ["$", B.toLocaleString()]
|
|
90
121
|
}), /* @__PURE__ */ g("p", {
|
|
91
122
|
className: "text-xs text-text-secondary",
|
|
92
123
|
children: "Total Spent"
|
|
@@ -103,7 +134,7 @@ function k() {
|
|
|
103
134
|
children: /* @__PURE__ */ g(o, { className: "h-5 w-5 text-status-warning-text" })
|
|
104
135
|
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ _("p", {
|
|
105
136
|
className: "text-2xl font-bold tabular-nums",
|
|
106
|
-
children: ["$",
|
|
137
|
+
children: ["$", V.toLocaleString()]
|
|
107
138
|
}), /* @__PURE__ */ g("p", {
|
|
108
139
|
className: "text-xs text-text-secondary",
|
|
109
140
|
children: "Pending"
|
|
@@ -120,7 +151,7 @@ function k() {
|
|
|
120
151
|
children: /* @__PURE__ */ g(c, { className: "h-5 w-5 text-accent-blue" })
|
|
121
152
|
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ _("p", {
|
|
122
153
|
className: "text-2xl font-bold tabular-nums",
|
|
123
|
-
children: ["$",
|
|
154
|
+
children: ["$", H.toLocaleString()]
|
|
124
155
|
}), /* @__PURE__ */ g("p", {
|
|
125
156
|
className: "text-xs text-text-secondary",
|
|
126
157
|
children: "Total Fees"
|
|
@@ -137,7 +168,7 @@ function k() {
|
|
|
137
168
|
children: /* @__PURE__ */ g(f, { className: "h-5 w-5 text-status-success-text" })
|
|
138
169
|
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ _("p", {
|
|
139
170
|
className: "text-2xl font-bold tabular-nums",
|
|
140
|
-
children: ["$",
|
|
171
|
+
children: ["$", U.toLocaleString()]
|
|
141
172
|
}), /* @__PURE__ */ g("p", {
|
|
142
173
|
className: "text-xs text-text-secondary",
|
|
143
174
|
children: "Refunded"
|
|
@@ -155,16 +186,16 @@ function k() {
|
|
|
155
186
|
}), /* @__PURE__ */ g(b, {
|
|
156
187
|
variant: "outline",
|
|
157
188
|
size: "sm",
|
|
158
|
-
onClick: () =>
|
|
189
|
+
onClick: () => F("transactions"),
|
|
159
190
|
children: "View All"
|
|
160
191
|
})]
|
|
161
192
|
}) }), /* @__PURE__ */ g(S, { children: /* @__PURE__ */ g("div", {
|
|
162
193
|
className: "space-y-3",
|
|
163
|
-
children:
|
|
194
|
+
children: j.slice(0, 5).map((e) => /* @__PURE__ */ _("div", {
|
|
164
195
|
className: "flex items-center justify-between rounded-lg border border-border-seam p-3 transition-shadow hover:shadow-pop",
|
|
165
196
|
children: [/* @__PURE__ */ _("div", {
|
|
166
197
|
className: "flex items-center gap-3",
|
|
167
|
-
children: [
|
|
198
|
+
children: [G(e.type), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
|
|
168
199
|
className: "text-sm font-medium",
|
|
169
200
|
children: e.description
|
|
170
201
|
}), /* @__PURE__ */ _("p", {
|
|
@@ -184,13 +215,13 @@ function k() {
|
|
|
184
215
|
"$",
|
|
185
216
|
e.amount.toLocaleString()
|
|
186
217
|
]
|
|
187
|
-
}),
|
|
218
|
+
}), K(e.status)]
|
|
188
219
|
})]
|
|
189
220
|
}, e.id))
|
|
190
221
|
}) })]
|
|
191
222
|
})]
|
|
192
223
|
}),
|
|
193
|
-
|
|
224
|
+
P === "transactions" && /* @__PURE__ */ _("div", {
|
|
194
225
|
className: "space-y-4",
|
|
195
226
|
children: [/* @__PURE__ */ _("div", {
|
|
196
227
|
className: "flex flex-col gap-4 sm:flex-row sm:items-center",
|
|
@@ -198,8 +229,8 @@ function k() {
|
|
|
198
229
|
className: "relative flex-1",
|
|
199
230
|
children: [/* @__PURE__ */ g(p, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ g(O, {
|
|
200
231
|
placeholder: "Search transactions...",
|
|
201
|
-
value:
|
|
202
|
-
onChange: (e) =>
|
|
232
|
+
value: I,
|
|
233
|
+
onChange: (e) => L(e.target.value),
|
|
203
234
|
className: "pl-10"
|
|
204
235
|
})]
|
|
205
236
|
}), /* @__PURE__ */ g("div", {
|
|
@@ -210,9 +241,9 @@ function k() {
|
|
|
210
241
|
"pending",
|
|
211
242
|
"failed"
|
|
212
243
|
].map((e) => /* @__PURE__ */ g(b, {
|
|
213
|
-
variant:
|
|
244
|
+
variant: R === e ? "default" : "outline",
|
|
214
245
|
size: "sm",
|
|
215
|
-
onClick: () =>
|
|
246
|
+
onClick: () => z(e),
|
|
216
247
|
children: e === "all" ? "All" : e.charAt(0).toUpperCase() + e.slice(1)
|
|
217
248
|
}, e))
|
|
218
249
|
})]
|
|
@@ -220,7 +251,7 @@ function k() {
|
|
|
220
251
|
className: "border-border-seam",
|
|
221
252
|
children: /* @__PURE__ */ g(S, {
|
|
222
253
|
className: "pt-4",
|
|
223
|
-
children:
|
|
254
|
+
children: W.length === 0 ? /* @__PURE__ */ g(D, {
|
|
224
255
|
illustration: "empty-search",
|
|
225
256
|
title: "No transactions found",
|
|
226
257
|
description: "No transactions match your current filters."
|
|
@@ -268,12 +299,12 @@ function k() {
|
|
|
268
299
|
children: "Date"
|
|
269
300
|
})
|
|
270
301
|
]
|
|
271
|
-
}) }), /* @__PURE__ */ g("tbody", { children:
|
|
302
|
+
}) }), /* @__PURE__ */ g("tbody", { children: W.map((e) => /* @__PURE__ */ _("tr", {
|
|
272
303
|
className: "border-b border-border-seam transition-colors hover:bg-bg-sunken/50",
|
|
273
304
|
children: [
|
|
274
305
|
/* @__PURE__ */ g("td", {
|
|
275
306
|
className: "p-3",
|
|
276
|
-
children:
|
|
307
|
+
children: G(e.type)
|
|
277
308
|
}),
|
|
278
309
|
/* @__PURE__ */ g("td", {
|
|
279
310
|
className: "p-3 font-medium",
|
|
@@ -308,7 +339,7 @@ function k() {
|
|
|
308
339
|
}),
|
|
309
340
|
/* @__PURE__ */ g("td", {
|
|
310
341
|
className: "p-3",
|
|
311
|
-
children:
|
|
342
|
+
children: K(e.status)
|
|
312
343
|
}),
|
|
313
344
|
/* @__PURE__ */ g("td", {
|
|
314
345
|
className: "p-3 text-text-secondary",
|
|
@@ -321,11 +352,11 @@ function k() {
|
|
|
321
352
|
})
|
|
322
353
|
})]
|
|
323
354
|
}),
|
|
324
|
-
|
|
355
|
+
P === "methods" && /* @__PURE__ */ g("div", {
|
|
325
356
|
className: "space-y-4",
|
|
326
357
|
children: /* @__PURE__ */ _("div", {
|
|
327
358
|
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
328
|
-
children: [
|
|
359
|
+
children: [M.map((e) => /* @__PURE__ */ _(T, {
|
|
329
360
|
treatment: "glass",
|
|
330
361
|
glow: e.isDefault,
|
|
331
362
|
className: `border-border-seam ${e.isDefault, ""}`,
|
|
@@ -336,7 +367,7 @@ function k() {
|
|
|
336
367
|
className: "flex items-center gap-3",
|
|
337
368
|
children: [/* @__PURE__ */ g("div", {
|
|
338
369
|
className: "rounded-lg border border-border-seam p-2 text-text-primary",
|
|
339
|
-
children:
|
|
370
|
+
children: q(e.type)
|
|
340
371
|
}), /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
|
|
341
372
|
className: "font-medium",
|
|
342
373
|
children: e.name
|
|
@@ -393,13 +424,13 @@ function k() {
|
|
|
393
424
|
})]
|
|
394
425
|
})
|
|
395
426
|
}),
|
|
396
|
-
|
|
427
|
+
P === "invoices" && /* @__PURE__ */ g("div", {
|
|
397
428
|
className: "space-y-4",
|
|
398
429
|
children: /* @__PURE__ */ g(x, {
|
|
399
430
|
className: "border-border-seam",
|
|
400
431
|
children: /* @__PURE__ */ g(S, {
|
|
401
432
|
className: "pt-4",
|
|
402
|
-
children:
|
|
433
|
+
children: N.length === 0 ? /* @__PURE__ */ g(D, {
|
|
403
434
|
illustration: "empty-files",
|
|
404
435
|
title: "No invoices yet",
|
|
405
436
|
description: "Invoices you create or receive will appear here."
|
|
@@ -439,7 +470,7 @@ function k() {
|
|
|
439
470
|
children: "Actions"
|
|
440
471
|
})
|
|
441
472
|
]
|
|
442
|
-
}) }), /* @__PURE__ */ g("tbody", { children:
|
|
473
|
+
}) }), /* @__PURE__ */ g("tbody", { children: N.map((e) => /* @__PURE__ */ _("tr", {
|
|
443
474
|
className: "border-b border-border-seam transition-colors hover:bg-bg-sunken/50",
|
|
444
475
|
children: [
|
|
445
476
|
/* @__PURE__ */ g("td", {
|
|
@@ -501,6 +532,6 @@ function k() {
|
|
|
501
532
|
});
|
|
502
533
|
}
|
|
503
534
|
//#endregion
|
|
504
|
-
export {
|
|
535
|
+
export { j as PaymentsPage };
|
|
505
536
|
|
|
506
537
|
//# sourceMappingURL=PaymentsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PaymentsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/PaymentsPage.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 IllustratedEmptyState,\n AuroraBackground,\n GradientText,\n} from '@burdenoff/fe-libs/ui';\nimport {\n DollarSign,\n CreditCard,\n Building2,\n Wallet,\n ArrowUpRight,\n ArrowDownLeft,\n RotateCcw,\n Clock,\n Search,\n FileText,\n Plus,\n Shield,\n Download,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\n\ntype PaymentTab = 'overview' | 'transactions' | 'methods' | 'invoices';\n\nexport function PaymentsPage() {\n const { transactions, paymentMethods, invoices } = useProServiceWorldStore();\n const [activeTab, setActiveTab] = useState<PaymentTab>('overview');\n const [searchQuery, setSearchQuery] = useState('');\n const [txnStatusFilter, setTxnStatusFilter] = useState<string>('all');\n\n // Overview stats\n const totalSpent = transactions\n .filter((t) => t.type === 'outgoing' && t.status === 'completed')\n .reduce((s, t) => s + t.amount, 0);\n const totalPending = transactions\n .filter((t) => t.status === 'pending')\n .reduce((s, t) => s + t.amount, 0);\n const totalFees = transactions\n .filter((t) => t.status === 'completed')\n .reduce((s, t) => s + t.fees, 0);\n const totalRefunded = transactions\n .filter((t) => t.type === 'refund' && t.status === 'completed')\n .reduce((s, t) => s + t.amount, 0);\n\n // Filter transactions\n const filteredTxns = useMemo(() => {\n let result = [...transactions];\n if (txnStatusFilter !== 'all') {\n result = result.filter((t) => t.status === txnStatusFilter);\n }\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (t) =>\n t.description.toLowerCase().includes(q) ||\n t.counterparty.toLowerCase().includes(q) ||\n (t.serviceName?.toLowerCase().includes(q) ?? false)\n );\n }\n return result.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n }, [transactions, txnStatusFilter, searchQuery]);\n\n const txnTypeIcon = (type: string) => {\n if (type === 'outgoing') return <ArrowUpRight className=\"h-4 w-4 text-status-error-text\" />;\n if (type === 'refund') return <RotateCcw className=\"h-4 w-4 text-status-success-text\" />;\n return <ArrowDownLeft className=\"h-4 w-4 text-accent-blue\" />;\n };\n\n const statusBadge = (status: string) => {\n const variants: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n completed: 'default',\n pending: 'secondary',\n failed: 'destructive',\n cancelled: 'outline',\n };\n return <Badge variant={variants[status] ?? 'secondary'}>{status}</Badge>;\n };\n\n const methodIcon = (type: string) => {\n if (type === 'card') return <CreditCard className=\"h-5 w-5\" />;\n if (type === 'bank') return <Building2 className=\"h-5 w-5\" />;\n return <Wallet className=\"h-5 w-5\" />;\n };\n\n const tabs: { key: PaymentTab; label: string }[] = [\n { key: 'overview', label: 'Overview' },\n { key: 'transactions', label: 'Transactions' },\n { key: 'methods', label: 'Payment Methods' },\n { key: 'invoices', label: 'Invoices' },\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 gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <GradientText>Payments</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Track transactions, manage payment methods, and view invoices.\n </p>\n </div>\n <Button size=\"sm\">\n <Plus className=\"mr-2 h-4 w-4\" /> Make Payment\n </Button>\n </div>\n </div>\n\n {/* Tabs */}\n <div className=\"flex flex-wrap gap-1 border-b border-border-seam\">\n {tabs.map(({ key, label }) => (\n <button\n key={key}\n onClick={() => setActiveTab(key)}\n aria-pressed={activeTab === 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 activeTab === key\n ? 'border-action-primary-bg text-text-primary'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n }`}\n >\n {label}\n </button>\n ))}\n </div>\n\n {/* Overview Tab */}\n {activeTab === 'overview' && (\n <div className=\"space-y-6\">\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-error-bg-subtle p-2\">\n <ArrowUpRight className=\"h-5 w-5 text-status-error-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">${totalSpent.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">Total Spent</p>\n </div>\n </div>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-warning-bg-subtle p-2\">\n <Clock className=\"h-5 w-5 text-status-warning-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">${totalPending.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">Pending</p>\n </div>\n </div>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-info-bg-subtle p-2\">\n <DollarSign className=\"h-5 w-5 text-accent-blue\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">${totalFees.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">Total Fees</p>\n </div>\n </div>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-success-bg-subtle p-2\">\n <RotateCcw className=\"h-5 w-5 text-status-success-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">\n ${totalRefunded.toLocaleString()}\n </p>\n <p className=\"text-xs text-text-secondary\">Refunded</p>\n </div>\n </div>\n </GlassCard>\n </div>\n\n {/* Recent transactions preview */}\n <Card className=\"border-border-seam\">\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">Recent Transactions</CardTitle>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setActiveTab('transactions')}>\n View All\n </Button>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {transactions.slice(0, 5).map((txn) => (\n <div\n key={txn.id}\n className=\"flex items-center justify-between rounded-lg border border-border-seam p-3 transition-shadow hover:shadow-pop\"\n >\n <div className=\"flex items-center gap-3\">\n {txnTypeIcon(txn.type)}\n <div>\n <p className=\"text-sm font-medium\">{txn.description}</p>\n <p className=\"text-xs text-text-secondary\">\n {txn.counterparty} - {txn.createdAt}\n </p>\n </div>\n </div>\n <div className=\"text-right\">\n <p\n className={`text-sm font-bold tabular-nums ${txn.type === 'refund' ? 'text-status-success-text' : ''}`}\n >\n {txn.type === 'refund' ? '+' : '-'}${txn.amount.toLocaleString()}\n </p>\n {statusBadge(txn.status)}\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n\n {/* Transactions Tab */}\n {activeTab === 'transactions' && (\n <div className=\"space-y-4\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\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 transactions...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n <div className=\"flex flex-wrap gap-2\">\n {['all', 'completed', 'pending', 'failed'].map((status) => (\n <Button\n key={status}\n variant={txnStatusFilter === status ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setTxnStatusFilter(status)}\n >\n {status === 'all' ? 'All' : status.charAt(0).toUpperCase() + status.slice(1)}\n </Button>\n ))}\n </div>\n </div>\n\n <Card className=\"border-border-seam\">\n <CardContent className=\"pt-4\">\n {filteredTxns.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No transactions found\"\n description=\"No transactions match your current filters.\"\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam text-left text-text-secondary\">\n <th className=\"p-3 font-medium\">Type</th>\n <th className=\"p-3 font-medium\">Description</th>\n <th className=\"p-3 font-medium\">Counterparty</th>\n <th className=\"p-3 font-medium\">Method</th>\n <th className=\"p-3 text-right font-medium\">Amount</th>\n <th className=\"p-3 text-right font-medium\">Fees</th>\n <th className=\"p-3 text-right font-medium\">Net</th>\n <th className=\"p-3 font-medium\">Status</th>\n <th className=\"p-3 font-medium\">Date</th>\n </tr>\n </thead>\n <tbody>\n {filteredTxns.map((txn) => (\n <tr\n key={txn.id}\n className=\"border-b border-border-seam transition-colors hover:bg-bg-sunken/50\"\n >\n <td className=\"p-3\">{txnTypeIcon(txn.type)}</td>\n <td className=\"p-3 font-medium\">{txn.description}</td>\n <td className=\"p-3\">{txn.counterparty}</td>\n <td className=\"p-3\">\n <Badge variant=\"outline\">{txn.method.replace('_', ' ')}</Badge>\n </td>\n <td\n className={`p-3 text-right font-medium tabular-nums ${txn.type === 'refund' ? 'text-status-success-text' : ''}`}\n >\n {txn.type === 'refund' ? '+' : '-'}${txn.amount.toLocaleString()}\n </td>\n <td className=\"p-3 text-right text-text-secondary tabular-nums\">\n ${txn.fees}\n </td>\n <td className=\"p-3 text-right tabular-nums\">\n ${txn.netAmount.toLocaleString()}\n </td>\n <td className=\"p-3\">{statusBadge(txn.status)}</td>\n <td className=\"p-3 text-text-secondary\">{txn.createdAt}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n )}\n\n {/* Payment Methods Tab */}\n {activeTab === 'methods' && (\n <div className=\"space-y-4\">\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {paymentMethods.map((method) => (\n <GlassCard\n key={method.id}\n treatment=\"glass\"\n glow={method.isDefault}\n className={`border-border-seam ${method.isDefault ? '' : ''}`}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg border border-border-seam p-2 text-text-primary\">\n {methodIcon(method.type)}\n </div>\n <div>\n <p className=\"font-medium\">{method.name}</p>\n <p className=\"text-sm text-text-secondary\">{method.details}</p>\n </div>\n </div>\n {method.isDefault && <Badge>Default</Badge>}\n </div>\n\n <div className=\"mt-4 flex items-center gap-4 text-sm\">\n {method.isVerified ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <Shield className=\"h-4 w-4\" /> Verified\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-status-warning-text\">\n <Clock className=\"h-4 w-4\" /> Unverified\n </span>\n )}\n {method.lastUsed && (\n <span className=\"text-text-secondary\">Last used: {method.lastUsed}</span>\n )}\n </div>\n\n <div className=\"mt-4 flex gap-2\">\n {!method.isDefault && (\n <Button variant=\"outline\" size=\"sm\" className=\"flex-1\">\n Set Default\n </Button>\n )}\n <Button variant=\"outline\" size=\"sm\" className=\"flex-1\">\n Remove\n </Button>\n </div>\n </GlassCard>\n ))}\n\n {/* Add new method card */}\n <Card className=\"flex items-center justify-center border-dashed border-border-seam transition-shadow hover:shadow-pop\">\n <CardContent className=\"py-8 text-center\">\n <Plus className=\"mx-auto h-8 w-8 text-text-secondary\" />\n <p className=\"mt-2 text-sm font-medium\">Add Payment Method</p>\n <p className=\"text-xs text-text-secondary\">Add a new card, bank, or PayPal</p>\n </CardContent>\n </Card>\n </div>\n </div>\n )}\n\n {/* Invoices Tab */}\n {activeTab === 'invoices' && (\n <div className=\"space-y-4\">\n <Card className=\"border-border-seam\">\n <CardContent className=\"pt-4\">\n {invoices.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title=\"No invoices yet\"\n description=\"Invoices you create or receive will appear here.\"\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam text-left text-text-secondary\">\n <th className=\"p-3 font-medium\">Invoice #</th>\n <th className=\"p-3 font-medium\">Description</th>\n <th className=\"p-3 font-medium\">Client</th>\n <th className=\"p-3 text-right font-medium\">Amount</th>\n <th className=\"p-3 font-medium\">Status</th>\n <th className=\"p-3 font-medium\">Due Date</th>\n <th className=\"p-3 text-right font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {invoices.map((inv) => {\n const invoiceStatusVariant: Record<\n string,\n 'default' | 'secondary' | 'destructive'\n > = {\n paid: 'default',\n pending: 'secondary',\n overdue: 'destructive',\n };\n return (\n <tr\n key={inv.id}\n className=\"border-b border-border-seam transition-colors hover:bg-bg-sunken/50\"\n >\n <td className=\"p-3 font-medium\">{inv.number}</td>\n <td className=\"p-3\">{inv.description}</td>\n <td className=\"p-3\">{inv.clientName}</td>\n <td className=\"p-3 text-right font-medium tabular-nums\">\n ${inv.amount.toLocaleString()}\n </td>\n <td className=\"p-3\">\n <Badge variant={invoiceStatusVariant[inv.status] ?? 'secondary'}>\n {inv.status}\n </Badge>\n </td>\n <td className=\"p-3 text-text-secondary\">{inv.dueDate}</td>\n <td className=\"p-3 text-right\">\n <div className=\"flex justify-end gap-1\">\n <Button variant=\"outline\" size=\"sm\" aria-label=\"View invoice\">\n <FileText className=\"h-3 w-3\" />\n </Button>\n <Button variant=\"outline\" size=\"sm\" aria-label=\"Download invoice\">\n <Download className=\"h-3 w-3\" />\n </Button>\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PaymentsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/PaymentsPage.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 IllustratedEmptyState,\n AuroraBackground,\n GradientText,\n PagePurpose,\n NextSteps,\n} from '@burdenoff/fe-libs/ui';\nimport {\n DollarSign,\n CreditCard,\n Building2,\n Wallet,\n ArrowUpRight,\n ArrowDownLeft,\n RotateCcw,\n Clock,\n Search,\n FileText,\n Plus,\n Shield,\n Download,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\n\ntype PaymentTab = 'overview' | 'transactions' | 'methods' | 'invoices';\n\nexport function PaymentsPage() {\n const { transactions, paymentMethods, invoices } = useProServiceWorldStore();\n const [activeTab, setActiveTab] = useState<PaymentTab>('overview');\n const [searchQuery, setSearchQuery] = useState('');\n const [txnStatusFilter, setTxnStatusFilter] = useState<string>('all');\n\n // Overview stats\n const totalSpent = transactions\n .filter((t) => t.type === 'outgoing' && t.status === 'completed')\n .reduce((s, t) => s + t.amount, 0);\n const totalPending = transactions\n .filter((t) => t.status === 'pending')\n .reduce((s, t) => s + t.amount, 0);\n const totalFees = transactions\n .filter((t) => t.status === 'completed')\n .reduce((s, t) => s + t.fees, 0);\n const totalRefunded = transactions\n .filter((t) => t.type === 'refund' && t.status === 'completed')\n .reduce((s, t) => s + t.amount, 0);\n\n // Filter transactions\n const filteredTxns = useMemo(() => {\n let result = [...transactions];\n if (txnStatusFilter !== 'all') {\n result = result.filter((t) => t.status === txnStatusFilter);\n }\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (t) =>\n t.description.toLowerCase().includes(q) ||\n t.counterparty.toLowerCase().includes(q) ||\n (t.serviceName?.toLowerCase().includes(q) ?? false)\n );\n }\n return result.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n }, [transactions, txnStatusFilter, searchQuery]);\n\n const txnTypeIcon = (type: string) => {\n if (type === 'outgoing') return <ArrowUpRight className=\"h-4 w-4 text-status-error-text\" />;\n if (type === 'refund') return <RotateCcw className=\"h-4 w-4 text-status-success-text\" />;\n return <ArrowDownLeft className=\"h-4 w-4 text-accent-blue\" />;\n };\n\n const statusBadge = (status: string) => {\n const variants: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n completed: 'default',\n pending: 'secondary',\n failed: 'destructive',\n cancelled: 'outline',\n };\n return <Badge variant={variants[status] ?? 'secondary'}>{status}</Badge>;\n };\n\n const methodIcon = (type: string) => {\n if (type === 'card') return <CreditCard className=\"h-5 w-5\" />;\n if (type === 'bank') return <Building2 className=\"h-5 w-5\" />;\n return <Wallet className=\"h-5 w-5\" />;\n };\n\n const tabs: { key: PaymentTab; label: string }[] = [\n { key: 'overview', label: 'Overview' },\n { key: 'transactions', label: 'Transactions' },\n { key: 'methods', label: 'Payment Methods' },\n { key: 'invoices', label: 'Invoices' },\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 gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <GradientText>Payments</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Track transactions, manage payment methods, and view invoices.\n </p>\n </div>\n <Button size=\"sm\">\n <Plus className=\"mr-2 h-4 w-4\" /> Make Payment\n </Button>\n </div>\n </div>\n\n <PagePurpose icon={<DollarSign className=\"h-4 w-4\" />}>\n Your money, end to end. See what you have spent, what is pending, and what has been\n refunded; search and reconcile individual transactions; manage the cards and bank accounts\n you pay with; and download invoices for your records.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"proserviceworld-payments\"\n steps={[\n {\n id: 'transactions',\n label: 'Review your transactions',\n description: 'Search and filter every payment, fee, and refund.',\n icon: <Search className=\"h-4 w-4\" />,\n onClick: () => setActiveTab('transactions'),\n },\n {\n id: 'methods',\n label: 'Manage payment methods',\n description: 'Add or set a default card, bank, or wallet.',\n icon: <CreditCard className=\"h-4 w-4\" />,\n onClick: () => setActiveTab('methods'),\n done: paymentMethods.length > 0,\n },\n {\n id: 'invoices',\n label: 'Check your invoices',\n description: 'View and download invoices you create or receive.',\n icon: <FileText className=\"h-4 w-4\" />,\n onClick: () => setActiveTab('invoices'),\n },\n ]}\n />\n\n {/* Tabs */}\n <div className=\"flex flex-wrap gap-1 border-b border-border-seam\">\n {tabs.map(({ key, label }) => (\n <button\n key={key}\n onClick={() => setActiveTab(key)}\n aria-pressed={activeTab === 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 activeTab === key\n ? 'border-action-primary-bg text-text-primary'\n : 'border-transparent text-text-secondary hover:text-text-primary'\n }`}\n >\n {label}\n </button>\n ))}\n </div>\n\n {/* Overview Tab */}\n {activeTab === 'overview' && (\n <div className=\"space-y-6\">\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-error-bg-subtle p-2\">\n <ArrowUpRight className=\"h-5 w-5 text-status-error-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">${totalSpent.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">Total Spent</p>\n </div>\n </div>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-warning-bg-subtle p-2\">\n <Clock className=\"h-5 w-5 text-status-warning-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">${totalPending.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">Pending</p>\n </div>\n </div>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-info-bg-subtle p-2\">\n <DollarSign className=\"h-5 w-5 text-accent-blue\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">${totalFees.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">Total Fees</p>\n </div>\n </div>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-success-bg-subtle p-2\">\n <RotateCcw className=\"h-5 w-5 text-status-success-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">\n ${totalRefunded.toLocaleString()}\n </p>\n <p className=\"text-xs text-text-secondary\">Refunded</p>\n </div>\n </div>\n </GlassCard>\n </div>\n\n {/* Recent transactions preview */}\n <Card className=\"border-border-seam\">\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">Recent Transactions</CardTitle>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setActiveTab('transactions')}>\n View All\n </Button>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n {transactions.slice(0, 5).map((txn) => (\n <div\n key={txn.id}\n className=\"flex items-center justify-between rounded-lg border border-border-seam p-3 transition-shadow hover:shadow-pop\"\n >\n <div className=\"flex items-center gap-3\">\n {txnTypeIcon(txn.type)}\n <div>\n <p className=\"text-sm font-medium\">{txn.description}</p>\n <p className=\"text-xs text-text-secondary\">\n {txn.counterparty} - {txn.createdAt}\n </p>\n </div>\n </div>\n <div className=\"text-right\">\n <p\n className={`text-sm font-bold tabular-nums ${txn.type === 'refund' ? 'text-status-success-text' : ''}`}\n >\n {txn.type === 'refund' ? '+' : '-'}${txn.amount.toLocaleString()}\n </p>\n {statusBadge(txn.status)}\n </div>\n </div>\n ))}\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n\n {/* Transactions Tab */}\n {activeTab === 'transactions' && (\n <div className=\"space-y-4\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\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 transactions...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n <div className=\"flex flex-wrap gap-2\">\n {['all', 'completed', 'pending', 'failed'].map((status) => (\n <Button\n key={status}\n variant={txnStatusFilter === status ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setTxnStatusFilter(status)}\n >\n {status === 'all' ? 'All' : status.charAt(0).toUpperCase() + status.slice(1)}\n </Button>\n ))}\n </div>\n </div>\n\n <Card className=\"border-border-seam\">\n <CardContent className=\"pt-4\">\n {filteredTxns.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No transactions found\"\n description=\"No transactions match your current filters.\"\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam text-left text-text-secondary\">\n <th className=\"p-3 font-medium\">Type</th>\n <th className=\"p-3 font-medium\">Description</th>\n <th className=\"p-3 font-medium\">Counterparty</th>\n <th className=\"p-3 font-medium\">Method</th>\n <th className=\"p-3 text-right font-medium\">Amount</th>\n <th className=\"p-3 text-right font-medium\">Fees</th>\n <th className=\"p-3 text-right font-medium\">Net</th>\n <th className=\"p-3 font-medium\">Status</th>\n <th className=\"p-3 font-medium\">Date</th>\n </tr>\n </thead>\n <tbody>\n {filteredTxns.map((txn) => (\n <tr\n key={txn.id}\n className=\"border-b border-border-seam transition-colors hover:bg-bg-sunken/50\"\n >\n <td className=\"p-3\">{txnTypeIcon(txn.type)}</td>\n <td className=\"p-3 font-medium\">{txn.description}</td>\n <td className=\"p-3\">{txn.counterparty}</td>\n <td className=\"p-3\">\n <Badge variant=\"outline\">{txn.method.replace('_', ' ')}</Badge>\n </td>\n <td\n className={`p-3 text-right font-medium tabular-nums ${txn.type === 'refund' ? 'text-status-success-text' : ''}`}\n >\n {txn.type === 'refund' ? '+' : '-'}${txn.amount.toLocaleString()}\n </td>\n <td className=\"p-3 text-right text-text-secondary tabular-nums\">\n ${txn.fees}\n </td>\n <td className=\"p-3 text-right tabular-nums\">\n ${txn.netAmount.toLocaleString()}\n </td>\n <td className=\"p-3\">{statusBadge(txn.status)}</td>\n <td className=\"p-3 text-text-secondary\">{txn.createdAt}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n )}\n\n {/* Payment Methods Tab */}\n {activeTab === 'methods' && (\n <div className=\"space-y-4\">\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {paymentMethods.map((method) => (\n <GlassCard\n key={method.id}\n treatment=\"glass\"\n glow={method.isDefault}\n className={`border-border-seam ${method.isDefault ? '' : ''}`}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg border border-border-seam p-2 text-text-primary\">\n {methodIcon(method.type)}\n </div>\n <div>\n <p className=\"font-medium\">{method.name}</p>\n <p className=\"text-sm text-text-secondary\">{method.details}</p>\n </div>\n </div>\n {method.isDefault && <Badge>Default</Badge>}\n </div>\n\n <div className=\"mt-4 flex items-center gap-4 text-sm\">\n {method.isVerified ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <Shield className=\"h-4 w-4\" /> Verified\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-status-warning-text\">\n <Clock className=\"h-4 w-4\" /> Unverified\n </span>\n )}\n {method.lastUsed && (\n <span className=\"text-text-secondary\">Last used: {method.lastUsed}</span>\n )}\n </div>\n\n <div className=\"mt-4 flex gap-2\">\n {!method.isDefault && (\n <Button variant=\"outline\" size=\"sm\" className=\"flex-1\">\n Set Default\n </Button>\n )}\n <Button variant=\"outline\" size=\"sm\" className=\"flex-1\">\n Remove\n </Button>\n </div>\n </GlassCard>\n ))}\n\n {/* Add new method card */}\n <Card className=\"flex items-center justify-center border-dashed border-border-seam transition-shadow hover:shadow-pop\">\n <CardContent className=\"py-8 text-center\">\n <Plus className=\"mx-auto h-8 w-8 text-text-secondary\" />\n <p className=\"mt-2 text-sm font-medium\">Add Payment Method</p>\n <p className=\"text-xs text-text-secondary\">Add a new card, bank, or PayPal</p>\n </CardContent>\n </Card>\n </div>\n </div>\n )}\n\n {/* Invoices Tab */}\n {activeTab === 'invoices' && (\n <div className=\"space-y-4\">\n <Card className=\"border-border-seam\">\n <CardContent className=\"pt-4\">\n {invoices.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title=\"No invoices yet\"\n description=\"Invoices you create or receive will appear here.\"\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam text-left text-text-secondary\">\n <th className=\"p-3 font-medium\">Invoice #</th>\n <th className=\"p-3 font-medium\">Description</th>\n <th className=\"p-3 font-medium\">Client</th>\n <th className=\"p-3 text-right font-medium\">Amount</th>\n <th className=\"p-3 font-medium\">Status</th>\n <th className=\"p-3 font-medium\">Due Date</th>\n <th className=\"p-3 text-right font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {invoices.map((inv) => {\n const invoiceStatusVariant: Record<\n string,\n 'default' | 'secondary' | 'destructive'\n > = {\n paid: 'default',\n pending: 'secondary',\n overdue: 'destructive',\n };\n return (\n <tr\n key={inv.id}\n className=\"border-b border-border-seam transition-colors hover:bg-bg-sunken/50\"\n >\n <td className=\"p-3 font-medium\">{inv.number}</td>\n <td className=\"p-3\">{inv.description}</td>\n <td className=\"p-3\">{inv.clientName}</td>\n <td className=\"p-3 text-right font-medium tabular-nums\">\n ${inv.amount.toLocaleString()}\n </td>\n <td className=\"p-3\">\n <Badge variant={invoiceStatusVariant[inv.status] ?? 'secondary'}>\n {inv.status}\n </Badge>\n </td>\n <td className=\"p-3 text-text-secondary\">{inv.dueDate}</td>\n <td className=\"p-3 text-right\">\n <div className=\"flex justify-end gap-1\">\n <Button variant=\"outline\" size=\"sm\" aria-label=\"View invoice\">\n <FileText className=\"h-3 w-3\" />\n </Button>\n <Button variant=\"outline\" size=\"sm\" aria-label=\"Download invoice\">\n <Download className=\"h-3 w-3\" />\n </Button>\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|