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