@djangocfg/layouts 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/package.json +5 -5
  2. package/src/layouts/AppLayout/layouts/AuthLayout/AuthHelp.tsx +7 -5
  3. package/src/layouts/AppLayout/layouts/AuthLayout/IdentifierForm.tsx +3 -3
  4. package/src/layouts/AppLayout/layouts/AuthLayout/OTPForm.tsx +26 -10
  5. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardSidebar.tsx +1 -1
  6. package/src/layouts/AppLayout/layouts/PublicLayout/components/DesktopUserMenu.tsx +6 -6
  7. package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +1 -1
  8. package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenu.tsx +43 -133
  9. package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenuUserCard.tsx +150 -0
  10. package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +2 -2
  11. package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +41 -57
  12. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +188 -57
  13. package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +323 -0
  14. package/src/layouts/PaymentsLayout/components/index.ts +1 -0
  15. package/src/layouts/PaymentsLayout/context/RootPaymentsContext.tsx +129 -0
  16. package/src/layouts/PaymentsLayout/views/apikeys/components/ApiKeysList.tsx +2 -2
  17. package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +6 -6
  18. package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +2 -2
  19. package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +9 -4
  20. package/src/layouts/SupportLayout/hooks/useInfiniteMessages.ts +2 -3
  21. package/src/layouts/SupportLayout/hooks/useInfiniteTickets.ts +2 -3
  22. package/src/snippets/Chat/components/SessionList.tsx +1 -1
  23. package/src/snippets/Chat/hooks/useInfiniteSessions.ts +2 -2
  24. package/src/snippets/VideoPlayer/VideoPlayer.tsx +1 -1
