@djangocfg/layouts 1.0.3 → 1.0.5
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/package.json +5 -5
- package/src/layouts/AppLayout/layouts/AuthLayout/AuthHelp.tsx +2 -2
- package/src/layouts/AppLayout/layouts/AuthLayout/OTPForm.tsx +6 -6
- package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardSidebar.tsx +1 -1
- package/src/layouts/AppLayout/layouts/PublicLayout/components/DesktopUserMenu.tsx +6 -6
- package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +1 -1
- package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenu.tsx +43 -133
- package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenuUserCard.tsx +150 -0
- package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +2 -2
- package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +47 -65
- package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +121 -144
- package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +103 -48
- package/src/layouts/PaymentsLayout/components/index.ts +1 -4
- package/src/layouts/PaymentsLayout/events.ts +23 -84
- package/src/layouts/PaymentsLayout/index.ts +7 -11
- package/src/layouts/PaymentsLayout/types.ts +3 -16
- package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +45 -16
- package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +18 -14
- package/src/layouts/PaymentsLayout/views/overview/components/index.ts +0 -2
- package/src/layouts/PaymentsLayout/views/overview/index.tsx +3 -6
- package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +51 -31
- package/src/layouts/PaymentsLayout/views/payments/components/index.ts +0 -1
- package/src/layouts/PaymentsLayout/views/payments/index.tsx +1 -2
- package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +273 -0
- package/src/layouts/PaymentsLayout/views/transactions/components/index.ts +1 -0
- package/src/layouts/PaymentsLayout/views/transactions/index.tsx +5 -17
- package/src/layouts/SupportLayout/hooks/useInfiniteMessages.ts +2 -3
- package/src/layouts/SupportLayout/hooks/useInfiniteTickets.ts +2 -3
- package/src/snippets/Chat/components/SessionList.tsx +1 -1
- package/src/snippets/Chat/hooks/useInfiniteSessions.ts +2 -2
- package/src/snippets/VideoPlayer/VideoPlayer.tsx +1 -1
- package/src/layouts/PaymentsLayout/README.md +0 -133
- package/src/layouts/PaymentsLayout/components/CreateApiKeyDialog.tsx +0 -172
- package/src/layouts/PaymentsLayout/components/DeleteApiKeyDialog.tsx +0 -100
- package/src/layouts/PaymentsLayout/context/RootPaymentsContext.tsx +0 -134
- package/src/layouts/PaymentsLayout/views/apikeys/components/ApiKeyMetrics.tsx +0 -109
- package/src/layouts/PaymentsLayout/views/apikeys/components/ApiKeysList.tsx +0 -194
- package/src/layouts/PaymentsLayout/views/apikeys/components/index.ts +0 -3
- package/src/layouts/PaymentsLayout/views/apikeys/index.tsx +0 -19
- package/src/layouts/PaymentsLayout/views/overview/components/MetricsCards.tsx +0 -103
- package/src/layouts/PaymentsLayout/views/tariffs/index.tsx +0 -29
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API Keys List Component
|
|
3
|
-
* Display and manage API keys
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use client';
|
|
7
|
-
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import {
|
|
10
|
-
Card,
|
|
11
|
-
CardContent,
|
|
12
|
-
CardHeader,
|
|
13
|
-
CardTitle,
|
|
14
|
-
Button,
|
|
15
|
-
Badge,
|
|
16
|
-
DropdownMenu,
|
|
17
|
-
DropdownMenuContent,
|
|
18
|
-
DropdownMenuItem,
|
|
19
|
-
DropdownMenuTrigger,
|
|
20
|
-
Skeleton,
|
|
21
|
-
useCopy,
|
|
22
|
-
} from '@djangocfg/ui';
|
|
23
|
-
import { Plus, MoreHorizontal, Edit, Trash2, Key, Copy, CheckCircle2 } from 'lucide-react';
|
|
24
|
-
import { useApiKeysContext } from '@djangocfg/api/cfg/contexts';
|
|
25
|
-
import { paymentsLogger } from '../../../../../utils/logger';
|
|
26
|
-
import { openCreateApiKeyDialog, openEditApiKeyDialog, openDeleteApiKeyDialog } from '../../../events';
|
|
27
|
-
|
|
28
|
-
export const ApiKeysList: React.FC = () => {
|
|
29
|
-
const { apiKeys, isLoadingApiKeys, deleteApiKey } = useApiKeysContext();
|
|
30
|
-
const { copyToClipboard } = useCopy({
|
|
31
|
-
successMessage: 'API key copied to clipboard',
|
|
32
|
-
errorMessage: 'Failed to copy API key',
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const keysList = apiKeys?.results || [];
|
|
36
|
-
|
|
37
|
-
const getStatusVariant = (isActive?: boolean | null) => {
|
|
38
|
-
return isActive ? 'default' : 'secondary';
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const getStatusLabel = (isActive?: boolean | null) => {
|
|
42
|
-
return isActive ? 'Active' : 'Inactive';
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const getRelativeTime = (date: string | null | undefined): string => {
|
|
46
|
-
if (!date) return 'N/A';
|
|
47
|
-
|
|
48
|
-
const now = new Date();
|
|
49
|
-
const target = new Date(date);
|
|
50
|
-
const diffInSeconds = Math.floor((now.getTime() - target.getTime()) / 1000);
|
|
51
|
-
|
|
52
|
-
if (diffInSeconds < 60) return 'Just now';
|
|
53
|
-
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
|
|
54
|
-
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
|
|
55
|
-
return `${Math.floor(diffInSeconds / 86400)}d ago`;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const formatApiKey = (key: string) => {
|
|
59
|
-
if (!key) return '';
|
|
60
|
-
if (key.length <= 12) return key;
|
|
61
|
-
return `${key.slice(0, 8)}...${key.slice(-4)}`;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const handleCopyKey = async (keyValue: string) => {
|
|
65
|
-
await copyToClipboard(keyValue);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const handleDelete = async (keyId: string) => {
|
|
69
|
-
try {
|
|
70
|
-
await deleteApiKey(keyId);
|
|
71
|
-
} catch (error) {
|
|
72
|
-
paymentsLogger.error('Failed to delete key:', error);
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
if (isLoadingApiKeys) {
|
|
77
|
-
return (
|
|
78
|
-
<Card>
|
|
79
|
-
<CardHeader>
|
|
80
|
-
<CardTitle className="flex items-center justify-between">
|
|
81
|
-
<span>API Keys</span>
|
|
82
|
-
<Button disabled>
|
|
83
|
-
<Plus className="h-4 w-4 mr-2" />
|
|
84
|
-
Create Key
|
|
85
|
-
</Button>
|
|
86
|
-
</CardTitle>
|
|
87
|
-
</CardHeader>
|
|
88
|
-
<CardContent>
|
|
89
|
-
<div className="space-y-4">
|
|
90
|
-
{Array.from({ length: 3 }).map((_, i) => (
|
|
91
|
-
<div key={i} className="flex items-center justify-between p-4 border rounded-lg">
|
|
92
|
-
<div className="space-y-2 flex-1">
|
|
93
|
-
<Skeleton className="h-4 w-32" />
|
|
94
|
-
<Skeleton className="h-3 w-48" />
|
|
95
|
-
</div>
|
|
96
|
-
<Skeleton className="h-8 w-8 rounded-full" />
|
|
97
|
-
</div>
|
|
98
|
-
))}
|
|
99
|
-
</div>
|
|
100
|
-
</CardContent>
|
|
101
|
-
</Card>
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
<Card>
|
|
107
|
-
<CardHeader>
|
|
108
|
-
<CardTitle className="flex items-center justify-between">
|
|
109
|
-
<span>API Keys</span>
|
|
110
|
-
<Button onClick={() => openCreateApiKeyDialog()}>
|
|
111
|
-
<Plus className="h-4 w-4 mr-2" />
|
|
112
|
-
Create Key
|
|
113
|
-
</Button>
|
|
114
|
-
</CardTitle>
|
|
115
|
-
</CardHeader>
|
|
116
|
-
<CardContent>
|
|
117
|
-
{keysList.length === 0 ? (
|
|
118
|
-
<div className="text-center py-12">
|
|
119
|
-
<Key className="h-12 w-12 mx-auto text-muted-foreground mb-4" />
|
|
120
|
-
<h3 className="text-lg font-semibold mb-2">No API Keys</h3>
|
|
121
|
-
<p className="text-muted-foreground mb-4">
|
|
122
|
-
Create your first API key to get started
|
|
123
|
-
</p>
|
|
124
|
-
<Button onClick={() => openCreateApiKeyDialog()}>
|
|
125
|
-
<Plus className="h-4 w-4 mr-2" />
|
|
126
|
-
Create Key
|
|
127
|
-
</Button>
|
|
128
|
-
</div>
|
|
129
|
-
) : (
|
|
130
|
-
<div className="space-y-4">
|
|
131
|
-
{keysList.map((key) => (
|
|
132
|
-
<div
|
|
133
|
-
key={key.id}
|
|
134
|
-
className="flex items-center justify-between p-4 border rounded-lg hover:bg-accent/50 transition-colors"
|
|
135
|
-
>
|
|
136
|
-
<div className="flex-1 min-w-0">
|
|
137
|
-
<div className="flex items-center gap-3 mb-2">
|
|
138
|
-
<h3 className="font-medium truncate">{key.name || 'Unnamed Key'}</h3>
|
|
139
|
-
<Badge variant={getStatusVariant(key.is_active)}>
|
|
140
|
-
{getStatusLabel(key.is_active)}
|
|
141
|
-
</Badge>
|
|
142
|
-
</div>
|
|
143
|
-
|
|
144
|
-
<div className="space-y-1">
|
|
145
|
-
<div className="flex items-center gap-2">
|
|
146
|
-
<code className="text-sm bg-muted px-2 py-1 rounded font-mono">
|
|
147
|
-
{formatApiKey(key.id)}
|
|
148
|
-
</code>
|
|
149
|
-
<Button
|
|
150
|
-
variant="ghost"
|
|
151
|
-
size="sm"
|
|
152
|
-
onClick={() => handleCopyKey(key.id)}
|
|
153
|
-
>
|
|
154
|
-
<Copy className="h-4 w-4" />
|
|
155
|
-
</Button>
|
|
156
|
-
</div>
|
|
157
|
-
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
|
158
|
-
<span>Created {getRelativeTime(key.created_at)}</span>
|
|
159
|
-
{key.last_used_at && (
|
|
160
|
-
<span>Last used {getRelativeTime(key.last_used_at)}</span>
|
|
161
|
-
)}
|
|
162
|
-
</div>
|
|
163
|
-
</div>
|
|
164
|
-
</div>
|
|
165
|
-
|
|
166
|
-
<DropdownMenu>
|
|
167
|
-
<DropdownMenuTrigger asChild>
|
|
168
|
-
<Button variant="ghost" size="sm">
|
|
169
|
-
<MoreHorizontal className="h-4 w-4" />
|
|
170
|
-
</Button>
|
|
171
|
-
</DropdownMenuTrigger>
|
|
172
|
-
<DropdownMenuContent align="end">
|
|
173
|
-
<DropdownMenuItem onClick={() => openEditApiKeyDialog(key.id)}>
|
|
174
|
-
<Edit className="h-4 w-4 mr-2" />
|
|
175
|
-
Edit
|
|
176
|
-
</DropdownMenuItem>
|
|
177
|
-
<DropdownMenuItem
|
|
178
|
-
onClick={() => openDeleteApiKeyDialog(key.id)}
|
|
179
|
-
className="text-destructive"
|
|
180
|
-
>
|
|
181
|
-
<Trash2 className="h-4 w-4 mr-2" />
|
|
182
|
-
Delete
|
|
183
|
-
</DropdownMenuItem>
|
|
184
|
-
</DropdownMenuContent>
|
|
185
|
-
</DropdownMenu>
|
|
186
|
-
</div>
|
|
187
|
-
))}
|
|
188
|
-
</div>
|
|
189
|
-
)}
|
|
190
|
-
</CardContent>
|
|
191
|
-
</Card>
|
|
192
|
-
);
|
|
193
|
-
};
|
|
194
|
-
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API Keys View
|
|
3
|
-
* Manage API keys for secure platform access
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use client';
|
|
7
|
-
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import { ApiKeyMetrics, ApiKeysList } from './components';
|
|
10
|
-
|
|
11
|
-
export const ApiKeysView: React.FC = () => {
|
|
12
|
-
return (
|
|
13
|
-
<div className="space-y-6">
|
|
14
|
-
<ApiKeyMetrics />
|
|
15
|
-
<ApiKeysList />
|
|
16
|
-
</div>
|
|
17
|
-
);
|
|
18
|
-
};
|
|
19
|
-
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Metrics Cards Component
|
|
3
|
-
* Display key payment metrics in cards
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use client';
|
|
7
|
-
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import {
|
|
10
|
-
Card,
|
|
11
|
-
CardContent,
|
|
12
|
-
CardHeader,
|
|
13
|
-
CardTitle,
|
|
14
|
-
Skeleton,
|
|
15
|
-
} from '@djangocfg/ui';
|
|
16
|
-
import { Wallet, TrendingUp, CreditCard, DollarSign } from 'lucide-react';
|
|
17
|
-
import { useOverviewContext } from '@djangocfg/api/cfg/contexts';
|
|
18
|
-
|
|
19
|
-
export const MetricsCards: React.FC = () => {
|
|
20
|
-
const { metrics, isLoadingOverview } = useOverviewContext();
|
|
21
|
-
|
|
22
|
-
const formatCurrency = (amount?: number | null) => {
|
|
23
|
-
if (amount === null || amount === undefined) return '$0.00';
|
|
24
|
-
return new Intl.NumberFormat('en-US', {
|
|
25
|
-
style: 'currency',
|
|
26
|
-
currency: 'USD',
|
|
27
|
-
minimumFractionDigits: 2,
|
|
28
|
-
}).format(amount);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
if (isLoadingOverview) {
|
|
32
|
-
return (
|
|
33
|
-
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
34
|
-
{Array.from({ length: 4 }).map((_, i) => (
|
|
35
|
-
<Card key={i}>
|
|
36
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
37
|
-
<Skeleton className="h-4 w-24" />
|
|
38
|
-
<Skeleton className="h-4 w-4 rounded-full" />
|
|
39
|
-
</CardHeader>
|
|
40
|
-
<CardContent>
|
|
41
|
-
<Skeleton className="h-7 w-20 mb-1" />
|
|
42
|
-
<Skeleton className="h-3 w-32" />
|
|
43
|
-
</CardContent>
|
|
44
|
-
</Card>
|
|
45
|
-
))}
|
|
46
|
-
</div>
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const metricsData = [
|
|
51
|
-
{
|
|
52
|
-
title: 'Current Balance',
|
|
53
|
-
value: formatCurrency(metrics?.balance?.current_balance),
|
|
54
|
-
description: 'Available funds',
|
|
55
|
-
icon: Wallet,
|
|
56
|
-
trend: null,
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
title: 'Total Payments',
|
|
60
|
-
value: metrics?.payments?.total_payments?.toString() || '0',
|
|
61
|
-
description: 'All-time payments',
|
|
62
|
-
icon: CreditCard,
|
|
63
|
-
trend: null,
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
title: 'Total Spent',
|
|
67
|
-
value: formatCurrency(metrics?.balance?.total_spent),
|
|
68
|
-
description: 'Lifetime spending',
|
|
69
|
-
icon: DollarSign,
|
|
70
|
-
trend: null,
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
title: 'Active API Keys',
|
|
74
|
-
value: metrics?.api_keys?.active_keys?.toString() || '0',
|
|
75
|
-
description: 'Currently active',
|
|
76
|
-
icon: TrendingUp,
|
|
77
|
-
trend: null,
|
|
78
|
-
},
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
83
|
-
{metricsData.map((metric, index) => {
|
|
84
|
-
const Icon = metric.icon;
|
|
85
|
-
return (
|
|
86
|
-
<Card key={index}>
|
|
87
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
88
|
-
<CardTitle className="text-sm font-medium">{metric.title}</CardTitle>
|
|
89
|
-
<Icon className="h-4 w-4 text-muted-foreground" />
|
|
90
|
-
</CardHeader>
|
|
91
|
-
<CardContent>
|
|
92
|
-
<div className="text-2xl font-bold">{metric.value}</div>
|
|
93
|
-
<p className="text-xs text-muted-foreground mt-1">
|
|
94
|
-
{metric.description}
|
|
95
|
-
</p>
|
|
96
|
-
</CardContent>
|
|
97
|
-
</Card>
|
|
98
|
-
);
|
|
99
|
-
})}
|
|
100
|
-
</div>
|
|
101
|
-
);
|
|
102
|
-
};
|
|
103
|
-
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tariffs View
|
|
3
|
-
* View and manage tariff plans
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use client';
|
|
7
|
-
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import { Card, CardContent } from '@djangocfg/ui';
|
|
10
|
-
import { Crown } from 'lucide-react';
|
|
11
|
-
|
|
12
|
-
export const TariffsView: React.FC = () => {
|
|
13
|
-
return (
|
|
14
|
-
<Card>
|
|
15
|
-
<CardContent className="py-12">
|
|
16
|
-
<div className="text-center">
|
|
17
|
-
<div className="w-16 h-16 mx-auto mb-4 bg-muted rounded-full flex items-center justify-center">
|
|
18
|
-
<Crown className="w-8 h-8 text-muted-foreground" />
|
|
19
|
-
</div>
|
|
20
|
-
<h3 className="text-lg font-semibold mb-2">Tariff Plans Coming Soon</h3>
|
|
21
|
-
<p className="text-muted-foreground">
|
|
22
|
-
Subscription tiers and pricing plans will be available here
|
|
23
|
-
</p>
|
|
24
|
-
</div>
|
|
25
|
-
</CardContent>
|
|
26
|
-
</Card>
|
|
27
|
-
);
|
|
28
|
-
};
|
|
29
|
-
|