@asteby/metacore-runtime-react 23.9.3 → 23.10.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/CHANGELOG.md +13 -0
- package/README.md +43 -0
- package/dist/action-modal-dispatcher.d.ts.map +1 -1
- package/dist/action-modal-dispatcher.js +122 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/license/index.d.ts +5 -0
- package/dist/license/index.d.ts.map +1 -0
- package/dist/license/index.js +4 -0
- package/dist/license/license-expiry-banner.d.ts +16 -0
- package/dist/license/license-expiry-banner.d.ts.map +1 -0
- package/dist/license/license-expiry-banner.js +85 -0
- package/dist/license/license-gate.d.ts +40 -0
- package/dist/license/license-gate.d.ts.map +1 -0
- package/dist/license/license-gate.js +108 -0
- package/dist/license/license-status-badge.d.ts +7 -0
- package/dist/license/license-status-badge.d.ts.map +1 -0
- package/dist/license/license-status-badge.js +57 -0
- package/dist/license/types.d.ts +63 -0
- package/dist/license/types.d.ts.map +1 -0
- package/dist/license/types.js +45 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/license-gate.test.tsx +242 -0
- package/src/__tests__/wizard-action-modal.test.tsx +121 -0
- package/src/action-modal-dispatcher.tsx +233 -0
- package/src/index.ts +15 -0
- package/src/license/index.ts +21 -0
- package/src/license/license-expiry-banner.tsx +151 -0
- package/src/license/license-gate.tsx +277 -0
- package/src/license/license-status-badge.tsx +93 -0
- package/src/license/types.ts +90 -0
- package/src/types.ts +9 -0
- package/LICENSE +0 -201
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 23.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c94ec63: feat(license-gate): gate de licencia reutilizable — el negocio blindado en el SDK.
|
|
8
|
+
|
|
9
|
+
Nuevo primitivo `<LicenseGate>` (más `<LicenseExpiryBanner>`, `<LicenseStatusBadge>` y los helpers `isLicenseOperable`/`isLicenseBlocking`/`isPresetEntitled`/`isTrialExpired`) que ops y todos los verticales montan en una línea para blindar la app tras la licencia de instancia:
|
|
10
|
+
- Sin enforcement o estado operable (`valid`/`stale`/`grace`) → renderiza children; `stale`/`grace` montan un banner degradado (`expired` no descartable, el resto descartable con TTL en localStorage).
|
|
11
|
+
- Enforcement && `missing`/`invalid`/`expired` → modal bloqueante full-screen no descartable con formulario de activación (clave `lic_…` o token pegado); `plan === 'trial'` + `expired` muestra "Tu prueba gratuita terminó". La activación exitosa desbloquea sin recargar.
|
|
12
|
+
- Branding-aware (logo/nombre) con fallback neutro; i18n es-first con `t(key, { defaultValue })`.
|
|
13
|
+
|
|
14
|
+
Independiente del kernel: el host resuelve el `LicenseState` con su propio transporte y pasa `onActivate`. No requiere release del kernel.
|
|
15
|
+
|
|
3
16
|
## 23.9.3
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -30,6 +30,49 @@ Peers: `react`, `react-dom`, `react-i18next`, `i18next`, `@tanstack/react-router
|
|
|
30
30
|
| `useMetadataCache()` | Zustand store for table/modal metadata, persisted to LocalStorage. `prefetchAll(api)` warms it from `/metadata/all`. |
|
|
31
31
|
| `defaultGetDynamicColumns` / `makeDefaultGetDynamicColumns(helpers)` | The factory `<DynamicTable>` uses to convert metadata into TanStack column defs. The default reads from `col.key` (matching the kernel contract). |
|
|
32
32
|
| `DynamicIcon` | Lucide icon resolver by name. |
|
|
33
|
+
| `<LicenseGate state={…} onActivate={…}>` | El blindaje del negocio: envuelve la app; bloquea con un modal full-screen no descartable cuando la licencia de instancia falta/venció, degrada con banner en `grace`/`stale`. Branding-aware. |
|
|
34
|
+
| `<LicenseExpiryBanner state={…} />` / `<LicenseStatusBadge status={…} />` | Piezas sueltas del gate para Ajustes u otros lugares. |
|
|
35
|
+
| `isLicenseOperable` / `isLicenseBlocking` / `isPresetEntitled` / `isTrialExpired` | Helpers puros sobre `LicenseState`, espejo de `State.Operable()/Blocking()` del backend. |
|
|
36
|
+
|
|
37
|
+
## Blindaje de licencia (`LicenseGate`)
|
|
38
|
+
|
|
39
|
+
El gate de licencia es un **primitivo del SDK**: ops y todos los verticales lo montan
|
|
40
|
+
en una línea. Reparto de responsabilidades:
|
|
41
|
+
|
|
42
|
+
- **kernel** → *enforcement* (qué está permitido; firma/verifica el estado).
|
|
43
|
+
- **SDK** (este módulo) → *UX* (gate, banner, badge).
|
|
44
|
+
- **hub** → *emisión* (mintea el token Ed25519).
|
|
45
|
+
- **hosts** → *wiring* (resuelven el `LicenseState` con su propio transporte y montan el gate).
|
|
46
|
+
|
|
47
|
+
Es **independiente del kernel**: no importa su cliente ni fija su versión. El host
|
|
48
|
+
resuelve el estado (p. ej. `GET /admin/license`) y pasa una promesa `onActivate`.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { LicenseGate } from '@asteby/metacore-runtime-react'
|
|
52
|
+
import { useLicenseState, useActivateLicense } from './features/license'
|
|
53
|
+
|
|
54
|
+
export function Shell({ children }) {
|
|
55
|
+
const { data: state } = useLicenseState() // GET /admin/license
|
|
56
|
+
const activate = useActivateLicense() // POST /admin/license/activate
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<LicenseGate
|
|
60
|
+
state={state}
|
|
61
|
+
onActivate={(code) => activate.mutateAsync(code)}
|
|
62
|
+
branding={{ name: brand.name, logo: brand.logo }}
|
|
63
|
+
onManage={() => navigate('/settings/license')}
|
|
64
|
+
>
|
|
65
|
+
{children}
|
|
66
|
+
</LicenseGate>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- Sin enforcement o estado operable (`valid`/`stale`/`grace`) → renderiza children.
|
|
72
|
+
`stale`/`grace` montan además el banner degradado (`expired` no es descartable, el resto sí con TTL en localStorage).
|
|
73
|
+
- Enforcement && `missing`/`invalid`/`expired` → modal **bloqueante** con el formulario de activación.
|
|
74
|
+
`plan === 'trial'` + `expired` → copy *"Tu prueba gratuita terminó"*.
|
|
75
|
+
- Activación exitosa desbloquea **sin recargar**: el host refresca el `state` y el gate se desmonta.
|
|
33
76
|
|
|
34
77
|
## Minimal usage
|
|
35
78
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-modal-dispatcher.d.ts","sourceRoot":"","sources":["../src/action-modal-dispatcher.tsx"],"names":[],"mappings":"AAgDA,OAAO,EACH,KAAK,cAAc,EACnB,KAAK,gBAAgB,EAExB,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAA;AA0FhD,wBAAgB,qBAAqB,CAAC,EAClC,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,KAAK,EACL,MAAM,EACN,QAAQ,EACR,SAAS,GACZ,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"action-modal-dispatcher.d.ts","sourceRoot":"","sources":["../src/action-modal-dispatcher.tsx"],"names":[],"mappings":"AAgDA,OAAO,EACH,KAAK,cAAc,EACnB,KAAK,gBAAgB,EAExB,MAAM,sBAAsB,CAAA;AAE7B,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAA;AA0FhD,wBAAgB,qBAAqB,CAAC,EAClC,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,KAAK,EACL,MAAM,EACN,QAAQ,EACR,SAAS,GACZ,EAAE,gBAAgB,sCA+DlB"}
|
|
@@ -87,6 +87,9 @@ export function ActionModalDispatcher({ open, onOpenChange, action, model, recor
|
|
|
87
87
|
if (CustomComponent) {
|
|
88
88
|
return (_jsx(CustomComponent, { open: open, onOpenChange: onOpenChange, action: action, model: model, record: record, endpoint: endpoint, onSuccess: onSuccess }));
|
|
89
89
|
}
|
|
90
|
+
if (action.steps && action.steps.length > 0) {
|
|
91
|
+
return (_jsx(WizardActionModal, { open: open, onOpenChange: onOpenChange, action: action, model: model, record: record, endpoint: endpoint, onSuccess: onSuccess }));
|
|
92
|
+
}
|
|
90
93
|
if (action.fields && action.fields.length > 0) {
|
|
91
94
|
return (_jsx(GenericActionModal, { open: open, onOpenChange: onOpenChange, action: action, model: model, record: record, endpoint: endpoint, onSuccess: onSuccess }));
|
|
92
95
|
}
|
|
@@ -254,6 +257,125 @@ function GenericActionModal({ open, onOpenChange, action, model, record, endpoin
|
|
|
254
257
|
return (_jsxs(FieldCell, { fullWidth: fullWidth, children: [_jsx(FieldLabel, { htmlFor: field.key, required: field.required, children: tl(field.label) }), renderField(field, formData[field.key], (v) => updateField(field.key, v), formData)] }, field.key));
|
|
255
258
|
}), relations.length > 0 && (_jsx(FieldCell, { fullWidth: true, children: _jsx(DynamicRelations, { record: record, relations: relations }) }))] }) }), _jsxs(DialogFooter, { className: "shrink-0", children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: executing, children: t('common.cancel') }), _jsxs(Button, { onClick: execute, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: [executing ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(DynamicIcon, { name: action.icon, className: "mr-2 h-4 w-4" }), tl(action.label)] })] })] }) }));
|
|
256
259
|
}
|
|
260
|
+
// buildFieldDefaults seeds formData for a set of action fields, honoring the
|
|
261
|
+
// same line-items prefill spec + boolean/empty rules GenericActionModal uses, so
|
|
262
|
+
// wizard steps and single-page forms initialize identically.
|
|
263
|
+
function buildFieldDefaults(fields, record) {
|
|
264
|
+
const defaults = {};
|
|
265
|
+
for (const field of fields) {
|
|
266
|
+
if (isLineItemsField(field)) {
|
|
267
|
+
const dv = lineItemsDefault(field);
|
|
268
|
+
defaults[field.key] = isPrefillSpec(dv)
|
|
269
|
+
? buildPrefillRows(dv, record)
|
|
270
|
+
: Array.isArray(dv)
|
|
271
|
+
? dv
|
|
272
|
+
: [];
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
defaults[field.key] = field.defaultValue ?? (field.type === 'boolean' ? false : '');
|
|
276
|
+
}
|
|
277
|
+
return defaults;
|
|
278
|
+
}
|
|
279
|
+
// validateFields returns the first validation error for a set of required
|
|
280
|
+
// fields, or null when they all pass. Shared by the wizard (per-step gate) and
|
|
281
|
+
// mirrors GenericActionModal's inline checks. `tl` localizes the field label.
|
|
282
|
+
function validateFields(fields, formData, tl) {
|
|
283
|
+
for (const field of fields) {
|
|
284
|
+
if (!field.required)
|
|
285
|
+
continue;
|
|
286
|
+
if (isLineItemsField(field)) {
|
|
287
|
+
const rows = formData[field.key];
|
|
288
|
+
if (!Array.isArray(rows) || rows.length === 0) {
|
|
289
|
+
return `${tl(field.label)} requiere al menos un renglón`;
|
|
290
|
+
}
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (!formData[field.key] && formData[field.key] !== false) {
|
|
294
|
+
return `${tl(field.label)} es requerido`;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
// WizardActionModal — the third render-path: a multi-step form. It accumulates
|
|
300
|
+
// every step's fields into ONE formData object and, on the final step, POSTs all
|
|
301
|
+
// of them to the same endpoint GenericActionModal uses (buildActionUrl). Each
|
|
302
|
+
// step is validated before "Siguiente" advances; a progress/step bar shows where
|
|
303
|
+
// the user is. Widgets are rendered by the same renderField/resolveWidget path,
|
|
304
|
+
// so line-items, dynamic_select, uploads and dates behave identically to a
|
|
305
|
+
// single-page action form — no widget is duplicated.
|
|
306
|
+
function WizardActionModal({ open, onOpenChange, action, model, record, endpoint, onSuccess }) {
|
|
307
|
+
const { t } = useTranslation();
|
|
308
|
+
const tl = (s) => t(s, { defaultValue: s });
|
|
309
|
+
const api = useApi();
|
|
310
|
+
const steps = action.steps ?? [];
|
|
311
|
+
const [stepIndex, setStepIndex] = useState(0);
|
|
312
|
+
const [formData, setFormData] = useState({});
|
|
313
|
+
const [executing, setExecuting] = useState(false);
|
|
314
|
+
// Reset to the first step and seed defaults for EVERY step's fields whenever
|
|
315
|
+
// the modal (re)opens, so accumulated values from a prior run don't leak.
|
|
316
|
+
useEffect(() => {
|
|
317
|
+
if (!open)
|
|
318
|
+
return;
|
|
319
|
+
const allFields = steps.flatMap((s) => s.fields ?? []);
|
|
320
|
+
setFormData(buildFieldDefaults(allFields, record));
|
|
321
|
+
setStepIndex(0);
|
|
322
|
+
}, [open, action.steps, record]);
|
|
323
|
+
const updateField = (key, value) => setFormData((prev) => ({ ...prev, [key]: value }));
|
|
324
|
+
const step = steps[stepIndex];
|
|
325
|
+
const isLast = stepIndex === steps.length - 1;
|
|
326
|
+
const stepFields = step?.fields ?? [];
|
|
327
|
+
const hasLineItems = useMemo(() => stepFields.some(isLineItemsField), [stepFields]);
|
|
328
|
+
const widthPx = hasLineItems ? '820px' : undefined;
|
|
329
|
+
const goNext = () => {
|
|
330
|
+
const err = validateFields(stepFields, formData, tl);
|
|
331
|
+
if (err) {
|
|
332
|
+
toast.error(err);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
setStepIndex((i) => Math.min(i + 1, steps.length - 1));
|
|
336
|
+
};
|
|
337
|
+
const goBack = () => setStepIndex((i) => Math.max(i - 1, 0));
|
|
338
|
+
const submit = async () => {
|
|
339
|
+
// Guard every step's required fields on final submit (a user could reach
|
|
340
|
+
// the last step with an untouched earlier line-items grid otherwise).
|
|
341
|
+
for (const s of steps) {
|
|
342
|
+
const err = validateFields(s.fields ?? [], formData, tl);
|
|
343
|
+
if (err) {
|
|
344
|
+
toast.error(err);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
setExecuting(true);
|
|
349
|
+
try {
|
|
350
|
+
const url = buildActionUrl(endpoint, model, record?.id, action.key);
|
|
351
|
+
const res = await api.post(url, formData);
|
|
352
|
+
if (res.data.success) {
|
|
353
|
+
toast.success(res.data.message ? t(res.data.message, { defaultValue: res.data.message }) : t('common.success'));
|
|
354
|
+
onOpenChange(false);
|
|
355
|
+
onSuccess();
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
toast.error(res.data.message ? t(res.data.message, { defaultValue: res.data.message }) : t('common.error'));
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
toast.error(err?.response?.data?.message || t('common.error'));
|
|
363
|
+
}
|
|
364
|
+
finally {
|
|
365
|
+
setExecuting(false);
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
if (steps.length === 0)
|
|
369
|
+
return null;
|
|
370
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: 'flex max-h-[90vh] flex-col overflow-hidden ' + (widthPx ? '' : 'sm:max-w-xl'), style: { maxHeight: '90vh', ...(widthPx ? { maxWidth: widthPx, width: '95vw' } : {}) }, children: [_jsxs(DialogHeader, { className: "shrink-0", children: [_jsxs(DialogTitle, { className: "flex items-center gap-2", children: [_jsx(DynamicIcon, { name: action.icon, className: "h-5 w-5" }), tl(action.label)] }), _jsxs("div", { className: "pt-2", children: [_jsx("div", { className: "flex items-center gap-1.5", role: "list", "aria-label": "progress", children: steps.map((s, i) => (_jsx("div", { role: "listitem", "aria-current": i === stepIndex ? 'step' : undefined, className: "h-1.5 flex-1 rounded-full", style: {
|
|
371
|
+
backgroundColor: i <= stepIndex ? (action.color || 'hsl(var(--primary))') : 'hsl(var(--muted))',
|
|
372
|
+
} }, i))) }), _jsxs(DialogDescription, { className: "pt-2", children: [t('common.step', { defaultValue: 'Paso' }), " ", stepIndex + 1, "/", steps.length, step?.title ? ` · ${tl(step.title)}` : ''] }), step?.description && (_jsx("p", { className: "pt-1 text-sm text-muted-foreground", children: tl(step.description) }))] })] }), _jsx("div", { className: "-mx-1 min-h-0 flex-1 overflow-y-auto px-1 py-4", children: _jsx(FieldGrid, { children: stepFields.map((field) => {
|
|
373
|
+
const fullWidth = isLineItemsField(field) ||
|
|
374
|
+
resolveWidget(field) === 'textarea' ||
|
|
375
|
+
resolveWidget(field) === 'richtext';
|
|
376
|
+
return (_jsxs(FieldCell, { fullWidth: fullWidth, children: [_jsx(FieldLabel, { htmlFor: field.key, required: field.required, children: tl(field.label) }), renderField(field, formData[field.key], (v) => updateField(field.key, v), formData)] }, field.key));
|
|
377
|
+
}) }) }), _jsxs(DialogFooter, { className: "shrink-0", children: [stepIndex > 0 ? (_jsx(Button, { variant: "outline", onClick: goBack, disabled: executing, children: t('common.back', { defaultValue: 'Atrás' }) })) : (_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: executing, children: t('common.cancel') })), isLast ? (_jsxs(Button, { onClick: submit, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: [executing ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(DynamicIcon, { name: action.icon, className: "mr-2 h-4 w-4" }), tl(action.label)] })) : (_jsx(Button, { onClick: goNext, disabled: executing, style: action.color ? { backgroundColor: action.color, color: 'white' } : undefined, children: t('common.next', { defaultValue: 'Siguiente' }) }))] })] }) }));
|
|
378
|
+
}
|
|
257
379
|
function renderField(field, value, onChange,
|
|
258
380
|
// Full current form values — lets a line-items grid (and any cascading
|
|
259
381
|
// header picker) resolve a `dependsOn` reference against sibling header
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './types';
|
|
2
|
+
export { LicenseGate, LicenseExpiryBanner, LicenseStatusBadge, isLicenseOperable, isLicenseBlocking, isPresetEntitled, isTrialExpired, type LicenseGateProps, type LicenseExpiryBannerProps, type LicenseStatusBadgeProps, type LicenseState, type LicenseStatus, type LicenseBranding, } from './license';
|
|
2
3
|
export * from './options-context';
|
|
3
4
|
export * from './dynamic-table';
|
|
4
5
|
export { DynamicKanban, type DynamicKanbanProps, deriveStages, groupByStage, isTransitionAllowed, applyOptimisticMove, selectCardColumns, UNASSIGNED_LANE, } from './dynamic-kanban';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// duplicate-symbol conflict; consumers who want the canonical SDK type
|
|
5
5
|
// should import from `@asteby/metacore-sdk` directly.
|
|
6
6
|
export * from './types';
|
|
7
|
+
export { LicenseGate, LicenseExpiryBanner, LicenseStatusBadge, isLicenseOperable, isLicenseBlocking, isPresetEntitled, isTrialExpired, } from './license';
|
|
7
8
|
export * from './options-context';
|
|
8
9
|
export * from './dynamic-table';
|
|
9
10
|
export { DynamicKanban, deriveStages, groupByStage, isTransitionAllowed, applyOptimisticMove, selectCardColumns, UNASSIGNED_LANE, } from './dynamic-kanban';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { LicenseGate, type LicenseGateProps, } from './license-gate';
|
|
2
|
+
export { LicenseExpiryBanner, type LicenseExpiryBannerProps, } from './license-expiry-banner';
|
|
3
|
+
export { LicenseStatusBadge, type LicenseStatusBadgeProps, } from './license-status-badge';
|
|
4
|
+
export { isLicenseOperable, isLicenseBlocking, isPresetEntitled, isTrialExpired, type LicenseState, type LicenseStatus, type LicenseBranding, } from './types';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/license/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,EACX,KAAK,gBAAgB,GACxB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACH,mBAAmB,EACnB,KAAK,wBAAwB,GAChC,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACH,kBAAkB,EAClB,KAAK,uBAAuB,GAC/B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACH,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,eAAe,GACvB,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { LicenseGate, } from './license-gate';
|
|
2
|
+
export { LicenseExpiryBanner, } from './license-expiry-banner';
|
|
3
|
+
export { LicenseStatusBadge, } from './license-status-badge';
|
|
4
|
+
export { isLicenseOperable, isLicenseBlocking, isPresetEntitled, isTrialExpired, } from './types';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LicenseState } from './types';
|
|
2
|
+
export interface LicenseExpiryBannerProps {
|
|
3
|
+
state: LicenseState | undefined;
|
|
4
|
+
/** Días de anticipación para el aviso de renovación. Default 15. */
|
|
5
|
+
upcomingThresholdDays?: number;
|
|
6
|
+
/** Clave localStorage para recordar el descarte. */
|
|
7
|
+
dismissStorageKey?: string;
|
|
8
|
+
/** Acción "Gestionar licencia" — el host enruta a sus Ajustes. Si se omite,
|
|
9
|
+
* no se muestra el botón (el gate no asume rutas del host). */
|
|
10
|
+
onManage?: () => void;
|
|
11
|
+
/** Etiqueta del botón de gestión (default localizado). */
|
|
12
|
+
manageLabel?: string;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function LicenseExpiryBanner({ state, upcomingThresholdDays, dismissStorageKey, onManage, manageLabel, className, }: LicenseExpiryBannerProps): import("react").JSX.Element | null;
|
|
16
|
+
//# sourceMappingURL=license-expiry-banner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license-expiry-banner.d.ts","sourceRoot":"","sources":["../../src/license/license-expiry-banner.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAU3C,MAAM,WAAW,wBAAwB;IACrC,KAAK,EAAE,YAAY,GAAG,SAAS,CAAA;IAC/B,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;mEAC+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,mBAAmB,CAAC,EAChC,KAAK,EACL,qBAA+C,EAC/C,iBAA+B,EAC/B,QAAQ,EACR,WAAW,EACX,SAAS,GACZ,EAAE,wBAAwB,sCAqG1B"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Banner de vencimiento de licencia — la señal degradada que acompaña a las
|
|
4
|
+
* posturas que NO bloquean la app pero exigen atención:
|
|
5
|
+
* - valid && days_remaining <= threshold → aviso de renovación próxima
|
|
6
|
+
* - stale → check-in con el hub pendiente
|
|
7
|
+
* - grace → vencida, dentro de la gracia
|
|
8
|
+
* - expired → vencida en duro (persistente)
|
|
9
|
+
*
|
|
10
|
+
* Silencioso sin enforcement o si el estado aún no cargó — nunca rompe el shell.
|
|
11
|
+
*
|
|
12
|
+
* Descartabilidad: todas las posturas son descartables con TTL en localStorage
|
|
13
|
+
* (re-aparecen pasado el TTL) MENOS `expired`, que se queda fijo como recordatorio
|
|
14
|
+
* porque el backend ya bloquea escrituras nuevas.
|
|
15
|
+
*/
|
|
16
|
+
import { useState } from 'react';
|
|
17
|
+
import { useTranslation } from 'react-i18next';
|
|
18
|
+
import { AlertTriangle, Clock, CloudOff, X } from 'lucide-react';
|
|
19
|
+
import { Button } from '@asteby/metacore-ui';
|
|
20
|
+
const DISMISS_KEY = 'license_banner_dismissed_at';
|
|
21
|
+
const DISMISS_TTL_MS = 12 * 60 * 60 * 1000; // re-mostrar cada 12h aunque se descarte
|
|
22
|
+
const UPCOMING_THRESHOLD_DAYS = 15;
|
|
23
|
+
function cx(...parts) {
|
|
24
|
+
return parts.filter(Boolean).join(' ');
|
|
25
|
+
}
|
|
26
|
+
export function LicenseExpiryBanner({ state, upcomingThresholdDays = UPCOMING_THRESHOLD_DAYS, dismissStorageKey = DISMISS_KEY, onManage, manageLabel, className, }) {
|
|
27
|
+
const { t } = useTranslation();
|
|
28
|
+
const [dismissed, setDismissed] = useState(() => {
|
|
29
|
+
if (typeof window === 'undefined')
|
|
30
|
+
return false;
|
|
31
|
+
const raw = window.localStorage.getItem(dismissStorageKey);
|
|
32
|
+
if (!raw)
|
|
33
|
+
return false;
|
|
34
|
+
return Date.now() - Number(raw) < DISMISS_TTL_MS;
|
|
35
|
+
});
|
|
36
|
+
if (!state || !state.enforced)
|
|
37
|
+
return null;
|
|
38
|
+
const isUpcoming = state.status === 'valid' && state.days_remaining <= upcomingThresholdDays;
|
|
39
|
+
const isStale = state.status === 'stale';
|
|
40
|
+
const isGrace = state.status === 'grace';
|
|
41
|
+
const isExpired = state.status === 'expired';
|
|
42
|
+
if (!isUpcoming && !isStale && !isGrace && !isExpired)
|
|
43
|
+
return null;
|
|
44
|
+
// Expired no es descartable — se queda como recordatorio constante.
|
|
45
|
+
if (dismissed && !isExpired)
|
|
46
|
+
return null;
|
|
47
|
+
const dismiss = () => {
|
|
48
|
+
setDismissed(true);
|
|
49
|
+
try {
|
|
50
|
+
window.localStorage.setItem(dismissStorageKey, String(Date.now()));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// cuota/entorno sin storage — el descarte solo dura la sesión.
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const message = isExpired
|
|
57
|
+
? t('license.banner.expired', {
|
|
58
|
+
defaultValue: 'Tu licencia venció. Algunas acciones pueden estar bloqueadas.',
|
|
59
|
+
})
|
|
60
|
+
: isStale
|
|
61
|
+
? t('license.banner.stale', {
|
|
62
|
+
defaultValue: 'Esta instancia no ha podido verificar su licencia con el hub. Reconéctala para completar el check-in.',
|
|
63
|
+
})
|
|
64
|
+
: isGrace
|
|
65
|
+
? t('license.banner.grace', {
|
|
66
|
+
defaultValue: 'Tu licencia venció y está en periodo de gracia hasta {{date}} ({{days}} días restantes).',
|
|
67
|
+
date: state.grace_until
|
|
68
|
+
? new Date(state.grace_until).toLocaleDateString()
|
|
69
|
+
: '—',
|
|
70
|
+
days: state.days_remaining,
|
|
71
|
+
})
|
|
72
|
+
: t('license.banner.upcoming', {
|
|
73
|
+
defaultValue: 'Tu licencia vence en {{days}} días.',
|
|
74
|
+
days: state.days_remaining,
|
|
75
|
+
});
|
|
76
|
+
const Icon = isExpired ? AlertTriangle : isStale ? CloudOff : Clock;
|
|
77
|
+
return (_jsxs("div", { role: "alert", "data-license-status": state.status, className: cx('flex items-center justify-between gap-3 border-b px-4 py-2.5 text-sm', isExpired
|
|
78
|
+
? 'border-destructive/30 bg-destructive text-white'
|
|
79
|
+
: 'border-amber-500/30 bg-amber-500/10 text-foreground', className), children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Icon, { className: "h-4 w-4 shrink-0", "aria-hidden": true }), _jsx("span", { className: "truncate", children: message })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [onManage && (_jsx(Button, { size: "sm", variant: isExpired ? 'secondary' : 'outline', onClick: onManage, children: manageLabel ??
|
|
80
|
+
t('license.banner.manage', {
|
|
81
|
+
defaultValue: 'Gestionar licencia',
|
|
82
|
+
}) })), !isExpired && (_jsx(Button, { size: "icon", variant: "ghost", className: "h-7 w-7", onClick: dismiss, title: t('license.banner.dismiss', {
|
|
83
|
+
defaultValue: 'Descartar',
|
|
84
|
+
}), children: _jsx(X, { className: "h-4 w-4" }) }))] })] }));
|
|
85
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <LicenseGate> — el primitivo del blindaje. Un host lo monta en UNA línea
|
|
3
|
+
* envolviendo su app autenticada:
|
|
4
|
+
*
|
|
5
|
+
* <LicenseGate state={state} onActivate={activate}>
|
|
6
|
+
* <AppShell />
|
|
7
|
+
* </LicenseGate>
|
|
8
|
+
*
|
|
9
|
+
* Comportamiento según el estado (resuelto por el backend del host):
|
|
10
|
+
* - Sin enforcement, o estado operable (valid/stale/grace) → renderiza children.
|
|
11
|
+
* stale/grace además montan el <LicenseExpiryBanner> degradado por encima.
|
|
12
|
+
* - enforcement && missing/invalid/expired → modal BLOQUEANTE full-screen,
|
|
13
|
+
* no descartable, con el formulario de activación. Al activar con éxito el
|
|
14
|
+
* host refresca el estado y el gate se abre sin recargar.
|
|
15
|
+
*
|
|
16
|
+
* Es branding-aware si el host pasa `branding` (logo/nombre desde el
|
|
17
|
+
* PlatformConfig del SDK); si no, cae a un encabezado neutro.
|
|
18
|
+
*
|
|
19
|
+
* INDEPENDIENTE del kernel: no importa su cliente ni fija su versión. Solo
|
|
20
|
+
* consume `LicenseState` y una promesa `onActivate`.
|
|
21
|
+
*/
|
|
22
|
+
import { type ReactNode } from 'react';
|
|
23
|
+
import { type LicenseState, type LicenseBranding } from './types';
|
|
24
|
+
export interface LicenseGateProps {
|
|
25
|
+
/** Estado actual, resuelto por el backend del host. `undefined` mientras
|
|
26
|
+
* carga → fail-open (renderiza children, nunca destella el candado). */
|
|
27
|
+
state: LicenseState | undefined;
|
|
28
|
+
/** Activa una licencia con el código/token pegado. Resuelve → el host
|
|
29
|
+
* refresca `state` y el gate se abre. Rechaza con un Error cuyo `message`
|
|
30
|
+
* se muestra al usuario. */
|
|
31
|
+
onActivate: (code: string) => Promise<void>;
|
|
32
|
+
children: ReactNode;
|
|
33
|
+
/** Branding opcional (logo/nombre) para el encabezado del modal. */
|
|
34
|
+
branding?: LicenseBranding;
|
|
35
|
+
/** Acción "Gestionar licencia" del banner degradado (opcional). */
|
|
36
|
+
onManage?: () => void;
|
|
37
|
+
className?: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function LicenseGate({ state, onActivate, children, branding, onManage, className, }: LicenseGateProps): import("react").JSX.Element;
|
|
40
|
+
//# sourceMappingURL=license-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license-gate.d.ts","sourceRoot":"","sources":["../../src/license/license-gate.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAIhD,OAAO,EAGH,KAAK,YAAY,EACjB,KAAK,eAAe,EACvB,MAAM,SAAS,CAAA;AAQhB,MAAM,WAAW,gBAAgB;IAC7B;4EACwE;IACxE,KAAK,EAAE,YAAY,GAAG,SAAS,CAAA;IAC/B;;gCAE4B;IAC5B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3C,QAAQ,EAAE,SAAS,CAAA;IACnB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,WAAW,CAAC,EACxB,KAAK,EACL,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,SAAS,GACZ,EAAE,gBAAgB,+BAqBlB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* <LicenseGate> — el primitivo del blindaje. Un host lo monta en UNA línea
|
|
4
|
+
* envolviendo su app autenticada:
|
|
5
|
+
*
|
|
6
|
+
* <LicenseGate state={state} onActivate={activate}>
|
|
7
|
+
* <AppShell />
|
|
8
|
+
* </LicenseGate>
|
|
9
|
+
*
|
|
10
|
+
* Comportamiento según el estado (resuelto por el backend del host):
|
|
11
|
+
* - Sin enforcement, o estado operable (valid/stale/grace) → renderiza children.
|
|
12
|
+
* stale/grace además montan el <LicenseExpiryBanner> degradado por encima.
|
|
13
|
+
* - enforcement && missing/invalid/expired → modal BLOQUEANTE full-screen,
|
|
14
|
+
* no descartable, con el formulario de activación. Al activar con éxito el
|
|
15
|
+
* host refresca el estado y el gate se abre sin recargar.
|
|
16
|
+
*
|
|
17
|
+
* Es branding-aware si el host pasa `branding` (logo/nombre desde el
|
|
18
|
+
* PlatformConfig del SDK); si no, cae a un encabezado neutro.
|
|
19
|
+
*
|
|
20
|
+
* INDEPENDIENTE del kernel: no importa su cliente ni fija su versión. Solo
|
|
21
|
+
* consume `LicenseState` y una promesa `onActivate`.
|
|
22
|
+
*/
|
|
23
|
+
import { useState } from 'react';
|
|
24
|
+
import { useTranslation } from 'react-i18next';
|
|
25
|
+
import { ShieldAlert, Clock, Loader2 } from 'lucide-react';
|
|
26
|
+
import { Button, Input } from '@asteby/metacore-ui';
|
|
27
|
+
import { isLicenseBlocking, isTrialExpired, } from './types';
|
|
28
|
+
import { LicenseStatusBadge } from './license-status-badge';
|
|
29
|
+
import { LicenseExpiryBanner } from './license-expiry-banner';
|
|
30
|
+
function cx(...parts) {
|
|
31
|
+
return parts.filter(Boolean).join(' ');
|
|
32
|
+
}
|
|
33
|
+
export function LicenseGate({ state, onActivate, children, branding, onManage, className, }) {
|
|
34
|
+
const blocking = isLicenseBlocking(state);
|
|
35
|
+
return (_jsxs(_Fragment, { children: [!blocking && (_jsx(LicenseExpiryBanner, { state: state, onManage: onManage })), children, blocking && state && (_jsx(LicenseGateModal, { state: state, onActivate: onActivate, branding: branding, className: className }))] }));
|
|
36
|
+
}
|
|
37
|
+
function LicenseGateModal({ state, onActivate, branding, className, }) {
|
|
38
|
+
const { t } = useTranslation();
|
|
39
|
+
const [code, setCode] = useState('');
|
|
40
|
+
const [submitting, setSubmitting] = useState(false);
|
|
41
|
+
const [error, setError] = useState(null);
|
|
42
|
+
const trialExpired = isTrialExpired(state);
|
|
43
|
+
const title = trialExpired
|
|
44
|
+
? t('license.gate.trial_title', {
|
|
45
|
+
defaultValue: 'Tu prueba gratuita terminó',
|
|
46
|
+
})
|
|
47
|
+
: t('license.gate.title', { defaultValue: 'Activa tu licencia' });
|
|
48
|
+
const description = trialExpired
|
|
49
|
+
? t('license.gate.trial_description', {
|
|
50
|
+
defaultValue: 'Tu prueba gratuita terminó. Activa una licencia para continuar. Pega tu clave (lic_…) o el token firmado que te entregaron.',
|
|
51
|
+
})
|
|
52
|
+
: state.status === 'expired'
|
|
53
|
+
? t('license.gate.expired_description', {
|
|
54
|
+
defaultValue: 'Tu licencia venció y el periodo de gracia terminó. Activa una licencia vigente para seguir operando. Pega tu clave (lic_…) o el token firmado.',
|
|
55
|
+
})
|
|
56
|
+
: state.status === 'invalid'
|
|
57
|
+
? t('license.gate.invalid_description', {
|
|
58
|
+
defaultValue: 'La licencia de esta instancia no es válida. Pega una clave (lic_…) o el token firmado que te entregó tu proveedor para reactivarla.',
|
|
59
|
+
})
|
|
60
|
+
: t('license.gate.missing_description', {
|
|
61
|
+
defaultValue: 'Esta instancia necesita una licencia activa para operar. Pega tu clave (lic_…) o el token firmado para activarla.',
|
|
62
|
+
});
|
|
63
|
+
const canSubmit = code.trim().length > 0 && !submitting;
|
|
64
|
+
const submit = async () => {
|
|
65
|
+
if (!canSubmit)
|
|
66
|
+
return;
|
|
67
|
+
setSubmitting(true);
|
|
68
|
+
setError(null);
|
|
69
|
+
try {
|
|
70
|
+
await onActivate(code.trim());
|
|
71
|
+
// Éxito → el host refresca `state`; el gate se re-renderiza y este
|
|
72
|
+
// modal se desmonta solo. No recargamos.
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
const message = e instanceof Error && e.message
|
|
76
|
+
? e.message
|
|
77
|
+
: t('license.gate.activate_error', {
|
|
78
|
+
defaultValue: 'No se pudo activar la licencia.',
|
|
79
|
+
});
|
|
80
|
+
setError(message);
|
|
81
|
+
setSubmitting(false);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return (_jsx("div", { role: "dialog", "aria-modal": "true", "aria-labelledby": "license-gate-title", "data-license-status": state.status, className: cx('fixed inset-0 z-[100] flex items-center justify-center bg-background/90 p-4 backdrop-blur-sm', className), children: _jsx("div", { className: "w-full max-w-lg overflow-hidden rounded-2xl border bg-card text-card-foreground shadow-2xl", children: _jsxs("div", { className: "flex flex-col gap-4 p-6", children: [_jsxs("div", { className: "flex items-start gap-3", children: [branding?.logo ? (_jsx("img", { src: branding.logo, alt: branding.name ?? '', className: "h-10 w-10 shrink-0 rounded-xl object-contain" })) : (_jsx("div", { className: cx('flex h-10 w-10 shrink-0 items-center justify-center rounded-xl', trialExpired
|
|
85
|
+
? 'bg-primary/10 text-primary'
|
|
86
|
+
: 'bg-destructive/10 text-destructive'), children: trialExpired ? (_jsx(Clock, { className: "h-5 w-5", "aria-hidden": true })) : (_jsx(ShieldAlert, { className: "h-5 w-5", "aria-hidden": true })) })), _jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [_jsx("h2", { id: "license-gate-title", className: "text-lg leading-tight font-semibold", children: title }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(LicenseStatusBadge, { status: state.status }), _jsx("span", { className: "text-muted-foreground text-xs", children: branding?.name
|
|
87
|
+
? branding.name
|
|
88
|
+
: t('license.gate.instance', {
|
|
89
|
+
defaultValue: 'Esta instancia',
|
|
90
|
+
}) })] })] })] }), _jsx("p", { className: "text-muted-foreground text-sm", children: description }), state.reason && (_jsx("p", { className: "bg-muted/50 text-muted-foreground rounded-md px-3 py-2 text-xs", children: state.reason })), _jsxs("form", { className: "flex flex-col gap-2", onSubmit: (e) => {
|
|
91
|
+
e.preventDefault();
|
|
92
|
+
void submit();
|
|
93
|
+
}, children: [_jsx("label", { htmlFor: "license-gate-code", className: "text-sm font-medium", children: t('license.gate.code_label', {
|
|
94
|
+
defaultValue: 'Clave o token de licencia',
|
|
95
|
+
}) }), _jsx(Input, { id: "license-gate-code", autoFocus: true, autoComplete: "off", spellCheck: false, placeholder: t('license.gate.code_placeholder', {
|
|
96
|
+
defaultValue: 'lic_… o pega el token firmado',
|
|
97
|
+
}), value: code, disabled: submitting, "aria-invalid": error ? true : undefined, onChange: (e) => {
|
|
98
|
+
setCode(e.target.value);
|
|
99
|
+
if (error)
|
|
100
|
+
setError(null);
|
|
101
|
+
} }), error && (_jsx("p", { role: "alert", className: "text-destructive text-sm", children: error })), _jsxs(Button, { type: "submit", className: "mt-1 w-full", disabled: !canSubmit, children: [submitting && (_jsx(Loader2, { className: "h-4 w-4 animate-spin", "aria-hidden": true })), submitting
|
|
102
|
+
? t('license.gate.activating', {
|
|
103
|
+
defaultValue: 'Activando…',
|
|
104
|
+
})
|
|
105
|
+
: t('license.gate.activate', {
|
|
106
|
+
defaultValue: 'Activar licencia',
|
|
107
|
+
})] })] })] }) }) }));
|
|
108
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LicenseStatus } from './types';
|
|
2
|
+
export interface LicenseStatusBadgeProps {
|
|
3
|
+
status: LicenseStatus;
|
|
4
|
+
className?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function LicenseStatusBadge({ status, className }: LicenseStatusBadgeProps): import("react").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=license-status-badge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license-status-badge.d.ts","sourceRoot":"","sources":["../../src/license/license-status-badge.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAuD5C,MAAM,WAAW,uBAAuB;IACpC,MAAM,EAAE,aAAa,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,uBAAuB,+BAkBhF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Insignia de estado de licencia — un chip que traduce el `LicenseStatus` a
|
|
4
|
+
* color + etiqueta legible. Reutilizable suelto (p. ej. en Ajustes de licencia)
|
|
5
|
+
* o embebido en el encabezado del <LicenseGate>.
|
|
6
|
+
*/
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
import { ShieldCheck, ShieldAlert, ShieldQuestion, Clock, CloudOff, } from 'lucide-react';
|
|
9
|
+
import { Badge } from '@asteby/metacore-ui';
|
|
10
|
+
const STATUS_META = {
|
|
11
|
+
valid: {
|
|
12
|
+
variant: 'default',
|
|
13
|
+
Icon: ShieldCheck,
|
|
14
|
+
key: 'license.status.valid',
|
|
15
|
+
defaultValue: 'Activa',
|
|
16
|
+
},
|
|
17
|
+
stale: {
|
|
18
|
+
variant: 'outline',
|
|
19
|
+
Icon: CloudOff,
|
|
20
|
+
key: 'license.status.stale',
|
|
21
|
+
defaultValue: 'Sin verificar',
|
|
22
|
+
warn: true,
|
|
23
|
+
},
|
|
24
|
+
grace: {
|
|
25
|
+
variant: 'outline',
|
|
26
|
+
Icon: Clock,
|
|
27
|
+
key: 'license.status.grace',
|
|
28
|
+
defaultValue: 'En gracia',
|
|
29
|
+
warn: true,
|
|
30
|
+
},
|
|
31
|
+
expired: {
|
|
32
|
+
variant: 'destructive',
|
|
33
|
+
Icon: ShieldAlert,
|
|
34
|
+
key: 'license.status.expired',
|
|
35
|
+
defaultValue: 'Vencida',
|
|
36
|
+
},
|
|
37
|
+
missing: {
|
|
38
|
+
variant: 'secondary',
|
|
39
|
+
Icon: ShieldQuestion,
|
|
40
|
+
key: 'license.status.missing',
|
|
41
|
+
defaultValue: 'Sin licencia',
|
|
42
|
+
},
|
|
43
|
+
invalid: {
|
|
44
|
+
variant: 'destructive',
|
|
45
|
+
Icon: ShieldAlert,
|
|
46
|
+
key: 'license.status.invalid',
|
|
47
|
+
defaultValue: 'Inválida',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
export function LicenseStatusBadge({ status, className }) {
|
|
51
|
+
const { t } = useTranslation();
|
|
52
|
+
const meta = STATUS_META[status] ?? STATUS_META.missing;
|
|
53
|
+
const { Icon } = meta;
|
|
54
|
+
return (_jsxs(Badge, { variant: meta.variant, className: (meta.warn
|
|
55
|
+
? 'border-amber-500/40 bg-amber-500/10 text-amber-700 dark:text-amber-400 '
|
|
56
|
+
: '') + (className ?? ''), children: [_jsx(Icon, { "aria-hidden": true }), t(meta.key, { defaultValue: meta.defaultValue })] }));
|
|
57
|
+
}
|