@@ -0,0 +1,323 @@
1
+ /**
2
+ * Payment Details Dialog
3
+ * Shows payment details with QR code, address, and status
4
+ */
5
+
6
+ 'use client';
7
+
8
+ import React, { useState, useEffect } from 'react';
9
+ import {
10
+ Dialog,
11
+ DialogContent,
12
+ DialogDescription,
13
+ DialogFooter,
14
+ DialogHeader,
15
+ DialogTitle,
16
+ Button,
17
+ TokenIcon,
18
+ } from '@djangocfg/ui';
19
+ import { Copy, ExternalLink, CheckCircle2, Clock, XCircle, AlertCircle, RefreshCw } from 'lucide-react';
20
+ import { Hooks, api } from '@djangocfg/api';
21
+ import type { API } from '@djangocfg/api';
22
+
23
+ export const PAYMENT_DETAILS_EVENTS = {
24
+ OPEN_PAYMENT_DETAILS: 'open-payment-details',
25
+ CLOSE_PAYMENT_DETAILS: 'close-payment-details',
26
+ } as const;
27
+
28
+ export const PaymentDetailsDialog: React.FC = () => {
29
+ const [open, setOpen] = useState(false);
30
+ const [paymentId, setPaymentId] = useState<string | null>(null);
31
+ const [copied, setCopied] = useState(false);
32
+ const [timeLeft, setTimeLeft] = useState<string>('');
33
+
34
+ // Load payment data by ID using hook
35
+ // Only fetch when dialog is open and paymentId is set
36
+ const shouldFetch = open && !!paymentId;
37
+ const { data: payment, isLoading, error, mutate } = Hooks.usePaymentsPaymentRetrieve(
38
+ shouldFetch ? paymentId : '',
39
+ api as unknown as API
40
+ );
41
+
42
+ // Debug logging
43
+ useEffect(() => {
44
+ if (error) {
45
+ console.error('Payment loading error:', error);
46
+ }
47
+ }, [error]);
48
+
49
+ useEffect(() => {
50
+ const handleOpen = (event: Event) => {
51
+ const customEvent = event as CustomEvent<{ paymentId: string }>;
52
+ console.log('Opening payment details for ID:', customEvent.detail.paymentId);
53
+ setPaymentId(customEvent.detail.paymentId);
54
+ setOpen(true);
55
+ };
56
+
57
+ const handleClose = () => {
58
+ setOpen(false);
59
+ setPaymentId(null);
60
+ };
61
+
62
+ window.addEventListener(PAYMENT_DETAILS_EVENTS.OPEN_PAYMENT_DETAILS, handleOpen);
63
+ window.addEventListener(PAYMENT_DETAILS_EVENTS.CLOSE_PAYMENT_DETAILS, handleClose);
64
+
65
+ return () => {
66
+ window.removeEventListener(PAYMENT_DETAILS_EVENTS.OPEN_PAYMENT_DETAILS, handleOpen);
67
+ window.removeEventListener(PAYMENT_DETAILS_EVENTS.CLOSE_PAYMENT_DETAILS, handleClose);
68
+ };
69
+ }, []);
70
+
71
+ const handleClose = () => {
72
+ setOpen(false);
73
+ };
74
+
75
+ const handleCopyAddress = async () => {
76
+ if (payment?.pay_address) {
77
+ await navigator.clipboard.writeText(payment.pay_address);
78
+ setCopied(true);
79
+ setTimeout(() => setCopied(false), 2000);
80
+ }
81
+ };
82
+
83
+ // Calculate time left until expiration
84
+ useEffect(() => {
85
+ if (!payment?.expires_at) return;
86
+
87
+ const updateTimeLeft = () => {
88
+ const now = new Date().getTime();
89
+ const expires = new Date(payment.expires_at!).getTime();
90
+ const diff = expires - now;
91
+
92
+ if (diff <= 0) {
93
+ setTimeLeft('Expired');
94
+ return;
95
+ }
96
+
97
+ const hours = Math.floor(diff / (1000 * 60 * 60));
98
+ const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
99
+ const seconds = Math.floor((diff % (1000 * 60)) / 1000);
100
+
101
+ setTimeLeft(`${hours}h ${minutes}m ${seconds}s`);
102
+ };
103
+
104
+ updateTimeLeft();
105
+ const interval = setInterval(updateTimeLeft, 1000);
106
+
107
+ return () => clearInterval(interval);
108
+ }, [payment?.expires_at]);
109
+
110
+ // Get status icon and color
111
+ const getStatusInfo = () => {
112
+ switch (payment?.status) {
113
+ case 'pending':
114
+ return { icon: Clock, color: 'text-yellow-500', bg: 'bg-yellow-500/10' };
115
+ case 'completed':
116
+ return { icon: CheckCircle2, color: 'text-green-500', bg: 'bg-green-500/10' };
117
+ case 'failed':
118
+ return { icon: XCircle, color: 'text-red-500', bg: 'bg-red-500/10' };
119
+ case 'expired':
120
+ return { icon: AlertCircle, color: 'text-gray-500', bg: 'bg-gray-500/10' };
121
+ default:
122
+ return { icon: Clock, color: 'text-gray-500', bg: 'bg-gray-500/10' };
123
+ }
124
+ };
125
+
126
+ if (!open) return null;
127
+
128
+ // Loading state
129
+ if (isLoading) {
130
+ return (
131
+ <Dialog open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>
132
+ <DialogContent className="sm:max-w-lg">
133
+ <DialogHeader>
134
+ <DialogTitle>Payment Details</DialogTitle>
135
+ <DialogDescription>Loading payment information...</DialogDescription>
136
+ </DialogHeader>
137
+ <div className="flex items-center justify-center py-12">
138
+ <RefreshCw className="h-8 w-8 animate-spin text-muted-foreground" />
139
+ </div>
140
+ </DialogContent>
141
+ </Dialog>
142
+ );
143
+ }
144
+
145
+ // Error state - only show error if we actually tried to fetch and failed
146
+ if (shouldFetch && !isLoading && (error || !payment)) {
147
+ return (
148
+ <Dialog open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>
149
+ <DialogContent className="sm:max-w-lg">
150
+ <DialogHeader>
151
+ <DialogTitle>Payment Details</DialogTitle>
152
+ <DialogDescription>Failed to load payment information</DialogDescription>
153
+ </DialogHeader>
154
+ <div className="flex flex-col items-center justify-center py-12 space-y-4">
155
+ <XCircle className="h-12 w-12 text-destructive" />
156
+ <p className="text-sm text-muted-foreground">
157
+ {error ? `Error: ${error}` : 'Payment not found'}
158
+ </p>
159
+ <Button onClick={() => mutate()}>Try Again</Button>
160
+ </div>
161
+ </DialogContent>
162
+ </Dialog>
163
+ );
164
+ }
165
+
166
+ const statusInfo = getStatusInfo();
167
+ const StatusIcon = statusInfo.icon;
168
+
169
+ // Generate QR code URL (using simple data URL)
170
+ const qrCodeUrl = payment.pay_address
171
+ ? `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(payment.pay_address)}`
172
+ : null;
173
+
174
+ return (
175
+ <Dialog open={open} onOpenChange={(isOpen) => !isOpen && handleClose()}>
176
+ <DialogContent className="sm:max-w-lg">
177
+ <DialogHeader>
178
+ <DialogTitle>Payment Details</DialogTitle>
179
+ <DialogDescription>
180
+ Send cryptocurrency to complete your payment
181
+ </DialogDescription>
182
+ </DialogHeader>
183
+
184
+ <div className="space-y-6">
185
+ {/* Status Badge */}
186
+ <div className={`flex items-center gap-3 p-4 rounded-sm ${statusInfo.bg}`}>
187
+ <StatusIcon className={`h-5 w-5 ${statusInfo.color}`} />
188
+ <div className="flex-1">
189
+ <div className="font-semibold capitalize">{payment.status}</div>
190
+ {payment.status === 'pending' && timeLeft && (
191
+ <div className="text-sm text-muted-foreground">
192
+ Expires in {timeLeft}
193
+ </div>
194
+ )}
195
+ </div>
196
+ </div>
197
+
198
+ {/* Amount Information */}
199
+ <div className="space-y-3">
200
+ <div className="flex items-center justify-between p-4 bg-muted rounded-sm">
201
+ <span className="text-sm text-muted-foreground">Amount to send</span>
202
+ <div className="flex items-center gap-2">
203
+ <TokenIcon symbol={String(payment.currency || 'BTC')} size={20} />
204
+ <span className="font-mono font-bold text-lg">
205
+ {payment.amount_crypto?.toFixed(8)} {payment.currency}
206
+ </span>
207
+ </div>
208
+ </div>
209
+
210
+ <div className="flex items-center justify-between px-4">
211
+ <span className="text-sm text-muted-foreground">Equivalent to</span>
212
+ <span className="font-semibold text-lg">${payment.amount_usd?.toFixed(2)} USD</span>
213
+ </div>
214
+
215
+ {payment.provider_payment_id && (
216
+ <div className="flex items-center justify-between px-4">
217
+ <span className="text-sm text-muted-foreground">Payment Order #</span>
218
+ <span className="font-mono font-medium">{payment.provider_payment_id}</span>
219
+ </div>
220
+ )}
221
+
222
+ {payment.network && (
223
+ <div className="flex items-center justify-between px-4">
224
+ <span className="text-sm text-muted-foreground">Network</span>
225
+ <span className="font-medium">{payment.network}</span>
226
+ </div>
227
+ )}
228
+ </div>
229
+
230
+ {/* QR Code */}
231
+ {qrCodeUrl && payment.status === 'pending' && (
232
+ <div className="flex justify-center p-6 bg-white rounded-sm">
233
+ <img src={qrCodeUrl} alt="Payment QR Code" className="w-48 h-48" />
234
+ </div>
235
+ )}
236
+
237
+ {/* Payment Address */}
238
+ {payment.pay_address && payment.status === 'pending' && (
239
+ <div className="space-y-2">
240
+ <label className="text-sm font-medium">Payment Address</label>
241
+ <div className="flex items-center gap-2">
242
+ <div className="flex-1 p-3 bg-muted rounded-sm font-mono text-sm break-all">
243
+ {payment.pay_address}
244
+ </div>
245
+ <Button
246
+ variant="outline"
247
+ size="icon"
248
+ onClick={handleCopyAddress}
249
+ className="shrink-0"
250
+ >
251
+ {copied ? (
252
+ <CheckCircle2 className="h-4 w-4 text-green-500" />
253
+ ) : (
254
+ <Copy className="h-4 w-4" />
255
+ )}
256
+ </Button>
257
+ </div>
258
+ </div>
259
+ )}
260
+
261
+ {/* Transaction Hash */}
262
+ {payment.transaction_hash && (
263
+ <div className="space-y-2">
264
+ <label className="text-sm font-medium">Transaction Hash</label>
265
+ <div className="p-3 bg-muted rounded-sm font-mono text-sm break-all">
266
+ {payment.transaction_hash}
267
+ </div>
268
+ </div>
269
+ )}
270
+
271
+ {/* Payment URL */}
272
+ {payment.payment_url && payment.status === 'pending' && (
273
+ <Button
274
+ variant="outline"
275
+ className="w-full"
276
+ onClick={() => window.open(payment.payment_url!, '_blank')}
277
+ >
278
+ <ExternalLink className="h-4 w-4 mr-2" />
279
+ Open in Payment Provider
280
+ </Button>
281
+ )}
282
+
283
+ {/* Additional Info */}
284
+ <div className="pt-4 border-t space-y-2 text-xs text-muted-foreground">
285
+ <div className="flex justify-between">
286
+ <span>Payment ID</span>
287
+ <span className="font-mono">{payment.id}</span>
288
+ </div>
289
+ <div className="flex justify-between">
290
+ <span>Created</span>
291
+ <span>{new Date(payment.created_at!).toLocaleString()}</span>
292
+ </div>
293
+ {payment.confirmations_count !== undefined && (
294
+ <div className="flex justify-between">
295
+ <span>Confirmations</span>
296
+ <span>{payment.confirmations_count}</span>
297
+ </div>
298
+ )}
299
+ </div>
300
+ </div>
301
+
302
+ <DialogFooter>
303
+ <Button variant="outline" onClick={handleClose}>
304
+ Close
305
+ </Button>
306
+ </DialogFooter>
307
+ </DialogContent>
308
+ </Dialog>
309
+ );
310
+ };
311
+
312
+ // Helper function to open payment details dialog
313
+ export const openPaymentDetails = (paymentId: string) => {
314
+ window.dispatchEvent(
315
+ new CustomEvent(PAYMENT_DETAILS_EVENTS.OPEN_PAYMENT_DETAILS, {
316
+ detail: { paymentId },
317
+ })
318
+ );
319
+ };
320
+
321
+ export const closePaymentDetails = () => {
322
+ window.dispatchEvent(new Event(PAYMENT_DETAILS_EVENTS.CLOSE_PAYMENT_DETAILS));
323
+ };
@@ -1,4 +1,5 @@
1
1
  export { CreateApiKeyDialog } from './CreateApiKeyDialog';
