@payez/next-mvp 4.1.7 → 4.1.9
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/README.md +792 -792
- package/dist/auth/better-auth.js +15 -3
- package/dist/components/account/MobileNavDrawer.js +18 -18
- package/dist/components/account/UserAvatarMenu.js +1 -1
- package/dist/components/admin/AlertSettingsTab.js +40 -40
- package/dist/components/admin/LoggingSettingsTab.js +28 -28
- package/dist/pages/login/page.js +28 -28
- package/dist/pages/settings/EnhancedSettingsPage.js +17 -17
- package/package.json +1 -1
- package/scripts/dev-broker.ps1 +35 -35
- package/scripts/dev-local.ps1 +45 -45
- package/src/api/auth-handler.ts +548 -548
- package/src/api-handlers/account/change-password.ts +142 -142
- package/src/api-handlers/account/update-phone.ts +79 -79
- package/src/api-handlers/account/verify-email.ts +125 -125
- package/src/api-handlers/account/verify-sms.ts +125 -125
- package/src/api-handlers/admin/analytics.ts +443 -443
- package/src/api-handlers/admin/audit.ts +223 -223
- package/src/api-handlers/admin/index.ts +63 -63
- package/src/api-handlers/admin/redis-sessions.ts +251 -251
- package/src/api-handlers/admin/sessions.ts +318 -318
- package/src/api-handlers/admin/site-logs.ts +365 -365
- package/src/api-handlers/admin/users.ts +242 -242
- package/src/api-handlers/admin/vibe-data.ts +324 -324
- package/src/api-handlers/auth/refresh.ts +682 -682
- package/src/api-handlers/auth/signout.ts +199 -199
- package/src/api-handlers/auth/status.ts +20 -20
- package/src/api-handlers/auth/update-session.ts +110 -110
- package/src/api-handlers/auth/verify-code.ts +112 -112
- package/src/api-handlers/session/refresh-viability.ts +36 -36
- package/src/api-handlers/test/force-expire.ts +60 -60
- package/src/auth/auth-decision.ts +229 -229
- package/src/auth/better-auth.ts +15 -3
- package/src/auth/route-config.ts +219 -219
- package/src/auth/types/auth-types.ts +555 -555
- package/src/auth/types/index.ts +7 -7
- package/src/auth/utils/idp-client.ts +445 -445
- package/src/auth/utils/index.ts +6 -6
- package/src/auth/utils/token-utils.ts +243 -243
- package/src/client/AuthContext.tsx +143 -143
- package/src/client/fetch-with-auth.ts +47 -47
- package/src/components/SessionSync.tsx +138 -138
- package/src/components/SignalRHealthCheck.tsx +131 -131
- package/src/components/account/MobileNavDrawer.tsx +305 -305
- package/src/components/account/UserAvatarMenu.tsx +266 -266
- package/src/components/account/index.ts +13 -13
- package/src/components/admin/AlertSettingsTab.tsx +728 -728
- package/src/components/admin/AnalyticsTab.tsx +703 -703
- package/src/components/admin/DataBrowserTab.tsx +505 -505
- package/src/components/admin/LoggingSettingsTab.tsx +665 -665
- package/src/components/admin/SessionsTab.tsx +414 -414
- package/src/components/admin/StatsTab.tsx +379 -379
- package/src/components/admin/VibeAdminLayout.tsx +187 -187
- package/src/components/admin/index.ts +59 -59
- package/src/components/auth/FederatedAuthSection.tsx +95 -95
- package/src/components/auth/ModeAwareLoginPage.tsx +135 -135
- package/src/components/auth/ModeAwareSignupPage.tsx +267 -267
- package/src/components/auth/TraditionalAuthSection.tsx +99 -99
- package/src/components/recovery/CompleteStep.tsx +36 -36
- package/src/components/recovery/InitiateRecoveryStep.tsx +68 -68
- package/src/components/recovery/SelectMethodStep.tsx +73 -73
- package/src/components/recovery/SetPasswordStep.tsx +97 -97
- package/src/components/recovery/VerifyCodeStep.tsx +90 -90
- package/src/components/reserved/ReservedRecoveryWarning.tsx +160 -160
- package/src/components/reserved/ReservedStatusBox.tsx +118 -118
- package/src/components/ui/BetaBadge.tsx +58 -58
- package/src/components/ui/Footer.tsx +93 -93
- package/src/config/env.ts +57 -57
- package/src/config/logger.ts +62 -62
- package/src/config/vibe-log-transport.ts +264 -264
- package/src/hooks/useAuth.ts +117 -117
- package/src/hooks/useAuthSettings.ts +97 -97
- package/src/hooks/useAvailableProviders.ts +120 -120
- package/src/hooks/usePasswordValidation.ts +127 -127
- package/src/hooks/usePublicAuthSettings.ts +149 -149
- package/src/hooks/useSessionExpiration.ts +101 -101
- package/src/hooks/useViabilitySession.ts +336 -336
- package/src/index.ts +60 -60
- package/src/lib/api-handler.ts +643 -643
- package/src/lib/app-slug.ts +178 -178
- package/src/lib/geolocation.ts +265 -265
- package/src/lib/idp-fetch.ts +110 -110
- package/src/lib/jwt-decode.ts +82 -82
- package/src/lib/roles.ts +177 -177
- package/src/lib/site-logger.ts +245 -245
- package/src/lib/standardized-client-api.ts +901 -901
- package/src/lib/test-aware-get-token.ts +41 -41
- package/src/lib/user-agent-parser.ts +252 -252
- package/src/logging/api/admin-analytics.ts +51 -51
- package/src/logging/api/audit-log.ts +53 -53
- package/src/logging/components/AdminAnalyticsLayout.tsx +49 -49
- package/src/logging/components/AuditLogViewer.tsx +125 -125
- package/src/logging/components/ErrorMetricsCard.tsx +98 -98
- package/src/logging/components/HealthMetricsCard.tsx +70 -70
- package/src/logging/hooks/useAdminAnalytics.ts +22 -22
- package/src/logging/hooks/useAuditLog.ts +24 -24
- package/src/logging/hooks/useErrorMetrics.ts +40 -40
- package/src/logging/hooks/useHealthMetrics.ts +44 -44
- package/src/logging/index.ts +18 -18
- package/src/logging/types/analytics.ts +81 -81
- package/src/logging/types/audit.ts +31 -31
- package/src/logging/types/index.ts +3 -3
- package/src/middleware/create-middleware.ts +663 -663
- package/src/middleware/rbac-check.ts +279 -279
- package/src/middleware/twofa-presets.ts +224 -224
- package/src/pages/admin-login/page.tsx +221 -221
- package/src/pages/admin-page-permissions/PagePermissionsAdminPage.tsx +527 -527
- package/src/pages/admin-page-permissions/index.ts +7 -7
- package/src/pages/admin-roles/RolesAdminPage.tsx +533 -533
- package/src/pages/admin-roles/modals.tsx +469 -469
- package/src/pages/client-admin/ClientSiteAdminPage.tsx +382 -382
- package/src/pages/client-admin/index.ts +33 -33
- package/src/pages/coming-soon/page.tsx +83 -83
- package/src/pages/login/page.tsx +456 -456
- package/src/pages/profile/EnhancedProfilePage.tsx +485 -485
- package/src/pages/profile/index.ts +9 -9
- package/src/pages/profile/page.tsx +166 -166
- package/src/pages/recovery/page.tsx +234 -234
- package/src/pages/roles/MyRolesPage.tsx +211 -211
- package/src/pages/roles/components.tsx +294 -294
- package/src/pages/roles/index.ts +17 -17
- package/src/pages/security/EnhancedSecurityPage.tsx +565 -565
- package/src/pages/security/index.ts +9 -9
- package/src/pages/security/page.tsx +507 -507
- package/src/pages/settings/EnhancedSettingsPage.tsx +642 -642
- package/src/pages/settings/index.ts +9 -9
- package/src/pages/settings/page.tsx +47 -47
- package/src/pages/showcase/ShowcasePage.tsx +532 -532
- package/src/pages/showcase/index.ts +13 -13
- package/src/pages/test-env/EmergencyLogoutPage.tsx +180 -180
- package/src/pages/test-env/JwtInspectPage.tsx +456 -456
- package/src/pages/test-env/RefreshTokenPage.tsx +157 -157
- package/src/pages/test-env/TestEnvPage.tsx +118 -118
- package/src/pages/test-env/index.ts +25 -25
- package/src/pages/verify-code/page.tsx +652 -652
- package/src/routes/account/update-phone.ts +13 -13
- package/src/routes/auth/logout.ts +108 -108
- package/src/routes/auth/nextauth.ts +45 -45
- package/src/routes/auth/settings.ts +75 -75
- package/src/routes/auth/viability.ts +224 -224
- package/src/server/auth-guard.ts +170 -170
- package/src/server/slim-middleware.ts +117 -117
- package/src/server/with-auth.ts +93 -93
- package/src/stores/authStore.ts +1899 -1899
- package/src/templates/instrumentation.ts +41 -41
- package/src/utils/logout.ts +30 -30
- package/src/vibe/client.ts +590 -590
- package/src/vibe/enterprise-auth.ts +208 -208
- package/src/vibe/errors.ts +185 -185
- package/src/vibe/generic.ts +431 -431
- package/src/vibe/hooks/index.ts +367 -367
- package/src/vibe/index.ts +132 -132
- package/src/vibe/sessions.ts +551 -551
- package/src/vibe/types.ts +577 -577
|
@@ -1,187 +1,187 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import React, { ReactNode } from 'react';
|
|
4
|
-
import { authClient } from '../../client/better-auth-client';
|
|
5
|
-
import { useRouter } from 'next/navigation';
|
|
6
|
-
import { useEffect } from 'react';
|
|
7
|
-
import Link from 'next/link';
|
|
8
|
-
import { useVibeAdmin } from './VibeAdminContext';
|
|
9
|
-
import {
|
|
10
|
-
Shield,
|
|
11
|
-
LayoutDashboard,
|
|
12
|
-
Users,
|
|
13
|
-
Activity,
|
|
14
|
-
BarChart3,
|
|
15
|
-
Database,
|
|
16
|
-
Settings,
|
|
17
|
-
ArrowLeft,
|
|
18
|
-
type LucideIcon,
|
|
19
|
-
} from 'lucide-react';
|
|
20
|
-
|
|
21
|
-
interface VibeAdminLayoutProps {
|
|
22
|
-
children?: ReactNode;
|
|
23
|
-
activeTabId?: string;
|
|
24
|
-
onTabChange?: (tabId: string) => void;
|
|
25
|
-
headerContent?: ReactNode;
|
|
26
|
-
isDarkMode?: boolean;
|
|
27
|
-
adminRole?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface NavItem {
|
|
31
|
-
id: string;
|
|
32
|
-
label: string;
|
|
33
|
-
icon: LucideIcon;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const defaultNavItems: NavItem[] = [
|
|
37
|
-
{ id: 'stats', label: 'Dashboard', icon: LayoutDashboard },
|
|
38
|
-
{ id: 'users', label: 'Users', icon: Users },
|
|
39
|
-
{ id: 'sessions', label: 'Sessions', icon: Activity },
|
|
40
|
-
{ id: 'analytics', label: 'Analytics', icon: BarChart3 },
|
|
41
|
-
{ id: 'data', label: 'Data Browser', icon: Database },
|
|
42
|
-
{ id: 'settings', label: 'Settings', icon: Settings },
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
export function VibeAdminLayout({
|
|
46
|
-
children,
|
|
47
|
-
activeTabId = 'stats',
|
|
48
|
-
onTabChange,
|
|
49
|
-
headerContent,
|
|
50
|
-
isDarkMode: isDarkModeProp,
|
|
51
|
-
adminRole = 'vibe_app_admin',
|
|
52
|
-
}: VibeAdminLayoutProps) {
|
|
53
|
-
const { data: sessionData, isPending } = authClient.useSession();
|
|
54
|
-
const session = sessionData;
|
|
55
|
-
const status = isPending ? 'loading' : session ? 'authenticated' : 'unauthenticated';
|
|
56
|
-
const router = useRouter();
|
|
57
|
-
const adminConfig = useVibeAdmin();
|
|
58
|
-
|
|
59
|
-
const isDark = isDarkModeProp ?? adminConfig.isDarkMode ?? false;
|
|
60
|
-
const basePath = adminConfig.basePath || '/vibe-admin';
|
|
61
|
-
|
|
62
|
-
const navItems = [...defaultNavItems];
|
|
63
|
-
adminConfig.customTabs?.forEach((tab) => {
|
|
64
|
-
navItems.push({
|
|
65
|
-
id: tab.id,
|
|
66
|
-
label: tab.label,
|
|
67
|
-
icon: (tab.icon as LucideIcon) || LayoutDashboard,
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const userRoles = (session?.user as any)?.roles || [];
|
|
72
|
-
const hasAdminRole = userRoles.includes(adminRole) || userRoles.includes('payez_admin');
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (status === 'unauthenticated') {
|
|
76
|
-
router.push('/account-auth/login?callbackUrl=' + basePath);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
if (status === 'authenticated' && !hasAdminRole) {
|
|
80
|
-
router.push('/?error=unauthorized');
|
|
81
|
-
}
|
|
82
|
-
}, [status, hasAdminRole, router, basePath]);
|
|
83
|
-
|
|
84
|
-
if (status === 'loading') {
|
|
85
|
-
return (
|
|
86
|
-
<div className={'min-h-screen flex items-center justify-center ' + (isDark ? 'bg-slate-950' : 'bg-gray-50')}>
|
|
87
|
-
<div className="flex flex-col items-center gap-4">
|
|
88
|
-
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-500" />
|
|
89
|
-
<p className={isDark ? 'text-slate-400' : 'text-slate-600'}>Loading...</p>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (status === 'authenticated' && !hasAdminRole) {
|
|
96
|
-
return (
|
|
97
|
-
<div className={'min-h-screen flex items-center justify-center ' + (isDark ? 'bg-slate-950' : 'bg-gray-50')}>
|
|
98
|
-
<div className="text-center">
|
|
99
|
-
<Shield className={'w-16 h-16 mx-auto mb-4 ' + (isDark ? 'text-red-400' : 'text-red-500')} />
|
|
100
|
-
<h1 className={'text-2xl font-bold mb-2 ' + (isDark ? 'text-white' : 'text-gray-900')}>
|
|
101
|
-
Access Denied
|
|
102
|
-
</h1>
|
|
103
|
-
<p className={'mb-6 ' + (isDark ? 'text-slate-400' : 'text-slate-600')}>
|
|
104
|
-
You do not have permission to access the admin panel.
|
|
105
|
-
</p>
|
|
106
|
-
<Link
|
|
107
|
-
href="/"
|
|
108
|
-
className="inline-flex items-center gap-2 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors"
|
|
109
|
-
>
|
|
110
|
-
<ArrowLeft className="w-4 h-4" />
|
|
111
|
-
Return to Home
|
|
112
|
-
</Link>
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (status === 'unauthenticated') {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return (
|
|
123
|
-
<div className={'min-h-screen ' + (isDark ? 'bg-slate-950 text-white' : 'bg-gray-50 text-gray-900')}>
|
|
124
|
-
<header className={'sticky top-0 z-40 border-b ' + (isDark ? 'bg-slate-900 border-slate-800' : 'bg-white border-gray-200')}>
|
|
125
|
-
<div className="container mx-auto px-4 py-4">
|
|
126
|
-
<div className="flex items-center justify-between">
|
|
127
|
-
<div className="flex items-center gap-3">
|
|
128
|
-
{adminConfig.logoUrl && (
|
|
129
|
-
<div className={'p-2 rounded-lg ' + (isDark ? 'bg-indigo-900/30' : 'bg-indigo-100')}>
|
|
130
|
-
<img src={adminConfig.logoUrl} alt={adminConfig.appName} className="w-6 h-6" />
|
|
131
|
-
</div>
|
|
132
|
-
)}
|
|
133
|
-
<div>
|
|
134
|
-
<h1 className="text-xl font-bold">Platform Admin</h1>
|
|
135
|
-
<p className={'text-sm ' + (isDark ? 'text-slate-400' : 'text-slate-600')}>
|
|
136
|
-
{adminConfig.appName} - {adminConfig.collectionName}
|
|
137
|
-
</p>
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
<div className="flex items-center gap-4">
|
|
141
|
-
{headerContent}
|
|
142
|
-
<Link
|
|
143
|
-
href="/"
|
|
144
|
-
className={'flex items-center gap-2 px-3 py-2 rounded-lg transition-colors ' + (isDark ? 'hover:bg-slate-800 text-slate-400' : 'hover:bg-gray-100 text-slate-600')}
|
|
145
|
-
>
|
|
146
|
-
<ArrowLeft className="w-4 h-4" />
|
|
147
|
-
Back to App
|
|
148
|
-
</Link>
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
151
|
-
</div>
|
|
152
|
-
</header>
|
|
153
|
-
|
|
154
|
-
<div className="container mx-auto px-4 py-4">
|
|
155
|
-
<nav className={'flex items-center gap-1 mb-6 border-b ' + (isDark ? 'border-slate-800' : 'border-gray-200')}>
|
|
156
|
-
{navItems.map((item) => {
|
|
157
|
-
const isActive = activeTabId === item.id;
|
|
158
|
-
const Icon = item.icon;
|
|
159
|
-
const activeClass = isDark
|
|
160
|
-
? 'border-indigo-500 text-indigo-400'
|
|
161
|
-
: 'border-indigo-600 text-indigo-700';
|
|
162
|
-
const inactiveClass = isDark
|
|
163
|
-
? 'border-transparent text-slate-400 hover:text-white hover:border-slate-600'
|
|
164
|
-
: 'border-transparent text-slate-600 hover:text-gray-900 hover:border-gray-300';
|
|
165
|
-
|
|
166
|
-
return (
|
|
167
|
-
<button
|
|
168
|
-
key={item.id}
|
|
169
|
-
onClick={() => onTabChange?.(item.id)}
|
|
170
|
-
className={'flex items-center gap-2 px-4 py-2.5 text-sm font-medium transition-colors border-b-2 -mb-px ' + (isActive ? activeClass : inactiveClass)}
|
|
171
|
-
>
|
|
172
|
-
<Icon className="w-4 h-4" />
|
|
173
|
-
{item.label}
|
|
174
|
-
</button>
|
|
175
|
-
);
|
|
176
|
-
})}
|
|
177
|
-
</nav>
|
|
178
|
-
|
|
179
|
-
<main className="min-w-0">
|
|
180
|
-
{children}
|
|
181
|
-
</main>
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export default VibeAdminLayout;
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import React, { ReactNode } from 'react';
|
|
4
|
+
import { authClient } from '../../client/better-auth-client';
|
|
5
|
+
import { useRouter } from 'next/navigation';
|
|
6
|
+
import { useEffect } from 'react';
|
|
7
|
+
import Link from 'next/link';
|
|
8
|
+
import { useVibeAdmin } from './VibeAdminContext';
|
|
9
|
+
import {
|
|
10
|
+
Shield,
|
|
11
|
+
LayoutDashboard,
|
|
12
|
+
Users,
|
|
13
|
+
Activity,
|
|
14
|
+
BarChart3,
|
|
15
|
+
Database,
|
|
16
|
+
Settings,
|
|
17
|
+
ArrowLeft,
|
|
18
|
+
type LucideIcon,
|
|
19
|
+
} from 'lucide-react';
|
|
20
|
+
|
|
21
|
+
interface VibeAdminLayoutProps {
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
activeTabId?: string;
|
|
24
|
+
onTabChange?: (tabId: string) => void;
|
|
25
|
+
headerContent?: ReactNode;
|
|
26
|
+
isDarkMode?: boolean;
|
|
27
|
+
adminRole?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface NavItem {
|
|
31
|
+
id: string;
|
|
32
|
+
label: string;
|
|
33
|
+
icon: LucideIcon;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const defaultNavItems: NavItem[] = [
|
|
37
|
+
{ id: 'stats', label: 'Dashboard', icon: LayoutDashboard },
|
|
38
|
+
{ id: 'users', label: 'Users', icon: Users },
|
|
39
|
+
{ id: 'sessions', label: 'Sessions', icon: Activity },
|
|
40
|
+
{ id: 'analytics', label: 'Analytics', icon: BarChart3 },
|
|
41
|
+
{ id: 'data', label: 'Data Browser', icon: Database },
|
|
42
|
+
{ id: 'settings', label: 'Settings', icon: Settings },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
export function VibeAdminLayout({
|
|
46
|
+
children,
|
|
47
|
+
activeTabId = 'stats',
|
|
48
|
+
onTabChange,
|
|
49
|
+
headerContent,
|
|
50
|
+
isDarkMode: isDarkModeProp,
|
|
51
|
+
adminRole = 'vibe_app_admin',
|
|
52
|
+
}: VibeAdminLayoutProps) {
|
|
53
|
+
const { data: sessionData, isPending } = authClient.useSession();
|
|
54
|
+
const session = sessionData;
|
|
55
|
+
const status = isPending ? 'loading' : session ? 'authenticated' : 'unauthenticated';
|
|
56
|
+
const router = useRouter();
|
|
57
|
+
const adminConfig = useVibeAdmin();
|
|
58
|
+
|
|
59
|
+
const isDark = isDarkModeProp ?? adminConfig.isDarkMode ?? false;
|
|
60
|
+
const basePath = adminConfig.basePath || '/vibe-admin';
|
|
61
|
+
|
|
62
|
+
const navItems = [...defaultNavItems];
|
|
63
|
+
adminConfig.customTabs?.forEach((tab) => {
|
|
64
|
+
navItems.push({
|
|
65
|
+
id: tab.id,
|
|
66
|
+
label: tab.label,
|
|
67
|
+
icon: (tab.icon as LucideIcon) || LayoutDashboard,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const userRoles = (session?.user as any)?.roles || [];
|
|
72
|
+
const hasAdminRole = userRoles.includes(adminRole) || userRoles.includes('payez_admin');
|
|
73
|
+
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (status === 'unauthenticated') {
|
|
76
|
+
router.push('/account-auth/login?callbackUrl=' + basePath);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (status === 'authenticated' && !hasAdminRole) {
|
|
80
|
+
router.push('/?error=unauthorized');
|
|
81
|
+
}
|
|
82
|
+
}, [status, hasAdminRole, router, basePath]);
|
|
83
|
+
|
|
84
|
+
if (status === 'loading') {
|
|
85
|
+
return (
|
|
86
|
+
<div className={'min-h-screen flex items-center justify-center ' + (isDark ? 'bg-slate-950' : 'bg-gray-50')}>
|
|
87
|
+
<div className="flex flex-col items-center gap-4">
|
|
88
|
+
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-500" />
|
|
89
|
+
<p className={isDark ? 'text-slate-400' : 'text-slate-600'}>Loading...</p>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (status === 'authenticated' && !hasAdminRole) {
|
|
96
|
+
return (
|
|
97
|
+
<div className={'min-h-screen flex items-center justify-center ' + (isDark ? 'bg-slate-950' : 'bg-gray-50')}>
|
|
98
|
+
<div className="text-center">
|
|
99
|
+
<Shield className={'w-16 h-16 mx-auto mb-4 ' + (isDark ? 'text-red-400' : 'text-red-500')} />
|
|
100
|
+
<h1 className={'text-2xl font-bold mb-2 ' + (isDark ? 'text-white' : 'text-gray-900')}>
|
|
101
|
+
Access Denied
|
|
102
|
+
</h1>
|
|
103
|
+
<p className={'mb-6 ' + (isDark ? 'text-slate-400' : 'text-slate-600')}>
|
|
104
|
+
You do not have permission to access the admin panel.
|
|
105
|
+
</p>
|
|
106
|
+
<Link
|
|
107
|
+
href="/"
|
|
108
|
+
className="inline-flex items-center gap-2 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors"
|
|
109
|
+
>
|
|
110
|
+
<ArrowLeft className="w-4 h-4" />
|
|
111
|
+
Return to Home
|
|
112
|
+
</Link>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (status === 'unauthenticated') {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<div className={'min-h-screen ' + (isDark ? 'bg-slate-950 text-white' : 'bg-gray-50 text-gray-900')}>
|
|
124
|
+
<header className={'sticky top-0 z-40 border-b ' + (isDark ? 'bg-slate-900 border-slate-800' : 'bg-white border-gray-200')}>
|
|
125
|
+
<div className="container mx-auto px-4 py-4">
|
|
126
|
+
<div className="flex items-center justify-between">
|
|
127
|
+
<div className="flex items-center gap-3">
|
|
128
|
+
{adminConfig.logoUrl && (
|
|
129
|
+
<div className={'p-2 rounded-lg ' + (isDark ? 'bg-indigo-900/30' : 'bg-indigo-100')}>
|
|
130
|
+
<img src={adminConfig.logoUrl} alt={adminConfig.appName} className="w-6 h-6" />
|
|
131
|
+
</div>
|
|
132
|
+
)}
|
|
133
|
+
<div>
|
|
134
|
+
<h1 className="text-xl font-bold">Platform Admin</h1>
|
|
135
|
+
<p className={'text-sm ' + (isDark ? 'text-slate-400' : 'text-slate-600')}>
|
|
136
|
+
{adminConfig.appName} - {adminConfig.collectionName}
|
|
137
|
+
</p>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
<div className="flex items-center gap-4">
|
|
141
|
+
{headerContent}
|
|
142
|
+
<Link
|
|
143
|
+
href="/"
|
|
144
|
+
className={'flex items-center gap-2 px-3 py-2 rounded-lg transition-colors ' + (isDark ? 'hover:bg-slate-800 text-slate-400' : 'hover:bg-gray-100 text-slate-600')}
|
|
145
|
+
>
|
|
146
|
+
<ArrowLeft className="w-4 h-4" />
|
|
147
|
+
Back to App
|
|
148
|
+
</Link>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</header>
|
|
153
|
+
|
|
154
|
+
<div className="container mx-auto px-4 py-4">
|
|
155
|
+
<nav className={'flex items-center gap-1 mb-6 border-b ' + (isDark ? 'border-slate-800' : 'border-gray-200')}>
|
|
156
|
+
{navItems.map((item) => {
|
|
157
|
+
const isActive = activeTabId === item.id;
|
|
158
|
+
const Icon = item.icon;
|
|
159
|
+
const activeClass = isDark
|
|
160
|
+
? 'border-indigo-500 text-indigo-400'
|
|
161
|
+
: 'border-indigo-600 text-indigo-700';
|
|
162
|
+
const inactiveClass = isDark
|
|
163
|
+
? 'border-transparent text-slate-400 hover:text-white hover:border-slate-600'
|
|
164
|
+
: 'border-transparent text-slate-600 hover:text-gray-900 hover:border-gray-300';
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<button
|
|
168
|
+
key={item.id}
|
|
169
|
+
onClick={() => onTabChange?.(item.id)}
|
|
170
|
+
className={'flex items-center gap-2 px-4 py-2.5 text-sm font-medium transition-colors border-b-2 -mb-px ' + (isActive ? activeClass : inactiveClass)}
|
|
171
|
+
>
|
|
172
|
+
<Icon className="w-4 h-4" />
|
|
173
|
+
{item.label}
|
|
174
|
+
</button>
|
|
175
|
+
);
|
|
176
|
+
})}
|
|
177
|
+
</nav>
|
|
178
|
+
|
|
179
|
+
<main className="min-w-0">
|
|
180
|
+
{children}
|
|
181
|
+
</main>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export default VibeAdminLayout;
|
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* =============================================================================
|
|
3
|
-
* VIBE ADMIN COMPONENTS
|
|
4
|
-
* =============================================================================
|
|
5
|
-
*
|
|
6
|
-
* Generic admin panel components for Vibe-powered applications.
|
|
7
|
-
* These components are designed to be multi-tenant and can be configured
|
|
8
|
-
* per-collection via the VibeAdminProvider.
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* ------
|
|
12
|
-
* import {
|
|
13
|
-
* VibeAdminProvider,
|
|
14
|
-
* VibeAdminLayout,
|
|
15
|
-
* SessionsTab,
|
|
16
|
-
* AnalyticsTab,
|
|
17
|
-
* StatsTab,
|
|
18
|
-
* } from '@payez/next-mvp/components/admin';
|
|
19
|
-
*
|
|
20
|
-
* =============================================================================
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
// Context & Provider
|
|
24
|
-
export {
|
|
25
|
-
VibeAdminProvider,
|
|
26
|
-
useVibeAdmin,
|
|
27
|
-
type VibeAdminConfig,
|
|
28
|
-
type AdminTab,
|
|
29
|
-
type VibeAdminContextValue,
|
|
30
|
-
} from './VibeAdminContext';
|
|
31
|
-
|
|
32
|
-
// Layout
|
|
33
|
-
export { VibeAdminLayout } from './VibeAdminLayout';
|
|
34
|
-
|
|
35
|
-
// Tab Components
|
|
36
|
-
export { SessionsTab, type SessionsTabProps, type LoginSession, type SessionStats } from './SessionsTab';
|
|
37
|
-
export { AnalyticsTab, type AnalyticsTabProps } from './AnalyticsTab';
|
|
38
|
-
export { StatsTab, type StatsTabProps, type StatCard, type QuickAction, type RecentActivity, type SystemStatus } from './StatsTab';
|
|
39
|
-
export { DataBrowserTab, type DataBrowserTabProps, type CollectionInfo, type TableInfo } from './DataBrowserTab';
|
|
40
|
-
export {
|
|
41
|
-
LoggingSettingsTab,
|
|
42
|
-
type LoggingSettingsTabProps,
|
|
43
|
-
type LogLevel,
|
|
44
|
-
type LogLevels,
|
|
45
|
-
type RetentionSettings,
|
|
46
|
-
type StorageLimits,
|
|
47
|
-
type UsageStats,
|
|
48
|
-
type LoggingSettings,
|
|
49
|
-
} from './LoggingSettingsTab';
|
|
50
|
-
export {
|
|
51
|
-
AlertSettingsTab,
|
|
52
|
-
type AlertSettingsTabProps,
|
|
53
|
-
type DeliveryMode,
|
|
54
|
-
type AlertConfig,
|
|
55
|
-
type AlertsConfig,
|
|
56
|
-
type RateLimit,
|
|
57
|
-
type AlertSettings,
|
|
58
|
-
type AlertHistoryItem,
|
|
59
|
-
} from './AlertSettingsTab';
|
|
1
|
+
/**
|
|
2
|
+
* =============================================================================
|
|
3
|
+
* VIBE ADMIN COMPONENTS
|
|
4
|
+
* =============================================================================
|
|
5
|
+
*
|
|
6
|
+
* Generic admin panel components for Vibe-powered applications.
|
|
7
|
+
* These components are designed to be multi-tenant and can be configured
|
|
8
|
+
* per-collection via the VibeAdminProvider.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ------
|
|
12
|
+
* import {
|
|
13
|
+
* VibeAdminProvider,
|
|
14
|
+
* VibeAdminLayout,
|
|
15
|
+
* SessionsTab,
|
|
16
|
+
* AnalyticsTab,
|
|
17
|
+
* StatsTab,
|
|
18
|
+
* } from '@payez/next-mvp/components/admin';
|
|
19
|
+
*
|
|
20
|
+
* =============================================================================
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// Context & Provider
|
|
24
|
+
export {
|
|
25
|
+
VibeAdminProvider,
|
|
26
|
+
useVibeAdmin,
|
|
27
|
+
type VibeAdminConfig,
|
|
28
|
+
type AdminTab,
|
|
29
|
+
type VibeAdminContextValue,
|
|
30
|
+
} from './VibeAdminContext';
|
|
31
|
+
|
|
32
|
+
// Layout
|
|
33
|
+
export { VibeAdminLayout } from './VibeAdminLayout';
|
|
34
|
+
|
|
35
|
+
// Tab Components
|
|
36
|
+
export { SessionsTab, type SessionsTabProps, type LoginSession, type SessionStats } from './SessionsTab';
|
|
37
|
+
export { AnalyticsTab, type AnalyticsTabProps } from './AnalyticsTab';
|
|
38
|
+
export { StatsTab, type StatsTabProps, type StatCard, type QuickAction, type RecentActivity, type SystemStatus } from './StatsTab';
|
|
39
|
+
export { DataBrowserTab, type DataBrowserTabProps, type CollectionInfo, type TableInfo } from './DataBrowserTab';
|
|
40
|
+
export {
|
|
41
|
+
LoggingSettingsTab,
|
|
42
|
+
type LoggingSettingsTabProps,
|
|
43
|
+
type LogLevel,
|
|
44
|
+
type LogLevels,
|
|
45
|
+
type RetentionSettings,
|
|
46
|
+
type StorageLimits,
|
|
47
|
+
type UsageStats,
|
|
48
|
+
type LoggingSettings,
|
|
49
|
+
} from './LoggingSettingsTab';
|
|
50
|
+
export {
|
|
51
|
+
AlertSettingsTab,
|
|
52
|
+
type AlertSettingsTabProps,
|
|
53
|
+
type DeliveryMode,
|
|
54
|
+
type AlertConfig,
|
|
55
|
+
type AlertsConfig,
|
|
56
|
+
type RateLimit,
|
|
57
|
+
type AlertSettings,
|
|
58
|
+
type AlertHistoryItem,
|
|
59
|
+
} from './AlertSettingsTab';
|