@kuraykaraaslan/kui-react 1.0.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/LICENSE +17 -0
- package/README.md +168 -0
- package/dist/AdvancedDataTable-F3DNXDKX.mjs +11 -0
- package/dist/DataTable-2G27T4E6.mjs +11 -0
- package/dist/DateRangePicker-AL32QB6L.mjs +11 -0
- package/dist/DropdownMenu-f5yV9dzM.d.mts +22 -0
- package/dist/DropdownMenu-f5yV9dzM.d.ts +22 -0
- package/dist/MapView-FERKPCDB.mjs +10 -0
- package/dist/ServerDataTable-RZV3K6KQ.mjs +11 -0
- package/dist/Tooltip-Bof5GvOc.d.mts +248 -0
- package/dist/Tooltip-Bof5GvOc.d.ts +248 -0
- package/dist/VideoPlayer-P3I6ESXJ.mjs +9 -0
- package/dist/app.d.mts +620 -0
- package/dist/app.d.ts +620 -0
- package/dist/app.js +7061 -0
- package/dist/app.mjs +100 -0
- package/dist/chunk-24BCQSLI.mjs +1 -0
- package/dist/chunk-45I3EDB2.mjs +90 -0
- package/dist/chunk-4IWCD7ID.mjs +1450 -0
- package/dist/chunk-5E2HXWFI.mjs +105 -0
- package/dist/chunk-C7AYI4XM.mjs +402 -0
- package/dist/chunk-J4D44TUA.mjs +1267 -0
- package/dist/chunk-KTEWZKNE.mjs +1020 -0
- package/dist/chunk-LMUQHL4Z.mjs +3829 -0
- package/dist/chunk-MD5OQ4J2.mjs +527 -0
- package/dist/chunk-MPJRPYIZ.mjs +1 -0
- package/dist/chunk-MPWUEQ7J.mjs +2422 -0
- package/dist/chunk-MTT5TKAJ.mjs +93 -0
- package/dist/chunk-RBDK7MWQ.mjs +46 -0
- package/dist/chunk-SVFQZPNZ.mjs +3648 -0
- package/dist/chunk-TZWBBMSG.mjs +1 -0
- package/dist/chunk-XA7J6PVJ.mjs +1488 -0
- package/dist/chunk-ZLYBRYWQ.mjs +726 -0
- package/dist/common.d.mts +921 -0
- package/dist/common.d.ts +921 -0
- package/dist/common.js +4991 -0
- package/dist/common.mjs +172 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +17563 -0
- package/dist/index.mjs +349 -0
- package/dist/ui.d.mts +937 -0
- package/dist/ui.d.ts +937 -0
- package/dist/ui.js +10095 -0
- package/dist/ui.mjs +163 -0
- package/package.json +114 -0
- package/styles/index.css +129 -0
|
@@ -0,0 +1,3648 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
Input,
|
|
4
|
+
RadioGroup,
|
|
5
|
+
Textarea,
|
|
6
|
+
Toggle
|
|
7
|
+
} from "./chunk-C7AYI4XM.mjs";
|
|
8
|
+
import {
|
|
9
|
+
Form,
|
|
10
|
+
ThemeSwitcher,
|
|
11
|
+
isBrowser
|
|
12
|
+
} from "./chunk-45I3EDB2.mjs";
|
|
13
|
+
import {
|
|
14
|
+
Avatar,
|
|
15
|
+
Badge,
|
|
16
|
+
DropdownMenu,
|
|
17
|
+
Select,
|
|
18
|
+
TagInput
|
|
19
|
+
} from "./chunk-ZLYBRYWQ.mjs";
|
|
20
|
+
import {
|
|
21
|
+
Button
|
|
22
|
+
} from "./chunk-MTT5TKAJ.mjs";
|
|
23
|
+
import {
|
|
24
|
+
__spreadProps,
|
|
25
|
+
__spreadValues,
|
|
26
|
+
cn
|
|
27
|
+
} from "./chunk-RBDK7MWQ.mjs";
|
|
28
|
+
|
|
29
|
+
// modules/domains/common/types.ts
|
|
30
|
+
import { z as z2 } from "zod";
|
|
31
|
+
|
|
32
|
+
// modules/domains/common/I18nTypes.ts
|
|
33
|
+
import { z } from "zod";
|
|
34
|
+
import ISO6391 from "iso-639-1";
|
|
35
|
+
var _a;
|
|
36
|
+
var parsedEnvLangs = (_a = process.env.NEXT_PUBLIC_I18N_LANGUAGES) == null ? void 0 : _a.split(",").map((l) => l.trim().toLowerCase()).filter((l) => ISO6391.validate(l));
|
|
37
|
+
var FALLBACK_LANGS = ["en"];
|
|
38
|
+
var AppLanguageEnum = z.enum(
|
|
39
|
+
parsedEnvLangs && parsedEnvLangs.length > 0 ? parsedEnvLangs : FALLBACK_LANGS
|
|
40
|
+
);
|
|
41
|
+
var AVAILABLE_LANGUAGES = AppLanguageEnum.options;
|
|
42
|
+
var _a2;
|
|
43
|
+
var DEFAULT_LANGUAGE = (_a2 = AVAILABLE_LANGUAGES[0]) != null ? _a2 : "en";
|
|
44
|
+
var RTL_SET = /* @__PURE__ */ new Set(["ar", "he", "fa", "ur"]);
|
|
45
|
+
function isRTL(lang) {
|
|
46
|
+
return RTL_SET.has(lang);
|
|
47
|
+
}
|
|
48
|
+
function getDirection(lang) {
|
|
49
|
+
return isRTL(lang) ? "rtl" : "ltr";
|
|
50
|
+
}
|
|
51
|
+
function getLanguageName(lang) {
|
|
52
|
+
return ISO6391.getName(lang) || lang;
|
|
53
|
+
}
|
|
54
|
+
var LANG_NAMES = Object.fromEntries(
|
|
55
|
+
AVAILABLE_LANGUAGES.map((lang) => [
|
|
56
|
+
lang,
|
|
57
|
+
ISO6391.getName(lang) || lang
|
|
58
|
+
])
|
|
59
|
+
);
|
|
60
|
+
function langToCountry(lang) {
|
|
61
|
+
return lang.length === 2 ? lang.toUpperCase() : "US";
|
|
62
|
+
}
|
|
63
|
+
function countryCodeToEmoji(code) {
|
|
64
|
+
return code.toUpperCase().replace(
|
|
65
|
+
/./g,
|
|
66
|
+
(char) => String.fromCodePoint(127397 + char.charCodeAt(0))
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
function getLangFlag(lang) {
|
|
70
|
+
return countryCodeToEmoji(langToCountry(lang));
|
|
71
|
+
}
|
|
72
|
+
var LANG_FLAGS = Object.fromEntries(
|
|
73
|
+
AVAILABLE_LANGUAGES.map((lang) => [lang, getLangFlag(lang)])
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// modules/domains/common/types.ts
|
|
77
|
+
var IdSchema = z2.string().min(1);
|
|
78
|
+
var UuidSchema = z2.uuid();
|
|
79
|
+
var SlugSchema = z2.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
|
|
80
|
+
var DateSchema = z2.coerce.date();
|
|
81
|
+
var NullableDateSchema = z2.coerce.date().nullable().optional();
|
|
82
|
+
var EmailSchema = z2.email();
|
|
83
|
+
var PasswordSchema = z2.string().min(8);
|
|
84
|
+
var SortOrderEnum = z2.enum(["asc", "desc"]);
|
|
85
|
+
var StatusEnum = z2.enum([
|
|
86
|
+
"ACTIVE",
|
|
87
|
+
"INACTIVE",
|
|
88
|
+
"DRAFT",
|
|
89
|
+
"PUBLISHED",
|
|
90
|
+
"ARCHIVED"
|
|
91
|
+
]);
|
|
92
|
+
var BaseEntitySchema = z2.object({
|
|
93
|
+
createdAt: DateSchema.optional(),
|
|
94
|
+
updatedAt: NullableDateSchema,
|
|
95
|
+
deletedAt: NullableDateSchema
|
|
96
|
+
});
|
|
97
|
+
var PaginationSchema = z2.object({
|
|
98
|
+
page: z2.coerce.number().int().positive().default(1),
|
|
99
|
+
limit: z2.coerce.number().int().positive().max(100).default(20)
|
|
100
|
+
});
|
|
101
|
+
var ApiSuccessSchema = z2.object({
|
|
102
|
+
success: z2.literal(true),
|
|
103
|
+
message: z2.string().optional()
|
|
104
|
+
});
|
|
105
|
+
var ApiErrorSchema = z2.object({
|
|
106
|
+
success: z2.literal(false),
|
|
107
|
+
message: z2.string(),
|
|
108
|
+
code: z2.string().optional(),
|
|
109
|
+
errors: z2.array(z2.object({
|
|
110
|
+
field: z2.string(),
|
|
111
|
+
message: z2.string()
|
|
112
|
+
})).optional()
|
|
113
|
+
});
|
|
114
|
+
var ApiResponseSchema = z2.union([
|
|
115
|
+
ApiSuccessSchema,
|
|
116
|
+
ApiErrorSchema
|
|
117
|
+
]);
|
|
118
|
+
var UserRoleEnum = z2.enum(["ADMIN", "AUTHOR", "USER"]);
|
|
119
|
+
var UserStatusEnum = z2.enum(["ACTIVE", "INACTIVE", "BANNED"]);
|
|
120
|
+
var ThemeEnum = z2.enum(["LIGHT", "DARK", "SYSTEM"]);
|
|
121
|
+
var LanguageEnum = z2.enum(["en"]);
|
|
122
|
+
var UserPreferencesSchema = z2.object({
|
|
123
|
+
theme: ThemeEnum.default("SYSTEM"),
|
|
124
|
+
language: AppLanguageEnum.default("en"),
|
|
125
|
+
emailNotifications: z2.boolean().default(true),
|
|
126
|
+
pushNotifications: z2.boolean().default(true),
|
|
127
|
+
newsletter: z2.boolean().default(true),
|
|
128
|
+
timezone: z2.string().default("UTC")
|
|
129
|
+
});
|
|
130
|
+
var UserProfileSchema = z2.object({
|
|
131
|
+
name: z2.string().nullable().optional(),
|
|
132
|
+
username: z2.string().nullable().optional(),
|
|
133
|
+
biography: z2.string().nullable().optional(),
|
|
134
|
+
profilePicture: z2.string().nullable().optional()
|
|
135
|
+
});
|
|
136
|
+
var UserSchema = z2.object({
|
|
137
|
+
userId: IdSchema,
|
|
138
|
+
email: EmailSchema,
|
|
139
|
+
phone: z2.string().nullable().optional(),
|
|
140
|
+
password: PasswordSchema,
|
|
141
|
+
userRole: UserRoleEnum.default("USER"),
|
|
142
|
+
userStatus: UserStatusEnum.default("ACTIVE"),
|
|
143
|
+
userPreferences: UserPreferencesSchema.optional(),
|
|
144
|
+
userProfile: UserProfileSchema.optional(),
|
|
145
|
+
createdAt: DateSchema.optional(),
|
|
146
|
+
updatedAt: DateSchema.optional(),
|
|
147
|
+
deletedAt: NullableDateSchema
|
|
148
|
+
});
|
|
149
|
+
var SafeUserSchema = UserSchema.omit({
|
|
150
|
+
password: true
|
|
151
|
+
});
|
|
152
|
+
var LoginRequestSchema = z2.object({
|
|
153
|
+
email: EmailSchema,
|
|
154
|
+
password: PasswordSchema
|
|
155
|
+
});
|
|
156
|
+
var RegisterRequestSchema = z2.object({
|
|
157
|
+
email: EmailSchema,
|
|
158
|
+
password: PasswordSchema,
|
|
159
|
+
confirmPassword: z2.string()
|
|
160
|
+
}).refine((d) => d.password === d.confirmPassword, {
|
|
161
|
+
message: "Passwords don't match",
|
|
162
|
+
path: ["confirmPassword"]
|
|
163
|
+
});
|
|
164
|
+
var ChangePasswordSchema = z2.object({
|
|
165
|
+
currentPassword: z2.string(),
|
|
166
|
+
newPassword: PasswordSchema,
|
|
167
|
+
confirmPassword: z2.string()
|
|
168
|
+
}).refine((d) => d.newPassword === d.confirmPassword, {
|
|
169
|
+
message: "Passwords don't match",
|
|
170
|
+
path: ["confirmPassword"]
|
|
171
|
+
});
|
|
172
|
+
var AuthSessionSchema = z2.object({
|
|
173
|
+
sessionId: IdSchema,
|
|
174
|
+
userId: IdSchema,
|
|
175
|
+
token: z2.string(),
|
|
176
|
+
refreshToken: z2.string().optional(),
|
|
177
|
+
expiresAt: DateSchema,
|
|
178
|
+
createdAt: DateSchema
|
|
179
|
+
});
|
|
180
|
+
var AuthResponseSchema = z2.object({
|
|
181
|
+
success: z2.boolean(),
|
|
182
|
+
message: z2.string(),
|
|
183
|
+
token: z2.string().optional(),
|
|
184
|
+
refreshToken: z2.string().optional(),
|
|
185
|
+
user: SafeUserSchema.optional()
|
|
186
|
+
});
|
|
187
|
+
var OAuthProviderEnum = z2.enum([
|
|
188
|
+
"GOOGLE",
|
|
189
|
+
"GITHUB",
|
|
190
|
+
"DISCORD",
|
|
191
|
+
"MICROSOFT"
|
|
192
|
+
]);
|
|
193
|
+
var OAuthCallbackSchema = z2.object({
|
|
194
|
+
code: z2.string(),
|
|
195
|
+
state: z2.string().optional(),
|
|
196
|
+
provider: OAuthProviderEnum
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// modules/domains/common/address/AddressCard.tsx
|
|
200
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
201
|
+
import { faLocationDot, faPhone, faUser } from "@fortawesome/free-solid-svg-icons";
|
|
202
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
203
|
+
function AddressCard({ address, onEdit, onDelete, selected = false, className }) {
|
|
204
|
+
const cityLine = [address.city, address.state, address.postalCode].filter(Boolean).join(", ");
|
|
205
|
+
const countryLine = [address.country, address.countryCode ? `(${address.countryCode})` : ""].filter(Boolean).join(" ");
|
|
206
|
+
const selectable = selected !== void 0;
|
|
207
|
+
return /* @__PURE__ */ jsxs(
|
|
208
|
+
"div",
|
|
209
|
+
{
|
|
210
|
+
className: cn(
|
|
211
|
+
"relative rounded-lg border bg-surface-raised p-4 space-y-2 transition-colors",
|
|
212
|
+
selectable && selected ? "border-primary ring-2 ring-primary ring-offset-1" : "border-border",
|
|
213
|
+
className
|
|
214
|
+
),
|
|
215
|
+
children: [
|
|
216
|
+
selectable && /* @__PURE__ */ jsx(
|
|
217
|
+
"span",
|
|
218
|
+
{
|
|
219
|
+
"aria-hidden": "true",
|
|
220
|
+
className: cn(
|
|
221
|
+
"absolute top-3 right-3 flex h-4 w-4 items-center justify-center rounded-full border-2 transition-colors",
|
|
222
|
+
selected ? "border-primary bg-primary" : "border-border bg-surface-base"
|
|
223
|
+
),
|
|
224
|
+
children: selected && /* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-white" })
|
|
225
|
+
}
|
|
226
|
+
),
|
|
227
|
+
address.fullName && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-medium text-text-primary", children: [
|
|
228
|
+
/* @__PURE__ */ jsx(FontAwesomeIcon, { icon: faUser, className: "w-3 h-3 text-text-disabled shrink-0" }),
|
|
229
|
+
address.fullName
|
|
230
|
+
] }),
|
|
231
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 text-sm text-text-secondary", children: [
|
|
232
|
+
/* @__PURE__ */ jsx(FontAwesomeIcon, { icon: faLocationDot, className: "w-3 h-3 text-text-disabled shrink-0 mt-0.5" }),
|
|
233
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
|
|
234
|
+
/* @__PURE__ */ jsx("p", { children: address.addressLine1 }),
|
|
235
|
+
address.addressLine2 && /* @__PURE__ */ jsx("p", { children: address.addressLine2 }),
|
|
236
|
+
cityLine && /* @__PURE__ */ jsx("p", { children: cityLine }),
|
|
237
|
+
countryLine && /* @__PURE__ */ jsx("p", { children: countryLine })
|
|
238
|
+
] })
|
|
239
|
+
] }),
|
|
240
|
+
address.phone && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-text-secondary", children: [
|
|
241
|
+
/* @__PURE__ */ jsx(FontAwesomeIcon, { icon: faPhone, className: "w-3 h-3 text-text-disabled shrink-0" }),
|
|
242
|
+
address.phone
|
|
243
|
+
] }),
|
|
244
|
+
(onEdit || onDelete) && /* @__PURE__ */ jsxs("div", { className: "flex gap-2 pt-2 border-t border-border", children: [
|
|
245
|
+
onEdit && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "xs", onClick: onEdit, className: "text-primary hover:text-primary-hover", children: "Edit" }),
|
|
246
|
+
onDelete && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "xs", onClick: onDelete, className: "text-error hover:opacity-80", children: "Delete" })
|
|
247
|
+
] })
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// modules/domains/common/address/AddressForm.tsx
|
|
254
|
+
import { useState } from "react";
|
|
255
|
+
import { FontAwesomeIcon as FontAwesomeIcon2 } from "@fortawesome/react-fontawesome";
|
|
256
|
+
import { faUser as faUser2, faPhone as faPhone2, faLocationDot as faLocationDot2, faGlobe } from "@fortawesome/free-solid-svg-icons";
|
|
257
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
258
|
+
function toStr(v) {
|
|
259
|
+
return v != null ? v : "";
|
|
260
|
+
}
|
|
261
|
+
function fromAddress(a) {
|
|
262
|
+
return {
|
|
263
|
+
fullName: toStr(a == null ? void 0 : a.fullName),
|
|
264
|
+
phone: toStr(a == null ? void 0 : a.phone),
|
|
265
|
+
addressLine1: toStr(a == null ? void 0 : a.addressLine1),
|
|
266
|
+
addressLine2: toStr(a == null ? void 0 : a.addressLine2),
|
|
267
|
+
city: toStr(a == null ? void 0 : a.city),
|
|
268
|
+
state: toStr(a == null ? void 0 : a.state),
|
|
269
|
+
postalCode: toStr(a == null ? void 0 : a.postalCode),
|
|
270
|
+
country: toStr(a == null ? void 0 : a.country),
|
|
271
|
+
countryCode: toStr(a == null ? void 0 : a.countryCode)
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
function toAddress(v) {
|
|
275
|
+
return {
|
|
276
|
+
addressLine1: v.addressLine1,
|
|
277
|
+
addressLine2: v.addressLine2 || null,
|
|
278
|
+
fullName: v.fullName || null,
|
|
279
|
+
phone: v.phone || null,
|
|
280
|
+
city: v.city || null,
|
|
281
|
+
state: v.state || null,
|
|
282
|
+
postalCode: v.postalCode || null,
|
|
283
|
+
country: v.country || null,
|
|
284
|
+
countryCode: v.countryCode || null
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function AddressForm({ initial, onSubmit, onCancel, submitLabel = "Save", className }) {
|
|
288
|
+
const [values, setValues] = useState(() => fromAddress(initial));
|
|
289
|
+
const [errors, setErrors] = useState({});
|
|
290
|
+
const [loading, setLoading] = useState(false);
|
|
291
|
+
function set(field) {
|
|
292
|
+
return (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { [field]: e.target.value }));
|
|
293
|
+
}
|
|
294
|
+
function validate() {
|
|
295
|
+
const next = {};
|
|
296
|
+
if (!values.fullName.trim()) next.fullName = "Full name is required.";
|
|
297
|
+
if (!values.addressLine1.trim()) next.addressLine1 = "Address line 1 is required.";
|
|
298
|
+
if (!values.city.trim()) next.city = "City is required.";
|
|
299
|
+
if (!values.country.trim()) next.country = "Country is required.";
|
|
300
|
+
setErrors(next);
|
|
301
|
+
return Object.keys(next).length === 0;
|
|
302
|
+
}
|
|
303
|
+
async function handleSubmit(e) {
|
|
304
|
+
e.preventDefault();
|
|
305
|
+
if (!validate()) return;
|
|
306
|
+
setLoading(true);
|
|
307
|
+
try {
|
|
308
|
+
await onSubmit(toAddress(values));
|
|
309
|
+
} finally {
|
|
310
|
+
setLoading(false);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return /* @__PURE__ */ jsxs2(
|
|
314
|
+
Form,
|
|
315
|
+
{
|
|
316
|
+
onSubmit: handleSubmit,
|
|
317
|
+
className,
|
|
318
|
+
actions: /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
319
|
+
onCancel && /* @__PURE__ */ jsx2(Button, { type: "button", variant: "outline", onClick: onCancel, disabled: loading, children: "Cancel" }),
|
|
320
|
+
/* @__PURE__ */ jsx2(Button, { type: "submit", loading, children: submitLabel })
|
|
321
|
+
] }),
|
|
322
|
+
children: [
|
|
323
|
+
/* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
|
|
324
|
+
/* @__PURE__ */ jsx2(
|
|
325
|
+
Input,
|
|
326
|
+
{
|
|
327
|
+
id: "addr-fullname",
|
|
328
|
+
label: "Full Name",
|
|
329
|
+
required: true,
|
|
330
|
+
prefixIcon: /* @__PURE__ */ jsx2(FontAwesomeIcon2, { icon: faUser2, className: "w-3 h-3" }),
|
|
331
|
+
value: values.fullName,
|
|
332
|
+
onChange: set("fullName"),
|
|
333
|
+
error: errors.fullName
|
|
334
|
+
}
|
|
335
|
+
),
|
|
336
|
+
/* @__PURE__ */ jsx2(
|
|
337
|
+
Input,
|
|
338
|
+
{
|
|
339
|
+
id: "addr-phone",
|
|
340
|
+
label: "Phone",
|
|
341
|
+
type: "tel",
|
|
342
|
+
prefixIcon: /* @__PURE__ */ jsx2(FontAwesomeIcon2, { icon: faPhone2, className: "w-3 h-3" }),
|
|
343
|
+
value: values.phone,
|
|
344
|
+
onChange: set("phone")
|
|
345
|
+
}
|
|
346
|
+
)
|
|
347
|
+
] }),
|
|
348
|
+
/* @__PURE__ */ jsx2(
|
|
349
|
+
Input,
|
|
350
|
+
{
|
|
351
|
+
id: "addr-line1",
|
|
352
|
+
label: "Address Line 1",
|
|
353
|
+
required: true,
|
|
354
|
+
prefixIcon: /* @__PURE__ */ jsx2(FontAwesomeIcon2, { icon: faLocationDot2, className: "w-3 h-3" }),
|
|
355
|
+
value: values.addressLine1,
|
|
356
|
+
onChange: set("addressLine1"),
|
|
357
|
+
error: errors.addressLine1
|
|
358
|
+
}
|
|
359
|
+
),
|
|
360
|
+
/* @__PURE__ */ jsx2(
|
|
361
|
+
Input,
|
|
362
|
+
{
|
|
363
|
+
id: "addr-line2",
|
|
364
|
+
label: "Address Line 2 (optional)",
|
|
365
|
+
value: values.addressLine2,
|
|
366
|
+
onChange: set("addressLine2")
|
|
367
|
+
}
|
|
368
|
+
),
|
|
369
|
+
/* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-1 sm:grid-cols-3 gap-4", children: [
|
|
370
|
+
/* @__PURE__ */ jsx2(Input, { id: "addr-city", label: "City", required: true, value: values.city, onChange: set("city"), error: errors.city }),
|
|
371
|
+
/* @__PURE__ */ jsx2(Input, { id: "addr-state", label: "State / District", value: values.state, onChange: set("state") }),
|
|
372
|
+
/* @__PURE__ */ jsx2(Input, { id: "addr-postalcode", label: "Postal Code", value: values.postalCode, onChange: set("postalCode") })
|
|
373
|
+
] }),
|
|
374
|
+
/* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
|
|
375
|
+
/* @__PURE__ */ jsx2(
|
|
376
|
+
Input,
|
|
377
|
+
{
|
|
378
|
+
id: "addr-country",
|
|
379
|
+
label: "Country",
|
|
380
|
+
required: true,
|
|
381
|
+
prefixIcon: /* @__PURE__ */ jsx2(FontAwesomeIcon2, { icon: faGlobe, className: "w-3 h-3" }),
|
|
382
|
+
value: values.country,
|
|
383
|
+
onChange: set("country"),
|
|
384
|
+
error: errors.country
|
|
385
|
+
}
|
|
386
|
+
),
|
|
387
|
+
/* @__PURE__ */ jsx2(
|
|
388
|
+
Input,
|
|
389
|
+
{
|
|
390
|
+
id: "addr-countrycode",
|
|
391
|
+
label: "Country Code (2 letters)",
|
|
392
|
+
value: values.countryCode,
|
|
393
|
+
onChange: set("countryCode"),
|
|
394
|
+
maxLength: 2
|
|
395
|
+
}
|
|
396
|
+
)
|
|
397
|
+
] })
|
|
398
|
+
]
|
|
399
|
+
}
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// modules/domains/common/address/AddressSelector.tsx
|
|
404
|
+
import { useState as useState2 } from "react";
|
|
405
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
406
|
+
function AddressSelector({
|
|
407
|
+
addresses,
|
|
408
|
+
selectedIndex,
|
|
409
|
+
onSelect,
|
|
410
|
+
onAdd,
|
|
411
|
+
onEdit,
|
|
412
|
+
onDelete,
|
|
413
|
+
className
|
|
414
|
+
}) {
|
|
415
|
+
const [active, setActive] = useState2(selectedIndex);
|
|
416
|
+
function handleSelect(i) {
|
|
417
|
+
setActive(i);
|
|
418
|
+
onSelect(i, addresses[i]);
|
|
419
|
+
}
|
|
420
|
+
return /* @__PURE__ */ jsxs3("fieldset", { className: cn("space-y-3", className), children: [
|
|
421
|
+
/* @__PURE__ */ jsx3("legend", { className: "sr-only", children: "Select delivery address" }),
|
|
422
|
+
addresses.length === 0 ? /* @__PURE__ */ jsx3("p", { className: "text-sm text-text-secondary py-4 text-center", children: "No saved addresses." }) : /* @__PURE__ */ jsx3("div", { className: "space-y-2", children: addresses.map((addr, i) => /* @__PURE__ */ jsxs3(
|
|
423
|
+
"label",
|
|
424
|
+
{
|
|
425
|
+
className: cn(
|
|
426
|
+
"block cursor-pointer rounded-lg",
|
|
427
|
+
"focus-within:ring-2 focus-within:ring-border-focus"
|
|
428
|
+
),
|
|
429
|
+
children: [
|
|
430
|
+
/* @__PURE__ */ jsx3(
|
|
431
|
+
"input",
|
|
432
|
+
{
|
|
433
|
+
type: "radio",
|
|
434
|
+
name: "address-selector",
|
|
435
|
+
value: String(i),
|
|
436
|
+
checked: active === i,
|
|
437
|
+
onChange: () => handleSelect(i),
|
|
438
|
+
className: "sr-only"
|
|
439
|
+
}
|
|
440
|
+
),
|
|
441
|
+
/* @__PURE__ */ jsx3(
|
|
442
|
+
AddressCard,
|
|
443
|
+
{
|
|
444
|
+
address: addr,
|
|
445
|
+
selected: active === i,
|
|
446
|
+
onEdit: onEdit ? () => onEdit(i, addr) : void 0,
|
|
447
|
+
onDelete: onDelete ? () => onDelete(i, addr) : void 0
|
|
448
|
+
}
|
|
449
|
+
)
|
|
450
|
+
]
|
|
451
|
+
},
|
|
452
|
+
i
|
|
453
|
+
)) }),
|
|
454
|
+
onAdd && /* @__PURE__ */ jsx3(Button, { variant: "outline", size: "sm", onClick: onAdd, className: "w-full", children: "+ Add new address" })
|
|
455
|
+
] });
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// modules/domains/common/auth/ChangePasswordForm.tsx
|
|
459
|
+
import { useState as useState3 } from "react";
|
|
460
|
+
import { FontAwesomeIcon as FontAwesomeIcon3 } from "@fortawesome/react-fontawesome";
|
|
461
|
+
import { faLock } from "@fortawesome/free-solid-svg-icons";
|
|
462
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
463
|
+
function ChangePasswordForm({ onSubmit, error, className }) {
|
|
464
|
+
const [values, setValues] = useState3({ currentPassword: "", newPassword: "", confirmPassword: "" });
|
|
465
|
+
const [errors, setErrors] = useState3({});
|
|
466
|
+
const [loading, setLoading] = useState3(false);
|
|
467
|
+
function validate() {
|
|
468
|
+
const next = {};
|
|
469
|
+
if (!values.currentPassword) next.currentPassword = "Current password is required.";
|
|
470
|
+
if (!values.newPassword) next.newPassword = "New password is required.";
|
|
471
|
+
else if (values.newPassword.length < 8) next.newPassword = "Password must be at least 8 characters.";
|
|
472
|
+
if (!values.confirmPassword) next.confirmPassword = "Please confirm your new password.";
|
|
473
|
+
else if (values.newPassword !== values.confirmPassword) next.confirmPassword = "Passwords don't match.";
|
|
474
|
+
setErrors(next);
|
|
475
|
+
return Object.keys(next).length === 0;
|
|
476
|
+
}
|
|
477
|
+
async function handleSubmit(e) {
|
|
478
|
+
e.preventDefault();
|
|
479
|
+
if (!validate()) return;
|
|
480
|
+
setLoading(true);
|
|
481
|
+
try {
|
|
482
|
+
await onSubmit(values);
|
|
483
|
+
} finally {
|
|
484
|
+
setLoading(false);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
const lockIcon = /* @__PURE__ */ jsx4(FontAwesomeIcon3, { icon: faLock, className: "w-3.5 h-3.5" });
|
|
488
|
+
return /* @__PURE__ */ jsxs4(Form, { onSubmit: handleSubmit, error, className, children: [
|
|
489
|
+
/* @__PURE__ */ jsx4(
|
|
490
|
+
Input,
|
|
491
|
+
{
|
|
492
|
+
id: "current-password",
|
|
493
|
+
label: "Current Password",
|
|
494
|
+
type: "password",
|
|
495
|
+
required: true,
|
|
496
|
+
autoComplete: "current-password",
|
|
497
|
+
prefixIcon: lockIcon,
|
|
498
|
+
value: values.currentPassword,
|
|
499
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { currentPassword: e.target.value })),
|
|
500
|
+
error: errors.currentPassword
|
|
501
|
+
}
|
|
502
|
+
),
|
|
503
|
+
/* @__PURE__ */ jsx4(
|
|
504
|
+
Input,
|
|
505
|
+
{
|
|
506
|
+
id: "new-password",
|
|
507
|
+
label: "New Password",
|
|
508
|
+
type: "password",
|
|
509
|
+
required: true,
|
|
510
|
+
autoComplete: "new-password",
|
|
511
|
+
prefixIcon: lockIcon,
|
|
512
|
+
value: values.newPassword,
|
|
513
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { newPassword: e.target.value })),
|
|
514
|
+
error: errors.newPassword
|
|
515
|
+
}
|
|
516
|
+
),
|
|
517
|
+
/* @__PURE__ */ jsx4(
|
|
518
|
+
Input,
|
|
519
|
+
{
|
|
520
|
+
id: "confirm-password",
|
|
521
|
+
label: "Confirm New Password",
|
|
522
|
+
type: "password",
|
|
523
|
+
required: true,
|
|
524
|
+
autoComplete: "new-password",
|
|
525
|
+
prefixIcon: lockIcon,
|
|
526
|
+
value: values.confirmPassword,
|
|
527
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { confirmPassword: e.target.value })),
|
|
528
|
+
error: errors.confirmPassword
|
|
529
|
+
}
|
|
530
|
+
),
|
|
531
|
+
/* @__PURE__ */ jsx4(Button, { type: "submit", fullWidth: true, loading, children: "Update Password" })
|
|
532
|
+
] });
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// modules/domains/common/auth/ForgotPasswordForm.tsx
|
|
536
|
+
import { useState as useState4 } from "react";
|
|
537
|
+
import { FontAwesomeIcon as FontAwesomeIcon4 } from "@fortawesome/react-fontawesome";
|
|
538
|
+
import { faEnvelope } from "@fortawesome/free-solid-svg-icons";
|
|
539
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
540
|
+
function ForgotPasswordForm({ onSubmit, error, className }) {
|
|
541
|
+
const [email, setEmail] = useState4("");
|
|
542
|
+
const [emailError, setEmailError] = useState4("");
|
|
543
|
+
const [loading, setLoading] = useState4(false);
|
|
544
|
+
const [sent, setSent] = useState4(false);
|
|
545
|
+
function validate() {
|
|
546
|
+
if (!email) {
|
|
547
|
+
setEmailError("Email is required.");
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
551
|
+
setEmailError("Enter a valid email address.");
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
setEmailError("");
|
|
555
|
+
return true;
|
|
556
|
+
}
|
|
557
|
+
async function handleSubmit(e) {
|
|
558
|
+
e.preventDefault();
|
|
559
|
+
if (!validate()) return;
|
|
560
|
+
setLoading(true);
|
|
561
|
+
try {
|
|
562
|
+
await onSubmit(email);
|
|
563
|
+
setSent(true);
|
|
564
|
+
} finally {
|
|
565
|
+
setLoading(false);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
if (sent) {
|
|
569
|
+
return /* @__PURE__ */ jsxs5("div", { className: "rounded-lg bg-success-subtle border border-success px-4 py-4 text-sm text-success-fg space-y-1", children: [
|
|
570
|
+
/* @__PURE__ */ jsx5("p", { className: "font-semibold", children: "Check your inbox" }),
|
|
571
|
+
/* @__PURE__ */ jsxs5("p", { children: [
|
|
572
|
+
"We sent a password reset link to ",
|
|
573
|
+
/* @__PURE__ */ jsx5("span", { className: "font-mono", children: email }),
|
|
574
|
+
"."
|
|
575
|
+
] })
|
|
576
|
+
] });
|
|
577
|
+
}
|
|
578
|
+
return /* @__PURE__ */ jsxs5(Form, { onSubmit: handleSubmit, error, className, children: [
|
|
579
|
+
/* @__PURE__ */ jsx5(
|
|
580
|
+
Input,
|
|
581
|
+
{
|
|
582
|
+
id: "forgot-email",
|
|
583
|
+
label: "Email",
|
|
584
|
+
type: "email",
|
|
585
|
+
required: true,
|
|
586
|
+
autoComplete: "email",
|
|
587
|
+
prefixIcon: /* @__PURE__ */ jsx5(FontAwesomeIcon4, { icon: faEnvelope, className: "w-3.5 h-3.5" }),
|
|
588
|
+
value: email,
|
|
589
|
+
onChange: (e) => setEmail(e.target.value),
|
|
590
|
+
error: emailError
|
|
591
|
+
}
|
|
592
|
+
),
|
|
593
|
+
/* @__PURE__ */ jsx5(Button, { type: "submit", fullWidth: true, loading, children: "Send reset link" })
|
|
594
|
+
] });
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// modules/domains/common/auth/LoginForm.tsx
|
|
598
|
+
import { useState as useState5 } from "react";
|
|
599
|
+
import { FontAwesomeIcon as FontAwesomeIcon5 } from "@fortawesome/react-fontawesome";
|
|
600
|
+
import { faEnvelope as faEnvelope2, faLock as faLock2 } from "@fortawesome/free-solid-svg-icons";
|
|
601
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
602
|
+
function LoginForm({ onSubmit, error, className }) {
|
|
603
|
+
const [values, setValues] = useState5({ email: "", password: "", rememberMe: false });
|
|
604
|
+
const [errors, setErrors] = useState5({});
|
|
605
|
+
const [loading, setLoading] = useState5(false);
|
|
606
|
+
function validate() {
|
|
607
|
+
const next = {};
|
|
608
|
+
if (!values.email) next.email = "Email is required.";
|
|
609
|
+
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(values.email)) next.email = "Enter a valid email address.";
|
|
610
|
+
if (!values.password) next.password = "Password is required.";
|
|
611
|
+
else if (values.password.length < 8) next.password = "Password must be at least 8 characters.";
|
|
612
|
+
setErrors(next);
|
|
613
|
+
return Object.keys(next).length === 0;
|
|
614
|
+
}
|
|
615
|
+
async function handleSubmit(e) {
|
|
616
|
+
e.preventDefault();
|
|
617
|
+
if (!validate()) return;
|
|
618
|
+
setLoading(true);
|
|
619
|
+
try {
|
|
620
|
+
await onSubmit(values);
|
|
621
|
+
} finally {
|
|
622
|
+
setLoading(false);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return /* @__PURE__ */ jsxs6(Form, { onSubmit: handleSubmit, error, className, children: [
|
|
626
|
+
/* @__PURE__ */ jsx6(
|
|
627
|
+
Input,
|
|
628
|
+
{
|
|
629
|
+
id: "login-email",
|
|
630
|
+
label: "Email",
|
|
631
|
+
type: "email",
|
|
632
|
+
required: true,
|
|
633
|
+
autoComplete: "email",
|
|
634
|
+
prefixIcon: /* @__PURE__ */ jsx6(FontAwesomeIcon5, { icon: faEnvelope2, className: "w-3.5 h-3.5" }),
|
|
635
|
+
value: values.email,
|
|
636
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { email: e.target.value })),
|
|
637
|
+
error: errors.email
|
|
638
|
+
}
|
|
639
|
+
),
|
|
640
|
+
/* @__PURE__ */ jsx6(
|
|
641
|
+
Input,
|
|
642
|
+
{
|
|
643
|
+
id: "login-password",
|
|
644
|
+
label: "Password",
|
|
645
|
+
type: "password",
|
|
646
|
+
required: true,
|
|
647
|
+
autoComplete: "current-password",
|
|
648
|
+
prefixIcon: /* @__PURE__ */ jsx6(FontAwesomeIcon5, { icon: faLock2, className: "w-3.5 h-3.5" }),
|
|
649
|
+
value: values.password,
|
|
650
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { password: e.target.value })),
|
|
651
|
+
error: errors.password
|
|
652
|
+
}
|
|
653
|
+
),
|
|
654
|
+
/* @__PURE__ */ jsxs6("label", { className: "flex items-center gap-2 text-sm text-text-secondary cursor-pointer select-none", children: [
|
|
655
|
+
/* @__PURE__ */ jsx6(
|
|
656
|
+
"input",
|
|
657
|
+
{
|
|
658
|
+
type: "checkbox",
|
|
659
|
+
checked: values.rememberMe,
|
|
660
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { rememberMe: e.target.checked })),
|
|
661
|
+
className: "rounded border-border accent-primary focus-visible:ring-2 focus-visible:ring-border-focus"
|
|
662
|
+
}
|
|
663
|
+
),
|
|
664
|
+
"Remember me"
|
|
665
|
+
] }),
|
|
666
|
+
/* @__PURE__ */ jsx6(Button, { type: "submit", fullWidth: true, loading, children: "Sign In" })
|
|
667
|
+
] });
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// modules/domains/common/auth/OAuthButtons.tsx
|
|
671
|
+
import { useState as useState6 } from "react";
|
|
672
|
+
import { FontAwesomeIcon as FontAwesomeIcon6 } from "@fortawesome/react-fontawesome";
|
|
673
|
+
import { faGoogle, faGithub, faDiscord, faMicrosoft } from "@fortawesome/free-brands-svg-icons";
|
|
674
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
675
|
+
var providerMeta = {
|
|
676
|
+
GOOGLE: { label: "Continue with Google", icon: /* @__PURE__ */ jsx7(FontAwesomeIcon6, { icon: faGoogle }), iconClass: "text-[#EA4335]" },
|
|
677
|
+
GITHUB: { label: "Continue with GitHub", icon: /* @__PURE__ */ jsx7(FontAwesomeIcon6, { icon: faGithub }), iconClass: "text-text-primary" },
|
|
678
|
+
DISCORD: { label: "Continue with Discord", icon: /* @__PURE__ */ jsx7(FontAwesomeIcon6, { icon: faDiscord }), iconClass: "text-[#5865F2]" },
|
|
679
|
+
MICROSOFT: { label: "Continue with Microsoft", icon: /* @__PURE__ */ jsx7(FontAwesomeIcon6, { icon: faMicrosoft }), iconClass: "text-[#00A4EF]" }
|
|
680
|
+
};
|
|
681
|
+
function OAuthButtons({
|
|
682
|
+
providers = ["GOOGLE", "GITHUB", "DISCORD", "MICROSOFT"],
|
|
683
|
+
onProvider,
|
|
684
|
+
className
|
|
685
|
+
}) {
|
|
686
|
+
const [loadingProvider, setLoadingProvider] = useState6(null);
|
|
687
|
+
async function handleClick(provider) {
|
|
688
|
+
setLoadingProvider(provider);
|
|
689
|
+
try {
|
|
690
|
+
await onProvider(provider);
|
|
691
|
+
} finally {
|
|
692
|
+
setLoadingProvider(null);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return /* @__PURE__ */ jsx7("div", { className: cn("flex flex-col gap-2", className), children: providers.map((provider) => {
|
|
696
|
+
const meta = providerMeta[provider];
|
|
697
|
+
const isLoading = loadingProvider === provider;
|
|
698
|
+
return /* @__PURE__ */ jsx7(
|
|
699
|
+
Button,
|
|
700
|
+
{
|
|
701
|
+
variant: "outline",
|
|
702
|
+
fullWidth: true,
|
|
703
|
+
loading: isLoading,
|
|
704
|
+
disabled: loadingProvider !== null,
|
|
705
|
+
"aria-label": meta.label,
|
|
706
|
+
onClick: () => handleClick(provider),
|
|
707
|
+
iconLeft: /* @__PURE__ */ jsx7("span", { className: meta.iconClass, children: meta.icon }),
|
|
708
|
+
children: meta.label
|
|
709
|
+
},
|
|
710
|
+
provider
|
|
711
|
+
);
|
|
712
|
+
}) });
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// modules/domains/common/auth/RegisterForm.tsx
|
|
716
|
+
import { useState as useState7 } from "react";
|
|
717
|
+
import { FontAwesomeIcon as FontAwesomeIcon7 } from "@fortawesome/react-fontawesome";
|
|
718
|
+
import { faEnvelope as faEnvelope3, faLock as faLock3 } from "@fortawesome/free-solid-svg-icons";
|
|
719
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
720
|
+
function RegisterForm({ onSubmit, error, className }) {
|
|
721
|
+
const [values, setValues] = useState7({ email: "", password: "", confirmPassword: "" });
|
|
722
|
+
const [errors, setErrors] = useState7({});
|
|
723
|
+
const [loading, setLoading] = useState7(false);
|
|
724
|
+
function validate() {
|
|
725
|
+
const next = {};
|
|
726
|
+
if (!values.email) next.email = "Email is required.";
|
|
727
|
+
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(values.email)) next.email = "Enter a valid email address.";
|
|
728
|
+
if (!values.password) next.password = "Password is required.";
|
|
729
|
+
else if (values.password.length < 8) next.password = "Password must be at least 8 characters.";
|
|
730
|
+
if (!values.confirmPassword) next.confirmPassword = "Please confirm your password.";
|
|
731
|
+
else if (values.password !== values.confirmPassword) next.confirmPassword = "Passwords do not match.";
|
|
732
|
+
setErrors(next);
|
|
733
|
+
return Object.keys(next).length === 0;
|
|
734
|
+
}
|
|
735
|
+
async function handleSubmit(e) {
|
|
736
|
+
e.preventDefault();
|
|
737
|
+
if (!validate()) return;
|
|
738
|
+
setLoading(true);
|
|
739
|
+
try {
|
|
740
|
+
await onSubmit({ email: values.email, password: values.password });
|
|
741
|
+
} finally {
|
|
742
|
+
setLoading(false);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
return /* @__PURE__ */ jsxs7(Form, { onSubmit: handleSubmit, error, className, children: [
|
|
746
|
+
/* @__PURE__ */ jsx8(
|
|
747
|
+
Input,
|
|
748
|
+
{
|
|
749
|
+
id: "register-email",
|
|
750
|
+
label: "Email",
|
|
751
|
+
type: "email",
|
|
752
|
+
required: true,
|
|
753
|
+
autoComplete: "email",
|
|
754
|
+
prefixIcon: /* @__PURE__ */ jsx8(FontAwesomeIcon7, { icon: faEnvelope3, className: "w-3.5 h-3.5" }),
|
|
755
|
+
value: values.email,
|
|
756
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { email: e.target.value })),
|
|
757
|
+
error: errors.email
|
|
758
|
+
}
|
|
759
|
+
),
|
|
760
|
+
/* @__PURE__ */ jsx8(
|
|
761
|
+
Input,
|
|
762
|
+
{
|
|
763
|
+
id: "register-password",
|
|
764
|
+
label: "Password",
|
|
765
|
+
type: "password",
|
|
766
|
+
required: true,
|
|
767
|
+
autoComplete: "new-password",
|
|
768
|
+
hint: "Minimum 8 characters",
|
|
769
|
+
prefixIcon: /* @__PURE__ */ jsx8(FontAwesomeIcon7, { icon: faLock3, className: "w-3.5 h-3.5" }),
|
|
770
|
+
value: values.password,
|
|
771
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { password: e.target.value })),
|
|
772
|
+
error: errors.password
|
|
773
|
+
}
|
|
774
|
+
),
|
|
775
|
+
/* @__PURE__ */ jsx8(
|
|
776
|
+
Input,
|
|
777
|
+
{
|
|
778
|
+
id: "register-confirm-password",
|
|
779
|
+
label: "Confirm Password",
|
|
780
|
+
type: "password",
|
|
781
|
+
required: true,
|
|
782
|
+
autoComplete: "new-password",
|
|
783
|
+
prefixIcon: /* @__PURE__ */ jsx8(FontAwesomeIcon7, { icon: faLock3, className: "w-3.5 h-3.5" }),
|
|
784
|
+
value: values.confirmPassword,
|
|
785
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { confirmPassword: e.target.value })),
|
|
786
|
+
error: errors.confirmPassword
|
|
787
|
+
}
|
|
788
|
+
),
|
|
789
|
+
/* @__PURE__ */ jsx8(Button, { type: "submit", fullWidth: true, loading, children: "Create Account" })
|
|
790
|
+
] });
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// modules/domains/common/auth/SessionExpiredBanner.tsx
|
|
794
|
+
import { FontAwesomeIcon as FontAwesomeIcon8 } from "@fortawesome/react-fontawesome";
|
|
795
|
+
import { faClock } from "@fortawesome/free-solid-svg-icons";
|
|
796
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
797
|
+
function SessionExpiredBanner({
|
|
798
|
+
onSignIn,
|
|
799
|
+
message = "Your session has expired. Please sign in again to continue.",
|
|
800
|
+
className
|
|
801
|
+
}) {
|
|
802
|
+
return /* @__PURE__ */ jsxs8(
|
|
803
|
+
"div",
|
|
804
|
+
{
|
|
805
|
+
role: "alert",
|
|
806
|
+
className: cn(
|
|
807
|
+
"flex items-start sm:items-center justify-between gap-4 flex-wrap",
|
|
808
|
+
"rounded-lg border border-warning bg-warning-subtle px-4 py-3",
|
|
809
|
+
className
|
|
810
|
+
),
|
|
811
|
+
children: [
|
|
812
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-start gap-3 min-w-0", children: [
|
|
813
|
+
/* @__PURE__ */ jsx9(FontAwesomeIcon8, { icon: faClock, className: "w-5 h-5 text-warning shrink-0 mt-0.5", "aria-hidden": "true" }),
|
|
814
|
+
/* @__PURE__ */ jsxs8("div", { className: "min-w-0", children: [
|
|
815
|
+
/* @__PURE__ */ jsx9("p", { className: "text-sm font-semibold text-text-primary", children: "Session expired" }),
|
|
816
|
+
/* @__PURE__ */ jsx9("p", { className: "text-sm text-text-secondary mt-0.5", children: message })
|
|
817
|
+
] })
|
|
818
|
+
] }),
|
|
819
|
+
onSignIn && /* @__PURE__ */ jsx9(Button, { variant: "primary", size: "sm", onClick: onSignIn, className: "shrink-0", children: "Sign in again" })
|
|
820
|
+
]
|
|
821
|
+
}
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// modules/domains/common/cart/CartBadge.tsx
|
|
826
|
+
import { FontAwesomeIcon as FontAwesomeIcon9 } from "@fortawesome/react-fontawesome";
|
|
827
|
+
import { faCartShopping } from "@fortawesome/free-solid-svg-icons";
|
|
828
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
829
|
+
function CartBadge({ cart, onClick, className }) {
|
|
830
|
+
const totalQty = cart.items.reduce((sum, item) => sum + item.quantity, 0);
|
|
831
|
+
return /* @__PURE__ */ jsxs9(
|
|
832
|
+
"button",
|
|
833
|
+
{
|
|
834
|
+
type: "button",
|
|
835
|
+
onClick,
|
|
836
|
+
"aria-label": `Cart \u2014 ${totalQty} item${totalQty !== 1 ? "s" : ""}`,
|
|
837
|
+
className: cn(
|
|
838
|
+
"relative inline-flex items-center justify-center h-10 w-10 rounded-full",
|
|
839
|
+
"border border-border bg-surface-raised text-text-primary",
|
|
840
|
+
"hover:bg-surface-overlay transition-colors",
|
|
841
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
842
|
+
className
|
|
843
|
+
),
|
|
844
|
+
children: [
|
|
845
|
+
/* @__PURE__ */ jsx10(FontAwesomeIcon9, { icon: faCartShopping, className: "w-5 h-5", "aria-hidden": "true" }),
|
|
846
|
+
totalQty > 0 && /* @__PURE__ */ jsx10(
|
|
847
|
+
"span",
|
|
848
|
+
{
|
|
849
|
+
"aria-hidden": "true",
|
|
850
|
+
className: "absolute -top-1 -right-1 flex h-5 min-w-[1.25rem] items-center justify-center rounded-full bg-primary px-1 text-[10px] font-bold text-primary-fg tabular-nums shadow",
|
|
851
|
+
children: totalQty > 99 ? "99+" : totalQty
|
|
852
|
+
}
|
|
853
|
+
)
|
|
854
|
+
]
|
|
855
|
+
}
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// modules/domains/common/money/PriceDisplay.tsx
|
|
860
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
861
|
+
var sizeMap = {
|
|
862
|
+
sm: "text-sm",
|
|
863
|
+
md: "text-base",
|
|
864
|
+
lg: "text-xl font-semibold",
|
|
865
|
+
xl: "text-3xl font-bold"
|
|
866
|
+
};
|
|
867
|
+
function PriceDisplay({
|
|
868
|
+
amount,
|
|
869
|
+
currency = "TRY",
|
|
870
|
+
locale = "tr-TR",
|
|
871
|
+
size = "md",
|
|
872
|
+
strikethrough = false,
|
|
873
|
+
className
|
|
874
|
+
}) {
|
|
875
|
+
const formatted = new Intl.NumberFormat(locale, {
|
|
876
|
+
style: "currency",
|
|
877
|
+
currency,
|
|
878
|
+
minimumFractionDigits: 2,
|
|
879
|
+
maximumFractionDigits: 2
|
|
880
|
+
}).format(amount);
|
|
881
|
+
return /* @__PURE__ */ jsx11(
|
|
882
|
+
"span",
|
|
883
|
+
{
|
|
884
|
+
className: cn(
|
|
885
|
+
"tabular-nums",
|
|
886
|
+
sizeMap[size],
|
|
887
|
+
strikethrough && "line-through text-text-secondary",
|
|
888
|
+
className
|
|
889
|
+
),
|
|
890
|
+
children: formatted
|
|
891
|
+
}
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// modules/domains/common/cart/CartItem.tsx
|
|
896
|
+
import { FontAwesomeIcon as FontAwesomeIcon10 } from "@fortawesome/react-fontawesome";
|
|
897
|
+
import { faBagShopping } from "@fortawesome/free-solid-svg-icons";
|
|
898
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
899
|
+
function CartItem({
|
|
900
|
+
item,
|
|
901
|
+
onQuantityChange,
|
|
902
|
+
onRemove,
|
|
903
|
+
compact = false,
|
|
904
|
+
className
|
|
905
|
+
}) {
|
|
906
|
+
const canDecrement = item.quantity > 1;
|
|
907
|
+
const canIncrement = item.maxQuantity == null || item.quantity < item.maxQuantity;
|
|
908
|
+
return /* @__PURE__ */ jsxs10("div", { className: cn("flex gap-3", className), children: [
|
|
909
|
+
/* @__PURE__ */ jsx12("div", { className: cn(
|
|
910
|
+
"shrink-0 rounded-lg border border-border bg-surface-overlay flex items-center justify-center text-text-disabled overflow-hidden",
|
|
911
|
+
compact ? "h-12 w-12" : "h-16 w-16"
|
|
912
|
+
), children: item.image ? /* @__PURE__ */ jsx12("img", { src: item.image, alt: item.name, className: "h-full w-full object-cover" }) : /* @__PURE__ */ jsx12(FontAwesomeIcon10, { icon: faBagShopping, className: cn("text-text-disabled", compact ? "w-5 h-5" : "w-7 h-7"), "aria-hidden": "true" }) }),
|
|
913
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex-1 min-w-0 space-y-0.5", children: [
|
|
914
|
+
/* @__PURE__ */ jsx12("p", { className: cn("font-medium text-text-primary truncate", compact ? "text-xs" : "text-sm"), children: item.name }),
|
|
915
|
+
item.variant && /* @__PURE__ */ jsx12("p", { className: "text-xs text-text-secondary truncate", children: item.variant }),
|
|
916
|
+
item.description && !compact && /* @__PURE__ */ jsx12("p", { className: "text-xs text-text-secondary line-clamp-1", children: item.description }),
|
|
917
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 pt-1 flex-wrap", children: [
|
|
918
|
+
onQuantityChange ? /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 rounded-md border border-border bg-surface-base", children: [
|
|
919
|
+
/* @__PURE__ */ jsx12(
|
|
920
|
+
"button",
|
|
921
|
+
{
|
|
922
|
+
type: "button",
|
|
923
|
+
"aria-label": "Decrease quantity",
|
|
924
|
+
disabled: !canDecrement,
|
|
925
|
+
onClick: () => onQuantityChange(item.cartItemId, item.quantity - 1),
|
|
926
|
+
className: "flex h-6 w-6 items-center justify-center rounded-l-md text-text-secondary hover:bg-surface-overlay disabled:opacity-40 disabled:cursor-not-allowed transition-colors text-xs font-bold",
|
|
927
|
+
children: "\u2212"
|
|
928
|
+
}
|
|
929
|
+
),
|
|
930
|
+
/* @__PURE__ */ jsx12("span", { className: "w-6 text-center text-xs font-medium text-text-primary tabular-nums", children: item.quantity }),
|
|
931
|
+
/* @__PURE__ */ jsx12(
|
|
932
|
+
"button",
|
|
933
|
+
{
|
|
934
|
+
type: "button",
|
|
935
|
+
"aria-label": "Increase quantity",
|
|
936
|
+
disabled: !canIncrement,
|
|
937
|
+
onClick: () => onQuantityChange(item.cartItemId, item.quantity + 1),
|
|
938
|
+
className: "flex h-6 w-6 items-center justify-center rounded-r-md text-text-secondary hover:bg-surface-overlay disabled:opacity-40 disabled:cursor-not-allowed transition-colors text-xs font-bold",
|
|
939
|
+
children: "+"
|
|
940
|
+
}
|
|
941
|
+
)
|
|
942
|
+
] }) : /* @__PURE__ */ jsxs10("span", { className: "text-xs text-text-secondary", children: [
|
|
943
|
+
"Qty: ",
|
|
944
|
+
item.quantity
|
|
945
|
+
] }),
|
|
946
|
+
onRemove && /* @__PURE__ */ jsx12(
|
|
947
|
+
Button,
|
|
948
|
+
{
|
|
949
|
+
variant: "ghost",
|
|
950
|
+
size: "xs",
|
|
951
|
+
onClick: () => onRemove(item.cartItemId),
|
|
952
|
+
className: "text-error hover:opacity-80 px-1",
|
|
953
|
+
children: "Remove"
|
|
954
|
+
}
|
|
955
|
+
)
|
|
956
|
+
] })
|
|
957
|
+
] }),
|
|
958
|
+
/* @__PURE__ */ jsxs10("div", { className: "shrink-0 text-right space-y-0.5", children: [
|
|
959
|
+
/* @__PURE__ */ jsx12(
|
|
960
|
+
PriceDisplay,
|
|
961
|
+
{
|
|
962
|
+
amount: item.price * item.quantity,
|
|
963
|
+
currency: item.currency,
|
|
964
|
+
size: compact ? "sm" : "md"
|
|
965
|
+
}
|
|
966
|
+
),
|
|
967
|
+
item.quantity > 1 && /* @__PURE__ */ jsxs10("p", { className: "text-xs text-text-secondary", children: [
|
|
968
|
+
/* @__PURE__ */ jsx12(PriceDisplay, { amount: item.price, currency: item.currency, size: "sm" }),
|
|
969
|
+
" each"
|
|
970
|
+
] })
|
|
971
|
+
] })
|
|
972
|
+
] });
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// modules/domains/common/cart/CartPreview.tsx
|
|
976
|
+
import { useState as useState8 } from "react";
|
|
977
|
+
import { FontAwesomeIcon as FontAwesomeIcon11 } from "@fortawesome/react-fontawesome";
|
|
978
|
+
import { faCartShopping as faCartShopping2, faChevronDown } from "@fortawesome/free-solid-svg-icons";
|
|
979
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
980
|
+
function CartPreview({ cart, defaultOpen = false, className }) {
|
|
981
|
+
const [open, setOpen] = useState8(defaultOpen);
|
|
982
|
+
const totalQty = cart.items.reduce((sum, item) => sum + item.quantity, 0);
|
|
983
|
+
const itemLabel = `${totalQty} item${totalQty !== 1 ? "s" : ""}`;
|
|
984
|
+
return /* @__PURE__ */ jsxs11("div", { className: cn("rounded-xl border border-border bg-surface-raised overflow-hidden", className), children: [
|
|
985
|
+
/* @__PURE__ */ jsxs11(
|
|
986
|
+
"button",
|
|
987
|
+
{
|
|
988
|
+
type: "button",
|
|
989
|
+
onClick: () => setOpen((o) => !o),
|
|
990
|
+
"aria-expanded": open,
|
|
991
|
+
className: "w-full flex items-center justify-between gap-3 px-4 py-3 text-left hover:bg-surface-overlay transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-border-focus",
|
|
992
|
+
children: [
|
|
993
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
994
|
+
/* @__PURE__ */ jsx13(FontAwesomeIcon11, { icon: faCartShopping2, className: "w-4 h-4 text-text-secondary", "aria-hidden": "true" }),
|
|
995
|
+
/* @__PURE__ */ jsx13("span", { className: "text-sm font-semibold text-text-primary", children: "Your order" }),
|
|
996
|
+
/* @__PURE__ */ jsxs11("span", { className: "text-xs text-text-secondary", children: [
|
|
997
|
+
"(",
|
|
998
|
+
itemLabel,
|
|
999
|
+
")"
|
|
1000
|
+
] })
|
|
1001
|
+
] }),
|
|
1002
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-3 shrink-0", children: [
|
|
1003
|
+
/* @__PURE__ */ jsx13(PriceDisplay, { amount: cart.totals.total, currency: cart.totals.currency, size: "sm" }),
|
|
1004
|
+
/* @__PURE__ */ jsx13(
|
|
1005
|
+
FontAwesomeIcon11,
|
|
1006
|
+
{
|
|
1007
|
+
icon: faChevronDown,
|
|
1008
|
+
className: cn("h-3.5 w-3.5 text-text-secondary transition-transform duration-200", open && "rotate-180"),
|
|
1009
|
+
"aria-hidden": "true"
|
|
1010
|
+
}
|
|
1011
|
+
)
|
|
1012
|
+
] })
|
|
1013
|
+
]
|
|
1014
|
+
}
|
|
1015
|
+
),
|
|
1016
|
+
open && /* @__PURE__ */ jsx13("div", { className: "border-t border-border px-4 py-3 space-y-3", children: cart.items.length === 0 ? /* @__PURE__ */ jsx13("p", { className: "text-sm text-text-secondary py-2 text-center", children: "No items in cart." }) : cart.items.map((item, idx) => /* @__PURE__ */ jsx13(
|
|
1017
|
+
CartItem,
|
|
1018
|
+
{
|
|
1019
|
+
item,
|
|
1020
|
+
compact: true,
|
|
1021
|
+
className: cn(idx > 0 && "border-t border-border pt-3")
|
|
1022
|
+
},
|
|
1023
|
+
item.cartItemId
|
|
1024
|
+
)) })
|
|
1025
|
+
] });
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
// modules/domains/common/money/OrderTotalsCard.tsx
|
|
1029
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1030
|
+
function OrderTotalsCard({ totals, locale, className }) {
|
|
1031
|
+
var _a3;
|
|
1032
|
+
const currency = (_a3 = totals.currency) != null ? _a3 : "TRY";
|
|
1033
|
+
const lines = [
|
|
1034
|
+
{ label: "Subtotal", amount: totals.subtotal },
|
|
1035
|
+
...totals.discountTotal && totals.discountTotal > 0 ? [{ label: "Discount", amount: -totals.discountTotal, isDiscount: true }] : [],
|
|
1036
|
+
...totals.taxTotal && totals.taxTotal > 0 ? [{ label: "Tax", amount: totals.taxTotal }] : [],
|
|
1037
|
+
...totals.serviceFee && totals.serviceFee > 0 ? [{ label: "Service Fee", amount: totals.serviceFee }] : [],
|
|
1038
|
+
...totals.shippingTotal && totals.shippingTotal > 0 ? [{ label: "Shipping", amount: totals.shippingTotal }] : []
|
|
1039
|
+
];
|
|
1040
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn("rounded-lg border border-border bg-surface-raised p-4 space-y-2", className), children: [
|
|
1041
|
+
lines.map(({ label, amount, isDiscount }) => /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between text-sm", children: [
|
|
1042
|
+
/* @__PURE__ */ jsx14("span", { className: "text-text-secondary", children: label }),
|
|
1043
|
+
/* @__PURE__ */ jsx14(
|
|
1044
|
+
PriceDisplay,
|
|
1045
|
+
{
|
|
1046
|
+
amount: Math.abs(amount),
|
|
1047
|
+
currency,
|
|
1048
|
+
locale,
|
|
1049
|
+
className: cn(isDiscount && "text-success-fg")
|
|
1050
|
+
}
|
|
1051
|
+
)
|
|
1052
|
+
] }, label)),
|
|
1053
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between pt-3 border-t border-border", children: [
|
|
1054
|
+
/* @__PURE__ */ jsx14("span", { className: "text-sm font-semibold text-text-primary", children: "Total" }),
|
|
1055
|
+
/* @__PURE__ */ jsx14(PriceDisplay, { amount: totals.total, currency, locale, size: "lg" })
|
|
1056
|
+
] })
|
|
1057
|
+
] });
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// modules/domains/common/cart/CartSummary.tsx
|
|
1061
|
+
import { FontAwesomeIcon as FontAwesomeIcon13 } from "@fortawesome/react-fontawesome";
|
|
1062
|
+
import { faCartShopping as faCartShopping3 } from "@fortawesome/free-solid-svg-icons";
|
|
1063
|
+
|
|
1064
|
+
// modules/domains/common/discount/CouponInput.tsx
|
|
1065
|
+
import { useState as useState9 } from "react";
|
|
1066
|
+
import { FontAwesomeIcon as FontAwesomeIcon12 } from "@fortawesome/react-fontawesome";
|
|
1067
|
+
import { faCheck } from "@fortawesome/free-solid-svg-icons";
|
|
1068
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1069
|
+
function CouponInput({ onApply, onRemove, appliedCode, className }) {
|
|
1070
|
+
const [code, setCode] = useState9("");
|
|
1071
|
+
const [state, setState] = useState9("idle");
|
|
1072
|
+
const [message, setMessage] = useState9("");
|
|
1073
|
+
async function handleApply() {
|
|
1074
|
+
var _a3, _b;
|
|
1075
|
+
const trimmed = code.trim().toUpperCase();
|
|
1076
|
+
if (!trimmed) return;
|
|
1077
|
+
setState("loading");
|
|
1078
|
+
setMessage("");
|
|
1079
|
+
try {
|
|
1080
|
+
const result = await onApply(trimmed);
|
|
1081
|
+
if (result.success) {
|
|
1082
|
+
setState("success");
|
|
1083
|
+
setMessage((_a3 = result.message) != null ? _a3 : "Coupon applied!");
|
|
1084
|
+
setCode("");
|
|
1085
|
+
} else {
|
|
1086
|
+
setState("error");
|
|
1087
|
+
setMessage((_b = result.message) != null ? _b : "Invalid coupon code.");
|
|
1088
|
+
}
|
|
1089
|
+
} catch (e) {
|
|
1090
|
+
setState("error");
|
|
1091
|
+
setMessage("Failed to apply coupon. Try again.");
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
function handleRemove() {
|
|
1095
|
+
setState("idle");
|
|
1096
|
+
setMessage("");
|
|
1097
|
+
setCode("");
|
|
1098
|
+
onRemove == null ? void 0 : onRemove();
|
|
1099
|
+
}
|
|
1100
|
+
if (appliedCode) {
|
|
1101
|
+
return /* @__PURE__ */ jsxs13("div", { className: cn("flex items-center justify-between gap-3 rounded-lg bg-success-subtle border border-success px-4 py-2.5", className), children: [
|
|
1102
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
1103
|
+
/* @__PURE__ */ jsx15(FontAwesomeIcon12, { icon: faCheck, className: "w-3.5 h-3.5 text-success-fg", "aria-hidden": "true" }),
|
|
1104
|
+
/* @__PURE__ */ jsxs13("span", { className: "text-sm font-medium text-success-fg truncate", children: [
|
|
1105
|
+
/* @__PURE__ */ jsx15("span", { className: "font-mono", children: appliedCode }),
|
|
1106
|
+
" applied"
|
|
1107
|
+
] })
|
|
1108
|
+
] }),
|
|
1109
|
+
onRemove && /* @__PURE__ */ jsx15(
|
|
1110
|
+
Button,
|
|
1111
|
+
{
|
|
1112
|
+
variant: "ghost",
|
|
1113
|
+
size: "xs",
|
|
1114
|
+
onClick: handleRemove,
|
|
1115
|
+
className: "text-success-fg underline hover:no-underline shrink-0",
|
|
1116
|
+
children: "Remove"
|
|
1117
|
+
}
|
|
1118
|
+
)
|
|
1119
|
+
] });
|
|
1120
|
+
}
|
|
1121
|
+
return /* @__PURE__ */ jsxs13("div", { className: cn("space-y-1.5", className), children: [
|
|
1122
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex gap-2", children: [
|
|
1123
|
+
/* @__PURE__ */ jsx15(
|
|
1124
|
+
Input,
|
|
1125
|
+
{
|
|
1126
|
+
id: "coupon-code",
|
|
1127
|
+
label: "",
|
|
1128
|
+
placeholder: "Enter coupon code",
|
|
1129
|
+
value: code,
|
|
1130
|
+
onChange: (e) => {
|
|
1131
|
+
setCode(e.target.value.toUpperCase());
|
|
1132
|
+
setState("idle");
|
|
1133
|
+
setMessage("");
|
|
1134
|
+
},
|
|
1135
|
+
onKeyDown: (e) => e.key === "Enter" && (e.preventDefault(), handleApply()),
|
|
1136
|
+
className: "flex-1",
|
|
1137
|
+
"aria-label": "Coupon code"
|
|
1138
|
+
}
|
|
1139
|
+
),
|
|
1140
|
+
/* @__PURE__ */ jsx15(
|
|
1141
|
+
Button,
|
|
1142
|
+
{
|
|
1143
|
+
variant: "outline",
|
|
1144
|
+
loading: state === "loading",
|
|
1145
|
+
disabled: !code.trim(),
|
|
1146
|
+
onClick: handleApply,
|
|
1147
|
+
className: "shrink-0 self-end mb-0.5",
|
|
1148
|
+
children: "Apply"
|
|
1149
|
+
}
|
|
1150
|
+
)
|
|
1151
|
+
] }),
|
|
1152
|
+
message && /* @__PURE__ */ jsx15("p", { className: cn("text-xs", state === "success" ? "text-success-fg" : "text-error"), children: message })
|
|
1153
|
+
] });
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
// modules/domains/common/cart/CartSummary.tsx
|
|
1157
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1158
|
+
function CartSummary({
|
|
1159
|
+
cart,
|
|
1160
|
+
onQuantityChange,
|
|
1161
|
+
onRemove,
|
|
1162
|
+
onCouponApply,
|
|
1163
|
+
onCouponRemove,
|
|
1164
|
+
appliedCoupon,
|
|
1165
|
+
onCheckout,
|
|
1166
|
+
checkoutLabel = "Proceed to Checkout",
|
|
1167
|
+
showTotals = true,
|
|
1168
|
+
showCoupon = true,
|
|
1169
|
+
className
|
|
1170
|
+
}) {
|
|
1171
|
+
if (cart.items.length === 0) {
|
|
1172
|
+
return /* @__PURE__ */ jsxs14("div", { className: cn("flex flex-col items-center justify-center gap-3 py-12 text-center", className), children: [
|
|
1173
|
+
/* @__PURE__ */ jsx16(FontAwesomeIcon13, { icon: faCartShopping3, className: "w-10 h-10 text-text-disabled", "aria-hidden": "true" }),
|
|
1174
|
+
/* @__PURE__ */ jsx16("p", { className: "font-medium text-text-primary", children: "Your cart is empty" }),
|
|
1175
|
+
/* @__PURE__ */ jsx16("p", { className: "text-sm text-text-secondary", children: "Add items to get started" })
|
|
1176
|
+
] });
|
|
1177
|
+
}
|
|
1178
|
+
return /* @__PURE__ */ jsxs14("div", { className: cn("space-y-4", className), children: [
|
|
1179
|
+
/* @__PURE__ */ jsx16("div", { className: "divide-y divide-border", children: cart.items.map((item) => /* @__PURE__ */ jsx16(
|
|
1180
|
+
CartItem,
|
|
1181
|
+
{
|
|
1182
|
+
item,
|
|
1183
|
+
onQuantityChange,
|
|
1184
|
+
onRemove,
|
|
1185
|
+
className: "py-4 first:pt-0 last:pb-0"
|
|
1186
|
+
},
|
|
1187
|
+
item.cartItemId
|
|
1188
|
+
)) }),
|
|
1189
|
+
showCoupon && onCouponApply && /* @__PURE__ */ jsx16(
|
|
1190
|
+
CouponInput,
|
|
1191
|
+
{
|
|
1192
|
+
appliedCode: appliedCoupon,
|
|
1193
|
+
onApply: onCouponApply,
|
|
1194
|
+
onRemove: onCouponRemove
|
|
1195
|
+
}
|
|
1196
|
+
),
|
|
1197
|
+
showTotals && /* @__PURE__ */ jsx16(OrderTotalsCard, { totals: cart.totals }),
|
|
1198
|
+
onCheckout && /* @__PURE__ */ jsx16(Button, { fullWidth: true, onClick: onCheckout, className: "h-11 font-semibold", children: checkoutLabel })
|
|
1199
|
+
] });
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
// modules/domains/common/charts/Charts.tsx
|
|
1203
|
+
import {
|
|
1204
|
+
Chart as ChartJS,
|
|
1205
|
+
CategoryScale,
|
|
1206
|
+
LinearScale,
|
|
1207
|
+
BarElement,
|
|
1208
|
+
LineElement,
|
|
1209
|
+
PointElement,
|
|
1210
|
+
ArcElement,
|
|
1211
|
+
RadialLinearScale,
|
|
1212
|
+
Filler,
|
|
1213
|
+
Tooltip,
|
|
1214
|
+
Legend,
|
|
1215
|
+
Title
|
|
1216
|
+
} from "chart.js";
|
|
1217
|
+
import { Bar, Line, Doughnut, Radar, PolarArea } from "react-chartjs-2";
|
|
1218
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1219
|
+
ChartJS.register(
|
|
1220
|
+
CategoryScale,
|
|
1221
|
+
LinearScale,
|
|
1222
|
+
BarElement,
|
|
1223
|
+
LineElement,
|
|
1224
|
+
PointElement,
|
|
1225
|
+
ArcElement,
|
|
1226
|
+
RadialLinearScale,
|
|
1227
|
+
Filler,
|
|
1228
|
+
Tooltip,
|
|
1229
|
+
Legend,
|
|
1230
|
+
Title
|
|
1231
|
+
);
|
|
1232
|
+
function ChartCard({ title, subtitle, children, className }) {
|
|
1233
|
+
return /* @__PURE__ */ jsxs15(
|
|
1234
|
+
"div",
|
|
1235
|
+
{
|
|
1236
|
+
className: cn(
|
|
1237
|
+
"rounded-xl border border-border bg-surface-raised p-5 shadow-sm",
|
|
1238
|
+
className
|
|
1239
|
+
),
|
|
1240
|
+
children: [
|
|
1241
|
+
/* @__PURE__ */ jsxs15("div", { className: "mb-4", children: [
|
|
1242
|
+
/* @__PURE__ */ jsx17("h3", { className: "text-sm font-semibold text-text-primary", children: title }),
|
|
1243
|
+
subtitle && /* @__PURE__ */ jsx17("p", { className: "mt-0.5 text-xs text-text-secondary", children: subtitle })
|
|
1244
|
+
] }),
|
|
1245
|
+
children
|
|
1246
|
+
]
|
|
1247
|
+
}
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
var BAR_DATA = {
|
|
1251
|
+
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
|
|
1252
|
+
datasets: [
|
|
1253
|
+
{
|
|
1254
|
+
label: "Revenue",
|
|
1255
|
+
data: [4200, 5800, 4900, 7100, 6300, 8400],
|
|
1256
|
+
backgroundColor: "rgba(59, 130, 246, 0.8)",
|
|
1257
|
+
borderRadius: 6
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
label: "Expenses",
|
|
1261
|
+
data: [2800, 3200, 3600, 4100, 3900, 4700],
|
|
1262
|
+
backgroundColor: "rgba(139, 92, 246, 0.8)",
|
|
1263
|
+
borderRadius: 6
|
|
1264
|
+
}
|
|
1265
|
+
]
|
|
1266
|
+
};
|
|
1267
|
+
function RevenueBarChart({ className }) {
|
|
1268
|
+
return /* @__PURE__ */ jsx17(
|
|
1269
|
+
ChartCard,
|
|
1270
|
+
{
|
|
1271
|
+
title: "Revenue vs Expenses",
|
|
1272
|
+
subtitle: "Monthly comparison (USD)",
|
|
1273
|
+
className,
|
|
1274
|
+
children: /* @__PURE__ */ jsx17(
|
|
1275
|
+
Bar,
|
|
1276
|
+
{
|
|
1277
|
+
data: BAR_DATA,
|
|
1278
|
+
options: {
|
|
1279
|
+
responsive: true,
|
|
1280
|
+
plugins: { legend: { position: "top" } },
|
|
1281
|
+
scales: { y: { beginAtZero: true } }
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
)
|
|
1285
|
+
}
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
var LINE_DATA = {
|
|
1289
|
+
labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
|
1290
|
+
datasets: [
|
|
1291
|
+
{
|
|
1292
|
+
label: "Active Users",
|
|
1293
|
+
data: [1200, 1900, 1500, 2300, 2100, 2800, 1700],
|
|
1294
|
+
borderColor: "rgb(59, 130, 246)",
|
|
1295
|
+
backgroundColor: "rgba(59, 130, 246, 0.1)",
|
|
1296
|
+
fill: true,
|
|
1297
|
+
tension: 0.4
|
|
1298
|
+
},
|
|
1299
|
+
{
|
|
1300
|
+
label: "New Signups",
|
|
1301
|
+
data: [300, 480, 220, 560, 410, 690, 320],
|
|
1302
|
+
borderColor: "rgb(34, 197, 94)",
|
|
1303
|
+
backgroundColor: "rgba(34, 197, 94, 0.1)",
|
|
1304
|
+
fill: true,
|
|
1305
|
+
tension: 0.4
|
|
1306
|
+
}
|
|
1307
|
+
]
|
|
1308
|
+
};
|
|
1309
|
+
function UserActivityLineChart({ className }) {
|
|
1310
|
+
return /* @__PURE__ */ jsx17(
|
|
1311
|
+
ChartCard,
|
|
1312
|
+
{
|
|
1313
|
+
title: "User Activity",
|
|
1314
|
+
subtitle: "Daily active users vs new signups",
|
|
1315
|
+
className,
|
|
1316
|
+
children: /* @__PURE__ */ jsx17(
|
|
1317
|
+
Line,
|
|
1318
|
+
{
|
|
1319
|
+
data: LINE_DATA,
|
|
1320
|
+
options: {
|
|
1321
|
+
responsive: true,
|
|
1322
|
+
plugins: { legend: { position: "top" } },
|
|
1323
|
+
scales: { y: { beginAtZero: true } }
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
)
|
|
1327
|
+
}
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
var DOUGHNUT_DATA = {
|
|
1331
|
+
labels: ["Electronics", "Clothing", "Food", "Books", "Other"],
|
|
1332
|
+
datasets: [
|
|
1333
|
+
{
|
|
1334
|
+
data: [35, 25, 20, 12, 8],
|
|
1335
|
+
backgroundColor: [
|
|
1336
|
+
"rgba(59, 130, 246, 0.85)",
|
|
1337
|
+
"rgba(139, 92, 246, 0.85)",
|
|
1338
|
+
"rgba(34, 197, 94, 0.85)",
|
|
1339
|
+
"rgba(245, 158, 11, 0.85)",
|
|
1340
|
+
"rgba(107, 114, 128, 0.85)"
|
|
1341
|
+
],
|
|
1342
|
+
borderWidth: 2,
|
|
1343
|
+
borderColor: "#fff"
|
|
1344
|
+
}
|
|
1345
|
+
]
|
|
1346
|
+
};
|
|
1347
|
+
function SalesByCategoryDoughnut({ className }) {
|
|
1348
|
+
return /* @__PURE__ */ jsx17(
|
|
1349
|
+
ChartCard,
|
|
1350
|
+
{
|
|
1351
|
+
title: "Sales by Category",
|
|
1352
|
+
subtitle: "Percentage share of total revenue",
|
|
1353
|
+
className,
|
|
1354
|
+
children: /* @__PURE__ */ jsx17("div", { className: "mx-auto max-w-xs", children: /* @__PURE__ */ jsx17(
|
|
1355
|
+
Doughnut,
|
|
1356
|
+
{
|
|
1357
|
+
data: DOUGHNUT_DATA,
|
|
1358
|
+
options: {
|
|
1359
|
+
responsive: true,
|
|
1360
|
+
plugins: { legend: { position: "bottom" } },
|
|
1361
|
+
cutout: "65%"
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
) })
|
|
1365
|
+
}
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
var RADAR_DATA = {
|
|
1369
|
+
labels: ["Speed", "Reliability", "Support", "Price", "Features", "UX"],
|
|
1370
|
+
datasets: [
|
|
1371
|
+
{
|
|
1372
|
+
label: "Our Product",
|
|
1373
|
+
data: [88, 92, 78, 70, 85, 90],
|
|
1374
|
+
borderColor: "rgb(59, 130, 246)",
|
|
1375
|
+
backgroundColor: "rgba(59, 130, 246, 0.2)",
|
|
1376
|
+
pointBackgroundColor: "rgb(59, 130, 246)"
|
|
1377
|
+
},
|
|
1378
|
+
{
|
|
1379
|
+
label: "Competitor",
|
|
1380
|
+
data: [72, 80, 65, 85, 75, 68],
|
|
1381
|
+
borderColor: "rgb(139, 92, 246)",
|
|
1382
|
+
backgroundColor: "rgba(139, 92, 246, 0.2)",
|
|
1383
|
+
pointBackgroundColor: "rgb(139, 92, 246)"
|
|
1384
|
+
}
|
|
1385
|
+
]
|
|
1386
|
+
};
|
|
1387
|
+
function ProductComparisonRadar({ className }) {
|
|
1388
|
+
return /* @__PURE__ */ jsx17(
|
|
1389
|
+
ChartCard,
|
|
1390
|
+
{
|
|
1391
|
+
title: "Product Comparison",
|
|
1392
|
+
subtitle: "Our product vs competitor across 6 dimensions",
|
|
1393
|
+
className,
|
|
1394
|
+
children: /* @__PURE__ */ jsx17(
|
|
1395
|
+
Radar,
|
|
1396
|
+
{
|
|
1397
|
+
data: RADAR_DATA,
|
|
1398
|
+
options: {
|
|
1399
|
+
responsive: true,
|
|
1400
|
+
plugins: { legend: { position: "top" } },
|
|
1401
|
+
scales: { r: { beginAtZero: true, max: 100 } }
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
)
|
|
1405
|
+
}
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
var POLAR_DATA = {
|
|
1409
|
+
labels: ["North", "South", "East", "West", "Central"],
|
|
1410
|
+
datasets: [
|
|
1411
|
+
{
|
|
1412
|
+
data: [42, 28, 35, 19, 56],
|
|
1413
|
+
backgroundColor: [
|
|
1414
|
+
"rgba(59, 130, 246, 0.75)",
|
|
1415
|
+
"rgba(34, 197, 94, 0.75)",
|
|
1416
|
+
"rgba(245, 158, 11, 0.75)",
|
|
1417
|
+
"rgba(239, 68, 68, 0.75)",
|
|
1418
|
+
"rgba(139, 92, 246, 0.75)"
|
|
1419
|
+
],
|
|
1420
|
+
borderWidth: 1
|
|
1421
|
+
}
|
|
1422
|
+
]
|
|
1423
|
+
};
|
|
1424
|
+
function RegionalSalesPolar({ className }) {
|
|
1425
|
+
return /* @__PURE__ */ jsx17(
|
|
1426
|
+
ChartCard,
|
|
1427
|
+
{
|
|
1428
|
+
title: "Regional Sales",
|
|
1429
|
+
subtitle: "Units sold per region",
|
|
1430
|
+
className,
|
|
1431
|
+
children: /* @__PURE__ */ jsx17("div", { className: "mx-auto max-w-xs", children: /* @__PURE__ */ jsx17(
|
|
1432
|
+
PolarArea,
|
|
1433
|
+
{
|
|
1434
|
+
data: POLAR_DATA,
|
|
1435
|
+
options: {
|
|
1436
|
+
responsive: true,
|
|
1437
|
+
plugins: { legend: { position: "bottom" } }
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
) })
|
|
1441
|
+
}
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// modules/domains/common/chat/ChatBox.tsx
|
|
1446
|
+
import { useState as useState10, useRef, useEffect } from "react";
|
|
1447
|
+
import { FontAwesomeIcon as FontAwesomeIcon14 } from "@fortawesome/react-fontawesome";
|
|
1448
|
+
import {
|
|
1449
|
+
faCommentDots,
|
|
1450
|
+
faTimes,
|
|
1451
|
+
faPaperPlane,
|
|
1452
|
+
faUser as faUser3,
|
|
1453
|
+
faRobot,
|
|
1454
|
+
faMinus
|
|
1455
|
+
} from "@fortawesome/free-solid-svg-icons";
|
|
1456
|
+
import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1457
|
+
function formatTime(date) {
|
|
1458
|
+
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
1459
|
+
}
|
|
1460
|
+
function ChatBox({
|
|
1461
|
+
title = "Support Chat",
|
|
1462
|
+
subtitle = "We typically reply in a few minutes",
|
|
1463
|
+
placeholder = "Type a message\u2026",
|
|
1464
|
+
initialMessages = [],
|
|
1465
|
+
onSend,
|
|
1466
|
+
className
|
|
1467
|
+
}) {
|
|
1468
|
+
const [open, setOpen] = useState10(false);
|
|
1469
|
+
const [minimised, setMinimised] = useState10(false);
|
|
1470
|
+
const [messages, setMessages] = useState10(initialMessages);
|
|
1471
|
+
const [input, setInput] = useState10("");
|
|
1472
|
+
const [loading, setLoading] = useState10(false);
|
|
1473
|
+
const [unread, setUnread] = useState10(0);
|
|
1474
|
+
const listRef = useRef(null);
|
|
1475
|
+
const inputRef = useRef(null);
|
|
1476
|
+
useEffect(() => {
|
|
1477
|
+
if (open) {
|
|
1478
|
+
setUnread(0);
|
|
1479
|
+
setTimeout(() => {
|
|
1480
|
+
var _a3;
|
|
1481
|
+
return (_a3 = inputRef.current) == null ? void 0 : _a3.focus();
|
|
1482
|
+
}, 120);
|
|
1483
|
+
}
|
|
1484
|
+
}, [open]);
|
|
1485
|
+
useEffect(() => {
|
|
1486
|
+
if (listRef.current) {
|
|
1487
|
+
listRef.current.scrollTop = listRef.current.scrollHeight;
|
|
1488
|
+
}
|
|
1489
|
+
}, [messages, open]);
|
|
1490
|
+
async function handleSend() {
|
|
1491
|
+
const text = input.trim();
|
|
1492
|
+
if (!text || loading) return;
|
|
1493
|
+
setInput("");
|
|
1494
|
+
const userMsg = {
|
|
1495
|
+
id: `u-${Date.now()}`,
|
|
1496
|
+
role: "user",
|
|
1497
|
+
text,
|
|
1498
|
+
timestamp: formatTime(/* @__PURE__ */ new Date())
|
|
1499
|
+
};
|
|
1500
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
1501
|
+
setLoading(true);
|
|
1502
|
+
try {
|
|
1503
|
+
const reply = onSend ? await onSend(text) : await new Promise((r) => setTimeout(() => r("Thanks for your message! We\u2019ll get back to you shortly."), 900));
|
|
1504
|
+
const agentMsg = {
|
|
1505
|
+
id: `a-${Date.now()}`,
|
|
1506
|
+
role: "agent",
|
|
1507
|
+
text: reply,
|
|
1508
|
+
timestamp: formatTime(/* @__PURE__ */ new Date())
|
|
1509
|
+
};
|
|
1510
|
+
setMessages((prev) => [...prev, agentMsg]);
|
|
1511
|
+
if (!open) setUnread((n) => n + 1);
|
|
1512
|
+
} finally {
|
|
1513
|
+
setLoading(false);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
function handleKeyDown(e) {
|
|
1517
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
1518
|
+
e.preventDefault();
|
|
1519
|
+
handleSend();
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
function toggleOpen() {
|
|
1523
|
+
setOpen((v) => !v);
|
|
1524
|
+
if (minimised) setMinimised(false);
|
|
1525
|
+
}
|
|
1526
|
+
return /* @__PURE__ */ jsxs16(
|
|
1527
|
+
"div",
|
|
1528
|
+
{
|
|
1529
|
+
className: cn("fixed bottom-6 right-6 z-50 flex flex-col items-end gap-3", className),
|
|
1530
|
+
role: "region",
|
|
1531
|
+
"aria-label": "Chat support",
|
|
1532
|
+
children: [
|
|
1533
|
+
open && /* @__PURE__ */ jsxs16(
|
|
1534
|
+
"div",
|
|
1535
|
+
{
|
|
1536
|
+
className: cn(
|
|
1537
|
+
"w-80 sm:w-96 rounded-2xl shadow-2xl border border-border overflow-hidden",
|
|
1538
|
+
"bg-surface-base flex flex-col transition-all duration-200",
|
|
1539
|
+
minimised ? "h-14" : "h-[480px]"
|
|
1540
|
+
),
|
|
1541
|
+
"aria-live": "polite",
|
|
1542
|
+
children: [
|
|
1543
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3 px-4 py-3 bg-primary text-primary-fg flex-shrink-0", children: [
|
|
1544
|
+
/* @__PURE__ */ jsx18("div", { className: "flex items-center justify-center w-8 h-8 rounded-full bg-white/20", children: /* @__PURE__ */ jsx18(FontAwesomeIcon14, { icon: faRobot, className: "w-4 h-4" }) }),
|
|
1545
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex-1 min-w-0", children: [
|
|
1546
|
+
/* @__PURE__ */ jsx18("p", { className: "text-sm font-semibold leading-tight truncate", children: title }),
|
|
1547
|
+
!minimised && /* @__PURE__ */ jsx18("p", { className: "text-xs text-primary-fg/70 truncate", children: subtitle })
|
|
1548
|
+
] }),
|
|
1549
|
+
/* @__PURE__ */ jsx18(
|
|
1550
|
+
"button",
|
|
1551
|
+
{
|
|
1552
|
+
onClick: () => setMinimised((v) => !v),
|
|
1553
|
+
"aria-label": minimised ? "Expand chat" : "Minimise chat",
|
|
1554
|
+
className: "flex items-center justify-center w-7 h-7 rounded-full hover:bg-white/20 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white",
|
|
1555
|
+
children: /* @__PURE__ */ jsx18(FontAwesomeIcon14, { icon: faMinus, className: "w-3 h-3" })
|
|
1556
|
+
}
|
|
1557
|
+
),
|
|
1558
|
+
/* @__PURE__ */ jsx18(
|
|
1559
|
+
"button",
|
|
1560
|
+
{
|
|
1561
|
+
onClick: () => setOpen(false),
|
|
1562
|
+
"aria-label": "Close chat",
|
|
1563
|
+
className: "flex items-center justify-center w-7 h-7 rounded-full hover:bg-white/20 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white",
|
|
1564
|
+
children: /* @__PURE__ */ jsx18(FontAwesomeIcon14, { icon: faTimes, className: "w-3 h-3" })
|
|
1565
|
+
}
|
|
1566
|
+
)
|
|
1567
|
+
] }),
|
|
1568
|
+
!minimised && /* @__PURE__ */ jsxs16(Fragment2, { children: [
|
|
1569
|
+
/* @__PURE__ */ jsxs16(
|
|
1570
|
+
"div",
|
|
1571
|
+
{
|
|
1572
|
+
ref: listRef,
|
|
1573
|
+
className: "flex-1 overflow-y-auto px-4 py-3 flex flex-col gap-3 scroll-smooth",
|
|
1574
|
+
children: [
|
|
1575
|
+
messages.length === 0 && /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center justify-center h-full gap-2 text-text-secondary", children: [
|
|
1576
|
+
/* @__PURE__ */ jsx18(FontAwesomeIcon14, { icon: faCommentDots, className: "w-8 h-8 opacity-30" }),
|
|
1577
|
+
/* @__PURE__ */ jsx18("p", { className: "text-sm", children: "Start the conversation" })
|
|
1578
|
+
] }),
|
|
1579
|
+
messages.map((msg) => /* @__PURE__ */ jsxs16(
|
|
1580
|
+
"div",
|
|
1581
|
+
{
|
|
1582
|
+
className: cn(
|
|
1583
|
+
"flex gap-2 items-end",
|
|
1584
|
+
msg.role === "user" ? "flex-row-reverse" : "flex-row"
|
|
1585
|
+
),
|
|
1586
|
+
children: [
|
|
1587
|
+
/* @__PURE__ */ jsx18(
|
|
1588
|
+
"div",
|
|
1589
|
+
{
|
|
1590
|
+
className: cn(
|
|
1591
|
+
"flex-shrink-0 flex items-center justify-center w-6 h-6 rounded-full text-xs",
|
|
1592
|
+
msg.role === "user" ? "bg-primary text-primary-fg" : "bg-surface-overlay text-text-secondary"
|
|
1593
|
+
),
|
|
1594
|
+
"aria-hidden": "true",
|
|
1595
|
+
children: /* @__PURE__ */ jsx18(
|
|
1596
|
+
FontAwesomeIcon14,
|
|
1597
|
+
{
|
|
1598
|
+
icon: msg.role === "user" ? faUser3 : faRobot,
|
|
1599
|
+
className: "w-3 h-3"
|
|
1600
|
+
}
|
|
1601
|
+
)
|
|
1602
|
+
}
|
|
1603
|
+
),
|
|
1604
|
+
/* @__PURE__ */ jsxs16(
|
|
1605
|
+
"div",
|
|
1606
|
+
{
|
|
1607
|
+
className: cn(
|
|
1608
|
+
"max-w-[75%] flex flex-col gap-0.5",
|
|
1609
|
+
msg.role === "user" ? "items-end" : "items-start"
|
|
1610
|
+
),
|
|
1611
|
+
children: [
|
|
1612
|
+
/* @__PURE__ */ jsx18(
|
|
1613
|
+
"div",
|
|
1614
|
+
{
|
|
1615
|
+
className: cn(
|
|
1616
|
+
"px-3 py-2 rounded-2xl text-sm leading-snug",
|
|
1617
|
+
msg.role === "user" ? "bg-primary text-primary-fg rounded-br-sm" : "bg-surface-raised border border-border text-text-primary rounded-bl-sm"
|
|
1618
|
+
),
|
|
1619
|
+
children: msg.text
|
|
1620
|
+
}
|
|
1621
|
+
),
|
|
1622
|
+
msg.timestamp && /* @__PURE__ */ jsx18("span", { className: "text-[10px] text-text-disabled px-1", children: msg.timestamp })
|
|
1623
|
+
]
|
|
1624
|
+
}
|
|
1625
|
+
)
|
|
1626
|
+
]
|
|
1627
|
+
},
|
|
1628
|
+
msg.id
|
|
1629
|
+
)),
|
|
1630
|
+
loading && /* @__PURE__ */ jsxs16("div", { className: "flex gap-2 items-end", children: [
|
|
1631
|
+
/* @__PURE__ */ jsx18("div", { className: "flex-shrink-0 flex items-center justify-center w-6 h-6 rounded-full bg-surface-overlay text-text-secondary", children: /* @__PURE__ */ jsx18(FontAwesomeIcon14, { icon: faRobot, className: "w-3 h-3" }) }),
|
|
1632
|
+
/* @__PURE__ */ jsx18("div", { className: "bg-surface-raised border border-border rounded-2xl rounded-bl-sm px-3 py-2", children: /* @__PURE__ */ jsxs16("span", { className: "flex gap-1 items-center", children: [
|
|
1633
|
+
/* @__PURE__ */ jsx18("span", { className: "w-1.5 h-1.5 rounded-full bg-text-disabled animate-bounce [animation-delay:0ms]" }),
|
|
1634
|
+
/* @__PURE__ */ jsx18("span", { className: "w-1.5 h-1.5 rounded-full bg-text-disabled animate-bounce [animation-delay:150ms]" }),
|
|
1635
|
+
/* @__PURE__ */ jsx18("span", { className: "w-1.5 h-1.5 rounded-full bg-text-disabled animate-bounce [animation-delay:300ms]" })
|
|
1636
|
+
] }) })
|
|
1637
|
+
] })
|
|
1638
|
+
]
|
|
1639
|
+
}
|
|
1640
|
+
),
|
|
1641
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex-shrink-0 border-t border-border bg-surface-base px-3 py-2 flex gap-2 items-end", children: [
|
|
1642
|
+
/* @__PURE__ */ jsx18(
|
|
1643
|
+
"textarea",
|
|
1644
|
+
{
|
|
1645
|
+
ref: inputRef,
|
|
1646
|
+
value: input,
|
|
1647
|
+
onChange: (e) => setInput(e.target.value),
|
|
1648
|
+
onKeyDown: handleKeyDown,
|
|
1649
|
+
placeholder,
|
|
1650
|
+
rows: 1,
|
|
1651
|
+
disabled: loading,
|
|
1652
|
+
"aria-label": "Chat message input",
|
|
1653
|
+
className: cn(
|
|
1654
|
+
"flex-1 resize-none rounded-xl border border-border bg-surface-raised px-3 py-2",
|
|
1655
|
+
"text-sm text-text-primary placeholder:text-text-disabled",
|
|
1656
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
1657
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1658
|
+
"max-h-28 overflow-y-auto leading-snug"
|
|
1659
|
+
),
|
|
1660
|
+
style: { height: 38 },
|
|
1661
|
+
onInput: (e) => {
|
|
1662
|
+
const el = e.currentTarget;
|
|
1663
|
+
el.style.height = "38px";
|
|
1664
|
+
el.style.height = `${Math.min(el.scrollHeight, 112)}px`;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
),
|
|
1668
|
+
/* @__PURE__ */ jsx18(
|
|
1669
|
+
"button",
|
|
1670
|
+
{
|
|
1671
|
+
onClick: handleSend,
|
|
1672
|
+
disabled: loading || !input.trim(),
|
|
1673
|
+
"aria-label": "Send message",
|
|
1674
|
+
className: cn(
|
|
1675
|
+
"flex-shrink-0 flex items-center justify-center w-9 h-9 rounded-xl",
|
|
1676
|
+
"bg-primary text-primary-fg",
|
|
1677
|
+
"hover:bg-primary-hover active:bg-primary-active transition-colors",
|
|
1678
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
1679
|
+
"disabled:opacity-50 disabled:cursor-not-allowed"
|
|
1680
|
+
),
|
|
1681
|
+
children: /* @__PURE__ */ jsx18(FontAwesomeIcon14, { icon: faPaperPlane, className: "w-3.5 h-3.5" })
|
|
1682
|
+
}
|
|
1683
|
+
)
|
|
1684
|
+
] })
|
|
1685
|
+
] })
|
|
1686
|
+
]
|
|
1687
|
+
}
|
|
1688
|
+
),
|
|
1689
|
+
/* @__PURE__ */ jsxs16(
|
|
1690
|
+
"button",
|
|
1691
|
+
{
|
|
1692
|
+
onClick: toggleOpen,
|
|
1693
|
+
"aria-label": open ? "Close chat" : "Open chat",
|
|
1694
|
+
"aria-expanded": open,
|
|
1695
|
+
className: cn(
|
|
1696
|
+
"relative flex items-center justify-center w-14 h-14 rounded-full shadow-xl",
|
|
1697
|
+
"bg-primary text-primary-fg",
|
|
1698
|
+
"hover:bg-primary-hover active:bg-primary-active transition-colors",
|
|
1699
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:ring-offset-2"
|
|
1700
|
+
),
|
|
1701
|
+
children: [
|
|
1702
|
+
/* @__PURE__ */ jsx18(
|
|
1703
|
+
FontAwesomeIcon14,
|
|
1704
|
+
{
|
|
1705
|
+
icon: open ? faTimes : faCommentDots,
|
|
1706
|
+
className: "w-6 h-6",
|
|
1707
|
+
"aria-hidden": "true"
|
|
1708
|
+
}
|
|
1709
|
+
),
|
|
1710
|
+
!open && unread > 0 && /* @__PURE__ */ jsx18("span", { className: "absolute -top-1 -right-1 flex items-center justify-center w-5 h-5 rounded-full bg-error text-white text-[10px] font-bold", children: unread > 9 ? "9+" : unread })
|
|
1711
|
+
]
|
|
1712
|
+
}
|
|
1713
|
+
)
|
|
1714
|
+
]
|
|
1715
|
+
}
|
|
1716
|
+
);
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
// modules/domains/common/discount/DiscountBadge.tsx
|
|
1720
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1721
|
+
var sizeMap2 = {
|
|
1722
|
+
sm: "text-xs px-1.5 py-0.5",
|
|
1723
|
+
md: "text-sm px-2 py-0.5",
|
|
1724
|
+
lg: "text-base px-2.5 py-1"
|
|
1725
|
+
};
|
|
1726
|
+
function DiscountBadge({ discountType, discountValue, currency = "TRY", size = "md", className }) {
|
|
1727
|
+
let label;
|
|
1728
|
+
if (discountType === "PERCENTAGE") {
|
|
1729
|
+
label = `${discountValue}% off`;
|
|
1730
|
+
} else if (discountType === "FIXED") {
|
|
1731
|
+
const formatted = new Intl.NumberFormat("tr-TR", { style: "currency", currency, maximumFractionDigits: 0 }).format(discountValue);
|
|
1732
|
+
label = `${formatted} off`;
|
|
1733
|
+
} else {
|
|
1734
|
+
label = "Free shipping";
|
|
1735
|
+
}
|
|
1736
|
+
return /* @__PURE__ */ jsx19(
|
|
1737
|
+
"span",
|
|
1738
|
+
{
|
|
1739
|
+
className: cn(
|
|
1740
|
+
"inline-flex items-center font-semibold rounded-full",
|
|
1741
|
+
"bg-error-subtle text-error border border-error/30",
|
|
1742
|
+
sizeMap2[size],
|
|
1743
|
+
className
|
|
1744
|
+
),
|
|
1745
|
+
children: label
|
|
1746
|
+
}
|
|
1747
|
+
);
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
// modules/domains/common/i18n/DirectionProvider.tsx
|
|
1751
|
+
import { createContext, useContext } from "react";
|
|
1752
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
1753
|
+
var DirectionContext = createContext({
|
|
1754
|
+
lang: "en",
|
|
1755
|
+
dir: "ltr",
|
|
1756
|
+
isRTL: false
|
|
1757
|
+
});
|
|
1758
|
+
function useDirection() {
|
|
1759
|
+
return useContext(DirectionContext);
|
|
1760
|
+
}
|
|
1761
|
+
function DirectionProvider({ lang, children, applyToDocument = false }) {
|
|
1762
|
+
const dir = getDirection(lang);
|
|
1763
|
+
if (applyToDocument && typeof document !== "undefined") {
|
|
1764
|
+
document.documentElement.dir = dir;
|
|
1765
|
+
document.documentElement.lang = lang;
|
|
1766
|
+
}
|
|
1767
|
+
return /* @__PURE__ */ jsx20(DirectionContext.Provider, { value: { lang, dir, isRTL: isRTL(lang) }, children: /* @__PURE__ */ jsx20("div", { dir, lang, children }) });
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
// modules/domains/common/i18n/LanguageSwitcher.tsx
|
|
1771
|
+
import { useState as useState11 } from "react";
|
|
1772
|
+
import { FontAwesomeIcon as FontAwesomeIcon15 } from "@fortawesome/react-fontawesome";
|
|
1773
|
+
import { faChevronDown as faChevronDown2 } from "@fortawesome/free-solid-svg-icons";
|
|
1774
|
+
import * as Flags from "country-flag-icons/react/3x2";
|
|
1775
|
+
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1776
|
+
var langToCountry2 = {
|
|
1777
|
+
en: "US",
|
|
1778
|
+
// veya 'GB' kullanılabilir
|
|
1779
|
+
tr: "TR",
|
|
1780
|
+
de: "DE",
|
|
1781
|
+
fr: "FR",
|
|
1782
|
+
ar: "SA"
|
|
1783
|
+
};
|
|
1784
|
+
function getFlag(lang) {
|
|
1785
|
+
const countryCode = langToCountry2[lang];
|
|
1786
|
+
if (countryCode) {
|
|
1787
|
+
const FlagComp = Flags[countryCode];
|
|
1788
|
+
if (FlagComp) {
|
|
1789
|
+
return /* @__PURE__ */ jsx21(FlagComp, { className: "w-4 h-auto rounded-[2px] shadow-sm" });
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
return LANG_FLAGS[lang];
|
|
1793
|
+
}
|
|
1794
|
+
function LanguageSwitcher({
|
|
1795
|
+
value,
|
|
1796
|
+
onChange,
|
|
1797
|
+
languages = AVAILABLE_LANGUAGES,
|
|
1798
|
+
className
|
|
1799
|
+
}) {
|
|
1800
|
+
const [internal, setInternal] = useState11(DEFAULT_LANGUAGE);
|
|
1801
|
+
const current = value !== void 0 ? value : internal;
|
|
1802
|
+
const items = languages.map((lang) => ({
|
|
1803
|
+
type: "item",
|
|
1804
|
+
label: getLanguageName(lang),
|
|
1805
|
+
icon: getFlag(lang),
|
|
1806
|
+
// DropdownMenu string beklediği için cast ediyoruz
|
|
1807
|
+
onClick: () => {
|
|
1808
|
+
setInternal(lang);
|
|
1809
|
+
onChange == null ? void 0 : onChange(lang);
|
|
1810
|
+
}
|
|
1811
|
+
}));
|
|
1812
|
+
return /* @__PURE__ */ jsx21(
|
|
1813
|
+
DropdownMenu,
|
|
1814
|
+
{
|
|
1815
|
+
className,
|
|
1816
|
+
trigger: /* @__PURE__ */ jsxs17(Button, { variant: "outline", size: "sm", className: "gap-2", children: [
|
|
1817
|
+
/* @__PURE__ */ jsx21("span", { className: "w-4 flex items-center justify-center shrink-0", "aria-hidden": "true", children: getFlag(current) }),
|
|
1818
|
+
/* @__PURE__ */ jsx21("span", { children: getLanguageName(current) }),
|
|
1819
|
+
/* @__PURE__ */ jsx21(FontAwesomeIcon15, { icon: faChevronDown2, className: "w-3 h-3 text-text-disabled" })
|
|
1820
|
+
] }),
|
|
1821
|
+
items
|
|
1822
|
+
}
|
|
1823
|
+
);
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
// modules/domains/common/location/CountrySelector.tsx
|
|
1827
|
+
import { useState as useState12, useRef as useRef2, useEffect as useEffect2, useId } from "react";
|
|
1828
|
+
import { createPortal } from "react-dom";
|
|
1829
|
+
import { getCountryDataList } from "countries-list";
|
|
1830
|
+
import * as Flags2 from "country-flag-icons/react/3x2";
|
|
1831
|
+
import { FontAwesomeIcon as FontAwesomeIcon16 } from "@fortawesome/react-fontawesome";
|
|
1832
|
+
import { faChevronDown as faChevronDown3, faCheck as faCheck2 } from "@fortawesome/free-solid-svg-icons";
|
|
1833
|
+
import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1834
|
+
var ALL_COUNTRIES = getCountryDataList().map((c) => ({ iso2: c.iso2, name: c.name })).sort((a, b) => a.name.localeCompare(b.name));
|
|
1835
|
+
function CountryFlag({ iso2 }) {
|
|
1836
|
+
if (!iso2) return null;
|
|
1837
|
+
const FlagComp = Flags2[iso2];
|
|
1838
|
+
if (!FlagComp) return null;
|
|
1839
|
+
return /* @__PURE__ */ jsx22(FlagComp, { className: "w-4 h-auto rounded-[2px] shadow-sm shrink-0" });
|
|
1840
|
+
}
|
|
1841
|
+
function CountrySelector({
|
|
1842
|
+
value,
|
|
1843
|
+
onChange,
|
|
1844
|
+
id: idProp,
|
|
1845
|
+
label = "Country",
|
|
1846
|
+
placeholder = "Select country\u2026",
|
|
1847
|
+
disabled = false,
|
|
1848
|
+
hint,
|
|
1849
|
+
error,
|
|
1850
|
+
required,
|
|
1851
|
+
className
|
|
1852
|
+
}) {
|
|
1853
|
+
const uid = useId();
|
|
1854
|
+
const id = idProp != null ? idProp : uid;
|
|
1855
|
+
const [open, setOpen] = useState12(false);
|
|
1856
|
+
const [search, setSearch] = useState12("");
|
|
1857
|
+
const [rect, setRect] = useState12(null);
|
|
1858
|
+
const triggerRef = useRef2(null);
|
|
1859
|
+
const searchRef = useRef2(null);
|
|
1860
|
+
const portalId = `country-selector-portal-${id.replace(/:/g, "")}`;
|
|
1861
|
+
const selected = ALL_COUNTRIES.find((c) => c.iso2 === value);
|
|
1862
|
+
const filtered = search.trim() ? ALL_COUNTRIES.filter(
|
|
1863
|
+
(c) => c.name.toLowerCase().includes(search.toLowerCase()) || c.iso2.toLowerCase().includes(search.toLowerCase())
|
|
1864
|
+
) : ALL_COUNTRIES;
|
|
1865
|
+
function handleOpen() {
|
|
1866
|
+
if (disabled) return;
|
|
1867
|
+
if (!open && triggerRef.current) {
|
|
1868
|
+
setRect(triggerRef.current.getBoundingClientRect());
|
|
1869
|
+
}
|
|
1870
|
+
setOpen((p) => !p);
|
|
1871
|
+
}
|
|
1872
|
+
useEffect2(() => {
|
|
1873
|
+
if (!open) {
|
|
1874
|
+
setSearch("");
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1877
|
+
setTimeout(() => {
|
|
1878
|
+
var _a3;
|
|
1879
|
+
return (_a3 = searchRef.current) == null ? void 0 : _a3.focus();
|
|
1880
|
+
}, 0);
|
|
1881
|
+
function onOutside(e) {
|
|
1882
|
+
var _a3, _b;
|
|
1883
|
+
const target = e.target;
|
|
1884
|
+
if (!((_a3 = triggerRef.current) == null ? void 0 : _a3.contains(target)) && !((_b = document.getElementById(portalId)) == null ? void 0 : _b.contains(target))) {
|
|
1885
|
+
setOpen(false);
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
function onKey(e) {
|
|
1889
|
+
if (e.key === "Escape") setOpen(false);
|
|
1890
|
+
}
|
|
1891
|
+
function onScroll() {
|
|
1892
|
+
if (triggerRef.current) setRect(triggerRef.current.getBoundingClientRect());
|
|
1893
|
+
}
|
|
1894
|
+
document.addEventListener("mousedown", onOutside);
|
|
1895
|
+
document.addEventListener("keydown", onKey);
|
|
1896
|
+
window.addEventListener("scroll", onScroll, true);
|
|
1897
|
+
return () => {
|
|
1898
|
+
document.removeEventListener("mousedown", onOutside);
|
|
1899
|
+
document.removeEventListener("keydown", onKey);
|
|
1900
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
1901
|
+
};
|
|
1902
|
+
}, [open, portalId]);
|
|
1903
|
+
const hintId = hint ? `${id}-hint` : void 0;
|
|
1904
|
+
const errorId = error ? `${id}-error` : void 0;
|
|
1905
|
+
const panel = open && rect && /* @__PURE__ */ jsxs18(
|
|
1906
|
+
"div",
|
|
1907
|
+
{
|
|
1908
|
+
id: portalId,
|
|
1909
|
+
role: "listbox",
|
|
1910
|
+
"aria-label": "Select country",
|
|
1911
|
+
style: { position: "fixed", top: rect.bottom + 4, left: rect.left, width: rect.width, zIndex: 9999 },
|
|
1912
|
+
className: "rounded-lg border border-border bg-surface-raised shadow-lg",
|
|
1913
|
+
children: [
|
|
1914
|
+
/* @__PURE__ */ jsx22("div", { className: "p-2 border-b border-border", children: /* @__PURE__ */ jsx22(
|
|
1915
|
+
"input",
|
|
1916
|
+
{
|
|
1917
|
+
ref: searchRef,
|
|
1918
|
+
type: "text",
|
|
1919
|
+
value: search,
|
|
1920
|
+
onChange: (e) => setSearch(e.target.value),
|
|
1921
|
+
placeholder: "Search country\u2026",
|
|
1922
|
+
className: cn(
|
|
1923
|
+
"w-full rounded-md border border-border bg-surface-base px-2.5 py-1.5 text-sm text-text-primary",
|
|
1924
|
+
"placeholder:text-text-disabled",
|
|
1925
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus"
|
|
1926
|
+
)
|
|
1927
|
+
}
|
|
1928
|
+
) }),
|
|
1929
|
+
/* @__PURE__ */ jsxs18("ul", { className: "max-h-56 overflow-y-auto py-1", children: [
|
|
1930
|
+
filtered.length === 0 && /* @__PURE__ */ jsx22("li", { className: "px-3 py-2 text-sm text-text-secondary", children: "No results" }),
|
|
1931
|
+
filtered.map((opt) => {
|
|
1932
|
+
const active = opt.iso2 === value;
|
|
1933
|
+
return /* @__PURE__ */ jsx22("li", { children: /* @__PURE__ */ jsxs18(
|
|
1934
|
+
"button",
|
|
1935
|
+
{
|
|
1936
|
+
type: "button",
|
|
1937
|
+
role: "option",
|
|
1938
|
+
"aria-selected": active,
|
|
1939
|
+
onClick: () => {
|
|
1940
|
+
onChange(opt.iso2);
|
|
1941
|
+
setOpen(false);
|
|
1942
|
+
},
|
|
1943
|
+
className: cn(
|
|
1944
|
+
"flex w-full items-center gap-2 px-3 py-2 text-sm text-left transition-colors",
|
|
1945
|
+
"focus-visible:outline-none focus-visible:bg-surface-overlay",
|
|
1946
|
+
active ? "bg-primary-subtle text-primary font-medium" : "text-text-primary hover:bg-surface-overlay"
|
|
1947
|
+
),
|
|
1948
|
+
children: [
|
|
1949
|
+
/* @__PURE__ */ jsx22(CountryFlag, { iso2: opt.iso2 }),
|
|
1950
|
+
/* @__PURE__ */ jsx22("span", { className: "flex-1 truncate", children: opt.name }),
|
|
1951
|
+
/* @__PURE__ */ jsx22("span", { className: "text-xs text-text-secondary shrink-0", children: opt.iso2 }),
|
|
1952
|
+
active && /* @__PURE__ */ jsx22(FontAwesomeIcon16, { icon: faCheck2, className: "w-3 h-3 text-primary shrink-0", "aria-hidden": "true" })
|
|
1953
|
+
]
|
|
1954
|
+
}
|
|
1955
|
+
) }, opt.iso2);
|
|
1956
|
+
})
|
|
1957
|
+
] })
|
|
1958
|
+
]
|
|
1959
|
+
}
|
|
1960
|
+
);
|
|
1961
|
+
return /* @__PURE__ */ jsxs18("div", { className: cn("space-y-1", className), children: [
|
|
1962
|
+
label && /* @__PURE__ */ jsxs18("label", { htmlFor: id, className: "block text-sm font-medium text-text-primary", children: [
|
|
1963
|
+
label,
|
|
1964
|
+
required && /* @__PURE__ */ jsxs18(Fragment3, { children: [
|
|
1965
|
+
/* @__PURE__ */ jsx22("span", { className: "text-error ml-1", "aria-hidden": "true", children: "*" }),
|
|
1966
|
+
/* @__PURE__ */ jsx22("span", { className: "sr-only", children: "(required)" })
|
|
1967
|
+
] })
|
|
1968
|
+
] }),
|
|
1969
|
+
/* @__PURE__ */ jsx22("div", { ref: triggerRef, className: "relative w-full", children: /* @__PURE__ */ jsxs18(
|
|
1970
|
+
Button,
|
|
1971
|
+
{
|
|
1972
|
+
id,
|
|
1973
|
+
type: "button",
|
|
1974
|
+
variant: "outline",
|
|
1975
|
+
size: "sm",
|
|
1976
|
+
disabled,
|
|
1977
|
+
onClick: handleOpen,
|
|
1978
|
+
"aria-haspopup": "listbox",
|
|
1979
|
+
"aria-expanded": open,
|
|
1980
|
+
"aria-describedby": [hintId, errorId].filter(Boolean).join(" ") || void 0,
|
|
1981
|
+
"aria-invalid": !!error,
|
|
1982
|
+
"aria-required": required,
|
|
1983
|
+
className: cn(
|
|
1984
|
+
"w-full justify-between gap-2",
|
|
1985
|
+
error && "border-error ring-1 ring-error"
|
|
1986
|
+
),
|
|
1987
|
+
children: [
|
|
1988
|
+
/* @__PURE__ */ jsx22("span", { className: "flex items-center gap-2 min-w-0", children: selected ? /* @__PURE__ */ jsxs18(Fragment3, { children: [
|
|
1989
|
+
/* @__PURE__ */ jsx22(CountryFlag, { iso2: selected.iso2 }),
|
|
1990
|
+
/* @__PURE__ */ jsx22("span", { className: "truncate", children: selected.name })
|
|
1991
|
+
] }) : /* @__PURE__ */ jsx22("span", { className: "text-text-disabled truncate", children: placeholder }) }),
|
|
1992
|
+
/* @__PURE__ */ jsx22(FontAwesomeIcon16, { icon: faChevronDown3, className: "w-3 h-3 text-text-disabled shrink-0", "aria-hidden": "true" })
|
|
1993
|
+
]
|
|
1994
|
+
}
|
|
1995
|
+
) }),
|
|
1996
|
+
hint && !error && /* @__PURE__ */ jsx22("p", { id: hintId, className: "text-xs text-text-secondary", children: hint }),
|
|
1997
|
+
error && /* @__PURE__ */ jsx22("p", { id: errorId, className: "text-xs text-error", role: "alert", children: error }),
|
|
1998
|
+
isBrowser && createPortal(panel, document.body)
|
|
1999
|
+
] });
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
// modules/domains/common/location/GeoPointDisplay.tsx
|
|
2003
|
+
import { FontAwesomeIcon as FontAwesomeIcon17 } from "@fortawesome/react-fontawesome";
|
|
2004
|
+
import { faLocationDot as faLocationDot3 } from "@fortawesome/free-solid-svg-icons";
|
|
2005
|
+
import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2006
|
+
function GeoPointDisplay({
|
|
2007
|
+
point,
|
|
2008
|
+
label,
|
|
2009
|
+
showMapLink = true,
|
|
2010
|
+
precision = 6,
|
|
2011
|
+
className
|
|
2012
|
+
}) {
|
|
2013
|
+
const lat = point.latitude.toFixed(precision);
|
|
2014
|
+
const lng = point.longitude.toFixed(precision);
|
|
2015
|
+
const mapsUrl = `https://www.google.com/maps?q=${lat},${lng}`;
|
|
2016
|
+
return /* @__PURE__ */ jsxs19("div", { className: cn("inline-flex items-center gap-2 text-sm", className), children: [
|
|
2017
|
+
/* @__PURE__ */ jsx23(FontAwesomeIcon17, { icon: faLocationDot3, className: "w-3.5 h-3.5 text-text-disabled shrink-0", "aria-hidden": "true" }),
|
|
2018
|
+
/* @__PURE__ */ jsxs19("div", { className: "min-w-0", children: [
|
|
2019
|
+
label && /* @__PURE__ */ jsx23("p", { className: "text-xs text-text-secondary mb-0.5", children: label }),
|
|
2020
|
+
/* @__PURE__ */ jsxs19("p", { className: "font-mono text-text-primary tabular-nums", children: [
|
|
2021
|
+
lat,
|
|
2022
|
+
", ",
|
|
2023
|
+
lng
|
|
2024
|
+
] })
|
|
2025
|
+
] }),
|
|
2026
|
+
showMapLink && /* @__PURE__ */ jsx23(
|
|
2027
|
+
"a",
|
|
2028
|
+
{
|
|
2029
|
+
href: mapsUrl,
|
|
2030
|
+
target: "_blank",
|
|
2031
|
+
rel: "noopener noreferrer",
|
|
2032
|
+
className: "text-xs text-primary hover:text-primary-hover underline shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus rounded",
|
|
2033
|
+
"aria-label": `Open ${lat}, ${lng} in Google Maps`,
|
|
2034
|
+
children: "Map"
|
|
2035
|
+
}
|
|
2036
|
+
)
|
|
2037
|
+
] });
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
// modules/domains/common/location/LocationPicker.tsx
|
|
2041
|
+
import { useState as useState13 } from "react";
|
|
2042
|
+
import { getCountryDataList as getCountryDataList2 } from "countries-list";
|
|
2043
|
+
import { Fragment as Fragment4, jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2044
|
+
var COUNTRY_OPTIONS = getCountryDataList2().sort((a, b) => a.name.localeCompare(b.name)).map((c) => ({ value: c.iso2, label: c.name }));
|
|
2045
|
+
function LocationPicker({ initial = {}, onSubmit, onCancel, error, className }) {
|
|
2046
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
2047
|
+
const [values, setValues] = useState13({
|
|
2048
|
+
city: (_a3 = initial.city) != null ? _a3 : null,
|
|
2049
|
+
state: (_b = initial.state) != null ? _b : null,
|
|
2050
|
+
country: (_c = initial.country) != null ? _c : null,
|
|
2051
|
+
countryCode: (_d = initial.countryCode) != null ? _d : null,
|
|
2052
|
+
postalCode: (_e = initial.postalCode) != null ? _e : null,
|
|
2053
|
+
latitude: (_f = initial.latitude) != null ? _f : null,
|
|
2054
|
+
longitude: (_g = initial.longitude) != null ? _g : null
|
|
2055
|
+
});
|
|
2056
|
+
const [loading, setLoading] = useState13(false);
|
|
2057
|
+
function set(key, val) {
|
|
2058
|
+
setValues((v) => __spreadProps(__spreadValues({}, v), { [key]: val }));
|
|
2059
|
+
}
|
|
2060
|
+
function handleCountry(code) {
|
|
2061
|
+
var _a4;
|
|
2062
|
+
const country = COUNTRY_OPTIONS.find((c) => c.value === code);
|
|
2063
|
+
set("countryCode", code || null);
|
|
2064
|
+
set("country", (_a4 = country == null ? void 0 : country.label) != null ? _a4 : null);
|
|
2065
|
+
}
|
|
2066
|
+
async function handleSubmit(e) {
|
|
2067
|
+
e.preventDefault();
|
|
2068
|
+
setLoading(true);
|
|
2069
|
+
try {
|
|
2070
|
+
await onSubmit(values);
|
|
2071
|
+
} finally {
|
|
2072
|
+
setLoading(false);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
return /* @__PURE__ */ jsxs20(
|
|
2076
|
+
Form,
|
|
2077
|
+
{
|
|
2078
|
+
onSubmit: handleSubmit,
|
|
2079
|
+
error,
|
|
2080
|
+
columns: 2,
|
|
2081
|
+
className,
|
|
2082
|
+
actions: /* @__PURE__ */ jsxs20(Fragment4, { children: [
|
|
2083
|
+
onCancel && /* @__PURE__ */ jsx24(Button, { type: "button", variant: "outline", onClick: onCancel, disabled: loading, children: "Cancel" }),
|
|
2084
|
+
/* @__PURE__ */ jsx24(Button, { type: "submit", loading, children: "Save Location" })
|
|
2085
|
+
] }),
|
|
2086
|
+
children: [
|
|
2087
|
+
/* @__PURE__ */ jsx24(
|
|
2088
|
+
Select,
|
|
2089
|
+
{
|
|
2090
|
+
id: "loc-country",
|
|
2091
|
+
label: "Country",
|
|
2092
|
+
options: [{ value: "", label: "Select country\u2026" }, ...COUNTRY_OPTIONS],
|
|
2093
|
+
value: (_h = values.countryCode) != null ? _h : "",
|
|
2094
|
+
onChange: (e) => handleCountry(e.target.value)
|
|
2095
|
+
}
|
|
2096
|
+
),
|
|
2097
|
+
/* @__PURE__ */ jsx24(
|
|
2098
|
+
Input,
|
|
2099
|
+
{
|
|
2100
|
+
id: "loc-city",
|
|
2101
|
+
label: "City",
|
|
2102
|
+
value: (_i = values.city) != null ? _i : "",
|
|
2103
|
+
onChange: (e) => set("city", e.target.value || null)
|
|
2104
|
+
}
|
|
2105
|
+
),
|
|
2106
|
+
/* @__PURE__ */ jsx24(
|
|
2107
|
+
Input,
|
|
2108
|
+
{
|
|
2109
|
+
id: "loc-state",
|
|
2110
|
+
label: "State / Province",
|
|
2111
|
+
value: (_j = values.state) != null ? _j : "",
|
|
2112
|
+
onChange: (e) => set("state", e.target.value || null)
|
|
2113
|
+
}
|
|
2114
|
+
),
|
|
2115
|
+
/* @__PURE__ */ jsx24(
|
|
2116
|
+
Input,
|
|
2117
|
+
{
|
|
2118
|
+
id: "loc-postal",
|
|
2119
|
+
label: "Postal Code",
|
|
2120
|
+
value: (_k = values.postalCode) != null ? _k : "",
|
|
2121
|
+
onChange: (e) => set("postalCode", e.target.value || null)
|
|
2122
|
+
}
|
|
2123
|
+
),
|
|
2124
|
+
/* @__PURE__ */ jsx24(
|
|
2125
|
+
Input,
|
|
2126
|
+
{
|
|
2127
|
+
id: "loc-lat",
|
|
2128
|
+
label: "Latitude",
|
|
2129
|
+
type: "number",
|
|
2130
|
+
value: (_l = values.latitude) != null ? _l : "",
|
|
2131
|
+
onChange: (e) => set("latitude", e.target.value ? parseFloat(e.target.value) : null)
|
|
2132
|
+
}
|
|
2133
|
+
),
|
|
2134
|
+
/* @__PURE__ */ jsx24(
|
|
2135
|
+
Input,
|
|
2136
|
+
{
|
|
2137
|
+
id: "loc-lng",
|
|
2138
|
+
label: "Longitude",
|
|
2139
|
+
type: "number",
|
|
2140
|
+
value: (_m = values.longitude) != null ? _m : "",
|
|
2141
|
+
onChange: (e) => set("longitude", e.target.value ? parseFloat(e.target.value) : null)
|
|
2142
|
+
}
|
|
2143
|
+
)
|
|
2144
|
+
]
|
|
2145
|
+
}
|
|
2146
|
+
);
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
// modules/domains/common/money/CurrencySelector.tsx
|
|
2150
|
+
import { useState as useState14, useRef as useRef3, useEffect as useEffect3 } from "react";
|
|
2151
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
2152
|
+
import { getCountryDataList as getCountryDataList3 } from "countries-list";
|
|
2153
|
+
import * as Flags3 from "country-flag-icons/react/3x2";
|
|
2154
|
+
import { FontAwesomeIcon as FontAwesomeIcon18 } from "@fortawesome/react-fontawesome";
|
|
2155
|
+
import { faChevronDown as faChevronDown4 } from "@fortawesome/free-solid-svg-icons";
|
|
2156
|
+
import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2157
|
+
var currencyToCountry = {};
|
|
2158
|
+
var _seen = /* @__PURE__ */ new Set();
|
|
2159
|
+
for (const c of getCountryDataList3()) {
|
|
2160
|
+
for (const cur of c.currency) {
|
|
2161
|
+
if (!currencyToCountry[cur]) currencyToCountry[cur] = c.iso2;
|
|
2162
|
+
_seen.add(cur);
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
var ALL_CURRENCIES = Array.from(_seen).sort().map((cur) => ({ value: cur, countryCode: currencyToCountry[cur] }));
|
|
2166
|
+
function CurrencyFlag({ countryCode }) {
|
|
2167
|
+
if (!countryCode) return null;
|
|
2168
|
+
const FlagComp = Flags3[countryCode];
|
|
2169
|
+
if (!FlagComp) return null;
|
|
2170
|
+
return /* @__PURE__ */ jsx25(FlagComp, { className: "w-4 h-auto rounded-[2px] shadow-sm shrink-0" });
|
|
2171
|
+
}
|
|
2172
|
+
function CurrencySelector({
|
|
2173
|
+
value,
|
|
2174
|
+
onChange,
|
|
2175
|
+
id = "currency",
|
|
2176
|
+
label = "Currency",
|
|
2177
|
+
disabled = false,
|
|
2178
|
+
className
|
|
2179
|
+
}) {
|
|
2180
|
+
const [open, setOpen] = useState14(false);
|
|
2181
|
+
const [search, setSearch] = useState14("");
|
|
2182
|
+
const [rect, setRect] = useState14(null);
|
|
2183
|
+
const triggerRef = useRef3(null);
|
|
2184
|
+
const searchRef = useRef3(null);
|
|
2185
|
+
const filtered = search.trim() ? ALL_CURRENCIES.filter((c) => c.value.toLowerCase().includes(search.toLowerCase())) : ALL_CURRENCIES;
|
|
2186
|
+
function handleOpen() {
|
|
2187
|
+
if (disabled) return;
|
|
2188
|
+
if (!open && triggerRef.current) {
|
|
2189
|
+
setRect(triggerRef.current.getBoundingClientRect());
|
|
2190
|
+
}
|
|
2191
|
+
setOpen((p) => !p);
|
|
2192
|
+
}
|
|
2193
|
+
useEffect3(() => {
|
|
2194
|
+
if (!open) {
|
|
2195
|
+
setSearch("");
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2198
|
+
setTimeout(() => {
|
|
2199
|
+
var _a3;
|
|
2200
|
+
return (_a3 = searchRef.current) == null ? void 0 : _a3.focus();
|
|
2201
|
+
}, 0);
|
|
2202
|
+
function onOutside(e) {
|
|
2203
|
+
var _a3, _b;
|
|
2204
|
+
const target = e.target;
|
|
2205
|
+
if (!((_a3 = triggerRef.current) == null ? void 0 : _a3.contains(target)) && !((_b = document.getElementById("currency-portal")) == null ? void 0 : _b.contains(target))) {
|
|
2206
|
+
setOpen(false);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
function onKey(e) {
|
|
2210
|
+
if (e.key === "Escape") setOpen(false);
|
|
2211
|
+
}
|
|
2212
|
+
function onScroll() {
|
|
2213
|
+
if (triggerRef.current) setRect(triggerRef.current.getBoundingClientRect());
|
|
2214
|
+
}
|
|
2215
|
+
document.addEventListener("mousedown", onOutside);
|
|
2216
|
+
document.addEventListener("keydown", onKey);
|
|
2217
|
+
window.addEventListener("scroll", onScroll, true);
|
|
2218
|
+
return () => {
|
|
2219
|
+
document.removeEventListener("mousedown", onOutside);
|
|
2220
|
+
document.removeEventListener("keydown", onKey);
|
|
2221
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
2222
|
+
};
|
|
2223
|
+
}, [open]);
|
|
2224
|
+
const panel = open && rect && /* @__PURE__ */ jsxs21(
|
|
2225
|
+
"div",
|
|
2226
|
+
{
|
|
2227
|
+
id: "currency-portal",
|
|
2228
|
+
role: "listbox",
|
|
2229
|
+
"aria-label": "Select currency",
|
|
2230
|
+
style: { position: "fixed", top: rect.bottom + 4, left: rect.left, width: rect.width, zIndex: 9999 },
|
|
2231
|
+
className: "rounded-lg border border-border bg-surface-raised shadow-lg",
|
|
2232
|
+
children: [
|
|
2233
|
+
/* @__PURE__ */ jsx25("div", { className: "p-2 border-b border-border", children: /* @__PURE__ */ jsx25(
|
|
2234
|
+
"input",
|
|
2235
|
+
{
|
|
2236
|
+
ref: searchRef,
|
|
2237
|
+
type: "text",
|
|
2238
|
+
value: search,
|
|
2239
|
+
onChange: (e) => setSearch(e.target.value),
|
|
2240
|
+
placeholder: "Search currency\u2026",
|
|
2241
|
+
className: cn(
|
|
2242
|
+
"w-full rounded-md border border-border bg-surface-base px-2.5 py-1.5 text-sm text-text-primary",
|
|
2243
|
+
"placeholder:text-text-disabled",
|
|
2244
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus"
|
|
2245
|
+
)
|
|
2246
|
+
}
|
|
2247
|
+
) }),
|
|
2248
|
+
/* @__PURE__ */ jsxs21("ul", { className: "max-h-56 overflow-y-auto py-1", children: [
|
|
2249
|
+
filtered.length === 0 && /* @__PURE__ */ jsx25("li", { className: "px-3 py-2 text-sm text-text-secondary", children: "No results" }),
|
|
2250
|
+
filtered.map((opt) => /* @__PURE__ */ jsx25("li", { children: /* @__PURE__ */ jsxs21(
|
|
2251
|
+
"button",
|
|
2252
|
+
{
|
|
2253
|
+
type: "button",
|
|
2254
|
+
role: "option",
|
|
2255
|
+
"aria-selected": opt.value === value,
|
|
2256
|
+
onClick: () => {
|
|
2257
|
+
onChange(opt.value);
|
|
2258
|
+
setOpen(false);
|
|
2259
|
+
},
|
|
2260
|
+
className: cn(
|
|
2261
|
+
"flex w-full items-center gap-2 px-3 py-2 text-sm text-left transition-colors",
|
|
2262
|
+
"focus-visible:outline-none focus-visible:bg-surface-overlay",
|
|
2263
|
+
opt.value === value ? "bg-primary-subtle text-primary font-medium" : "text-text-primary hover:bg-surface-overlay"
|
|
2264
|
+
),
|
|
2265
|
+
children: [
|
|
2266
|
+
/* @__PURE__ */ jsx25(CurrencyFlag, { countryCode: opt.countryCode }),
|
|
2267
|
+
/* @__PURE__ */ jsx25("span", { children: opt.value })
|
|
2268
|
+
]
|
|
2269
|
+
}
|
|
2270
|
+
) }, opt.value))
|
|
2271
|
+
] })
|
|
2272
|
+
]
|
|
2273
|
+
}
|
|
2274
|
+
);
|
|
2275
|
+
return /* @__PURE__ */ jsxs21("div", { className: cn("space-y-1", className), children: [
|
|
2276
|
+
label && /* @__PURE__ */ jsx25("label", { htmlFor: id, className: "block text-sm font-medium text-text-primary", children: label }),
|
|
2277
|
+
/* @__PURE__ */ jsx25("div", { ref: triggerRef, className: "relative w-full", children: /* @__PURE__ */ jsxs21(
|
|
2278
|
+
Button,
|
|
2279
|
+
{
|
|
2280
|
+
id,
|
|
2281
|
+
type: "button",
|
|
2282
|
+
variant: "outline",
|
|
2283
|
+
size: "sm",
|
|
2284
|
+
disabled,
|
|
2285
|
+
onClick: handleOpen,
|
|
2286
|
+
"aria-haspopup": "listbox",
|
|
2287
|
+
"aria-expanded": open,
|
|
2288
|
+
className: "w-full justify-between gap-2",
|
|
2289
|
+
children: [
|
|
2290
|
+
/* @__PURE__ */ jsxs21("span", { className: "flex items-center gap-2", children: [
|
|
2291
|
+
/* @__PURE__ */ jsx25(CurrencyFlag, { countryCode: currencyToCountry[value] }),
|
|
2292
|
+
/* @__PURE__ */ jsx25("span", { children: value })
|
|
2293
|
+
] }),
|
|
2294
|
+
/* @__PURE__ */ jsx25(FontAwesomeIcon18, { icon: faChevronDown4, className: "w-3 h-3 text-text-disabled" })
|
|
2295
|
+
]
|
|
2296
|
+
}
|
|
2297
|
+
) }),
|
|
2298
|
+
isBrowser && createPortal2(panel, document.body)
|
|
2299
|
+
] });
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
// modules/domains/common/notification/NotificationMenu.tsx
|
|
2303
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState15 } from "react";
|
|
2304
|
+
import { FontAwesomeIcon as FontAwesomeIcon19 } from "@fortawesome/react-fontawesome";
|
|
2305
|
+
import { faBell } from "@fortawesome/free-solid-svg-icons";
|
|
2306
|
+
import { jsx as jsx26, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2307
|
+
var variantDot = {
|
|
2308
|
+
info: "bg-info",
|
|
2309
|
+
success: "bg-success",
|
|
2310
|
+
warning: "bg-warning",
|
|
2311
|
+
error: "bg-error"
|
|
2312
|
+
};
|
|
2313
|
+
function NotificationMenu({
|
|
2314
|
+
items,
|
|
2315
|
+
onMarkAllRead,
|
|
2316
|
+
onViewAll,
|
|
2317
|
+
align = "right",
|
|
2318
|
+
className
|
|
2319
|
+
}) {
|
|
2320
|
+
const [open, setOpen] = useState15(false);
|
|
2321
|
+
const containerRef = useRef4(null);
|
|
2322
|
+
const unreadCount = items.filter((n) => !n.read).length;
|
|
2323
|
+
useEffect4(() => {
|
|
2324
|
+
if (!open) return;
|
|
2325
|
+
function onOutside(e) {
|
|
2326
|
+
var _a3;
|
|
2327
|
+
if (!((_a3 = containerRef.current) == null ? void 0 : _a3.contains(e.target))) setOpen(false);
|
|
2328
|
+
}
|
|
2329
|
+
function onKey(e) {
|
|
2330
|
+
if (e.key === "Escape") setOpen(false);
|
|
2331
|
+
}
|
|
2332
|
+
document.addEventListener("mousedown", onOutside);
|
|
2333
|
+
document.addEventListener("keydown", onKey);
|
|
2334
|
+
return () => {
|
|
2335
|
+
document.removeEventListener("mousedown", onOutside);
|
|
2336
|
+
document.removeEventListener("keydown", onKey);
|
|
2337
|
+
};
|
|
2338
|
+
}, [open]);
|
|
2339
|
+
return /* @__PURE__ */ jsxs22("div", { ref: containerRef, className: cn("relative", className), children: [
|
|
2340
|
+
/* @__PURE__ */ jsxs22(
|
|
2341
|
+
"button",
|
|
2342
|
+
{
|
|
2343
|
+
type: "button",
|
|
2344
|
+
"aria-label": `Notifications${unreadCount > 0 ? `, ${unreadCount} unread` : ""}`,
|
|
2345
|
+
"aria-haspopup": "dialog",
|
|
2346
|
+
"aria-expanded": open,
|
|
2347
|
+
onClick: () => setOpen((p) => !p),
|
|
2348
|
+
className: "relative flex items-center justify-center w-8 h-8 rounded-md text-text-secondary hover:bg-surface-overlay hover:text-text-primary transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
2349
|
+
children: [
|
|
2350
|
+
/* @__PURE__ */ jsx26(FontAwesomeIcon19, { icon: faBell, className: "w-4 h-4", "aria-hidden": "true" }),
|
|
2351
|
+
unreadCount > 0 && /* @__PURE__ */ jsx26("span", { className: "absolute -top-0.5 -right-0.5 flex items-center justify-center min-w-[1rem] h-4 px-1 rounded-full bg-error text-primary-fg text-[10px] font-bold leading-none pointer-events-none", children: unreadCount > 9 ? "9+" : unreadCount })
|
|
2352
|
+
]
|
|
2353
|
+
}
|
|
2354
|
+
),
|
|
2355
|
+
open && /* @__PURE__ */ jsxs22(
|
|
2356
|
+
"div",
|
|
2357
|
+
{
|
|
2358
|
+
role: "dialog",
|
|
2359
|
+
"aria-label": "Notifications",
|
|
2360
|
+
className: cn(
|
|
2361
|
+
"absolute top-full mt-2 z-50 w-80 rounded-xl border border-border bg-surface-raised shadow-xl overflow-hidden",
|
|
2362
|
+
align === "right" ? "right-0" : "left-0"
|
|
2363
|
+
),
|
|
2364
|
+
children: [
|
|
2365
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border", children: [
|
|
2366
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
|
|
2367
|
+
/* @__PURE__ */ jsx26("span", { className: "text-sm font-semibold text-text-primary", children: "Notifications" }),
|
|
2368
|
+
unreadCount > 0 && /* @__PURE__ */ jsx26("span", { className: "px-1.5 py-0.5 rounded-full bg-error text-primary-fg text-[10px] font-bold leading-none", children: unreadCount })
|
|
2369
|
+
] }),
|
|
2370
|
+
onMarkAllRead && unreadCount > 0 && /* @__PURE__ */ jsx26(
|
|
2371
|
+
"button",
|
|
2372
|
+
{
|
|
2373
|
+
type: "button",
|
|
2374
|
+
onClick: onMarkAllRead,
|
|
2375
|
+
className: "text-xs text-primary hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus rounded",
|
|
2376
|
+
children: "Mark all read"
|
|
2377
|
+
}
|
|
2378
|
+
)
|
|
2379
|
+
] }),
|
|
2380
|
+
/* @__PURE__ */ jsx26("div", { className: "max-h-80 overflow-y-auto divide-y divide-border", children: items.length === 0 ? /* @__PURE__ */ jsxs22("div", { className: "flex flex-col items-center justify-center py-10 gap-2 text-text-disabled", children: [
|
|
2381
|
+
/* @__PURE__ */ jsx26(FontAwesomeIcon19, { icon: faBell, className: "w-6 h-6", "aria-hidden": "true" }),
|
|
2382
|
+
/* @__PURE__ */ jsx26("p", { className: "text-sm", children: "No notifications" })
|
|
2383
|
+
] }) : items.map((item) => {
|
|
2384
|
+
var _a3;
|
|
2385
|
+
return /* @__PURE__ */ jsxs22(
|
|
2386
|
+
"button",
|
|
2387
|
+
{
|
|
2388
|
+
type: "button",
|
|
2389
|
+
onClick: () => {
|
|
2390
|
+
var _a4;
|
|
2391
|
+
(_a4 = item.onClick) == null ? void 0 : _a4.call(item);
|
|
2392
|
+
setOpen(false);
|
|
2393
|
+
},
|
|
2394
|
+
className: cn(
|
|
2395
|
+
"w-full flex items-start gap-3 px-4 py-3 text-left transition-colors",
|
|
2396
|
+
"hover:bg-surface-overlay focus-visible:outline-none focus-visible:bg-surface-overlay",
|
|
2397
|
+
!item.read && "bg-primary-subtle/40"
|
|
2398
|
+
),
|
|
2399
|
+
children: [
|
|
2400
|
+
/* @__PURE__ */ jsx26(
|
|
2401
|
+
"span",
|
|
2402
|
+
{
|
|
2403
|
+
className: cn(
|
|
2404
|
+
"mt-1.5 shrink-0 w-2 h-2 rounded-full",
|
|
2405
|
+
item.read ? "bg-transparent" : variantDot[(_a3 = item.variant) != null ? _a3 : "info"]
|
|
2406
|
+
),
|
|
2407
|
+
"aria-hidden": "true"
|
|
2408
|
+
}
|
|
2409
|
+
),
|
|
2410
|
+
/* @__PURE__ */ jsxs22("div", { className: "flex-1 min-w-0", children: [
|
|
2411
|
+
/* @__PURE__ */ jsx26("p", { className: cn(
|
|
2412
|
+
"text-sm truncate",
|
|
2413
|
+
item.read ? "text-text-secondary" : "text-text-primary font-medium"
|
|
2414
|
+
), children: item.title }),
|
|
2415
|
+
item.description && /* @__PURE__ */ jsx26("p", { className: "text-xs text-text-secondary mt-0.5 line-clamp-2", children: item.description }),
|
|
2416
|
+
/* @__PURE__ */ jsx26("p", { className: "text-[11px] text-text-disabled mt-1", children: item.timestamp })
|
|
2417
|
+
] })
|
|
2418
|
+
]
|
|
2419
|
+
},
|
|
2420
|
+
item.id
|
|
2421
|
+
);
|
|
2422
|
+
}) }),
|
|
2423
|
+
onViewAll && /* @__PURE__ */ jsx26("div", { className: "border-t border-border", children: /* @__PURE__ */ jsx26(
|
|
2424
|
+
"button",
|
|
2425
|
+
{
|
|
2426
|
+
type: "button",
|
|
2427
|
+
onClick: () => {
|
|
2428
|
+
onViewAll();
|
|
2429
|
+
setOpen(false);
|
|
2430
|
+
},
|
|
2431
|
+
className: "w-full py-2.5 text-xs text-primary font-medium hover:bg-surface-overlay transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
2432
|
+
children: "View all notifications"
|
|
2433
|
+
}
|
|
2434
|
+
) })
|
|
2435
|
+
]
|
|
2436
|
+
}
|
|
2437
|
+
)
|
|
2438
|
+
] });
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
// modules/domains/common/payment/CheckoutSuccessState.tsx
|
|
2442
|
+
import { FontAwesomeIcon as FontAwesomeIcon20 } from "@fortawesome/react-fontawesome";
|
|
2443
|
+
import { faCheck as faCheck3 } from "@fortawesome/free-solid-svg-icons";
|
|
2444
|
+
|
|
2445
|
+
// modules/domains/common/payment/PaymentStatusBadge.tsx
|
|
2446
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
2447
|
+
var statusMeta = {
|
|
2448
|
+
PENDING: { label: "Pending", variant: "warning" },
|
|
2449
|
+
AUTHORIZED: { label: "Authorized", variant: "info" },
|
|
2450
|
+
PAID: { label: "Paid", variant: "success" },
|
|
2451
|
+
FAILED: { label: "Failed", variant: "error" },
|
|
2452
|
+
CANCELLED: { label: "Cancelled", variant: "neutral" },
|
|
2453
|
+
REFUNDED: { label: "Refunded", variant: "info" }
|
|
2454
|
+
};
|
|
2455
|
+
function PaymentStatusBadge({ status, size = "md", dot = false }) {
|
|
2456
|
+
var _a3;
|
|
2457
|
+
const meta = (_a3 = statusMeta[status]) != null ? _a3 : { label: status, variant: "neutral" };
|
|
2458
|
+
return /* @__PURE__ */ jsx27(Badge, { variant: meta.variant, size, dot, children: meta.label });
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
// modules/domains/common/payment/PaymentSummaryCard.tsx
|
|
2462
|
+
import { jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2463
|
+
var METHOD_LABELS = {
|
|
2464
|
+
CREDIT_CARD: "Credit Card",
|
|
2465
|
+
DEBIT_CARD: "Debit Card",
|
|
2466
|
+
BANK_TRANSFER: "Bank Transfer",
|
|
2467
|
+
CASH: "Cash",
|
|
2468
|
+
WALLET: "Digital Wallet",
|
|
2469
|
+
CRYPTO: "Crypto"
|
|
2470
|
+
};
|
|
2471
|
+
function PaymentSummaryCard({ payment, className }) {
|
|
2472
|
+
var _a3;
|
|
2473
|
+
return /* @__PURE__ */ jsxs23("div", { className: cn("bg-surface-raised border border-border rounded-xl overflow-hidden", className), children: [
|
|
2474
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border bg-surface-overlay", children: [
|
|
2475
|
+
/* @__PURE__ */ jsx28("span", { className: "text-sm font-semibold text-text-primary", children: "Payment" }),
|
|
2476
|
+
/* @__PURE__ */ jsx28(PaymentStatusBadge, { status: payment.status, size: "sm", dot: true })
|
|
2477
|
+
] }),
|
|
2478
|
+
/* @__PURE__ */ jsxs23("div", { className: "px-4 py-4 space-y-3", children: [
|
|
2479
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between", children: [
|
|
2480
|
+
/* @__PURE__ */ jsx28("span", { className: "text-sm text-text-secondary", children: "Amount" }),
|
|
2481
|
+
/* @__PURE__ */ jsx28(PriceDisplay, { amount: payment.amount, currency: payment.currency, size: "lg" })
|
|
2482
|
+
] }),
|
|
2483
|
+
payment.method && /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between", children: [
|
|
2484
|
+
/* @__PURE__ */ jsx28("span", { className: "text-sm text-text-secondary", children: "Method" }),
|
|
2485
|
+
/* @__PURE__ */ jsx28("span", { className: "text-sm font-medium text-text-primary", children: (_a3 = METHOD_LABELS[payment.method]) != null ? _a3 : payment.method })
|
|
2486
|
+
] }),
|
|
2487
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between", children: [
|
|
2488
|
+
/* @__PURE__ */ jsx28("span", { className: "text-sm text-text-secondary", children: "Provider" }),
|
|
2489
|
+
/* @__PURE__ */ jsx28("span", { className: "text-sm font-medium text-text-primary", children: payment.provider })
|
|
2490
|
+
] }),
|
|
2491
|
+
payment.providerPaymentId && /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between gap-4", children: [
|
|
2492
|
+
/* @__PURE__ */ jsx28("span", { className: "text-sm text-text-secondary shrink-0", children: "Ref" }),
|
|
2493
|
+
/* @__PURE__ */ jsx28("span", { className: "text-xs font-mono text-text-secondary truncate text-right", children: payment.providerPaymentId })
|
|
2494
|
+
] })
|
|
2495
|
+
] })
|
|
2496
|
+
] });
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
// modules/domains/common/payment/CheckoutSuccessState.tsx
|
|
2500
|
+
import { jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2501
|
+
function CheckoutSuccessState({
|
|
2502
|
+
payment,
|
|
2503
|
+
address,
|
|
2504
|
+
onReset,
|
|
2505
|
+
locale = "tr-TR"
|
|
2506
|
+
}) {
|
|
2507
|
+
const fmt = new Intl.NumberFormat(locale, { style: "currency", currency: payment.currency });
|
|
2508
|
+
return /* @__PURE__ */ jsxs24("div", { className: "flex flex-col items-center justify-center py-16 space-y-6 text-center max-w-md mx-auto", children: [
|
|
2509
|
+
/* @__PURE__ */ jsx29("span", { className: "flex h-20 w-20 items-center justify-center rounded-full bg-success-subtle", children: /* @__PURE__ */ jsx29(FontAwesomeIcon20, { icon: faCheck3, className: "w-10 h-10 text-success", "aria-hidden": "true" }) }),
|
|
2510
|
+
/* @__PURE__ */ jsxs24("div", { className: "space-y-2", children: [
|
|
2511
|
+
/* @__PURE__ */ jsx29("h2", { className: "text-2xl font-bold text-text-primary", children: "Payment successful!" }),
|
|
2512
|
+
/* @__PURE__ */ jsxs24("p", { className: "text-text-secondary", children: [
|
|
2513
|
+
fmt.format(payment.amount),
|
|
2514
|
+
" was charged. A receipt has been sent to your email."
|
|
2515
|
+
] })
|
|
2516
|
+
] }),
|
|
2517
|
+
/* @__PURE__ */ jsxs24("div", { className: "w-full space-y-4 text-left", children: [
|
|
2518
|
+
/* @__PURE__ */ jsx29(PaymentSummaryCard, { payment }),
|
|
2519
|
+
address && /* @__PURE__ */ jsxs24("div", { className: "rounded-xl border border-border bg-surface-raised p-4 space-y-2", children: [
|
|
2520
|
+
/* @__PURE__ */ jsx29("p", { className: "text-xs font-semibold text-text-secondary uppercase tracking-wide", children: "Delivering to" }),
|
|
2521
|
+
/* @__PURE__ */ jsx29(AddressCard, { address })
|
|
2522
|
+
] })
|
|
2523
|
+
] }),
|
|
2524
|
+
onReset && /* @__PURE__ */ jsx29(Button, { variant: "outline", onClick: onReset, children: "Start over" })
|
|
2525
|
+
] });
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
// modules/domains/common/payment/CreditCardForm.tsx
|
|
2529
|
+
import { useState as useState16 } from "react";
|
|
2530
|
+
|
|
2531
|
+
// modules/domains/common/payment/CreditCardVisual.tsx
|
|
2532
|
+
import { jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2533
|
+
var BRAND_STYLE = {
|
|
2534
|
+
VISA: {
|
|
2535
|
+
label: "VISA",
|
|
2536
|
+
gradient: "from-[#1A1F71] to-[#0A0F3D]"
|
|
2537
|
+
},
|
|
2538
|
+
MASTERCARD: {
|
|
2539
|
+
label: "Mastercard",
|
|
2540
|
+
gradient: "from-[#EB001B] via-[#F79E1B] to-[#FF5F00]"
|
|
2541
|
+
},
|
|
2542
|
+
AMEX: {
|
|
2543
|
+
label: "AMEX",
|
|
2544
|
+
gradient: "from-[#2E77BC] to-[#006FCF]"
|
|
2545
|
+
},
|
|
2546
|
+
DISCOVER: {
|
|
2547
|
+
label: "Discover",
|
|
2548
|
+
gradient: "from-[#F58220] to-[#111827]"
|
|
2549
|
+
},
|
|
2550
|
+
TROY: {
|
|
2551
|
+
label: "TROY",
|
|
2552
|
+
gradient: "from-[#00AEEF] via-[#003B71] to-[#111827]"
|
|
2553
|
+
},
|
|
2554
|
+
MIR: {
|
|
2555
|
+
label: "MIR",
|
|
2556
|
+
gradient: "from-[#00A551] via-[#0072BC] to-[#111827]"
|
|
2557
|
+
},
|
|
2558
|
+
UNIONPAY: {
|
|
2559
|
+
label: "UnionPay",
|
|
2560
|
+
gradient: "from-[#E21836] via-[#00447C] to-[#007A3D]"
|
|
2561
|
+
},
|
|
2562
|
+
JCB: {
|
|
2563
|
+
label: "JCB",
|
|
2564
|
+
gradient: "from-[#0B5CAD] via-[#D71920] to-[#009A44]"
|
|
2565
|
+
},
|
|
2566
|
+
UNKNOWN: {
|
|
2567
|
+
label: "",
|
|
2568
|
+
gradient: "from-[#4B5563] to-[#111827]"
|
|
2569
|
+
}
|
|
2570
|
+
};
|
|
2571
|
+
function maskNumber(raw, brand) {
|
|
2572
|
+
const d = raw.replace(/\D/g, "").padEnd(brand === "AMEX" ? 15 : 16, "\u2022");
|
|
2573
|
+
if (brand === "AMEX") return `${d.slice(0, 4)} ${d.slice(4, 10)} ${d.slice(10, 15)}`;
|
|
2574
|
+
return `${d.slice(0, 4)} ${d.slice(4, 8)} ${d.slice(8, 12)} ${d.slice(12, 16)}`;
|
|
2575
|
+
}
|
|
2576
|
+
function CreditCardVisual({
|
|
2577
|
+
cardNumber = "",
|
|
2578
|
+
cardholderName = "",
|
|
2579
|
+
expiryMonth = "MM",
|
|
2580
|
+
expiryYear = "YY",
|
|
2581
|
+
cvv = "",
|
|
2582
|
+
brand = "UNKNOWN",
|
|
2583
|
+
flipped = false,
|
|
2584
|
+
className
|
|
2585
|
+
}) {
|
|
2586
|
+
const { label, gradient } = BRAND_STYLE[brand];
|
|
2587
|
+
return /* @__PURE__ */ jsx30(
|
|
2588
|
+
"div",
|
|
2589
|
+
{
|
|
2590
|
+
className: cn("w-72 h-44 select-none", className),
|
|
2591
|
+
style: { perspective: "1000px" },
|
|
2592
|
+
"aria-hidden": "true",
|
|
2593
|
+
children: /* @__PURE__ */ jsxs25(
|
|
2594
|
+
"div",
|
|
2595
|
+
{
|
|
2596
|
+
className: "relative w-full h-full transition-transform duration-500",
|
|
2597
|
+
style: { transformStyle: "preserve-3d", transform: flipped ? "rotateY(180deg)" : "rotateY(0deg)" },
|
|
2598
|
+
children: [
|
|
2599
|
+
/* @__PURE__ */ jsxs25(
|
|
2600
|
+
"div",
|
|
2601
|
+
{
|
|
2602
|
+
className: cn("absolute inset-0 rounded-2xl bg-gradient-to-br p-5 flex flex-col justify-between shadow-xl text-white", gradient),
|
|
2603
|
+
style: { backfaceVisibility: "hidden" },
|
|
2604
|
+
children: [
|
|
2605
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex justify-between items-start", children: [
|
|
2606
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex gap-1", children: [
|
|
2607
|
+
/* @__PURE__ */ jsx30("div", { className: "w-8 h-6 rounded bg-yellow-400/80" }),
|
|
2608
|
+
/* @__PURE__ */ jsx30("div", { className: "w-8 h-6 rounded bg-yellow-300/50 -ml-3" })
|
|
2609
|
+
] }),
|
|
2610
|
+
label && /* @__PURE__ */ jsx30("span", { className: "text-sm font-bold tracking-widest opacity-90", children: label })
|
|
2611
|
+
] }),
|
|
2612
|
+
/* @__PURE__ */ jsx30("p", { className: "font-mono text-lg tracking-widest", children: maskNumber(cardNumber, brand) }),
|
|
2613
|
+
/* @__PURE__ */ jsxs25("div", { className: "flex justify-between items-end", children: [
|
|
2614
|
+
/* @__PURE__ */ jsxs25("div", { children: [
|
|
2615
|
+
/* @__PURE__ */ jsx30("p", { className: "text-[9px] uppercase opacity-60 mb-0.5", children: "Card Holder" }),
|
|
2616
|
+
/* @__PURE__ */ jsx30("p", { className: "text-xs font-medium tracking-wide uppercase truncate max-w-[10rem]", children: cardholderName || "\u2022\u2022\u2022\u2022\u2022 \u2022\u2022\u2022\u2022\u2022" })
|
|
2617
|
+
] }),
|
|
2618
|
+
/* @__PURE__ */ jsxs25("div", { className: "text-right", children: [
|
|
2619
|
+
/* @__PURE__ */ jsx30("p", { className: "text-[9px] uppercase opacity-60 mb-0.5", children: "Expires" }),
|
|
2620
|
+
/* @__PURE__ */ jsxs25("p", { className: "text-xs font-medium font-mono", children: [
|
|
2621
|
+
expiryMonth,
|
|
2622
|
+
"/",
|
|
2623
|
+
expiryYear
|
|
2624
|
+
] })
|
|
2625
|
+
] })
|
|
2626
|
+
] })
|
|
2627
|
+
]
|
|
2628
|
+
}
|
|
2629
|
+
),
|
|
2630
|
+
/* @__PURE__ */ jsxs25(
|
|
2631
|
+
"div",
|
|
2632
|
+
{
|
|
2633
|
+
className: cn("absolute inset-0 rounded-2xl bg-gradient-to-br shadow-xl overflow-hidden text-white", gradient),
|
|
2634
|
+
style: { backfaceVisibility: "hidden", transform: "rotateY(180deg)" },
|
|
2635
|
+
children: [
|
|
2636
|
+
/* @__PURE__ */ jsx30("div", { className: "mt-7 h-10 bg-black/60 w-full" }),
|
|
2637
|
+
/* @__PURE__ */ jsxs25("div", { className: "px-5 mt-4 flex items-center justify-end gap-3", children: [
|
|
2638
|
+
/* @__PURE__ */ jsx30("div", { className: "flex-1 h-6 bg-white/20 rounded" }),
|
|
2639
|
+
/* @__PURE__ */ jsxs25("div", { className: "bg-white/90 rounded px-3 py-1 text-right min-w-[3.5rem]", children: [
|
|
2640
|
+
/* @__PURE__ */ jsx30("p", { className: "text-[9px] text-gray-500 mb-0.5", children: "CVV" }),
|
|
2641
|
+
/* @__PURE__ */ jsx30("p", { className: "font-mono text-sm text-gray-800 tracking-widest", children: cvv ? "\u2022".repeat(cvv.length) : "\u2022\u2022\u2022" })
|
|
2642
|
+
] })
|
|
2643
|
+
] }),
|
|
2644
|
+
label && /* @__PURE__ */ jsx30("p", { className: "absolute bottom-4 right-5 text-sm font-bold tracking-widest opacity-80", children: label })
|
|
2645
|
+
]
|
|
2646
|
+
}
|
|
2647
|
+
)
|
|
2648
|
+
]
|
|
2649
|
+
}
|
|
2650
|
+
)
|
|
2651
|
+
}
|
|
2652
|
+
);
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
// modules/domains/common/payment/CreditCardForm.tsx
|
|
2656
|
+
import { Fragment as Fragment5, jsx as jsx31, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2657
|
+
function detectBrand(number) {
|
|
2658
|
+
const n = number.replace(/\D/g, "");
|
|
2659
|
+
if (!n) return "UNKNOWN";
|
|
2660
|
+
const len = n.length;
|
|
2661
|
+
const prefix2 = len >= 2 ? Number(n.slice(0, 2)) : 0;
|
|
2662
|
+
const prefix3 = len >= 3 ? Number(n.slice(0, 3)) : 0;
|
|
2663
|
+
const prefix4 = len >= 4 ? Number(n.slice(0, 4)) : 0;
|
|
2664
|
+
const prefix6 = len >= 6 ? Number(n.slice(0, 6)) : 0;
|
|
2665
|
+
if (n.startsWith("9792")) return "TROY";
|
|
2666
|
+
if (prefix4 >= 2200 && prefix4 <= 2204) return "MIR";
|
|
2667
|
+
if (n.startsWith("62")) return "UNIONPAY";
|
|
2668
|
+
if (prefix4 >= 3528 && prefix4 <= 3589) return "JCB";
|
|
2669
|
+
if (n.startsWith("4")) return "VISA";
|
|
2670
|
+
if (prefix2 >= 51 && prefix2 <= 55) return "MASTERCARD";
|
|
2671
|
+
if (prefix4 >= 2221 && prefix4 <= 2720) return "MASTERCARD";
|
|
2672
|
+
if (prefix2 === 34 || prefix2 === 37) return "AMEX";
|
|
2673
|
+
if (n.startsWith("6011") || n.startsWith("65")) return "DISCOVER";
|
|
2674
|
+
if (prefix3 >= 644 && prefix3 <= 649) return "DISCOVER";
|
|
2675
|
+
if (prefix6 >= 622126 && prefix6 <= 622925) return "DISCOVER";
|
|
2676
|
+
return "UNKNOWN";
|
|
2677
|
+
}
|
|
2678
|
+
function formatNumber(raw, brand) {
|
|
2679
|
+
const digits = raw.replace(/\D/g, "");
|
|
2680
|
+
const maxLen = brand === "AMEX" ? 15 : 16;
|
|
2681
|
+
const trimmed = digits.slice(0, maxLen);
|
|
2682
|
+
if (brand === "AMEX") {
|
|
2683
|
+
return trimmed.replace(
|
|
2684
|
+
/(\d{4})(\d{0,6})(\d{0,5})/,
|
|
2685
|
+
(_, a, b, c) => [a, b, c].filter(Boolean).join(" ")
|
|
2686
|
+
);
|
|
2687
|
+
}
|
|
2688
|
+
return trimmed.replace(/(\d{4})(?=\d)/g, "$1 ");
|
|
2689
|
+
}
|
|
2690
|
+
function formatExpiry(raw) {
|
|
2691
|
+
const digits = raw.replace(/\D/g, "").slice(0, 4);
|
|
2692
|
+
return digits.length > 2 ? `${digits.slice(0, 2)}/${digits.slice(2)}` : digits;
|
|
2693
|
+
}
|
|
2694
|
+
function CreditCardForm({ onSubmit, onCancel, error, className }) {
|
|
2695
|
+
const [cardNumber, setCardNumber] = useState16("");
|
|
2696
|
+
const [cardholderName, setCardholderName] = useState16("");
|
|
2697
|
+
const [expiry, setExpiry] = useState16("");
|
|
2698
|
+
const [cvv, setCvv] = useState16("");
|
|
2699
|
+
const [cvvFocused, setCvvFocused] = useState16(false);
|
|
2700
|
+
const [errors, setErrors] = useState16({});
|
|
2701
|
+
const [loading, setLoading] = useState16(false);
|
|
2702
|
+
const brand = detectBrand(cardNumber);
|
|
2703
|
+
const maxCvv = brand === "AMEX" ? 4 : 3;
|
|
2704
|
+
function validate() {
|
|
2705
|
+
const next = {};
|
|
2706
|
+
const digits = cardNumber.replace(/\D/g, "");
|
|
2707
|
+
const minLen = brand === "AMEX" ? 15 : 16;
|
|
2708
|
+
if (digits.length < minLen) next.cardNumber = `Card number must be ${minLen} digits.`;
|
|
2709
|
+
const [mm, yy] = expiry.split("/");
|
|
2710
|
+
const month = parseInt(mm != null ? mm : "", 10);
|
|
2711
|
+
const year = parseInt(`20${yy != null ? yy : ""}`, 10);
|
|
2712
|
+
const now = /* @__PURE__ */ new Date();
|
|
2713
|
+
if (!mm || !yy || month < 1 || month > 12) {
|
|
2714
|
+
next.expiry = "Enter a valid expiry date (MM/YY).";
|
|
2715
|
+
} else if (year < now.getFullYear() || year === now.getFullYear() && month < now.getMonth() + 1) {
|
|
2716
|
+
next.expiry = "Card has expired.";
|
|
2717
|
+
}
|
|
2718
|
+
if (cvv.length < maxCvv) next.cvv = `CVV must be ${maxCvv} digits.`;
|
|
2719
|
+
if (!cardholderName.trim()) next.cardholderName = "Cardholder name is required.";
|
|
2720
|
+
setErrors(next);
|
|
2721
|
+
return Object.keys(next).length === 0;
|
|
2722
|
+
}
|
|
2723
|
+
async function handleSubmit(e) {
|
|
2724
|
+
e.preventDefault();
|
|
2725
|
+
if (!validate()) return;
|
|
2726
|
+
setLoading(true);
|
|
2727
|
+
try {
|
|
2728
|
+
await onSubmit({
|
|
2729
|
+
cardNumber: cardNumber.replace(/\s/g, ""),
|
|
2730
|
+
cardholderName: cardholderName.trim(),
|
|
2731
|
+
expiryMonth: expiry.split("/")[0],
|
|
2732
|
+
expiryYear: expiry.split("/")[1],
|
|
2733
|
+
cvv
|
|
2734
|
+
});
|
|
2735
|
+
} finally {
|
|
2736
|
+
setLoading(false);
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
return /* @__PURE__ */ jsxs26(
|
|
2740
|
+
Form,
|
|
2741
|
+
{
|
|
2742
|
+
onSubmit: handleSubmit,
|
|
2743
|
+
error,
|
|
2744
|
+
className,
|
|
2745
|
+
actions: /* @__PURE__ */ jsxs26(Fragment5, { children: [
|
|
2746
|
+
onCancel && /* @__PURE__ */ jsx31(Button, { type: "button", variant: "outline", onClick: onCancel, disabled: loading, children: "Cancel" }),
|
|
2747
|
+
/* @__PURE__ */ jsx31(Button, { type: "submit", loading, children: "Add Card" })
|
|
2748
|
+
] }),
|
|
2749
|
+
children: [
|
|
2750
|
+
/* @__PURE__ */ jsx31("div", { className: "flex justify-center mb-2", children: /* @__PURE__ */ jsx31(
|
|
2751
|
+
CreditCardVisual,
|
|
2752
|
+
{
|
|
2753
|
+
cardNumber,
|
|
2754
|
+
cardholderName,
|
|
2755
|
+
expiryMonth: expiry.split("/")[0] || "MM",
|
|
2756
|
+
expiryYear: expiry.split("/")[1] || "YY",
|
|
2757
|
+
cvv,
|
|
2758
|
+
brand,
|
|
2759
|
+
flipped: cvvFocused
|
|
2760
|
+
}
|
|
2761
|
+
) }),
|
|
2762
|
+
/* @__PURE__ */ jsx31(
|
|
2763
|
+
Input,
|
|
2764
|
+
{
|
|
2765
|
+
id: "card-number",
|
|
2766
|
+
label: "Card Number",
|
|
2767
|
+
placeholder: "1234 5678 9012 3456",
|
|
2768
|
+
value: cardNumber,
|
|
2769
|
+
inputMode: "numeric",
|
|
2770
|
+
autoComplete: "cc-number",
|
|
2771
|
+
onChange: (e) => setCardNumber(formatNumber(e.target.value, brand)),
|
|
2772
|
+
error: errors.cardNumber
|
|
2773
|
+
}
|
|
2774
|
+
),
|
|
2775
|
+
/* @__PURE__ */ jsx31(
|
|
2776
|
+
Input,
|
|
2777
|
+
{
|
|
2778
|
+
id: "cardholder-name",
|
|
2779
|
+
label: "Cardholder Name",
|
|
2780
|
+
placeholder: "Name on card",
|
|
2781
|
+
value: cardholderName,
|
|
2782
|
+
autoComplete: "cc-name",
|
|
2783
|
+
onChange: (e) => setCardholderName(e.target.value.toUpperCase()),
|
|
2784
|
+
error: errors.cardholderName
|
|
2785
|
+
}
|
|
2786
|
+
),
|
|
2787
|
+
/* @__PURE__ */ jsxs26("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
2788
|
+
/* @__PURE__ */ jsx31(
|
|
2789
|
+
Input,
|
|
2790
|
+
{
|
|
2791
|
+
id: "expiry",
|
|
2792
|
+
label: "Expiry",
|
|
2793
|
+
placeholder: "MM/YY",
|
|
2794
|
+
value: expiry,
|
|
2795
|
+
inputMode: "numeric",
|
|
2796
|
+
autoComplete: "cc-exp",
|
|
2797
|
+
onChange: (e) => setExpiry(formatExpiry(e.target.value)),
|
|
2798
|
+
error: errors.expiry
|
|
2799
|
+
}
|
|
2800
|
+
),
|
|
2801
|
+
/* @__PURE__ */ jsx31(
|
|
2802
|
+
Input,
|
|
2803
|
+
{
|
|
2804
|
+
id: "cvv",
|
|
2805
|
+
label: "CVV",
|
|
2806
|
+
type: "password",
|
|
2807
|
+
placeholder: "\u2022".repeat(maxCvv),
|
|
2808
|
+
value: cvv,
|
|
2809
|
+
inputMode: "numeric",
|
|
2810
|
+
autoComplete: "cc-csc",
|
|
2811
|
+
onChange: (e) => setCvv(e.target.value.replace(/\D/g, "").slice(0, maxCvv)),
|
|
2812
|
+
onFocus: () => setCvvFocused(true),
|
|
2813
|
+
onBlur: () => setCvvFocused(false),
|
|
2814
|
+
error: errors.cvv
|
|
2815
|
+
}
|
|
2816
|
+
)
|
|
2817
|
+
] })
|
|
2818
|
+
]
|
|
2819
|
+
}
|
|
2820
|
+
);
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
// modules/domains/common/payment/PaymentMethodSelector.tsx
|
|
2824
|
+
import { useState as useState17 } from "react";
|
|
2825
|
+
import { FontAwesomeIcon as FontAwesomeIcon21 } from "@fortawesome/react-fontawesome";
|
|
2826
|
+
import {
|
|
2827
|
+
faPaypal,
|
|
2828
|
+
faApple,
|
|
2829
|
+
faGoogle as faGoogle2,
|
|
2830
|
+
faBitcoin
|
|
2831
|
+
} from "@fortawesome/free-brands-svg-icons";
|
|
2832
|
+
import { faCreditCard } from "@fortawesome/free-solid-svg-icons";
|
|
2833
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
2834
|
+
var paymentOptions = [
|
|
2835
|
+
{ value: "CREDIT_CARD", label: "Credit Card", icon: /* @__PURE__ */ jsx32(FontAwesomeIcon21, { icon: faCreditCard, className: "h-4 w-4 text-blue-600" }) },
|
|
2836
|
+
{ value: "PAYPAL", label: "PayPal", icon: /* @__PURE__ */ jsx32(FontAwesomeIcon21, { icon: faPaypal, className: "h-4 w-4 text-blue-500" }) },
|
|
2837
|
+
{ value: "APPLE_PAY", label: "Apple Pay", icon: /* @__PURE__ */ jsx32(FontAwesomeIcon21, { icon: faApple, className: "h-4 w-4 text-gray-900" }) },
|
|
2838
|
+
{ value: "GOOGLE_PAY", label: "Google Pay", icon: /* @__PURE__ */ jsx32(FontAwesomeIcon21, { icon: faGoogle2, className: "h-4 w-4 text-blue-600" }) },
|
|
2839
|
+
{ value: "CRYPTO", label: "Cryptocurrency", icon: /* @__PURE__ */ jsx32(FontAwesomeIcon21, { icon: faBitcoin, className: "h-4 w-4 text-orange-500" }) }
|
|
2840
|
+
];
|
|
2841
|
+
function PaymentMethodSelector({
|
|
2842
|
+
value,
|
|
2843
|
+
onChange,
|
|
2844
|
+
disabled = false,
|
|
2845
|
+
className
|
|
2846
|
+
}) {
|
|
2847
|
+
const [selected, setSelected] = useState17("CREDIT_CARD");
|
|
2848
|
+
return /* @__PURE__ */ jsx32("div", { className: cn("w-full", className), children: /* @__PURE__ */ jsx32(
|
|
2849
|
+
RadioGroup,
|
|
2850
|
+
{
|
|
2851
|
+
name: "payment-method",
|
|
2852
|
+
legend: "Payment method",
|
|
2853
|
+
options: paymentOptions,
|
|
2854
|
+
value: selected,
|
|
2855
|
+
variant: "card",
|
|
2856
|
+
columns: 2,
|
|
2857
|
+
onChange: (val) => {
|
|
2858
|
+
setSelected(val);
|
|
2859
|
+
onChange == null ? void 0 : onChange(val);
|
|
2860
|
+
},
|
|
2861
|
+
disabled
|
|
2862
|
+
}
|
|
2863
|
+
) });
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
// modules/domains/common/payment/SavedCardSelector.tsx
|
|
2867
|
+
import { useState as useState18 } from "react";
|
|
2868
|
+
import { jsx as jsx33, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2869
|
+
var BRAND_COLOR = {
|
|
2870
|
+
VISA: "bg-blue-600",
|
|
2871
|
+
MASTERCARD: "bg-orange-500",
|
|
2872
|
+
AMEX: "bg-teal-600",
|
|
2873
|
+
DISCOVER: "bg-orange-400",
|
|
2874
|
+
JCB: "bg-blue-600",
|
|
2875
|
+
TROY: "bg-cyan-600",
|
|
2876
|
+
MIR: "bg-green-600",
|
|
2877
|
+
UNIONPAY: "bg-red-600",
|
|
2878
|
+
UNKNOWN: "bg-gray-500"
|
|
2879
|
+
};
|
|
2880
|
+
function CardBrandBadge({ brand }) {
|
|
2881
|
+
const labels = {
|
|
2882
|
+
VISA: "VISA",
|
|
2883
|
+
MASTERCARD: "MC",
|
|
2884
|
+
AMEX: "AMEX",
|
|
2885
|
+
DISCOVER: "DISC",
|
|
2886
|
+
JCB: "JCB",
|
|
2887
|
+
TROY: "TROY",
|
|
2888
|
+
MIR: "MIR",
|
|
2889
|
+
UNIONPAY: "UNIONPAY",
|
|
2890
|
+
UNKNOWN: "\u2022\u2022"
|
|
2891
|
+
};
|
|
2892
|
+
return /* @__PURE__ */ jsx33("span", { className: cn("inline-flex items-center justify-center rounded px-1.5 py-0.5 text-[10px] font-bold text-white tracking-wide shrink-0", BRAND_COLOR[brand]), children: labels[brand] });
|
|
2893
|
+
}
|
|
2894
|
+
function SavedCardSelector({
|
|
2895
|
+
cards,
|
|
2896
|
+
selectedCardId,
|
|
2897
|
+
onSelect,
|
|
2898
|
+
onRemove,
|
|
2899
|
+
onAddNew,
|
|
2900
|
+
className
|
|
2901
|
+
}) {
|
|
2902
|
+
const [active, setActive] = useState18(selectedCardId);
|
|
2903
|
+
function handleSelect(card) {
|
|
2904
|
+
setActive(card.cardId);
|
|
2905
|
+
onSelect(card.cardId, card);
|
|
2906
|
+
}
|
|
2907
|
+
return /* @__PURE__ */ jsxs27("fieldset", { className: cn("space-y-3", className), children: [
|
|
2908
|
+
/* @__PURE__ */ jsx33("legend", { className: "sr-only", children: "Select payment card" }),
|
|
2909
|
+
cards.length === 0 ? /* @__PURE__ */ jsx33("p", { className: "text-sm text-text-secondary py-4 text-center", children: "No saved cards." }) : /* @__PURE__ */ jsx33("div", { className: "space-y-2", children: cards.map((card) => {
|
|
2910
|
+
const isSelected = active === card.cardId;
|
|
2911
|
+
return /* @__PURE__ */ jsxs27(
|
|
2912
|
+
"label",
|
|
2913
|
+
{
|
|
2914
|
+
className: cn(
|
|
2915
|
+
"flex items-center gap-3 rounded-lg border bg-surface-raised p-3 cursor-pointer transition-colors",
|
|
2916
|
+
"focus-within:ring-2 focus-within:ring-border-focus",
|
|
2917
|
+
isSelected ? "border-primary ring-2 ring-primary ring-offset-1" : "border-border hover:border-border-strong"
|
|
2918
|
+
),
|
|
2919
|
+
children: [
|
|
2920
|
+
/* @__PURE__ */ jsx33(
|
|
2921
|
+
"input",
|
|
2922
|
+
{
|
|
2923
|
+
type: "radio",
|
|
2924
|
+
name: "saved-card",
|
|
2925
|
+
value: card.cardId,
|
|
2926
|
+
checked: isSelected,
|
|
2927
|
+
onChange: () => handleSelect(card),
|
|
2928
|
+
className: "sr-only"
|
|
2929
|
+
}
|
|
2930
|
+
),
|
|
2931
|
+
/* @__PURE__ */ jsx33(
|
|
2932
|
+
"span",
|
|
2933
|
+
{
|
|
2934
|
+
"aria-hidden": "true",
|
|
2935
|
+
className: cn(
|
|
2936
|
+
"flex h-4 w-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
|
|
2937
|
+
isSelected ? "border-primary bg-primary" : "border-border bg-surface-base"
|
|
2938
|
+
),
|
|
2939
|
+
children: isSelected && /* @__PURE__ */ jsx33("span", { className: "h-1.5 w-1.5 rounded-full bg-white" })
|
|
2940
|
+
}
|
|
2941
|
+
),
|
|
2942
|
+
/* @__PURE__ */ jsx33(CardBrandBadge, { brand: card.brand }),
|
|
2943
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex-1 min-w-0", children: [
|
|
2944
|
+
/* @__PURE__ */ jsxs27("p", { className: "text-sm font-medium text-text-primary font-mono", children: [
|
|
2945
|
+
"\u2022\u2022\u2022\u2022 \u2022\u2022\u2022\u2022 \u2022\u2022\u2022\u2022 ",
|
|
2946
|
+
card.last4
|
|
2947
|
+
] }),
|
|
2948
|
+
/* @__PURE__ */ jsxs27("p", { className: "text-xs text-text-secondary", children: [
|
|
2949
|
+
card.cardholderName,
|
|
2950
|
+
" \xB7 ",
|
|
2951
|
+
card.expiryMonth,
|
|
2952
|
+
"/",
|
|
2953
|
+
card.expiryYear,
|
|
2954
|
+
card.isDefault && /* @__PURE__ */ jsx33("span", { className: "ml-2 text-[10px] font-semibold text-primary uppercase", children: "Default" })
|
|
2955
|
+
] })
|
|
2956
|
+
] }),
|
|
2957
|
+
onRemove && /* @__PURE__ */ jsx33(
|
|
2958
|
+
Button,
|
|
2959
|
+
{
|
|
2960
|
+
type: "button",
|
|
2961
|
+
variant: "ghost",
|
|
2962
|
+
size: "xs",
|
|
2963
|
+
onClick: (e) => {
|
|
2964
|
+
e.preventDefault();
|
|
2965
|
+
onRemove(card.cardId);
|
|
2966
|
+
},
|
|
2967
|
+
className: "text-error shrink-0",
|
|
2968
|
+
children: "Remove"
|
|
2969
|
+
}
|
|
2970
|
+
)
|
|
2971
|
+
]
|
|
2972
|
+
},
|
|
2973
|
+
card.cardId
|
|
2974
|
+
);
|
|
2975
|
+
}) }),
|
|
2976
|
+
onAddNew && /* @__PURE__ */ jsx33(Button, { variant: "outline", size: "sm", onClick: onAddNew, className: "w-full", children: "+ Add new card" })
|
|
2977
|
+
] });
|
|
2978
|
+
}
|
|
2979
|
+
|
|
2980
|
+
// modules/domains/common/seo/SeoForm.tsx
|
|
2981
|
+
import { useState as useState19 } from "react";
|
|
2982
|
+
import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2983
|
+
function SeoForm({ initial = {}, onSubmit, onCancel, error, className }) {
|
|
2984
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
2985
|
+
const [values, setValues] = useState19({
|
|
2986
|
+
seoTitle: (_a3 = initial.seoTitle) != null ? _a3 : null,
|
|
2987
|
+
seoDescription: (_b = initial.seoDescription) != null ? _b : null,
|
|
2988
|
+
keywords: (_c = initial.keywords) != null ? _c : []
|
|
2989
|
+
});
|
|
2990
|
+
const [errors, setErrors] = useState19({});
|
|
2991
|
+
const [loading, setLoading] = useState19(false);
|
|
2992
|
+
function validate() {
|
|
2993
|
+
const next = {};
|
|
2994
|
+
if (values.seoTitle && values.seoTitle.length > 60)
|
|
2995
|
+
next.seoTitle = "Title should be 60 characters or less for best SEO results.";
|
|
2996
|
+
if (values.seoDescription && values.seoDescription.length > 160)
|
|
2997
|
+
next.seoDescription = "Description should be 160 characters or less.";
|
|
2998
|
+
setErrors(next);
|
|
2999
|
+
return Object.keys(next).length === 0;
|
|
3000
|
+
}
|
|
3001
|
+
async function handleSubmit(e) {
|
|
3002
|
+
e.preventDefault();
|
|
3003
|
+
if (!validate()) return;
|
|
3004
|
+
setLoading(true);
|
|
3005
|
+
try {
|
|
3006
|
+
await onSubmit(values);
|
|
3007
|
+
} finally {
|
|
3008
|
+
setLoading(false);
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
const titleLen = (_e = (_d = values.seoTitle) == null ? void 0 : _d.length) != null ? _e : 0;
|
|
3012
|
+
const descLen = (_g = (_f = values.seoDescription) == null ? void 0 : _f.length) != null ? _g : 0;
|
|
3013
|
+
return /* @__PURE__ */ jsxs28(
|
|
3014
|
+
Form,
|
|
3015
|
+
{
|
|
3016
|
+
onSubmit: handleSubmit,
|
|
3017
|
+
error,
|
|
3018
|
+
className,
|
|
3019
|
+
actions: /* @__PURE__ */ jsxs28(Fragment6, { children: [
|
|
3020
|
+
onCancel && /* @__PURE__ */ jsx34(Button, { type: "button", variant: "outline", onClick: onCancel, disabled: loading, children: "Cancel" }),
|
|
3021
|
+
/* @__PURE__ */ jsx34(Button, { type: "submit", loading, children: "Save SEO" })
|
|
3022
|
+
] }),
|
|
3023
|
+
children: [
|
|
3024
|
+
/* @__PURE__ */ jsx34(
|
|
3025
|
+
Input,
|
|
3026
|
+
{
|
|
3027
|
+
id: "seo-title",
|
|
3028
|
+
label: "SEO Title",
|
|
3029
|
+
type: "text",
|
|
3030
|
+
placeholder: "Page title for search engines",
|
|
3031
|
+
value: (_h = values.seoTitle) != null ? _h : "",
|
|
3032
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { seoTitle: e.target.value || null })),
|
|
3033
|
+
error: errors.seoTitle,
|
|
3034
|
+
hint: `${titleLen}/60`
|
|
3035
|
+
}
|
|
3036
|
+
),
|
|
3037
|
+
/* @__PURE__ */ jsx34(
|
|
3038
|
+
Textarea,
|
|
3039
|
+
{
|
|
3040
|
+
id: "seo-description",
|
|
3041
|
+
label: "Meta Description",
|
|
3042
|
+
rows: 3,
|
|
3043
|
+
placeholder: "Short description shown in search results",
|
|
3044
|
+
value: (_i = values.seoDescription) != null ? _i : "",
|
|
3045
|
+
onChange: (e) => setValues((v) => __spreadProps(__spreadValues({}, v), { seoDescription: e.target.value || null })),
|
|
3046
|
+
error: errors.seoDescription,
|
|
3047
|
+
hint: `${descLen}/160`
|
|
3048
|
+
}
|
|
3049
|
+
),
|
|
3050
|
+
/* @__PURE__ */ jsx34(
|
|
3051
|
+
TagInput,
|
|
3052
|
+
{
|
|
3053
|
+
id: "seo-keywords",
|
|
3054
|
+
label: "Keywords",
|
|
3055
|
+
value: (_j = values.keywords) != null ? _j : [],
|
|
3056
|
+
onChange: (keywords) => setValues((v) => __spreadProps(__spreadValues({}, v), { keywords })),
|
|
3057
|
+
placeholder: "Add keyword\u2026"
|
|
3058
|
+
}
|
|
3059
|
+
)
|
|
3060
|
+
]
|
|
3061
|
+
}
|
|
3062
|
+
);
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
// modules/domains/common/seo/SeoPreview.tsx
|
|
3066
|
+
import { jsx as jsx35, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3067
|
+
var TITLE_PLACEHOLDER = "Page title will appear here";
|
|
3068
|
+
var DESC_PLACEHOLDER = "Meta description will appear here. Keep it between 120\u2013160 characters for best results in search engines.";
|
|
3069
|
+
function SeoPreview({ seo, url = "https://example.com/page", siteName, className }) {
|
|
3070
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
3071
|
+
const title = ((_a3 = seo.seoTitle) == null ? void 0 : _a3.trim()) || TITLE_PLACEHOLDER;
|
|
3072
|
+
const desc = ((_b = seo.seoDescription) == null ? void 0 : _b.trim()) || DESC_PLACEHOLDER;
|
|
3073
|
+
const hasTitle = !!((_c = seo.seoTitle) == null ? void 0 : _c.trim());
|
|
3074
|
+
const hasDesc = !!((_d = seo.seoDescription) == null ? void 0 : _d.trim());
|
|
3075
|
+
return /* @__PURE__ */ jsxs29("div", { className: cn("rounded-xl border border-border bg-surface-raised p-4 space-y-3", className), children: [
|
|
3076
|
+
/* @__PURE__ */ jsx35("p", { className: "text-xs font-semibold text-text-secondary uppercase tracking-wider", children: "Google Preview" }),
|
|
3077
|
+
/* @__PURE__ */ jsxs29("div", { className: "max-w-lg space-y-1", children: [
|
|
3078
|
+
siteName && /* @__PURE__ */ jsx35("p", { className: "text-xs text-text-secondary truncate", children: siteName }),
|
|
3079
|
+
/* @__PURE__ */ jsx35("p", { className: "text-xs text-success-fg truncate", children: url }),
|
|
3080
|
+
/* @__PURE__ */ jsx35("p", { className: cn("text-base font-medium leading-snug truncate", hasTitle ? "text-[#1a0dab]" : "text-text-disabled italic"), children: title }),
|
|
3081
|
+
/* @__PURE__ */ jsx35("p", { className: cn("text-sm leading-relaxed line-clamp-2", hasDesc ? "text-text-secondary" : "text-text-disabled italic"), children: desc })
|
|
3082
|
+
] }),
|
|
3083
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex gap-4 pt-1 border-t border-border", children: [
|
|
3084
|
+
/* @__PURE__ */ jsxs29("div", { className: "text-center", children: [
|
|
3085
|
+
/* @__PURE__ */ jsxs29("p", { className: cn("text-sm font-semibold tabular-nums", ((_f = (_e = seo.seoTitle) == null ? void 0 : _e.length) != null ? _f : 0) > 60 ? "text-error" : "text-text-primary"), children: [
|
|
3086
|
+
(_h = (_g = seo.seoTitle) == null ? void 0 : _g.length) != null ? _h : 0,
|
|
3087
|
+
/* @__PURE__ */ jsx35("span", { className: "text-text-secondary font-normal", children: "/60" })
|
|
3088
|
+
] }),
|
|
3089
|
+
/* @__PURE__ */ jsx35("p", { className: "text-xs text-text-secondary", children: "Title" })
|
|
3090
|
+
] }),
|
|
3091
|
+
/* @__PURE__ */ jsxs29("div", { className: "text-center", children: [
|
|
3092
|
+
/* @__PURE__ */ jsxs29("p", { className: cn("text-sm font-semibold tabular-nums", ((_j = (_i = seo.seoDescription) == null ? void 0 : _i.length) != null ? _j : 0) > 160 ? "text-error" : "text-text-primary"), children: [
|
|
3093
|
+
(_l = (_k = seo.seoDescription) == null ? void 0 : _k.length) != null ? _l : 0,
|
|
3094
|
+
/* @__PURE__ */ jsx35("span", { className: "text-text-secondary font-normal", children: "/160" })
|
|
3095
|
+
] }),
|
|
3096
|
+
/* @__PURE__ */ jsx35("p", { className: "text-xs text-text-secondary", children: "Description" })
|
|
3097
|
+
] }),
|
|
3098
|
+
/* @__PURE__ */ jsxs29("div", { className: "text-center", children: [
|
|
3099
|
+
/* @__PURE__ */ jsx35("p", { className: "text-sm font-semibold text-text-primary tabular-nums", children: (_n = (_m = seo.keywords) == null ? void 0 : _m.length) != null ? _n : 0 }),
|
|
3100
|
+
/* @__PURE__ */ jsx35("p", { className: "text-xs text-text-secondary", children: "Keywords" })
|
|
3101
|
+
] })
|
|
3102
|
+
] })
|
|
3103
|
+
] });
|
|
3104
|
+
}
|
|
3105
|
+
|
|
3106
|
+
// modules/domains/common/status/ProcessingStatusIndicator.tsx
|
|
3107
|
+
import { FontAwesomeIcon as FontAwesomeIcon22 } from "@fortawesome/react-fontawesome";
|
|
3108
|
+
import { faCloudArrowUp, faGear, faCheck as faCheck4, faXmark } from "@fortawesome/free-solid-svg-icons";
|
|
3109
|
+
import { jsx as jsx36, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3110
|
+
var STATUS_META = {
|
|
3111
|
+
UPLOADING: { label: "Uploading", icon: /* @__PURE__ */ jsx36(FontAwesomeIcon22, { icon: faCloudArrowUp }), color: "text-info", pulse: true },
|
|
3112
|
+
PROCESSING: { label: "Processing", icon: /* @__PURE__ */ jsx36(FontAwesomeIcon22, { icon: faGear }), color: "text-warning", pulse: true },
|
|
3113
|
+
READY: { label: "Ready", icon: /* @__PURE__ */ jsx36(FontAwesomeIcon22, { icon: faCheck4 }), color: "text-success", pulse: false },
|
|
3114
|
+
FAILED: { label: "Failed", icon: /* @__PURE__ */ jsx36(FontAwesomeIcon22, { icon: faXmark }), color: "text-error", pulse: false }
|
|
3115
|
+
};
|
|
3116
|
+
var sizeMap3 = {
|
|
3117
|
+
sm: { text: "text-xs", icon: "text-sm", bar: "h-1" },
|
|
3118
|
+
md: { text: "text-sm", icon: "text-base", bar: "h-1.5" },
|
|
3119
|
+
lg: { text: "text-base", icon: "text-lg", bar: "h-2" }
|
|
3120
|
+
};
|
|
3121
|
+
function ProcessingStatusIndicator({
|
|
3122
|
+
status,
|
|
3123
|
+
label,
|
|
3124
|
+
progress,
|
|
3125
|
+
size = "md",
|
|
3126
|
+
className
|
|
3127
|
+
}) {
|
|
3128
|
+
const meta = STATUS_META[status];
|
|
3129
|
+
const s = sizeMap3[size];
|
|
3130
|
+
return /* @__PURE__ */ jsxs30("div", { className: cn("space-y-1.5", className), role: "status", "aria-label": label != null ? label : meta.label, "aria-live": "polite", children: [
|
|
3131
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-2", children: [
|
|
3132
|
+
/* @__PURE__ */ jsx36(
|
|
3133
|
+
"span",
|
|
3134
|
+
{
|
|
3135
|
+
className: cn(s.icon, meta.color, meta.pulse && "animate-pulse"),
|
|
3136
|
+
"aria-hidden": "true",
|
|
3137
|
+
children: meta.icon
|
|
3138
|
+
}
|
|
3139
|
+
),
|
|
3140
|
+
/* @__PURE__ */ jsx36("span", { className: cn(s.text, "font-medium text-text-primary"), children: label != null ? label : meta.label }),
|
|
3141
|
+
progress !== void 0 && /* @__PURE__ */ jsxs30("span", { className: cn(s.text, "text-text-secondary ml-auto tabular-nums"), children: [
|
|
3142
|
+
Math.round(progress),
|
|
3143
|
+
"%"
|
|
3144
|
+
] })
|
|
3145
|
+
] }),
|
|
3146
|
+
progress !== void 0 && /* @__PURE__ */ jsx36("div", { className: cn("w-full rounded-full bg-surface-sunken overflow-hidden", s.bar), children: /* @__PURE__ */ jsx36(
|
|
3147
|
+
"div",
|
|
3148
|
+
{
|
|
3149
|
+
role: "progressbar",
|
|
3150
|
+
"aria-valuenow": progress,
|
|
3151
|
+
"aria-valuemin": 0,
|
|
3152
|
+
"aria-valuemax": 100,
|
|
3153
|
+
className: cn(
|
|
3154
|
+
"h-full rounded-full transition-all duration-300",
|
|
3155
|
+
status === "READY" && "bg-success",
|
|
3156
|
+
status === "FAILED" && "bg-error",
|
|
3157
|
+
status === "UPLOADING" && "bg-info",
|
|
3158
|
+
status === "PROCESSING" && "bg-warning"
|
|
3159
|
+
),
|
|
3160
|
+
style: { width: `${Math.min(100, Math.max(0, progress))}%` }
|
|
3161
|
+
}
|
|
3162
|
+
) })
|
|
3163
|
+
] });
|
|
3164
|
+
}
|
|
3165
|
+
|
|
3166
|
+
// modules/domains/common/status/PublishStatusBadge.tsx
|
|
3167
|
+
import { FontAwesomeIcon as FontAwesomeIcon23 } from "@fortawesome/react-fontawesome";
|
|
3168
|
+
import { faPenToSquare, faGlobe as faGlobe2, faBoxArchive } from "@fortawesome/free-solid-svg-icons";
|
|
3169
|
+
import { jsx as jsx37, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3170
|
+
var statusMeta2 = {
|
|
3171
|
+
DRAFT: { label: "Draft", variant: "warning", icon: /* @__PURE__ */ jsx37(FontAwesomeIcon23, { icon: faPenToSquare, className: "w-3 h-3" }) },
|
|
3172
|
+
PUBLISHED: { label: "Published", variant: "success", icon: /* @__PURE__ */ jsx37(FontAwesomeIcon23, { icon: faGlobe2, className: "w-3 h-3" }) },
|
|
3173
|
+
ARCHIVED: { label: "Archived", variant: "neutral", icon: /* @__PURE__ */ jsx37(FontAwesomeIcon23, { icon: faBoxArchive, className: "w-3 h-3" }) }
|
|
3174
|
+
};
|
|
3175
|
+
function PublishStatusBadge({ status, size = "md", showIcon = true, className }) {
|
|
3176
|
+
var _a3;
|
|
3177
|
+
const meta = (_a3 = statusMeta2[status]) != null ? _a3 : { label: status, variant: "neutral", icon: null };
|
|
3178
|
+
return /* @__PURE__ */ jsxs31(Badge, { variant: meta.variant, size, className: cn("gap-1", className), children: [
|
|
3179
|
+
showIcon && meta.icon,
|
|
3180
|
+
meta.label
|
|
3181
|
+
] });
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
// modules/domains/common/status/VisibilityBadge.tsx
|
|
3185
|
+
import { FontAwesomeIcon as FontAwesomeIcon24 } from "@fortawesome/react-fontawesome";
|
|
3186
|
+
import { faEye, faLock as faLock4, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
|
|
3187
|
+
import { jsx as jsx38, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3188
|
+
var visibilityMeta = {
|
|
3189
|
+
PUBLIC: { label: "Public", variant: "success", icon: /* @__PURE__ */ jsx38(FontAwesomeIcon24, { icon: faEye, className: "w-3 h-3" }) },
|
|
3190
|
+
PRIVATE: { label: "Private", variant: "error", icon: /* @__PURE__ */ jsx38(FontAwesomeIcon24, { icon: faLock4, className: "w-3 h-3" }) },
|
|
3191
|
+
UNLISTED: { label: "Unlisted", variant: "neutral", icon: /* @__PURE__ */ jsx38(FontAwesomeIcon24, { icon: faEyeSlash, className: "w-3 h-3" }) }
|
|
3192
|
+
};
|
|
3193
|
+
function VisibilityBadge({ visibility, size = "md", showIcon = true, className }) {
|
|
3194
|
+
var _a3;
|
|
3195
|
+
const meta = (_a3 = visibilityMeta[visibility]) != null ? _a3 : { label: visibility, variant: "neutral", icon: null };
|
|
3196
|
+
return /* @__PURE__ */ jsxs32(Badge, { variant: meta.variant, size, className: cn("gap-1", className), children: [
|
|
3197
|
+
showIcon && meta.icon,
|
|
3198
|
+
meta.label
|
|
3199
|
+
] });
|
|
3200
|
+
}
|
|
3201
|
+
|
|
3202
|
+
// modules/domains/common/subscription/SubscriptionPlanCard.tsx
|
|
3203
|
+
import { FontAwesomeIcon as FontAwesomeIcon25 } from "@fortawesome/react-fontawesome";
|
|
3204
|
+
import { faCheck as faCheck5, faStar } from "@fortawesome/free-solid-svg-icons";
|
|
3205
|
+
import { jsx as jsx39, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3206
|
+
var INTERVAL_LABEL = {
|
|
3207
|
+
MONTHLY: "/ month",
|
|
3208
|
+
YEARLY: "/ year",
|
|
3209
|
+
ONCE: "one-time"
|
|
3210
|
+
};
|
|
3211
|
+
function SubscriptionPlanCard({
|
|
3212
|
+
plan,
|
|
3213
|
+
isCurrent = false,
|
|
3214
|
+
isSelected = false,
|
|
3215
|
+
onSelect,
|
|
3216
|
+
loading = false,
|
|
3217
|
+
className
|
|
3218
|
+
}) {
|
|
3219
|
+
var _a3, _b;
|
|
3220
|
+
const interval = (_a3 = plan.interval) != null ? _a3 : "MONTHLY";
|
|
3221
|
+
const currency = (_b = plan.currency) != null ? _b : "USD";
|
|
3222
|
+
const formattedPrice = new Intl.NumberFormat("en-US", {
|
|
3223
|
+
style: "currency",
|
|
3224
|
+
currency,
|
|
3225
|
+
minimumFractionDigits: plan.price % 100 === 0 ? 0 : 2
|
|
3226
|
+
}).format(plan.price / 100);
|
|
3227
|
+
const highlighted = plan.isPopular || isSelected || isCurrent;
|
|
3228
|
+
return /* @__PURE__ */ jsxs33(
|
|
3229
|
+
"div",
|
|
3230
|
+
{
|
|
3231
|
+
className: cn(
|
|
3232
|
+
"relative flex flex-col rounded-2xl border p-6 transition-shadow",
|
|
3233
|
+
highlighted ? "border-primary shadow-md shadow-primary/10" : "border-border shadow-sm hover:shadow-md",
|
|
3234
|
+
className
|
|
3235
|
+
),
|
|
3236
|
+
children: [
|
|
3237
|
+
plan.isPopular && !isCurrent && /* @__PURE__ */ jsxs33("span", { className: "absolute -top-3 left-1/2 -translate-x-1/2 inline-flex items-center gap-1 rounded-full bg-primary px-3 py-0.5 text-xs font-semibold text-primary-fg", children: [
|
|
3238
|
+
/* @__PURE__ */ jsx39(FontAwesomeIcon25, { icon: faStar, className: "w-2.5 h-2.5" }),
|
|
3239
|
+
"Popular"
|
|
3240
|
+
] }),
|
|
3241
|
+
isCurrent && /* @__PURE__ */ jsxs33("span", { className: "absolute -top-3 left-1/2 -translate-x-1/2 inline-flex items-center gap-1 rounded-full bg-success px-3 py-0.5 text-xs font-semibold text-white", children: [
|
|
3242
|
+
/* @__PURE__ */ jsx39(FontAwesomeIcon25, { icon: faCheck5, className: "w-2.5 h-2.5" }),
|
|
3243
|
+
"Current Plan"
|
|
3244
|
+
] }),
|
|
3245
|
+
/* @__PURE__ */ jsxs33("div", { className: "mb-4", children: [
|
|
3246
|
+
/* @__PURE__ */ jsx39("h3", { className: "text-base font-semibold text-text-primary", children: plan.name }),
|
|
3247
|
+
plan.description && /* @__PURE__ */ jsx39("p", { className: "mt-1 text-xs text-text-secondary", children: plan.description })
|
|
3248
|
+
] }),
|
|
3249
|
+
/* @__PURE__ */ jsxs33("div", { className: "mb-6 flex items-baseline gap-1", children: [
|
|
3250
|
+
/* @__PURE__ */ jsx39("span", { className: "text-3xl font-bold text-text-primary tracking-tight", children: formattedPrice }),
|
|
3251
|
+
/* @__PURE__ */ jsx39("span", { className: "text-sm text-text-secondary", children: INTERVAL_LABEL[interval] })
|
|
3252
|
+
] }),
|
|
3253
|
+
plan.features && plan.features.length > 0 && /* @__PURE__ */ jsx39("ul", { className: "mb-6 flex-1 space-y-2", children: plan.features.map((feature) => /* @__PURE__ */ jsxs33("li", { className: "flex items-start gap-2 text-sm text-text-primary", children: [
|
|
3254
|
+
/* @__PURE__ */ jsx39(
|
|
3255
|
+
FontAwesomeIcon25,
|
|
3256
|
+
{
|
|
3257
|
+
icon: faCheck5,
|
|
3258
|
+
className: "w-3.5 h-3.5 text-success mt-0.5 flex-shrink-0",
|
|
3259
|
+
"aria-hidden": "true"
|
|
3260
|
+
}
|
|
3261
|
+
),
|
|
3262
|
+
/* @__PURE__ */ jsx39("span", { children: feature })
|
|
3263
|
+
] }, feature)) }),
|
|
3264
|
+
/* @__PURE__ */ jsx39(
|
|
3265
|
+
"button",
|
|
3266
|
+
{
|
|
3267
|
+
type: "button",
|
|
3268
|
+
disabled: isCurrent || loading || !onSelect,
|
|
3269
|
+
onClick: () => onSelect == null ? void 0 : onSelect(plan.planId),
|
|
3270
|
+
className: cn(
|
|
3271
|
+
"mt-auto w-full rounded-xl px-4 py-2.5 text-sm font-medium transition-colors",
|
|
3272
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
3273
|
+
isCurrent ? "bg-surface-raised text-text-secondary cursor-default" : "bg-primary text-primary-fg hover:bg-primary-hover active:bg-primary-active disabled:opacity-50 disabled:cursor-not-allowed"
|
|
3274
|
+
),
|
|
3275
|
+
children: isCurrent ? "Current Plan" : loading ? "Processing\u2026" : `Choose ${plan.name}`
|
|
3276
|
+
}
|
|
3277
|
+
)
|
|
3278
|
+
]
|
|
3279
|
+
}
|
|
3280
|
+
);
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
// modules/domains/common/user/UserAvatar.tsx
|
|
3284
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
3285
|
+
function UserAvatar({ user, size = "md", status, className }) {
|
|
3286
|
+
var _a3, _b, _c, _d;
|
|
3287
|
+
const name = (_b = (_a3 = user.userProfile) == null ? void 0 : _a3.name) != null ? _b : user.email;
|
|
3288
|
+
const src = (_d = (_c = user.userProfile) == null ? void 0 : _c.profilePicture) != null ? _d : null;
|
|
3289
|
+
return /* @__PURE__ */ jsx40(Avatar, { src, name, size, status, className });
|
|
3290
|
+
}
|
|
3291
|
+
|
|
3292
|
+
// modules/domains/common/user/UserMenu.tsx
|
|
3293
|
+
import { FontAwesomeIcon as FontAwesomeIcon26 } from "@fortawesome/react-fontawesome";
|
|
3294
|
+
import { faChevronDown as faChevronDown6, faUser as faUser4, faGear as faGear2, faArrowRightFromBracket } from "@fortawesome/free-solid-svg-icons";
|
|
3295
|
+
import { jsx as jsx41, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
3296
|
+
function UserMenu({
|
|
3297
|
+
user,
|
|
3298
|
+
items,
|
|
3299
|
+
align = "right",
|
|
3300
|
+
onlyAvatar = false
|
|
3301
|
+
}) {
|
|
3302
|
+
var _a3, _b, _c, _d;
|
|
3303
|
+
const displayName = (_b = (_a3 = user.userProfile) == null ? void 0 : _a3.name) != null ? _b : user.email;
|
|
3304
|
+
const avatar = (_d = (_c = user.userProfile) == null ? void 0 : _c.profilePicture) != null ? _d : null;
|
|
3305
|
+
const defaultItems = items != null ? items : [
|
|
3306
|
+
{ type: "item", label: "Profile", icon: /* @__PURE__ */ jsx41(FontAwesomeIcon26, { icon: faUser4, className: "w-3.5 h-3.5", "aria-hidden": "true" }) },
|
|
3307
|
+
{ type: "item", label: "Settings", icon: /* @__PURE__ */ jsx41(FontAwesomeIcon26, { icon: faGear2, className: "w-3.5 h-3.5", "aria-hidden": "true" }) },
|
|
3308
|
+
{ type: "separator" },
|
|
3309
|
+
{ type: "item", label: "Sign out", icon: /* @__PURE__ */ jsx41(FontAwesomeIcon26, { icon: faArrowRightFromBracket, className: "w-3.5 h-3.5", "aria-hidden": "true" }), danger: true }
|
|
3310
|
+
];
|
|
3311
|
+
const trigger = /* @__PURE__ */ jsxs34(
|
|
3312
|
+
Button,
|
|
3313
|
+
{
|
|
3314
|
+
variant: "ghost",
|
|
3315
|
+
size: "sm",
|
|
3316
|
+
"aria-label": `User menu for ${displayName}`,
|
|
3317
|
+
className: cn("gap-2 px-2"),
|
|
3318
|
+
children: [
|
|
3319
|
+
/* @__PURE__ */ jsx41(Avatar, { src: avatar, name: displayName, size: "sm" }),
|
|
3320
|
+
!onlyAvatar && /* @__PURE__ */ jsxs34("div", { className: "hidden sm:block text-left min-w-0", children: [
|
|
3321
|
+
/* @__PURE__ */ jsx41("p", { className: "text-sm font-medium text-text-primary truncate max-w-[8rem]", children: displayName }),
|
|
3322
|
+
/* @__PURE__ */ jsx41("p", { className: "text-xs text-text-secondary truncate", children: user.userRole })
|
|
3323
|
+
] }),
|
|
3324
|
+
/* @__PURE__ */ jsx41(FontAwesomeIcon26, { icon: faChevronDown6, className: "w-3 h-3 text-text-disabled hidden sm:block", "aria-hidden": "true" })
|
|
3325
|
+
]
|
|
3326
|
+
}
|
|
3327
|
+
);
|
|
3328
|
+
const header = /* @__PURE__ */ jsxs34("div", { className: "px-3 py-2.5", children: [
|
|
3329
|
+
/* @__PURE__ */ jsx41("p", { className: "text-sm font-semibold text-text-primary truncate", children: displayName }),
|
|
3330
|
+
/* @__PURE__ */ jsx41("p", { className: "text-xs text-text-secondary truncate", children: user.email })
|
|
3331
|
+
] });
|
|
3332
|
+
return /* @__PURE__ */ jsx41(DropdownMenu, { trigger, items: defaultItems, header, align });
|
|
3333
|
+
}
|
|
3334
|
+
|
|
3335
|
+
// modules/domains/common/user/UserPreferencesForm.tsx
|
|
3336
|
+
import { useState as useState20 } from "react";
|
|
3337
|
+
import { jsx as jsx42, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
3338
|
+
var ControlledThemeSwitcher = ThemeSwitcher;
|
|
3339
|
+
function UserPreferencesForm({ initial = {}, onSubmit, error, className }) {
|
|
3340
|
+
var _a3, _b, _c, _d, _e, _f;
|
|
3341
|
+
const [values, setValues] = useState20({
|
|
3342
|
+
theme: (_a3 = initial.theme) != null ? _a3 : "SYSTEM",
|
|
3343
|
+
language: (_b = initial.language) != null ? _b : "en",
|
|
3344
|
+
emailNotifications: (_c = initial.emailNotifications) != null ? _c : true,
|
|
3345
|
+
pushNotifications: (_d = initial.pushNotifications) != null ? _d : true,
|
|
3346
|
+
newsletter: (_e = initial.newsletter) != null ? _e : true,
|
|
3347
|
+
timezone: (_f = initial.timezone) != null ? _f : "UTC"
|
|
3348
|
+
});
|
|
3349
|
+
const [loading, setLoading] = useState20(false);
|
|
3350
|
+
async function handleSubmit(e) {
|
|
3351
|
+
e.preventDefault();
|
|
3352
|
+
setLoading(true);
|
|
3353
|
+
try {
|
|
3354
|
+
await onSubmit(values);
|
|
3355
|
+
} finally {
|
|
3356
|
+
setLoading(false);
|
|
3357
|
+
}
|
|
3358
|
+
}
|
|
3359
|
+
function setField(key, val) {
|
|
3360
|
+
setValues((v) => __spreadProps(__spreadValues({}, v), { [key]: val }));
|
|
3361
|
+
}
|
|
3362
|
+
return /* @__PURE__ */ jsxs35(
|
|
3363
|
+
Form,
|
|
3364
|
+
{
|
|
3365
|
+
onSubmit: handleSubmit,
|
|
3366
|
+
error,
|
|
3367
|
+
className,
|
|
3368
|
+
actions: /* @__PURE__ */ jsx42(Button, { type: "submit", loading, children: "Save Preferences" }),
|
|
3369
|
+
children: [
|
|
3370
|
+
/* @__PURE__ */ jsxs35("div", { className: "space-y-3", children: [
|
|
3371
|
+
/* @__PURE__ */ jsx42("h3", { className: "text-sm font-semibold text-text-primary", children: "Appearance" }),
|
|
3372
|
+
/* @__PURE__ */ jsx42(ControlledThemeSwitcher, { value: values.theme, onChange: (theme) => setField("theme", theme) }),
|
|
3373
|
+
/* @__PURE__ */ jsx42(LanguageSwitcher, { value: values.language, onChange: (lang) => setField("language", lang) })
|
|
3374
|
+
] }),
|
|
3375
|
+
/* @__PURE__ */ jsxs35("div", { className: "space-y-3 pt-2 border-t border-border", children: [
|
|
3376
|
+
/* @__PURE__ */ jsx42("h3", { className: "text-sm font-semibold text-text-primary pt-2", children: "Notifications" }),
|
|
3377
|
+
/* @__PURE__ */ jsx42(
|
|
3378
|
+
Toggle,
|
|
3379
|
+
{
|
|
3380
|
+
id: "email-notifications",
|
|
3381
|
+
label: "Email notifications",
|
|
3382
|
+
checked: values.emailNotifications,
|
|
3383
|
+
onChange: (checked) => setField("emailNotifications", checked)
|
|
3384
|
+
}
|
|
3385
|
+
),
|
|
3386
|
+
/* @__PURE__ */ jsx42(
|
|
3387
|
+
Toggle,
|
|
3388
|
+
{
|
|
3389
|
+
id: "push-notifications",
|
|
3390
|
+
label: "Push notifications",
|
|
3391
|
+
checked: values.pushNotifications,
|
|
3392
|
+
onChange: (checked) => setField("pushNotifications", checked)
|
|
3393
|
+
}
|
|
3394
|
+
),
|
|
3395
|
+
/* @__PURE__ */ jsx42(
|
|
3396
|
+
Toggle,
|
|
3397
|
+
{
|
|
3398
|
+
id: "newsletter",
|
|
3399
|
+
label: "Newsletter",
|
|
3400
|
+
checked: values.newsletter,
|
|
3401
|
+
onChange: (checked) => setField("newsletter", checked)
|
|
3402
|
+
}
|
|
3403
|
+
)
|
|
3404
|
+
] })
|
|
3405
|
+
]
|
|
3406
|
+
}
|
|
3407
|
+
);
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3410
|
+
// modules/domains/common/user/UserRoleBadge.tsx
|
|
3411
|
+
import { jsx as jsx43 } from "react/jsx-runtime";
|
|
3412
|
+
var roleMeta = {
|
|
3413
|
+
ADMIN: { label: "Admin", variant: "error" },
|
|
3414
|
+
AUTHOR: { label: "Author", variant: "primary" },
|
|
3415
|
+
USER: { label: "User", variant: "neutral" }
|
|
3416
|
+
};
|
|
3417
|
+
function UserRoleBadge({ role, size = "md" }) {
|
|
3418
|
+
var _a3;
|
|
3419
|
+
const meta = (_a3 = roleMeta[role]) != null ? _a3 : { label: role, variant: "neutral" };
|
|
3420
|
+
return /* @__PURE__ */ jsx43(Badge, { variant: meta.variant, size, children: meta.label });
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
// modules/domains/common/user/UserStatusBadge.tsx
|
|
3424
|
+
import { jsx as jsx44 } from "react/jsx-runtime";
|
|
3425
|
+
var statusMeta3 = {
|
|
3426
|
+
ACTIVE: { label: "Active", variant: "success" },
|
|
3427
|
+
INACTIVE: { label: "Inactive", variant: "neutral" },
|
|
3428
|
+
BANNED: { label: "Banned", variant: "error" }
|
|
3429
|
+
};
|
|
3430
|
+
function UserStatusBadge({ status, size = "md", dot = false }) {
|
|
3431
|
+
var _a3;
|
|
3432
|
+
const meta = (_a3 = statusMeta3[status]) != null ? _a3 : { label: status, variant: "neutral" };
|
|
3433
|
+
return /* @__PURE__ */ jsx44(Badge, { variant: meta.variant, size, dot, children: meta.label });
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3436
|
+
// modules/domains/common/user/UserProfileCard.tsx
|
|
3437
|
+
import { jsx as jsx45, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
3438
|
+
function UserProfileCard({ user, actions, className }) {
|
|
3439
|
+
var _a3, _b, _c, _d;
|
|
3440
|
+
const name = (_b = (_a3 = user.userProfile) == null ? void 0 : _a3.name) != null ? _b : user.email;
|
|
3441
|
+
const username = (_c = user.userProfile) == null ? void 0 : _c.username;
|
|
3442
|
+
const bio = (_d = user.userProfile) == null ? void 0 : _d.biography;
|
|
3443
|
+
return /* @__PURE__ */ jsxs36("div", { className: cn("bg-surface-raised border border-border rounded-xl overflow-hidden", className), children: [
|
|
3444
|
+
/* @__PURE__ */ jsx45("div", { className: "h-20 bg-gradient-to-r from-primary-subtle to-secondary/20" }),
|
|
3445
|
+
/* @__PURE__ */ jsxs36("div", { className: "px-5 pb-5", children: [
|
|
3446
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex items-end justify-between -mt-8 mb-3", children: [
|
|
3447
|
+
/* @__PURE__ */ jsx45("div", { className: "ring-4 ring-surface-raised rounded-full", children: /* @__PURE__ */ jsx45(UserAvatar, { user, size: "xl" }) }),
|
|
3448
|
+
actions && /* @__PURE__ */ jsx45("div", { className: "flex items-center gap-2 pb-1", children: actions })
|
|
3449
|
+
] }),
|
|
3450
|
+
/* @__PURE__ */ jsxs36("div", { className: "space-y-1 mb-3", children: [
|
|
3451
|
+
/* @__PURE__ */ jsx45("h3", { className: "text-lg font-bold text-text-primary leading-tight", children: name }),
|
|
3452
|
+
username && /* @__PURE__ */ jsxs36("p", { className: "text-sm text-text-secondary", children: [
|
|
3453
|
+
"@",
|
|
3454
|
+
username
|
|
3455
|
+
] }),
|
|
3456
|
+
bio && /* @__PURE__ */ jsx45("p", { className: "text-sm text-text-secondary leading-relaxed pt-1", children: bio })
|
|
3457
|
+
] }),
|
|
3458
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
3459
|
+
/* @__PURE__ */ jsx45(UserRoleBadge, { role: user.userRole }),
|
|
3460
|
+
/* @__PURE__ */ jsx45(UserStatusBadge, { status: user.userStatus }),
|
|
3461
|
+
/* @__PURE__ */ jsx45("span", { className: "text-xs text-text-secondary truncate", children: user.email })
|
|
3462
|
+
] })
|
|
3463
|
+
] })
|
|
3464
|
+
] });
|
|
3465
|
+
}
|
|
3466
|
+
|
|
3467
|
+
// modules/domains/common/user/UserProfileForm.tsx
|
|
3468
|
+
import { useState as useState21 } from "react";
|
|
3469
|
+
import { Fragment as Fragment7, jsx as jsx46, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
3470
|
+
function UserProfileForm({ initial = {}, onSubmit, onCancel, error, className }) {
|
|
3471
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
3472
|
+
const [values, setValues] = useState21({
|
|
3473
|
+
name: (_a3 = initial.name) != null ? _a3 : null,
|
|
3474
|
+
username: (_b = initial.username) != null ? _b : null,
|
|
3475
|
+
biography: (_c = initial.biography) != null ? _c : null,
|
|
3476
|
+
profilePicture: (_d = initial.profilePicture) != null ? _d : null
|
|
3477
|
+
});
|
|
3478
|
+
const [errors, setErrors] = useState21({});
|
|
3479
|
+
const [loading, setLoading] = useState21(false);
|
|
3480
|
+
function validate() {
|
|
3481
|
+
const next = {};
|
|
3482
|
+
if (values.username && !/^[a-z0-9_]{3,32}$/.test(values.username)) {
|
|
3483
|
+
next.username = "Username must be 3\u201332 characters: lowercase letters, numbers, underscores.";
|
|
3484
|
+
}
|
|
3485
|
+
if (values.biography && values.biography.length > 300) {
|
|
3486
|
+
next.biography = "Bio must be 300 characters or less.";
|
|
3487
|
+
}
|
|
3488
|
+
setErrors(next);
|
|
3489
|
+
return Object.keys(next).length === 0;
|
|
3490
|
+
}
|
|
3491
|
+
async function handleSubmit(e) {
|
|
3492
|
+
e.preventDefault();
|
|
3493
|
+
if (!validate()) return;
|
|
3494
|
+
setLoading(true);
|
|
3495
|
+
try {
|
|
3496
|
+
await onSubmit(values);
|
|
3497
|
+
} finally {
|
|
3498
|
+
setLoading(false);
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
function set(key, val) {
|
|
3502
|
+
setValues((v) => __spreadProps(__spreadValues({}, v), { [key]: val }));
|
|
3503
|
+
}
|
|
3504
|
+
return /* @__PURE__ */ jsxs37(
|
|
3505
|
+
Form,
|
|
3506
|
+
{
|
|
3507
|
+
onSubmit: handleSubmit,
|
|
3508
|
+
error,
|
|
3509
|
+
className,
|
|
3510
|
+
actions: /* @__PURE__ */ jsxs37(Fragment7, { children: [
|
|
3511
|
+
onCancel && /* @__PURE__ */ jsx46(Button, { type: "button", variant: "outline", onClick: onCancel, disabled: loading, children: "Cancel" }),
|
|
3512
|
+
/* @__PURE__ */ jsx46(Button, { type: "submit", loading, children: "Save Profile" })
|
|
3513
|
+
] }),
|
|
3514
|
+
children: [
|
|
3515
|
+
/* @__PURE__ */ jsx46(
|
|
3516
|
+
Input,
|
|
3517
|
+
{
|
|
3518
|
+
id: "profile-name",
|
|
3519
|
+
label: "Display Name",
|
|
3520
|
+
type: "text",
|
|
3521
|
+
autoComplete: "name",
|
|
3522
|
+
value: (_e = values.name) != null ? _e : "",
|
|
3523
|
+
onChange: (e) => set("name", e.target.value || null),
|
|
3524
|
+
error: (_f = errors.name) != null ? _f : void 0
|
|
3525
|
+
}
|
|
3526
|
+
),
|
|
3527
|
+
/* @__PURE__ */ jsx46(
|
|
3528
|
+
Input,
|
|
3529
|
+
{
|
|
3530
|
+
id: "profile-username",
|
|
3531
|
+
label: "Username",
|
|
3532
|
+
type: "text",
|
|
3533
|
+
autoComplete: "username",
|
|
3534
|
+
value: (_g = values.username) != null ? _g : "",
|
|
3535
|
+
onChange: (e) => set("username", e.target.value || null),
|
|
3536
|
+
error: (_h = errors.username) != null ? _h : void 0
|
|
3537
|
+
}
|
|
3538
|
+
),
|
|
3539
|
+
/* @__PURE__ */ jsx46(
|
|
3540
|
+
Textarea,
|
|
3541
|
+
{
|
|
3542
|
+
id: "profile-bio",
|
|
3543
|
+
label: "Bio",
|
|
3544
|
+
rows: 3,
|
|
3545
|
+
value: (_i = values.biography) != null ? _i : "",
|
|
3546
|
+
onChange: (e) => set("biography", e.target.value || null),
|
|
3547
|
+
error: (_j = errors.biography) != null ? _j : void 0
|
|
3548
|
+
}
|
|
3549
|
+
),
|
|
3550
|
+
/* @__PURE__ */ jsx46(
|
|
3551
|
+
Input,
|
|
3552
|
+
{
|
|
3553
|
+
id: "profile-picture",
|
|
3554
|
+
label: "Profile Picture URL",
|
|
3555
|
+
type: "url",
|
|
3556
|
+
value: (_k = values.profilePicture) != null ? _k : "",
|
|
3557
|
+
onChange: (e) => set("profilePicture", e.target.value || null),
|
|
3558
|
+
error: (_l = errors.profilePicture) != null ? _l : void 0
|
|
3559
|
+
}
|
|
3560
|
+
)
|
|
3561
|
+
]
|
|
3562
|
+
}
|
|
3563
|
+
);
|
|
3564
|
+
}
|
|
3565
|
+
|
|
3566
|
+
export {
|
|
3567
|
+
IdSchema,
|
|
3568
|
+
UuidSchema,
|
|
3569
|
+
SlugSchema,
|
|
3570
|
+
DateSchema,
|
|
3571
|
+
NullableDateSchema,
|
|
3572
|
+
EmailSchema,
|
|
3573
|
+
PasswordSchema,
|
|
3574
|
+
SortOrderEnum,
|
|
3575
|
+
StatusEnum,
|
|
3576
|
+
BaseEntitySchema,
|
|
3577
|
+
PaginationSchema,
|
|
3578
|
+
ApiSuccessSchema,
|
|
3579
|
+
ApiErrorSchema,
|
|
3580
|
+
ApiResponseSchema,
|
|
3581
|
+
UserRoleEnum,
|
|
3582
|
+
UserStatusEnum,
|
|
3583
|
+
ThemeEnum,
|
|
3584
|
+
LanguageEnum,
|
|
3585
|
+
UserPreferencesSchema,
|
|
3586
|
+
UserProfileSchema,
|
|
3587
|
+
UserSchema,
|
|
3588
|
+
SafeUserSchema,
|
|
3589
|
+
LoginRequestSchema,
|
|
3590
|
+
RegisterRequestSchema,
|
|
3591
|
+
ChangePasswordSchema,
|
|
3592
|
+
AuthSessionSchema,
|
|
3593
|
+
AuthResponseSchema,
|
|
3594
|
+
OAuthProviderEnum,
|
|
3595
|
+
OAuthCallbackSchema,
|
|
3596
|
+
AddressCard,
|
|
3597
|
+
AddressForm,
|
|
3598
|
+
AddressSelector,
|
|
3599
|
+
ChangePasswordForm,
|
|
3600
|
+
ForgotPasswordForm,
|
|
3601
|
+
LoginForm,
|
|
3602
|
+
OAuthButtons,
|
|
3603
|
+
RegisterForm,
|
|
3604
|
+
SessionExpiredBanner,
|
|
3605
|
+
CartBadge,
|
|
3606
|
+
PriceDisplay,
|
|
3607
|
+
CartItem,
|
|
3608
|
+
CartPreview,
|
|
3609
|
+
OrderTotalsCard,
|
|
3610
|
+
CouponInput,
|
|
3611
|
+
CartSummary,
|
|
3612
|
+
RevenueBarChart,
|
|
3613
|
+
UserActivityLineChart,
|
|
3614
|
+
SalesByCategoryDoughnut,
|
|
3615
|
+
ProductComparisonRadar,
|
|
3616
|
+
RegionalSalesPolar,
|
|
3617
|
+
ChatBox,
|
|
3618
|
+
DiscountBadge,
|
|
3619
|
+
useDirection,
|
|
3620
|
+
DirectionProvider,
|
|
3621
|
+
LanguageSwitcher,
|
|
3622
|
+
CountrySelector,
|
|
3623
|
+
GeoPointDisplay,
|
|
3624
|
+
LocationPicker,
|
|
3625
|
+
CurrencySelector,
|
|
3626
|
+
NotificationMenu,
|
|
3627
|
+
PaymentStatusBadge,
|
|
3628
|
+
PaymentSummaryCard,
|
|
3629
|
+
CheckoutSuccessState,
|
|
3630
|
+
CreditCardVisual,
|
|
3631
|
+
detectBrand,
|
|
3632
|
+
CreditCardForm,
|
|
3633
|
+
PaymentMethodSelector,
|
|
3634
|
+
SavedCardSelector,
|
|
3635
|
+
SeoForm,
|
|
3636
|
+
SeoPreview,
|
|
3637
|
+
ProcessingStatusIndicator,
|
|
3638
|
+
PublishStatusBadge,
|
|
3639
|
+
VisibilityBadge,
|
|
3640
|
+
SubscriptionPlanCard,
|
|
3641
|
+
UserAvatar,
|
|
3642
|
+
UserMenu,
|
|
3643
|
+
UserPreferencesForm,
|
|
3644
|
+
UserRoleBadge,
|
|
3645
|
+
UserStatusBadge,
|
|
3646
|
+
UserProfileCard,
|
|
3647
|
+
UserProfileForm
|
|
3648
|
+
};
|