@rovela-ai/sdk 0.18.6 → 0.19.0
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/admin/components/AdminAccountPage.d.ts.map +1 -1
- package/dist/admin/components/AdminAccountPage.js +44 -29
- package/dist/admin/components/AdminAccountPage.js.map +1 -1
- package/dist/admin/components/AdminEmptyState.d.ts +33 -0
- package/dist/admin/components/AdminEmptyState.d.ts.map +1 -0
- package/dist/admin/components/AdminEmptyState.js +12 -0
- package/dist/admin/components/AdminEmptyState.js.map +1 -0
- package/dist/admin/components/AdminLoginForm.js +1 -1
- package/dist/admin/components/AdminLoginForm.js.map +1 -1
- package/dist/admin/components/AdminModal.d.ts +51 -0
- package/dist/admin/components/AdminModal.d.ts.map +1 -0
- package/dist/admin/components/AdminModal.js +118 -0
- package/dist/admin/components/AdminModal.js.map +1 -0
- package/dist/admin/components/AdminPagination.d.ts +22 -0
- package/dist/admin/components/AdminPagination.d.ts.map +1 -0
- package/dist/admin/components/AdminPagination.js +15 -0
- package/dist/admin/components/AdminPagination.js.map +1 -0
- package/dist/admin/components/AdminSearchInput.d.ts +14 -0
- package/dist/admin/components/AdminSearchInput.d.ts.map +1 -0
- package/dist/admin/components/AdminSearchInput.js +56 -0
- package/dist/admin/components/AdminSearchInput.js.map +1 -0
- package/dist/admin/components/AdminSelect.d.ts +3 -1
- package/dist/admin/components/AdminSelect.d.ts.map +1 -1
- package/dist/admin/components/AdminSelect.js +2 -2
- package/dist/admin/components/AdminSelect.js.map +1 -1
- package/dist/admin/components/AdminSwitch.d.ts +20 -0
- package/dist/admin/components/AdminSwitch.d.ts.map +1 -0
- package/dist/admin/components/AdminSwitch.js +9 -0
- package/dist/admin/components/AdminSwitch.js.map +1 -0
- package/dist/admin/components/AdminUserMenu.js +1 -1
- package/dist/admin/components/BrandingAssetUpload.d.ts.map +1 -1
- package/dist/admin/components/BrandingAssetUpload.js +3 -3
- package/dist/admin/components/BrandingAssetUpload.js.map +1 -1
- package/dist/admin/components/CategoryForm.d.ts.map +1 -1
- package/dist/admin/components/CategoryForm.js +19 -10
- package/dist/admin/components/CategoryForm.js.map +1 -1
- package/dist/admin/components/CategorySelect.js +2 -2
- package/dist/admin/components/CategorySelect.js.map +1 -1
- package/dist/admin/components/CustomerAddressPanel.d.ts.map +1 -1
- package/dist/admin/components/CustomerAddressPanel.js +9 -5
- package/dist/admin/components/CustomerAddressPanel.js.map +1 -1
- package/dist/admin/components/CustomerDetails.d.ts.map +1 -1
- package/dist/admin/components/CustomerDetails.js +54 -33
- package/dist/admin/components/CustomerDetails.js.map +1 -1
- package/dist/admin/components/CustomerGroupsManager.d.ts.map +1 -1
- package/dist/admin/components/CustomerGroupsManager.js +4 -2
- package/dist/admin/components/CustomerGroupsManager.js.map +1 -1
- package/dist/admin/components/CustomerTable.d.ts.map +1 -1
- package/dist/admin/components/CustomerTable.js +14 -13
- package/dist/admin/components/CustomerTable.js.map +1 -1
- package/dist/admin/components/DeleteConfirmDialog.d.ts +5 -5
- package/dist/admin/components/DeleteConfirmDialog.d.ts.map +1 -1
- package/dist/admin/components/DeleteConfirmDialog.js +11 -8
- package/dist/admin/components/DeleteConfirmDialog.js.map +1 -1
- package/dist/admin/components/DiscardChangesModal.d.ts +9 -0
- package/dist/admin/components/DiscardChangesModal.d.ts.map +1 -0
- package/dist/admin/components/DiscardChangesModal.js +19 -0
- package/dist/admin/components/DiscardChangesModal.js.map +1 -0
- package/dist/admin/components/DiscountsManager.d.ts.map +1 -1
- package/dist/admin/components/DiscountsManager.js +81 -28
- package/dist/admin/components/DiscountsManager.js.map +1 -1
- package/dist/admin/components/EmailsManager.d.ts.map +1 -1
- package/dist/admin/components/EmailsManager.js +128 -54
- package/dist/admin/components/EmailsManager.js.map +1 -1
- package/dist/admin/components/FilesManager.d.ts.map +1 -1
- package/dist/admin/components/FilesManager.js +9 -4
- package/dist/admin/components/FilesManager.js.map +1 -1
- package/dist/admin/components/InventoryEditor.js +1 -1
- package/dist/admin/components/InventoryEditor.js.map +1 -1
- package/dist/admin/components/InviteUserDialog.d.ts.map +1 -1
- package/dist/admin/components/InviteUserDialog.js +12 -16
- package/dist/admin/components/InviteUserDialog.js.map +1 -1
- package/dist/admin/components/LocationsManager.d.ts.map +1 -1
- package/dist/admin/components/LocationsManager.js +54 -22
- package/dist/admin/components/LocationsManager.js.map +1 -1
- package/dist/admin/components/MediaLibraryPicker.d.ts.map +1 -1
- package/dist/admin/components/MediaLibraryPicker.js +22 -15
- package/dist/admin/components/MediaLibraryPicker.js.map +1 -1
- package/dist/admin/components/OrderDetails.d.ts.map +1 -1
- package/dist/admin/components/OrderDetails.js +10 -34
- package/dist/admin/components/OrderDetails.js.map +1 -1
- package/dist/admin/components/OrderStatusChart.js +1 -1
- package/dist/admin/components/OrderStatusChart.js.map +1 -1
- package/dist/admin/components/OrderTable.d.ts.map +1 -1
- package/dist/admin/components/OrderTable.js +14 -13
- package/dist/admin/components/OrderTable.js.map +1 -1
- package/dist/admin/components/PaymentMethodsManager.d.ts.map +1 -1
- package/dist/admin/components/PaymentMethodsManager.js +4 -2
- package/dist/admin/components/PaymentMethodsManager.js.map +1 -1
- package/dist/admin/components/PaymentSettings.d.ts.map +1 -1
- package/dist/admin/components/PaymentSettings.js +2 -2
- package/dist/admin/components/PaymentSettings.js.map +1 -1
- package/dist/admin/components/PermissionsMatrix.js +1 -1
- package/dist/admin/components/PermissionsMatrix.js.map +1 -1
- package/dist/admin/components/PrimaryMetricsRow.d.ts.map +1 -1
- package/dist/admin/components/PrimaryMetricsRow.js +4 -1
- package/dist/admin/components/PrimaryMetricsRow.js.map +1 -1
- package/dist/admin/components/ProductForm.d.ts.map +1 -1
- package/dist/admin/components/ProductForm.js +25 -10
- package/dist/admin/components/ProductForm.js.map +1 -1
- package/dist/admin/components/ProductTable.d.ts.map +1 -1
- package/dist/admin/components/ProductTable.js +14 -5
- package/dist/admin/components/ProductTable.js.map +1 -1
- package/dist/admin/components/RecentOrders.d.ts.map +1 -1
- package/dist/admin/components/RecentOrders.js +3 -16
- package/dist/admin/components/RecentOrders.js.map +1 -1
- package/dist/admin/components/RefundDialog.d.ts +1 -1
- package/dist/admin/components/RefundDialog.d.ts.map +1 -1
- package/dist/admin/components/RefundDialog.js +7 -17
- package/dist/admin/components/RefundDialog.js.map +1 -1
- package/dist/admin/components/RevenueChart.js +1 -1
- package/dist/admin/components/RevenueChart.js.map +1 -1
- package/dist/admin/components/SEOPreview.js +1 -1
- package/dist/admin/components/SEOPreview.js.map +1 -1
- package/dist/admin/components/SecondaryMetricsRow.d.ts.map +1 -1
- package/dist/admin/components/SecondaryMetricsRow.js +6 -1
- package/dist/admin/components/SecondaryMetricsRow.js.map +1 -1
- package/dist/admin/components/ShippingSettings.d.ts.map +1 -1
- package/dist/admin/components/ShippingSettings.js +22 -31
- package/dist/admin/components/ShippingSettings.js.map +1 -1
- package/dist/admin/components/StatsCards.d.ts.map +1 -1
- package/dist/admin/components/StatsCards.js +4 -1
- package/dist/admin/components/StatsCards.js.map +1 -1
- package/dist/admin/components/TagInput.d.ts +1 -1
- package/dist/admin/components/TagInput.js +1 -1
- package/dist/admin/components/TaxSettings.d.ts.map +1 -1
- package/dist/admin/components/TaxSettings.js +20 -19
- package/dist/admin/components/TaxSettings.js.map +1 -1
- package/dist/admin/components/UsersTable.d.ts.map +1 -1
- package/dist/admin/components/UsersTable.js +21 -20
- package/dist/admin/components/UsersTable.js.map +1 -1
- package/dist/admin/components/VariantManager.d.ts.map +1 -1
- package/dist/admin/components/VariantManager.js +5 -5
- package/dist/admin/components/VariantManager.js.map +1 -1
- package/dist/admin/components/emails/ColorField.d.ts.map +1 -1
- package/dist/admin/components/emails/ColorField.js +1 -1
- package/dist/admin/components/emails/ColorField.js.map +1 -1
- package/dist/admin/components/emails/EmailPreviewPane.js +1 -1
- package/dist/admin/components/emails/EmailPreviewPane.js.map +1 -1
- package/dist/admin/components/emails/EmailThemePanel.d.ts +4 -2
- package/dist/admin/components/emails/EmailThemePanel.d.ts.map +1 -1
- package/dist/admin/components/emails/EmailThemePanel.js +2 -2
- package/dist/admin/components/emails/EmailThemePanel.js.map +1 -1
- package/dist/admin/components/emails/FontPicker.js +2 -2
- package/dist/admin/components/emails/FontPicker.js.map +1 -1
- package/dist/admin/components/index.d.ts +13 -0
- package/dist/admin/components/index.d.ts.map +1 -1
- package/dist/admin/components/index.js +8 -0
- package/dist/admin/components/index.js.map +1 -1
- package/dist/admin/components/statusBadges.d.ts +12 -0
- package/dist/admin/components/statusBadges.d.ts.map +1 -0
- package/dist/admin/components/statusBadges.js +50 -0
- package/dist/admin/components/statusBadges.js.map +1 -0
- package/dist/admin/hooks/useDirtyState.d.ts.map +1 -1
- package/dist/admin/hooks/useDirtyState.js +7 -0
- package/dist/admin/hooks/useDirtyState.js.map +1 -1
- package/dist/admin/index.d.ts +2 -2
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/styles/admin-theme.css +96 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminAccountPage.d.ts","sourceRoot":"","sources":["../../../src/admin/components/AdminAccountPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AdminAccountPage.d.ts","sourceRoot":"","sources":["../../../src/admin/components/AdminAccountPage.tsx"],"names":[],"mappings":"AA8BA,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAMD,wBAAgB,gBAAgB,CAAC,EAC/B,SAAc,EACd,QAAyB,EACzB,eAAsB,GACvB,EAAE,qBAAqB,2CAoWvB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
/**
|
|
4
4
|
* @rovela/sdk/admin/components/AdminAccountPage
|
|
5
5
|
*
|
|
@@ -16,11 +16,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
16
16
|
* Styled with the shared admin-theme classes, matching AdminLoginForm and
|
|
17
17
|
* the rest of the admin panel.
|
|
18
18
|
*/
|
|
19
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
19
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
20
20
|
import { User, KeyRound, Mail, CheckCircle2, AlertCircle } from 'lucide-react';
|
|
21
21
|
import { AdminPageHeader } from './AdminPageHeader';
|
|
22
22
|
import { useAdminMe } from '../hooks/useAdminMe';
|
|
23
|
-
import {
|
|
23
|
+
import { AdminModal } from './AdminModal';
|
|
24
|
+
import { AdminSaveBar } from './AdminSaveBar';
|
|
24
25
|
// =============================================================================
|
|
25
26
|
// Component
|
|
26
27
|
// =============================================================================
|
|
@@ -30,10 +31,8 @@ export function AdminAccountPage({ className = '', loginUrl = '/admin/login', re
|
|
|
30
31
|
const [name, setName] = useState('');
|
|
31
32
|
const [email, setEmail] = useState('');
|
|
32
33
|
const [originalEmail, setOriginalEmail] = useState('');
|
|
33
|
-
const [profileSaving, setProfileSaving] = useState(false);
|
|
34
|
-
const [profileError, setProfileError] = useState(null);
|
|
35
34
|
const [showEmailWarning, setShowEmailWarning] = useState(false);
|
|
36
|
-
// Seed form fields once `me` loads.
|
|
35
|
+
// Seed form fields once `me` loads (and re-seed after a save refetch).
|
|
37
36
|
// Pattern C — populate state from async-loaded data.
|
|
38
37
|
// Alternative is a data-fetching library (TanStack Query / SWR).
|
|
39
38
|
useEffect(() => {
|
|
@@ -45,30 +44,44 @@ export function AdminAccountPage({ className = '', loginUrl = '/admin/login', re
|
|
|
45
44
|
}
|
|
46
45
|
}, [me]);
|
|
47
46
|
const emailChanged = email.trim().toLowerCase() !== originalEmail.toLowerCase();
|
|
47
|
+
// Dirty is a live compare against `me` (not useDirtyState): the source of
|
|
48
|
+
// truth re-seeds the fields after every save refetch, so snapshot capture
|
|
49
|
+
// timing can never produce phantom dirt here.
|
|
48
50
|
const profileDirty = me ? (name.trim() !== me.name || emailChanged) : false;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
// Email-change confirm interlock: the bar's onSave awaits the modal's
|
|
52
|
+
// answer through this resolver. Confirm proceeds; Cancel reverts the email
|
|
53
|
+
// field to the current address (declining the change IS discarding that
|
|
54
|
+
// edit) so the bar never has to surface a fake error.
|
|
55
|
+
const emailConfirmResolver = useRef(null);
|
|
56
|
+
const doProfileSave = useCallback(async () => {
|
|
57
|
+
if (!me)
|
|
58
|
+
return { success: false, error: 'Account not loaded' };
|
|
59
|
+
let sendEmail = emailChanged;
|
|
60
|
+
if (emailChanged) {
|
|
61
|
+
const ok = await new Promise((resolve) => {
|
|
62
|
+
emailConfirmResolver.current = resolve;
|
|
63
|
+
setShowEmailWarning(true);
|
|
64
|
+
});
|
|
65
|
+
setShowEmailWarning(false);
|
|
66
|
+
emailConfirmResolver.current = null;
|
|
67
|
+
if (!ok) {
|
|
68
|
+
setEmail(originalEmail);
|
|
69
|
+
sendEmail = false;
|
|
70
|
+
// Only the email had changed — nothing left to save; the fields now
|
|
71
|
+
// match the server again, so a clean "Saved" morph is honest.
|
|
72
|
+
if (name.trim() === me.name)
|
|
73
|
+
return { success: true };
|
|
74
|
+
}
|
|
56
75
|
}
|
|
57
|
-
setProfileSaving(true);
|
|
58
76
|
const result = await updateProfile({
|
|
59
|
-
name: name.trim() !== me
|
|
60
|
-
email:
|
|
77
|
+
name: name.trim() !== me.name ? name.trim() : undefined,
|
|
78
|
+
email: sendEmail ? email.trim() : undefined,
|
|
61
79
|
});
|
|
62
|
-
setProfileSaving(false);
|
|
63
|
-
setShowEmailWarning(false);
|
|
64
80
|
if (!result.success) {
|
|
65
|
-
|
|
66
|
-
return;
|
|
81
|
+
return { success: false, error: result.error || 'Failed to update profile.' };
|
|
67
82
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
adminToast.success('Profile updated');
|
|
71
|
-
}, [emailChanged, showEmailWarning, me, name, email, updateProfile]);
|
|
83
|
+
return { success: true };
|
|
84
|
+
}, [me, emailChanged, name, email, originalEmail, updateProfile]);
|
|
72
85
|
// --- Password form state -----------------------------------------------
|
|
73
86
|
const [currentPassword, setCurrentPassword] = useState('');
|
|
74
87
|
const [newPassword, setNewPassword] = useState('');
|
|
@@ -115,12 +128,14 @@ export function AdminAccountPage({ className = '', loginUrl = '/admin/login', re
|
|
|
115
128
|
if (error || !me) {
|
|
116
129
|
return (_jsx("div", { className: `space-y-4 ${className}`, children: _jsx("div", { className: "admin-alert admin-alert-error", children: _jsx("div", { className: "admin-alert-description", children: error || 'Unable to load your account.' }) }) }));
|
|
117
130
|
}
|
|
118
|
-
return (_jsxs("div", { className: `space-y-6 ${className}`, children: [_jsx(AdminPageHeader, { title: "My account", subtitle: "Manage your profile and password." }), _jsxs("div", { className: "admin-card p-6", children: [_jsxs("div", { className: "flex items-center gap-2 mb-4", children: [_jsx(User, { className: "h-5 w-5 admin-icon-primary" }), _jsx("h2", { className: "text-lg font-semibold", children: "Profile" })] }), _jsxs("form", { onSubmit:
|
|
119
|
-
background: 'hsl(var(--admin-card))',
|
|
120
|
-
border: '1px solid hsl(var(--admin-border))',
|
|
121
|
-
}, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "flex items-start gap-3 mb-4", children: [_jsx("div", { className: "flex-shrink-0 h-10 w-10 rounded-full flex items-center justify-center", style: { background: 'hsl(var(--admin-warning) / 0.1)' }, children: _jsx(AlertCircle, { className: "h-5 w-5 text-[hsl(var(--admin-warning,0_95%_55%))]" }) }), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-1", children: "Change email?" }), _jsxs("p", { className: "text-sm admin-text-muted", children: ["Your sign-in email will change from", ' ', _jsx("strong", { children: originalEmail }), " to", ' ', _jsx("strong", { children: email }), ". Future forgot-password emails will go to the new address. Make sure you can receive email there."] })] })] }), _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx("button", { type: "button", onClick: () => setShowEmailWarning(false), disabled: profileSaving, className: "admin-btn admin-btn-secondary", children: "Cancel" }), _jsx("button", { type: "button", onClick: (e) => handleProfileSubmit(e), disabled: profileSaving, className: "admin-btn admin-btn-primary", children: profileSaving ? 'Saving...' : 'Yes, change email' })] })] }) }))] }), _jsxs("div", { className: "admin-card p-6", children: [_jsxs("div", { className: "flex items-center gap-2 mb-4", children: [_jsx(KeyRound, { className: "h-5 w-5 admin-icon-primary" }), _jsx("h2", { className: "text-lg font-semibold", children: "Password" })] }), passwordSuccess ? (_jsxs("div", { className: "text-center py-6", children: [_jsx("div", { className: "admin-icon-container-sm mx-auto mb-4", children: _jsx(CheckCircle2, { className: "h-6 w-6 admin-icon-primary" }) }), _jsx("h3", { className: "admin-heading-2 mb-2", children: "Password changed" }), _jsx("p", { className: "text-sm admin-text-muted", children: "For your security, all sessions have been signed out. Redirecting to sign in..." })] })) : (_jsxs("form", { onSubmit: handlePasswordSubmit, className: "space-y-4", children: [passwordError && (_jsx("div", { className: "admin-alert admin-alert-error", children: _jsx("div", { className: "admin-alert-description", children: passwordError }) })), _jsxs("div", { children: [_jsx("label", { htmlFor: "current-password", className: "admin-label admin-label-required", children: "Current password" }), _jsx("input", { id: "current-password", type: "password", value: currentPassword, onChange: (e) => setCurrentPassword(e.target.value), required: true, autoComplete: "current-password", disabled: passwordSaving, className: "admin-input w-full" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "new-password", className: "admin-label admin-label-required", children: "New password" }), _jsx("input", { id: "new-password", type: "password", value: newPassword, onChange: (e) => setNewPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: passwordSaving, className: "admin-input w-full", placeholder: "At least 8 characters" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "confirm-new-password", className: "admin-label admin-label-required", children: "Confirm new password" }), _jsx("input", { id: "confirm-new-password", type: "password", value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: passwordSaving, className: "admin-input w-full" })] }), _jsx("p", { className: "text-xs admin-text-muted", children: "After changing your password, you'll be signed out and need to sign back in." }), _jsx("div", { className: "flex items-center justify-end pt-2", children: _jsx("button", { type: "submit", disabled: passwordSaving ||
|
|
131
|
+
return (_jsxs("div", { className: `space-y-6 ${className}`, children: [_jsx(AdminPageHeader, { title: "My account", subtitle: "Manage your profile and password." }), _jsxs("div", { className: "admin-card p-6", children: [_jsxs("div", { className: "flex items-center gap-2 mb-4", children: [_jsx(User, { className: "h-5 w-5 admin-icon-primary" }), _jsx("h2", { className: "text-lg font-semibold", children: "Profile" })] }), _jsxs("form", { onSubmit: (e) => e.preventDefault(), className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "account-name", className: "admin-label", children: "Name" }), _jsx("input", { id: "account-name", type: "text", value: name, onChange: (e) => setName(e.target.value), required: true, minLength: 2, className: "admin-input w-full" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "account-email", className: "admin-label", children: "Email" }), _jsxs("div", { className: "admin-input-with-icon", children: [_jsx(Mail, { className: "admin-input-with-icon-left h-4 w-4" }), _jsx("input", { id: "account-email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, className: "admin-input w-full" })] }), _jsx("p", { className: "text-xs admin-text-muted mt-1", children: "Used for sign-in and forgot-password emails." })] }), _jsxs("div", { children: [_jsx("label", { className: "admin-label", children: "Role" }), _jsxs("div", { className: "text-sm admin-text-muted", children: [me.role, " (managed by the store owner)"] })] })] }), _jsx(AdminModal, { open: showEmailWarning, onClose: () => emailConfirmResolver.current?.(false), title: "Change email?", description: `Your sign-in email will change from ${originalEmail} to ${email}. Future forgot-password emails will go to the new address. Make sure you can receive email there.`, icon: _jsx(AlertCircle, { className: "h-5 w-5" }), iconTone: "warning", footer: _jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: () => emailConfirmResolver.current?.(false), className: "admin-btn admin-btn-secondary", children: "Keep current email" }), _jsx("button", { type: "button", onClick: () => emailConfirmResolver.current?.(true), className: "admin-btn admin-btn-primary", children: "Yes, change email" })] }) })] }), _jsxs("div", { className: "admin-card p-6", children: [_jsxs("div", { className: "flex items-center gap-2 mb-4", children: [_jsx(KeyRound, { className: "h-5 w-5 admin-icon-primary" }), _jsx("h2", { className: "text-lg font-semibold", children: "Password" })] }), passwordSuccess ? (_jsxs("div", { className: "text-center py-6", children: [_jsx("div", { className: "admin-icon-container-sm mx-auto mb-4", children: _jsx(CheckCircle2, { className: "h-6 w-6 admin-icon-primary" }) }), _jsx("h3", { className: "admin-heading-2 mb-2", children: "Password changed" }), _jsx("p", { className: "text-sm admin-text-muted", children: "For your security, all sessions have been signed out. Redirecting to sign in..." })] })) : (_jsxs("form", { onSubmit: handlePasswordSubmit, className: "space-y-4", children: [passwordError && (_jsx("div", { className: "admin-alert admin-alert-error", children: _jsx("div", { className: "admin-alert-description", children: passwordError }) })), _jsxs("div", { children: [_jsx("label", { htmlFor: "current-password", className: "admin-label admin-label-required", children: "Current password" }), _jsx("input", { id: "current-password", type: "password", value: currentPassword, onChange: (e) => setCurrentPassword(e.target.value), required: true, autoComplete: "current-password", disabled: passwordSaving, className: "admin-input w-full" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "new-password", className: "admin-label admin-label-required", children: "New password" }), _jsx("input", { id: "new-password", type: "password", value: newPassword, onChange: (e) => setNewPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: passwordSaving, className: "admin-input w-full", placeholder: "At least 8 characters" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "confirm-new-password", className: "admin-label admin-label-required", children: "Confirm new password" }), _jsx("input", { id: "confirm-new-password", type: "password", value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: passwordSaving, className: "admin-input w-full" })] }), _jsx("p", { className: "text-xs admin-text-muted", children: "After changing your password, you'll be signed out and need to sign back in." }), _jsx("div", { className: "flex items-center justify-end pt-2", children: _jsx("button", { type: "submit", disabled: passwordSaving ||
|
|
122
132
|
!currentPassword ||
|
|
123
133
|
!newPassword ||
|
|
124
|
-
!confirmPassword, className: "admin-btn admin-btn-primary", children: passwordSaving ? (_jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: "admin-spinner admin-spinner-sm" }), "Updating..."] })) : ('Change password') }) })] }))] })
|
|
134
|
+
!confirmPassword, className: "admin-btn admin-btn-primary", children: passwordSaving ? (_jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: "admin-spinner admin-spinner-sm" }), "Updating..."] })) : ('Change password') }) })] }))] }), _jsx(AdminSaveBar, { isDirty: profileDirty, onSave: doProfileSave, onDiscard: () => {
|
|
135
|
+
if (me) {
|
|
136
|
+
setName(me.name);
|
|
137
|
+
setEmail(me.email);
|
|
138
|
+
}
|
|
139
|
+
} })] }));
|
|
125
140
|
}
|
|
126
141
|
//# sourceMappingURL=AdminAccountPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminAccountPage.js","sourceRoot":"","sources":["../../../src/admin/components/AdminAccountPage.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"AdminAccountPage.js","sourceRoot":"","sources":["../../../src/admin/components/AdminAccountPage.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAChE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAe7C,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF,MAAM,UAAU,gBAAgB,CAAC,EAC/B,SAAS,GAAG,EAAE,EACd,QAAQ,GAAG,cAAc,EACzB,eAAe,GAAG,IAAI,GACA;IACtB,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,UAAU,EAAE,CAAA;IAE5E,0EAA0E;IAE1E,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IACpC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IACtC,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IACtD,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE/D,uEAAuE;IACvE,qDAAqD;IACrD,iEAAiE;IACjE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,EAAE,EAAE,CAAC;YACP,2DAA2D;YAC3D,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;YAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;YAClB,gBAAgB,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;QAC5B,CAAC;IACH,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAER,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,aAAa,CAAC,WAAW,EAAE,CAAA;IAC/E,0EAA0E;IAC1E,0EAA0E;IAC1E,8CAA8C;IAC9C,MAAM,YAAY,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IAE3E,sEAAsE;IACtE,2EAA2E;IAC3E,wEAAwE;IACxE,sDAAsD;IACtD,MAAM,oBAAoB,GAAG,MAAM,CAAiC,IAAI,CAAC,CAAA;IAEzE,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,IAAmD,EAAE;QAC1F,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAA;QAE/D,IAAI,SAAS,GAAG,YAAY,CAAA;QAC5B,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,EAAE,GAAG,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;gBAChD,oBAAoB,CAAC,OAAO,GAAG,OAAO,CAAA;gBACtC,mBAAmB,CAAC,IAAI,CAAC,CAAA;YAC3B,CAAC,CAAC,CAAA;YACF,mBAAmB,CAAC,KAAK,CAAC,CAAA;YAC1B,oBAAoB,CAAC,OAAO,GAAG,IAAI,CAAA;YACnC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,QAAQ,CAAC,aAAa,CAAC,CAAA;gBACvB,SAAS,GAAG,KAAK,CAAA;gBACjB,oEAAoE;gBACpE,8DAA8D;gBAC9D,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,IAAI;oBAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;YACvD,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC;YACjC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS;YACvD,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS;SAC5C,CAAC,CAAA;QACF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,2BAA2B,EAAE,CAAA;QAC/E,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC1B,CAAC,EAAE,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC,CAAA;IAEjE,0EAA0E;IAE1E,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC1D,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IAClD,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC1D,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3D,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAA;IACvE,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE7D,MAAM,oBAAoB,GAAG,WAAW,CACtC,KAAK,EAAE,CAAkB,EAAE,EAAE;QAC3B,CAAC,CAAC,cAAc,EAAE,CAAA;QAClB,gBAAgB,CAAC,IAAI,CAAC,CAAA;QACtB,kBAAkB,CAAC,KAAK,CAAC,CAAA;QAEzB,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,gBAAgB,CAAC,6CAA6C,CAAC,CAAA;YAC/D,OAAM;QACR,CAAC;QAED,IAAI,WAAW,KAAK,eAAe,EAAE,CAAC;YACpC,gBAAgB,CAAC,6BAA6B,CAAC,CAAA;YAC/C,OAAM;QACR,CAAC;QAED,IAAI,WAAW,KAAK,eAAe,EAAE,CAAC;YACpC,gBAAgB,CAAC,uDAAuD,CAAC,CAAA;YACzE,OAAM;QACR,CAAC;QAED,iBAAiB,CAAC,IAAI,CAAC,CAAA;QACvB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;YAClC,eAAe;YACf,WAAW;SACZ,CAAC,CAAA;QACF,iBAAiB,CAAC,KAAK,CAAC,CAAA;QAExB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,gBAAgB,CAAC,MAAM,CAAC,KAAK,IAAI,4BAA4B,CAAC,CAAA;YAC9D,OAAM;QACR,CAAC;QAED,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAExB,kEAAkE;QAClE,UAAU,CAAC,GAAG,EAAE;YACd,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAA;QACjC,CAAC,EAAE,eAAe,CAAC,CAAA;IACrB,CAAC,EACD,CAAC,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,QAAQ,EAAE,eAAe,CAAC,CAC3F,CAAA;IAED,0EAA0E;IAE1E,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CACL,cAAK,SAAS,EAAE,aAAa,SAAS,EAAE,YACtC,cAAK,SAAS,EAAC,wCAAwC,YACrD,eAAM,SAAS,EAAC,gCAAgC,GAAG,GAC/C,GACF,CACP,CAAA;IACH,CAAC;IAED,IAAI,KAAK,IAAI,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO,CACL,cAAK,SAAS,EAAE,aAAa,SAAS,EAAE,YACtC,cAAK,SAAS,EAAC,+BAA+B,YAC5C,cAAK,SAAS,EAAC,yBAAyB,YACrC,KAAK,IAAI,8BAA8B,GACpC,GACF,GACF,CACP,CAAA;IACH,CAAC;IAED,OAAO,CACL,eAAK,SAAS,EAAE,aAAa,SAAS,EAAE,aACtC,KAAC,eAAe,IACd,KAAK,EAAC,YAAY,EAClB,QAAQ,EAAC,mCAAmC,GAC5C,EAKF,eAAK,SAAS,EAAC,gBAAgB,aAC7B,eAAK,SAAS,EAAC,8BAA8B,aAC3C,KAAC,IAAI,IAAC,SAAS,EAAC,4BAA4B,GAAG,EAC/C,aAAI,SAAS,EAAC,uBAAuB,wBAAa,IAC9C,EAIN,gBAAM,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE,EAAE,SAAS,EAAC,WAAW,aAC9D,0BACE,gBAAO,OAAO,EAAC,cAAc,EAAC,SAAS,EAAC,aAAa,qBAE7C,EACR,gBACE,EAAE,EAAC,cAAc,EACjB,IAAI,EAAC,MAAM,EACX,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACxC,QAAQ,QACR,SAAS,EAAE,CAAC,EACZ,SAAS,EAAC,oBAAoB,GAC9B,IACE,EAEN,0BACE,gBAAO,OAAO,EAAC,eAAe,EAAC,SAAS,EAAC,aAAa,sBAE9C,EACR,eAAK,SAAS,EAAC,uBAAuB,aACpC,KAAC,IAAI,IAAC,SAAS,EAAC,oCAAoC,GAAG,EACvD,gBACE,EAAE,EAAC,eAAe,EAClB,IAAI,EAAC,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACzC,QAAQ,QACR,SAAS,EAAC,oBAAoB,GAC9B,IACE,EACN,YAAG,SAAS,EAAC,+BAA+B,6DAExC,IACA,EAEN,0BACE,gBAAO,SAAS,EAAC,aAAa,qBAAa,EAC3C,eAAK,SAAS,EAAC,0BAA0B,aACtC,EAAE,CAAC,IAAI,qCACJ,IACF,IACD,EAIP,KAAC,UAAU,IACT,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,EACpD,KAAK,EAAC,eAAe,EACrB,WAAW,EAAE,uCAAuC,aAAa,OAAO,KAAK,oGAAoG,EACjL,IAAI,EAAE,KAAC,WAAW,IAAC,SAAS,EAAC,SAAS,GAAG,EACzC,QAAQ,EAAC,SAAS,EAClB,MAAM,EACJ,8BACE,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,EACpD,SAAS,EAAC,+BAA+B,mCAGlC,EACT,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EACnD,SAAS,EAAC,6BAA6B,kCAGhC,IACR,GAEL,IACE,EAKN,eAAK,SAAS,EAAC,gBAAgB,aAC7B,eAAK,SAAS,EAAC,8BAA8B,aAC3C,KAAC,QAAQ,IAAC,SAAS,EAAC,4BAA4B,GAAG,EACnD,aAAI,SAAS,EAAC,uBAAuB,yBAAc,IAC/C,EAEL,eAAe,CAAC,CAAC,CAAC,CACjB,eAAK,SAAS,EAAC,kBAAkB,aAC/B,cAAK,SAAS,EAAC,sCAAsC,YACnD,KAAC,YAAY,IAAC,SAAS,EAAC,4BAA4B,GAAG,GACnD,EACN,aAAI,SAAS,EAAC,sBAAsB,iCAAsB,EAC1D,YAAG,SAAS,EAAC,0BAA0B,gGAGnC,IACA,CACP,CAAC,CAAC,CAAC,CACF,gBAAM,QAAQ,EAAE,oBAAoB,EAAE,SAAS,EAAC,WAAW,aACxD,aAAa,IAAI,CAChB,cAAK,SAAS,EAAC,+BAA+B,YAC5C,cAAK,SAAS,EAAC,yBAAyB,YAAE,aAAa,GAAO,GAC1D,CACP,EAED,0BACE,gBAAO,OAAO,EAAC,kBAAkB,EAAC,SAAS,EAAC,kCAAkC,iCAEtE,EACR,gBACE,EAAE,EAAC,kBAAkB,EACrB,IAAI,EAAC,UAAU,EACf,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACnD,QAAQ,QACR,YAAY,EAAC,kBAAkB,EAC/B,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAC,oBAAoB,GAC9B,IACE,EAEN,0BACE,gBAAO,OAAO,EAAC,cAAc,EAAC,SAAS,EAAC,kCAAkC,6BAElE,EACR,gBACE,EAAE,EAAC,cAAc,EACjB,IAAI,EAAC,UAAU,EACf,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC/C,QAAQ,QACR,SAAS,EAAE,CAAC,EACZ,YAAY,EAAC,cAAc,EAC3B,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAC,oBAAoB,EAC9B,WAAW,EAAC,uBAAuB,GACnC,IACE,EAEN,0BACE,gBAAO,OAAO,EAAC,sBAAsB,EAAC,SAAS,EAAC,kCAAkC,qCAE1E,EACR,gBACE,EAAE,EAAC,sBAAsB,EACzB,IAAI,EAAC,UAAU,EACf,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACnD,QAAQ,QACR,SAAS,EAAE,CAAC,EACZ,YAAY,EAAC,cAAc,EAC3B,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAC,oBAAoB,GAC9B,IACE,EAEN,YAAG,SAAS,EAAC,0BAA0B,6FAGnC,EAEJ,cAAK,SAAS,EAAC,oCAAoC,YACjD,iBACE,IAAI,EAAC,QAAQ,EACb,QAAQ,EACN,cAAc;wCACd,CAAC,eAAe;wCAChB,CAAC,WAAW;wCACZ,CAAC,eAAe,EAElB,SAAS,EAAC,6BAA6B,YAEtC,cAAc,CAAC,CAAC,CAAC,CAChB,gBAAM,SAAS,EAAC,yBAAyB,aACvC,eAAM,SAAS,EAAC,gCAAgC,GAAG,mBAE9C,CACR,CAAC,CAAC,CAAC,CACF,iBAAiB,CAClB,GACM,GACL,IACD,CACR,IACG,EAKN,KAAC,YAAY,IACX,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,GAAG,EAAE;oBACd,IAAI,EAAE,EAAE,CAAC;wBACP,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;wBAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;oBACpB,CAAC;gBACH,CAAC,GACD,IACE,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela/sdk/admin/components/AdminEmptyState
|
|
3
|
+
*
|
|
4
|
+
* THE empty state — one shape for every "nothing here" moment. An empty
|
|
5
|
+
* list always answers three questions: what is this, why is it empty,
|
|
6
|
+
* what do I do next.
|
|
7
|
+
*
|
|
8
|
+
* Two meanings, two messages (never conflate them):
|
|
9
|
+
* - FIRST RUN (`tone="accent"`, default): the merchant hasn't created any
|
|
10
|
+
* yet — invite creation ("No products yet" + Add product).
|
|
11
|
+
* - NO MATCHES (`tone="muted"`): a search/filter matched nothing — offer
|
|
12
|
+
* relief ("No products match" + Clear filters).
|
|
13
|
+
*
|
|
14
|
+
* `compact` is the quiet single-line tier for sub-panels ("No customer
|
|
15
|
+
* groups yet. Create them from Customers → Manage groups."). Inside a
|
|
16
|
+
* table, wrap in `<td colSpan={n}>`.
|
|
17
|
+
*/
|
|
18
|
+
import type { ReactNode } from 'react';
|
|
19
|
+
export interface AdminEmptyStateProps {
|
|
20
|
+
/** Lucide icon element, rendered inside the small tile */
|
|
21
|
+
icon?: ReactNode;
|
|
22
|
+
title?: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
/** CTA slot — a button or link ("Add product", "Clear filters") */
|
|
25
|
+
action?: ReactNode;
|
|
26
|
+
/** 'accent' first-run (default) · 'muted' no-match / neutral */
|
|
27
|
+
tone?: 'accent' | 'muted';
|
|
28
|
+
/** Single quiet line for sub-panels; renders `description` only */
|
|
29
|
+
compact?: boolean;
|
|
30
|
+
className?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function AdminEmptyState({ icon, title, description, action, tone, compact, className, }: AdminEmptyStateProps): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
//# sourceMappingURL=AdminEmptyState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminEmptyState.d.ts","sourceRoot":"","sources":["../../../src/admin/components/AdminEmptyState.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMtC,MAAM,WAAW,oBAAoB;IACnC,0DAA0D;IAC1D,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mEAAmE;IACnE,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;IACzB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAMD,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,KAAK,EACL,WAAW,EACX,MAAM,EACN,IAAe,EACf,OAAe,EACf,SAAc,GACf,EAAE,oBAAoB,2CAyBtB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Component
|
|
5
|
+
// =============================================================================
|
|
6
|
+
export function AdminEmptyState({ icon, title, description, action, tone = 'accent', compact = false, className = '', }) {
|
|
7
|
+
if (compact) {
|
|
8
|
+
return (_jsx("p", { className: `admin-empty-compact ${className}`.trim(), children: description }));
|
|
9
|
+
}
|
|
10
|
+
return (_jsxs("div", { className: `admin-empty-state ${className}`.trim(), children: [icon && (_jsx("div", { className: `admin-empty-state-tile ${tone === 'muted' ? 'admin-empty-state-tile-muted' : ''}`.trim(), children: icon })), title && _jsx("div", { className: "admin-empty-state-title", children: title }), description && (_jsx("p", { className: "admin-empty-state-description", children: description })), action] }));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=AdminEmptyState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminEmptyState.js","sourceRoot":"","sources":["../../../src/admin/components/AdminEmptyState.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAwCZ,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF,MAAM,UAAU,eAAe,CAAC,EAC9B,IAAI,EACJ,KAAK,EACL,WAAW,EACX,MAAM,EACN,IAAI,GAAG,QAAQ,EACf,OAAO,GAAG,KAAK,EACf,SAAS,GAAG,EAAE,GACO;IACrB,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CACL,YAAG,SAAS,EAAE,uBAAuB,SAAS,EAAE,CAAC,IAAI,EAAE,YAAG,WAAW,GAAK,CAC3E,CAAA;IACH,CAAC;IAED,OAAO,CACL,eAAK,SAAS,EAAE,qBAAqB,SAAS,EAAE,CAAC,IAAI,EAAE,aACpD,IAAI,IAAI,CACP,cACE,SAAS,EAAE,0BACT,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,EACtD,EAAE,CAAC,IAAI,EAAE,YAER,IAAI,GACD,CACP,EACA,KAAK,IAAI,cAAK,SAAS,EAAC,yBAAyB,YAAE,KAAK,GAAO,EAC/D,WAAW,IAAI,CACd,YAAG,SAAS,EAAC,+BAA+B,YAAE,WAAW,GAAK,CAC/D,EACA,MAAM,IACH,CACP,CAAA;AACH,CAAC"}
|
|
@@ -56,6 +56,6 @@ export function AdminLoginForm({ redirectTo = '/admin', onSuccess, className = '
|
|
|
56
56
|
}
|
|
57
57
|
}, [email, password, redirectTo, rememberMe, signIn, onSuccess]);
|
|
58
58
|
const isLoading = isSubmitting || authLoading;
|
|
59
|
-
return (_jsxs("div", { className: `w-full max-w-sm admin-animate-in ${className}`, children: [_jsxs("div", { className: "mb-8 text-center", children: [_jsx("div", { className: "admin-icon-container-sm mx-auto mb-4", children: _jsx(Lock, { className: "h-6 w-6 admin-icon-primary" }) }), _jsx("h1", { className: "admin-heading-2", children: "
|
|
59
|
+
return (_jsxs("div", { className: `w-full max-w-sm admin-animate-in ${className}`, children: [_jsxs("div", { className: "mb-8 text-center", children: [_jsx("div", { className: "admin-icon-container-sm mx-auto mb-4", children: _jsx(Lock, { className: "h-6 w-6 admin-icon-primary" }) }), _jsx("h1", { className: "admin-heading-2", children: "Sign in" }), _jsx("p", { className: "mt-2 text-sm admin-text-muted", children: "Enter your credentials to access the admin panel" })] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", autoComplete: "off", children: [error && (_jsx("div", { className: "admin-alert admin-alert-error", children: _jsx("div", { className: "admin-alert-description", children: error }) })), _jsxs("div", { children: [_jsx("label", { htmlFor: "email", className: "admin-label admin-label-required", children: "Email" }), _jsx("input", { id: "email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "off", disabled: isLoading, className: "admin-input w-full", placeholder: "admin@example.com" })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "password", className: "admin-label admin-label-required", children: "Password" }), _jsx("input", { id: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "off", disabled: isLoading, className: "admin-input w-full", placeholder: "Enter your password" })] }), showRememberMe && (_jsxs("label", { className: "flex items-center gap-2 cursor-pointer select-none", children: [_jsx("input", { id: "admin-remember-me", type: "checkbox", checked: rememberMe, onChange: (e) => setRememberMe(e.target.checked), disabled: isLoading, className: "admin-checkbox" }), _jsx("span", { className: "text-sm admin-text-muted", children: "Keep me signed in for 30 days" })] })), _jsx("button", { type: "submit", disabled: isLoading, className: "admin-btn admin-btn-primary w-full", children: isLoading ? (_jsxs("span", { className: "flex items-center justify-center gap-2", children: [_jsx("span", { className: "admin-spinner admin-spinner-sm" }), "Signing in\u2026"] })) : ('Sign in') })] })] }));
|
|
60
60
|
}
|
|
61
61
|
//# sourceMappingURL=AdminLoginForm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminLoginForm.js","sourceRoot":"","sources":["../../../src/admin/components/AdminLoginForm.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAGpD,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,cAAc,CAAC,EAC7B,UAAU,GAAG,QAAQ,EACrB,SAAS,EACT,SAAS,GAAG,EAAE,EACd,cAAc,GAAG,IAAI,GACD;IACpB,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,YAAY,EAAE,CAAA;IACzD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IACtC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC5C,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACnD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAA;IACvD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEvD,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,EAAE,CAAkB,EAAE,EAAE;QAC5D,CAAC,CAAC,cAAc,EAAE,CAAA;QAClB,QAAQ,CAAC,IAAI,CAAC,CAAA;QACd,eAAe,CAAC,IAAI,CAAC,CAAA;QAErB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAA;YAExE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,QAAQ,CAAC,MAAM,CAAC,KAAK,IAAI,gBAAgB,CAAC,CAAA;gBAC1C,OAAM;YACR,CAAC;YAED,uCAAuC;YACvC,SAAS,EAAE,EAAE,CAAA;YACb,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,UAAU,CAAA;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,CAAC,8BAA8B,CAAC,CAAA;QAC1C,CAAC;gBAAS,CAAC;YACT,eAAe,CAAC,KAAK,CAAC,CAAA;QACxB,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;IAEhE,MAAM,SAAS,GAAG,YAAY,IAAI,WAAW,CAAA;IAE7C,OAAO,CACL,eAAK,SAAS,EAAE,oCAAoC,SAAS,EAAE,aAE7D,eAAK,SAAS,EAAC,kBAAkB,aAC/B,cAAK,SAAS,EAAC,sCAAsC,YACnD,KAAC,IAAI,IAAC,SAAS,EAAC,4BAA4B,GAAG,GAC3C,EACN,aAAI,SAAS,EAAC,iBAAiB,
|
|
1
|
+
{"version":3,"file":"AdminLoginForm.js","sourceRoot":"","sources":["../../../src/admin/components/AdminLoginForm.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela/sdk/admin/components/AdminModal
|
|
3
|
+
*
|
|
4
|
+
* THE overlay primitive — every dialog in the admin renders through it, so
|
|
5
|
+
* the behaviors no hand-rolled overlay gets right live exactly once:
|
|
6
|
+
*
|
|
7
|
+
* - React portal to <body> (wrapped in `.rovela-admin-theme` so the theme
|
|
8
|
+
* scope survives the teleport)
|
|
9
|
+
* - the one blurred backdrop (`admin-modal-backdrop`)
|
|
10
|
+
* - Escape closes, click-outside closes — both inert while `busy`
|
|
11
|
+
* (an in-flight submit must never be dismissed out from under itself)
|
|
12
|
+
* - body scroll lock (counter-based, safe for stacked modals)
|
|
13
|
+
* - focus moves into the card on open, Tab wraps inside it, and focus
|
|
14
|
+
* returns to the opener on close
|
|
15
|
+
*
|
|
16
|
+
* Three widths, one anatomy: default 28rem confirms · `width="md"` (30rem)
|
|
17
|
+
* editors · `width="lg"` (46rem) pickers. Header carries the title +
|
|
18
|
+
* optional icon circle + optional X; `footer` is always right-aligned.
|
|
19
|
+
* Errors inside the body are inline `admin-alert` STATES, never toasts.
|
|
20
|
+
*
|
|
21
|
+
* Forms: put the <form id="…"> in children and submit from the footer via
|
|
22
|
+
* <button type="submit" form="…">.
|
|
23
|
+
*/
|
|
24
|
+
import { type ReactNode } from 'react';
|
|
25
|
+
export interface AdminModalProps {
|
|
26
|
+
/** Whether the modal is visible */
|
|
27
|
+
open: boolean;
|
|
28
|
+
/** Called on Escape, backdrop click, or the X button (not while `busy`) */
|
|
29
|
+
onClose: () => void;
|
|
30
|
+
/** Header title. Omit for fully custom children. */
|
|
31
|
+
title?: string;
|
|
32
|
+
/** Muted copy under the title */
|
|
33
|
+
description?: string;
|
|
34
|
+
/** Icon element rendered inside the colored header circle */
|
|
35
|
+
icon?: ReactNode;
|
|
36
|
+
/** Tone of the icon circle (default 'error' — matches the delete confirm) */
|
|
37
|
+
iconTone?: 'error' | 'warning' | 'success' | 'info';
|
|
38
|
+
/** Card width: 28rem confirms (default) · 30rem editors · 46rem pickers */
|
|
39
|
+
width?: 'sm' | 'md' | 'lg';
|
|
40
|
+
/** While true, Escape / backdrop / X are inert and won't close the modal */
|
|
41
|
+
busy?: boolean;
|
|
42
|
+
/** Render an X close button in the header (pickers and form editors) */
|
|
43
|
+
showClose?: boolean;
|
|
44
|
+
/** Right-aligned footer content (action buttons) */
|
|
45
|
+
footer?: ReactNode;
|
|
46
|
+
/** Extra classes on the modal card */
|
|
47
|
+
className?: string;
|
|
48
|
+
children?: ReactNode;
|
|
49
|
+
}
|
|
50
|
+
export declare function AdminModal({ open, onClose, title, description, icon, iconTone, width, busy, showClose, footer, className, children, }: AdminModalProps): import("react").ReactPortal | null;
|
|
51
|
+
//# sourceMappingURL=AdminModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminModal.d.ts","sourceRoot":"","sources":["../../../src/admin/components/AdminModal.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAQnE,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,IAAI,EAAE,OAAO,CAAA;IACb,2EAA2E;IAC3E,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iCAAiC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAA;IACnD,2EAA2E;IAC3E,KAAK,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IAC1B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,oDAAoD;IACpD,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAkCD,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,OAAO,EACP,KAAK,EACL,WAAW,EACX,IAAI,EACJ,QAAkB,EAClB,KAAY,EACZ,IAAY,EACZ,SAAiB,EACjB,MAAM,EACN,SAAc,EACd,QAAQ,GACT,EAAE,eAAe,sCA0HjB"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @rovela/sdk/admin/components/AdminModal
|
|
5
|
+
*
|
|
6
|
+
* THE overlay primitive — every dialog in the admin renders through it, so
|
|
7
|
+
* the behaviors no hand-rolled overlay gets right live exactly once:
|
|
8
|
+
*
|
|
9
|
+
* - React portal to <body> (wrapped in `.rovela-admin-theme` so the theme
|
|
10
|
+
* scope survives the teleport)
|
|
11
|
+
* - the one blurred backdrop (`admin-modal-backdrop`)
|
|
12
|
+
* - Escape closes, click-outside closes — both inert while `busy`
|
|
13
|
+
* (an in-flight submit must never be dismissed out from under itself)
|
|
14
|
+
* - body scroll lock (counter-based, safe for stacked modals)
|
|
15
|
+
* - focus moves into the card on open, Tab wraps inside it, and focus
|
|
16
|
+
* returns to the opener on close
|
|
17
|
+
*
|
|
18
|
+
* Three widths, one anatomy: default 28rem confirms · `width="md"` (30rem)
|
|
19
|
+
* editors · `width="lg"` (46rem) pickers. Header carries the title +
|
|
20
|
+
* optional icon circle + optional X; `footer` is always right-aligned.
|
|
21
|
+
* Errors inside the body are inline `admin-alert` STATES, never toasts.
|
|
22
|
+
*
|
|
23
|
+
* Forms: put the <form id="…"> in children and submit from the footer via
|
|
24
|
+
* <button type="submit" form="…">.
|
|
25
|
+
*/
|
|
26
|
+
import { useEffect, useRef, useState } from 'react';
|
|
27
|
+
import { createPortal } from 'react-dom';
|
|
28
|
+
import { X } from 'lucide-react';
|
|
29
|
+
// =============================================================================
|
|
30
|
+
// Body scroll lock — counter-based so stacked modals can't unlock early
|
|
31
|
+
// =============================================================================
|
|
32
|
+
let scrollLockCount = 0;
|
|
33
|
+
let previousOverflow = '';
|
|
34
|
+
function lockBodyScroll() {
|
|
35
|
+
if (scrollLockCount === 0) {
|
|
36
|
+
previousOverflow = document.body.style.overflow;
|
|
37
|
+
document.body.style.overflow = 'hidden';
|
|
38
|
+
}
|
|
39
|
+
scrollLockCount++;
|
|
40
|
+
}
|
|
41
|
+
function unlockBodyScroll() {
|
|
42
|
+
scrollLockCount = Math.max(0, scrollLockCount - 1);
|
|
43
|
+
if (scrollLockCount === 0) {
|
|
44
|
+
document.body.style.overflow = previousOverflow;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// =============================================================================
|
|
48
|
+
// Component
|
|
49
|
+
// =============================================================================
|
|
50
|
+
const WIDTH_CLASS = {
|
|
51
|
+
sm: '',
|
|
52
|
+
md: 'admin-modal-md',
|
|
53
|
+
lg: 'admin-modal-lg',
|
|
54
|
+
};
|
|
55
|
+
export function AdminModal({ open, onClose, title, description, icon, iconTone = 'error', width = 'sm', busy = false, showClose = false, footer, className = '', children, }) {
|
|
56
|
+
const cardRef = useRef(null);
|
|
57
|
+
const openerRef = useRef(null);
|
|
58
|
+
// Keep latest onClose/busy without re-binding document listeners.
|
|
59
|
+
// Synced in an effect (render-time ref writes trip the React Compiler
|
|
60
|
+
// lint); effects run before any user event can fire the listeners.
|
|
61
|
+
const onCloseRef = useRef(onClose);
|
|
62
|
+
const busyRef = useRef(busy);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
onCloseRef.current = onClose;
|
|
65
|
+
busyRef.current = busy;
|
|
66
|
+
}, [onClose, busy]);
|
|
67
|
+
// Portal target only exists in the browser (client components still SSR)
|
|
68
|
+
const [mounted, setMounted] = useState(false);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
// Pattern B — post-mount hydration to avoid SSR mismatch.
|
|
71
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
72
|
+
setMounted(true);
|
|
73
|
+
}, []);
|
|
74
|
+
// Escape + scroll lock + initial focus / focus restore
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!open)
|
|
77
|
+
return;
|
|
78
|
+
const onKeyDown = (e) => {
|
|
79
|
+
if (e.key === 'Escape' && !busyRef.current)
|
|
80
|
+
onCloseRef.current();
|
|
81
|
+
};
|
|
82
|
+
document.addEventListener('keydown', onKeyDown);
|
|
83
|
+
lockBodyScroll();
|
|
84
|
+
openerRef.current = document.activeElement ?? null;
|
|
85
|
+
// Move focus into the card so Escape/Tab work immediately
|
|
86
|
+
cardRef.current?.focus();
|
|
87
|
+
return () => {
|
|
88
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
89
|
+
unlockBodyScroll();
|
|
90
|
+
openerRef.current?.focus?.();
|
|
91
|
+
};
|
|
92
|
+
}, [open]);
|
|
93
|
+
if (!open || !mounted)
|
|
94
|
+
return null;
|
|
95
|
+
// Lightweight Tab wrap — keeps keyboard focus inside the card
|
|
96
|
+
const handleTabWrap = (e) => {
|
|
97
|
+
if (e.key !== 'Tab' || !cardRef.current)
|
|
98
|
+
return;
|
|
99
|
+
const focusables = Array.from(cardRef.current.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')).filter((el) => !el.hasAttribute('disabled'));
|
|
100
|
+
if (focusables.length === 0)
|
|
101
|
+
return;
|
|
102
|
+
const first = focusables[0];
|
|
103
|
+
const last = focusables[focusables.length - 1];
|
|
104
|
+
if (e.shiftKey && document.activeElement === first) {
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
last.focus();
|
|
107
|
+
}
|
|
108
|
+
else if (!e.shiftKey && document.activeElement === last) {
|
|
109
|
+
e.preventDefault();
|
|
110
|
+
first.focus();
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const modal = (_jsx("div", { className: "rovela-admin-theme", children: _jsxs("div", { className: "admin-modal-root", children: [_jsx("div", { className: "admin-modal-backdrop admin-modal-backdrop-animate absolute inset-0", onClick: () => !busy && onClose() }), _jsxs("div", { ref: cardRef, role: "dialog", "aria-modal": "true", "aria-label": title, tabIndex: -1, onKeyDown: handleTabWrap, className: `admin-modal admin-modal-animate relative w-full mx-4 ${WIDTH_CLASS[width]} ${className}`
|
|
114
|
+
.replace(/\s+/g, ' ')
|
|
115
|
+
.trim(), children: [(title || showClose) && (_jsxs("div", { className: "admin-modal-header", children: [icon && (_jsx("div", { className: `admin-modal-icon admin-modal-icon-${iconTone}`, children: icon })), _jsxs("div", { className: "flex-1 min-w-0", children: [title && _jsx("h3", { className: "admin-modal-title", children: title }), description && (_jsx("p", { className: "admin-modal-description", children: description }))] }), showClose && (_jsx("button", { type: "button", onClick: () => !busy && onClose(), disabled: busy, "aria-label": "Close", className: "admin-btn admin-btn-ghost admin-btn-icon admin-btn-sm -mt-1 -mr-2 flex-shrink-0", children: _jsx(X, { className: "h-4 w-4" }) }))] })), children, footer && _jsx("div", { className: "admin-modal-footer", children: footer })] })] }) }));
|
|
116
|
+
return createPortal(modal, document.body);
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=AdminModal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminModal.js","sourceRoot":"","sources":["../../../src/admin/components/AdminModal.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela/sdk/admin/components/AdminPagination
|
|
3
|
+
*
|
|
4
|
+
* THE pagination row — "Showing X to Y of Z {noun}" on the left, quiet
|
|
5
|
+
* Previous/Next on the right. Replaces the block that was copy-pasted
|
|
6
|
+
* inline across the tables (plus a divergent fourth variant).
|
|
7
|
+
*/
|
|
8
|
+
export interface AdminPaginationProps {
|
|
9
|
+
/** 1-based current page */
|
|
10
|
+
page: number;
|
|
11
|
+
pageSize: number;
|
|
12
|
+
/** Total matching rows across all pages */
|
|
13
|
+
total: number;
|
|
14
|
+
onPageChange: (page: number) => void;
|
|
15
|
+
/** Plural noun for the info line ("products", "orders"). Optional. */
|
|
16
|
+
noun?: string;
|
|
17
|
+
/** Disable the controls while a page is loading */
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function AdminPagination({ page, pageSize, total, onPageChange, noun, disabled, className, }: AdminPaginationProps): import("react/jsx-runtime").JSX.Element | null;
|
|
22
|
+
//# sourceMappingURL=AdminPagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminPagination.d.ts","sourceRoot":"","sources":["../../../src/admin/components/AdminPagination.tsx"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAMH,MAAM,WAAW,oBAAoB;IACnC,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAMD,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,YAAY,EACZ,IAAI,EACJ,QAAgB,EAChB,SAAc,GACf,EAAE,oBAAoB,kDAkCtB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Component
|
|
5
|
+
// =============================================================================
|
|
6
|
+
export function AdminPagination({ page, pageSize, total, onPageChange, noun, disabled = false, className = '', }) {
|
|
7
|
+
if (total <= 0)
|
|
8
|
+
return null;
|
|
9
|
+
const from = (page - 1) * pageSize + 1;
|
|
10
|
+
const to = Math.min(page * pageSize, total);
|
|
11
|
+
const hasPrev = page > 1;
|
|
12
|
+
const hasNext = to < total;
|
|
13
|
+
return (_jsxs("div", { className: `admin-pagination ${className}`.trim(), children: [_jsxs("span", { className: "admin-pagination-info", children: ["Showing ", from, " to ", to, " of ", total, noun ? ` ${noun}` : ''] }), _jsxs("div", { className: "admin-pagination-controls", children: [_jsx("button", { type: "button", onClick: () => onPageChange(page - 1), disabled: disabled || !hasPrev, className: "admin-btn admin-btn-secondary admin-btn-sm", children: "Previous" }), _jsx("button", { type: "button", onClick: () => onPageChange(page + 1), disabled: disabled || !hasNext, className: "admin-btn admin-btn-secondary admin-btn-sm", children: "Next" })] })] }));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=AdminPagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminPagination.js","sourceRoot":"","sources":["../../../src/admin/components/AdminPagination.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AA4BZ,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF,MAAM,UAAU,eAAe,CAAC,EAC9B,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,YAAY,EACZ,IAAI,EACJ,QAAQ,GAAG,KAAK,EAChB,SAAS,GAAG,EAAE,GACO;IACrB,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAE3B,MAAM,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAA;IACtC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,QAAQ,EAAE,KAAK,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAA;IACxB,MAAM,OAAO,GAAG,EAAE,GAAG,KAAK,CAAA;IAE1B,OAAO,CACL,eAAK,SAAS,EAAE,oBAAoB,SAAS,EAAE,CAAC,IAAI,EAAE,aACpD,gBAAM,SAAS,EAAC,uBAAuB,yBAC5B,IAAI,UAAM,EAAE,UAAM,KAAK,EAC/B,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAClB,EACP,eAAK,SAAS,EAAC,2BAA2B,aACxC,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,EACrC,QAAQ,EAAE,QAAQ,IAAI,CAAC,OAAO,EAC9B,SAAS,EAAC,4CAA4C,yBAG/C,EACT,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,EACrC,QAAQ,EAAE,QAAQ,IAAI,CAAC,OAAO,EAC9B,SAAS,EAAC,4CAA4C,qBAG/C,IACL,IACF,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface AdminSearchInputProps {
|
|
2
|
+
/** Fires with the trimmed query, debounced */
|
|
3
|
+
onSearch: (query: string) => void;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
/** Initial text (e.g. restoring a persisted filter) */
|
|
6
|
+
initialValue?: string;
|
|
7
|
+
/** Debounce in ms (default 300; use 0 for client-side filtering) */
|
|
8
|
+
debounceMs?: number;
|
|
9
|
+
ariaLabel?: string;
|
|
10
|
+
autoFocus?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function AdminSearchInput({ onSearch, placeholder, initialValue, debounceMs, ariaLabel, autoFocus, className, }: AdminSearchInputProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=AdminSearchInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminSearchInput.d.ts","sourceRoot":"","sources":["../../../src/admin/components/AdminSearchInput.tsx"],"names":[],"mappings":"AAqBA,MAAM,WAAW,qBAAqB;IACpC,8CAA8C;IAC9C,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAMD,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,WAAuB,EACvB,YAAiB,EACjB,UAAgB,EAChB,SAAS,EACT,SAAiB,EACjB,SAAc,GACf,EAAE,qBAAqB,2CAkDvB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @rovela/sdk/admin/components/AdminSearchInput
|
|
5
|
+
*
|
|
6
|
+
* THE list search box — icon inside, one markup, one debounce. Replaces
|
|
7
|
+
* the three parallel search constructions (bare input, two icon-wrapper
|
|
8
|
+
* CSS families) and the tables that fetched on every keystroke.
|
|
9
|
+
*
|
|
10
|
+
* `onSearch` fires 300ms after the last keystroke (Enter flushes
|
|
11
|
+
* immediately). The component owns the draft text; the consumer owns the
|
|
12
|
+
* committed query.
|
|
13
|
+
*/
|
|
14
|
+
import { useEffect, useRef, useState } from 'react';
|
|
15
|
+
import { Search } from 'lucide-react';
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Component
|
|
18
|
+
// =============================================================================
|
|
19
|
+
export function AdminSearchInput({ onSearch, placeholder = 'Search…', initialValue = '', debounceMs = 300, ariaLabel, autoFocus = false, className = '', }) {
|
|
20
|
+
const [draft, setDraft] = useState(initialValue);
|
|
21
|
+
const timerRef = useRef(null);
|
|
22
|
+
// Synced in an effect (render-time ref writes trip the React Compiler
|
|
23
|
+
// lint); the debounce timer always fires after the effect has run.
|
|
24
|
+
const onSearchRef = useRef(onSearch);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
onSearchRef.current = onSearch;
|
|
27
|
+
}, [onSearch]);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
return () => {
|
|
30
|
+
if (timerRef.current)
|
|
31
|
+
clearTimeout(timerRef.current);
|
|
32
|
+
};
|
|
33
|
+
}, []);
|
|
34
|
+
const schedule = (value) => {
|
|
35
|
+
if (timerRef.current)
|
|
36
|
+
clearTimeout(timerRef.current);
|
|
37
|
+
if (debounceMs <= 0) {
|
|
38
|
+
onSearchRef.current(value.trim());
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
timerRef.current = setTimeout(() => onSearchRef.current(value.trim()), debounceMs);
|
|
42
|
+
};
|
|
43
|
+
const flush = (value) => {
|
|
44
|
+
if (timerRef.current)
|
|
45
|
+
clearTimeout(timerRef.current);
|
|
46
|
+
onSearchRef.current(value.trim());
|
|
47
|
+
};
|
|
48
|
+
return (_jsxs("div", { className: `admin-input-with-icon ${className}`.trim(), children: [_jsx(Search, { className: "admin-input-with-icon-left h-4 w-4" }), _jsx("input", { type: "search", value: draft, onChange: (e) => {
|
|
49
|
+
setDraft(e.target.value);
|
|
50
|
+
schedule(e.target.value);
|
|
51
|
+
}, onKeyDown: (e) => {
|
|
52
|
+
if (e.key === 'Enter')
|
|
53
|
+
flush(draft);
|
|
54
|
+
}, placeholder: placeholder, autoFocus: autoFocus, "aria-label": ariaLabel ?? placeholder, className: "admin-input w-full" })] }));
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=AdminSearchInput.js.map
|