subos-frontend 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/LIBRARY_USAGE.md +162 -0
  2. package/README.md +396 -0
  3. package/dist/index.js +2289 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.mjs +2220 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/dist/style.css +1684 -0
  8. package/dist/types/App.d.ts +2 -0
  9. package/dist/types/App.d.ts.map +1 -0
  10. package/dist/types/api/client.d.ts +49 -0
  11. package/dist/types/api/client.d.ts.map +1 -0
  12. package/dist/types/api/config.d.ts +16 -0
  13. package/dist/types/api/config.d.ts.map +1 -0
  14. package/dist/types/components/LogoInline.d.ts +8 -0
  15. package/dist/types/components/LogoInline.d.ts.map +1 -0
  16. package/dist/types/components/common/Layout.d.ts +7 -0
  17. package/dist/types/components/common/Layout.d.ts.map +1 -0
  18. package/dist/types/components/email/EmailEntry.d.ts +10 -0
  19. package/dist/types/components/email/EmailEntry.d.ts.map +1 -0
  20. package/dist/types/components/email/index.d.ts +3 -0
  21. package/dist/types/components/email/index.d.ts.map +1 -0
  22. package/dist/types/components/icons/CheckIcon.d.ts +6 -0
  23. package/dist/types/components/icons/CheckIcon.d.ts.map +1 -0
  24. package/dist/types/components/icons/CommonIcons.d.ts +21 -0
  25. package/dist/types/components/icons/CommonIcons.d.ts.map +1 -0
  26. package/dist/types/components/pagination/Pagination.d.ts +12 -0
  27. package/dist/types/components/pagination/Pagination.d.ts.map +1 -0
  28. package/dist/types/components/pagination/index.d.ts +3 -0
  29. package/dist/types/components/pagination/index.d.ts.map +1 -0
  30. package/dist/types/components/payments/ChangeCardButton.d.ts +10 -0
  31. package/dist/types/components/payments/ChangeCardButton.d.ts.map +1 -0
  32. package/dist/types/components/payments/PaymentCancelView.d.ts +8 -0
  33. package/dist/types/components/payments/PaymentCancelView.d.ts.map +1 -0
  34. package/dist/types/components/payments/PaymentSuccessView.d.ts +8 -0
  35. package/dist/types/components/payments/PaymentSuccessView.d.ts.map +1 -0
  36. package/dist/types/components/payments/index.d.ts +5 -0
  37. package/dist/types/components/payments/index.d.ts.map +1 -0
  38. package/dist/types/components/plans/BillingCycleToggle.d.ts +7 -0
  39. package/dist/types/components/plans/BillingCycleToggle.d.ts.map +1 -0
  40. package/dist/types/components/plans/PlanCard.d.ts +11 -0
  41. package/dist/types/components/plans/PlanCard.d.ts.map +1 -0
  42. package/dist/types/components/plans/PlanSelector.d.ts +19 -0
  43. package/dist/types/components/plans/PlanSelector.d.ts.map +1 -0
  44. package/dist/types/components/plans/PlansGrid.d.ts +13 -0
  45. package/dist/types/components/plans/PlansGrid.d.ts.map +1 -0
  46. package/dist/types/components/plans/TierFilterDropdown.d.ts +12 -0
  47. package/dist/types/components/plans/TierFilterDropdown.d.ts.map +1 -0
  48. package/dist/types/components/plans/index.d.ts +11 -0
  49. package/dist/types/components/plans/index.d.ts.map +1 -0
  50. package/dist/types/components/subscription/SubscriptionDetails.d.ts +11 -0
  51. package/dist/types/components/subscription/SubscriptionDetails.d.ts.map +1 -0
  52. package/dist/types/components/subscription/index.d.ts +3 -0
  53. package/dist/types/components/subscription/index.d.ts.map +1 -0
  54. package/dist/types/components/transaction/TransactionList.d.ts +11 -0
  55. package/dist/types/components/transaction/TransactionList.d.ts.map +1 -0
  56. package/dist/types/components/transaction/TransactionModal.d.ts +9 -0
  57. package/dist/types/components/transaction/TransactionModal.d.ts.map +1 -0
  58. package/dist/types/components/transaction/index.d.ts +5 -0
  59. package/dist/types/components/transaction/index.d.ts.map +1 -0
  60. package/dist/types/components/upgrade/UpgradeSummary.d.ts +8 -0
  61. package/dist/types/components/upgrade/UpgradeSummary.d.ts.map +1 -0
  62. package/dist/types/components/upgrade/index.d.ts +3 -0
  63. package/dist/types/components/upgrade/index.d.ts.map +1 -0
  64. package/dist/types/config/envConfig.d.ts +36 -0
  65. package/dist/types/config/envConfig.d.ts.map +1 -0
  66. package/dist/types/hooks/index.d.ts +15 -0
  67. package/dist/types/hooks/index.d.ts.map +1 -0
  68. package/dist/types/hooks/payments/usePaymentParams.d.ts +8 -0
  69. package/dist/types/hooks/payments/usePaymentParams.d.ts.map +1 -0
  70. package/dist/types/hooks/payments/useProcessPaymentCancel.d.ts +8 -0
  71. package/dist/types/hooks/payments/useProcessPaymentCancel.d.ts.map +1 -0
  72. package/dist/types/hooks/payments/useProcessPaymentSuccess.d.ts +8 -0
  73. package/dist/types/hooks/payments/useProcessPaymentSuccess.d.ts.map +1 -0
  74. package/dist/types/hooks/useCancelSubscription.d.ts +16 -0
  75. package/dist/types/hooks/useCancelSubscription.d.ts.map +1 -0
  76. package/dist/types/hooks/useCustomerPortal.d.ts +12 -0
  77. package/dist/types/hooks/useCustomerPortal.d.ts.map +1 -0
  78. package/dist/types/hooks/useEmailManagement.d.ts +13 -0
  79. package/dist/types/hooks/useEmailManagement.d.ts.map +1 -0
  80. package/dist/types/hooks/usePagination.d.ts +20 -0
  81. package/dist/types/hooks/usePagination.d.ts.map +1 -0
  82. package/dist/types/hooks/usePlans.d.ts +22 -0
  83. package/dist/types/hooks/usePlans.d.ts.map +1 -0
  84. package/dist/types/hooks/useSubscription.d.ts +10 -0
  85. package/dist/types/hooks/useSubscription.d.ts.map +1 -0
  86. package/dist/types/hooks/useTransactions.d.ts +26 -0
  87. package/dist/types/hooks/useTransactions.d.ts.map +1 -0
  88. package/dist/types/index.d.ts +20 -0
  89. package/dist/types/index.d.ts.map +1 -0
  90. package/dist/types/pages/DashboardPage.d.ts +3 -0
  91. package/dist/types/pages/DashboardPage.d.ts.map +1 -0
  92. package/dist/types/pages/PaymentCancelPage.d.ts +4 -0
  93. package/dist/types/pages/PaymentCancelPage.d.ts.map +1 -0
  94. package/dist/types/pages/PaymentSuccessPage.d.ts +4 -0
  95. package/dist/types/pages/PaymentSuccessPage.d.ts.map +1 -0
  96. package/dist/types/types/index.d.ts +117 -0
  97. package/dist/types/types/index.d.ts.map +1 -0
  98. package/dist/types/utils/index.d.ts +3 -0
  99. package/dist/types/utils/index.d.ts.map +1 -0
  100. package/dist/types/utils/planUtils.d.ts +47 -0
  101. package/dist/types/utils/planUtils.d.ts.map +1 -0
  102. package/package.json +74 -0