2
2
  export { DeleteApiKeyDialog } from './DeleteApiKeyDialog';
3
3
  export { CreatePaymentDialog } from './CreatePaymentDialog';
4
+ export { PaymentDetailsDialog, openPaymentDetails, closePaymentDetails } from './PaymentDetailsDialog';
4
5
 
@@ -0,0 +1,129 @@
1
+ 'use client';
2
+
3
+ import React, { createContext, useContext, useEffect, type ReactNode } from 'react';
4
+ import { api, Hooks } from '@djangocfg/api';
5
+ import type { API } from '@djangocfg/api';
6
+ import type {
7
+ Currency,
8
+ PaginatedCurrencyListList,
9
+ ProviderCurrency,
10
+ PaginatedProviderCurrencyList,
11
+ Network,
12
+ PaginatedNetworkList,
13
+ } from '@djangocfg/api';
14
+
15
+ // ─────────────────────────────────────────────────────────────────────────
16
+ // Context Type
17
+ // ─────────────────────────────────────────────────────────────────────────
18
+
19
+ export interface RootPaymentsContextValue {
20
+ // Currencies
21
+ currencies: PaginatedCurrencyListList | undefined;
22
+ isLoadingCurrencies: boolean;
23
+ currenciesError: Error | undefined;
24
+ refreshCurrencies: () => Promise<void>;
25
+
26
+ // Provider Currencies
27
+ providerCurrencies: PaginatedProviderCurrencyList | undefined;
28
+ isLoadingProviderCurrencies: boolean;
29
+ providerCurrenciesError: Error | undefined;
30
+ refreshProviderCurrencies: () => Promise<void>;
31
+
32
+ // Networks
33
+ networks: PaginatedNetworkList | undefined;
34
+ isLoadingNetworks: boolean;
35
+ networksError: Error | undefined;
36
+ refreshNetworks: () => Promise<void>;
37
+ }
38
+
39
+ // ─────────────────────────────────────────────────────────────────────────
40
+ // Context
41
+ // ─────────────────────────────────────────────────────────────────────────
42
+
43
+ const RootPaymentsContext = createContext<RootPaymentsContextValue | undefined>(undefined);
44
+
45
+ // ─────────────────────────────────────────────────────────────────────────
46
+ // Provider
47
+ // ─────────────────────────────────────────────────────────────────────────
48
+
49
+ export function RootPaymentsProvider({ children }: { children: ReactNode }) {
50
+ // List all currencies
51
+ const {
52
+ data: currencies,
53
+ error: currenciesError,
54
+ isLoading: isLoadingCurrencies,
55
+ mutate: mutateCurrencies,
56
+ } = Hooks.usePaymentsCurrenciesList({}, api as unknown as API);
57
+
58
+ // List all provider currencies
59
+ const {
60
+ data: providerCurrencies,
61
+ error: providerCurrenciesError,
62
+ isLoading: isLoadingProviderCurrencies,
63
+ mutate: mutateProviderCurrencies,
64
+ } = Hooks.usePaymentsProviderCurrenciesList({}, api as unknown as API);
65
+
66
+ // List all networks
67
+ const {
68
+ data: networks,
69
+ error: networksError,
70
+ isLoading: isLoadingNetworks,
71
+ mutate: mutateNetworks,
72
+ } = Hooks.usePaymentsNetworksList({}, api as unknown as API);
73
+
74
+ const refreshCurrencies = async () => {
75
+ await mutateCurrencies();
76
+ };
77
+
78
+ const refreshProviderCurrencies = async () => {
79
+ await mutateProviderCurrencies();
80
+ };
81
+
82
+ const refreshNetworks = async () => {
83
+ await mutateNetworks();
84
+ };
85
+
86
+ const value: RootPaymentsContextValue = {
87
+ currencies,
88
+ isLoadingCurrencies,
89
+ currenciesError,
90
+ refreshCurrencies,
91
+ providerCurrencies,
92
+ isLoadingProviderCurrencies,
93
+ providerCurrenciesError,
94
+ refreshProviderCurrencies,
95
+ networks,
96
+ isLoadingNetworks,
97
+ networksError,
98
+ refreshNetworks,
99
+ };
100
+
101
+ return (
102
+ <RootPaymentsContext.Provider value={value}>{children}</RootPaymentsContext.Provider>
103
+ );
104
+ }
105
+
106
+ // ─────────────────────────────────────────────────────────────────────────
107
+ // Hook
108
+ // ─────────────────────────────────────────────────────────────────────────
109
+
110
+ export function useRootPaymentsContext(): RootPaymentsContextValue {
111
+ const context = useContext(RootPaymentsContext);
112
+ if (!context) {
113
+ throw new Error('useRootPaymentsContext must be used within RootPaymentsProvider');
114
+ }
115
+ return context;
116
+ }
117
+
118
+ // ─────────────────────────────────────────────────────────────────────────
119
+ // Re-export types
120
+ // ─────────────────────────────────────────────────────────────────────────
121
+
122
+ export type {
123
+ Currency,
124
+ PaginatedCurrencyListList,
125
+ ProviderCurrency,
126
+ PaginatedProviderCurrencyList,
127
+ Network,
128
+ PaginatedNetworkList,
129
+ };
@@ -88,7 +88,7 @@ export const ApiKeysList: React.FC = () => {
88
88
  <CardContent>
89
89
  <div className="space-y-4">
90
90
  {Array.from({ length: 3 }).map((_, i) => (
91
- <div key={i} className="flex items-center justify-between p-4 border rounded-lg">
91
+ <div key={i} className="flex items-center justify-between p-4 border rounded-sm">
92
92
  <div className="space-y-2 flex-1">
93
93
  <Skeleton className="h-4 w-32" />
94
94
  <Skeleton className="h-3 w-48" />
@@ -131,7 +131,7 @@ export const ApiKeysList: React.FC = () => {
131
131
  {keysList.map((key) => (
132
132
  <div
133
133
  key={key.id}
134
- className="flex items-center justify-between p-4 border rounded-lg hover:bg-accent/50 transition-colors"
134
+ className="flex items-center justify-between p-4 border rounded-sm hover:bg-accent/50 transition-colors"
135
135
  >
136
136
  <div className="flex-1 min-w-0">
137
137
  <div className="flex items-center gap-3 mb-2">
@@ -16,15 +16,15 @@ import {
16
16
  Skeleton,
17
17
  } from '@djangocfg/ui';
18
18
  import { Wallet, RefreshCw, Plus } from 'lucide-react';
19
- import { useBalancesContext } from '@djangocfg/api/cfg/contexts';
19
+ import { useOverviewContext } from '@djangocfg/api/cfg/contexts';
20
20
  import { openCreatePaymentDialog } from '../../../events';
21
21
 
22
22
  export const BalanceCard: React.FC = () => {
23
- const {
24
- balanceSummary,
25
- isLoadingSummary,
26
- refreshSummary
27
- } = useBalancesContext();
23
+ const {
24
+ balanceSummary,
25
+ isLoadingSummary,
26
+ refreshSummary
27
+ } = useOverviewContext();
28
28
 
29
29
  const formatCurrency = (amount?: number | null) => {
30
30
  if (amount === null || amount === undefined) return '$0.00';
@@ -72,7 +72,7 @@ export const RecentPayments: React.FC = () => {
72
72
  </CardHeader>
73
73
  <CardContent className="space-y-3">
74
74
  {Array.from({ length: 5 }).map((_, i) => (
75
- <div key={i} className="flex items-center justify-between p-3 border rounded-lg">
75
+ <div key={i} className="flex items-center justify-between p-3 border rounded-sm">
76
76
  <div className="space-y-2">
77
77
  <Skeleton className="h-4 w-32" />
78
78
  <Skeleton className="h-3 w-24" />
@@ -112,7 +112,7 @@ export const RecentPayments: React.FC = () => {
112
112
  {payments.map((payment) => (
113
113
  <div
114
114
  key={payment.id}
115
- className="flex items-center justify-between p-3 border rounded-lg hover:bg-accent cursor-pointer transition-colors"
115
+ className="flex items-center justify-between p-3 border rounded-sm hover:bg-accent cursor-pointer transition-colors"
116
116
  onClick={() => openPaymentDetailsDialog(payment.id)}
117
117
  >
118
118
  <div className="flex-1">
@@ -29,7 +29,8 @@ import {
29
29
  } from '@djangocfg/ui';
30
30
  import { Plus, Search, Filter, ChevronLeft, ChevronRight, RefreshCw, ExternalLink } from 'lucide-react';
31
31
  import { usePaymentsContext } from '@djangocfg/api/cfg/contexts';
32
- import { openCreatePaymentDialog, openPaymentDetailsDialog } from '../../../events';
32
+ import { openCreatePaymentDialog } from '../../../events';
33
+ import { openPaymentDetails } from '../../../components/PaymentDetailsDialog';
33
34
 
34
35
  export const PaymentsList: React.FC = () => {
35
36
  const {
@@ -155,7 +156,7 @@ export const PaymentsList: React.FC = () => {
155
156
  {isLoadingPayments ? (
156
157
  <div className="space-y-3">
157
158
  {Array.from({ length: 5 }).map((_, i) => (
158
- <div key={i} className="flex items-center justify-between p-4 border rounded-lg">
159
+ <div key={i} className="flex items-center justify-between p-4 border rounded-sm">
159
160
  <div className="space-y-2">
160
161
  <Skeleton className="h-4 w-32" />
161
162
  <Skeleton className="h-3 w-24" />
@@ -197,7 +198,11 @@ export const PaymentsList: React.FC = () => {
197
198
  </TableHeader>
198
199
  <TableBody>
199
200
  {paymentsList.map((payment) => (
200
- <TableRow key={payment.id} className="cursor-pointer hover:bg-accent">
201
+ <TableRow
202
+ key={payment.id}
203
+ className="cursor-pointer hover:bg-accent"
204
+ onClick={() => openPaymentDetails(payment.id)}
205
+ >
201
206
  <TableCell>
202
207
  <div>
203
208
  <div className="font-medium">
@@ -229,7 +234,7 @@ export const PaymentsList: React.FC = () => {
229
234
  size="sm"
230
235
  onClick={(e) => {
231
236
  e.stopPropagation();
232
- openPaymentDetailsDialog(payment.id);
237
+ openPaymentDetails(payment.id);
233
238
  }}
234
239
  >
235
240
  <ExternalLink className="h-4 w-4" />
@@ -4,9 +4,8 @@
4
4
  */
5
5
 
6
6
  import useSWRInfinite from 'swr/infinite';
7
- import { api, getSupportTicketsMessagesList } from '@djangocfg/api';
7
+ import { api, Fetchers, CfgSupportTypes } from '@djangocfg/api';
8
8
  import type { API } from '@djangocfg/api';
9
- import { CfgSupportTypes } from '@djangocfg/api';
10
9
 
11
10
  type PaginatedMessageList = CfgSupportTypes.PaginatedMessageList;
12
11
  type Message = CfgSupportTypes.Message;
@@ -41,7 +40,7 @@ export function useInfiniteMessages(ticketUuid: string | null): UseInfiniteMessa
41
40
  };
42
41
 
43
42
  const fetcher = async ([, ticket_uuid, page, pageSize]: [string, string, number, number]) => {
44
- return getSupportTicketsMessagesList(
43
+ return Fetchers.getSupportTicketsMessagesList(
45
44
  ticket_uuid,
46
45
  { page, page_size: pageSize },
47
46
  api as unknown as API
@@ -4,9 +4,8 @@
4
4
  */
5
5
 
6
6
  import useSWRInfinite from 'swr/infinite';
7
- import { api, getSupportTicketsList } from '@djangocfg/api';
7
+ import { api, Fetchers, CfgSupportTypes } from '@djangocfg/api';
8
8
  import type { API } from '@djangocfg/api';
9
- import { CfgSupportTypes } from '@djangocfg/api';
10
9
 
11
10
  type PaginatedTicketList = CfgSupportTypes.PaginatedTicketList;
12
11
  type Ticket = CfgSupportTypes.Ticket;
@@ -37,7 +36,7 @@ export function useInfiniteTickets(): UseInfiniteTicketsReturn {
37
36
  };
38
37
 
39
38
  const fetcher = async ([, page, pageSize]: [string, number, number]) => {
40
- return getSupportTicketsList(
39
+ return Fetchers.getSupportTicketsList(
41
40
  { page, page_size: pageSize },
42
41
  api as unknown as API
43
42
  );
@@ -102,7 +102,7 @@ export const SessionList: React.FC<SessionListProps> = ({
102
102
  {sessions.map((session, index) => (
103
103
  <div
104
104
  key={session.id}
105
- className="group relative flex items-start gap-3 p-4 border rounded-lg
105
+ className="group relative flex items-start gap-3 p-4 border rounded-sm
106
106
  hover:bg-muted/50 hover:border-primary/50 hover:shadow-md
107
107
  transition-all duration-200 cursor-pointer
108
108
  animate-in fade-in slide-in-from-left-2"
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import useSWRInfinite from 'swr/infinite';
7
- import { api, getKnowbaseAdminSessionsList, CfgKnowbaseTypes } from '@djangocfg/api';
7
+ import { api, Fetchers, CfgKnowbaseTypes } from '@djangocfg/api';
8
8
  import type { API } from '@djangocfg/api';
9
9
 
10
10
  type PaginatedChatSessionList = CfgKnowbaseTypes.PaginatedChatSessionList;
@@ -25,7 +25,7 @@ export function useInfiniteSessions() {
25
25
  };
26
26
 
27
27
  const fetcher = async ([, page, pageSize]: [string, number, number]) => {
28
- return getKnowbaseAdminSessionsList(
28
+ return Fetchers.getKnowbaseAdminSessionsList(
29
29
  { page, page_size: pageSize },
30
30
  api as unknown as API
31
31
  );
@@ -71,7 +71,7 @@ export const VideoPlayer = forwardRef<VideoPlayerRef, VideoPlayerProps>(({
71
71
  {/* Video Player */}
72
72
  <div
73
73
  className={cn(
74
- "relative w-full overflow-hidden rounded-lg bg-black",
74
+ "relative w-full overflow-hidden rounded-sm bg-black",
75
75
  theme === 'minimal' && "rounded-none",
76
76
  theme === 'modern' && "rounded-xl shadow-2xl"
77
77
  )}