@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.
Files changed (47) hide show
  1. package/LICENSE +17 -0
  2. package/README.md +168 -0
  3. package/dist/AdvancedDataTable-F3DNXDKX.mjs +11 -0
  4. package/dist/DataTable-2G27T4E6.mjs +11 -0
  5. package/dist/DateRangePicker-AL32QB6L.mjs +11 -0
  6. package/dist/DropdownMenu-f5yV9dzM.d.mts +22 -0
  7. package/dist/DropdownMenu-f5yV9dzM.d.ts +22 -0
  8. package/dist/MapView-FERKPCDB.mjs +10 -0
  9. package/dist/ServerDataTable-RZV3K6KQ.mjs +11 -0
  10. package/dist/Tooltip-Bof5GvOc.d.mts +248 -0
  11. package/dist/Tooltip-Bof5GvOc.d.ts +248 -0
  12. package/dist/VideoPlayer-P3I6ESXJ.mjs +9 -0
  13. package/dist/app.d.mts +620 -0
  14. package/dist/app.d.ts +620 -0
  15. package/dist/app.js +7061 -0
  16. package/dist/app.mjs +100 -0
  17. package/dist/chunk-24BCQSLI.mjs +1 -0
  18. package/dist/chunk-45I3EDB2.mjs +90 -0
  19. package/dist/chunk-4IWCD7ID.mjs +1450 -0
  20. package/dist/chunk-5E2HXWFI.mjs +105 -0
  21. package/dist/chunk-C7AYI4XM.mjs +402 -0
  22. package/dist/chunk-J4D44TUA.mjs +1267 -0
  23. package/dist/chunk-KTEWZKNE.mjs +1020 -0
  24. package/dist/chunk-LMUQHL4Z.mjs +3829 -0
  25. package/dist/chunk-MD5OQ4J2.mjs +527 -0
  26. package/dist/chunk-MPJRPYIZ.mjs +1 -0
  27. package/dist/chunk-MPWUEQ7J.mjs +2422 -0
  28. package/dist/chunk-MTT5TKAJ.mjs +93 -0
  29. package/dist/chunk-RBDK7MWQ.mjs +46 -0
  30. package/dist/chunk-SVFQZPNZ.mjs +3648 -0
  31. package/dist/chunk-TZWBBMSG.mjs +1 -0
  32. package/dist/chunk-XA7J6PVJ.mjs +1488 -0
  33. package/dist/chunk-ZLYBRYWQ.mjs +726 -0
  34. package/dist/common.d.mts +921 -0
  35. package/dist/common.d.ts +921 -0
  36. package/dist/common.js +4991 -0
  37. package/dist/common.mjs +172 -0
  38. package/dist/index.d.mts +10 -0
  39. package/dist/index.d.ts +10 -0
  40. package/dist/index.js +17563 -0
  41. package/dist/index.mjs +349 -0
  42. package/dist/ui.d.mts +937 -0
  43. package/dist/ui.d.ts +937 -0
  44. package/dist/ui.js +10095 -0
  45. package/dist/ui.mjs +163 -0
  46. package/package.json +114 -0
  47. 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
+ };