package/dist/index.js ADDED
@@ -0,0 +1,2289 @@
1
+ 'use strict';
2
+
3
+ var React3 = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var reactRouterDom = require('react-router-dom');
6
+
7
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var React3__default = /*#__PURE__*/_interopDefault(React3);
11
+
12
+ // src/config/envConfig.ts
13
+ function getEnvVar(key, fallback) {
14
+ var _a;
15
+ try {
16
+ if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)) }) !== "undefined" && undefined) {
17
+ const v = undefined[key];
18
+ if (typeof fallback === "boolean") {
19
+ if (typeof v === "boolean") return v;
20
+ if (typeof v === "string") return ["true", "1", "yes"].includes(v.toLowerCase());
21
+ return fallback;
22
+ }
23
+ if (typeof fallback === "string") {
24
+ if (typeof v === "string") return v;
25
+ if (typeof v === "boolean") return v ? "true" : "false";
26
+ return fallback;
27
+ }
28
+ return v;
29
+ }
30
+ const nodeEnv = typeof globalThis !== "undefined" && ((_a = globalThis.process) == null ? void 0 : _a.env);
31
+ if (nodeEnv) {
32
+ const v = nodeEnv[key];
33
+ if (typeof fallback === "boolean") {
34
+ if (typeof v === "string") return ["true", "1", "yes"].includes(v.toLowerCase());
35
+ return fallback;
36
+ }
37
+ if (typeof fallback === "string") {
38
+ return v ?? fallback;
39
+ }
40
+ return v;
41
+ }
42
+ return fallback;
43
+ } catch {
44
+ return fallback;
45
+ }
46
+ }
47
+ var envDefaults = {
48
+ // API Configuration - These MUST be configured by the consuming app
49
+ API_ENDPOINT: getEnvVar("VITE_API_ENDPOINT", ""),
50
+ NEXT_PUBLIC_API_END_POINT: getEnvVar("VITE_NEXT_PUBLIC_API_END_POINT", ""),
51
+ // Project configuration for backend header - This MUST be configured by the consuming app
52
+ PROJECT_ID: getEnvVar("VITE_PROJECT_ID", ""),
53
+ // Third-party keys - This MUST be configured by the consuming app
54
+ STRIPE_PUBLISHABLE_KEY: getEnvVar("VITE_STRIPE_PUBLISHABLE_KEY", ""),
55
+ // App Configuration
56
+ APP_NAME: getEnvVar("VITE_APP_NAME", "SubOS Frontend"),
57
+ APP_VERSION: getEnvVar("VITE_APP_VERSION", "1.0.0"),
58
+ APP_ENVIRONMENT: getEnvVar("VITE_APP_ENVIRONMENT", "development"),
59
+ // Development Configuration
60
+ DEBUG: getEnvVar("VITE_DEBUG", false),
61
+ // Mode
62
+ MODE: getEnvVar("MODE", "development"),
63
+ DEV: getEnvVar("DEV", false),
64
+ PROD: getEnvVar("PROD", false)
65
+ };
66
+ var runtimeOverrides = {};
67
+ function configureSubOS(input = {}) {
68
+ if (input.apiEndpoint !== void 0) runtimeOverrides.API_ENDPOINT = input.apiEndpoint;
69
+ if (input.projectId !== void 0) runtimeOverrides.PROJECT_ID = input.projectId;
70
+ if (input.stripePublishableKey !== void 0) runtimeOverrides.STRIPE_PUBLISHABLE_KEY = input.stripePublishableKey;
71
+ if (input.appName !== void 0) runtimeOverrides.APP_NAME = input.appName;
72
+ if (input.appVersion !== void 0) runtimeOverrides.APP_VERSION = input.appVersion;
73
+ if (input.appEnvironment !== void 0) runtimeOverrides.APP_ENVIRONMENT = input.appEnvironment;
74
+ if (input.debug !== void 0) runtimeOverrides.DEBUG = input.debug;
75
+ }
76
+ function validateSubOSConfig() {
77
+ const missingFields = [];
78
+ if (!getApiBaseUrl()) missingFields.push("apiEndpoint");
79
+ if (!getProjectId()) missingFields.push("projectId");
80
+ if (!getStripePublishableKey()) missingFields.push("stripePublishableKey");
81
+ return {
82
+ isValid: missingFields.length === 0,
83
+ missingFields
84
+ };
85
+ }
86
+ function ensureSubOSConfig() {
87
+ const validation = validateSubOSConfig();
88
+ if (!validation.isValid) {
89
+ throw new Error(
90
+ `SubOS configuration is incomplete. Missing required fields: ${validation.missingFields.join(", ")}. Please call configureSubOS() with the required configuration before using SubOS components.`
91
+ );
92
+ }
93
+ }
94
+ var getApiBaseUrl = () => runtimeOverrides.API_ENDPOINT ?? envDefaults.API_ENDPOINT;
95
+ var getProjectId = () => runtimeOverrides.PROJECT_ID ?? envDefaults.PROJECT_ID;
96
+ var getStripePublishableKey = () => runtimeOverrides.STRIPE_PUBLISHABLE_KEY ?? envDefaults.STRIPE_PUBLISHABLE_KEY;
97
+
98
+ // src/api/config.ts
99
+ var getHeaders = () => {
100
+ return {
101
+ "Content-Type": "application/json",
102
+ "auth": "auth",
103
+ // Adding auth header with value 'auth' for all API requests
104
+ "projectId": getProjectId()
105
+ };
106
+ };
107
+ var ENDPOINTS = {
108
+ PLANS: "/plans",
109
+ PAYMENTS: "/api/payments",
110
+ CHECKOUT: "/checkout",
111
+ SUBSCRIPTION: "/subscription",
112
+ CUSTOMER: "/customer",
113
+ TRANSACTIONS: "/transaction"
114
+ };
115
+
116
+ // src/api/client.ts
117
+ async function apiRequest(endpoint, method = "GET", data) {
118
+ try {
119
+ const url = `${getApiBaseUrl()}${endpoint}`;
120
+ const options = {
121
+ method,
122
+ headers: getHeaders(),
123
+ credentials: "include"
124
+ };
125
+ if (data) {
126
+ options.body = JSON.stringify(data);
127
+ }
128
+ const response = await fetch(url, options);
129
+ const result = await response.json();
130
+ if (!response.ok) {
131
+ return { success: false, error: result.message || "An error occurred" };
132
+ }
133
+ return { success: true, data: result };
134
+ } catch (error) {
135
+ console.error("API request failed:", error);
136
+ return {
137
+ success: false,
138
+ error: error instanceof Error ? error.message : "Unknown error occurred"
139
+ };
140
+ }
141
+ }
142
+ var plansApi = {
143
+ getPlans: async () => {
144
+ return apiRequest(`${ENDPOINTS.PLANS}`);
145
+ },
146
+ getPlanByCode: (code, externalId, queryParams) => {
147
+ const params = new URLSearchParams({ planCode: code, externalId });
148
+ if (queryParams == null ? void 0 : queryParams.paymentMethodId) params.append("paymentMethodId", queryParams.paymentMethodId);
149
+ if (queryParams == null ? void 0 : queryParams.couponCode) params.append("couponCode", queryParams.couponCode);
150
+ return apiRequest(`${ENDPOINTS.PLANS}?${params.toString()}`);
151
+ },
152
+ // Create unified checkout session and get hosted checkout URL
153
+ createPaymentSession: async (planCode, options) => {
154
+ const customerEmail = (options == null ? void 0 : options.customerEmail) || localStorage.getItem("userEmail") || void 0;
155
+ const currency = (options == null ? void 0 : options.currency) || "USD";
156
+ const amount = options == null ? void 0 : options.amount;
157
+ const payload = {
158
+ planCode,
159
+ currency,
160
+ returnUrl: `${window.location.origin}/payment-success`,
161
+ cancelUrl: `${window.location.origin}/payment-cancel`
162
+ };
163
+ if (customerEmail) payload.customerEmail = customerEmail;
164
+ if (options == null ? void 0 : options.couponCode) payload.couponCode = options.couponCode;
165
+ if (typeof amount === "number" && amount > 0) payload.amount = amount;
166
+ const resp = await apiRequest(
167
+ `${ENDPOINTS.PAYMENTS}/checkout`,
168
+ "POST",
169
+ payload
170
+ );
171
+ if (resp.success && resp.data && typeof resp.data === "object" && "data" in resp.data) {
172
+ return { success: true, data: resp.data.data };
173
+ }
174
+ return resp;
175
+ }
176
+ };
177
+ var checkoutApi = {
178
+ getCheckoutDetails: (planCode, queryParams) => {
179
+ const params = new URLSearchParams({ planCode });
180
+ if (queryParams == null ? void 0 : queryParams.externalId) params.append("externalId", queryParams.externalId);
181
+ if (queryParams == null ? void 0 : queryParams.paymentMethodId) params.append("paymentMethodId", queryParams.paymentMethodId);
182
+ if (queryParams == null ? void 0 : queryParams.couponCode) params.append("couponCode", queryParams.couponCode);
183
+ return apiRequest(`${ENDPOINTS.CHECKOUT}?${params.toString()}`);
184
+ }
185
+ };
186
+ var subscriptionApi = {
187
+ getActiveSubscription: async (externalId) => {
188
+ return apiRequest(`${ENDPOINTS.SUBSCRIPTION}/${externalId}`);
189
+ },
190
+ cancelSubscription: async (externalId, options) => {
191
+ let endpoint = `${ENDPOINTS.SUBSCRIPTION}/${externalId}`;
192
+ if (options) {
193
+ const params = new URLSearchParams();
194
+ if (options.cancellationMode) params.append("cancellationMode", options.cancellationMode);
195
+ if (options.cancellationReason) params.append("cancellationReason", options.cancellationReason);
196
+ if (params.toString()) {
197
+ endpoint += `?${params.toString()}`;
198
+ }
199
+ }
200
+ return apiRequest(endpoint, "DELETE");
201
+ }
202
+ };
203
+ var customerApi = {
204
+ getCustomer: (externalId) => apiRequest(`${ENDPOINTS.CUSTOMER}/${externalId}`)
205
+ };
206
+ var transactionApi = {
207
+ getTransactions: (externalId, filters) => {
208
+ let endpoint = `${ENDPOINTS.TRANSACTIONS}/${externalId}/history`;
209
+ if (filters) {
210
+ const params = new URLSearchParams();
211
+ if (filters.startDate) params.append("startDate", filters.startDate);
212
+ if (filters.endDate) params.append("endDate", filters.endDate);
213
+ if (filters.status) params.append("status", filters.status);
214
+ if (filters.page) params.append("page", filters.page.toString());
215
+ if (filters.limit) params.append("limit", filters.limit.toString());
216
+ if (params.toString()) {
217
+ endpoint += `?${params.toString()}`;
218
+ }
219
+ }
220
+ return apiRequest(endpoint);
221
+ },
222
+ getInvoice: (transactionId) => apiRequest(`${ENDPOINTS.TRANSACTIONS}/${transactionId}/invoice`)
223
+ };
224
+ var useEmailManagement = (onEmailValidated) => {
225
+ const [email, setEmail] = React3.useState(localStorage.getItem("userEmail") || "");
226
+ const [emailError, setEmailError] = React3.useState(null);
227
+ const [isEmailScreen, setIsEmailScreen] = React3.useState(!localStorage.getItem("userEmail"));
228
+ const validateEmail = (emailValue) => {
229
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
230
+ return emailRegex.test(emailValue);
231
+ };
232
+ React3.useEffect(() => {
233
+ if (email) {
234
+ if (!validateEmail(email)) {
235
+ setEmailError("Please enter a valid email address");
236
+ } else {
237
+ onEmailValidated == null ? void 0 : onEmailValidated(email);
238
+ }
239
+ }
240
+ }, []);
241
+ const handleEmailSubmit = () => {
242
+ if (!validateEmail(email)) {
243
+ setEmailError("Please enter a valid email address");
244
+ return;
245
+ }
246
+ localStorage.setItem("userEmail", email);
247
+ setIsEmailScreen(false);
248
+ onEmailValidated == null ? void 0 : onEmailValidated(email);
249
+ };
250
+ const handleChangeEmail = () => {
251
+ localStorage.removeItem("userEmail");
252
+ setEmail("");
253
+ setIsEmailScreen(true);
254
+ setEmailError(null);
255
+ };
256
+ return {
257
+ email,
258
+ setEmail,
259
+ emailError,
260
+ setEmailError,
261
+ isEmailScreen,
262
+ setIsEmailScreen,
263
+ handleEmailSubmit,
264
+ handleChangeEmail,
265
+ validateEmail
266
+ };
267
+ };
268
+ var useSubscription = () => {
269
+ const [subscription, setSubscription] = React3.useState(null);
270
+ const [loading, setLoading] = React3.useState(false);
271
+ const [error, setError] = React3.useState(null);
272
+ const fetchSubscription = React3.useCallback(async (email) => {
273
+ setLoading(true);
274
+ setError(null);
275
+ try {
276
+ const response = await subscriptionApi.getActiveSubscription(email);
277
+ if (response.success && response.data) {
278
+ setSubscription(response.data);
279
+ } else {
280
+ setError(response.error || "Failed to load subscription information");
281
+ }
282
+ } catch (err) {
283
+ console.error("Error fetching subscription:", err);
284
+ setError("Failed to load subscription information. Please try again later.");
285
+ } finally {
286
+ setLoading(false);
287
+ }
288
+ }, []);
289
+ const clearSubscription = React3.useCallback(() => {
290
+ setSubscription(null);
291
+ setError(null);
292
+ }, []);
293
+ return {
294
+ subscription,
295
+ loading,
296
+ error,
297
+ fetchSubscription,
298
+ clearSubscription
299
+ };
300
+ };
301
+
302
+ // src/utils/planUtils.ts
303
+ var getPlanFeatures = (plan) => {
304
+ const planName = plan.name.toLowerCase();
305
+ if (planName.includes("starter")) {
306
+ return [
307
+ "Import/Export User",
308
+ "Active Jobs",
309
+ "Text Change Module",
310
+ "Employers Auto Approval",
311
+ "Create Page in Manage Portal",
312
+ "Multi Select Master with action button"
313
+ ];
314
+ } else if (planName.includes("growth")) {
315
+ return [
316
+ "Resume Builder",
317
+ "Custom Email Body",
318
+ "View Candidate Resume",
319
+ "Advanced Analytics",
320
+ "Priority Support",
321
+ "Custom Branding"
322
+ ];
323
+ } else if (planName.includes("scale")) {
324
+ return [
325
+ "AI-Powered Matching",
326
+ "Advanced Reporting",
327
+ "API Access",
328
+ "White-label Solution",
329
+ "Dedicated Account Manager",
330
+ "Custom Integrations"
331
+ ];
332
+ }
333
+ const features = [];
334
+ if (plan.charges && plan.charges.length > 0) {
335
+ plan.charges.forEach((charge) => {
336
+ var _a;
337
+ if ((_a = charge.billableMetric) == null ? void 0 : _a.name) {
338
+ features.push(charge.billableMetric.name);
339
+ }
340
+ });
341
+ }
342
+ return features.length > 0 ? features : ["Core features included"];
343
+ };
344
+ var getCandidateUnits = (plan) => {
345
+ var _a;
346
+ if (plan.charges && plan.charges.length > 0) {
347
+ const candidateCharge = plan.charges.find(
348
+ (charge) => charge.billableMetric && charge.billableMetric.code === "CANDIDATES"
349
+ );
350
+ const units = (_a = candidateCharge == null ? void 0 : candidateCharge.properties) == null ? void 0 : _a.units;
351
+ if (typeof units === "number" && Number.isFinite(units)) {
352
+ return units;
353
+ }
354
+ }
355
+ return 0;
356
+ };
357
+ var getUniqueCandidateUnits = (plans) => {
358
+ const unitsSet = /* @__PURE__ */ new Set();
359
+ plans.forEach((plan) => {
360
+ plan.charges.forEach((charge) => {
361
+ var _a, _b;
362
+ if (((_a = charge.billableMetric) == null ? void 0 : _a.code) === "CANDIDATES") {
363
+ const units = (_b = charge.properties) == null ? void 0 : _b.units;
364
+ if (typeof units === "number" && Number.isFinite(units)) {
365
+ unitsSet.add(units);
366
+ }
367
+ }
368
+ });
369
+ });
370
+ return Array.from(unitsSet).sort((a, b) => a - b);
371
+ };
372
+ var getDropdownOptions = (plans) => {
373
+ const options = [];
374
+ const uniqueUnits = getUniqueCandidateUnits(plans);
375
+ uniqueUnits.forEach((units) => {
376
+ options.push({
377
+ value: units.toString(),
378
+ label: `Up to ${units.toLocaleString()} Candidates`,
379
+ candidates: units
380
+ });
381
+ });
382
+ return options;
383
+ };
384
+ var getCurrentSelectionText = (tierFilter, plans) => {
385
+ const options = getDropdownOptions(plans);
386
+ const currentOption = options.find((option) => option.value === tierFilter);
387
+ if (!currentOption) {
388
+ const units = parseInt(tierFilter);
389
+ if (!isNaN(units)) {
390
+ return `Up to ${units.toLocaleString()} Candidates`;
391
+ }
392
+ return options.length > 0 ? options[0].label : "";
393
+ }
394
+ return currentOption.label;
395
+ };
396
+ var filterPlansByBillingCycle = (plans, billingCycle) => {
397
+ return plans.filter((plan) => {
398
+ const planInterval = plan.interval.toLowerCase();
399
+ if (billingCycle === "monthly") {
400
+ return planInterval === "month" || planInterval === "monthly";
401
+ } else {
402
+ return planInterval === "year" || planInterval === "yearly";
403
+ }
404
+ });
405
+ };
406
+ var filterPlansByTier = (plans, tierFilter) => {
407
+ if (tierFilter === "all") {
408
+ return plans;
409
+ }
410
+ const targetUnits = parseInt(tierFilter);
411
+ return plans.filter((plan) => {
412
+ var _a, _b;
413
+ const planNameLc = ((_b = (_a = plan.name) == null ? void 0 : _a.toLowerCase) == null ? void 0 : _b.call(_a)) || "";
414
+ if (planNameLc.includes("starter")) return true;
415
+ const planCandidateUnits = getCandidateUnits(plan);
416
+ return planCandidateUnits === targetUnits;
417
+ });
418
+ };
419
+ var isPlanPopular = (plan) => {
420
+ const planName = plan.name.toLowerCase();
421
+ return planName.includes("growth");
422
+ };
423
+ var getPlanDescription = (plan) => {
424
+ const planName = plan.name.toLowerCase();
425
+ if (planName.includes("starter") || planName.includes("basic")) {
426
+ return "Ideal for solopreneurs looking to start their niche job board journey.";
427
+ } else if (planName.includes("growth") || planName.includes("pro")) {
428
+ return "Ideal for creators launching their job board with powerful features and built-in scalability.";
429
+ } else {
430
+ return "Perfect for creators ready to run a full-scale, smart hiring engine with AI and advanced capabilities.";
431
+ }
432
+ };
433
+ var formatDate = (dateString) => {
434
+ const date = new Date(dateString);
435
+ return new Intl.DateTimeFormat("en-US", {
436
+ year: "numeric",
437
+ month: "short",
438
+ day: "numeric"
439
+ }).format(date);
440
+ };
441
+
442
+ // src/hooks/usePlans.ts
443
+ var usePlans = () => {
444
+ const [plans, setPlans] = React3.useState([]);
445
+ const [filteredPlans, setFilteredPlans] = React3.useState([]);
446
+ const [selectedPlan, setSelectedPlan] = React3.useState(null);
447
+ const [tierFilter, setTierFilter] = React3.useState("all");
448
+ const [billingCycle, setBillingCycle] = React3.useState("monthly");
449
+ const [loading, setLoading] = React3.useState(false);
450
+ const [error, setError] = React3.useState(null);
451
+ const fetchPlans = React3.useCallback(async () => {
452
+ setLoading(true);
453
+ setError(null);
454
+ try {
455
+ const response = await plansApi.getPlans();
456
+ if (response.success && response.data) {
457
+ const data = response.data;
458
+ setPlans(data);
459
+ setFilteredPlans(data);
460
+ } else {
461
+ setError(response.error || "Failed to load plan information");
462
+ }
463
+ } catch (err) {
464
+ console.error("Error fetching plans:", err);
465
+ setError("Failed to load plan information. Please try again later.");
466
+ } finally {
467
+ setLoading(false);
468
+ }
469
+ }, []);
470
+ React3.useEffect(() => {
471
+ if (plans.length > 0 && tierFilter === "all") {
472
+ const uniqueUnits = getUniqueCandidateUnits(plans);
473
+ if (uniqueUnits.length > 0) {
474
+ setTierFilter(uniqueUnits[0].toString());
475
+ }
476
+ }
477
+ }, [plans, tierFilter]);
478
+ React3.useEffect(() => {
479
+ let filtered = [...plans];
480
+ filtered = filterPlansByBillingCycle(filtered, billingCycle);
481
+ filtered = filterPlansByTier(filtered, tierFilter);
482
+ setFilteredPlans(filtered);
483
+ }, [plans, tierFilter, billingCycle]);
484
+ const handlePlanSelect = React3.useCallback((plan) => {
485
+ setSelectedPlan(plan);
486
+ }, []);
487
+ const handleUpgrade = React3.useCallback(async (email) => {
488
+ var _a;
489
+ if (!selectedPlan) return;
490
+ try {
491
+ const response = await plansApi.createPaymentSession(selectedPlan.code, {
492
+ customerEmail: email || void 0
493
+ });
494
+ if (response.success && ((_a = response.data) == null ? void 0 : _a.checkoutUrl)) {
495
+ window.location.href = response.data.checkoutUrl;
496
+ } else {
497
+ console.error("Failed to create payment session:", response.error);
498
+ alert("Failed to initiate payment. Please try again.");
499
+ }
500
+ } catch (error2) {
501
+ console.error("Error creating payment session:", error2);
502
+ alert("An error occurred. Please try again.");
503
+ }
504
+ }, [selectedPlan]);
505
+ const clearPlans = React3.useCallback(() => {
506
+ setPlans([]);
507
+ setFilteredPlans([]);
508
+ setSelectedPlan(null);
509
+ setError(null);
510
+ setTierFilter("all");
511
+ }, []);
512
+ const dropdownOptions = getDropdownOptions(plans);
513
+ const currentSelectionText = getCurrentSelectionText(tierFilter, plans);
514
+ return {
515
+ // Data
516
+ plans,
517
+ filteredPlans,
518
+ selectedPlan,
519
+ // Filters
520
+ tierFilter,
521
+ billingCycle,
522
+ // Loading and error states
523
+ loading,
524
+ error,
525
+ // Actions
526
+ fetchPlans,
527
+ setSelectedPlan,
528
+ setTierFilter,
529
+ setBillingCycle,
530
+ clearPlans,
531
+ // Computed values
532
+ dropdownOptions,
533
+ currentSelectionText,
534
+ // Plan operations
535
+ handlePlanSelect,
536
+ handleUpgrade
537
+ };
538
+ };
539
+ var DEFAULT_FILTERS = {
540
+ page: 1,
541
+ limit: 10
542
+ };
543
+ var applyFrontendFilters = (transactions, filters) => {
544
+ console.log("applyFrontendFilters input:", { transactions: transactions.length, filters });
545
+ let filtered = [...transactions];
546
+ if (filters.status && filters.status.trim() !== "") {
547
+ console.log("Applying status filter:", filters.status);
548
+ filtered = filtered.filter(
549
+ (transaction) => {
550
+ var _a;
551
+ return transaction.transactionStatus.toLowerCase() === ((_a = filters.status) == null ? void 0 : _a.toLowerCase());
552
+ }
553
+ );
554
+ console.log("After status filter:", filtered.length);
555
+ }
556
+ if (filters.startDate && filters.startDate.trim() !== "") {
557
+ console.log("Applying start date filter:", filters.startDate);
558
+ const startDate = new Date(filters.startDate);
559
+ filtered = filtered.filter((transaction) => {
560
+ const transactionDate = new Date(transaction.transactionDate || transaction.membershipDate);
561
+ return transactionDate >= startDate;
562
+ });
563
+ console.log("After start date filter:", filtered.length);
564
+ }
565
+ if (filters.endDate && filters.endDate.trim() !== "") {
566
+ console.log("Applying end date filter:", filters.endDate);
567
+ const endDate = new Date(filters.endDate);
568
+ filtered = filtered.filter((transaction) => {
569
+ const transactionDate = new Date(transaction.transactionDate || transaction.membershipDate);
570
+ return transactionDate <= endDate;
571
+ });
572
+ console.log("After end date filter:", filtered.length);
573
+ }
574
+ console.log("applyFrontendFilters output:", filtered.length);
575
+ return filtered;
576
+ };
577
+ var applyFrontendPagination = (transactions, filters) => {
578
+ const currentPage = filters.page || 1;
579
+ const limit = filters.limit || 10;
580
+ const startIndex = (currentPage - 1) * limit;
581
+ const endIndex = startIndex + limit;
582
+ const paginatedTransactions = transactions.slice(startIndex, endIndex);
583
+ console.log("applyFrontendPagination:", {
584
+ totalTransactions: transactions.length,
585
+ currentPage,
586
+ limit,
587
+ startIndex,
588
+ endIndex,
589
+ paginatedCount: paginatedTransactions.length
590
+ });
591
+ return {
592
+ data: paginatedTransactions,
593
+ meta: {
594
+ currentPage,
595
+ totalPages: Math.ceil(transactions.length / limit),
596
+ totalItems: transactions.length,
597
+ itemsPerPage: limit,
598
+ hasNextPage: endIndex < transactions.length,
599
+ hasPreviousPage: currentPage > 1
600
+ }
601
+ };
602
+ };
603
+ var useTransactions = ({
604
+ externalId,
605
+ initialFilters = {},
606
+ autoFetch = false
607
+ }) => {
608
+ const [transactions, setTransactions] = React3.useState([]);
609
+ const [allTransactions, setAllTransactions] = React3.useState([]);
610
+ const [loading, setLoading] = React3.useState(false);
611
+ const [error, setError] = React3.useState(null);
612
+ const [filters, setFilters] = React3.useState({
613
+ ...DEFAULT_FILTERS,
614
+ ...initialFilters
615
+ });
616
+ const [meta, setMeta] = React3.useState(null);
617
+ const [isBackendPaginated, setIsBackendPaginated] = React3.useState(false);
618
+ const hasAutoFetchedRef = React3.useRef(false);
619
+ const fetchTransactions = React3.useCallback(async () => {
620
+ if (!externalId) return;
621
+ setLoading(true);
622
+ setError(null);
623
+ try {
624
+ const response = await transactionApi.getTransactions(
625
+ externalId,
626
+ filters
627
+ );
628
+ if (response.success && response.data) {
629
+ console.log("API Response successful, data type:", Array.isArray(response.data) ? "Array" : "Object");
630
+ console.log("Raw API data:", response.data);
631
+ if (Array.isArray(response.data)) {
632
+ console.log("Processing non-paginated response with", response.data.length, "transactions");
633
+ setIsBackendPaginated(false);
634
+ setAllTransactions(response.data);
635
+ console.log("TEMP: Skipping filters, showing all data directly");
636
+ setTransactions(response.data);
637
+ setMeta({
638
+ currentPage: 1,
639
+ totalPages: 1,
640
+ totalItems: response.data.length,
641
+ itemsPerPage: response.data.length,
642
+ hasNextPage: false,
643
+ hasPreviousPage: false
644
+ });
645
+ } else {
646
+ setIsBackendPaginated(true);
647
+ const paginatedData = response.data;
648
+ setTransactions(paginatedData.data);
649
+ setMeta(paginatedData.meta);
650
+ setAllTransactions([]);
651
+ }
652
+ } else {
653
+ setError(response.error || "Failed to fetch transactions");
654
+ setTransactions([]);
655
+ setAllTransactions([]);
656
+ setMeta(null);
657
+ }
658
+ } catch (err) {
659
+ setError(err instanceof Error ? err.message : "An unexpected error occurred");
660
+ setTransactions([]);
661
+ setAllTransactions([]);
662
+ setMeta(null);
663
+ } finally {
664
+ setLoading(false);
665
+ }
666
+ }, [externalId, filters]);
667
+ const updateFilters = React3.useCallback((newFilters) => {
668
+ setFilters((prev) => ({
669
+ ...prev,
670
+ ...newFilters,
671
+ // Reset to page 1 when filters change (except when explicitly setting page)
672
+ page: newFilters.page !== void 0 ? newFilters.page : 1
673
+ }));
674
+ }, []);
675
+ React3.useEffect(() => {
676
+ if (!isBackendPaginated && allTransactions.length > 0) {
677
+ const filteredTransactions = applyFrontendFilters(allTransactions, filters);
678
+ const paginatedResult = applyFrontendPagination(filteredTransactions, filters);
679
+ setTransactions(paginatedResult.data);
680
+ setMeta(paginatedResult.meta);
681
+ }
682
+ }, [filters, allTransactions, isBackendPaginated]);
683
+ const clearFilters = React3.useCallback(() => {
684
+ setFilters(DEFAULT_FILTERS);
685
+ }, []);
686
+ const refetch = React3.useCallback(async () => {
687
+ await fetchTransactions();
688
+ }, [fetchTransactions]);
689
+ React3.useEffect(() => {
690
+ if (autoFetch && externalId && !hasAutoFetchedRef.current) {
691
+ hasAutoFetchedRef.current = true;
692
+ fetchTransactions();
693
+ }
694
+ }, [autoFetch, externalId]);
695
+ React3.useEffect(() => {
696
+ if (!autoFetch) return;
697
+ const hasNonPaginationFilters = filters.startDate !== void 0 || filters.endDate !== void 0 || filters.status !== void 0;
698
+ const shouldFetch = isBackendPaginated || allTransactions.length === 0 && hasNonPaginationFilters;
699
+ if (shouldFetch) {
700
+ const timeoutId = setTimeout(() => {
701
+ fetchTransactions();
702
+ }, 300);
703
+ return () => clearTimeout(timeoutId);
704
+ }
705
+ }, [filters, fetchTransactions, autoFetch, isBackendPaginated, allTransactions.length]);
706
+ return {
707
+ transactions,
708
+ loading,
709
+ error,
710
+ filters,
711
+ meta,
712
+ fetchTransactions,
713
+ updateFilters,
714
+ clearFilters,
715
+ refetch
716
+ };
717
+ };
718
+ var usePagination = ({
719
+ initialPage = 1,
720
+ initialLimit = 10
721
+ } = {}) => {
722
+ const [currentPage, setCurrentPage] = React3.useState(initialPage);
723
+ const [limit, setLimitState] = React3.useState(initialLimit);
724
+ const [meta, setMeta] = React3.useState(null);
725
+ const goToPage = React3.useCallback((page) => {
726
+ if (meta) {
727
+ const validPage = Math.max(1, Math.min(page, meta.totalPages));
728
+ setCurrentPage(validPage);
729
+ } else {
730
+ setCurrentPage(Math.max(1, page));
731
+ }
732
+ }, [meta]);
733
+ const goToNextPage = React3.useCallback(() => {
734
+ if (meta && meta.hasNextPage) {
735
+ setCurrentPage((prev) => prev + 1);
736
+ }
737
+ }, [meta]);
738
+ const goToPreviousPage = React3.useCallback(() => {
739
+ if (meta && meta.hasPreviousPage) {
740
+ setCurrentPage((prev) => prev - 1);
741
+ }
742
+ }, [meta]);
743
+ const goToFirstPage = React3.useCallback(() => {
744
+ setCurrentPage(1);
745
+ }, []);
746
+ const goToLastPage = React3.useCallback(() => {
747
+ if (meta) {
748
+ setCurrentPage(meta.totalPages);
749
+ }
750
+ }, [meta]);
751
+ const setLimit = React3.useCallback((newLimit) => {
752
+ setLimitState(newLimit);
753
+ setCurrentPage(1);
754
+ }, []);
755
+ const reset = React3.useCallback(() => {
756
+ setCurrentPage(initialPage);
757
+ setLimitState(initialLimit);
758
+ setMeta(null);
759
+ }, [initialPage, initialLimit]);
760
+ return {
761
+ currentPage,
762
+ limit,
763
+ meta,
764
+ goToPage,
765
+ goToNextPage,
766
+ goToPreviousPage,
767
+ goToFirstPage,
768
+ goToLastPage,
769
+ setLimit,
770
+ setMeta,
771
+ reset
772
+ };
773
+ };
774
+ var useCancelSubscription = ({
775
+ onSuccess,
776
+ onError
777
+ } = {}) => {
778
+ const [loading, setLoading] = React3.useState(false);
779
+ const [error, setError] = React3.useState(null);
780
+ const cancelSubscription = React3.useCallback(async (externalId, options) => {
781
+ if (!externalId) {
782
+ const errorMsg = "External ID is required";
783
+ setError(errorMsg);
784
+ onError == null ? void 0 : onError(errorMsg);
785
+ return false;
786
+ }
787
+ setLoading(true);
788
+ setError(null);
789
+ try {
790
+ const response = await subscriptionApi.cancelSubscription(externalId, options);
791
+ if (response.success) {
792
+ onSuccess == null ? void 0 : onSuccess();
793
+ return true;
794
+ } else {
795
+ const errorMsg = response.error || "Failed to cancel subscription";
796
+ setError(errorMsg);
797
+ onError == null ? void 0 : onError(errorMsg);
798
+ return false;
799
+ }
800
+ } catch (err) {
801
+ const errorMsg = err instanceof Error ? err.message : "An unexpected error occurred";
802
+ setError(errorMsg);
803
+ onError == null ? void 0 : onError(errorMsg);
804
+ return false;
805
+ } finally {
806
+ setLoading(false);
807
+ }
808
+ }, [onSuccess, onError]);
809
+ const reset = React3.useCallback(() => {
810
+ setLoading(false);
811
+ setError(null);
812
+ }, []);
813
+ return {
814
+ loading,
815
+ error,
816
+ cancelSubscription,
817
+ reset
818
+ };
819
+ };
820
+ async function apiRequest2(endpoint, method = "GET", data) {
821
+ try {
822
+ const url = `${getApiBaseUrl()}${endpoint}`;
823
+ const options = {
824
+ method,
825
+ headers: getHeaders(),
826
+ credentials: "include"
827
+ };
828
+ if (data) {
829
+ options.body = JSON.stringify(data);
830
+ }
831
+ const response = await fetch(url, options);
832
+ const result = await response.json();
833
+ if (!response.ok) {
834
+ return { success: false, error: result.message || "An error occurred" };
835
+ }
836
+ return { success: true, data: result };
837
+ } catch (error) {
838
+ console.error("API request failed:", error);
839
+ return {
840
+ success: false,
841
+ error: error instanceof Error ? error.message : "Unknown error occurred"
842
+ };
843
+ }
844
+ }
845
+ var useCustomerPortal = ({
846
+ onSuccess,
847
+ onError
848
+ } = {}) => {
849
+ const [loading, setLoading] = React3.useState(false);
850
+ const [error, setError] = React3.useState(null);
851
+ const openCustomerPortal = React3.useCallback(async (externalId) => {
852
+ var _a;
853
+ if (!externalId) {
854
+ const errorMsg = "External ID is required";
855
+ setError(errorMsg);
856
+ onError == null ? void 0 : onError(errorMsg);
857
+ return false;
858
+ }
859
+ setLoading(true);
860
+ setError(null);
861
+ try {
862
+ const returnUrl = `${window.location.origin}/dashboard`;
863
+ const response = await apiRequest2(
864
+ `${ENDPOINTS.CUSTOMER}/${externalId}/portal`,
865
+ "POST",
866
+ { returnUrl }
867
+ );
868
+ const portalResponse = response.data;
869
+ const portalUrl = ((_a = portalResponse == null ? void 0 : portalResponse.data) == null ? void 0 : _a.url) ?? (portalResponse == null ? void 0 : portalResponse.url);
870
+ if (response.success && portalUrl) {
871
+ onSuccess == null ? void 0 : onSuccess(portalUrl);
872
+ window.location.href = portalUrl;
873
+ return true;
874
+ } else {
875
+ const errorMsg = response.error || (portalResponse == null ? void 0 : portalResponse.error) || (portalResponse == null ? void 0 : portalResponse.message) || "Failed to open customer portal";
876
+ setError(errorMsg);
877
+ onError == null ? void 0 : onError(errorMsg);
878
+ return false;
879
+ }
880
+ } catch (err) {
881
+ const errorMsg = err instanceof Error ? err.message : "An unexpected error occurred";
882
+ setError(errorMsg);
883
+ onError == null ? void 0 : onError(errorMsg);
884
+ return false;
885
+ } finally {
886
+ setLoading(false);
887
+ }
888
+ }, [onSuccess, onError]);
889
+ const reset = React3.useCallback(() => {
890
+ setLoading(false);
891
+ setError(null);
892
+ }, []);
893
+ return {
894
+ loading,
895
+ error,
896
+ openCustomerPortal,
897
+ reset
898
+ };
899
+ };
900
+ var BillingCycleToggle = ({
901
+ billingCycle,
902
+ onBillingCycleChange
903
+ }) => {
904
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex bg-gray-100 rounded-lg p-1", children: [
905
+ /* @__PURE__ */ jsxRuntime.jsx(
906
+ "button",
907
+ {
908
+ onClick: () => onBillingCycleChange("monthly"),
909
+ className: `px-4 py-2 rounded-md text-sm font-medium transition-colors ${billingCycle === "monthly" ? "bg-white text-gray-900 shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
910
+ children: "Monthly"
911
+ }
912
+ ),
913
+ /* @__PURE__ */ jsxRuntime.jsx(
914
+ "button",
915
+ {
916
+ onClick: () => onBillingCycleChange("yearly"),
917
+ className: `px-4 py-2 rounded-md text-sm font-medium transition-colors ${billingCycle === "yearly" ? "bg-green-600 text-white shadow-sm" : "text-gray-600 hover:text-gray-900"}`,
918
+ children: "Yearly"
919
+ }
920
+ )
921
+ ] });
922
+ };
923
+ var TierFilterDropdown = ({
924
+ isOpen,
925
+ onToggle,
926
+ currentSelectionText,
927
+ options,
928
+ selectedValue,
929
+ onSelect
930
+ }) => {
931
+ const dropdownRef = React3.useRef(null);
932
+ React3.useEffect(() => {
933
+ const handleClickOutside = (event) => {
934
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
935
+ if (isOpen) {
936
+ onToggle();
937
+ }
938
+ }
939
+ };
940
+ document.addEventListener("mousedown", handleClickOutside);
941
+ return () => {
942
+ document.removeEventListener("mousedown", handleClickOutside);
943
+ };
944
+ }, [isOpen, onToggle]);
945
+ const handleOptionSelect = (value) => {
946
+ onSelect(value);
947
+ onToggle();
948
+ };
949
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: dropdownRef, children: [
950
+ /* @__PURE__ */ jsxRuntime.jsxs(
951
+ "button",
952
+ {
953
+ onClick: onToggle,
954
+ className: "w-full max-w-xs px-4 py-3 border border-gray-300 rounded-lg bg-white text-left focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500 flex items-center justify-between hover:border-gray-400 transition-colors",
955
+ children: [
956
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-700", children: currentSelectionText }),
957
+ /* @__PURE__ */ jsxRuntime.jsx(
958
+ "svg",
959
+ {
960
+ className: `w-5 h-5 text-gray-400 transition-transform ${isOpen ? "rotate-180" : ""}`,
961
+ fill: "none",
962
+ stroke: "currentColor",
963
+ viewBox: "0 0 24 24",
964
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
965
+ }
966
+ )
967
+ ]
968
+ }
969
+ ),
970
+ isOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-full left-0 w-full max-w-xs mt-1 bg-white border border-gray-200 rounded-lg shadow-lg z-50", children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
971
+ "button",
972
+ {
973
+ onClick: () => handleOptionSelect(option.value),
974
+ className: `w-full px-4 py-3 text-left hover:bg-gray-50 transition-colors border-b border-gray-100 last:border-b-0 first:rounded-t-lg last:rounded-b-lg ${selectedValue === option.value ? "bg-green-50 text-green-700" : "text-gray-700"}`,
975
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: option.label }) })
976
+ },
977
+ option.value
978
+ )) })
979
+ ] });
980
+ };
981
+ var CheckIcon = ({ className = "w-5 h-5" }) => {
982
+ return /* @__PURE__ */ jsxRuntime.jsx(
983
+ "svg",
984
+ {
985
+ className,
986
+ fill: "currentColor",
987
+ viewBox: "0 0 20 20",
988
+ xmlns: "http://www.w3.org/2000/svg",
989
+ children: /* @__PURE__ */ jsxRuntime.jsx(
990
+ "path",
991
+ {
992
+ fillRule: "evenodd",
993
+ d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",
994
+ clipRule: "evenodd"
995
+ }
996
+ )
997
+ }
998
+ );
999
+ };
1000
+ var PlanCard = ({
1001
+ plan,
1002
+ isSelected,
1003
+ billingCycle,
1004
+ onSelect,
1005
+ isActive = false
1006
+ }) => {
1007
+ const features = getPlanFeatures(plan);
1008
+ const description = getPlanDescription(plan);
1009
+ const isPopular = isPlanPopular(plan);
1010
+ const isFree = Number(plan.fixedCost) === 0;
1011
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1012
+ "div",
1013
+ {
1014
+ onClick: isFree || isActive ? void 0 : () => onSelect(plan),
1015
+ className: `relative border rounded-lg p-6 transition-all ${!isFree && !isActive ? "cursor-pointer" : "cursor-default"} ${!isFree && isSelected && !isActive ? "border-green-500 bg-green-50" : "border-gray-200"} ${!isFree && !isActive ? "hover:border-gray-300" : ""} ${isPopular ? "border-green-500" : ""}`,
1016
+ children: [
1017
+ isPopular && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-3 left-1/2 transform -translate-x-1/2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-green-500 text-white px-3 py-1 rounded-full text-xs font-medium", children: "Most Popular" }) }),
1018
+ !isFree && isSelected && !isActive && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-4 right-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-green-500 text-white rounded-full p-1", children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "w-4 h-4" }) }) }),
1019
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
1020
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-xl font-bold text-gray-900 mb-2", children: plan.name }),
1021
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600 text-sm mb-4", children: description }),
1022
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4", children: isFree ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-3xl font-bold text-gray-900", children: "Free" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1023
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-3xl font-bold text-gray-900", children: [
1024
+ "$",
1025
+ plan.fixedCost
1026
+ ] }),
1027
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-600 ml-1", children: [
1028
+ "per ",
1029
+ billingCycle === "yearly" ? "year" : "month"
1030
+ ] })
1031
+ ] }) })
1032
+ ] }),
1033
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-2 mb-6", children: features.map((feature, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center text-sm", children: [
1034
+ /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "w-4 h-4 text-green-500 mr-2 flex-shrink-0" }),
1035
+ feature
1036
+ ] }, index)) }),
1037
+ !isFree && (isActive ? /* @__PURE__ */ jsxRuntime.jsx(
1038
+ "button",
1039
+ {
1040
+ className: "w-full bg-gray-100 border border-gray-200 text-gray-500 py-2 px-4 rounded-md font-medium cursor-default",
1041
+ disabled: true,
1042
+ children: "Active"
1043
+ }
1044
+ ) : isSelected ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: "w-full bg-green-600 text-white py-2 px-4 rounded-md font-medium", children: "Selected" }) : /* @__PURE__ */ jsxRuntime.jsx("button", { className: "w-full bg-white border border-gray-300 text-gray-700 py-2 px-4 rounded-md font-medium hover:bg-gray-50", children: "Select" }))
1045
+ ]
1046
+ }
1047
+ );
1048
+ };
1049
+ var SearchIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) });
1050
+ var FilterIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" }) });
1051
+ var TrendingUpIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" }) });
1052
+ var LoadingSpinner = ({ className = "w-8 h-8" }) => /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: `${className} animate-spin`, fill: "none", viewBox: "0 0 24 24", children: [
1053
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
1054
+ /* @__PURE__ */ jsxRuntime.jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
1055
+ ] });
1056
+ var CheckCircleIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z", clipRule: "evenodd" }) });
1057
+ var AddIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 4v16m8-8H4" }) });
1058
+ var CreditCardIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" }) });
1059
+ var DeleteIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) });
1060
+ var DownloadIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) });
1061
+ var DashboardIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" }) });
1062
+ var EmailIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" }) });
1063
+ var ReceiptIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12h6m-6 4h6m2 5l-5-5-4 4-3-3m6-6V4a2 2 0 00-2-2H5a2 2 0 00-2 2v16l3-3 3 3 3-3 3 3z" }) });
1064
+ var StarBorderIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" }) });
1065
+ var UpgradeIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 10l7-7m0 0l7 7m-7-7v18" }) });
1066
+ var CancelIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) });
1067
+ var AddCardIcon = ({ className = "w-5 h-5" }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { className, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 6v6m0 0v6m0-6h6m-6 0H6m12-3h3a3 3 0 013 3v8a3 3 0 01-3 3H6a3 3 0 01-3-3v-8a3 3 0 013-3h3" }) });
1068
+ var PlansGrid = ({
1069
+ plans,
1070
+ selectedPlan,
1071
+ billingCycle,
1072
+ loading,
1073
+ error,
1074
+ onPlanSelect,
1075
+ activePlanCode
1076
+ }) => {
1077
+ if (loading) {
1078
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner, { className: "h-10 w-10 text-primary animate-spin" }) });
1079
+ }
1080
+ if (error) {
1081
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 bg-red-50 border border-red-200 text-red-700 rounded-md", children: error });
1082
+ }
1083
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6", children: plans.map((plan) => /* @__PURE__ */ jsxRuntime.jsx(
1084
+ PlanCard,
1085
+ {
1086
+ plan,
1087
+ isSelected: (selectedPlan == null ? void 0 : selectedPlan.id) === plan.id,
1088
+ billingCycle,
1089
+ onSelect: onPlanSelect,
1090
+ isActive: activePlanCode ? plan.code === activePlanCode : false
1091
+ },
1092
+ plan.id
1093
+ )) });
1094
+ };
1095
+ var PlanSelector = ({
1096
+ plans,
1097
+ selectedPlan,
1098
+ tierFilter,
1099
+ billingCycle,
1100
+ loading,
1101
+ error,
1102
+ dropdownOptions,
1103
+ currentSelectionText,
1104
+ onPlanSelect,
1105
+ onTierFilterChange,
1106
+ onBillingCycleChange,
1107
+ activePlanCode
1108
+ }) => {
1109
+ const [isDropdownOpen, setIsDropdownOpen] = React3.useState(false);
1110
+ const handleDropdownToggle = () => {
1111
+ setIsDropdownOpen(!isDropdownOpen);
1112
+ };
1113
+ const handleTierSelect = (value) => {
1114
+ onTierFilterChange(value);
1115
+ setIsDropdownOpen(false);
1116
+ };
1117
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
1118
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold mb-2", children: "Upgrade your plan" }),
1119
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 justify-between flex-wrap mb-6", children: [
1120
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600 mb-0 flex-1 min-w-[260px]", children: "Enhance your experience with exclusive access - unlock more features and possibilities!" }),
1121
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
1122
+ /* @__PURE__ */ jsxRuntime.jsx(
1123
+ TierFilterDropdown,
1124
+ {
1125
+ isOpen: isDropdownOpen,
1126
+ onToggle: handleDropdownToggle,
1127
+ currentSelectionText,
1128
+ options: dropdownOptions,
1129
+ selectedValue: tierFilter,
1130
+ onSelect: handleTierSelect
1131
+ }
1132
+ ),
1133
+ /* @__PURE__ */ jsxRuntime.jsx(
1134
+ BillingCycleToggle,
1135
+ {
1136
+ billingCycle,
1137
+ onBillingCycleChange
1138
+ }
1139
+ )
1140
+ ] })
1141
+ ] }),
1142
+ /* @__PURE__ */ jsxRuntime.jsx(
1143
+ PlansGrid,
1144
+ {
1145
+ plans,
1146
+ selectedPlan,
1147
+ billingCycle,
1148
+ loading,
1149
+ error,
1150
+ onPlanSelect,
1151
+ activePlanCode
1152
+ }
1153
+ )
1154
+ ] });
1155
+ };
1156
+ var ChangeCardButton = ({
1157
+ externalId,
1158
+ className = "",
1159
+ children,
1160
+ onSuccess,
1161
+ onError
1162
+ }) => {
1163
+ const { loading, openCustomerPortal } = useCustomerPortal({
1164
+ onSuccess: (url) => {
1165
+ console.log("Customer portal opened:", url);
1166
+ onSuccess == null ? void 0 : onSuccess();
1167
+ },
1168
+ onError: (error) => {
1169
+ console.error("Failed to open customer portal:", error);
1170
+ onError == null ? void 0 : onError(error);
1171
+ }
1172
+ });
1173
+ const handleClick = async () => {
1174
+ await openCustomerPortal(externalId);
1175
+ };
1176
+ const defaultClassName = "text-sm text-blue-600 font-medium hover:text-blue-700 hover:underline disabled:opacity-50 disabled:cursor-not-allowed";
1177
+ const finalClassName = className || defaultClassName;
1178
+ return /* @__PURE__ */ jsxRuntime.jsx(
1179
+ "button",
1180
+ {
1181
+ onClick: handleClick,
1182
+ disabled: loading,
1183
+ className: finalClassName,
1184
+ type: "button",
1185
+ children: loading ? "Opening..." : children || "Change Card"
1186
+ }
1187
+ );
1188
+ };
1189
+ var PaymentCancelView = ({ details }) => {
1190
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-md mx-auto bg-white rounded-lg shadow-md overflow-hidden", children: [
1191
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-gradient-to-r from-orange-500 to-red-500 text-white p-6 text-center", children: [
1192
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-4xl mb-2", children: "\u274C" }),
1193
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-bold", children: "Payment Cancelled" }),
1194
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-orange-100 mt-1", children: "Your payment was not processed" })
1195
+ ] }),
1196
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
1197
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
1198
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "What Happened?" }),
1199
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 bg-orange-50 rounded-lg mb-4", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-orange-800", children: details.reason ? `Reason: ${details.reason}` : "You cancelled the payment process before it was completed. No charges were made to your account." }) }),
1200
+ (details.gateway || details.sessionId) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 mb-4", children: [
1201
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-medium text-gray-900", children: "Transaction Details" }),
1202
+ details.gateway && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1203
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600", children: "Payment Gateway" }),
1204
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium capitalize", children: details.gateway })
1205
+ ] }),
1206
+ details.sessionId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1207
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600", children: "Session ID" }),
1208
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium font-mono text-sm", children: details.sessionId })
1209
+ ] }),
1210
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1211
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600", children: "Status" }),
1212
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-orange-600", children: "Cancelled" })
1213
+ ] }),
1214
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1215
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600", children: "Date" }),
1216
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: (/* @__PURE__ */ new Date()).toLocaleDateString() })
1217
+ ] })
1218
+ ] })
1219
+ ] }),
1220
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 p-4 bg-blue-50 rounded-lg", children: [
1221
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-blue-900 mb-2", children: "What's Next?" }),
1222
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "text-sm text-blue-800 space-y-1", children: [
1223
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "\u2022 No charges were made to your account" }),
1224
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "\u2022 You can try the payment again anytime" }),
1225
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "\u2022 Contact support if you need assistance" }),
1226
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "\u2022 Your cart/selection is still saved" })
1227
+ ] })
1228
+ ] }),
1229
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
1230
+ /* @__PURE__ */ jsxRuntime.jsx(
1231
+ "button",
1232
+ {
1233
+ onClick: () => window.history.back(),
1234
+ className: "w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-4 rounded-md transition-colors",
1235
+ children: "Try Payment Again"
1236
+ }
1237
+ ),
1238
+ /* @__PURE__ */ jsxRuntime.jsx(
1239
+ "button",
1240
+ {
1241
+ onClick: () => window.location.href = "/dashboard",
1242
+ className: "w-full bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-3 px-4 rounded-md transition-colors",
1243
+ children: "Browse Plans"
1244
+ }
1245
+ ),
1246
+ /* @__PURE__ */ jsxRuntime.jsx(
1247
+ "button",
1248
+ {
1249
+ onClick: () => window.location.href = "/",
1250
+ className: "w-full bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-3 px-4 rounded-md transition-colors",
1251
+ children: "Return Home"
1252
+ }
1253
+ )
1254
+ ] }),
1255
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-500", children: [
1256
+ "Having trouble?",
1257
+ " ",
1258
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/support", className: "text-blue-600 hover:text-blue-700", children: "Contact Support" })
1259
+ ] }) })
1260
+ ] })
1261
+ ] });
1262
+ };
1263
+ var PaymentCancelView_default = PaymentCancelView;
1264
+ var PaymentSuccessView = ({ details }) => {
1265
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-md mx-auto bg-white rounded-lg shadow-md overflow-hidden", children: [
1266
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-gradient-to-r from-green-500 to-green-600 text-white p-6 text-center", children: [
1267
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-4xl mb-2", children: "\u2705" }),
1268
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-bold", children: "Payment Successful!" }),
1269
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-green-100 mt-1", children: "Thank you for your purchase" })
1270
+ ] }),
1271
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
1272
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
1273
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Payment Details" }),
1274
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
1275
+ details.gateway && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1276
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600", children: "Payment Gateway" }),
1277
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium capitalize", children: details.gateway })
1278
+ ] }),
1279
+ details.sessionId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1280
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600", children: "Session ID" }),
1281
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium font-mono text-sm", children: details.sessionId })
1282
+ ] }),
1283
+ details.paymentId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1284
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600", children: "Payment ID" }),
1285
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium font-mono text-sm", children: details.paymentId })
1286
+ ] }),
1287
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1288
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600", children: "Status" }),
1289
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-green-600", children: "Completed" })
1290
+ ] }),
1291
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
1292
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-600", children: "Date" }),
1293
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: (/* @__PURE__ */ new Date()).toLocaleDateString() })
1294
+ ] })
1295
+ ] })
1296
+ ] }),
1297
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 p-4 bg-blue-50 rounded-lg", children: [
1298
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-blue-900 mb-2", children: "What's Next?" }),
1299
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "text-sm text-blue-800 space-y-1", children: [
1300
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "\u2022 You'll receive a confirmation email shortly" }),
1301
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "\u2022 Your subscription/purchase is now active" }),
1302
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "\u2022 Access your dashboard to manage your account" })
1303
+ ] })
1304
+ ] }),
1305
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
1306
+ /* @__PURE__ */ jsxRuntime.jsx(
1307
+ "button",
1308
+ {
1309
+ onClick: () => window.location.href = "/dashboard",
1310
+ className: "w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-4 rounded-md transition-colors",
1311
+ children: "Go to Dashboard"
1312
+ }
1313
+ ),
1314
+ /* @__PURE__ */ jsxRuntime.jsx(
1315
+ "button",
1316
+ {
1317
+ onClick: () => window.location.href = "/",
1318
+ className: "w-full bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-3 px-4 rounded-md transition-colors",
1319
+ children: "Return Home"
1320
+ }
1321
+ )
1322
+ ] }),
1323
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-500", children: [
1324
+ "Need help?",
1325
+ " ",
1326
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/support", className: "text-blue-600 hover:text-blue-700", children: "Contact Support" })
1327
+ ] }) })
1328
+ ] })
1329
+ ] });
1330
+ };
1331
+ var PaymentSuccessView_default = PaymentSuccessView;
1332
+ var getStatusColor = (status) => {
1333
+ switch (status.toLowerCase()) {
1334
+ case "activated":
1335
+ case "succeeded":
1336
+ case "renewed":
1337
+ case "use_stripe_sdk":
1338
+ return "bg-green-100 text-green-800";
1339
+ case "pending":
1340
+ case "processing":
1341
+ return "bg-yellow-100 text-yellow-800";
1342
+ case "payment_failed":
1343
+ return "bg-red-100 text-red-800";
1344
+ default:
1345
+ return "bg-blue-100 text-blue-800";
1346
+ }
1347
+ };
1348
+ var formatCurrency = (amount, currency = "USD") => {
1349
+ const numericAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1350
+ return new Intl.NumberFormat("en-US", {
1351
+ style: "currency",
1352
+ currency
1353
+ }).format(numericAmount);
1354
+ };
1355
+ var TransactionList = ({
1356
+ transactions,
1357
+ loading = false,
1358
+ error = null,
1359
+ onInvoiceClick,
1360
+ className = ""
1361
+ }) => {
1362
+ console.log("=== TransactionList Render ===");
1363
+ console.log("transactions:", transactions);
1364
+ console.log("transactions.length:", transactions.length);
1365
+ console.log("First transaction:", transactions[0]);
1366
+ console.log("loading:", loading);
1367
+ console.log("error:", error);
1368
+ console.log("=== End TransactionList Debug ===");
1369
+ if (loading) {
1370
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center justify-center py-8 ${className}`, children: [
1371
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary" }),
1372
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 text-gray-600", children: "Loading transactions..." })
1373
+ ] });
1374
+ }
1375
+ if (error) {
1376
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `bg-red-50 border border-red-200 rounded-md p-4 ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
1377
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "h-5 w-5 text-red-400", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx(
1378
+ "path",
1379
+ {
1380
+ fillRule: "evenodd",
1381
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z",
1382
+ clipRule: "evenodd"
1383
+ }
1384
+ ) }) }),
1385
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-3", children: [
1386
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-medium text-red-800", children: "Error loading transactions" }),
1387
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-sm text-red-700", children: error })
1388
+ ] })
1389
+ ] }) });
1390
+ }
1391
+ if (transactions.length === 0) {
1392
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `text-center py-8 ${className}`, children: [
1393
+ /* @__PURE__ */ jsxRuntime.jsx(
1394
+ "svg",
1395
+ {
1396
+ className: "mx-auto h-12 w-12 text-gray-400",
1397
+ fill: "none",
1398
+ viewBox: "0 0 24 24",
1399
+ stroke: "currentColor",
1400
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1401
+ "path",
1402
+ {
1403
+ strokeLinecap: "round",
1404
+ strokeLinejoin: "round",
1405
+ strokeWidth: 2,
1406
+ d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
1407
+ }
1408
+ )
1409
+ }
1410
+ ),
1411
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mt-2 text-sm font-medium text-gray-900", children: "No transactions found" }),
1412
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-gray-500", children: "There are no transactions to display." })
1413
+ ] });
1414
+ }
1415
+ console.log("About to render transactions, count:", transactions.length);
1416
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `bg-white shadow overflow-hidden sm:rounded-md ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "divide-y divide-gray-200", children: transactions.map((transaction, index) => {
1417
+ var _a;
1418
+ console.log(`Rendering transaction ${index}:`, transaction);
1419
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-6 py-4 hover:bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
1420
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1421
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1422
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900 truncate", children: transaction.planName ? `${transaction.planName} Plan` : `Transaction #${transaction.transactionCode || transaction.id}` }),
1423
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: formatDate(transaction.transactionDate || transaction.membershipDate) })
1424
+ ] }),
1425
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
1426
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
1427
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-900", children: formatCurrency(transaction.amount, (_a = transaction.currency) == null ? void 0 : _a.toUpperCase()) }),
1428
+ transaction.tax && transaction.tax > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-500", children: [
1429
+ "Tax: ",
1430
+ formatCurrency(transaction.tax)
1431
+ ] }),
1432
+ transaction.charge && parseFloat(transaction.charge.toString()) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-500", children: [
1433
+ "Charge: ",
1434
+ formatCurrency(transaction.charge)
1435
+ ] })
1436
+ ] }),
1437
+ /* @__PURE__ */ jsxRuntime.jsx(
1438
+ "span",
1439
+ {
1440
+ className: `inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getStatusColor(
1441
+ transaction.transactionStatus
1442
+ )}`,
1443
+ children: transaction.transactionStatus
1444
+ }
1445
+ )
1446
+ ] })
1447
+ ] }),
1448
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between", children: [
1449
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center text-sm text-gray-500 flex-wrap gap-4", children: [
1450
+ transaction.paymentGateway && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1451
+ "Gateway: ",
1452
+ transaction.paymentGateway
1453
+ ] }),
1454
+ transaction.planInterval && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1455
+ "Billing: ",
1456
+ transaction.planInterval
1457
+ ] }),
1458
+ transaction.expiryDate && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1459
+ "Expires: ",
1460
+ formatDate(transaction.expiryDate)
1461
+ ] }),
1462
+ transaction.isPlanActive !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: transaction.isPlanActive ? "text-green-600" : "text-red-600", children: transaction.isPlanActive ? "Active" : "Inactive" })
1463
+ ] }),
1464
+ transaction.invoiceUrl && onInvoiceClick && /* @__PURE__ */ jsxRuntime.jsx(
1465
+ "button",
1466
+ {
1467
+ onClick: () => onInvoiceClick(transaction.id),
1468
+ className: "text-sm text-primary hover:text-primary-dark font-medium",
1469
+ children: "View Invoice"
1470
+ }
1471
+ )
1472
+ ] })
1473
+ ] }) }) }, transaction.id);
1474
+ }) }) });
1475
+ };
1476
+ var Pagination = ({
1477
+ meta,
1478
+ onPageChange,
1479
+ onLimitChange,
1480
+ showLimitSelector = true,
1481
+ limitOptions = [10, 25, 50, 100],
1482
+ className = ""
1483
+ }) => {
1484
+ const { currentPage, totalPages, totalItems, itemsPerPage, hasNextPage, hasPreviousPage } = meta;
1485
+ const getPageNumbers = () => {
1486
+ const pages = [];
1487
+ const maxVisiblePages = 7;
1488
+ if (totalPages <= maxVisiblePages) {
1489
+ for (let i = 1; i <= totalPages; i++) {
1490
+ pages.push(i);
1491
+ }
1492
+ } else {
1493
+ pages.push(1);
1494
+ if (currentPage > 4) {
1495
+ pages.push("...");
1496
+ }
1497
+ const start = Math.max(2, currentPage - 1);
1498
+ const end = Math.min(totalPages - 1, currentPage + 1);
1499
+ for (let i = start; i <= end; i++) {
1500
+ if (i !== 1 && i !== totalPages) {
1501
+ pages.push(i);
1502
+ }
1503
+ }
1504
+ if (currentPage < totalPages - 3) {
1505
+ pages.push("...");
1506
+ }
1507
+ if (totalPages > 1) {
1508
+ pages.push(totalPages);
1509
+ }
1510
+ }
1511
+ return pages;
1512
+ };
1513
+ const pageNumbers = getPageNumbers();
1514
+ const startItem = (currentPage - 1) * itemsPerPage + 1;
1515
+ const endItem = Math.min(currentPage * itemsPerPage, totalItems);
1516
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col sm:flex-row items-center justify-between gap-4 ${className}`, children: [
1517
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-gray-700", children: [
1518
+ "Showing ",
1519
+ startItem,
1520
+ " to ",
1521
+ endItem,
1522
+ " of ",
1523
+ totalItems,
1524
+ " results"
1525
+ ] }),
1526
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
1527
+ showLimitSelector && onLimitChange && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1528
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "limit-select", className: "text-sm text-gray-700", children: "Show:" }),
1529
+ /* @__PURE__ */ jsxRuntime.jsx(
1530
+ "select",
1531
+ {
1532
+ id: "limit-select",
1533
+ value: itemsPerPage,
1534
+ onChange: (e) => onLimitChange(Number(e.target.value)),
1535
+ className: "border border-gray-300 rounded px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent",
1536
+ children: limitOptions.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option, children: option }, option))
1537
+ }
1538
+ )
1539
+ ] }),
1540
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
1541
+ /* @__PURE__ */ jsxRuntime.jsx(
1542
+ "button",
1543
+ {
1544
+ onClick: () => onPageChange(currentPage - 1),
1545
+ disabled: !hasPreviousPage,
1546
+ className: "px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-l-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",
1547
+ children: "Previous"
1548
+ }
1549
+ ),
1550
+ pageNumbers.map((page, index) => /* @__PURE__ */ jsxRuntime.jsx(React3__default.default.Fragment, { children: page === "..." ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300", children: "..." }) : /* @__PURE__ */ jsxRuntime.jsx(
1551
+ "button",
1552
+ {
1553
+ onClick: () => onPageChange(page),
1554
+ className: `px-3 py-2 text-sm font-medium border ${currentPage === page ? "bg-primary text-white border-primary" : "text-gray-700 bg-white border-gray-300 hover:bg-gray-50"}`,
1555
+ children: page
1556
+ }
1557
+ ) }, index)),
1558
+ /* @__PURE__ */ jsxRuntime.jsx(
1559
+ "button",
1560
+ {
1561
+ onClick: () => onPageChange(currentPage + 1),
1562
+ disabled: !hasNextPage,
1563
+ className: "px-3 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-r-md hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed",
1564
+ children: "Next"
1565
+ }
1566
+ )
1567
+ ] })
1568
+ ] })
1569
+ ] });
1570
+ };
1571
+ var TransactionModal = ({
1572
+ isOpen,
1573
+ onClose,
1574
+ externalId,
1575
+ title = "Transaction History"
1576
+ }) => {
1577
+ const {
1578
+ transactions,
1579
+ loading,
1580
+ error,
1581
+ filters,
1582
+ meta,
1583
+ updateFilters
1584
+ } = useTransactions({
1585
+ externalId,
1586
+ initialFilters: { page: 1, limit: 10 },
1587
+ autoFetch: true
1588
+ // Enable auto-fetch so it works when modal opens
1589
+ });
1590
+ console.log("=== TransactionModal Debug ===");
1591
+ console.log("isOpen:", isOpen);
1592
+ console.log("externalId:", externalId);
1593
+ console.log("transactions:", transactions);
1594
+ console.log("transactions.length:", transactions.length);
1595
+ console.log("loading:", loading);
1596
+ console.log("error:", error);
1597
+ console.log("filters:", filters);
1598
+ console.log("meta:", meta);
1599
+ console.log("=== End Debug ===");
1600
+ const handlePageChange = (page) => {
1601
+ updateFilters({ page });
1602
+ };
1603
+ const handleLimitChange = (limit) => {
1604
+ updateFilters({ limit, page: 1 });
1605
+ };
1606
+ const handleInvoiceClick = (transactionId) => {
1607
+ console.log("View invoice for transaction:", transactionId);
1608
+ };
1609
+ const handleFilterChange = (newFilters) => {
1610
+ updateFilters(newFilters);
1611
+ };
1612
+ if (!isOpen) return null;
1613
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0", children: [
1614
+ /* @__PURE__ */ jsxRuntime.jsx(
1615
+ "div",
1616
+ {
1617
+ className: "fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity z-0",
1618
+ onClick: onClose
1619
+ }
1620
+ ),
1621
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full relative z-10", children: [
1622
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4", children: [
1623
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
1624
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg leading-6 font-medium text-gray-900", children: title }),
1625
+ /* @__PURE__ */ jsxRuntime.jsxs(
1626
+ "button",
1627
+ {
1628
+ onClick: onClose,
1629
+ className: "bg-white rounded-md text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary",
1630
+ children: [
1631
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" }),
1632
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx(
1633
+ "path",
1634
+ {
1635
+ strokeLinecap: "round",
1636
+ strokeLinejoin: "round",
1637
+ strokeWidth: 2,
1638
+ d: "M6 18L18 6M6 6l12 12"
1639
+ }
1640
+ ) })
1641
+ ]
1642
+ }
1643
+ )
1644
+ ] }),
1645
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4 grid grid-cols-1 sm:grid-cols-3 gap-4", children: [
1646
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1647
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "status-filter", className: "block text-sm font-medium text-gray-700 mb-1", children: "Status" }),
1648
+ /* @__PURE__ */ jsxRuntime.jsxs(
1649
+ "select",
1650
+ {
1651
+ id: "status-filter",
1652
+ value: filters.status || "",
1653
+ onChange: (e) => handleFilterChange({ status: e.target.value || void 0 }),
1654
+ className: "w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent",
1655
+ children: [
1656
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "All" }),
1657
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "succeeded", children: "Completed" }),
1658
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "pending", children: "Pending" }),
1659
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "payment_failed", children: "Failed" })
1660
+ ]
1661
+ }
1662
+ )
1663
+ ] }),
1664
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1665
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "start-date", className: "block text-sm font-medium text-gray-700 mb-1", children: "Start Date" }),
1666
+ /* @__PURE__ */ jsxRuntime.jsx(
1667
+ "input",
1668
+ {
1669
+ type: "date",
1670
+ id: "start-date",
1671
+ value: filters.startDate || "",
1672
+ onChange: (e) => handleFilterChange({ startDate: e.target.value || void 0 }),
1673
+ className: "w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
1674
+ }
1675
+ )
1676
+ ] }),
1677
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1678
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "end-date", className: "block text-sm font-medium text-gray-700 mb-1", children: "End Date" }),
1679
+ /* @__PURE__ */ jsxRuntime.jsx(
1680
+ "input",
1681
+ {
1682
+ type: "date",
1683
+ id: "end-date",
1684
+ value: filters.endDate || "",
1685
+ onChange: (e) => handleFilterChange({ endDate: e.target.value || void 0 }),
1686
+ className: "w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
1687
+ }
1688
+ )
1689
+ ] })
1690
+ ] })
1691
+ ] }),
1692
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 pb-4 sm:px-6 sm:pb-6", children: [
1693
+ /* @__PURE__ */ jsxRuntime.jsx(
1694
+ TransactionList,
1695
+ {
1696
+ transactions,
1697
+ loading,
1698
+ error,
1699
+ onInvoiceClick: handleInvoiceClick,
1700
+ className: "mb-4"
1701
+ }
1702
+ ),
1703
+ meta && /* @__PURE__ */ jsxRuntime.jsx(
1704
+ Pagination,
1705
+ {
1706
+ meta,
1707
+ onPageChange: handlePageChange,
1708
+ onLimitChange: handleLimitChange,
1709
+ showLimitSelector: true,
1710
+ limitOptions: [5, 10, 25, 50]
1711
+ }
1712
+ )
1713
+ ] }),
1714
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse", children: /* @__PURE__ */ jsxRuntime.jsx(
1715
+ "button",
1716
+ {
1717
+ type: "button",
1718
+ onClick: onClose,
1719
+ className: "w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-primary text-base font-medium text-white hover:bg-primary-dark focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary sm:ml-3 sm:w-auto sm:text-sm",
1720
+ children: "Close"
1721
+ }
1722
+ ) })
1723
+ ] })
1724
+ ] }) });
1725
+ };
1726
+ var SubscriptionDetails = ({
1727
+ subscription,
1728
+ email,
1729
+ externalId,
1730
+ onChangeEmail,
1731
+ onSubscriptionCancelled
1732
+ }) => {
1733
+ var _a, _b, _c, _d, _e, _f;
1734
+ const [isTransactionModalOpen, setIsTransactionModalOpen] = React3.useState(false);
1735
+ const [showCancelConfirmation, setShowCancelConfirmation] = React3.useState(false);
1736
+ const { cancelSubscription, loading: cancelLoading } = useCancelSubscription({
1737
+ onSuccess: () => {
1738
+ setShowCancelConfirmation(false);
1739
+ onSubscriptionCancelled == null ? void 0 : onSubscriptionCancelled();
1740
+ alert("Subscription cancelled successfully");
1741
+ },
1742
+ onError: (error) => {
1743
+ alert(`Failed to cancel subscription: ${error}`);
1744
+ }
1745
+ });
1746
+ const handleTransactionClick = () => {
1747
+ setIsTransactionModalOpen(true);
1748
+ };
1749
+ const handleCancelClick = () => {
1750
+ setShowCancelConfirmation(true);
1751
+ };
1752
+ const handleConfirmCancel = async () => {
1753
+ await cancelSubscription(externalId, {
1754
+ cancellationMode: "endOfPeriod",
1755
+ cancellationReason: "subscription_user_canceled_request"
1756
+ });
1757
+ };
1758
+ const handleCancelModalClose = () => {
1759
+ setShowCancelConfirmation(false);
1760
+ };
1761
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1762
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 flex items-center justify-between", children: [
1763
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-gray-600", children: [
1764
+ "Using email: ",
1765
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: email })
1766
+ ] }),
1767
+ /* @__PURE__ */ jsxRuntime.jsx(
1768
+ "button",
1769
+ {
1770
+ className: "text-sm text-primary hover:underline",
1771
+ onClick: onChangeEmail,
1772
+ children: "Change email"
1773
+ }
1774
+ )
1775
+ ] }),
1776
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 bg-white rounded-lg border border-gray-200 p-6", children: [
1777
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
1778
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-semibold", children: "Subscription Details" }),
1779
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4", children: [
1780
+ /* @__PURE__ */ jsxRuntime.jsx(
1781
+ "button",
1782
+ {
1783
+ onClick: handleTransactionClick,
1784
+ className: "text-sm text-green-600 font-medium hover:text-green-700 hover:underline",
1785
+ children: "Transactions"
1786
+ }
1787
+ ),
1788
+ /* @__PURE__ */ jsxRuntime.jsx(
1789
+ ChangeCardButton,
1790
+ {
1791
+ externalId,
1792
+ className: "text-sm text-blue-600 font-medium hover:text-blue-700 hover:underline",
1793
+ onSuccess: () => {
1794
+ console.log("Customer portal opened successfully");
1795
+ },
1796
+ onError: (error) => {
1797
+ alert(`Failed to open payment portal: ${error}`);
1798
+ },
1799
+ children: "Change Card"
1800
+ }
1801
+ ),
1802
+ /* @__PURE__ */ jsxRuntime.jsx(
1803
+ "button",
1804
+ {
1805
+ onClick: handleCancelClick,
1806
+ className: "text-sm text-red-500 font-medium hover:text-red-600 hover:underline",
1807
+ children: "Cancel Renewal"
1808
+ }
1809
+ )
1810
+ ] })
1811
+ ] }),
1812
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 md:grid-cols-5 gap-4 mb-4", children: [
1813
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1814
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Active Subscription" }),
1815
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: (_a = subscription == null ? void 0 : subscription.plan) == null ? void 0 : _a.name })
1816
+ ] }),
1817
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1818
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Subscription Type" }),
1819
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: (_b = subscription == null ? void 0 : subscription.plan) == null ? void 0 : _b.interval })
1820
+ ] }),
1821
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1822
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Subscription Renews on" }),
1823
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: (subscription == null ? void 0 : subscription.expiryDate) ? formatDate(subscription.expiryDate) : "" })
1824
+ ] }),
1825
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1826
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Active Jobs" }),
1827
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "font-medium", children: [
1828
+ ((_c = subscription == null ? void 0 : subscription.usage) == null ? void 0 : _c.ACTIVE_JOBS) || 0,
1829
+ "/",
1830
+ (_d = subscription == null ? void 0 : subscription.meta) == null ? void 0 : _d.ACTIVE_JOBS
1831
+ ] })
1832
+ ] }),
1833
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1834
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Candidates" }),
1835
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "font-medium", children: [
1836
+ ((_e = subscription == null ? void 0 : subscription.usage) == null ? void 0 : _e.CANDIDATES) || 0,
1837
+ "/",
1838
+ (_f = subscription == null ? void 0 : subscription.meta) == null ? void 0 : _f.CANDIDATES
1839
+ ] })
1840
+ ] })
1841
+ ] })
1842
+ ] }),
1843
+ /* @__PURE__ */ jsxRuntime.jsx(
1844
+ TransactionModal,
1845
+ {
1846
+ isOpen: isTransactionModalOpen,
1847
+ onClose: () => setIsTransactionModalOpen(false),
1848
+ externalId,
1849
+ title: "Transaction History"
1850
+ }
1851
+ ),
1852
+ showCancelConfirmation && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0", children: [
1853
+ /* @__PURE__ */ jsxRuntime.jsx(
1854
+ "div",
1855
+ {
1856
+ className: "fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity z-0",
1857
+ onClick: handleCancelModalClose
1858
+ }
1859
+ ),
1860
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full relative z-10", children: [
1861
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm:flex sm:items-start", children: [
1862
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10", children: /* @__PURE__ */ jsxRuntime.jsx(
1863
+ "svg",
1864
+ {
1865
+ className: "h-6 w-6 text-red-600",
1866
+ fill: "none",
1867
+ viewBox: "0 0 24 24",
1868
+ stroke: "currentColor",
1869
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1870
+ "path",
1871
+ {
1872
+ strokeLinecap: "round",
1873
+ strokeLinejoin: "round",
1874
+ strokeWidth: 2,
1875
+ d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
1876
+ }
1877
+ )
1878
+ }
1879
+ ) }),
1880
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left", children: [
1881
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg leading-6 font-medium text-gray-900", children: "Cancel Subscription" }),
1882
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Are you sure you want to cancel your subscription? This action will prevent automatic renewal, but you'll continue to have access until your current billing period ends." }) })
1883
+ ] })
1884
+ ] }) }),
1885
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse", children: [
1886
+ /* @__PURE__ */ jsxRuntime.jsx(
1887
+ "button",
1888
+ {
1889
+ type: "button",
1890
+ onClick: handleConfirmCancel,
1891
+ disabled: cancelLoading,
1892
+ className: "w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm disabled:opacity-50 disabled:cursor-not-allowed",
1893
+ children: cancelLoading ? "Cancelling..." : "Cancel Subscription"
1894
+ }
1895
+ ),
1896
+ /* @__PURE__ */ jsxRuntime.jsx(
1897
+ "button",
1898
+ {
1899
+ type: "button",
1900
+ onClick: handleCancelModalClose,
1901
+ disabled: cancelLoading,
1902
+ className: "mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm disabled:opacity-50 disabled:cursor-not-allowed",
1903
+ children: "Keep Subscription"
1904
+ }
1905
+ )
1906
+ ] })
1907
+ ] })
1908
+ ] }) })
1909
+ ] });
1910
+ };
1911
+ var EmailEntry = ({
1912
+ email,
1913
+ emailError,
1914
+ onEmailChange,
1915
+ onEmailSubmit,
1916
+ onEmailError
1917
+ }) => {
1918
+ const handleEmailChange = (e) => {
1919
+ const value = e.target.value;
1920
+ onEmailChange(value);
1921
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1922
+ if (!value) {
1923
+ onEmailError("Email is required");
1924
+ } else if (!emailRegex.test(value)) {
1925
+ onEmailError("Please enter a valid email address");
1926
+ } else {
1927
+ onEmailError(null);
1928
+ }
1929
+ };
1930
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-8 max-w-xl mx-auto text-center bg-white rounded-lg shadow-md", children: [
1931
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-bold mb-2", children: "Your Subscription Portal" }),
1932
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-700 mb-8", children: "Enter your email to access your subscription details, plans and transaction history." }),
1933
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
1934
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
1935
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "email", className: "sr-only", children: "Email Address" }),
1936
+ /* @__PURE__ */ jsxRuntime.jsx(
1937
+ "input",
1938
+ {
1939
+ id: "email",
1940
+ type: "email",
1941
+ className: `w-full px-4 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-primary ${emailError ? "border-red-500" : "border-gray-300"}`,
1942
+ placeholder: "Email Address",
1943
+ value: email,
1944
+ onChange: handleEmailChange,
1945
+ required: true
1946
+ }
1947
+ ),
1948
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: `mt-1 text-sm ${emailError ? "text-red-500" : "text-gray-500"}`, children: emailError || "We'll use this to identify your account" })
1949
+ ] }),
1950
+ /* @__PURE__ */ jsxRuntime.jsx(
1951
+ "button",
1952
+ {
1953
+ className: `w-full btn-primary py-2 px-4 rounded-md ${!email || !!emailError ? "opacity-50 cursor-not-allowed" : ""}`,
1954
+ disabled: !email || !!emailError,
1955
+ onClick: onEmailSubmit,
1956
+ children: "Continue"
1957
+ }
1958
+ )
1959
+ ] }),
1960
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Don't have a subscription yet? You can browse our plans after entering your email." })
1961
+ ] });
1962
+ };
1963
+ var UpgradeSummary = ({
1964
+ selectedPlan,
1965
+ onUpgrade
1966
+ }) => {
1967
+ if (!selectedPlan || Number(selectedPlan.fixedCost) === 0) {
1968
+ return null;
1969
+ }
1970
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1971
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1972
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-semibold text-gray-900", children: "Summary" }),
1973
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600", children: selectedPlan.name }),
1974
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "See Price Breakdown" })
1975
+ ] }),
1976
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
1977
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-2xl font-bold text-gray-900", children: [
1978
+ "$",
1979
+ selectedPlan.fixedCost,
1980
+ "/Yr"
1981
+ ] }),
1982
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Due Today" }),
1983
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm font-medium", children: [
1984
+ "$",
1985
+ selectedPlan.fixedCost
1986
+ ] })
1987
+ ] }),
1988
+ /* @__PURE__ */ jsxRuntime.jsx(
1989
+ "button",
1990
+ {
1991
+ onClick: onUpgrade,
1992
+ className: "bg-green-600 text-white px-6 py-2 rounded-md font-medium hover:bg-green-700 transition-colors",
1993
+ children: "Upgrade Now"
1994
+ }
1995
+ )
1996
+ ] }) });
1997
+ };
1998
+ var LogoInline = ({ src, alt = "Logo", viewBox = "0 0 1024 1024", ...props }) => {
1999
+ const resolvedSrc = src ?? `${undefined.BASE_URL}file.svg`;
2000
+ return /* @__PURE__ */ jsxRuntime.jsx(
2001
+ "svg",
2002
+ {
2003
+ version: "1.1",
2004
+ xmlns: "http://www.w3.org/2000/svg",
2005
+ viewBox,
2006
+ "aria-label": alt,
2007
+ role: "img",
2008
+ ...props,
2009
+ children: /* @__PURE__ */ jsxRuntime.jsx("image", { href: resolvedSrc, width: "100%", height: "100%", preserveAspectRatio: "xMidYMid meet" })
2010
+ }
2011
+ );
2012
+ };
2013
+ var Layout = ({ children }) => {
2014
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-h-screen w-full", children: [
2015
+ /* @__PURE__ */ jsxRuntime.jsx("header", { className: "bg-white/80 backdrop-blur border-b border-gray-200", children: /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "w-full flex items-center justify-between px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow", children: /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: "/", className: "no-underline text-inherit", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(LogoInline, { className: "h-8 w-auto", alt: "SubOS" }) }) }) }) }) }),
2016
+ /* @__PURE__ */ jsxRuntime.jsx("main", { className: "flex-1 w-full", children }),
2017
+ /* @__PURE__ */ jsxRuntime.jsx("footer", { className: "bg-gray-100 py-6 w-full mt-auto", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-7xl mx-auto px-4", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-gray-600 text-center", children: [
2018
+ "\xA9 ",
2019
+ (/* @__PURE__ */ new Date()).getFullYear(),
2020
+ " SubOS. All rights reserved."
2021
+ ] }) }) })
2022
+ ] });
2023
+ };
2024
+ var DashboardPage = () => {
2025
+ var _a;
2026
+ const emailManagement = useEmailManagement();
2027
+ const subscription = useSubscription();
2028
+ const plans = usePlans();
2029
+ const loadDashboardData = (email) => {
2030
+ subscription.fetchSubscription(email);
2031
+ plans.fetchPlans();
2032
+ };
2033
+ React3.useEffect(() => {
2034
+ if (emailManagement.email && !emailManagement.isEmailScreen) {
2035
+ loadDashboardData(emailManagement.email);
2036
+ }
2037
+ }, [emailManagement.email, emailManagement.isEmailScreen]);
2038
+ const handleChangeEmail = () => {
2039
+ emailManagement.handleChangeEmail();
2040
+ subscription.clearSubscription();
2041
+ plans.clearPlans();
2042
+ };
2043
+ const handleUpgrade = () => {
2044
+ plans.handleUpgrade(emailManagement.email);
2045
+ };
2046
+ return /* @__PURE__ */ jsxRuntime.jsx(Layout, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-7xl mx-auto w-full h-full py-8 px-4", children: !emailManagement.isEmailScreen ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2047
+ /* @__PURE__ */ jsxRuntime.jsx(
2048
+ SubscriptionDetails,
2049
+ {
2050
+ subscription: subscription.subscription,
2051
+ email: emailManagement.email,
2052
+ externalId: emailManagement.email,
2053
+ onChangeEmail: handleChangeEmail,
2054
+ onSubscriptionCancelled: () => {
2055
+ subscription.fetchSubscription(emailManagement.email);
2056
+ }
2057
+ }
2058
+ ),
2059
+ /* @__PURE__ */ jsxRuntime.jsx(
2060
+ PlanSelector,
2061
+ {
2062
+ plans: plans.filteredPlans,
2063
+ selectedPlan: plans.selectedPlan,
2064
+ tierFilter: plans.tierFilter,
2065
+ billingCycle: plans.billingCycle,
2066
+ loading: plans.loading,
2067
+ error: plans.error,
2068
+ dropdownOptions: plans.dropdownOptions,
2069
+ currentSelectionText: plans.currentSelectionText,
2070
+ onPlanSelect: plans.handlePlanSelect,
2071
+ onTierFilterChange: plans.setTierFilter,
2072
+ onBillingCycleChange: plans.setBillingCycle,
2073
+ activePlanCode: (_a = subscription.subscription) == null ? void 0 : _a.plan.code
2074
+ }
2075
+ ),
2076
+ /* @__PURE__ */ jsxRuntime.jsx(
2077
+ UpgradeSummary,
2078
+ {
2079
+ selectedPlan: plans.selectedPlan,
2080
+ onUpgrade: handleUpgrade
2081
+ }
2082
+ )
2083
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
2084
+ EmailEntry,
2085
+ {
2086
+ email: emailManagement.email,
2087
+ emailError: emailManagement.emailError,
2088
+ onEmailChange: emailManagement.setEmail,
2089
+ onEmailSubmit: emailManagement.handleEmailSubmit,
2090
+ onEmailError: emailManagement.setEmailError
2091
+ }
2092
+ ) }) });
2093
+ };
2094
+ var usePaymentParams = () => {
2095
+ return React3.useMemo(() => {
2096
+ const params = new URLSearchParams(window.location.search);
2097
+ return {
2098
+ gateway: params.get("gateway") || void 0,
2099
+ sessionId: params.get("session_id") || void 0,
2100
+ paymentId: params.get("payment_id") || void 0,
2101
+ reason: params.get("reason") || void 0
2102
+ };
2103
+ }, []);
2104
+ };
2105
+ var useProcessPaymentSuccess = (params) => {
2106
+ const [loading, setLoading] = React3.useState(true);
2107
+ const [error, setError] = React3.useState(null);
2108
+ React3.useEffect(() => {
2109
+ const run = async () => {
2110
+ try {
2111
+ const qs = new URLSearchParams({
2112
+ ...params.gateway ? { gateway: params.gateway } : {},
2113
+ ...params.sessionId ? { session_id: params.sessionId } : {},
2114
+ ...params.paymentId ? { payment_id: params.paymentId } : {}
2115
+ }).toString();
2116
+ const url = `${getApiBaseUrl()}/api/payments/success?${qs}`;
2117
+ const response = await fetch(url, {
2118
+ headers: getHeaders(),
2119
+ credentials: "include"
2120
+ });
2121
+ const contentType = response.headers.get("content-type") || "";
2122
+ if (!contentType.includes("application/json")) {
2123
+ const text = await response.text();
2124
+ throw new Error(`Unexpected response type: ${contentType}. Body: ${text.slice(0, 200)}...`);
2125
+ }
2126
+ const result = await response.json();
2127
+ if (!result.success) {
2128
+ setError(result.error || "Failed to process payment");
2129
+ }
2130
+ } catch (err) {
2131
+ setError((err == null ? void 0 : err.message) || "Failed to process payment");
2132
+ } finally {
2133
+ setLoading(false);
2134
+ }
2135
+ };
2136
+ run();
2137
+ }, []);
2138
+ return { loading, error };
2139
+ };
2140
+ var PaymentSuccessPage = () => {
2141
+ const paymentDetails = usePaymentParams();
2142
+ const { loading, error } = useProcessPaymentSuccess(paymentDetails);
2143
+ if (loading) {
2144
+ return /* @__PURE__ */ jsxRuntime.jsx(Layout, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto p-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-md mx-auto bg-white rounded-lg shadow-md p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
2145
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-green-600 mx-auto" }),
2146
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 text-gray-600", children: "Processing your payment..." })
2147
+ ] }) }) }) });
2148
+ }
2149
+ if (error) {
2150
+ return /* @__PURE__ */ jsxRuntime.jsx(Layout, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto p-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-md mx-auto bg-white rounded-lg shadow-md p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
2151
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-red-600 text-4xl mb-4", children: "\u26A0\uFE0F" }),
2152
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-semibold text-gray-900 mb-2", children: "Payment Processing Error" }),
2153
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-red-600 mb-4", children: error }),
2154
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2155
+ /* @__PURE__ */ jsxRuntime.jsx(
2156
+ "button",
2157
+ {
2158
+ onClick: () => window.location.reload(),
2159
+ className: "w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md transition-colors",
2160
+ children: "Try Again"
2161
+ }
2162
+ ),
2163
+ /* @__PURE__ */ jsxRuntime.jsx(
2164
+ "button",
2165
+ {
2166
+ onClick: () => window.location.href = "/",
2167
+ className: "w-full bg-gray-500 hover:bg-gray-600 text-white font-medium py-2 px-4 rounded-md transition-colors",
2168
+ children: "Go Home"
2169
+ }
2170
+ )
2171
+ ] })
2172
+ ] }) }) }) });
2173
+ }
2174
+ return /* @__PURE__ */ jsxRuntime.jsx(Layout, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto p-4", children: /* @__PURE__ */ jsxRuntime.jsx(PaymentSuccessView_default, { details: paymentDetails }) }) });
2175
+ };
2176
+ var PaymentSuccessPage_default = PaymentSuccessPage;
2177
+ var useProcessPaymentCancel = (params) => {
2178
+ const [loading, setLoading] = React3.useState(true);
2179
+ const [error, setError] = React3.useState(null);
2180
+ React3.useEffect(() => {
2181
+ const run = async () => {
2182
+ try {
2183
+ const qs = new URLSearchParams({
2184
+ ...params.gateway ? { gateway: params.gateway } : {},
2185
+ ...params.sessionId ? { session_id: params.sessionId } : {},
2186
+ ...params.paymentId ? { payment_id: params.paymentId } : {},
2187
+ ...params.reason ? { reason: params.reason } : {}
2188
+ }).toString();
2189
+ const url = `${getApiBaseUrl()}/api/payments/cancel?${qs}`;
2190
+ await fetch(url, {
2191
+ headers: getHeaders(),
2192
+ credentials: "include"
2193
+ });
2194
+ } catch (err) {
2195
+ setError((err == null ? void 0 : err.message) || "Failed to process cancellation");
2196
+ } finally {
2197
+ setLoading(false);
2198
+ }
2199
+ };
2200
+ run();
2201
+ }, []);
2202
+ return { loading, error };
2203
+ };
2204
+ var PaymentCancelPage = () => {
2205
+ const details = usePaymentParams();
2206
+ const { loading } = useProcessPaymentCancel(details);
2207
+ if (loading) {
2208
+ return /* @__PURE__ */ jsxRuntime.jsx(Layout, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto p-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-md mx-auto bg-white rounded-lg shadow-md p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
2209
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-orange-600 mx-auto" }),
2210
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 text-gray-600", children: "Processing cancellation..." })
2211
+ ] }) }) }) });
2212
+ }
2213
+ return /* @__PURE__ */ jsxRuntime.jsx(Layout, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "container mx-auto p-4", children: /* @__PURE__ */ jsxRuntime.jsx(PaymentCancelView_default, { details }) }) });
2214
+ };
2215
+ var PaymentCancelPage_default = PaymentCancelPage;
2216
+ var App = function App2() {
2217
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.BrowserRouter, { children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Routes, { children: [
2218
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/", element: /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/dashboard", replace: true }) }),
2219
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/dashboard", element: /* @__PURE__ */ jsxRuntime.jsx(DashboardPage, {}) }),
2220
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/payment-success", element: /* @__PURE__ */ jsxRuntime.jsx(PaymentSuccessPage_default, {}) }),
2221
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/payment-cancel", element: /* @__PURE__ */ jsxRuntime.jsx(PaymentCancelPage_default, {}) })
2222
+ ] }) });
2223
+ };
2224
+
2225
+ exports.AddCardIcon = AddCardIcon;
2226
+ exports.AddIcon = AddIcon;
2227
+ exports.App = App;
2228
+ exports.BillingCycleToggle = BillingCycleToggle;
2229
+ exports.CancelIcon = CancelIcon;
2230
+ exports.ChangeCardButton = ChangeCardButton;
2231
+ exports.CheckCircleIcon = CheckCircleIcon;
2232
+ exports.CheckIcon = CheckIcon;
2233
+ exports.CreditCardIcon = CreditCardIcon;
2234
+ exports.DashboardIcon = DashboardIcon;
2235
+ exports.DashboardPage = DashboardPage;
2236
+ exports.DeleteIcon = DeleteIcon;
2237
+ exports.DownloadIcon = DownloadIcon;
2238
+ exports.EmailEntry = EmailEntry;
2239
+ exports.EmailIcon = EmailIcon;
2240
+ exports.FilterIcon = FilterIcon;
2241
+ exports.Layout = Layout;
2242
+ exports.LoadingSpinner = LoadingSpinner;
2243
+ exports.LogoInline = LogoInline;
2244
+ exports.Pagination = Pagination;
2245
+ exports.PaymentCancelView = PaymentCancelView;
2246
+ exports.PaymentSuccessView = PaymentSuccessView;
2247
+ exports.PlanCard = PlanCard;
2248
+ exports.PlanSelector = PlanSelector;
2249
+ exports.PlansGrid = PlansGrid;
2250
+ exports.ReceiptIcon = ReceiptIcon;
2251
+ exports.SearchIcon = SearchIcon;
2252
+ exports.StarBorderIcon = StarBorderIcon;
2253
+ exports.SubscriptionDetails = SubscriptionDetails;
2254
+ exports.TierFilterDropdown = TierFilterDropdown;
2255
+ exports.TransactionList = TransactionList;
2256
+ exports.TransactionModal = TransactionModal;
2257
+ exports.TrendingUpIcon = TrendingUpIcon;
2258
+ exports.UpgradeIcon = UpgradeIcon;
2259
+ exports.UpgradeSummary = UpgradeSummary;
2260
+ exports.checkoutApi = checkoutApi;
2261
+ exports.configureSubOS = configureSubOS;
2262
+ exports.customerApi = customerApi;
2263
+ exports.ensureSubOSConfig = ensureSubOSConfig;
2264
+ exports.filterPlansByBillingCycle = filterPlansByBillingCycle;
2265
+ exports.filterPlansByTier = filterPlansByTier;
2266
+ exports.formatDate = formatDate;
2267
+ exports.getApiBaseUrl = getApiBaseUrl;
2268
+ exports.getCandidateUnits = getCandidateUnits;
2269
+ exports.getCurrentSelectionText = getCurrentSelectionText;
2270
+ exports.getDropdownOptions = getDropdownOptions;
2271
+ exports.getPlanDescription = getPlanDescription;
2272
+ exports.getPlanFeatures = getPlanFeatures;
2273
+ exports.getProjectId = getProjectId;
2274
+ exports.getStripePublishableKey = getStripePublishableKey;
2275
+ exports.getUniqueCandidateUnits = getUniqueCandidateUnits;
2276
+ exports.isPlanPopular = isPlanPopular;
2277
+ exports.plansApi = plansApi;
2278
+ exports.subscriptionApi = subscriptionApi;
2279
+ exports.transactionApi = transactionApi;
2280
+ exports.useCancelSubscription = useCancelSubscription;
2281
+ exports.useCustomerPortal = useCustomerPortal;
2282
+ exports.useEmailManagement = useEmailManagement;
2283
+ exports.usePagination = usePagination;
2284
+ exports.usePlans = usePlans;
2285
+ exports.useSubscription = useSubscription;
2286
+ exports.useTransactions = useTransactions;
2287
+ exports.validateSubOSConfig = validateSubOSConfig;
2288
+ //# sourceMappingURL=index.js.map
2289
+ //# sourceMappingURL=index.js.map