@umituz/web-dashboard 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/web-dashboard",
3
- "version": "2.3.0",
3
+ "version": "2.4.1",
4
4
  "description": "Dashboard Layout System - Customizable, themeable dashboard layouts and settings",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -4,7 +4,7 @@
4
4
  * Configurable analytics page layout with KPIs and charts
5
5
  */
6
6
 
7
- import { RefreshCw, Download, Calendar } from "lucide-react";
7
+ import { RefreshCw, Download, Calendar, Loader2 } from "lucide-react";
8
8
  import { cn } from "@umituz/web-design-system/utils";
9
9
  import { Button } from "@umituz/web-design-system/atoms";
10
10
  import type { AnalyticsLayoutProps } from "../types/analytics";
@@ -13,11 +13,16 @@ import { MetricCard } from "./MetricCard";
13
13
  import { getDateRangePresets } from "../utils/analytics";
14
14
 
15
15
  export const AnalyticsLayout = ({
16
+ config,
16
17
  title,
17
18
  description,
19
+ metrics,
20
+ loading = false,
21
+ period,
22
+ onPeriodChange,
18
23
  showDateRange = true,
19
- showRefresh = true,
20
- showExport = true,
24
+ showRefresh,
25
+ showExport,
21
26
  kpis,
22
27
  charts,
23
28
  headerContent,
@@ -35,38 +40,50 @@ export const AnalyticsLayout = ({
35
40
  console.log("Refreshing analytics data...");
36
41
  };
37
42
 
43
+ // Use config settings if props not provided
44
+ const _showRefresh = showRefresh ?? config?.showRefresh ?? true;
45
+ const _showExport = showExport ?? config?.showExport ?? true;
46
+
38
47
  return (
39
48
  <div className="w-full space-y-6">
40
49
  {/* Header */}
41
50
  <div className="flex items-center justify-between">
42
51
  <div>
43
- {title && <h1 className="text-3xl font-bold text-foreground">{title}</h1>}
52
+ {(title || config?.brandName) && (
53
+ <h1 className="text-3xl font-bold text-foreground">
54
+ {title || `${config?.brandName || ''} Analytics`}
55
+ </h1>
56
+ )}
44
57
  {description && <p className="text-muted-foreground mt-1">{description}</p>}
45
58
  </div>
46
59
 
47
60
  {/* Actions */}
48
61
  <div className="flex items-center gap-3">
49
- {showDateRange && (
62
+ {showDateRange && onPeriodChange && (
50
63
  <div className="flex items-center gap-2 bg-background border border-border rounded-lg px-3 py-2">
51
64
  <Calendar className="h-4 w-4 text-muted-foreground" />
52
- <select className="bg-transparent text-sm text-foreground outline-none">
53
- {dateRangePresets.map((preset) => (
54
- <option key={preset.value} value={preset.value}>
55
- {preset.label}
65
+ <select
66
+ className="bg-transparent text-sm text-foreground outline-none"
67
+ value={period}
68
+ onChange={(e) => onPeriodChange(e.target.value)}
69
+ >
70
+ {config?.availablePeriods?.map((p) => (
71
+ <option key={p} value={p}>
72
+ {p === "7d" ? "7 Days" : p === "30d" ? "30 Days" : p === "90d" ? "90 Days" : p}
56
73
  </option>
57
74
  ))}
58
75
  </select>
59
76
  </div>
60
77
  )}
61
78
 
62
- {showRefresh && (
63
- <Button variant="ghost" size="sm" onClick={handleRefresh}>
64
- <RefreshCw className="h-4 w-4" />
79
+ {_showRefresh && (
80
+ <Button variant="ghost" size="sm" onClick={handleRefresh} disabled={loading}>
81
+ <RefreshCw className={cn("h-4 w-4", loading && "animate-spin")} />
65
82
  </Button>
66
83
  )}
67
84
 
68
- {showExport && (
69
- <Button variant="ghost" size="sm" onClick={handleExport}>
85
+ {_showExport && (
86
+ <Button variant="ghost" size="sm" onClick={handleExport} disabled={loading}>
70
87
  <Download className="h-4 w-4" />
71
88
  Export
72
89
  </Button>
@@ -76,59 +93,78 @@ export const AnalyticsLayout = ({
76
93
  </div>
77
94
  </div>
78
95
 
79
- {/* KPI Cards */}
80
- {kpis && (
81
- <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4">
82
- <MetricCard
83
- metric={{
84
- id: "downloads",
85
- name: "Downloads",
86
- value: kpis.downloads.current,
87
- previousValue: kpis.downloads.previous,
88
- unit: "K",
89
- }}
90
- />
91
- <MetricCard
92
- metric={{
93
- id: "engagement",
94
- name: "Engagement",
95
- value: kpis.engagement.current,
96
- previousValue: kpis.engagement.previous,
97
- unit: "%",
98
- }}
99
- />
100
- <MetricCard
101
- metric={{
102
- id: "users",
103
- name: "Users",
104
- value: kpis.users.current,
105
- previousValue: kpis.users.previous,
106
- unit: "K",
107
- }}
108
- />
109
- <MetricCard
110
- metric={{
111
- id: "revenue",
112
- name: "Revenue",
113
- value: kpis.revenue.current,
114
- previousValue: kpis.revenue.previous,
115
- unit: "$",
116
- }}
117
- />
118
- <MetricCard
119
- metric={{
120
- id: "retention",
121
- name: "Retention",
122
- value: kpis.retention.current,
123
- previousValue: kpis.retention.previous,
124
- unit: "%",
125
- }}
126
- />
96
+ {/* Loading State */}
97
+ {loading && (
98
+ <div className="flex items-center justify-center py-24">
99
+ <Loader2 className="h-12 w-12 animate-spin text-muted-foreground" />
100
+ </div>
101
+ )}
102
+
103
+ {/* Metrics / KPI Cards */}
104
+ {!loading && (metrics || kpis) && (
105
+ <div className={cn(
106
+ "grid gap-4",
107
+ (metrics || kpis) && "grid-cols-1 sm:grid-cols-2 lg:grid-cols-5"
108
+ )}>
109
+ {metrics?.map((metric) => (
110
+ <MetricCard key={metric.id} metric={metric} />
111
+ ))}
112
+
113
+ {/* Legacy kpis support */}
114
+ {kpis && !metrics && (
115
+ <>
116
+ <MetricCard
117
+ metric={{
118
+ id: "downloads",
119
+ name: "Downloads",
120
+ value: kpis.downloads.current,
121
+ previousValue: kpis.downloads.previous,
122
+ unit: "K",
123
+ }}
124
+ />
125
+ <MetricCard
126
+ metric={{
127
+ id: "engagement",
128
+ name: "Engagement",
129
+ value: kpis.engagement.current,
130
+ previousValue: kpis.engagement.previous,
131
+ unit: "%",
132
+ }}
133
+ />
134
+ <MetricCard
135
+ metric={{
136
+ id: "users",
137
+ name: "Users",
138
+ value: kpis.users.current,
139
+ previousValue: kpis.users.previous,
140
+ unit: "K",
141
+ }}
142
+ />
143
+ <MetricCard
144
+ metric={{
145
+ id: "revenue",
146
+ name: "Revenue",
147
+ value: kpis.revenue.current,
148
+ previousValue: kpis.revenue.previous,
149
+ unit: "$",
150
+ }}
151
+ />
152
+ <MetricCard
153
+ metric={{
154
+ id: "retention",
155
+ name: "Retention",
156
+ value: kpis.retention.current,
157
+ previousValue: kpis.retention.previous,
158
+ unit: "%",
159
+ }}
160
+ />
161
+ </>
162
+ )}
127
163
  </div>
128
164
  )}
129
165
 
130
166
  {/* Charts */}
131
- {charts && charts.length > 0 && (
167
+ {!loading && charts && charts.length > 0 && (
132
168
  <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
133
169
  {charts.map((chartConfig, index) => (
134
170
  <AnalyticsCard
@@ -142,7 +178,7 @@ export const AnalyticsLayout = ({
142
178
  )}
143
179
 
144
180
  {/* Custom Content */}
145
- {children}
181
+ {!loading && children}
146
182
  </div>
147
183
  );
148
184
  };
@@ -225,10 +225,20 @@ export interface AnalyticsCardProps {
225
225
  * Analytics layout props
226
226
  */
227
227
  export interface AnalyticsLayoutProps {
228
+ /** Analytics configuration */
229
+ config?: AnalyticsConfig;
228
230
  /** Page title */
229
231
  title?: string;
230
232
  /** Page description */
231
233
  description?: string;
234
+ /** Metrics data */
235
+ metrics?: Metric[];
236
+ /** Loading state */
237
+ loading?: boolean;
238
+ /** Current period */
239
+ period?: string;
240
+ /** Period change handler */
241
+ onPeriodChange?: (period: string) => void;
232
242
  /** Date range selector */
233
243
  showDateRange?: boolean;
234
244
  /** Refresh button */
@@ -289,3 +299,38 @@ export interface AnalyticsExportOptions {
289
299
  /** Filename */
290
300
  filename?: string;
291
301
  }
302
+
303
+ /**
304
+ * Analytics configuration
305
+ */
306
+ export interface AnalyticsConfig {
307
+ /** Brand/application name */
308
+ brandName: string;
309
+ /** Default period selection */
310
+ defaultPeriod?: string;
311
+ /** Available period options */
312
+ availablePeriods?: string[];
313
+ /** Show export button */
314
+ showExport?: boolean;
315
+ /** Show refresh button */
316
+ showRefresh?: boolean;
317
+ /** Enable real-time updates */
318
+ enableRealTime?: boolean;
319
+ /** Metrics configuration */
320
+ metrics?: MetricConfig[];
321
+ }
322
+
323
+ /**
324
+ * Metric configuration
325
+ */
326
+ export interface MetricConfig {
327
+ /** Metric identifier */
328
+ id: string;
329
+ /** Metric name */
330
+ name: string;
331
+ /** Unit type */
332
+ unit?: string;
333
+ /** Icon identifier */
334
+ icon?: string;
335
+ }
336
+
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import { BrandLogo } from "../../layouts/components";
8
+ import { cn } from "@umituz/web-design-system/utils";
8
9
  import type { AuthLayoutProps } from "../types/auth";
9
10
 
10
11
  export const AuthLayout = ({
@@ -18,8 +18,11 @@ export const LoginForm = ({
18
18
  showRememberMe = true,
19
19
  showForgotPassword = true,
20
20
  showRegisterLink = true,
21
+ showSocialLogin,
21
22
  onLoginSuccess,
22
23
  onLoginError,
24
+ onGoogleLogin,
25
+ onAppleLogin,
23
26
  }: LoginFormProps) => {
24
27
  const navigate = useNavigate();
25
28
  const [email, setEmail] = useState(defaultCredentials.email || "");
@@ -221,6 +224,62 @@ export const LoginForm = ({
221
224
  </button>
222
225
  </p>
223
226
  )}
227
+
228
+ {/* Social Login */}
229
+ {showSocialLogin && config.showSocialLogin && config.socialProviders && config.socialProviders.length > 0 && (
230
+ <>
231
+ {/* Divider */}
232
+ <div className="relative">
233
+ <div className="absolute inset-0 flex items-center">
234
+ <div className="w-full border-t border-border" />
235
+ </div>
236
+ <div className="relative flex justify-center text-sm">
237
+ <span className="px-2 bg-background text-muted-foreground">
238
+ Or continue with
239
+ </span>
240
+ </div>
241
+ </div>
242
+
243
+ {/* Social Buttons */}
244
+ <div className="grid grid-cols-2 gap-3">
245
+ {config.socialProviders.map((provider) => (
246
+ <button
247
+ key={provider.id}
248
+ type="button"
249
+ className={cn(
250
+ "flex items-center justify-center gap-2 px-4 py-3 rounded-lg border",
251
+ "bg-background hover:bg-muted transition-colors",
252
+ "text-sm font-medium text-foreground",
253
+ isLoading && "opacity-50 cursor-not-allowed"
254
+ )}
255
+ onClick={async () => {
256
+ if (provider.id === "google" && onGoogleLogin) {
257
+ await onGoogleLogin();
258
+ } else if (provider.id === "apple" && onAppleLogin) {
259
+ await onAppleLogin();
260
+ }
261
+ }}
262
+ disabled={isLoading}
263
+ >
264
+ {provider.icon === "google" && (
265
+ <svg width="18" height="18" viewBox="0 0 24 24">
266
+ <path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill="#4285F4"/>
267
+ <path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/>
268
+ <path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/>
269
+ <path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/>
270
+ </svg>
271
+ )}
272
+ {provider.icon === "apple" && (
273
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" className="text-foreground">
274
+ <path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8.3-3.12 1.38-5.98 0-8.1-3.12-1.87-3.12-3.28-8.1.3-8.1.8-1.06 0-2.29.44-3.06.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
275
+ </svg>
276
+ )}
277
+ <span>{provider.name}</span>
278
+ </button>
279
+ ))}
280
+ </div>
281
+ </>
282
+ )}
224
283
  </form>
225
284
  );
226
285
  };
@@ -18,8 +18,11 @@ export const RegisterForm = ({
18
18
  showTerms = true,
19
19
  showLoginLink = true,
20
20
  requirePasswordConfirm = true,
21
+ showSocialLogin,
21
22
  onRegisterSuccess,
22
23
  onRegisterError,
24
+ onGoogleLogin,
25
+ onAppleLogin,
23
26
  }: RegisterFormProps) => {
24
27
  const navigate = useNavigate();
25
28
  const [name, setName] = useState(defaultData.name || "");
@@ -289,6 +292,62 @@ export const RegisterForm = ({
289
292
  </button>
290
293
  </p>
291
294
  )}
295
+
296
+ {/* Social Login */}
297
+ {showSocialLogin && config.showSocialLogin && config.socialProviders && config.socialProviders.length > 0 && (
298
+ <>
299
+ {/* Divider */}
300
+ <div className="relative">
301
+ <div className="absolute inset-0 flex items-center">
302
+ <div className="w-full border-t border-border" />
303
+ </div>
304
+ <div className="relative flex justify-center text-sm">
305
+ <span className="px-2 bg-background text-muted-foreground">
306
+ Or continue with
307
+ </span>
308
+ </div>
309
+ </div>
310
+
311
+ {/* Social Buttons */}
312
+ <div className="grid grid-cols-2 gap-3">
313
+ {config.socialProviders.map((provider) => (
314
+ <button
315
+ key={provider.id}
316
+ type="button"
317
+ className={cn(
318
+ "flex items-center justify-center gap-2 px-4 py-3 rounded-lg border",
319
+ "bg-background hover:bg-muted transition-colors",
320
+ "text-sm font-medium text-foreground",
321
+ isLoading && "opacity-50 cursor-not-allowed"
322
+ )}
323
+ onClick={async () => {
324
+ if (provider.id === "google" && onGoogleLogin) {
325
+ await onGoogleLogin();
326
+ } else if (provider.id === "apple" && onAppleLogin) {
327
+ await onAppleLogin();
328
+ }
329
+ }}
330
+ disabled={isLoading}
331
+ >
332
+ {provider.icon === "google" && (
333
+ <svg width="18" height="18" viewBox="0 0 24 24">
334
+ <path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill="#4285F4"/>
335
+ <path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/>
336
+ <path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/>
337
+ <path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/>
338
+ </svg>
339
+ )}
340
+ {provider.icon === "apple" && (
341
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" className="text-foreground">
342
+ <path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8.3-3.12 1.38-5.98 0-8.1-3.12-1.87-3.12-3.28-8.1.3-8.1.8-1.06 0-2.29.44-3.06.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
343
+ </svg>
344
+ )}
345
+ <span>{provider.name}</span>
346
+ </button>
347
+ ))}
348
+ </div>
349
+ </>
350
+ )}
292
351
  </form>
293
352
  );
294
353
  };
@@ -210,10 +210,16 @@ export interface LoginFormProps {
210
210
  showForgotPassword?: boolean;
211
211
  /** Show register link */
212
212
  showRegisterLink?: boolean;
213
+ /** Show social login buttons */
214
+ showSocialLogin?: boolean;
213
215
  /** On successful login */
214
216
  onLoginSuccess?: (user: User) => void | Promise<void>;
215
217
  /** On login error */
216
218
  onLoginError?: (error: string) => void;
219
+ /** Google login handler */
220
+ onGoogleLogin?: () => void | Promise<void>;
221
+ /** Apple login handler */
222
+ onAppleLogin?: () => void | Promise<void>;
217
223
  }
218
224
 
219
225
  /**
@@ -230,10 +236,16 @@ export interface RegisterFormProps {
230
236
  showLoginLink?: boolean;
231
237
  /** Require password confirmation */
232
238
  requirePasswordConfirm?: boolean;
239
+ /** Show social login buttons */
240
+ showSocialLogin?: boolean;
233
241
  /** On successful registration */
234
242
  onRegisterSuccess?: (user: User) => void | Promise<void>;
235
243
  /** On registration error */
236
244
  onRegisterError?: (error: string) => void;
245
+ /** Google login handler */
246
+ onGoogleLogin?: () => void | Promise<void>;
247
+ /** Apple login handler */
248
+ onAppleLogin?: () => void | Promise<void>;
237
249
  }
238
250
 
239
251
  /**
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Billing Constants
3
+ *
4
+ * Centralized constants for billing domain to avoid hardcoded strings
5
+ */
6
+
7
+ /**
8
+ * Subscription status constants
9
+ */
10
+ export const SUBSCRIPTION_STATUS = {
11
+ ACTIVE: "active",
12
+ TRIALING: "trialing",
13
+ PAST_DUE: "past_due",
14
+ CANCELED: "canceled",
15
+ UNPAID: "unpaid",
16
+ INCOMPLETE: "incomplete",
17
+ REVOKED: "revoked",
18
+ } as const;
19
+
20
+ export type SubscriptionStatus = typeof SUBSCRIPTION_STATUS[keyof typeof SUBSCRIPTION_STATUS];
21
+
22
+ /**
23
+ * Invoice status constants
24
+ */
25
+ export const INVOICE_STATUS = {
26
+ DRAFT: "draft",
27
+ OPEN: "open",
28
+ PAID: "paid",
29
+ VOID: "void",
30
+ UNCOLLECTIBLE: "uncollectible",
31
+ REFUNDED: "refunded",
32
+ } as const;
33
+
34
+ export type InvoiceStatus = typeof INVOICE_STATUS[keyof typeof INVOICE_STATUS];
35
+
36
+ /**
37
+ * Billing cycle constants
38
+ */
39
+ export const BILLING_CYCLE = {
40
+ MONTHLY: "monthly",
41
+ YEARLY: "yearly",
42
+ } as const;
43
+
44
+ export type BillingCycle = typeof BILLING_CYCLE[keyof typeof BILLING_CYCLE];
45
+
46
+ /**
47
+ * Currency constants
48
+ */
49
+ export const CURRENCY = {
50
+ USD: "USD",
51
+ EUR: "EUR",
52
+ GBP: "GBP",
53
+ TRY: "TRY",
54
+ JPY: "JPY",
55
+ } as const;
56
+
57
+ export type Currency = typeof CURRENCY[keyof typeof CURRENCY];
58
+
59
+ /**
60
+ * Plan type constants
61
+ */
62
+ export const PLAN_TYPE = {
63
+ STANDARD: "standard",
64
+ PRO: "pro",
65
+ BUSINESS: "business",
66
+ ENTERPRISE: "enterprise",
67
+ } as const;
68
+
69
+ export type PlanType = typeof PLAN_TYPE[keyof typeof PLAN_TYPE];
@@ -5,22 +5,22 @@
5
5
  */
6
6
 
7
7
  import type { ComponentType, ReactElement } from "react";
8
+ import { SUBSCRIPTION_STATUS, INVOICE_STATUS, BILLING_CYCLE, CURRENCY } from "../constants/billing";
8
9
 
9
10
  /**
10
11
  * Billing cycle
11
12
  */
12
- export type BillingCycle = "monthly" | "yearly";
13
+ export type BillingCycle = typeof BILLING_CYCLE[keyof typeof BILLING_CYCLE];
13
14
 
14
15
  /**
15
16
  * Subscription status
16
17
  */
17
- export type SubscriptionStatus =
18
- | "active"
19
- | "trialing"
20
- | "past_due"
21
- | "canceled"
22
- | "unpaid"
23
- | "incomplete";
18
+ export type SubscriptionStatus = typeof SUBSCRIPTION_STATUS[keyof typeof SUBSCRIPTION_STATUS];
19
+
20
+ /**
21
+ * Invoice status
22
+ */
23
+ export type InvoiceStatus = typeof INVOICE_STATUS[keyof typeof INVOICE_STATUS];
24
24
 
25
25
  /**
26
26
  * Plan type
@@ -30,7 +30,7 @@ export type PlanType = "free" | "basic" | "pro" | "enterprise" | "custom";
30
30
  /**
31
31
  * Currency
32
32
  */
33
- export type Currency = "USD" | "EUR" | "GBP" | "TRY" | "JPY";
33
+ export type Currency = typeof CURRENCY[keyof typeof CURRENCY];
34
34
 
35
35
  /**
36
36
  * Plan pricing tier
@@ -133,11 +133,6 @@ export interface PaymentMethod {
133
133
  createdAt: string;
134
134
  }
135
135
 
136
- /**
137
- * Invoice status
138
- */
139
- export type InvoiceStatus = "draft" | "open" "paid" "void" "uncollectible";
140
-
141
136
  /**
142
137
  * Invoice item
143
138
  */