@replicated/portal-components 0.0.2 → 0.0.4
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/components/metadata/registry.json +83 -2
- package/components/metadata/registry.md +27 -2
- package/dist/actions/index.d.mts +566 -3
- package/dist/actions/index.d.ts +566 -3
- package/dist/actions/index.js +1853 -12
- package/dist/actions/index.js.map +1 -1
- package/dist/airgap-instances.d.mts +26 -0
- package/dist/airgap-instances.d.ts +26 -0
- package/dist/airgap-instances.js +354 -0
- package/dist/airgap-instances.js.map +1 -0
- package/dist/error-page.d.mts +14 -0
- package/dist/error-page.d.ts +14 -0
- package/dist/error-page.js +153 -0
- package/dist/error-page.js.map +1 -0
- package/dist/error.d.mts +15 -0
- package/dist/error.d.ts +15 -0
- package/dist/error.js +144 -0
- package/dist/error.js.map +1 -0
- package/dist/esm/actions/index.js +1816 -13
- package/dist/esm/actions/index.js.map +1 -1
- package/dist/esm/airgap-instances.js +352 -0
- package/dist/esm/airgap-instances.js.map +1 -0
- package/dist/esm/error-page.js +151 -0
- package/dist/esm/error-page.js.map +1 -0
- package/dist/esm/error.js +142 -0
- package/dist/esm/error.js.map +1 -0
- package/dist/esm/helm-install-wizard.js +1007 -0
- package/dist/esm/helm-install-wizard.js.map +1 -0
- package/dist/esm/index.js +2232 -155
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/install-actions.js +746 -0
- package/dist/esm/install-actions.js.map +1 -0
- package/dist/esm/install-card.js +115 -0
- package/dist/esm/install-card.js.map +1 -0
- package/dist/esm/install-targets.js +48 -0
- package/dist/esm/install-targets.js.map +1 -0
- package/dist/esm/instance-card.js +197 -0
- package/dist/esm/instance-card.js.map +1 -0
- package/dist/esm/join-team.js +218 -0
- package/dist/esm/join-team.js.map +1 -0
- package/dist/esm/license-card.js +131 -0
- package/dist/esm/license-card.js.map +1 -0
- package/dist/esm/license-details.js +667 -0
- package/dist/esm/license-details.js.map +1 -0
- package/dist/esm/linux-install-wizard.js +1083 -0
- package/dist/esm/linux-install-wizard.js.map +1 -0
- package/dist/esm/login.js +261 -0
- package/dist/esm/login.js.map +1 -0
- package/dist/esm/online-instance-list.js +287 -0
- package/dist/esm/online-instance-list.js.map +1 -0
- package/dist/esm/pending-installations.js +235 -0
- package/dist/esm/pending-installations.js.map +1 -0
- package/dist/esm/release-history-panel.js +100 -0
- package/dist/esm/release-history-panel.js.map +1 -0
- package/dist/esm/release-notes-card.js +23 -0
- package/dist/esm/release-notes-card.js.map +1 -0
- package/dist/esm/security-card.js +700 -0
- package/dist/esm/security-card.js.map +1 -0
- package/dist/esm/support-bundle-collection-card.js +170 -0
- package/dist/esm/support-bundle-collection-card.js.map +1 -0
- package/dist/esm/support-bundles-card.js +306 -0
- package/dist/esm/support-bundles-card.js.map +1 -0
- package/dist/esm/support-card.js +305 -0
- package/dist/esm/support-card.js.map +1 -0
- package/dist/esm/team-selection.js +117 -0
- package/dist/esm/team-selection.js.map +1 -0
- package/dist/esm/team-settings-card.js +78 -0
- package/dist/esm/team-settings-card.js.map +1 -0
- package/dist/esm/team-settings.js +136 -0
- package/dist/esm/team-settings.js.map +1 -0
- package/dist/esm/top-nav-user-menu.js +173 -0
- package/dist/esm/top-nav-user-menu.js.map +1 -0
- package/dist/esm/top-nav.js +398 -0
- package/dist/esm/top-nav.js.map +1 -0
- package/dist/esm/update-layout.js +405 -0
- package/dist/esm/update-layout.js.map +1 -0
- package/dist/esm/updates-card.js +85 -0
- package/dist/esm/updates-card.js.map +1 -0
- package/dist/esm/upload-support-bundle-modal.js +143 -0
- package/dist/esm/upload-support-bundle-modal.js.map +1 -0
- package/dist/esm/user-settings-card.js +21 -0
- package/dist/esm/user-settings-card.js.map +1 -0
- package/dist/esm/user-settings.js +368 -0
- package/dist/esm/user-settings.js.map +1 -0
- package/dist/esm/utils/index.js +170 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/helm-install-wizard.d.mts +38 -0
- package/dist/helm-install-wizard.d.ts +38 -0
- package/dist/helm-install-wizard.js +1011 -0
- package/dist/helm-install-wizard.js.map +1 -0
- package/dist/index.d.mts +11 -27
- package/dist/index.d.ts +11 -27
- package/dist/index.js +2258 -154
- package/dist/index.js.map +1 -1
- package/dist/install-B19AaKF_.d.mts +233 -0
- package/dist/install-Bi1qJ8Bu.d.ts +233 -0
- package/dist/install-actions.d.mts +141 -0
- package/dist/install-actions.d.ts +141 -0
- package/dist/install-actions.js +765 -0
- package/dist/install-actions.js.map +1 -0
- package/dist/install-card.d.mts +15 -0
- package/dist/install-card.d.ts +15 -0
- package/dist/install-card.js +117 -0
- package/dist/install-card.js.map +1 -0
- package/dist/install-targets.d.mts +19 -0
- package/dist/install-targets.d.ts +19 -0
- package/dist/install-targets.js +50 -0
- package/dist/install-targets.js.map +1 -0
- package/dist/instance-card.d.mts +22 -0
- package/dist/instance-card.d.ts +22 -0
- package/dist/instance-card.js +199 -0
- package/dist/instance-card.js.map +1 -0
- package/dist/join-team.d.mts +30 -0
- package/dist/join-team.d.ts +30 -0
- package/dist/join-team.js +220 -0
- package/dist/join-team.js.map +1 -0
- package/dist/license-card.d.mts +15 -0
- package/dist/license-card.d.ts +15 -0
- package/dist/license-card.js +133 -0
- package/dist/license-card.js.map +1 -0
- package/dist/license-details.d.mts +10 -0
- package/dist/license-details.d.ts +10 -0
- package/dist/license-details.js +669 -0
- package/dist/license-details.js.map +1 -0
- package/dist/linux-install-wizard.d.mts +66 -0
- package/dist/linux-install-wizard.d.ts +66 -0
- package/dist/linux-install-wizard.js +1093 -0
- package/dist/linux-install-wizard.js.map +1 -0
- package/dist/login.d.mts +37 -0
- package/dist/login.d.ts +37 -0
- package/dist/login.js +263 -0
- package/dist/login.js.map +1 -0
- package/dist/online-instance-list.d.mts +22 -0
- package/dist/online-instance-list.d.ts +22 -0
- package/dist/online-instance-list.js +289 -0
- package/dist/online-instance-list.js.map +1 -0
- package/dist/pending-installations.d.mts +15 -0
- package/dist/pending-installations.d.ts +15 -0
- package/dist/pending-installations.js +237 -0
- package/dist/pending-installations.js.map +1 -0
- package/dist/release-history-panel.d.mts +22 -0
- package/dist/release-history-panel.d.ts +22 -0
- package/dist/release-history-panel.js +102 -0
- package/dist/release-history-panel.js.map +1 -0
- package/dist/release-notes-card.d.mts +13 -0
- package/dist/release-notes-card.d.ts +13 -0
- package/dist/release-notes-card.js +25 -0
- package/dist/release-notes-card.js.map +1 -0
- package/dist/security-card.d.mts +73 -0
- package/dist/security-card.d.ts +73 -0
- package/dist/security-card.js +702 -0
- package/dist/security-card.js.map +1 -0
- package/dist/styles.css +1877 -194
- package/dist/support-bundle-collection-card.d.mts +20 -0
- package/dist/support-bundle-collection-card.d.ts +20 -0
- package/dist/support-bundle-collection-card.js +172 -0
- package/dist/support-bundle-collection-card.js.map +1 -0
- package/dist/support-bundles-card.d.mts +19 -0
- package/dist/support-bundles-card.d.ts +19 -0
- package/dist/support-bundles-card.js +308 -0
- package/dist/support-bundles-card.js.map +1 -0
- package/dist/support-card.d.mts +8 -0
- package/dist/support-card.d.ts +8 -0
- package/dist/support-card.js +307 -0
- package/dist/support-card.js.map +1 -0
- package/dist/team-selection.d.mts +23 -0
- package/dist/team-selection.d.ts +23 -0
- package/dist/team-selection.js +119 -0
- package/dist/team-selection.js.map +1 -0
- package/dist/team-settings-card-Dq1d9b5c.d.mts +14 -0
- package/dist/team-settings-card-Dq1d9b5c.d.ts +14 -0
- package/dist/team-settings-card.d.mts +2 -0
- package/dist/team-settings-card.d.ts +2 -0
- package/dist/team-settings-card.js +80 -0
- package/dist/team-settings-card.js.map +1 -0
- package/dist/team-settings.d.mts +25 -0
- package/dist/team-settings.d.ts +25 -0
- package/dist/team-settings.js +138 -0
- package/dist/team-settings.js.map +1 -0
- package/dist/top-nav-0mb1K_H0.d.mts +32 -0
- package/dist/top-nav-0mb1K_H0.d.ts +32 -0
- package/dist/top-nav-user-menu.d.mts +18 -0
- package/dist/top-nav-user-menu.d.ts +18 -0
- package/dist/top-nav-user-menu.js +175 -0
- package/dist/top-nav-user-menu.js.map +1 -0
- package/dist/top-nav.d.mts +3 -0
- package/dist/top-nav.d.ts +3 -0
- package/dist/top-nav.js +400 -0
- package/dist/top-nav.js.map +1 -0
- package/dist/update-layout.d.mts +12 -0
- package/dist/update-layout.d.ts +12 -0
- package/dist/update-layout.js +407 -0
- package/dist/update-layout.js.map +1 -0
- package/dist/updates-card-BbubBrVR.d.mts +18 -0
- package/dist/updates-card-BbubBrVR.d.ts +18 -0
- package/dist/updates-card.d.mts +2 -0
- package/dist/updates-card.d.ts +2 -0
- package/dist/updates-card.js +87 -0
- package/dist/updates-card.js.map +1 -0
- package/dist/upload-support-bundle-modal.d.mts +19 -0
- package/dist/upload-support-bundle-modal.d.ts +19 -0
- package/dist/upload-support-bundle-modal.js +145 -0
- package/dist/upload-support-bundle-modal.js.map +1 -0
- package/dist/user-settings-card.d.mts +8 -0
- package/dist/user-settings-card.d.ts +8 -0
- package/dist/user-settings-card.js +23 -0
- package/dist/user-settings-card.js.map +1 -0
- package/dist/user-settings.d.mts +47 -0
- package/dist/user-settings.d.ts +47 -0
- package/dist/user-settings.js +370 -0
- package/dist/user-settings.js.map +1 -0
- package/dist/utils/index.d.mts +70 -0
- package/dist/utils/index.d.ts +70 -0
- package/dist/utils/index.js +177 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +163 -3
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Enterprise Portal Components
|
|
9
|
+
* This file is generated by tsup. Do not edit manually.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
var variantStyles = {
|
|
13
|
+
primary: "bg-primary text-primary-foreground hover:bg-primary/90 focus-visible:ring-primary",
|
|
14
|
+
secondary: "bg-secondary/20 text-secondary-foreground hover:bg-secondary/30 focus-visible:ring-secondary",
|
|
15
|
+
ghost: "bg-transparent text-primary hover:bg-primary/10 focus-visible:ring-primary/60",
|
|
16
|
+
destructive: "bg-danger text-white hover:bg-danger/90 focus-visible:ring-danger"
|
|
17
|
+
};
|
|
18
|
+
var sizeStyles = {
|
|
19
|
+
sm: "h-8 px-3 text-sm",
|
|
20
|
+
md: "h-10 px-4 text-sm",
|
|
21
|
+
lg: "h-12 px-6 text-base"
|
|
22
|
+
};
|
|
23
|
+
var inlineFlexBase = "inline-flex items-center justify-center gap-2 rounded-md font-medium tracking-tight transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-60";
|
|
24
|
+
var Spinner = () => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex h-3.5 w-3.5 animate-spin items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-3 w-3 rounded-full border-2 border-transparent border-t-current" }) });
|
|
25
|
+
var composeClassName = (...values) => values.filter(Boolean).join(" ");
|
|
26
|
+
var Button = react.forwardRef(
|
|
27
|
+
({
|
|
28
|
+
variant = "primary",
|
|
29
|
+
size = "md",
|
|
30
|
+
type = "button",
|
|
31
|
+
isLoading = false,
|
|
32
|
+
leadingIcon,
|
|
33
|
+
trailingIcon,
|
|
34
|
+
disabled,
|
|
35
|
+
className,
|
|
36
|
+
children,
|
|
37
|
+
...props
|
|
38
|
+
}, ref) => {
|
|
39
|
+
const computedLeading = isLoading ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) : leadingIcon;
|
|
40
|
+
const computedDisabled = disabled ?? isLoading;
|
|
41
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
42
|
+
"button",
|
|
43
|
+
{
|
|
44
|
+
ref,
|
|
45
|
+
type,
|
|
46
|
+
className: composeClassName(
|
|
47
|
+
inlineFlexBase,
|
|
48
|
+
variantStyles[variant],
|
|
49
|
+
sizeStyles[size],
|
|
50
|
+
className
|
|
51
|
+
),
|
|
52
|
+
"aria-busy": isLoading || void 0,
|
|
53
|
+
disabled: computedDisabled,
|
|
54
|
+
...props,
|
|
55
|
+
children: [
|
|
56
|
+
computedLeading ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "inline-flex", children: computedLeading }) : null,
|
|
57
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 whitespace-nowrap", children }),
|
|
58
|
+
trailingIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "inline-flex", children: trailingIcon }) : null
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
Button.displayName = "Button";
|
|
65
|
+
var JoinTeam = react.forwardRef(
|
|
66
|
+
({
|
|
67
|
+
logo,
|
|
68
|
+
teamName = "Enterprise Portal",
|
|
69
|
+
initialCode = "",
|
|
70
|
+
isSubmitting = false,
|
|
71
|
+
error = null,
|
|
72
|
+
isExpired = false,
|
|
73
|
+
onAcceptInvite,
|
|
74
|
+
onRefreshInvite,
|
|
75
|
+
loginUrl = "/login",
|
|
76
|
+
className,
|
|
77
|
+
...props
|
|
78
|
+
}, ref) => {
|
|
79
|
+
const [manualCode, setManualCode] = react.useState("");
|
|
80
|
+
const [localError, setLocalError] = react.useState(null);
|
|
81
|
+
const [isRefreshing, setIsRefreshing] = react.useState(false);
|
|
82
|
+
const [refreshSuccess, setRefreshSuccess] = react.useState(false);
|
|
83
|
+
const [useUrlCode, setUseUrlCode] = react.useState(true);
|
|
84
|
+
const hasUrlCode = Boolean(initialCode) && useUrlCode;
|
|
85
|
+
const effectiveCode = hasUrlCode ? initialCode : manualCode.trim();
|
|
86
|
+
react.useEffect(() => {
|
|
87
|
+
if (manualCode) {
|
|
88
|
+
setLocalError(null);
|
|
89
|
+
}
|
|
90
|
+
}, [manualCode]);
|
|
91
|
+
const handleSubmit = async (event) => {
|
|
92
|
+
event.preventDefault();
|
|
93
|
+
if (!effectiveCode) {
|
|
94
|
+
setLocalError("Please enter your invite code");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (!onAcceptInvite) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
setLocalError(null);
|
|
102
|
+
await onAcceptInvite(effectiveCode);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
if (!hasUrlCode) {
|
|
105
|
+
const message = err instanceof Error ? err.message : "Invalid or expired code. Please check the code and try again.";
|
|
106
|
+
setLocalError(message);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const handleRefresh = async () => {
|
|
111
|
+
if (!onRefreshInvite || !effectiveCode) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
setIsRefreshing(true);
|
|
116
|
+
setRefreshSuccess(false);
|
|
117
|
+
await onRefreshInvite(effectiveCode);
|
|
118
|
+
setRefreshSuccess(true);
|
|
119
|
+
if (typeof window !== "undefined") {
|
|
120
|
+
window.history.replaceState(null, "", window.location.pathname + window.location.search);
|
|
121
|
+
}
|
|
122
|
+
setUseUrlCode(false);
|
|
123
|
+
} catch {
|
|
124
|
+
} finally {
|
|
125
|
+
setIsRefreshing(false);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const displayError = error || localError;
|
|
129
|
+
const showRefreshLink = hasUrlCode && (isExpired || displayError);
|
|
130
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
131
|
+
"div",
|
|
132
|
+
{
|
|
133
|
+
ref,
|
|
134
|
+
className: [
|
|
135
|
+
"w-full max-w-xl rounded-3xl border-2 border-gray-900 bg-white p-12 shadow-xl",
|
|
136
|
+
"text-gray-900 transition-shadow",
|
|
137
|
+
className
|
|
138
|
+
].filter(Boolean).join(" "),
|
|
139
|
+
...props,
|
|
140
|
+
children: [
|
|
141
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-6 text-center", children: [
|
|
142
|
+
logo ?? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-blue-500 to-violet-500 text-lg font-semibold leading-tight text-white", children: "EP" }),
|
|
143
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
144
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h1", { className: "text-3xl font-bold tracking-tight text-gray-900", children: [
|
|
145
|
+
"Join the ",
|
|
146
|
+
teamName,
|
|
147
|
+
" team"
|
|
148
|
+
] }),
|
|
149
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-base text-gray-600", children: "Accept your invitation to get started" })
|
|
150
|
+
] })
|
|
151
|
+
] }),
|
|
152
|
+
/* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "mt-10 space-y-4", children: [
|
|
153
|
+
!hasUrlCode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
154
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
155
|
+
"label",
|
|
156
|
+
{
|
|
157
|
+
htmlFor: "invite-code",
|
|
158
|
+
className: "block text-sm font-medium text-gray-700",
|
|
159
|
+
children: "Paste your invite code"
|
|
160
|
+
}
|
|
161
|
+
),
|
|
162
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
163
|
+
"input",
|
|
164
|
+
{
|
|
165
|
+
id: "invite-code",
|
|
166
|
+
type: "text",
|
|
167
|
+
placeholder: "Paste code from your email",
|
|
168
|
+
value: manualCode,
|
|
169
|
+
onChange: (e) => setManualCode(e.target.value),
|
|
170
|
+
className: [
|
|
171
|
+
"portal-input w-full px-5 py-4 text-base font-mono",
|
|
172
|
+
displayError ? "border-red-500" : ""
|
|
173
|
+
].filter(Boolean).join(" "),
|
|
174
|
+
autoFocus: true,
|
|
175
|
+
disabled: isSubmitting
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
] }),
|
|
179
|
+
displayError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-red-600", children: displayError }),
|
|
180
|
+
refreshSuccess && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-green-600", children: "A new invitation has been sent to your email." }),
|
|
181
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
182
|
+
Button,
|
|
183
|
+
{
|
|
184
|
+
type: "submit",
|
|
185
|
+
size: "lg",
|
|
186
|
+
className: "w-full justify-center rounded-xl bg-indigo-600 text-white hover:bg-indigo-700",
|
|
187
|
+
disabled: !effectiveCode || isSubmitting,
|
|
188
|
+
isLoading: isSubmitting,
|
|
189
|
+
children: "Accept invite"
|
|
190
|
+
}
|
|
191
|
+
),
|
|
192
|
+
showRefreshLink && onRefreshInvite && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
193
|
+
"button",
|
|
194
|
+
{
|
|
195
|
+
type: "button",
|
|
196
|
+
onClick: handleRefresh,
|
|
197
|
+
disabled: isRefreshing,
|
|
198
|
+
className: "text-sm font-medium text-indigo-600 hover:text-indigo-700 hover:underline disabled:opacity-50",
|
|
199
|
+
children: isRefreshing ? "Sending..." : "Refresh invite"
|
|
200
|
+
}
|
|
201
|
+
) }),
|
|
202
|
+
!hasUrlCode && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
203
|
+
"a",
|
|
204
|
+
{
|
|
205
|
+
href: loginUrl,
|
|
206
|
+
className: "text-sm font-medium text-indigo-600 hover:text-indigo-700 hover:underline",
|
|
207
|
+
children: "or login"
|
|
208
|
+
}
|
|
209
|
+
) })
|
|
210
|
+
] })
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
JoinTeam.displayName = "JoinTeam";
|
|
217
|
+
|
|
218
|
+
exports.JoinTeam = JoinTeam;
|
|
219
|
+
//# sourceMappingURL=join-team.js.map
|
|
220
|
+
//# sourceMappingURL=join-team.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/button.tsx","../src/components/join-team.tsx"],"names":["jsx","forwardRef","jsxs","useState","useEffect","Fragment"],"mappings":";;;;;;;;;;AASA,IAAM,aAAA,GAA+C;AAAA,EACnD,OAAA,EACE,mFAAA;AAAA,EACF,SAAA,EACE,8FAAA;AAAA,EACF,KAAA,EACE,+EAAA;AAAA,EACF,WAAA,EACE;AACJ,CAAA;AAEA,IAAM,UAAA,GAAyC;AAAA,EAC7C,EAAA,EAAI,kBAAA;AAAA,EACJ,EAAA,EAAI,mBAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAEA,IAAM,cAAA,GACJ,oOAAA;AAEF,IAAM,OAAA,GAAU,sBACdA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oEACd,QAAA,kBAAAA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mEAAA,EAAoE,CAAA,EACtF,CAAA;AAcF,IAAM,gBAAA,GAAmB,IACpB,MAAA,KACQ,MAAA,CAAO,OAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AAMrC,IAAM,MAAA,GAASC,gBAAA;AAAA,EACpB,CACE;AAAA,IACE,OAAA,GAAU,SAAA;AAAA,IACV,IAAA,GAAO,IAAA;AAAA,IACP,IAAA,GAAO,QAAA;AAAA,IACP,SAAA,GAAY,KAAA;AAAA,IACZ,WAAA;AAAA,IACA,YAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,GAAG;AAAA,KAEL,GAAA,KACG;AACH,IAAA,MAAM,eAAA,GAAkB,SAAA,mBAAYD,cAAA,CAAC,OAAA,EAAA,EAAQ,CAAA,GAAK,WAAA;AAClD,IAAA,MAAM,mBAAmB,QAAA,IAAY,SAAA;AAErC,IAAA,uBACEE,eAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,IAAA;AAAA,QACA,SAAA,EAAW,gBAAA;AAAA,UACT,cAAA;AAAA,UACA,cAAc,OAAO,CAAA;AAAA,UACrB,WAAW,IAAI,CAAA;AAAA,UACf;AAAA,SACF;AAAA,QACA,aAAW,SAAA,IAAa,MAAA;AAAA,QACxB,QAAA,EAAU,gBAAA;AAAA,QACT,GAAG,KAAA;AAAA,QAEH,QAAA,EAAA;AAAA,UAAA,eAAA,kCACE,MAAA,EAAA,EAAK,aAAA,EAAY,QAAO,SAAA,EAAU,aAAA,EAChC,2BACH,CAAA,GACE,IAAA;AAAA,0BACJF,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,0BAAA,EAA4B,QAAA,EAAS,CAAA;AAAA,UACpD,YAAA,kCACE,MAAA,EAAA,EAAK,aAAA,EAAY,QAAO,SAAA,EAAU,aAAA,EAChC,wBACH,CAAA,GACE;AAAA;AAAA;AAAA,KACN;AAAA,EAEJ;AACF,CAAA;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA;AChEd,IAAM,QAAA,GAAWC,gBAAAA;AAAA,EACtB,CACE;AAAA,IACE,IAAA;AAAA,IACA,QAAA,GAAW,mBAAA;AAAA,IACX,WAAA,GAAc,EAAA;AAAA,IACd,YAAA,GAAe,KAAA;AAAA,IACf,KAAA,GAAQ,IAAA;AAAA,IACR,SAAA,GAAY,KAAA;AAAA,IACZ,cAAA;AAAA,IACA,eAAA;AAAA,IACA,QAAA,GAAW,QAAA;AAAA,IACX,SAAA;AAAA,IACA,GAAG;AAAA,KAEL,GAAA,KACG;AACH,IAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIE,eAAS,EAAE,CAAA;AAC/C,IAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIA,eAAwB,IAAI,CAAA;AAChE,IAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,eAAS,KAAK,CAAA;AACtD,IAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAIA,eAAS,KAAK,CAAA;AAE1D,IAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIA,eAAS,IAAI,CAAA;AAGjD,IAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,WAAW,CAAA,IAAK,UAAA;AAC3C,IAAA,MAAM,aAAA,GAAgB,UAAA,GAAa,WAAA,GAAc,UAAA,CAAW,IAAA,EAAK;AAGjE,IAAAC,eAAA,CAAU,MAAM;AACd,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,aAAA,CAAc,IAAI,CAAA;AAAA,MACpB;AAAA,IACF,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,IAAA,MAAM,YAAA,GAAe,OAAO,KAAA,KAAqB;AAC/C,MAAA,KAAA,CAAM,cAAA,EAAe;AAErB,MAAA,IAAI,CAAC,aAAA,EAAe;AAClB,QAAA,aAAA,CAAc,+BAA+B,CAAA;AAC7C,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,QAAA;AAAA,MACF;AAEA,MAAA,IAAI;AACF,QAAA,aAAA,CAAc,IAAI,CAAA;AAClB,QAAA,MAAM,eAAe,aAAa,CAAA;AAAA,MACpC,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,CAAC,UAAA,EAAY;AAEf,UAAA,MAAM,OAAA,GACJ,GAAA,YAAe,KAAA,GACX,GAAA,CAAI,OAAA,GACJ,+DAAA;AACN,UAAA,aAAA,CAAc,OAAO,CAAA;AAAA,QACvB;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,gBAAgB,YAAY;AAChC,MAAA,IAAI,CAAC,eAAA,IAAmB,CAAC,aAAA,EAAe;AACtC,QAAA;AAAA,MACF;AAEA,MAAA,IAAI;AACF,QAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,QAAA,iBAAA,CAAkB,KAAK,CAAA;AACvB,QAAA,MAAM,gBAAgB,aAAa,CAAA;AACnC,QAAA,iBAAA,CAAkB,IAAI,CAAA;AAItB,QAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,UAAA,MAAA,CAAO,OAAA,CAAQ,aAAa,IAAA,EAAM,EAAA,EAAI,OAAO,QAAA,CAAS,QAAA,GAAW,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA;AAAA,QACzF;AACA,QAAA,aAAA,CAAc,KAAK,CAAA;AAAA,MACrB,CAAA,CAAA,MAAQ;AAAA,MAER,CAAA,SAAE;AACA,QAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,MACvB;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,eAAe,KAAA,IAAS,UAAA;AAC9B,IAAA,MAAM,eAAA,GAAkB,eAAe,SAAA,IAAa,YAAA,CAAA;AAEpD,IAAA,uBACEF,eAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAW;AAAA,UACT,8EAAA;AAAA,UACA,iCAAA;AAAA,UACA;AAAA,SACF,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,QACV,GAAG,KAAA;AAAA,QAEJ,QAAA,EAAA;AAAA,0BAAAA,eAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8CAAA,EACZ,QAAA,EAAA;AAAA,YAAA,IAAA,oBACCF,cAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uJAAsJ,QAAA,EAAA,IAAA,EAErK,CAAA;AAAA,4BAEFE,gBAAC,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,8BAAAA,eAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,iDAAA,EAAkD,QAAA,EAAA;AAAA,gBAAA,WAAA;AAAA,gBACpD,QAAA;AAAA,gBAAS;AAAA,eAAA,EACrB,CAAA;AAAA,8BACAF,cAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,gCAA+B,QAAA,EAAA,uCAAA,EAE5C;AAAA,aAAA,EACF;AAAA,WAAA,EACF,CAAA;AAAA,0BAEAE,eAAAA,CAAC,MAAA,EAAA,EAAK,QAAA,EAAU,YAAA,EAAc,WAAU,iBAAA,EAErC,QAAA,EAAA;AAAA,YAAA,CAAC,UAAA,oBACAA,eAAAA,CAAAG,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,8BAAAL,cAAAA;AAAA,gBAAC,OAAA;AAAA,gBAAA;AAAA,kBACC,OAAA,EAAQ,aAAA;AAAA,kBACR,SAAA,EAAU,yCAAA;AAAA,kBACX,QAAA,EAAA;AAAA;AAAA,eAED;AAAA,8BACAA,cAAAA;AAAA,gBAAC,OAAA;AAAA,gBAAA;AAAA,kBACC,EAAA,EAAG,aAAA;AAAA,kBACH,IAAA,EAAK,MAAA;AAAA,kBACL,WAAA,EAAY,4BAAA;AAAA,kBACZ,KAAA,EAAO,UAAA;AAAA,kBACP,UAAU,CAAC,CAAA,KAAM,aAAA,CAAc,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,kBAC7C,SAAA,EAAW;AAAA,oBACT,mDAAA;AAAA,oBACA,eAAe,gBAAA,GAAmB;AAAA,mBACpC,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,kBACX,SAAA,EAAS,IAAA;AAAA,kBACT,QAAA,EAAU;AAAA;AAAA;AACZ,aAAA,EACF,CAAA;AAAA,YAID,gCACCA,cAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,oCAAoC,QAAA,EAAA,YAAA,EAAa,CAAA;AAAA,YAI/D,kCACCA,cAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,sCAAqC,QAAA,EAAA,+CAAA,EAElD,CAAA;AAAA,4BAIFA,cAAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,IAAA,EAAK,IAAA;AAAA,gBACL,SAAA,EAAU,+EAAA;AAAA,gBACV,QAAA,EAAU,CAAC,aAAA,IAAiB,YAAA;AAAA,gBAC5B,SAAA,EAAW,YAAA;AAAA,gBACZ,QAAA,EAAA;AAAA;AAAA,aAED;AAAA,YAGC,mBAAmB,eAAA,oBAClBA,eAAC,KAAA,EAAA,EAAI,SAAA,EAAU,eACb,QAAA,kBAAAA,cAAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAS,aAAA;AAAA,gBACT,QAAA,EAAU,YAAA;AAAA,gBACV,SAAA,EAAU,+FAAA;AAAA,gBAET,yBAAe,YAAA,GAAe;AAAA;AAAA,aACjC,EACF,CAAA;AAAA,YAID,CAAC,UAAA,oBACAA,eAAC,KAAA,EAAA,EAAI,SAAA,EAAU,eACb,QAAA,kBAAAA,cAAAA;AAAA,cAAC,GAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAM,QAAA;AAAA,gBACN,SAAA,EAAU,2EAAA;AAAA,gBACX,QAAA,EAAA;AAAA;AAAA,aAED,EACF;AAAA,WAAA,EAEJ;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AACF;AAEA,QAAA,CAAS,WAAA,GAAc,UAAA","file":"join-team.js","sourcesContent":["import {\n forwardRef,\n type ComponentPropsWithoutRef,\n type ReactNode\n} from \"react\";\n\nconst buttonVariants = [\"primary\", \"secondary\", \"ghost\", \"destructive\"] as const;\nconst buttonSizes = [\"sm\", \"md\", \"lg\"] as const;\n\nconst variantStyles: Record<ButtonVariant, string> = {\n primary:\n \"bg-primary text-primary-foreground hover:bg-primary/90 focus-visible:ring-primary\",\n secondary:\n \"bg-secondary/20 text-secondary-foreground hover:bg-secondary/30 focus-visible:ring-secondary\",\n ghost:\n \"bg-transparent text-primary hover:bg-primary/10 focus-visible:ring-primary/60\",\n destructive:\n \"bg-danger text-white hover:bg-danger/90 focus-visible:ring-danger\"\n};\n\nconst sizeStyles: Record<ButtonSize, string> = {\n sm: \"h-8 px-3 text-sm\",\n md: \"h-10 px-4 text-sm\",\n lg: \"h-12 px-6 text-base\"\n};\n\nconst inlineFlexBase =\n \"inline-flex items-center justify-center gap-2 rounded-md font-medium tracking-tight transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-60\";\n\nconst Spinner = () => (\n <span className=\"inline-flex h-3.5 w-3.5 animate-spin items-center justify-center\">\n <span className=\"h-3 w-3 rounded-full border-2 border-transparent border-t-current\" />\n </span>\n);\n\nexport type ButtonVariant = (typeof buttonVariants)[number];\nexport type ButtonSize = (typeof buttonSizes)[number];\n\nexport interface ButtonProps extends ComponentPropsWithoutRef<\"button\"> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n isLoading?: boolean;\n leadingIcon?: ReactNode;\n trailingIcon?: ReactNode;\n}\n\nconst composeClassName = (\n ...values: Array<string | undefined | false>\n): string => values.filter(Boolean).join(\" \");\n\n/**\n * Button is the primary interactive primitive for triggering portal actions.\n * It is theme aware via CSS variables generated from portal tokens.\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = \"primary\",\n size = \"md\",\n type = \"button\",\n isLoading = false,\n leadingIcon,\n trailingIcon,\n disabled,\n className,\n children,\n ...props\n },\n ref\n ) => {\n const computedLeading = isLoading ? <Spinner /> : leadingIcon;\n const computedDisabled = disabled ?? isLoading;\n\n return (\n <button\n ref={ref}\n type={type}\n className={composeClassName(\n inlineFlexBase,\n variantStyles[variant],\n sizeStyles[size],\n className\n )}\n aria-busy={isLoading || undefined}\n disabled={computedDisabled}\n {...props}\n >\n {computedLeading ? (\n <span aria-hidden=\"true\" className=\"inline-flex\">\n {computedLeading}\n </span>\n ) : null}\n <span className=\"flex-1 whitespace-nowrap\">{children}</span>\n {trailingIcon ? (\n <span aria-hidden=\"true\" className=\"inline-flex\">\n {trailingIcon}\n </span>\n ) : null}\n </button>\n );\n }\n);\n\nButton.displayName = \"Button\";\n","'use client';\n\nimport {\n forwardRef,\n useEffect,\n useState,\n type ComponentPropsWithoutRef,\n type FormEvent,\n type ReactNode\n} from \"react\";\n\nimport { Button } from \"./button\";\n\nexport interface JoinTeamProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /** Logo element to display at the top */\n logo?: ReactNode;\n /** Team/product name to display in the heading */\n teamName?: string;\n /** Invite code from URL fragment (if available) */\n initialCode?: string;\n /** Whether an accept operation is in progress */\n isSubmitting?: boolean;\n /** Error message from a previous accept attempt */\n error?: string | null;\n /** Whether the invite has expired */\n isExpired?: boolean;\n /** Called when user clicks \"Accept invite\" */\n onAcceptInvite?: (code: string) => Promise<void> | void;\n /** Called when user clicks \"Refresh invite\" for expired invites */\n onRefreshInvite?: (code: string) => Promise<void> | void;\n /** URL to navigate to for login (when no code in URL) */\n loginUrl?: string;\n}\n\n/**\n * JoinTeam renders a form for accepting team invitations.\n * Supports both URL-based codes (from email links) and manual code entry.\n */\nexport const JoinTeam = forwardRef<HTMLDivElement, JoinTeamProps>(\n (\n {\n logo,\n teamName = \"Enterprise Portal\",\n initialCode = \"\",\n isSubmitting = false,\n error = null,\n isExpired = false,\n onAcceptInvite,\n onRefreshInvite,\n loginUrl = \"/login\",\n className,\n ...props\n },\n ref\n ) => {\n const [manualCode, setManualCode] = useState(\"\");\n const [localError, setLocalError] = useState<string | null>(null);\n const [isRefreshing, setIsRefreshing] = useState(false);\n const [refreshSuccess, setRefreshSuccess] = useState(false);\n // Track whether to use URL code - can be cleared after refresh\n const [useUrlCode, setUseUrlCode] = useState(true);\n\n // Use code from URL if available and not cleared, otherwise use manual input\n const hasUrlCode = Boolean(initialCode) && useUrlCode;\n const effectiveCode = hasUrlCode ? initialCode : manualCode.trim();\n\n // Clear local error when code changes\n useEffect(() => {\n if (manualCode) {\n setLocalError(null);\n }\n }, [manualCode]);\n\n const handleSubmit = async (event: FormEvent) => {\n event.preventDefault();\n\n if (!effectiveCode) {\n setLocalError(\"Please enter your invite code\");\n return;\n }\n\n if (!onAcceptInvite) {\n return;\n }\n\n try {\n setLocalError(null);\n await onAcceptInvite(effectiveCode);\n } catch (err) {\n if (!hasUrlCode) {\n // Only show local error for manual entry\n const message =\n err instanceof Error\n ? err.message\n : \"Invalid or expired code. Please check the code and try again.\";\n setLocalError(message);\n }\n }\n };\n\n const handleRefresh = async () => {\n if (!onRefreshInvite || !effectiveCode) {\n return;\n }\n\n try {\n setIsRefreshing(true);\n setRefreshSuccess(false);\n await onRefreshInvite(effectiveCode);\n setRefreshSuccess(true);\n \n // After refresh, clear URL hash and switch to manual entry mode\n // This matches Vandoor's behavior where href=\"#\" clears the hash\n if (typeof window !== \"undefined\") {\n window.history.replaceState(null, \"\", window.location.pathname + window.location.search);\n }\n setUseUrlCode(false);\n } catch {\n // Refresh errors are typically silent per the API design\n } finally {\n setIsRefreshing(false);\n }\n };\n\n const displayError = error || localError;\n const showRefreshLink = hasUrlCode && (isExpired || displayError);\n\n return (\n <div\n ref={ref}\n className={[\n \"w-full max-w-xl rounded-3xl border-2 border-gray-900 bg-white p-12 shadow-xl\",\n \"text-gray-900 transition-shadow\",\n className\n ]\n .filter(Boolean)\n .join(\" \")}\n {...props}\n >\n <div className=\"flex flex-col items-center gap-6 text-center\">\n {logo ?? (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-blue-500 to-violet-500 text-lg font-semibold leading-tight text-white\">\n EP\n </div>\n )}\n <div>\n <h1 className=\"text-3xl font-bold tracking-tight text-gray-900\">\n Join the {teamName} team\n </h1>\n <p className=\"mt-3 text-base text-gray-600\">\n Accept your invitation to get started\n </p>\n </div>\n </div>\n\n <form onSubmit={handleSubmit} className=\"mt-10 space-y-4\">\n {/* Show input field only when no code in URL */}\n {!hasUrlCode && (\n <>\n <label\n htmlFor=\"invite-code\"\n className=\"block text-sm font-medium text-gray-700\"\n >\n Paste your invite code\n </label>\n <input\n id=\"invite-code\"\n type=\"text\"\n placeholder=\"Paste code from your email\"\n value={manualCode}\n onChange={(e) => setManualCode(e.target.value)}\n className={[\n \"portal-input w-full px-5 py-4 text-base font-mono\",\n displayError ? \"border-red-500\" : \"\"\n ]\n .filter(Boolean)\n .join(\" \")}\n autoFocus\n disabled={isSubmitting}\n />\n </>\n )}\n\n {/* Error message */}\n {displayError && (\n <p className=\"text-sm font-medium text-red-600\">{displayError}</p>\n )}\n\n {/* Refresh success message */}\n {refreshSuccess && (\n <p className=\"text-sm font-medium text-green-600\">\n A new invitation has been sent to your email.\n </p>\n )}\n\n {/* Accept button */}\n <Button\n type=\"submit\"\n size=\"lg\"\n className=\"w-full justify-center rounded-xl bg-indigo-600 text-white hover:bg-indigo-700\"\n disabled={!effectiveCode || isSubmitting}\n isLoading={isSubmitting}\n >\n Accept invite\n </Button>\n\n {/* Refresh invite link (shown on error for URL-based codes) */}\n {showRefreshLink && onRefreshInvite && (\n <div className=\"text-center\">\n <button\n type=\"button\"\n onClick={handleRefresh}\n disabled={isRefreshing}\n className=\"text-sm font-medium text-indigo-600 hover:text-indigo-700 hover:underline disabled:opacity-50\"\n >\n {isRefreshing ? \"Sending...\" : \"Refresh invite\"}\n </button>\n </div>\n )}\n\n {/* Login link (shown when no URL code) */}\n {!hasUrlCode && (\n <div className=\"text-center\">\n <a\n href={loginUrl}\n className=\"text-sm font-medium text-indigo-600 hover:text-indigo-700 hover:underline\"\n >\n or login\n </a>\n </div>\n )}\n </form>\n </div>\n );\n }\n);\n\nJoinTeam.displayName = \"JoinTeam\";\n\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { FetchLicenseSummaryResult } from './actions/index.mjs';
|
|
3
|
+
|
|
4
|
+
interface LicenseCardProps {
|
|
5
|
+
fetchLicenseSummaryAction: () => Promise<FetchLicenseSummaryResult>;
|
|
6
|
+
initialType?: string;
|
|
7
|
+
initialExpiresAt?: string | null;
|
|
8
|
+
pollIntervalMs?: number;
|
|
9
|
+
}
|
|
10
|
+
declare const LicenseCard: {
|
|
11
|
+
({ fetchLicenseSummaryAction, initialType, initialExpiresAt, pollIntervalMs }: LicenseCardProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
displayName: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { LicenseCard };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { FetchLicenseSummaryResult } from './actions/index.js';
|
|
3
|
+
|
|
4
|
+
interface LicenseCardProps {
|
|
5
|
+
fetchLicenseSummaryAction: () => Promise<FetchLicenseSummaryResult>;
|
|
6
|
+
initialType?: string;
|
|
7
|
+
initialExpiresAt?: string | null;
|
|
8
|
+
pollIntervalMs?: number;
|
|
9
|
+
}
|
|
10
|
+
declare const LicenseCard: {
|
|
11
|
+
({ fetchLicenseSummaryAction, initialType, initialExpiresAt, pollIntervalMs }: LicenseCardProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
displayName: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { LicenseCard };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Enterprise Portal Components
|
|
9
|
+
* This file is generated by tsup. Do not edit manually.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
var FileIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13
|
+
"svg",
|
|
14
|
+
{
|
|
15
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
16
|
+
viewBox: "0 0 24 24",
|
|
17
|
+
fill: "none",
|
|
18
|
+
stroke: "currentColor",
|
|
19
|
+
strokeWidth: 1.5,
|
|
20
|
+
"aria-hidden": "true",
|
|
21
|
+
...props,
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 2h5l5 5v13a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2Z" }),
|
|
24
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M13 2v6h6" })
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
var CalendarIcon = (props) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
29
|
+
"svg",
|
|
30
|
+
{
|
|
31
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
32
|
+
viewBox: "0 0 24 24",
|
|
33
|
+
fill: "none",
|
|
34
|
+
stroke: "currentColor",
|
|
35
|
+
strokeWidth: 1.5,
|
|
36
|
+
"aria-hidden": "true",
|
|
37
|
+
...props,
|
|
38
|
+
children: [
|
|
39
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 2v2" }),
|
|
40
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 2v2" }),
|
|
41
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: 16, height: 16, x: 4, y: 4, rx: 2 }),
|
|
42
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 10h16" })
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
var baseCardClass = "flex h-full flex-col rounded-xl border border-gray-200 bg-white p-6 shadow-[0_16px_32px_rgba(15,23,42,0.05)]";
|
|
47
|
+
var headingClass = "text-lg font-semibold text-gray-900";
|
|
48
|
+
var contentClass = "mt-4 flex-1 space-y-3";
|
|
49
|
+
var itemClass = "flex items-center gap-3 text-sm text-gray-600";
|
|
50
|
+
var iconClass = "h-5 w-5 text-gray-500";
|
|
51
|
+
var footerClass = "mt-6 flex justify-end text-sm font-semibold text-primary hover:text-primary/80";
|
|
52
|
+
var formatDate = (dateString) => {
|
|
53
|
+
if (!dateString) {
|
|
54
|
+
return "Never";
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const date = new Date(dateString);
|
|
58
|
+
return date.toLocaleDateString("en-US", {
|
|
59
|
+
year: "numeric",
|
|
60
|
+
month: "2-digit",
|
|
61
|
+
day: "2-digit"
|
|
62
|
+
});
|
|
63
|
+
} catch {
|
|
64
|
+
return dateString;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var formatLicenseType = (type) => {
|
|
68
|
+
if (!type || type === "Unknown") {
|
|
69
|
+
return "Unknown";
|
|
70
|
+
}
|
|
71
|
+
const capitalized = type.charAt(0).toUpperCase() + type.slice(1).toLowerCase();
|
|
72
|
+
return `${capitalized} license`;
|
|
73
|
+
};
|
|
74
|
+
var LicenseCard = ({
|
|
75
|
+
fetchLicenseSummaryAction,
|
|
76
|
+
initialType = "Unknown",
|
|
77
|
+
initialExpiresAt = null,
|
|
78
|
+
pollIntervalMs = 2e3
|
|
79
|
+
}) => {
|
|
80
|
+
const [type, setType] = react.useState(initialType);
|
|
81
|
+
const [expiresAt, setExpiresAt] = react.useState(initialExpiresAt);
|
|
82
|
+
react.useEffect(() => {
|
|
83
|
+
const fetchSummary = async () => {
|
|
84
|
+
if (document.hidden) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const result = await fetchLicenseSummaryAction();
|
|
89
|
+
setType(result.type);
|
|
90
|
+
setExpiresAt(result.expiresAt);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error("[license-card] Failed to fetch license summary", error);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
fetchSummary();
|
|
96
|
+
const intervalId = setInterval(fetchSummary, pollIntervalMs);
|
|
97
|
+
const handleVisibilityChange = () => {
|
|
98
|
+
if (!document.hidden) {
|
|
99
|
+
fetchSummary();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
103
|
+
return () => {
|
|
104
|
+
clearInterval(intervalId);
|
|
105
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
106
|
+
};
|
|
107
|
+
}, [fetchLicenseSummaryAction, pollIntervalMs]);
|
|
108
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: baseCardClass, "aria-labelledby": "license-card-heading", children: [
|
|
109
|
+
/* @__PURE__ */ jsxRuntime.jsx("header", { children: /* @__PURE__ */ jsxRuntime.jsx("h2", { id: "license-card-heading", className: headingClass, children: "License" }) }),
|
|
110
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: contentClass, children: [
|
|
111
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: itemClass, children: [
|
|
112
|
+
/* @__PURE__ */ jsxRuntime.jsx(FileIcon, { className: iconClass }),
|
|
113
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
114
|
+
"Type: ",
|
|
115
|
+
formatLicenseType(type)
|
|
116
|
+
] })
|
|
117
|
+
] }),
|
|
118
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: itemClass, children: [
|
|
119
|
+
/* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { className: iconClass }),
|
|
120
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
121
|
+
"Expiration: ",
|
|
122
|
+
formatDate(expiresAt)
|
|
123
|
+
] })
|
|
124
|
+
] })
|
|
125
|
+
] }),
|
|
126
|
+
/* @__PURE__ */ jsxRuntime.jsx("footer", { className: footerClass, children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/license", children: "View license \u2192" }) })
|
|
127
|
+
] });
|
|
128
|
+
};
|
|
129
|
+
LicenseCard.displayName = "LicenseCard";
|
|
130
|
+
|
|
131
|
+
exports.LicenseCard = LicenseCard;
|
|
132
|
+
//# sourceMappingURL=license-card.js.map
|
|
133
|
+
//# sourceMappingURL=license-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/license-card.tsx"],"names":["jsxs","jsx","useState","useEffect"],"mappings":"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","file":"license-card.js","sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { SVGProps } from \"react\";\nimport type { FetchLicenseSummaryResult } from \"../actions\";\n\nconst FileIcon = (props: SVGProps<SVGSVGElement>) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n aria-hidden=\"true\"\n {...props}\n >\n <path d=\"M8 2h5l5 5v13a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2Z\" />\n <path d=\"M13 2v6h6\" />\n </svg>\n);\n\nconst CalendarIcon = (props: SVGProps<SVGSVGElement>) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n aria-hidden=\"true\"\n {...props}\n >\n <path d=\"M8 2v2\" />\n <path d=\"M16 2v2\" />\n <rect width={16} height={16} x={4} y={4} rx={2} />\n <path d=\"M4 10h16\" />\n </svg>\n);\n\nconst baseCardClass =\n \"flex h-full flex-col rounded-xl border border-gray-200 bg-white p-6 shadow-[0_16px_32px_rgba(15,23,42,0.05)]\";\nconst headingClass = \"text-lg font-semibold text-gray-900\";\nconst contentClass = \"mt-4 flex-1 space-y-3\";\nconst itemClass = \"flex items-center gap-3 text-sm text-gray-600\";\nconst iconClass = \"h-5 w-5 text-gray-500\";\nconst footerClass =\n \"mt-6 flex justify-end text-sm font-semibold text-primary hover:text-primary/80\";\n\nexport interface LicenseCardProps {\n fetchLicenseSummaryAction: () => Promise<FetchLicenseSummaryResult>;\n initialType?: string;\n initialExpiresAt?: string | null;\n pollIntervalMs?: number;\n}\n\nconst formatDate = (dateString: string | null): string => {\n if (!dateString) {\n return \"Never\";\n }\n \n try {\n const date = new Date(dateString);\n return date.toLocaleDateString(\"en-US\", {\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\"\n });\n } catch {\n return dateString;\n }\n};\n\nconst formatLicenseType = (type: string): string => {\n if (!type || type === \"Unknown\") {\n return \"Unknown\";\n }\n \n // Capitalize first letter and add \" license\"\n const capitalized = type.charAt(0).toUpperCase() + type.slice(1).toLowerCase();\n return `${capitalized} license`;\n};\n\nexport const LicenseCard = ({\n fetchLicenseSummaryAction,\n initialType = \"Unknown\",\n initialExpiresAt = null,\n pollIntervalMs = 2000\n}: LicenseCardProps) => {\n const [type, setType] = useState(initialType);\n const [expiresAt, setExpiresAt] = useState(initialExpiresAt);\n\n useEffect(() => {\n const fetchSummary = async () => {\n // Skip if tab is not visible\n if (document.hidden) {\n return;\n }\n \n try {\n const result = await fetchLicenseSummaryAction();\n setType(result.type);\n setExpiresAt(result.expiresAt);\n } catch (error) {\n console.error(\"[license-card] Failed to fetch license summary\", error);\n }\n };\n\n // Fetch immediately\n fetchSummary();\n\n // Set up polling interval\n const intervalId = setInterval(fetchSummary, pollIntervalMs);\n\n // Also fetch when tab becomes visible again\n const handleVisibilityChange = () => {\n if (!document.hidden) {\n fetchSummary();\n }\n };\n document.addEventListener('visibilitychange', handleVisibilityChange);\n\n // Cleanup on unmount\n return () => {\n clearInterval(intervalId);\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n };\n }, [fetchLicenseSummaryAction, pollIntervalMs]);\n\n return (\n <section className={baseCardClass} aria-labelledby=\"license-card-heading\">\n <header>\n <h2 id=\"license-card-heading\" className={headingClass}>\n License\n </h2>\n </header>\n <div className={contentClass}>\n <div className={itemClass}>\n <FileIcon className={iconClass} />\n <span>Type: {formatLicenseType(type)}</span>\n </div>\n <div className={itemClass}>\n <CalendarIcon className={iconClass} />\n <span>Expiration: {formatDate(expiresAt)}</span>\n </div>\n </div>\n <footer className={footerClass}>\n <a href=\"/license\">View license →</a>\n </footer>\n </section>\n );\n};\n\nLicenseCard.displayName = \"LicenseCard\";\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface LicenseDetailsProps {
|
|
4
|
+
token: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const LicenseDetails: ({ token, title, description }: LicenseDetailsProps) => Promise<react_jsx_runtime.JSX.Element>;
|
|
9
|
+
|
|
10
|
+
export { LicenseDetails, type LicenseDetailsProps };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface LicenseDetailsProps {
|
|
4
|
+
token: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const LicenseDetails: ({ token, title, description }: LicenseDetailsProps) => Promise<react_jsx_runtime.JSX.Element>;
|
|
9
|
+
|
|
10
|
+
export { LicenseDetails, type LicenseDetailsProps };
|