@nice2dev/licensing 1.0.10

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/react.mjs ADDED
@@ -0,0 +1,1039 @@
1
+ import { jsx, Fragment, jsxs } from "react/jsx-runtime";
2
+ import { createContext, useState, useCallback, useEffect, useContext } from "react";
3
+ import { c as checkFeatureAccess, k as getAllPlans, L as LicenseValidator, D as normalizeLicenseKey, y as hasFeature, C as maskLicenseKey, r as getMissingFeatures } from "./FeatureGate-Da7fCJA5.js";
4
+ const LicenseContext = createContext(null);
5
+ function LicenseProvider({
6
+ serverUrl = "https://license.nice2dev.com/api/v1",
7
+ apiKey,
8
+ initialKey,
9
+ storageKey = "nice2dev_license_key",
10
+ autoValidate = true,
11
+ validationInterval = 36e5,
12
+ // 1 hour
13
+ onLicenseChange,
14
+ children
15
+ }) {
16
+ var _a;
17
+ const [state, setState] = useState({
18
+ license: null,
19
+ validation: null,
20
+ loading: true,
21
+ error: null,
22
+ features: /* @__PURE__ */ new Set(),
23
+ fingerprint: null
24
+ });
25
+ const [validator] = useState(() => new LicenseValidator({ serverUrl, apiKey }));
26
+ const loadStoredKey = useCallback(() => {
27
+ if (typeof localStorage === "undefined") {
28
+ return null;
29
+ }
30
+ try {
31
+ return localStorage.getItem(storageKey);
32
+ } catch {
33
+ return null;
34
+ }
35
+ }, [storageKey]);
36
+ const saveKey = useCallback(
37
+ (key) => {
38
+ if (typeof localStorage === "undefined") {
39
+ return;
40
+ }
41
+ try {
42
+ if (key) {
43
+ localStorage.setItem(storageKey, key);
44
+ } else {
45
+ localStorage.removeItem(storageKey);
46
+ }
47
+ } catch {
48
+ }
49
+ },
50
+ [storageKey]
51
+ );
52
+ const validateLicense = useCallback(
53
+ async (key) => {
54
+ setState((s) => ({ ...s, loading: true, error: null }));
55
+ try {
56
+ const result = await validator.validate(key);
57
+ setState((s) => ({
58
+ ...s,
59
+ license: result.license || null,
60
+ validation: result,
61
+ loading: false,
62
+ error: result.valid ? null : result.errorMessage || "Validation failed",
63
+ features: new Set(result.availableFeatures || [])
64
+ }));
65
+ if (result.valid && result.license) {
66
+ onLicenseChange == null ? void 0 : onLicenseChange(result.license);
67
+ }
68
+ return result;
69
+ } catch (error) {
70
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
71
+ setState((s) => ({
72
+ ...s,
73
+ loading: false,
74
+ error: errorMessage,
75
+ validation: {
76
+ valid: false,
77
+ errorCode: "SERVER_ERROR",
78
+ errorMessage,
79
+ validatedAt: (/* @__PURE__ */ new Date()).toISOString()
80
+ }
81
+ }));
82
+ return {
83
+ valid: false,
84
+ errorCode: "SERVER_ERROR",
85
+ errorMessage,
86
+ validatedAt: (/* @__PURE__ */ new Date()).toISOString()
87
+ };
88
+ }
89
+ },
90
+ [validator, onLicenseChange]
91
+ );
92
+ const activate = useCallback(
93
+ async (key) => {
94
+ const normalized = normalizeLicenseKey(key);
95
+ if (!normalized) {
96
+ const result2 = {
97
+ valid: false,
98
+ errorCode: "INVALID_KEY",
99
+ errorMessage: "Invalid license key format",
100
+ validatedAt: (/* @__PURE__ */ new Date()).toISOString()
101
+ };
102
+ setState((s) => ({ ...s, error: result2.errorMessage || null, validation: result2 }));
103
+ return result2;
104
+ }
105
+ const result = await validateLicense(normalized);
106
+ if (result.valid) {
107
+ saveKey(normalized);
108
+ }
109
+ return result;
110
+ },
111
+ [validateLicense, saveKey]
112
+ );
113
+ const deactivate = useCallback(async () => {
114
+ const key = loadStoredKey();
115
+ if (key) {
116
+ await validator.deactivateMachine(key);
117
+ }
118
+ saveKey(null);
119
+ setState({
120
+ license: null,
121
+ validation: null,
122
+ loading: false,
123
+ error: null,
124
+ features: /* @__PURE__ */ new Set(),
125
+ fingerprint: null
126
+ });
127
+ onLicenseChange == null ? void 0 : onLicenseChange(null);
128
+ }, [validator, loadStoredKey, saveKey, onLicenseChange]);
129
+ const refresh = useCallback(async () => {
130
+ var _a2;
131
+ const key = ((_a2 = state.license) == null ? void 0 : _a2.key) || loadStoredKey();
132
+ if (key) {
133
+ await validateLicense(key);
134
+ }
135
+ }, [(_a = state.license) == null ? void 0 : _a.key, loadStoredKey, validateLicense]);
136
+ const checkFeature = useCallback(
137
+ (featureId) => {
138
+ return hasFeature(state.license, featureId);
139
+ },
140
+ [state.license]
141
+ );
142
+ useEffect(() => {
143
+ if (!autoValidate) {
144
+ setState((s) => ({ ...s, loading: false }));
145
+ return;
146
+ }
147
+ const key = initialKey || loadStoredKey();
148
+ if (key) {
149
+ validateLicense(key);
150
+ } else {
151
+ setState((s) => ({ ...s, loading: false }));
152
+ }
153
+ }, [autoValidate, initialKey, loadStoredKey, validateLicense]);
154
+ useEffect(() => {
155
+ if (validationInterval <= 0 || !state.license) {
156
+ return;
157
+ }
158
+ const interval = setInterval(() => {
159
+ refresh();
160
+ }, validationInterval);
161
+ return () => clearInterval(interval);
162
+ }, [validationInterval, state.license, refresh]);
163
+ const value = {
164
+ ...state,
165
+ activate,
166
+ deactivate,
167
+ refresh,
168
+ hasFeature: checkFeature
169
+ };
170
+ return /* @__PURE__ */ jsx(LicenseContext.Provider, { value, children });
171
+ }
172
+ function useLicense() {
173
+ const context = useContext(LicenseContext);
174
+ if (!context) {
175
+ throw new Error("useLicense must be used within a LicenseProvider");
176
+ }
177
+ return context;
178
+ }
179
+ function useFeature(featureId) {
180
+ const { license, loading, error } = useLicense();
181
+ const allowed = hasFeature(license, featureId);
182
+ return { allowed, loading, error };
183
+ }
184
+ function FeatureGate({
185
+ feature,
186
+ children,
187
+ fallback = null,
188
+ showUpgradePrompt = false,
189
+ renderUpgradePrompt
190
+ }) {
191
+ const { license, loading } = useLicense();
192
+ if (loading) {
193
+ return null;
194
+ }
195
+ const result = checkFeatureAccess(license, feature);
196
+ if (result.allowed) {
197
+ return /* @__PURE__ */ jsx(Fragment, { children });
198
+ }
199
+ if (showUpgradePrompt && result.upgradeTarget) {
200
+ if (renderUpgradePrompt) {
201
+ return /* @__PURE__ */ jsx(Fragment, { children: renderUpgradePrompt(result.upgradeTarget) });
202
+ }
203
+ return /* @__PURE__ */ jsx(UpgradePrompt, { targetTier: result.upgradeTarget, feature });
204
+ }
205
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
206
+ }
207
+ function LicenseStatus({ detailed = false, style, className }) {
208
+ const { license, validation, loading, error } = useLicense();
209
+ const baseStyle = {
210
+ padding: "8px 12px",
211
+ borderRadius: "6px",
212
+ fontSize: "14px",
213
+ display: "inline-flex",
214
+ alignItems: "center",
215
+ gap: "8px",
216
+ ...style
217
+ };
218
+ if (loading) {
219
+ return /* @__PURE__ */ jsxs(
220
+ "div",
221
+ {
222
+ style: { ...baseStyle, backgroundColor: "#f0f0f0", color: "#666" },
223
+ className,
224
+ children: [
225
+ /* @__PURE__ */ jsx("span", { children: "⏳" }),
226
+ /* @__PURE__ */ jsx("span", { children: "Checking license..." })
227
+ ]
228
+ }
229
+ );
230
+ }
231
+ if (error || !license) {
232
+ return /* @__PURE__ */ jsxs(
233
+ "div",
234
+ {
235
+ style: { ...baseStyle, backgroundColor: "#fee2e2", color: "#991b1b" },
236
+ className,
237
+ children: [
238
+ /* @__PURE__ */ jsx("span", { children: "⚠️" }),
239
+ /* @__PURE__ */ jsx("span", { children: error || "No license" })
240
+ ]
241
+ }
242
+ );
243
+ }
244
+ const tierColors = {
245
+ trial: "#fef3c7",
246
+ personal: "#dbeafe",
247
+ team: "#d1fae5",
248
+ enterprise: "#ede9fe",
249
+ site: "#fce7f3",
250
+ oem: "#f3e8ff"
251
+ };
252
+ const tierTextColors = {
253
+ trial: "#92400e",
254
+ personal: "#1e40af",
255
+ team: "#065f46",
256
+ enterprise: "#5b21b6",
257
+ site: "#9d174d",
258
+ oem: "#7c3aed"
259
+ };
260
+ const bgColor = tierColors[license.tier] || "#f0f0f0";
261
+ const textColor = tierTextColors[license.tier] || "#333";
262
+ return /* @__PURE__ */ jsxs("div", { style: { ...baseStyle, backgroundColor: bgColor, color: textColor }, className, children: [
263
+ /* @__PURE__ */ jsx("span", { children: "✓" }),
264
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600 }, children: license.tier.charAt(0).toUpperCase() + license.tier.slice(1) }),
265
+ (validation == null ? void 0 : validation.inGracePeriod) && /* @__PURE__ */ jsx("span", { style: { color: "#dc2626", fontSize: "12px" }, children: "(Grace period)" }),
266
+ detailed && (validation == null ? void 0 : validation.daysRemaining) !== void 0 && validation.daysRemaining > 0 && /* @__PURE__ */ jsxs("span", { style: { fontSize: "12px", opacity: 0.8 }, children: [
267
+ validation.daysRemaining,
268
+ " days remaining"
269
+ ] }),
270
+ detailed && /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", opacity: 0.6 }, children: maskLicenseKey(license.key) })
271
+ ] });
272
+ }
273
+ function LicenseActivator({
274
+ onActivated,
275
+ onError,
276
+ style,
277
+ className
278
+ }) {
279
+ const { activate, loading } = useLicense();
280
+ const [key, setKey] = useState("");
281
+ const [localError, setLocalError] = useState(null);
282
+ const [isActivating, setIsActivating] = useState(false);
283
+ const handleSubmit = async (e) => {
284
+ e.preventDefault();
285
+ if (!key.trim() || isActivating) {
286
+ return;
287
+ }
288
+ setIsActivating(true);
289
+ setLocalError(null);
290
+ try {
291
+ const result = await activate(key.trim());
292
+ if (result.valid && result.license) {
293
+ setKey("");
294
+ onActivated == null ? void 0 : onActivated(result.license);
295
+ } else {
296
+ setLocalError(result.errorMessage || "Activation failed");
297
+ onError == null ? void 0 : onError(result.errorMessage || "Activation failed");
298
+ }
299
+ } finally {
300
+ setIsActivating(false);
301
+ }
302
+ };
303
+ const containerStyle = {
304
+ display: "flex",
305
+ flexDirection: "column",
306
+ gap: "12px",
307
+ padding: "16px",
308
+ border: "1px solid #e5e7eb",
309
+ borderRadius: "8px",
310
+ backgroundColor: "#fff",
311
+ ...style
312
+ };
313
+ const inputStyle = {
314
+ padding: "10px 12px",
315
+ fontSize: "14px",
316
+ fontFamily: "monospace",
317
+ border: "1px solid #d1d5db",
318
+ borderRadius: "6px",
319
+ outline: "none",
320
+ textTransform: "uppercase"
321
+ };
322
+ const buttonStyle = {
323
+ padding: "10px 16px",
324
+ fontSize: "14px",
325
+ fontWeight: 600,
326
+ color: "#fff",
327
+ backgroundColor: isActivating || loading ? "#9ca3af" : "#2563eb",
328
+ border: "none",
329
+ borderRadius: "6px",
330
+ cursor: isActivating || loading ? "not-allowed" : "pointer"
331
+ };
332
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: containerStyle, className, children: [
333
+ /* @__PURE__ */ jsx("label", { style: { fontWeight: 500, color: "#374151" }, children: "Enter License Key" }),
334
+ /* @__PURE__ */ jsx(
335
+ "input",
336
+ {
337
+ type: "text",
338
+ value: key,
339
+ onChange: (e) => setKey(e.target.value),
340
+ placeholder: "XXXX-XXXX-XXXX-XXXX-XXXX",
341
+ style: inputStyle,
342
+ disabled: isActivating || loading
343
+ }
344
+ ),
345
+ localError && /* @__PURE__ */ jsx("div", { style: { color: "#dc2626", fontSize: "13px" }, children: localError }),
346
+ /* @__PURE__ */ jsx("button", { type: "submit", style: buttonStyle, disabled: isActivating || loading || !key.trim(), children: isActivating ? "Activating..." : "Activate License" })
347
+ ] });
348
+ }
349
+ function UpgradePrompt({
350
+ targetTier,
351
+ feature,
352
+ onUpgrade,
353
+ style,
354
+ compact = false
355
+ }) {
356
+ const { license } = useLicense();
357
+ const missingFeatures = getMissingFeatures(license, targetTier);
358
+ const handleUpgrade = () => {
359
+ onUpgrade == null ? void 0 : onUpgrade(targetTier);
360
+ if (!onUpgrade) {
361
+ window.open(`https://nice2dev.com/pricing?upgrade=${targetTier}`, "_blank");
362
+ }
363
+ };
364
+ const containerStyle = {
365
+ padding: compact ? "12px" : "20px",
366
+ backgroundColor: "#eff6ff",
367
+ borderRadius: "8px",
368
+ border: "1px solid #bfdbfe",
369
+ ...style
370
+ };
371
+ const titleStyle = {
372
+ fontSize: compact ? "14px" : "16px",
373
+ fontWeight: 600,
374
+ color: "#1e40af",
375
+ marginBottom: "8px"
376
+ };
377
+ const buttonStyle = {
378
+ padding: "8px 16px",
379
+ fontSize: "14px",
380
+ fontWeight: 600,
381
+ color: "#fff",
382
+ backgroundColor: "#2563eb",
383
+ border: "none",
384
+ borderRadius: "6px",
385
+ cursor: "pointer",
386
+ marginTop: "12px"
387
+ };
388
+ return /* @__PURE__ */ jsxs("div", { style: containerStyle, children: [
389
+ /* @__PURE__ */ jsxs("div", { style: titleStyle, children: [
390
+ "🚀 Upgrade to ",
391
+ targetTier.charAt(0).toUpperCase() + targetTier.slice(1)
392
+ ] }),
393
+ !compact && missingFeatures.length > 0 && /* @__PURE__ */ jsxs("ul", { style: { margin: "8px 0", paddingLeft: "20px", color: "#374151", fontSize: "14px" }, children: [
394
+ missingFeatures.slice(0, 3).map((f) => /* @__PURE__ */ jsx("li", { children: f.name }, f.id)),
395
+ missingFeatures.length > 3 && /* @__PURE__ */ jsxs("li", { children: [
396
+ "+",
397
+ missingFeatures.length - 3,
398
+ " more features"
399
+ ] })
400
+ ] }),
401
+ /* @__PURE__ */ jsx("button", { onClick: handleUpgrade, style: buttonStyle, children: "Upgrade Now" })
402
+ ] });
403
+ }
404
+ function LicenseComparison({
405
+ plans: customPlans,
406
+ currentTier,
407
+ onSelect,
408
+ showPrices = true
409
+ }) {
410
+ const { license } = useLicense();
411
+ const tier = currentTier || (license == null ? void 0 : license.tier);
412
+ const plans = customPlans || getAllPlans().filter((p) => p.priceMonthly > 0 || p.id === "trial");
413
+ const formatPrice = (cents) => {
414
+ if (cents === 0) {
415
+ return "Free";
416
+ }
417
+ return `$${(cents / 100).toFixed(0)}`;
418
+ };
419
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "16px", flexWrap: "wrap", justifyContent: "center" }, children: plans.map((plan) => {
420
+ const isCurrent = plan.id === tier;
421
+ const isRecommended = plan.recommended;
422
+ return /* @__PURE__ */ jsxs(
423
+ "div",
424
+ {
425
+ style: {
426
+ flex: "1 1 250px",
427
+ maxWidth: "300px",
428
+ padding: "24px",
429
+ borderRadius: "12px",
430
+ border: isRecommended ? "2px solid #2563eb" : "1px solid #e5e7eb",
431
+ backgroundColor: isCurrent ? "#f0f9ff" : "#fff",
432
+ position: "relative"
433
+ },
434
+ children: [
435
+ isRecommended && /* @__PURE__ */ jsx(
436
+ "div",
437
+ {
438
+ style: {
439
+ position: "absolute",
440
+ top: "-12px",
441
+ left: "50%",
442
+ transform: "translateX(-50%)",
443
+ backgroundColor: "#2563eb",
444
+ color: "#fff",
445
+ padding: "4px 12px",
446
+ borderRadius: "12px",
447
+ fontSize: "12px",
448
+ fontWeight: 600
449
+ },
450
+ children: "Recommended"
451
+ }
452
+ ),
453
+ /* @__PURE__ */ jsx("h3", { style: { margin: "0 0 4px", fontSize: "20px", color: "#111" }, children: plan.name }),
454
+ /* @__PURE__ */ jsx("p", { style: { margin: "0 0 16px", fontSize: "14px", color: "#6b7280" }, children: plan.description }),
455
+ showPrices && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "16px" }, children: [
456
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "32px", fontWeight: 700, color: "#111" }, children: formatPrice(plan.priceMonthly) }),
457
+ plan.priceMonthly > 0 && /* @__PURE__ */ jsx("span", { style: { fontSize: "14px", color: "#6b7280" }, children: "/month" })
458
+ ] }),
459
+ /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", padding: 0, margin: "0 0 16px" }, children: plan.highlights.map((h, i) => /* @__PURE__ */ jsxs("li", { style: { padding: "6px 0", fontSize: "14px", color: "#374151" }, children: [
460
+ "✓ ",
461
+ h
462
+ ] }, i)) }),
463
+ /* @__PURE__ */ jsx(
464
+ "button",
465
+ {
466
+ onClick: () => onSelect == null ? void 0 : onSelect(plan),
467
+ disabled: isCurrent,
468
+ style: {
469
+ width: "100%",
470
+ padding: "10px",
471
+ fontSize: "14px",
472
+ fontWeight: 600,
473
+ color: isCurrent ? "#9ca3af" : isRecommended ? "#fff" : "#2563eb",
474
+ backgroundColor: isCurrent ? "#f3f4f6" : isRecommended ? "#2563eb" : "#fff",
475
+ border: isCurrent ? "none" : isRecommended ? "none" : "1px solid #2563eb",
476
+ borderRadius: "6px",
477
+ cursor: isCurrent ? "default" : "pointer"
478
+ },
479
+ children: isCurrent ? "Current Plan" : "Select"
480
+ }
481
+ )
482
+ ]
483
+ },
484
+ plan.id
485
+ );
486
+ }) });
487
+ }
488
+ function TrialWatermark({
489
+ position = "bottom-right",
490
+ text = "Trial Version"
491
+ }) {
492
+ const { license, hasFeature: hasFeature2 } = useLicense();
493
+ if (!hasFeature2("trial-watermark") && (license == null ? void 0 : license.tier) !== "trial") {
494
+ return null;
495
+ }
496
+ const positions = {
497
+ "top-left": { top: "16px", left: "16px" },
498
+ "top-right": { top: "16px", right: "16px" },
499
+ "bottom-left": { bottom: "16px", left: "16px" },
500
+ "bottom-right": { bottom: "16px", right: "16px" }
501
+ };
502
+ return /* @__PURE__ */ jsx(
503
+ "div",
504
+ {
505
+ style: {
506
+ position: "fixed",
507
+ ...positions[position],
508
+ padding: "8px 16px",
509
+ backgroundColor: "rgba(0, 0, 0, 0.8)",
510
+ color: "#fff",
511
+ fontSize: "12px",
512
+ fontWeight: 600,
513
+ borderRadius: "4px",
514
+ zIndex: 9999,
515
+ pointerEvents: "none"
516
+ },
517
+ children: text
518
+ }
519
+ );
520
+ }
521
+ function LicensePortal({
522
+ tabs = ["overview", "activation", "seats", "features", "plans"],
523
+ defaultTab = "overview",
524
+ onUpgrade,
525
+ onDeactivate,
526
+ style,
527
+ className
528
+ }) {
529
+ const {
530
+ license,
531
+ validation,
532
+ loading,
533
+ error,
534
+ deactivate,
535
+ refresh,
536
+ hasFeature: checkFeat
537
+ } = useLicense();
538
+ const [activeTab, setActiveTab] = useState(defaultTab);
539
+ const [refreshing, setRefreshing] = useState(false);
540
+ const handleRefresh = async () => {
541
+ setRefreshing(true);
542
+ try {
543
+ await refresh();
544
+ } finally {
545
+ setRefreshing(false);
546
+ }
547
+ };
548
+ const handleDeactivate = async () => {
549
+ await deactivate();
550
+ onDeactivate == null ? void 0 : onDeactivate();
551
+ };
552
+ const tabLabels = {
553
+ overview: "Overview",
554
+ activation: "Activation",
555
+ seats: "Seats",
556
+ features: "Features",
557
+ plans: "Plans"
558
+ };
559
+ const containerStyle = {
560
+ border: "1px solid #e5e7eb",
561
+ borderRadius: "12px",
562
+ backgroundColor: "#fff",
563
+ overflow: "hidden",
564
+ ...style
565
+ };
566
+ const tabBarStyle = {
567
+ display: "flex",
568
+ borderBottom: "1px solid #e5e7eb",
569
+ backgroundColor: "#f9fafb"
570
+ };
571
+ const getTabStyle = (tab) => ({
572
+ padding: "12px 20px",
573
+ fontSize: "14px",
574
+ fontWeight: activeTab === tab ? 600 : 400,
575
+ color: activeTab === tab ? "#2563eb" : "#6b7280",
576
+ backgroundColor: "transparent",
577
+ border: "none",
578
+ borderBottom: activeTab === tab ? "2px solid #2563eb" : "2px solid transparent",
579
+ cursor: "pointer"
580
+ });
581
+ const panelStyle = { padding: "24px" };
582
+ return /* @__PURE__ */ jsxs("div", { style: containerStyle, className, children: [
583
+ /* @__PURE__ */ jsx("div", { style: tabBarStyle, children: tabs.map((tab) => /* @__PURE__ */ jsx("button", { style: getTabStyle(tab), onClick: () => setActiveTab(tab), children: tabLabels[tab] }, tab)) }),
584
+ /* @__PURE__ */ jsxs("div", { style: panelStyle, children: [
585
+ loading && /* @__PURE__ */ jsx("p", { style: { color: "#6b7280" }, children: "Loading license information..." }),
586
+ !loading && activeTab === "overview" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [
587
+ /* @__PURE__ */ jsx(LicenseStatus, { detailed: true }),
588
+ license && /* @__PURE__ */ jsxs(Fragment, { children: [
589
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "12px" }, children: [
590
+ /* @__PURE__ */ jsxs("div", { children: [
591
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "#6b7280" }, children: "Licensee" }),
592
+ /* @__PURE__ */ jsx("p", { style: { margin: "2px 0 0", fontWeight: 500 }, children: license.licensee })
593
+ ] }),
594
+ /* @__PURE__ */ jsxs("div", { children: [
595
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "#6b7280" }, children: "Email" }),
596
+ /* @__PURE__ */ jsx("p", { style: { margin: "2px 0 0", fontWeight: 500 }, children: license.email })
597
+ ] }),
598
+ /* @__PURE__ */ jsxs("div", { children: [
599
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "#6b7280" }, children: "Seats" }),
600
+ /* @__PURE__ */ jsxs("p", { style: { margin: "2px 0 0", fontWeight: 500 }, children: [
601
+ license.activeSeats,
602
+ " / ",
603
+ license.maxSeats ?? "∞"
604
+ ] })
605
+ ] }),
606
+ /* @__PURE__ */ jsxs("div", { children: [
607
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "#6b7280" }, children: "Expires" }),
608
+ /* @__PURE__ */ jsx("p", { style: { margin: "2px 0 0", fontWeight: 500 }, children: license.expiresAt ? new Date(license.expiresAt).toLocaleDateString() : "Perpetual" })
609
+ ] })
610
+ ] }),
611
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
612
+ /* @__PURE__ */ jsx(
613
+ "button",
614
+ {
615
+ onClick: handleRefresh,
616
+ disabled: refreshing,
617
+ style: {
618
+ padding: "8px 16px",
619
+ fontSize: "13px",
620
+ border: "1px solid #d1d5db",
621
+ borderRadius: "6px",
622
+ backgroundColor: "#fff",
623
+ cursor: refreshing ? "not-allowed" : "pointer"
624
+ },
625
+ children: refreshing ? "Refreshing..." : "Refresh"
626
+ }
627
+ ),
628
+ /* @__PURE__ */ jsx(
629
+ "button",
630
+ {
631
+ onClick: handleDeactivate,
632
+ style: {
633
+ padding: "8px 16px",
634
+ fontSize: "13px",
635
+ color: "#dc2626",
636
+ border: "1px solid #fecaca",
637
+ borderRadius: "6px",
638
+ backgroundColor: "#fff",
639
+ cursor: "pointer"
640
+ },
641
+ children: "Deactivate"
642
+ }
643
+ )
644
+ ] })
645
+ ] }),
646
+ !license && !error && /* @__PURE__ */ jsx("p", { style: { color: "#6b7280" }, children: "No active license. Go to the Activation tab to enter your license key." }),
647
+ error && /* @__PURE__ */ jsx("p", { style: { color: "#dc2626" }, children: error })
648
+ ] }),
649
+ !loading && activeTab === "activation" && /* @__PURE__ */ jsx(LicenseActivator, { onActivated: () => setActiveTab("overview") }),
650
+ !loading && activeTab === "seats" && /* @__PURE__ */ jsx("div", { children: license ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
651
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: "14px", color: "#374151" }, children: [
652
+ /* @__PURE__ */ jsx("strong", { children: license.activeSeats }),
653
+ " of",
654
+ " ",
655
+ /* @__PURE__ */ jsx("strong", { children: license.maxSeats ?? "∞" }),
656
+ " seats in use",
657
+ license.floatingSeats != null && /* @__PURE__ */ jsxs("span", { children: [
658
+ " (",
659
+ license.floatingSeats,
660
+ " floating)"
661
+ ] })
662
+ ] }),
663
+ /* @__PURE__ */ jsx(
664
+ "div",
665
+ {
666
+ style: {
667
+ height: "8px",
668
+ borderRadius: "4px",
669
+ backgroundColor: "#e5e7eb",
670
+ overflow: "hidden"
671
+ },
672
+ children: /* @__PURE__ */ jsx(
673
+ "div",
674
+ {
675
+ style: {
676
+ height: "100%",
677
+ width: license.maxSeats ? `${Math.min(100, license.activeSeats / license.maxSeats * 100)}%` : "10%",
678
+ backgroundColor: license.maxSeats && license.activeSeats / license.maxSeats > 0.9 ? "#dc2626" : "#2563eb",
679
+ borderRadius: "4px",
680
+ transition: "width 0.3s ease"
681
+ }
682
+ }
683
+ )
684
+ }
685
+ ),
686
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: "12px", color: "#9ca3af" }, children: [
687
+ "Machines bound: ",
688
+ license.boundMachines.length,
689
+ " / ",
690
+ license.maxMachines
691
+ ] })
692
+ ] }) : /* @__PURE__ */ jsx("p", { style: { color: "#6b7280" }, children: "Activate a license to view seat information." }) }),
693
+ !loading && activeTab === "features" && /* @__PURE__ */ jsx("div", { children: license ? /* @__PURE__ */ jsxs(
694
+ "ul",
695
+ {
696
+ style: {
697
+ listStyle: "none",
698
+ padding: 0,
699
+ margin: 0,
700
+ display: "flex",
701
+ flexDirection: "column",
702
+ gap: "8px"
703
+ },
704
+ children: [
705
+ license.features.map((f) => /* @__PURE__ */ jsxs(
706
+ "li",
707
+ {
708
+ style: {
709
+ padding: "8px 12px",
710
+ borderRadius: "6px",
711
+ backgroundColor: "#f0fdf4",
712
+ color: "#166534",
713
+ fontSize: "14px"
714
+ },
715
+ children: [
716
+ "✓ ",
717
+ f
718
+ ]
719
+ },
720
+ f
721
+ )),
722
+ license.features.length === 0 && /* @__PURE__ */ jsx("li", { style: { color: "#6b7280", fontSize: "14px" }, children: "No explicit features — tier-based access applies." })
723
+ ]
724
+ }
725
+ ) : /* @__PURE__ */ jsx("p", { style: { color: "#6b7280" }, children: "Activate a license to view features." }) }),
726
+ !loading && activeTab === "plans" && /* @__PURE__ */ jsx(
727
+ LicenseComparison,
728
+ {
729
+ currentTier: license == null ? void 0 : license.tier,
730
+ onSelect: (plan) => onUpgrade == null ? void 0 : onUpgrade(plan.id)
731
+ }
732
+ )
733
+ ] })
734
+ ] });
735
+ }
736
+ function NiceLicenseManager({
737
+ licenses,
738
+ onRevoke,
739
+ onExtend,
740
+ onChangeTier,
741
+ onAddSeats,
742
+ onGenerate,
743
+ onSearchChange,
744
+ style,
745
+ className
746
+ }) {
747
+ const [search, setSearch] = useState("");
748
+ const [expandedKey, setExpandedKey] = useState(null);
749
+ const handleSearch = (value) => {
750
+ setSearch(value);
751
+ onSearchChange == null ? void 0 : onSearchChange(value);
752
+ };
753
+ const filtered = search ? licenses.filter(
754
+ (l) => l.licensee.toLowerCase().includes(search.toLowerCase()) || l.email.toLowerCase().includes(search.toLowerCase()) || l.key.toLowerCase().includes(search.toLowerCase())
755
+ ) : licenses;
756
+ const statusColors = {
757
+ valid: "#059669",
758
+ expired: "#dc2626",
759
+ revoked: "#6b7280",
760
+ grace: "#d97706"
761
+ };
762
+ const containerStyle = {
763
+ border: "1px solid #e5e7eb",
764
+ borderRadius: "12px",
765
+ backgroundColor: "#fff",
766
+ overflow: "hidden",
767
+ ...style
768
+ };
769
+ return /* @__PURE__ */ jsxs("div", { style: containerStyle, className, children: [
770
+ /* @__PURE__ */ jsxs(
771
+ "div",
772
+ {
773
+ style: {
774
+ display: "flex",
775
+ justifyContent: "space-between",
776
+ alignItems: "center",
777
+ padding: "16px 20px",
778
+ borderBottom: "1px solid #e5e7eb",
779
+ backgroundColor: "#f9fafb"
780
+ },
781
+ children: [
782
+ /* @__PURE__ */ jsx("h3", { style: { margin: 0, fontSize: "16px", color: "#111" }, children: "License Manager" }),
783
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
784
+ /* @__PURE__ */ jsx(
785
+ "input",
786
+ {
787
+ type: "text",
788
+ value: search,
789
+ onChange: (e) => handleSearch(e.target.value),
790
+ placeholder: "Search licenses...",
791
+ style: {
792
+ padding: "6px 12px",
793
+ fontSize: "13px",
794
+ border: "1px solid #d1d5db",
795
+ borderRadius: "6px",
796
+ outline: "none",
797
+ width: "220px"
798
+ }
799
+ }
800
+ ),
801
+ onGenerate && /* @__PURE__ */ jsx(
802
+ "button",
803
+ {
804
+ onClick: onGenerate,
805
+ style: {
806
+ padding: "6px 14px",
807
+ fontSize: "13px",
808
+ fontWeight: 600,
809
+ color: "#fff",
810
+ backgroundColor: "#2563eb",
811
+ border: "none",
812
+ borderRadius: "6px",
813
+ cursor: "pointer"
814
+ },
815
+ children: "+ Generate"
816
+ }
817
+ )
818
+ ] })
819
+ ]
820
+ }
821
+ ),
822
+ /* @__PURE__ */ jsxs("div", { style: { maxHeight: "500px", overflow: "auto" }, children: [
823
+ filtered.length === 0 && /* @__PURE__ */ jsx("p", { style: { padding: "20px", textAlign: "center", color: "#6b7280" }, children: search ? "No licenses match your search." : "No licenses found." }),
824
+ filtered.map((lic) => {
825
+ const isExpanded = expandedKey === lic.key;
826
+ return /* @__PURE__ */ jsxs(
827
+ "div",
828
+ {
829
+ style: {
830
+ borderBottom: "1px solid #f3f4f6"
831
+ },
832
+ children: [
833
+ /* @__PURE__ */ jsxs(
834
+ "div",
835
+ {
836
+ style: {
837
+ display: "grid",
838
+ gridTemplateColumns: "1fr 140px 100px 80px 60px",
839
+ alignItems: "center",
840
+ padding: "12px 20px",
841
+ cursor: "pointer",
842
+ backgroundColor: isExpanded ? "#f9fafb" : "transparent"
843
+ },
844
+ onClick: () => setExpandedKey(isExpanded ? null : lic.key),
845
+ children: [
846
+ /* @__PURE__ */ jsxs("div", { children: [
847
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 500, fontSize: "14px", color: "#111" }, children: lic.licensee }),
848
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: "#6b7280" }, children: lic.email })
849
+ ] }),
850
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "12px", fontFamily: "monospace", color: "#6b7280" }, children: maskLicenseKey(lic.key) }),
851
+ /* @__PURE__ */ jsx(
852
+ "div",
853
+ {
854
+ style: {
855
+ fontSize: "12px",
856
+ fontWeight: 600,
857
+ textTransform: "capitalize",
858
+ color: statusColors[lic.status]
859
+ },
860
+ children: lic.status
861
+ }
862
+ ),
863
+ /* @__PURE__ */ jsx(
864
+ "div",
865
+ {
866
+ style: {
867
+ fontSize: "12px",
868
+ fontWeight: 500,
869
+ textTransform: "capitalize",
870
+ color: "#374151"
871
+ },
872
+ children: lic.tier
873
+ }
874
+ ),
875
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "14px", color: "#6b7280", textAlign: "right" }, children: isExpanded ? "▲" : "▼" })
876
+ ]
877
+ }
878
+ ),
879
+ isExpanded && /* @__PURE__ */ jsxs("div", { style: { padding: "12px 20px 16px", backgroundColor: "#f9fafb" }, children: [
880
+ /* @__PURE__ */ jsxs(
881
+ "div",
882
+ {
883
+ style: {
884
+ display: "grid",
885
+ gridTemplateColumns: "repeat(4, 1fr)",
886
+ gap: "12px",
887
+ marginBottom: "12px"
888
+ },
889
+ children: [
890
+ /* @__PURE__ */ jsxs("div", { children: [
891
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: "#9ca3af" }, children: "Issued" }),
892
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "13px" }, children: new Date(lic.issuedAt).toLocaleDateString() })
893
+ ] }),
894
+ /* @__PURE__ */ jsxs("div", { children: [
895
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: "#9ca3af" }, children: "Expires" }),
896
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "13px" }, children: lic.expiresAt ? new Date(lic.expiresAt).toLocaleDateString() : "Perpetual" })
897
+ ] }),
898
+ /* @__PURE__ */ jsxs("div", { children: [
899
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: "#9ca3af" }, children: "Seats" }),
900
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: "13px" }, children: [
901
+ lic.activeSeats,
902
+ " / ",
903
+ lic.maxSeats ?? "∞"
904
+ ] })
905
+ ] }),
906
+ /* @__PURE__ */ jsxs("div", { children: [
907
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: "#9ca3af" }, children: "Features" }),
908
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: "13px" }, children: [
909
+ lic.features.length,
910
+ " enabled"
911
+ ] })
912
+ ] })
913
+ ]
914
+ }
915
+ ),
916
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap" }, children: [
917
+ onExtend && lic.status !== "revoked" && /* @__PURE__ */ jsx(
918
+ "button",
919
+ {
920
+ onClick: (e) => {
921
+ e.stopPropagation();
922
+ onExtend(lic.key, 365);
923
+ },
924
+ style: {
925
+ padding: "5px 12px",
926
+ fontSize: "12px",
927
+ border: "1px solid #d1d5db",
928
+ borderRadius: "4px",
929
+ backgroundColor: "#fff",
930
+ cursor: "pointer"
931
+ },
932
+ children: "Extend 1 Year"
933
+ }
934
+ ),
935
+ onAddSeats && lic.status !== "revoked" && /* @__PURE__ */ jsx(
936
+ "button",
937
+ {
938
+ onClick: (e) => {
939
+ e.stopPropagation();
940
+ onAddSeats(lic.key, 5);
941
+ },
942
+ style: {
943
+ padding: "5px 12px",
944
+ fontSize: "12px",
945
+ border: "1px solid #d1d5db",
946
+ borderRadius: "4px",
947
+ backgroundColor: "#fff",
948
+ cursor: "pointer"
949
+ },
950
+ children: "+5 Seats"
951
+ }
952
+ ),
953
+ onChangeTier && lic.status !== "revoked" && /* @__PURE__ */ jsxs(
954
+ "select",
955
+ {
956
+ onClick: (e) => e.stopPropagation(),
957
+ onChange: (e) => onChangeTier(lic.key, e.target.value),
958
+ value: lic.tier,
959
+ style: {
960
+ padding: "5px 8px",
961
+ fontSize: "12px",
962
+ border: "1px solid #d1d5db",
963
+ borderRadius: "4px",
964
+ cursor: "pointer"
965
+ },
966
+ children: [
967
+ /* @__PURE__ */ jsx("option", { value: "trial", children: "Trial" }),
968
+ /* @__PURE__ */ jsx("option", { value: "personal", children: "Personal" }),
969
+ /* @__PURE__ */ jsx("option", { value: "team", children: "Team" }),
970
+ /* @__PURE__ */ jsx("option", { value: "enterprise", children: "Enterprise" }),
971
+ /* @__PURE__ */ jsx("option", { value: "site", children: "Site" }),
972
+ /* @__PURE__ */ jsx("option", { value: "oem", children: "OEM" })
973
+ ]
974
+ }
975
+ ),
976
+ onRevoke && lic.status !== "revoked" && /* @__PURE__ */ jsx(
977
+ "button",
978
+ {
979
+ onClick: (e) => {
980
+ e.stopPropagation();
981
+ onRevoke(lic.key);
982
+ },
983
+ style: {
984
+ padding: "5px 12px",
985
+ fontSize: "12px",
986
+ color: "#dc2626",
987
+ border: "1px solid #fecaca",
988
+ borderRadius: "4px",
989
+ backgroundColor: "#fff",
990
+ cursor: "pointer"
991
+ },
992
+ children: "Revoke"
993
+ }
994
+ )
995
+ ] })
996
+ ] })
997
+ ]
998
+ },
999
+ lic.key
1000
+ );
1001
+ })
1002
+ ] }),
1003
+ /* @__PURE__ */ jsxs(
1004
+ "div",
1005
+ {
1006
+ style: {
1007
+ padding: "10px 20px",
1008
+ borderTop: "1px solid #e5e7eb",
1009
+ backgroundColor: "#f9fafb",
1010
+ fontSize: "12px",
1011
+ color: "#6b7280"
1012
+ },
1013
+ children: [
1014
+ filtered.length,
1015
+ " license",
1016
+ filtered.length !== 1 ? "s" : "",
1017
+ search && ` matching "${search}"`,
1018
+ " · ",
1019
+ licenses.filter((l) => l.status === "valid").length,
1020
+ " active"
1021
+ ]
1022
+ }
1023
+ )
1024
+ ] });
1025
+ }
1026
+ export {
1027
+ FeatureGate,
1028
+ LicenseActivator,
1029
+ LicenseComparison,
1030
+ LicensePortal,
1031
+ LicenseProvider,
1032
+ LicenseStatus,
1033
+ NiceLicenseManager,
1034
+ TrialWatermark,
1035
+ UpgradePrompt,
1036
+ useFeature,
1037
+ useLicense
1038
+ };
1039
+ //# sourceMappingURL=react.mjs.map