@sudobility/entity_pages 0.0.13 → 0.0.14
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/index.d.ts +1 -1
- package/dist/index.esm.js +433 -258
- package/dist/index.umd.js +1 -1
- package/dist/pages/EntityPricingPage.d.ts +86 -0
- package/dist/pages/EntitySubscriptionsPage.d.ts +2 -0
- package/dist/pages/index.d.ts +1 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -20,4 +20,4 @@
|
|
|
20
20
|
* }
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
|
-
export { EntityListPage, type EntityListPageProps, MembersManagementPage, type MembersManagementPageProps, InvitationsPage, type InvitationsPageProps, EntitySubscriptionsPage, type EntitySubscriptionsPageProps, type SubscriptionProduct, type CurrentSubscription, type SubscriptionContextValue, type SubscriptionPageLabels, type SubscriptionPageFormatters, } from './pages';
|
|
23
|
+
export { EntityListPage, type EntityListPageProps, MembersManagementPage, type MembersManagementPageProps, InvitationsPage, type InvitationsPageProps, EntitySubscriptionsPage, type EntitySubscriptionsPageProps, type SubscriptionProduct, type CurrentSubscription, type SubscriptionContextValue, type SubscriptionPageLabels, type SubscriptionPageFormatters, EntityPricingPage, type EntityPricingPageProps, type PricingProduct, type FAQItem, type PricingPageLabels, type PricingPageFormatters, type EntitlementMap, type EntitlementLevels, } from './pages';
|
package/dist/index.esm.js
CHANGED
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { useState as
|
|
3
|
-
import { Plus as
|
|
4
|
-
import { EntityList as
|
|
5
|
-
import { useEntities as se, useCreateEntity as
|
|
6
|
-
import { SubscriptionLayout as
|
|
7
|
-
function
|
|
8
|
-
client:
|
|
9
|
-
onSelectEntity:
|
|
1
|
+
import { jsxs as s, jsx as i, Fragment as ne } from "react/jsx-runtime";
|
|
2
|
+
import { useState as E, useEffect as re, useCallback as x } from "react";
|
|
3
|
+
import { Plus as ae } from "lucide-react";
|
|
4
|
+
import { EntityList as G, InvitationForm as oe, InvitationList as K, MemberList as le } from "@sudobility/entity-components";
|
|
5
|
+
import { useEntities as se, useCreateEntity as ce, useEntityMembers as de, useUpdateMemberRole as ue, useRemoveMember as me, useEntityInvitations as he, useCreateInvitation as ye, useCancelInvitation as fe, useMyInvitations as ge, useAcceptInvitation as pe, useDeclineInvitation as ve } from "@sudobility/entity_client";
|
|
6
|
+
import { SubscriptionLayout as xe, SubscriptionTile as W, SegmentedControl as J } from "@sudobility/subscription-components";
|
|
7
|
+
function Te({
|
|
8
|
+
client: u,
|
|
9
|
+
onSelectEntity: a
|
|
10
10
|
}) {
|
|
11
|
-
const [t,
|
|
11
|
+
const [t, l] = E(!1), [o, b] = E({
|
|
12
12
|
displayName: "",
|
|
13
13
|
description: ""
|
|
14
|
-
}), [y,
|
|
15
|
-
(
|
|
14
|
+
}), [y, N] = E(null), { data: h = [], isLoading: c } = se(u), f = ce(u), S = h.filter((d) => d.entityType === "personal"), T = h.filter(
|
|
15
|
+
(d) => d.entityType === "organization"
|
|
16
16
|
);
|
|
17
|
-
return /* @__PURE__ */
|
|
18
|
-
/* @__PURE__ */
|
|
19
|
-
/* @__PURE__ */
|
|
17
|
+
return /* @__PURE__ */ s("div", { className: "space-y-8", children: [
|
|
18
|
+
/* @__PURE__ */ s("div", { className: "flex items-center justify-between", children: [
|
|
19
|
+
/* @__PURE__ */ s("div", { children: [
|
|
20
20
|
/* @__PURE__ */ i("h1", { className: "text-2xl font-bold text-foreground", children: "Workspaces" }),
|
|
21
21
|
/* @__PURE__ */ i("p", { className: "text-muted-foreground", children: "Manage your personal and organization workspaces" })
|
|
22
22
|
] }),
|
|
23
|
-
/* @__PURE__ */
|
|
23
|
+
/* @__PURE__ */ s(
|
|
24
24
|
"button",
|
|
25
25
|
{
|
|
26
26
|
type: "button",
|
|
27
|
-
onClick: () =>
|
|
27
|
+
onClick: () => l(!0),
|
|
28
28
|
className: "flex items-center gap-2 px-4 py-2 rounded-lg bg-primary text-primary-foreground font-medium hover:bg-primary/90 transition-colors",
|
|
29
29
|
children: [
|
|
30
|
-
/* @__PURE__ */ i(
|
|
30
|
+
/* @__PURE__ */ i(ae, { className: "h-4 w-4" }),
|
|
31
31
|
/* @__PURE__ */ i("span", { children: "New Organization" })
|
|
32
32
|
]
|
|
33
33
|
}
|
|
34
34
|
)
|
|
35
35
|
] }),
|
|
36
|
-
t && /* @__PURE__ */ i("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", children: /* @__PURE__ */
|
|
36
|
+
t && /* @__PURE__ */ i("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", children: /* @__PURE__ */ s("div", { className: "w-full max-w-md rounded-lg bg-background p-6 shadow-lg", children: [
|
|
37
37
|
/* @__PURE__ */ i("h2", { className: "text-lg font-semibold mb-4", children: "Create Organization" }),
|
|
38
|
-
/* @__PURE__ */
|
|
39
|
-
if (
|
|
40
|
-
|
|
38
|
+
/* @__PURE__ */ s("form", { onSubmit: async (d) => {
|
|
39
|
+
if (d.preventDefault(), N(null), !o.displayName.trim()) {
|
|
40
|
+
N("Display name is required");
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
try {
|
|
44
|
-
await
|
|
45
|
-
displayName:
|
|
46
|
-
description:
|
|
47
|
-
}),
|
|
48
|
-
} catch (
|
|
49
|
-
|
|
44
|
+
await f.mutateAsync({
|
|
45
|
+
displayName: o.displayName.trim(),
|
|
46
|
+
description: o.description.trim() || void 0
|
|
47
|
+
}), l(!1), b({ displayName: "", description: "" });
|
|
48
|
+
} catch (g) {
|
|
49
|
+
N(g.message || "Failed to create organization");
|
|
50
50
|
}
|
|
51
51
|
}, className: "space-y-4", children: [
|
|
52
|
-
/* @__PURE__ */
|
|
52
|
+
/* @__PURE__ */ s("div", { children: [
|
|
53
53
|
/* @__PURE__ */ i("label", { className: "block text-sm font-medium mb-1", children: "Display Name" }),
|
|
54
54
|
/* @__PURE__ */ i(
|
|
55
55
|
"input",
|
|
56
56
|
{
|
|
57
57
|
type: "text",
|
|
58
|
-
value:
|
|
59
|
-
onChange: (
|
|
60
|
-
...
|
|
61
|
-
displayName:
|
|
58
|
+
value: o.displayName,
|
|
59
|
+
onChange: (d) => b((g) => ({
|
|
60
|
+
...g,
|
|
61
|
+
displayName: d.target.value
|
|
62
62
|
})),
|
|
63
63
|
placeholder: "My Organization",
|
|
64
64
|
className: "w-full px-3 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary"
|
|
65
65
|
}
|
|
66
66
|
)
|
|
67
67
|
] }),
|
|
68
|
-
/* @__PURE__ */
|
|
68
|
+
/* @__PURE__ */ s("div", { children: [
|
|
69
69
|
/* @__PURE__ */ i("label", { className: "block text-sm font-medium mb-1", children: "Description (optional)" }),
|
|
70
70
|
/* @__PURE__ */ i(
|
|
71
71
|
"textarea",
|
|
72
72
|
{
|
|
73
|
-
value:
|
|
74
|
-
onChange: (
|
|
75
|
-
...
|
|
76
|
-
description:
|
|
73
|
+
value: o.description,
|
|
74
|
+
onChange: (d) => b((g) => ({
|
|
75
|
+
...g,
|
|
76
|
+
description: d.target.value
|
|
77
77
|
})),
|
|
78
78
|
placeholder: "What is this organization for?",
|
|
79
79
|
rows: 3,
|
|
@@ -82,13 +82,13 @@ function Ie({
|
|
|
82
82
|
)
|
|
83
83
|
] }),
|
|
84
84
|
y && /* @__PURE__ */ i("p", { className: "text-sm text-destructive", children: y }),
|
|
85
|
-
/* @__PURE__ */
|
|
85
|
+
/* @__PURE__ */ s("div", { className: "flex justify-end gap-2", children: [
|
|
86
86
|
/* @__PURE__ */ i(
|
|
87
87
|
"button",
|
|
88
88
|
{
|
|
89
89
|
type: "button",
|
|
90
90
|
onClick: () => {
|
|
91
|
-
|
|
91
|
+
l(!1), b({ displayName: "", description: "" }), N(null);
|
|
92
92
|
},
|
|
93
93
|
className: "px-4 py-2 rounded-lg border hover:bg-muted transition-colors",
|
|
94
94
|
children: "Cancel"
|
|
@@ -98,182 +98,182 @@ function Ie({
|
|
|
98
98
|
"button",
|
|
99
99
|
{
|
|
100
100
|
type: "submit",
|
|
101
|
-
disabled:
|
|
101
|
+
disabled: f.isPending,
|
|
102
102
|
className: "px-4 py-2 rounded-lg bg-primary text-primary-foreground font-medium hover:bg-primary/90 transition-colors disabled:opacity-50",
|
|
103
|
-
children:
|
|
103
|
+
children: f.isPending ? "Creating..." : "Create"
|
|
104
104
|
}
|
|
105
105
|
)
|
|
106
106
|
] })
|
|
107
107
|
] })
|
|
108
108
|
] }) }),
|
|
109
|
-
|
|
109
|
+
S.length > 0 && /* @__PURE__ */ s("div", { children: [
|
|
110
110
|
/* @__PURE__ */ i("h2", { className: "text-lg font-semibold mb-3", children: "Personal Workspace" }),
|
|
111
111
|
/* @__PURE__ */ i(
|
|
112
|
-
|
|
112
|
+
G,
|
|
113
113
|
{
|
|
114
|
-
entities:
|
|
115
|
-
onSelect:
|
|
116
|
-
isLoading:
|
|
114
|
+
entities: S,
|
|
115
|
+
onSelect: a,
|
|
116
|
+
isLoading: c
|
|
117
117
|
}
|
|
118
118
|
)
|
|
119
119
|
] }),
|
|
120
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ s("div", { children: [
|
|
121
121
|
/* @__PURE__ */ i("h2", { className: "text-lg font-semibold mb-3", children: "Organizations" }),
|
|
122
|
-
|
|
122
|
+
T.length === 0 && !c ? /* @__PURE__ */ s("div", { className: "text-center py-8 text-muted-foreground border border-dashed rounded-lg", children: [
|
|
123
123
|
/* @__PURE__ */ i("p", { children: "No organizations yet" }),
|
|
124
124
|
/* @__PURE__ */ i(
|
|
125
125
|
"button",
|
|
126
126
|
{
|
|
127
127
|
type: "button",
|
|
128
|
-
onClick: () =>
|
|
128
|
+
onClick: () => l(!0),
|
|
129
129
|
className: "mt-2 text-primary hover:underline",
|
|
130
130
|
children: "Create your first organization"
|
|
131
131
|
}
|
|
132
132
|
)
|
|
133
133
|
] }) : /* @__PURE__ */ i(
|
|
134
|
-
|
|
134
|
+
G,
|
|
135
135
|
{
|
|
136
|
-
entities:
|
|
137
|
-
onSelect:
|
|
138
|
-
isLoading:
|
|
136
|
+
entities: T,
|
|
137
|
+
onSelect: a,
|
|
138
|
+
isLoading: c
|
|
139
139
|
}
|
|
140
140
|
)
|
|
141
141
|
] })
|
|
142
142
|
] });
|
|
143
143
|
}
|
|
144
|
-
function
|
|
145
|
-
client:
|
|
146
|
-
entity:
|
|
144
|
+
function Fe({
|
|
145
|
+
client: u,
|
|
146
|
+
entity: a,
|
|
147
147
|
currentUserId: t
|
|
148
148
|
}) {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
), y =
|
|
149
|
+
const l = a.userRole === "admin", { data: o = [], isLoading: b } = de(
|
|
150
|
+
u,
|
|
151
|
+
a.entitySlug
|
|
152
|
+
), y = ue(u), N = me(u), { data: h = [], isLoading: c } = he(u, l ? a.entitySlug : null), f = ye(u), S = fe(u), T = async (w, P) => {
|
|
153
153
|
try {
|
|
154
154
|
await y.mutateAsync({
|
|
155
|
-
entitySlug:
|
|
156
|
-
memberId:
|
|
157
|
-
role:
|
|
155
|
+
entitySlug: a.entitySlug,
|
|
156
|
+
memberId: w,
|
|
157
|
+
role: P
|
|
158
158
|
});
|
|
159
|
-
} catch (
|
|
160
|
-
console.error("Failed to update role:",
|
|
159
|
+
} catch (F) {
|
|
160
|
+
console.error("Failed to update role:", F);
|
|
161
161
|
}
|
|
162
|
-
},
|
|
162
|
+
}, R = async (w) => {
|
|
163
163
|
if (confirm("Are you sure you want to remove this member?"))
|
|
164
164
|
try {
|
|
165
|
-
await
|
|
166
|
-
entitySlug:
|
|
167
|
-
memberId:
|
|
165
|
+
await N.mutateAsync({
|
|
166
|
+
entitySlug: a.entitySlug,
|
|
167
|
+
memberId: w
|
|
168
168
|
});
|
|
169
|
-
} catch (
|
|
170
|
-
console.error("Failed to remove member:",
|
|
169
|
+
} catch (P) {
|
|
170
|
+
console.error("Failed to remove member:", P);
|
|
171
171
|
}
|
|
172
|
-
},
|
|
173
|
-
await
|
|
174
|
-
entitySlug:
|
|
175
|
-
request:
|
|
172
|
+
}, d = async (w) => {
|
|
173
|
+
await f.mutateAsync({
|
|
174
|
+
entitySlug: a.entitySlug,
|
|
175
|
+
request: w
|
|
176
176
|
});
|
|
177
|
-
},
|
|
177
|
+
}, g = async (w) => {
|
|
178
178
|
try {
|
|
179
|
-
await
|
|
180
|
-
entitySlug:
|
|
181
|
-
invitationId:
|
|
179
|
+
await S.mutateAsync({
|
|
180
|
+
entitySlug: a.entitySlug,
|
|
181
|
+
invitationId: w
|
|
182
182
|
});
|
|
183
|
-
} catch (
|
|
184
|
-
console.error("Failed to cancel invitation:",
|
|
183
|
+
} catch (P) {
|
|
184
|
+
console.error("Failed to cancel invitation:", P);
|
|
185
185
|
}
|
|
186
186
|
};
|
|
187
|
-
return
|
|
187
|
+
return a.entityType === "personal" ? /* @__PURE__ */ s("div", { className: "text-center py-12 text-muted-foreground", children: [
|
|
188
188
|
/* @__PURE__ */ i("p", { children: "Personal workspaces cannot have additional members." }),
|
|
189
189
|
/* @__PURE__ */ i("p", { className: "mt-2", children: "Create an organization to collaborate with others." })
|
|
190
|
-
] }) : /* @__PURE__ */
|
|
191
|
-
/* @__PURE__ */
|
|
190
|
+
] }) : /* @__PURE__ */ s("div", { className: "space-y-8", children: [
|
|
191
|
+
/* @__PURE__ */ s("div", { children: [
|
|
192
192
|
/* @__PURE__ */ i("h1", { className: "text-2xl font-bold text-foreground", children: "Members" }),
|
|
193
|
-
/* @__PURE__ */
|
|
193
|
+
/* @__PURE__ */ s("p", { className: "text-muted-foreground", children: [
|
|
194
194
|
"Manage members and invitations for ",
|
|
195
|
-
|
|
195
|
+
a.displayName
|
|
196
196
|
] })
|
|
197
197
|
] }),
|
|
198
|
-
|
|
198
|
+
l && /* @__PURE__ */ s("div", { className: "rounded-lg border p-4", children: [
|
|
199
199
|
/* @__PURE__ */ i("h2", { className: "text-lg font-semibold mb-4", children: "Invite Members" }),
|
|
200
200
|
/* @__PURE__ */ i(
|
|
201
|
-
|
|
201
|
+
oe,
|
|
202
202
|
{
|
|
203
|
-
onSubmit:
|
|
204
|
-
isSubmitting:
|
|
203
|
+
onSubmit: d,
|
|
204
|
+
isSubmitting: f.isPending
|
|
205
205
|
}
|
|
206
206
|
)
|
|
207
207
|
] }),
|
|
208
|
-
|
|
208
|
+
l && /* @__PURE__ */ s("div", { children: [
|
|
209
209
|
/* @__PURE__ */ i("h2", { className: "text-lg font-semibold mb-3", children: "Pending Invitations" }),
|
|
210
210
|
/* @__PURE__ */ i(
|
|
211
|
-
|
|
211
|
+
K,
|
|
212
212
|
{
|
|
213
|
-
invitations:
|
|
213
|
+
invitations: h,
|
|
214
214
|
mode: "admin",
|
|
215
|
-
onCancel:
|
|
216
|
-
isLoading:
|
|
215
|
+
onCancel: g,
|
|
216
|
+
isLoading: c,
|
|
217
217
|
emptyMessage: "No pending invitations"
|
|
218
218
|
}
|
|
219
219
|
)
|
|
220
220
|
] }),
|
|
221
|
-
/* @__PURE__ */
|
|
222
|
-
/* @__PURE__ */
|
|
221
|
+
/* @__PURE__ */ s("div", { children: [
|
|
222
|
+
/* @__PURE__ */ s("h2", { className: "text-lg font-semibold mb-3", children: [
|
|
223
223
|
"Current Members (",
|
|
224
|
-
|
|
224
|
+
o.length,
|
|
225
225
|
")"
|
|
226
226
|
] }),
|
|
227
227
|
/* @__PURE__ */ i(
|
|
228
|
-
|
|
228
|
+
le,
|
|
229
229
|
{
|
|
230
|
-
members:
|
|
230
|
+
members: o,
|
|
231
231
|
currentUserId: t,
|
|
232
|
-
canManage:
|
|
233
|
-
onRoleChange:
|
|
234
|
-
onRemove:
|
|
235
|
-
isLoading:
|
|
232
|
+
canManage: l,
|
|
233
|
+
onRoleChange: T,
|
|
234
|
+
onRemove: R,
|
|
235
|
+
isLoading: b
|
|
236
236
|
}
|
|
237
237
|
)
|
|
238
238
|
] })
|
|
239
239
|
] });
|
|
240
240
|
}
|
|
241
|
-
function
|
|
242
|
-
client:
|
|
243
|
-
onInvitationAccepted:
|
|
241
|
+
function Le({
|
|
242
|
+
client: u,
|
|
243
|
+
onInvitationAccepted: a
|
|
244
244
|
}) {
|
|
245
|
-
const { data: t = [], isLoading:
|
|
245
|
+
const { data: t = [], isLoading: l } = ge(u), o = pe(u), b = ve(u), y = async (c) => {
|
|
246
246
|
try {
|
|
247
|
-
await
|
|
248
|
-
} catch (
|
|
249
|
-
console.error("Failed to accept invitation:",
|
|
247
|
+
await o.mutateAsync(c), a?.();
|
|
248
|
+
} catch (f) {
|
|
249
|
+
console.error("Failed to accept invitation:", f);
|
|
250
250
|
}
|
|
251
|
-
},
|
|
251
|
+
}, N = async (c) => {
|
|
252
252
|
try {
|
|
253
|
-
await
|
|
254
|
-
} catch (
|
|
255
|
-
console.error("Failed to decline invitation:",
|
|
253
|
+
await b.mutateAsync(c);
|
|
254
|
+
} catch (f) {
|
|
255
|
+
console.error("Failed to decline invitation:", f);
|
|
256
256
|
}
|
|
257
|
-
},
|
|
258
|
-
return /* @__PURE__ */
|
|
259
|
-
/* @__PURE__ */
|
|
257
|
+
}, h = t.filter((c) => c.status === "pending").length;
|
|
258
|
+
return /* @__PURE__ */ s("div", { className: "space-y-6", children: [
|
|
259
|
+
/* @__PURE__ */ s("div", { children: [
|
|
260
260
|
/* @__PURE__ */ i("h1", { className: "text-2xl font-bold text-foreground", children: "Invitations" }),
|
|
261
|
-
/* @__PURE__ */ i("p", { className: "text-muted-foreground", children:
|
|
261
|
+
/* @__PURE__ */ i("p", { className: "text-muted-foreground", children: h > 0 ? `You have ${h} pending invitation${h > 1 ? "s" : ""}` : "No pending invitations" })
|
|
262
262
|
] }),
|
|
263
263
|
/* @__PURE__ */ i(
|
|
264
|
-
|
|
264
|
+
K,
|
|
265
265
|
{
|
|
266
266
|
invitations: t,
|
|
267
267
|
mode: "user",
|
|
268
268
|
onAccept: y,
|
|
269
|
-
onDecline:
|
|
270
|
-
isLoading:
|
|
269
|
+
onDecline: N,
|
|
270
|
+
isLoading: l,
|
|
271
271
|
emptyMessage: "You don't have any pending invitations"
|
|
272
272
|
}
|
|
273
273
|
)
|
|
274
274
|
] });
|
|
275
275
|
}
|
|
276
|
-
const
|
|
276
|
+
const O = {
|
|
277
277
|
ultra_yearly: "bandwidth_ultra",
|
|
278
278
|
ultra_monthly: "bandwidth_ultra",
|
|
279
279
|
pro_yearly: "bandwidth_pro",
|
|
@@ -282,247 +282,247 @@ const L = {
|
|
|
282
282
|
dev_monthly: "bandwidth_dev"
|
|
283
283
|
};
|
|
284
284
|
function Ce({
|
|
285
|
-
subscription:
|
|
286
|
-
rateLimitsConfig:
|
|
285
|
+
subscription: u,
|
|
286
|
+
rateLimitsConfig: a,
|
|
287
287
|
labels: t,
|
|
288
|
-
formatters:
|
|
289
|
-
onPurchaseSuccess:
|
|
290
|
-
onRestoreSuccess:
|
|
288
|
+
formatters: l,
|
|
289
|
+
onPurchaseSuccess: o,
|
|
290
|
+
onRestoreSuccess: b,
|
|
291
291
|
onError: y,
|
|
292
|
-
onWarning:
|
|
292
|
+
onWarning: N
|
|
293
293
|
}) {
|
|
294
294
|
const {
|
|
295
|
-
products:
|
|
296
|
-
currentSubscription:
|
|
297
|
-
isLoading:
|
|
298
|
-
error:
|
|
299
|
-
purchase:
|
|
300
|
-
restore:
|
|
301
|
-
clearError:
|
|
302
|
-
} =
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
}, [
|
|
306
|
-
const
|
|
295
|
+
products: h,
|
|
296
|
+
currentSubscription: c,
|
|
297
|
+
isLoading: f,
|
|
298
|
+
error: S,
|
|
299
|
+
purchase: T,
|
|
300
|
+
restore: R,
|
|
301
|
+
clearError: d
|
|
302
|
+
} = u, [g, w] = E("monthly"), [P, F] = E(null), [L, z] = E(!1), [C, n] = E(!1);
|
|
303
|
+
re(() => {
|
|
304
|
+
S && (y?.(t.errorTitle, S), d());
|
|
305
|
+
}, [S, d, t.errorTitle, y]);
|
|
306
|
+
const m = h.filter((e) => {
|
|
307
307
|
if (!e.period) return !1;
|
|
308
|
-
const
|
|
309
|
-
return
|
|
310
|
-
}).sort((e,
|
|
311
|
-
|
|
312
|
-
},
|
|
313
|
-
if (
|
|
314
|
-
|
|
308
|
+
const r = e.period.includes("Y") || e.period.includes("year");
|
|
309
|
+
return g === "yearly" ? r : !r;
|
|
310
|
+
}).sort((e, r) => parseFloat(e.price) - parseFloat(r.price)), B = (e) => {
|
|
311
|
+
w(e), F(null);
|
|
312
|
+
}, M = async () => {
|
|
313
|
+
if (P) {
|
|
314
|
+
z(!0), d();
|
|
315
315
|
try {
|
|
316
|
-
await
|
|
316
|
+
await T(P) && (o?.(), F(null));
|
|
317
317
|
} catch (e) {
|
|
318
318
|
y?.(
|
|
319
319
|
t.errorTitle,
|
|
320
320
|
e instanceof Error ? e.message : t.purchaseError
|
|
321
321
|
);
|
|
322
322
|
} finally {
|
|
323
|
-
|
|
323
|
+
z(!1);
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
|
-
},
|
|
327
|
-
|
|
326
|
+
}, I = async () => {
|
|
327
|
+
n(!0), d();
|
|
328
328
|
try {
|
|
329
|
-
await
|
|
329
|
+
await R() ? b?.() : N?.(t.errorTitle, t.restoreNoPurchases);
|
|
330
330
|
} catch (e) {
|
|
331
331
|
y?.(
|
|
332
332
|
t.errorTitle,
|
|
333
333
|
e instanceof Error ? e.message : t.restoreError
|
|
334
334
|
);
|
|
335
335
|
} finally {
|
|
336
|
-
|
|
336
|
+
n(!1);
|
|
337
337
|
}
|
|
338
|
-
},
|
|
338
|
+
}, k = x((e) => e ? new Intl.DateTimeFormat(void 0, {
|
|
339
339
|
year: "numeric",
|
|
340
340
|
month: "long",
|
|
341
341
|
day: "numeric"
|
|
342
|
-
}).format(e) : "", []),
|
|
342
|
+
}).format(e) : "", []), A = x(
|
|
343
343
|
(e) => e ? e.includes("Y") || e.includes("year") ? t.periodYear : e.includes("M") || e.includes("month") ? t.periodMonth : e.includes("W") || e.includes("week") ? t.periodWeek : "" : "",
|
|
344
344
|
[t]
|
|
345
|
-
),
|
|
345
|
+
), Y = x(
|
|
346
346
|
(e) => {
|
|
347
347
|
if (!e) return;
|
|
348
|
-
const
|
|
349
|
-
return e.includes("W") ?
|
|
348
|
+
const r = parseInt(e.replace(/\D/g, "") || "1", 10);
|
|
349
|
+
return e.includes("W") ? l.formatTrialWeeks(r) : e.includes("M") ? l.formatTrialMonths(r) : l.formatTrialDays(r);
|
|
350
350
|
},
|
|
351
|
-
[
|
|
352
|
-
),
|
|
351
|
+
[l]
|
|
352
|
+
), _ = x(
|
|
353
353
|
(e) => {
|
|
354
|
-
if (!
|
|
355
|
-
const
|
|
356
|
-
return
|
|
357
|
-
(
|
|
358
|
-
) :
|
|
354
|
+
if (!a?.tiers) return;
|
|
355
|
+
const r = O[e];
|
|
356
|
+
return r ? a.tiers.find(
|
|
357
|
+
(v) => v.entitlement === r
|
|
358
|
+
) : a.tiers.find((v) => v.entitlement === "none");
|
|
359
359
|
},
|
|
360
|
-
[
|
|
361
|
-
),
|
|
360
|
+
[a]
|
|
361
|
+
), p = x(
|
|
362
362
|
(e) => e === null ? t.unlimited : e.toLocaleString(),
|
|
363
363
|
[t.unlimited]
|
|
364
|
-
),
|
|
364
|
+
), j = x(
|
|
365
365
|
(e) => {
|
|
366
|
-
const
|
|
367
|
-
if (!
|
|
368
|
-
const
|
|
369
|
-
return
|
|
370
|
-
|
|
371
|
-
),
|
|
372
|
-
|
|
373
|
-
),
|
|
374
|
-
|
|
375
|
-
),
|
|
366
|
+
const r = _(e);
|
|
367
|
+
if (!r) return [];
|
|
368
|
+
const v = [];
|
|
369
|
+
return r.limits.hourly !== null && v.push(
|
|
370
|
+
l.formatHourlyLimit(p(r.limits.hourly))
|
|
371
|
+
), r.limits.daily !== null && v.push(
|
|
372
|
+
l.formatDailyLimit(p(r.limits.daily))
|
|
373
|
+
), r.limits.monthly !== null && v.push(
|
|
374
|
+
l.formatMonthlyLimit(p(r.limits.monthly))
|
|
375
|
+
), r.limits.hourly === null && r.limits.daily === null && r.limits.monthly === null && v.push(t.unlimitedRequests), v;
|
|
376
376
|
},
|
|
377
|
-
[
|
|
378
|
-
),
|
|
379
|
-
(e) =>
|
|
380
|
-
[
|
|
381
|
-
),
|
|
377
|
+
[_, p, l, t.unlimitedRequests]
|
|
378
|
+
), Q = x(
|
|
379
|
+
(e) => j(e),
|
|
380
|
+
[j]
|
|
381
|
+
), X = x(() => {
|
|
382
382
|
const e = [...t.freeTierFeatures];
|
|
383
|
-
if (
|
|
384
|
-
const
|
|
385
|
-
(
|
|
383
|
+
if (a?.tiers) {
|
|
384
|
+
const r = a.tiers.find(
|
|
385
|
+
(v) => v.entitlement === "none"
|
|
386
386
|
);
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
),
|
|
390
|
-
|
|
391
|
-
),
|
|
392
|
-
|
|
387
|
+
r && (r.limits.hourly !== null && e.push(
|
|
388
|
+
l.formatHourlyLimit(p(r.limits.hourly))
|
|
389
|
+
), r.limits.daily !== null && e.push(
|
|
390
|
+
l.formatDailyLimit(p(r.limits.daily))
|
|
391
|
+
), r.limits.monthly !== null && e.push(
|
|
392
|
+
l.formatMonthlyLimit(p(r.limits.monthly))
|
|
393
393
|
));
|
|
394
394
|
}
|
|
395
395
|
return e;
|
|
396
|
-
}, [
|
|
396
|
+
}, [a, p, l, t.freeTierFeatures]), Z = x(
|
|
397
397
|
(e) => {
|
|
398
|
-
const
|
|
399
|
-
if (!
|
|
400
|
-
const
|
|
401
|
-
(
|
|
398
|
+
const r = O[e];
|
|
399
|
+
if (!r) return;
|
|
400
|
+
const v = h.find(
|
|
401
|
+
(D) => D.identifier === e
|
|
402
402
|
);
|
|
403
|
-
if (!
|
|
404
|
-
const
|
|
405
|
-
([
|
|
403
|
+
if (!v) return;
|
|
404
|
+
const U = Object.entries(O).find(
|
|
405
|
+
([D, ie]) => ie === r && D.includes("monthly")
|
|
406
406
|
)?.[0];
|
|
407
|
-
if (!
|
|
408
|
-
const
|
|
409
|
-
(
|
|
407
|
+
if (!U) return;
|
|
408
|
+
const $ = h.find(
|
|
409
|
+
(D) => D.identifier === U
|
|
410
410
|
);
|
|
411
|
-
if (
|
|
412
|
-
const
|
|
413
|
-
if (
|
|
414
|
-
const
|
|
415
|
-
return Math.round(
|
|
411
|
+
if (!$) return;
|
|
412
|
+
const V = parseFloat(v.price), q = parseFloat($.price);
|
|
413
|
+
if (q <= 0 || V <= 0) return;
|
|
414
|
+
const H = q * 12, te = (H - V) / H * 100;
|
|
415
|
+
return Math.round(te);
|
|
416
416
|
},
|
|
417
|
-
[
|
|
418
|
-
),
|
|
417
|
+
[h]
|
|
418
|
+
), ee = [
|
|
419
419
|
{ value: "monthly", label: t.billingMonthly },
|
|
420
420
|
{ value: "yearly", label: t.billingYearly }
|
|
421
421
|
];
|
|
422
422
|
return /* @__PURE__ */ i(
|
|
423
|
-
|
|
423
|
+
xe,
|
|
424
424
|
{
|
|
425
425
|
title: t.title,
|
|
426
|
-
error:
|
|
426
|
+
error: S,
|
|
427
427
|
currentStatusLabel: t.currentStatusLabel,
|
|
428
428
|
currentStatus: {
|
|
429
|
-
isActive:
|
|
430
|
-
activeContent:
|
|
429
|
+
isActive: c?.isActive ?? !1,
|
|
430
|
+
activeContent: c?.isActive ? {
|
|
431
431
|
title: t.statusActive,
|
|
432
432
|
fields: [
|
|
433
433
|
{
|
|
434
434
|
label: t.labelPlan,
|
|
435
|
-
value:
|
|
435
|
+
value: c.productIdentifier || t.labelPremium
|
|
436
436
|
},
|
|
437
437
|
{
|
|
438
438
|
label: t.labelExpires,
|
|
439
|
-
value:
|
|
440
|
-
|
|
439
|
+
value: k(
|
|
440
|
+
c.expirationDate
|
|
441
441
|
)
|
|
442
442
|
},
|
|
443
443
|
{
|
|
444
444
|
label: t.labelWillRenew,
|
|
445
|
-
value:
|
|
445
|
+
value: c.willRenew ? t.yes : t.no
|
|
446
446
|
},
|
|
447
|
-
...
|
|
447
|
+
...a ? [
|
|
448
448
|
{
|
|
449
449
|
label: t.labelMonthlyUsage,
|
|
450
|
-
value: `${
|
|
450
|
+
value: `${a.currentUsage.monthly.toLocaleString()} / ${p(a.currentLimits.monthly)}`
|
|
451
451
|
},
|
|
452
452
|
{
|
|
453
453
|
label: t.labelDailyUsage,
|
|
454
|
-
value: `${
|
|
454
|
+
value: `${a.currentUsage.daily.toLocaleString()} / ${p(a.currentLimits.daily)}`
|
|
455
455
|
}
|
|
456
456
|
] : []
|
|
457
457
|
]
|
|
458
458
|
} : void 0,
|
|
459
|
-
inactiveContent:
|
|
459
|
+
inactiveContent: c?.isActive ? void 0 : {
|
|
460
460
|
title: t.statusInactive,
|
|
461
461
|
message: t.statusInactiveMessage
|
|
462
462
|
}
|
|
463
463
|
},
|
|
464
|
-
aboveProducts: !
|
|
465
|
-
|
|
464
|
+
aboveProducts: !f && h.length > 0 ? /* @__PURE__ */ i("div", { className: "flex justify-center mb-6", children: /* @__PURE__ */ i(
|
|
465
|
+
J,
|
|
466
466
|
{
|
|
467
|
-
options:
|
|
468
|
-
value:
|
|
469
|
-
onChange:
|
|
467
|
+
options: ee,
|
|
468
|
+
value: g,
|
|
469
|
+
onChange: B
|
|
470
470
|
}
|
|
471
471
|
) }) : null,
|
|
472
472
|
primaryAction: {
|
|
473
|
-
label:
|
|
474
|
-
onClick:
|
|
475
|
-
disabled: !
|
|
476
|
-
loading:
|
|
473
|
+
label: L ? t.buttonPurchasing : t.buttonSubscribe,
|
|
474
|
+
onClick: M,
|
|
475
|
+
disabled: !P || L || C,
|
|
476
|
+
loading: L
|
|
477
477
|
},
|
|
478
478
|
secondaryAction: {
|
|
479
|
-
label:
|
|
480
|
-
onClick:
|
|
481
|
-
disabled:
|
|
482
|
-
loading:
|
|
479
|
+
label: C ? t.buttonRestoring : t.buttonRestore,
|
|
480
|
+
onClick: I,
|
|
481
|
+
disabled: L || C,
|
|
482
|
+
loading: C
|
|
483
483
|
},
|
|
484
|
-
children:
|
|
484
|
+
children: f ? /* @__PURE__ */ i("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ i("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" }) }) : h.length === 0 ? /* @__PURE__ */ i("div", { className: "text-center py-12 text-theme-text-secondary", children: t.noProducts }) : m.length === 0 ? /* @__PURE__ */ i("div", { className: "text-center py-12 text-theme-text-secondary", children: t.noProductsForPeriod }) : /* @__PURE__ */ s(ne, { children: [
|
|
485
485
|
/* @__PURE__ */ i(
|
|
486
|
-
|
|
486
|
+
W,
|
|
487
487
|
{
|
|
488
488
|
id: "free",
|
|
489
489
|
title: t.freeTierTitle,
|
|
490
490
|
price: t.freeTierPrice,
|
|
491
491
|
periodLabel: t.periodMonth,
|
|
492
|
-
features:
|
|
493
|
-
isSelected: !
|
|
494
|
-
onSelect: () =>
|
|
495
|
-
topBadge:
|
|
492
|
+
features: X(),
|
|
493
|
+
isSelected: !c?.isActive && P === null,
|
|
494
|
+
onSelect: () => F(null),
|
|
495
|
+
topBadge: c?.isActive ? void 0 : {
|
|
496
496
|
text: t.currentPlanBadge,
|
|
497
497
|
color: "green"
|
|
498
498
|
},
|
|
499
|
-
disabled:
|
|
499
|
+
disabled: L || C,
|
|
500
500
|
hideSelectionIndicator: !0
|
|
501
501
|
},
|
|
502
502
|
"free"
|
|
503
503
|
),
|
|
504
|
-
|
|
505
|
-
|
|
504
|
+
m.map((e) => /* @__PURE__ */ i(
|
|
505
|
+
W,
|
|
506
506
|
{
|
|
507
507
|
id: e.identifier,
|
|
508
508
|
title: e.title,
|
|
509
509
|
price: e.priceString,
|
|
510
|
-
periodLabel:
|
|
511
|
-
features:
|
|
512
|
-
isSelected:
|
|
513
|
-
onSelect: () =>
|
|
510
|
+
periodLabel: A(e.period),
|
|
511
|
+
features: Q(e.identifier),
|
|
512
|
+
isSelected: P === e.identifier,
|
|
513
|
+
onSelect: () => F(e.identifier),
|
|
514
514
|
isBestValue: e.identifier.includes("pro"),
|
|
515
515
|
discountBadge: e.period?.includes("Y") ? (() => {
|
|
516
|
-
const
|
|
516
|
+
const r = Z(
|
|
517
517
|
e.identifier
|
|
518
518
|
);
|
|
519
|
-
return
|
|
520
|
-
text:
|
|
519
|
+
return r && r > 0 ? {
|
|
520
|
+
text: l.formatSavePercent(r),
|
|
521
521
|
isBestValue: !0
|
|
522
522
|
} : void 0;
|
|
523
523
|
})() : void 0,
|
|
524
|
-
introPriceNote: e.freeTrialPeriod ?
|
|
525
|
-
disabled:
|
|
524
|
+
introPriceNote: e.freeTrialPeriod ? Y(e.freeTrialPeriod) : e.introPrice ? l.formatIntroNote(e.introPrice) : void 0,
|
|
525
|
+
disabled: L || C
|
|
526
526
|
},
|
|
527
527
|
e.identifier
|
|
528
528
|
))
|
|
@@ -530,9 +530,184 @@ function Ce({
|
|
|
530
530
|
}
|
|
531
531
|
);
|
|
532
532
|
}
|
|
533
|
+
function Ie({
|
|
534
|
+
products: u,
|
|
535
|
+
isAuthenticated: a,
|
|
536
|
+
hasActiveSubscription: t,
|
|
537
|
+
currentProductIdentifier: l,
|
|
538
|
+
labels: o,
|
|
539
|
+
formatters: b,
|
|
540
|
+
entitlementMap: y,
|
|
541
|
+
entitlementLevels: N,
|
|
542
|
+
onPlanClick: h,
|
|
543
|
+
onFreePlanClick: c,
|
|
544
|
+
faqItems: f,
|
|
545
|
+
className: S
|
|
546
|
+
}) {
|
|
547
|
+
const [T, R] = E("monthly"), d = x(
|
|
548
|
+
(n) => {
|
|
549
|
+
const m = y[n];
|
|
550
|
+
return m ? N[m] ?? 0 : 0;
|
|
551
|
+
},
|
|
552
|
+
[y, N]
|
|
553
|
+
), g = l ? d(l) : 0, w = u.filter((n) => {
|
|
554
|
+
if (!n.period) return !1;
|
|
555
|
+
const m = n.period.includes("Y") || n.period.includes("year");
|
|
556
|
+
return T === "yearly" ? m : !m;
|
|
557
|
+
}).sort((n, m) => parseFloat(n.price) - parseFloat(m.price)), P = x(
|
|
558
|
+
(n) => n ? n.includes("Y") || n.includes("year") ? o.periodYear : n.includes("M") || n.includes("month") ? o.periodMonth : n.includes("W") || n.includes("week") ? o.periodWeek : "" : "",
|
|
559
|
+
[o]
|
|
560
|
+
), F = x(
|
|
561
|
+
(n) => {
|
|
562
|
+
const m = y[n];
|
|
563
|
+
if (!m) return;
|
|
564
|
+
const B = u.find(
|
|
565
|
+
(p) => p.identifier === n
|
|
566
|
+
);
|
|
567
|
+
if (!B) return;
|
|
568
|
+
const M = Object.entries(y).find(
|
|
569
|
+
([p, j]) => j === m && p.includes("monthly")
|
|
570
|
+
)?.[0];
|
|
571
|
+
if (!M) return;
|
|
572
|
+
const I = u.find(
|
|
573
|
+
(p) => p.identifier === M
|
|
574
|
+
);
|
|
575
|
+
if (!I) return;
|
|
576
|
+
const k = parseFloat(B.price), A = parseFloat(I.price);
|
|
577
|
+
if (A <= 0 || k <= 0) return;
|
|
578
|
+
const Y = A * 12, _ = (Y - k) / Y * 100;
|
|
579
|
+
return Math.round(_);
|
|
580
|
+
},
|
|
581
|
+
[u, y]
|
|
582
|
+
), L = [
|
|
583
|
+
{ value: "monthly", label: o.billingMonthly },
|
|
584
|
+
{ value: "yearly", label: o.billingYearly }
|
|
585
|
+
], z = x(
|
|
586
|
+
(n) => !a || !t ? !1 : d(n) === g && g > 0,
|
|
587
|
+
[a, t, d, g]
|
|
588
|
+
), C = x(
|
|
589
|
+
(n) => d(n) > g,
|
|
590
|
+
[d, g]
|
|
591
|
+
);
|
|
592
|
+
return /* @__PURE__ */ s("div", { className: S, children: [
|
|
593
|
+
/* @__PURE__ */ i("section", { className: "py-16 px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ s("div", { className: "max-w-4xl mx-auto text-center", children: [
|
|
594
|
+
/* @__PURE__ */ i("h1", { className: "text-4xl sm:text-5xl font-bold text-theme-text-primary mb-4", children: o.title }),
|
|
595
|
+
/* @__PURE__ */ i("p", { className: "text-lg text-theme-text-secondary", children: o.subtitle })
|
|
596
|
+
] }) }),
|
|
597
|
+
/* @__PURE__ */ i("section", { className: "pb-20 px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ s("div", { className: "max-w-6xl mx-auto", children: [
|
|
598
|
+
/* @__PURE__ */ i("div", { className: "flex justify-center mb-8", children: /* @__PURE__ */ i(
|
|
599
|
+
J,
|
|
600
|
+
{
|
|
601
|
+
options: L,
|
|
602
|
+
value: T,
|
|
603
|
+
onChange: R
|
|
604
|
+
}
|
|
605
|
+
) }),
|
|
606
|
+
/* @__PURE__ */ s(
|
|
607
|
+
"div",
|
|
608
|
+
{
|
|
609
|
+
style: {
|
|
610
|
+
display: "grid",
|
|
611
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 280px), 1fr))",
|
|
612
|
+
gap: "1.5rem"
|
|
613
|
+
},
|
|
614
|
+
children: [
|
|
615
|
+
/* @__PURE__ */ i(
|
|
616
|
+
W,
|
|
617
|
+
{
|
|
618
|
+
id: "free",
|
|
619
|
+
title: o.freeTierTitle,
|
|
620
|
+
price: o.freeTierPrice,
|
|
621
|
+
periodLabel: o.periodMonth,
|
|
622
|
+
features: o.freeTierFeatures,
|
|
623
|
+
isSelected: !1,
|
|
624
|
+
onSelect: () => {
|
|
625
|
+
},
|
|
626
|
+
topBadge: a && !t ? {
|
|
627
|
+
text: o.currentPlanBadge,
|
|
628
|
+
color: "green"
|
|
629
|
+
} : void 0,
|
|
630
|
+
ctaButton: (
|
|
631
|
+
// Not logged in: show "Try it for Free"
|
|
632
|
+
// Logged in on free plan: no CTA (current plan)
|
|
633
|
+
// Logged in with subscription: no CTA (can't downgrade here)
|
|
634
|
+
a ? void 0 : {
|
|
635
|
+
label: o.ctaTryFree,
|
|
636
|
+
onClick: c
|
|
637
|
+
}
|
|
638
|
+
),
|
|
639
|
+
hideSelectionIndicator: a
|
|
640
|
+
}
|
|
641
|
+
),
|
|
642
|
+
w.map((n) => {
|
|
643
|
+
const m = z(n.identifier), B = C(n.identifier);
|
|
644
|
+
let M;
|
|
645
|
+
a ? m ? M = void 0 : B && (M = {
|
|
646
|
+
label: o.ctaUpgrade,
|
|
647
|
+
onClick: () => h(n.identifier)
|
|
648
|
+
}) : M = {
|
|
649
|
+
label: o.ctaLogIn,
|
|
650
|
+
onClick: () => h(n.identifier)
|
|
651
|
+
};
|
|
652
|
+
let I;
|
|
653
|
+
return m ? I = {
|
|
654
|
+
text: o.currentPlanBadge,
|
|
655
|
+
color: "green"
|
|
656
|
+
} : n.identifier.includes("pro") && (I = {
|
|
657
|
+
text: o.mostPopularBadge,
|
|
658
|
+
color: "yellow"
|
|
659
|
+
}), /* @__PURE__ */ i(
|
|
660
|
+
W,
|
|
661
|
+
{
|
|
662
|
+
id: n.identifier,
|
|
663
|
+
title: n.title,
|
|
664
|
+
price: n.priceString,
|
|
665
|
+
periodLabel: P(n.period),
|
|
666
|
+
features: b.getProductFeatures(n.identifier),
|
|
667
|
+
isSelected: !1,
|
|
668
|
+
onSelect: () => {
|
|
669
|
+
},
|
|
670
|
+
isBestValue: n.identifier.includes("pro"),
|
|
671
|
+
topBadge: I,
|
|
672
|
+
discountBadge: n.period?.includes("Y") ? (() => {
|
|
673
|
+
const k = F(
|
|
674
|
+
n.identifier
|
|
675
|
+
);
|
|
676
|
+
return k && k > 0 ? {
|
|
677
|
+
text: b.formatSavePercent(k),
|
|
678
|
+
isBestValue: !0
|
|
679
|
+
} : void 0;
|
|
680
|
+
})() : void 0,
|
|
681
|
+
ctaButton: M,
|
|
682
|
+
hideSelectionIndicator: !M
|
|
683
|
+
},
|
|
684
|
+
n.identifier
|
|
685
|
+
);
|
|
686
|
+
})
|
|
687
|
+
]
|
|
688
|
+
}
|
|
689
|
+
)
|
|
690
|
+
] }) }),
|
|
691
|
+
f && f.length > 0 && /* @__PURE__ */ i("section", { className: "py-20 px-4 sm:px-6 lg:px-8 bg-theme-bg-secondary", children: /* @__PURE__ */ s("div", { className: "max-w-3xl mx-auto", children: [
|
|
692
|
+
/* @__PURE__ */ i("h2", { className: "text-3xl font-bold text-theme-text-primary text-center mb-12", children: o.faqTitle }),
|
|
693
|
+
/* @__PURE__ */ i("div", { className: "space-y-6", children: f.map((n, m) => /* @__PURE__ */ s(
|
|
694
|
+
"div",
|
|
695
|
+
{
|
|
696
|
+
className: "bg-theme-bg-primary p-6 rounded-xl border border-theme-border",
|
|
697
|
+
children: [
|
|
698
|
+
/* @__PURE__ */ i("h3", { className: "text-lg font-semibold text-theme-text-primary mb-2", children: n.question }),
|
|
699
|
+
/* @__PURE__ */ i("p", { className: "text-theme-text-secondary", children: n.answer })
|
|
700
|
+
]
|
|
701
|
+
},
|
|
702
|
+
m
|
|
703
|
+
)) })
|
|
704
|
+
] }) })
|
|
705
|
+
] });
|
|
706
|
+
}
|
|
533
707
|
export {
|
|
534
|
-
|
|
708
|
+
Te as EntityListPage,
|
|
709
|
+
Ie as EntityPricingPage,
|
|
535
710
|
Ce as EntitySubscriptionsPage,
|
|
536
|
-
|
|
537
|
-
|
|
711
|
+
Le as InvitationsPage,
|
|
712
|
+
Fe as MembersManagementPage
|
|
538
713
|
};
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(c,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("react/jsx-runtime"),require("react"),require("lucide-react"),require("@sudobility/entity-components"),require("@sudobility/entity_client"),require("@sudobility/subscription-components")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","lucide-react","@sudobility/entity-components","@sudobility/entity_client","@sudobility/subscription-components"],e):(c=typeof globalThis<"u"?globalThis:c||self,e(c.EntityPages={},c.jsxRuntime,c.React,c.LucideReact,c.SudobilityEntityComponents,c.SudobilityEntityClient,c.SudobilitySubscriptionComponents))})(this,(function(c,e,o,$,w,g,C){"use strict";function U({client:d,onSelectEntity:r}){const[i,a]=o.useState(!1),[m,v]=o.useState({displayName:"",description:""}),[f,b]=o.useState(null),{data:u=[],isLoading:s}=g.useEntities(d),h=g.useCreateEntity(d),S=u.filter(l=>l.entityType==="personal"),M=u.filter(l=>l.entityType==="organization"),k=async l=>{if(l.preventDefault(),b(null),!m.displayName.trim()){b("Display name is required");return}try{await h.mutateAsync({displayName:m.displayName.trim(),description:m.description.trim()||void 0}),a(!1),v({displayName:"",description:""})}catch(N){b(N.message||"Failed to create organization")}};return e.jsxs("div",{className:"space-y-8",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-foreground",children:"Workspaces"}),e.jsx("p",{className:"text-muted-foreground",children:"Manage your personal and organization workspaces"})]}),e.jsxs("button",{type:"button",onClick:()=>a(!0),className:"flex items-center gap-2 px-4 py-2 rounded-lg bg-primary text-primary-foreground font-medium hover:bg-primary/90 transition-colors",children:[e.jsx($.Plus,{className:"h-4 w-4"}),e.jsx("span",{children:"New Organization"})]})]}),i&&e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",children:e.jsxs("div",{className:"w-full max-w-md rounded-lg bg-background p-6 shadow-lg",children:[e.jsx("h2",{className:"text-lg font-semibold mb-4",children:"Create Organization"}),e.jsxs("form",{onSubmit:k,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1",children:"Display Name"}),e.jsx("input",{type:"text",value:m.displayName,onChange:l=>v(N=>({...N,displayName:l.target.value})),placeholder:"My Organization",className:"w-full px-3 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1",children:"Description (optional)"}),e.jsx("textarea",{value:m.description,onChange:l=>v(N=>({...N,description:l.target.value})),placeholder:"What is this organization for?",rows:3,className:"w-full px-3 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary resize-none"})]}),f&&e.jsx("p",{className:"text-sm text-destructive",children:f}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx("button",{type:"button",onClick:()=>{a(!1),v({displayName:"",description:""}),b(null)},className:"px-4 py-2 rounded-lg border hover:bg-muted transition-colors",children:"Cancel"}),e.jsx("button",{type:"submit",disabled:h.isPending,className:"px-4 py-2 rounded-lg bg-primary text-primary-foreground font-medium hover:bg-primary/90 transition-colors disabled:opacity-50",children:h.isPending?"Creating...":"Create"})]})]})]})}),S.length>0&&e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-semibold mb-3",children:"Personal Workspace"}),e.jsx(w.EntityList,{entities:S,onSelect:r,isLoading:s})]}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-semibold mb-3",children:"Organizations"}),M.length===0&&!s?e.jsxs("div",{className:"text-center py-8 text-muted-foreground border border-dashed rounded-lg",children:[e.jsx("p",{children:"No organizations yet"}),e.jsx("button",{type:"button",onClick:()=>a(!0),className:"mt-2 text-primary hover:underline",children:"Create your first organization"})]}):e.jsx(w.EntityList,{entities:M,onSelect:r,isLoading:s})]})]})}function H({client:d,entity:r,currentUserId:i}){const a=r.userRole==="admin",{data:m=[],isLoading:v}=g.useEntityMembers(d,r.entitySlug),f=g.useUpdateMemberRole(d),b=g.useRemoveMember(d),{data:u=[],isLoading:s}=g.useEntityInvitations(d,a?r.entitySlug:null),h=g.useCreateInvitation(d),S=g.useCancelInvitation(d),M=async(P,p)=>{try{await f.mutateAsync({entitySlug:r.entitySlug,memberId:P,role:p})}catch(T){console.error("Failed to update role:",T)}},k=async P=>{if(confirm("Are you sure you want to remove this member?"))try{await b.mutateAsync({entitySlug:r.entitySlug,memberId:P})}catch(p){console.error("Failed to remove member:",p)}},l=async P=>{await h.mutateAsync({entitySlug:r.entitySlug,request:P})},N=async P=>{try{await S.mutateAsync({entitySlug:r.entitySlug,invitationId:P})}catch(p){console.error("Failed to cancel invitation:",p)}};return r.entityType==="personal"?e.jsxs("div",{className:"text-center py-12 text-muted-foreground",children:[e.jsx("p",{children:"Personal workspaces cannot have additional members."}),e.jsx("p",{className:"mt-2",children:"Create an organization to collaborate with others."})]}):e.jsxs("div",{className:"space-y-8",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-foreground",children:"Members"}),e.jsxs("p",{className:"text-muted-foreground",children:["Manage members and invitations for ",r.displayName]})]}),a&&e.jsxs("div",{className:"rounded-lg border p-4",children:[e.jsx("h2",{className:"text-lg font-semibold mb-4",children:"Invite Members"}),e.jsx(w.InvitationForm,{onSubmit:l,isSubmitting:h.isPending})]}),a&&e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-semibold mb-3",children:"Pending Invitations"}),e.jsx(w.InvitationList,{invitations:u,mode:"admin",onCancel:N,isLoading:s,emptyMessage:"No pending invitations"})]}),e.jsxs("div",{children:[e.jsxs("h2",{className:"text-lg font-semibold mb-3",children:["Current Members (",m.length,")"]}),e.jsx(w.MemberList,{members:m,currentUserId:i,canManage:a,onRoleChange:M,onRemove:k,isLoading:v})]})]})}function V({client:d,onInvitationAccepted:r}){const{data:i=[],isLoading:a}=g.useMyInvitations(d),m=g.useAcceptInvitation(d),v=g.useDeclineInvitation(d),f=async s=>{try{await m.mutateAsync(s),r?.()}catch(h){console.error("Failed to accept invitation:",h)}},b=async s=>{try{await v.mutateAsync(s)}catch(h){console.error("Failed to decline invitation:",h)}},u=i.filter(s=>s.status==="pending").length;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-foreground",children:"Invitations"}),e.jsx("p",{className:"text-muted-foreground",children:u>0?`You have ${u} pending invitation${u>1?"s":""}`:"No pending invitations"})]}),e.jsx(w.InvitationList,{invitations:i,mode:"user",onAccept:f,onDecline:b,isLoading:a,emptyMessage:"You don't have any pending invitations"})]})}const F={ultra_yearly:"bandwidth_ultra",ultra_monthly:"bandwidth_ultra",pro_yearly:"bandwidth_pro",pro_monthly:"bandwidth_pro",dev_yearly:"bandwidth_dev",dev_monthly:"bandwidth_dev"};function G({subscription:d,rateLimitsConfig:r,labels:i,formatters:a,onPurchaseSuccess:m,onRestoreSuccess:v,onError:f,onWarning:b}){const{products:u,currentSubscription:s,isLoading:h,error:S,purchase:M,restore:k,clearError:l}=d,[N,P]=o.useState("monthly"),[p,T]=o.useState(null),[I,A]=o.useState(!1),[L,D]=o.useState(!1);o.useEffect(()=>{S&&(f?.(i.errorTitle,S),l())},[S,l,i.errorTitle,f]);const z=u.filter(t=>{if(!t.period)return!1;const n=t.period.includes("Y")||t.period.includes("year");return N==="yearly"?n:!n}).sort((t,n)=>parseFloat(t.price)-parseFloat(n.price)),K=t=>{P(t),T(null)},J=async()=>{if(p){A(!0),l();try{await M(p)&&(m?.(),T(null))}catch(t){f?.(i.errorTitle,t instanceof Error?t.message:i.purchaseError)}finally{A(!1)}}},Q=async()=>{D(!0),l();try{await k()?v?.():b?.(i.errorTitle,i.restoreNoPurchases)}catch(t){f?.(i.errorTitle,t instanceof Error?t.message:i.restoreError)}finally{D(!1)}},X=o.useCallback(t=>t?new Intl.DateTimeFormat(void 0,{year:"numeric",month:"long",day:"numeric"}).format(t):"",[]),Z=o.useCallback(t=>t?t.includes("Y")||t.includes("year")?i.periodYear:t.includes("M")||t.includes("month")?i.periodMonth:t.includes("W")||t.includes("week")?i.periodWeek:"":"",[i]),R=o.useCallback(t=>{if(!t)return;const n=parseInt(t.replace(/\D/g,"")||"1",10);return t.includes("W")?a.formatTrialWeeks(n):t.includes("M")?a.formatTrialMonths(n):a.formatTrialDays(n)},[a]),j=o.useCallback(t=>{if(!r?.tiers)return;const n=F[t];return n?r.tiers.find(y=>y.entitlement===n):r.tiers.find(y=>y.entitlement==="none")},[r]),x=o.useCallback(t=>t===null?i.unlimited:t.toLocaleString(),[i.unlimited]),q=o.useCallback(t=>{const n=j(t);if(!n)return[];const y=[];return n.limits.hourly!==null&&y.push(a.formatHourlyLimit(x(n.limits.hourly))),n.limits.daily!==null&&y.push(a.formatDailyLimit(x(n.limits.daily))),n.limits.monthly!==null&&y.push(a.formatMonthlyLimit(x(n.limits.monthly))),n.limits.hourly===null&&n.limits.daily===null&&n.limits.monthly===null&&y.push(i.unlimitedRequests),y},[j,x,a,i.unlimitedRequests]),ee=o.useCallback(t=>q(t),[q]),te=o.useCallback(()=>{const t=[...i.freeTierFeatures];if(r?.tiers){const n=r.tiers.find(y=>y.entitlement==="none");n&&(n.limits.hourly!==null&&t.push(a.formatHourlyLimit(x(n.limits.hourly))),n.limits.daily!==null&&t.push(a.formatDailyLimit(x(n.limits.daily))),n.limits.monthly!==null&&t.push(a.formatMonthlyLimit(x(n.limits.monthly))))}return t},[r,x,a,i.freeTierFeatures]),ie=o.useCallback(t=>{const n=F[t];if(!n)return;const y=u.find(E=>E.identifier===t);if(!y)return;const Y=Object.entries(F).find(([E,ae])=>ae===n&&E.includes("monthly"))?.[0];if(!Y)return;const W=u.find(E=>E.identifier===Y);if(!W)return;const O=parseFloat(y.price),B=parseFloat(W.price);if(B<=0||O<=0)return;const _=B*12,re=(_-O)/_*100;return Math.round(re)},[u]),ne=[{value:"monthly",label:i.billingMonthly},{value:"yearly",label:i.billingYearly}];return e.jsx(C.SubscriptionLayout,{title:i.title,error:S,currentStatusLabel:i.currentStatusLabel,currentStatus:{isActive:s?.isActive??!1,activeContent:s?.isActive?{title:i.statusActive,fields:[{label:i.labelPlan,value:s.productIdentifier||i.labelPremium},{label:i.labelExpires,value:X(s.expirationDate)},{label:i.labelWillRenew,value:s.willRenew?i.yes:i.no},...r?[{label:i.labelMonthlyUsage,value:`${r.currentUsage.monthly.toLocaleString()} / ${x(r.currentLimits.monthly)}`},{label:i.labelDailyUsage,value:`${r.currentUsage.daily.toLocaleString()} / ${x(r.currentLimits.daily)}`}]:[]]}:void 0,inactiveContent:s?.isActive?void 0:{title:i.statusInactive,message:i.statusInactiveMessage}},aboveProducts:!h&&u.length>0?e.jsx("div",{className:"flex justify-center mb-6",children:e.jsx(C.SegmentedControl,{options:ne,value:N,onChange:K})}):null,primaryAction:{label:I?i.buttonPurchasing:i.buttonSubscribe,onClick:J,disabled:!p||I||L,loading:I},secondaryAction:{label:L?i.buttonRestoring:i.buttonRestore,onClick:Q,disabled:I||L,loading:L},children:h?e.jsx("div",{className:"flex items-center justify-center py-12",children:e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"})}):u.length===0?e.jsx("div",{className:"text-center py-12 text-theme-text-secondary",children:i.noProducts}):z.length===0?e.jsx("div",{className:"text-center py-12 text-theme-text-secondary",children:i.noProductsForPeriod}):e.jsxs(e.Fragment,{children:[e.jsx(C.SubscriptionTile,{id:"free",title:i.freeTierTitle,price:i.freeTierPrice,periodLabel:i.periodMonth,features:te(),isSelected:!s?.isActive&&p===null,onSelect:()=>T(null),topBadge:s?.isActive?void 0:{text:i.currentPlanBadge,color:"green"},disabled:I||L,hideSelectionIndicator:!0},"free"),z.map(t=>e.jsx(C.SubscriptionTile,{id:t.identifier,title:t.title,price:t.priceString,periodLabel:Z(t.period),features:ee(t.identifier),isSelected:p===t.identifier,onSelect:()=>T(t.identifier),isBestValue:t.identifier.includes("pro"),discountBadge:t.period?.includes("Y")?(()=>{const n=ie(t.identifier);return n&&n>0?{text:a.formatSavePercent(n),isBestValue:!0}:void 0})():void 0,introPriceNote:t.freeTrialPeriod?R(t.freeTrialPeriod):t.introPrice?a.formatIntroNote(t.introPrice):void 0,disabled:I||L},t.identifier))]})})}c.EntityListPage=U,c.EntitySubscriptionsPage=G,c.InvitationsPage=V,c.MembersManagementPage=H,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
|
|
1
|
+
(function(m,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("react/jsx-runtime"),require("react"),require("lucide-react"),require("@sudobility/entity-components"),require("@sudobility/entity_client"),require("@sudobility/subscription-components")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","lucide-react","@sudobility/entity-components","@sudobility/entity_client","@sudobility/subscription-components"],e):(m=typeof globalThis<"u"?globalThis:m||self,e(m.EntityPages={},m.jsxRuntime,m.React,m.LucideReact,m.SudobilityEntityComponents,m.SudobilityEntityClient,m.SudobilitySubscriptionComponents))})(this,(function(m,e,l,J,z,S,B){"use strict";function Q({client:u,onSelectEntity:a}){const[i,o]=l.useState(!1),[s,x]=l.useState({displayName:"",description:""}),[f,N]=l.useState(null),{data:h=[],isLoading:c}=S.useEntities(u),g=S.useCreateEntity(u),w=h.filter(d=>d.entityType==="personal"),k=h.filter(d=>d.entityType==="organization"),D=async d=>{if(d.preventDefault(),N(null),!s.displayName.trim()){N("Display name is required");return}try{await g.mutateAsync({displayName:s.displayName.trim(),description:s.description.trim()||void 0}),o(!1),x({displayName:"",description:""})}catch(p){N(p.message||"Failed to create organization")}};return e.jsxs("div",{className:"space-y-8",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-foreground",children:"Workspaces"}),e.jsx("p",{className:"text-muted-foreground",children:"Manage your personal and organization workspaces"})]}),e.jsxs("button",{type:"button",onClick:()=>o(!0),className:"flex items-center gap-2 px-4 py-2 rounded-lg bg-primary text-primary-foreground font-medium hover:bg-primary/90 transition-colors",children:[e.jsx(J.Plus,{className:"h-4 w-4"}),e.jsx("span",{children:"New Organization"})]})]}),i&&e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",children:e.jsxs("div",{className:"w-full max-w-md rounded-lg bg-background p-6 shadow-lg",children:[e.jsx("h2",{className:"text-lg font-semibold mb-4",children:"Create Organization"}),e.jsxs("form",{onSubmit:D,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1",children:"Display Name"}),e.jsx("input",{type:"text",value:s.displayName,onChange:d=>x(p=>({...p,displayName:d.target.value})),placeholder:"My Organization",className:"w-full px-3 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium mb-1",children:"Description (optional)"}),e.jsx("textarea",{value:s.description,onChange:d=>x(p=>({...p,description:d.target.value})),placeholder:"What is this organization for?",rows:3,className:"w-full px-3 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary resize-none"})]}),f&&e.jsx("p",{className:"text-sm text-destructive",children:f}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx("button",{type:"button",onClick:()=>{o(!1),x({displayName:"",description:""}),N(null)},className:"px-4 py-2 rounded-lg border hover:bg-muted transition-colors",children:"Cancel"}),e.jsx("button",{type:"submit",disabled:g.isPending,className:"px-4 py-2 rounded-lg bg-primary text-primary-foreground font-medium hover:bg-primary/90 transition-colors disabled:opacity-50",children:g.isPending?"Creating...":"Create"})]})]})]})}),w.length>0&&e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-semibold mb-3",children:"Personal Workspace"}),e.jsx(z.EntityList,{entities:w,onSelect:a,isLoading:c})]}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-semibold mb-3",children:"Organizations"}),k.length===0&&!c?e.jsxs("div",{className:"text-center py-8 text-muted-foreground border border-dashed rounded-lg",children:[e.jsx("p",{children:"No organizations yet"}),e.jsx("button",{type:"button",onClick:()=>o(!0),className:"mt-2 text-primary hover:underline",children:"Create your first organization"})]}):e.jsx(z.EntityList,{entities:k,onSelect:a,isLoading:c})]})]})}function X({client:u,entity:a,currentUserId:i}){const o=a.userRole==="admin",{data:s=[],isLoading:x}=S.useEntityMembers(u,a.entitySlug),f=S.useUpdateMemberRole(u),N=S.useRemoveMember(u),{data:h=[],isLoading:c}=S.useEntityInvitations(u,o?a.entitySlug:null),g=S.useCreateInvitation(u),w=S.useCancelInvitation(u),k=async(T,P)=>{try{await f.mutateAsync({entitySlug:a.entitySlug,memberId:T,role:P})}catch(C){console.error("Failed to update role:",C)}},D=async T=>{if(confirm("Are you sure you want to remove this member?"))try{await N.mutateAsync({entitySlug:a.entitySlug,memberId:T})}catch(P){console.error("Failed to remove member:",P)}},d=async T=>{await g.mutateAsync({entitySlug:a.entitySlug,request:T})},p=async T=>{try{await w.mutateAsync({entitySlug:a.entitySlug,invitationId:T})}catch(P){console.error("Failed to cancel invitation:",P)}};return a.entityType==="personal"?e.jsxs("div",{className:"text-center py-12 text-muted-foreground",children:[e.jsx("p",{children:"Personal workspaces cannot have additional members."}),e.jsx("p",{className:"mt-2",children:"Create an organization to collaborate with others."})]}):e.jsxs("div",{className:"space-y-8",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-foreground",children:"Members"}),e.jsxs("p",{className:"text-muted-foreground",children:["Manage members and invitations for ",a.displayName]})]}),o&&e.jsxs("div",{className:"rounded-lg border p-4",children:[e.jsx("h2",{className:"text-lg font-semibold mb-4",children:"Invite Members"}),e.jsx(z.InvitationForm,{onSubmit:d,isSubmitting:g.isPending})]}),o&&e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-semibold mb-3",children:"Pending Invitations"}),e.jsx(z.InvitationList,{invitations:h,mode:"admin",onCancel:p,isLoading:c,emptyMessage:"No pending invitations"})]}),e.jsxs("div",{children:[e.jsxs("h2",{className:"text-lg font-semibold mb-3",children:["Current Members (",s.length,")"]}),e.jsx(z.MemberList,{members:s,currentUserId:i,canManage:o,onRoleChange:k,onRemove:D,isLoading:x})]})]})}function Z({client:u,onInvitationAccepted:a}){const{data:i=[],isLoading:o}=S.useMyInvitations(u),s=S.useAcceptInvitation(u),x=S.useDeclineInvitation(u),f=async c=>{try{await s.mutateAsync(c),a?.()}catch(g){console.error("Failed to accept invitation:",g)}},N=async c=>{try{await x.mutateAsync(c)}catch(g){console.error("Failed to decline invitation:",g)}},h=i.filter(c=>c.status==="pending").length;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-foreground",children:"Invitations"}),e.jsx("p",{className:"text-muted-foreground",children:h>0?`You have ${h} pending invitation${h>1?"s":""}`:"No pending invitations"})]}),e.jsx(z.InvitationList,{invitations:i,mode:"user",onAccept:f,onDecline:N,isLoading:o,emptyMessage:"You don't have any pending invitations"})]})}const _={ultra_yearly:"bandwidth_ultra",ultra_monthly:"bandwidth_ultra",pro_yearly:"bandwidth_pro",pro_monthly:"bandwidth_pro",dev_yearly:"bandwidth_dev",dev_monthly:"bandwidth_dev"};function R({subscription:u,rateLimitsConfig:a,labels:i,formatters:o,onPurchaseSuccess:s,onRestoreSuccess:x,onError:f,onWarning:N}){const{products:h,currentSubscription:c,isLoading:g,error:w,purchase:k,restore:D,clearError:d}=u,[p,T]=l.useState("monthly"),[P,C]=l.useState(null),[L,j]=l.useState(!1),[F,n]=l.useState(!1);l.useEffect(()=>{w&&(f?.(i.errorTitle,w),d())},[w,d,i.errorTitle,f]);const y=h.filter(t=>{if(!t.period)return!1;const r=t.period.includes("Y")||t.period.includes("year");return p==="yearly"?r:!r}).sort((t,r)=>parseFloat(t.price)-parseFloat(r.price)),A=t=>{T(t),C(null)},M=async()=>{if(P){j(!0),d();try{await k(P)&&(s?.(),C(null))}catch(t){f?.(i.errorTitle,t instanceof Error?t.message:i.purchaseError)}finally{j(!1)}}},E=async()=>{n(!0),d();try{await D()?x?.():N?.(i.errorTitle,i.restoreNoPurchases)}catch(t){f?.(i.errorTitle,t instanceof Error?t.message:i.restoreError)}finally{n(!1)}},I=l.useCallback(t=>t?new Intl.DateTimeFormat(void 0,{year:"numeric",month:"long",day:"numeric"}).format(t):"",[]),W=l.useCallback(t=>t?t.includes("Y")||t.includes("year")?i.periodYear:t.includes("M")||t.includes("month")?i.periodMonth:t.includes("W")||t.includes("week")?i.periodWeek:"":"",[i]),q=l.useCallback(t=>{if(!t)return;const r=parseInt(t.replace(/\D/g,"")||"1",10);return t.includes("W")?o.formatTrialWeeks(r):t.includes("M")?o.formatTrialMonths(r):o.formatTrialDays(r)},[o]),O=l.useCallback(t=>{if(!a?.tiers)return;const r=_[t];return r?a.tiers.find(b=>b.entitlement===r):a.tiers.find(b=>b.entitlement==="none")},[a]),v=l.useCallback(t=>t===null?i.unlimited:t.toLocaleString(),[i.unlimited]),U=l.useCallback(t=>{const r=O(t);if(!r)return[];const b=[];return r.limits.hourly!==null&&b.push(o.formatHourlyLimit(v(r.limits.hourly))),r.limits.daily!==null&&b.push(o.formatDailyLimit(v(r.limits.daily))),r.limits.monthly!==null&&b.push(o.formatMonthlyLimit(v(r.limits.monthly))),r.limits.hourly===null&&r.limits.daily===null&&r.limits.monthly===null&&b.push(i.unlimitedRequests),b},[O,v,o,i.unlimitedRequests]),te=l.useCallback(t=>U(t),[U]),ie=l.useCallback(()=>{const t=[...i.freeTierFeatures];if(a?.tiers){const r=a.tiers.find(b=>b.entitlement==="none");r&&(r.limits.hourly!==null&&t.push(o.formatHourlyLimit(v(r.limits.hourly))),r.limits.daily!==null&&t.push(o.formatDailyLimit(v(r.limits.daily))),r.limits.monthly!==null&&t.push(o.formatMonthlyLimit(v(r.limits.monthly))))}return t},[a,v,o,i.freeTierFeatures]),ne=l.useCallback(t=>{const r=_[t];if(!r)return;const b=h.find(Y=>Y.identifier===t);if(!b)return;const $=Object.entries(_).find(([Y,se])=>se===r&&Y.includes("monthly"))?.[0];if(!$)return;const V=h.find(Y=>Y.identifier===$);if(!V)return;const H=parseFloat(b.price),G=parseFloat(V.price);if(G<=0||H<=0)return;const K=G*12,ae=(K-H)/K*100;return Math.round(ae)},[h]),re=[{value:"monthly",label:i.billingMonthly},{value:"yearly",label:i.billingYearly}];return e.jsx(B.SubscriptionLayout,{title:i.title,error:w,currentStatusLabel:i.currentStatusLabel,currentStatus:{isActive:c?.isActive??!1,activeContent:c?.isActive?{title:i.statusActive,fields:[{label:i.labelPlan,value:c.productIdentifier||i.labelPremium},{label:i.labelExpires,value:I(c.expirationDate)},{label:i.labelWillRenew,value:c.willRenew?i.yes:i.no},...a?[{label:i.labelMonthlyUsage,value:`${a.currentUsage.monthly.toLocaleString()} / ${v(a.currentLimits.monthly)}`},{label:i.labelDailyUsage,value:`${a.currentUsage.daily.toLocaleString()} / ${v(a.currentLimits.daily)}`}]:[]]}:void 0,inactiveContent:c?.isActive?void 0:{title:i.statusInactive,message:i.statusInactiveMessage}},aboveProducts:!g&&h.length>0?e.jsx("div",{className:"flex justify-center mb-6",children:e.jsx(B.SegmentedControl,{options:re,value:p,onChange:A})}):null,primaryAction:{label:L?i.buttonPurchasing:i.buttonSubscribe,onClick:M,disabled:!P||L||F,loading:L},secondaryAction:{label:F?i.buttonRestoring:i.buttonRestore,onClick:E,disabled:L||F,loading:F},children:g?e.jsx("div",{className:"flex items-center justify-center py-12",children:e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"})}):h.length===0?e.jsx("div",{className:"text-center py-12 text-theme-text-secondary",children:i.noProducts}):y.length===0?e.jsx("div",{className:"text-center py-12 text-theme-text-secondary",children:i.noProductsForPeriod}):e.jsxs(e.Fragment,{children:[e.jsx(B.SubscriptionTile,{id:"free",title:i.freeTierTitle,price:i.freeTierPrice,periodLabel:i.periodMonth,features:ie(),isSelected:!c?.isActive&&P===null,onSelect:()=>C(null),topBadge:c?.isActive?void 0:{text:i.currentPlanBadge,color:"green"},disabled:L||F,hideSelectionIndicator:!0},"free"),y.map(t=>e.jsx(B.SubscriptionTile,{id:t.identifier,title:t.title,price:t.priceString,periodLabel:W(t.period),features:te(t.identifier),isSelected:P===t.identifier,onSelect:()=>C(t.identifier),isBestValue:t.identifier.includes("pro"),discountBadge:t.period?.includes("Y")?(()=>{const r=ne(t.identifier);return r&&r>0?{text:o.formatSavePercent(r),isBestValue:!0}:void 0})():void 0,introPriceNote:t.freeTrialPeriod?q(t.freeTrialPeriod):t.introPrice?o.formatIntroNote(t.introPrice):void 0,disabled:L||F},t.identifier))]})})}function ee({products:u,isAuthenticated:a,hasActiveSubscription:i,currentProductIdentifier:o,labels:s,formatters:x,entitlementMap:f,entitlementLevels:N,onPlanClick:h,onFreePlanClick:c,faqItems:g,className:w}){const[k,D]=l.useState("monthly"),d=l.useCallback(n=>{const y=f[n];return y?N[y]??0:0},[f,N]),p=o?d(o):0,T=u.filter(n=>{if(!n.period)return!1;const y=n.period.includes("Y")||n.period.includes("year");return k==="yearly"?y:!y}).sort((n,y)=>parseFloat(n.price)-parseFloat(y.price)),P=l.useCallback(n=>n?n.includes("Y")||n.includes("year")?s.periodYear:n.includes("M")||n.includes("month")?s.periodMonth:n.includes("W")||n.includes("week")?s.periodWeek:"":"",[s]),C=l.useCallback(n=>{const y=f[n];if(!y)return;const A=u.find(v=>v.identifier===n);if(!A)return;const M=Object.entries(f).find(([v,U])=>U===y&&v.includes("monthly"))?.[0];if(!M)return;const E=u.find(v=>v.identifier===M);if(!E)return;const I=parseFloat(A.price),W=parseFloat(E.price);if(W<=0||I<=0)return;const q=W*12,O=(q-I)/q*100;return Math.round(O)},[u,f]),L=[{value:"monthly",label:s.billingMonthly},{value:"yearly",label:s.billingYearly}],j=l.useCallback(n=>!a||!i?!1:d(n)===p&&p>0,[a,i,d,p]),F=l.useCallback(n=>d(n)>p,[d,p]);return e.jsxs("div",{className:w,children:[e.jsx("section",{className:"py-16 px-4 sm:px-6 lg:px-8",children:e.jsxs("div",{className:"max-w-4xl mx-auto text-center",children:[e.jsx("h1",{className:"text-4xl sm:text-5xl font-bold text-theme-text-primary mb-4",children:s.title}),e.jsx("p",{className:"text-lg text-theme-text-secondary",children:s.subtitle})]})}),e.jsx("section",{className:"pb-20 px-4 sm:px-6 lg:px-8",children:e.jsxs("div",{className:"max-w-6xl mx-auto",children:[e.jsx("div",{className:"flex justify-center mb-8",children:e.jsx(B.SegmentedControl,{options:L,value:k,onChange:D})}),e.jsxs("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fit, minmax(min(100%, 280px), 1fr))",gap:"1.5rem"},children:[e.jsx(B.SubscriptionTile,{id:"free",title:s.freeTierTitle,price:s.freeTierPrice,periodLabel:s.periodMonth,features:s.freeTierFeatures,isSelected:!1,onSelect:()=>{},topBadge:a&&!i?{text:s.currentPlanBadge,color:"green"}:void 0,ctaButton:a?void 0:{label:s.ctaTryFree,onClick:c},hideSelectionIndicator:a}),T.map(n=>{const y=j(n.identifier),A=F(n.identifier);let M;a?y?M=void 0:A&&(M={label:s.ctaUpgrade,onClick:()=>h(n.identifier)}):M={label:s.ctaLogIn,onClick:()=>h(n.identifier)};let E;return y?E={text:s.currentPlanBadge,color:"green"}:n.identifier.includes("pro")&&(E={text:s.mostPopularBadge,color:"yellow"}),e.jsx(B.SubscriptionTile,{id:n.identifier,title:n.title,price:n.priceString,periodLabel:P(n.period),features:x.getProductFeatures(n.identifier),isSelected:!1,onSelect:()=>{},isBestValue:n.identifier.includes("pro"),topBadge:E,discountBadge:n.period?.includes("Y")?(()=>{const I=C(n.identifier);return I&&I>0?{text:x.formatSavePercent(I),isBestValue:!0}:void 0})():void 0,ctaButton:M,hideSelectionIndicator:!M},n.identifier)})]})]})}),g&&g.length>0&&e.jsx("section",{className:"py-20 px-4 sm:px-6 lg:px-8 bg-theme-bg-secondary",children:e.jsxs("div",{className:"max-w-3xl mx-auto",children:[e.jsx("h2",{className:"text-3xl font-bold text-theme-text-primary text-center mb-12",children:s.faqTitle}),e.jsx("div",{className:"space-y-6",children:g.map((n,y)=>e.jsxs("div",{className:"bg-theme-bg-primary p-6 rounded-xl border border-theme-border",children:[e.jsx("h3",{className:"text-lg font-semibold text-theme-text-primary mb-2",children:n.question}),e.jsx("p",{className:"text-theme-text-secondary",children:n.answer})]},y))})]})})]})}m.EntityListPage=Q,m.EntityPricingPage=ee,m.EntitySubscriptionsPage=R,m.InvitationsPage=Z,m.MembersManagementPage=X,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}));
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Entity Pricing Page
|
|
3
|
+
* @description Public pricing page for displaying subscription options
|
|
4
|
+
*/
|
|
5
|
+
/** Product from subscription provider */
|
|
6
|
+
export interface PricingProduct {
|
|
7
|
+
identifier: string;
|
|
8
|
+
title: string;
|
|
9
|
+
price: string;
|
|
10
|
+
priceString: string;
|
|
11
|
+
period?: string;
|
|
12
|
+
}
|
|
13
|
+
/** FAQ item */
|
|
14
|
+
export interface FAQItem {
|
|
15
|
+
question: string;
|
|
16
|
+
answer: string;
|
|
17
|
+
}
|
|
18
|
+
/** All localized labels for the pricing page */
|
|
19
|
+
export interface PricingPageLabels {
|
|
20
|
+
title: string;
|
|
21
|
+
subtitle: string;
|
|
22
|
+
periodYear: string;
|
|
23
|
+
periodMonth: string;
|
|
24
|
+
periodWeek: string;
|
|
25
|
+
billingMonthly: string;
|
|
26
|
+
billingYearly: string;
|
|
27
|
+
freeTierTitle: string;
|
|
28
|
+
freeTierPrice: string;
|
|
29
|
+
freeTierFeatures: string[];
|
|
30
|
+
currentPlanBadge: string;
|
|
31
|
+
mostPopularBadge: string;
|
|
32
|
+
ctaLogIn: string;
|
|
33
|
+
ctaTryFree: string;
|
|
34
|
+
ctaUpgrade: string;
|
|
35
|
+
faqTitle: string;
|
|
36
|
+
}
|
|
37
|
+
/** Formatter functions for dynamic strings */
|
|
38
|
+
export interface PricingPageFormatters {
|
|
39
|
+
/** Format savings badge: "Save 20%" */
|
|
40
|
+
formatSavePercent: (percent: number) => string;
|
|
41
|
+
/** Get features for a product by its identifier */
|
|
42
|
+
getProductFeatures: (productId: string) => string[];
|
|
43
|
+
}
|
|
44
|
+
/** Package ID to entitlement mapping */
|
|
45
|
+
export interface EntitlementMap {
|
|
46
|
+
[packageId: string]: string;
|
|
47
|
+
}
|
|
48
|
+
/** Entitlement to level mapping for comparing plan tiers */
|
|
49
|
+
export interface EntitlementLevels {
|
|
50
|
+
[entitlement: string]: number;
|
|
51
|
+
}
|
|
52
|
+
export interface EntityPricingPageProps {
|
|
53
|
+
/** Available subscription products */
|
|
54
|
+
products: PricingProduct[];
|
|
55
|
+
/** Whether user is authenticated */
|
|
56
|
+
isAuthenticated: boolean;
|
|
57
|
+
/** Whether user has an active subscription */
|
|
58
|
+
hasActiveSubscription: boolean;
|
|
59
|
+
/** Current subscription product identifier (if any) */
|
|
60
|
+
currentProductIdentifier?: string;
|
|
61
|
+
/** Entity ID used for subscription (the selected entity's ID when logged in) */
|
|
62
|
+
subscriptionUserId?: string;
|
|
63
|
+
/** All localized labels */
|
|
64
|
+
labels: PricingPageLabels;
|
|
65
|
+
/** Formatter functions */
|
|
66
|
+
formatters: PricingPageFormatters;
|
|
67
|
+
/** Package ID to entitlement mapping for calculating savings */
|
|
68
|
+
entitlementMap: EntitlementMap;
|
|
69
|
+
/** Entitlement to level mapping for comparing tiers (higher = better) */
|
|
70
|
+
entitlementLevels: EntitlementLevels;
|
|
71
|
+
/** Called when user clicks on a plan */
|
|
72
|
+
onPlanClick: (planIdentifier: string) => void;
|
|
73
|
+
/** Called when user clicks on free plan */
|
|
74
|
+
onFreePlanClick: () => void;
|
|
75
|
+
/** Optional FAQ items */
|
|
76
|
+
faqItems?: FAQItem[];
|
|
77
|
+
/** Optional className for the container */
|
|
78
|
+
className?: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Public pricing page for displaying subscription options.
|
|
82
|
+
* - Non-authenticated: Free tile shows "Try it for Free", paid tiles show "Log in to Continue"
|
|
83
|
+
* - Authenticated on free: Free tile shows "Current Plan" badge (no CTA), paid tiles show "Upgrade"
|
|
84
|
+
* - Authenticated with subscription: Current plan shows badge (no CTA), higher tiers show "Upgrade"
|
|
85
|
+
*/
|
|
86
|
+
export declare function EntityPricingPage({ products, isAuthenticated, hasActiveSubscription, currentProductIdentifier, labels, formatters, entitlementMap, entitlementLevels, onPlanClick, onFreePlanClick, faqItems, className, }: EntityPricingPageProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -87,6 +87,8 @@ export interface EntitySubscriptionsPageProps {
|
|
|
87
87
|
subscription: SubscriptionContextValue;
|
|
88
88
|
/** Rate limit configuration */
|
|
89
89
|
rateLimitsConfig?: RateLimitsConfigData | null;
|
|
90
|
+
/** Entity ID used for subscription (the selected entity's ID when logged in) */
|
|
91
|
+
subscriptionUserId?: string;
|
|
90
92
|
/** All localized labels */
|
|
91
93
|
labels: SubscriptionPageLabels;
|
|
92
94
|
/** Formatter functions for dynamic strings */
|
package/dist/pages/index.d.ts
CHANGED
|
@@ -5,3 +5,4 @@ export { EntityListPage, type EntityListPageProps } from './EntityListPage';
|
|
|
5
5
|
export { MembersManagementPage, type MembersManagementPageProps, } from './MembersManagementPage';
|
|
6
6
|
export { InvitationsPage, type InvitationsPageProps } from './InvitationsPage';
|
|
7
7
|
export { EntitySubscriptionsPage, type EntitySubscriptionsPageProps, type SubscriptionProduct, type CurrentSubscription, type SubscriptionContextValue, type SubscriptionPageLabels, type SubscriptionPageFormatters, } from './EntitySubscriptionsPage';
|
|
8
|
+
export { EntityPricingPage, type EntityPricingPageProps, type PricingProduct, type FAQItem, type PricingPageLabels, type PricingPageFormatters, type EntitlementMap, type EntitlementLevels, } from './EntityPricingPage';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sudobility/entity_pages",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "Page containers for entity/organization management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.umd.js",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
44
44
|
"@tanstack/react-query": "^5.0.0",
|
|
45
45
|
"@sudobility/types": "^1.9.43",
|
|
46
|
-
"@sudobility/entity_client": "^0.0.
|
|
46
|
+
"@sudobility/entity_client": "^0.0.10",
|
|
47
47
|
"@sudobility/entity-components": "^1.0.4",
|
|
48
48
|
"@sudobility/subscription-components": "^1.0.13"
|
|
49
49
|
},
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@eslint/js": "^9.38.0",
|
|
57
57
|
"@sudobility/entity-components": "^1.0.4",
|
|
58
|
-
"@sudobility/entity_client": "^0.0.
|
|
58
|
+
"@sudobility/entity_client": "^0.0.10",
|
|
59
59
|
"@sudobility/subscription-components": "^1.0.13",
|
|
60
60
|
"@sudobility/types": "^1.9.43",
|
|
61
61
|
"@tanstack/react-query": "^5.0.0",
|