@greatapps/common 1.1.24 → 1.1.26

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 (128) hide show
  1. package/dist/components/account/ConfigurationsMyAccountModal.mjs +121 -0
  2. package/dist/components/account/ConfigurationsMyAccountModal.mjs.map +1 -0
  3. package/dist/components/account/ConfirmGlobalPreferencesModal.mjs +45 -0
  4. package/dist/components/account/ConfirmGlobalPreferencesModal.mjs.map +1 -0
  5. package/dist/components/account/DisableTwoFactorAuthModal.mjs +67 -0
  6. package/dist/components/account/DisableTwoFactorAuthModal.mjs.map +1 -0
  7. package/dist/components/account/TwoFactorAuthModal.mjs +190 -0
  8. package/dist/components/account/TwoFactorAuthModal.mjs.map +1 -0
  9. package/dist/components/account/constants.mjs +32 -0
  10. package/dist/components/account/constants.mjs.map +1 -0
  11. package/dist/components/account/hooks/useChangeEmailForm.mjs +53 -0
  12. package/dist/components/account/hooks/useChangeEmailForm.mjs.map +1 -0
  13. package/dist/components/account/hooks/useChangePasswordForm.mjs +47 -0
  14. package/dist/components/account/hooks/useChangePasswordForm.mjs.map +1 -0
  15. package/dist/components/account/hooks/useChangePhoneForm.mjs +64 -0
  16. package/dist/components/account/hooks/useChangePhoneForm.mjs.map +1 -0
  17. package/dist/components/account/hooks/useConfigurationsModal.mjs +33 -0
  18. package/dist/components/account/hooks/useConfigurationsModal.mjs.map +1 -0
  19. package/dist/components/account/hooks/useDisableTwoFactorAuthForm.mjs +54 -0
  20. package/dist/components/account/hooks/useDisableTwoFactorAuthForm.mjs.map +1 -0
  21. package/dist/components/account/hooks/useOtpVerification.mjs +94 -0
  22. package/dist/components/account/hooks/useOtpVerification.mjs.map +1 -0
  23. package/dist/components/account/hooks/useTwoFactorAuthForm.mjs +88 -0
  24. package/dist/components/account/hooks/useTwoFactorAuthForm.mjs.map +1 -0
  25. package/dist/components/account/sections/ChangeEmailModal.mjs +180 -0
  26. package/dist/components/account/sections/ChangeEmailModal.mjs.map +1 -0
  27. package/dist/components/account/sections/ChangePasswordSection.mjs +64 -0
  28. package/dist/components/account/sections/ChangePasswordSection.mjs.map +1 -0
  29. package/dist/components/account/sections/ChangePhoneModal.mjs +182 -0
  30. package/dist/components/account/sections/ChangePhoneModal.mjs.map +1 -0
  31. package/dist/components/account/sections/MyProfileSection.mjs +312 -0
  32. package/dist/components/account/sections/MyProfileSection.mjs.map +1 -0
  33. package/dist/components/account/sections/PreferencesSection.mjs +246 -0
  34. package/dist/components/account/sections/PreferencesSection.mjs.map +1 -0
  35. package/dist/components/account/sections/SecuritySection.mjs +147 -0
  36. package/dist/components/account/sections/SecuritySection.mjs.map +1 -0
  37. package/dist/components/ui/form/ComboboxField.mjs +130 -0
  38. package/dist/components/ui/form/ComboboxField.mjs.map +1 -0
  39. package/dist/components/ui/form/FormField.mjs +103 -0
  40. package/dist/components/ui/form/FormField.mjs.map +1 -0
  41. package/dist/components/ui/form/PhoneInput.mjs +78 -0
  42. package/dist/components/ui/form/PhoneInput.mjs.map +1 -0
  43. package/dist/components/ui/form/SelectField.mjs +80 -0
  44. package/dist/components/ui/form/SelectField.mjs.map +1 -0
  45. package/dist/components/ui/form/SwitchOptionFieldWithIcon.mjs +40 -0
  46. package/dist/components/ui/form/SwitchOptionFieldWithIcon.mjs.map +1 -0
  47. package/dist/components/ui/form/TextAreaField.mjs +56 -0
  48. package/dist/components/ui/form/TextAreaField.mjs.map +1 -0
  49. package/dist/enums/AccountSectionType.mjs +11 -0
  50. package/dist/enums/AccountSectionType.mjs.map +1 -0
  51. package/dist/hooks/useCountdownTimer.mjs +29 -0
  52. package/dist/hooks/useCountdownTimer.mjs.map +1 -0
  53. package/dist/hooks/useIsMobile.mjs +18 -0
  54. package/dist/hooks/useIsMobile.mjs.map +1 -0
  55. package/dist/hooks/usePasswordVisibility.mjs +13 -0
  56. package/dist/hooks/usePasswordVisibility.mjs.map +1 -0
  57. package/dist/index.mjs +80 -0
  58. package/dist/index.mjs.map +1 -1
  59. package/dist/modules/accounts/actions/account-management.action.mjs +163 -0
  60. package/dist/modules/accounts/actions/account-management.action.mjs.map +1 -0
  61. package/dist/modules/accounts/hooks/useAccountManagement.mjs +64 -0
  62. package/dist/modules/accounts/hooks/useAccountManagement.mjs.map +1 -0
  63. package/dist/modules/accounts/services/account.service.mjs +162 -25
  64. package/dist/modules/accounts/services/account.service.mjs.map +1 -1
  65. package/dist/modules/accounts/services/two-factor.service.mjs +77 -0
  66. package/dist/modules/accounts/services/two-factor.service.mjs.map +1 -0
  67. package/dist/modules/auth/services/auth.service.mjs +7 -4
  68. package/dist/modules/auth/services/auth.service.mjs.map +1 -1
  69. package/dist/server.mjs +36 -0
  70. package/dist/server.mjs.map +1 -1
  71. package/dist/utils/browser/clipboard.mjs +36 -0
  72. package/dist/utils/browser/clipboard.mjs.map +1 -0
  73. package/dist/utils/file/index.mjs +9 -0
  74. package/dist/utils/file/index.mjs.map +1 -0
  75. package/dist/utils/format/masks.mjs +56 -0
  76. package/dist/utils/format/masks.mjs.map +1 -0
  77. package/dist/utils/intl/locales.mjs +12 -0
  78. package/dist/utils/intl/locales.mjs.map +1 -0
  79. package/dist/utils/intl/timezones.mjs +41 -0
  80. package/dist/utils/intl/timezones.mjs.map +1 -0
  81. package/dist/utils/validators/account.mjs +26 -0
  82. package/dist/utils/validators/account.mjs.map +1 -0
  83. package/dist/utils/validators/common.mjs +47 -0
  84. package/dist/utils/validators/common.mjs.map +1 -0
  85. package/package.json +5 -1
  86. package/src/components/account/ConfigurationsMyAccountModal.tsx +147 -0
  87. package/src/components/account/ConfirmGlobalPreferencesModal.tsx +66 -0
  88. package/src/components/account/DisableTwoFactorAuthModal.tsx +86 -0
  89. package/src/components/account/TwoFactorAuthModal.tsx +221 -0
  90. package/src/components/account/constants.ts +29 -0
  91. package/src/components/account/hooks/useChangeEmailForm.tsx +56 -0
  92. package/src/components/account/hooks/useChangePasswordForm.tsx +59 -0
  93. package/src/components/account/hooks/useChangePhoneForm.tsx +69 -0
  94. package/src/components/account/hooks/useConfigurationsModal.ts +40 -0
  95. package/src/components/account/hooks/useDisableTwoFactorAuthForm.tsx +69 -0
  96. package/src/components/account/hooks/useOtpVerification.tsx +116 -0
  97. package/src/components/account/hooks/useTwoFactorAuthForm.tsx +114 -0
  98. package/src/components/account/sections/ChangeEmailModal.tsx +224 -0
  99. package/src/components/account/sections/ChangePasswordSection.tsx +64 -0
  100. package/src/components/account/sections/ChangePhoneModal.tsx +229 -0
  101. package/src/components/account/sections/MyProfileSection.tsx +337 -0
  102. package/src/components/account/sections/PreferencesSection.tsx +277 -0
  103. package/src/components/account/sections/SecuritySection.tsx +160 -0
  104. package/src/components/ui/form/ComboboxField.tsx +154 -0
  105. package/src/components/ui/form/FormField.tsx +130 -0
  106. package/src/components/ui/form/PhoneInput.tsx +98 -0
  107. package/src/components/ui/form/SelectField.tsx +118 -0
  108. package/src/components/ui/form/SwitchOptionFieldWithIcon.tsx +47 -0
  109. package/src/components/ui/form/TextAreaField.tsx +70 -0
  110. package/src/enums/AccountSectionType.ts +6 -0
  111. package/src/hooks/useCountdownTimer.ts +41 -0
  112. package/src/hooks/useIsMobile.ts +19 -0
  113. package/src/hooks/usePasswordVisibility.ts +13 -0
  114. package/src/index.ts +70 -0
  115. package/src/modules/accounts/actions/account-management.action.ts +197 -0
  116. package/src/modules/accounts/hooks/useAccountManagement.ts +79 -0
  117. package/src/modules/accounts/services/account.service.ts +229 -50
  118. package/src/modules/accounts/services/two-factor.service.ts +98 -0
  119. package/src/modules/accounts/types.ts +157 -0
  120. package/src/modules/auth/services/auth.service.ts +9 -5
  121. package/src/server.ts +21 -0
  122. package/src/utils/browser/clipboard.ts +34 -0
  123. package/src/utils/file/index.ts +5 -0
  124. package/src/utils/format/masks.ts +52 -0
  125. package/src/utils/intl/locales.ts +15 -0
  126. package/src/utils/intl/timezones.ts +53 -0
  127. package/src/utils/validators/account.ts +36 -0
  128. package/src/utils/validators/common.ts +43 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/ui/form/ComboboxField.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { useState, useMemo } from 'react';\r\nimport { CheckIcon, ChevronDownIcon, SearchIcon } from 'lucide-react';\r\nimport { Popover, PopoverContent, PopoverTrigger } from '../overlay/Popover';\r\nimport { cn } from '../../../infra/utils/clsx';\r\n\r\nexport type ComboboxOption = {\r\n value: string;\r\n label: string;\r\n displayValue?: string;\r\n};\r\n\r\ninterface ComboboxFieldProps {\r\n options: ComboboxOption[];\r\n label?: string;\r\n placeholder?: string;\r\n searchPlaceholder?: string;\r\n emptyMessage?: string;\r\n value?: string;\r\n onChange?: (value: string) => void;\r\n disabled?: boolean;\r\n icon?: React.ReactNode;\r\n className?: string;\r\n containerClassName?: string;\r\n}\r\n\r\nexport function ComboboxField({\r\n options,\r\n label,\r\n placeholder = 'Selecione uma opção',\r\n searchPlaceholder = 'Buscar...',\r\n emptyMessage = 'Nenhuma opção encontrada.',\r\n value,\r\n onChange,\r\n disabled = false,\r\n icon,\r\n className,\r\n containerClassName,\r\n}: ComboboxFieldProps) {\r\n const [open, setOpen] = useState(false);\r\n const [search, setSearch] = useState('');\r\n\r\n const selectedOption = useMemo(\r\n () => options.find((o) => o.value === value),\r\n [options, value]\r\n );\r\n\r\n const filteredOptions = useMemo(() => {\r\n const q = search.trim().toLowerCase();\r\n if (!q) return options;\r\n return options.filter((o) => o.label.toLowerCase().includes(q));\r\n }, [options, search]);\r\n\r\n const handleSelect = (optionValue: string) => {\r\n onChange?.(optionValue);\r\n setOpen(false);\r\n setSearch('');\r\n };\r\n\r\n return (\r\n <div className={cn('flex flex-col gap-1.5', containerClassName)}>\r\n {label && (\r\n <div className=\"flex items-center gap-1 paragraph-xsmall-semibold\">\r\n <span className=\"text-gray-600\">{label}</span>\r\n </div>\r\n )}\r\n\r\n <Popover\r\n open={open}\r\n onOpenChange={(v) => {\r\n if (!disabled) {\r\n setOpen(v);\r\n if (!v) setSearch('');\r\n }\r\n }}\r\n >\r\n <PopoverTrigger asChild>\r\n <button\r\n type=\"button\"\r\n disabled={disabled}\r\n className={cn(\r\n 'paragraph-small-medium w-full h-10 text-gray-950 px-4 transition-colors',\r\n 'flex items-center justify-between gap-2 rounded-md border bg-transparent',\r\n 'border-gray-200 hover:border-gray-400 focus:border-gray-950 focus:outline-none',\r\n disabled && 'cursor-not-allowed opacity-50',\r\n className\r\n )}\r\n >\r\n <span className={cn('truncate text-left', !selectedOption && 'text-gray-400')}>\r\n {selectedOption\r\n ? (selectedOption.displayValue ?? selectedOption.label)\r\n : placeholder}\r\n </span>\r\n {icon ?? (\r\n <ChevronDownIcon\r\n className={cn(\r\n 'size-4 opacity-50 shrink-0 transition-all duration-200',\r\n open && 'rotate-180 opacity-100 text-gray-950'\r\n )}\r\n />\r\n )}\r\n </button>\r\n </PopoverTrigger>\r\n\r\n <PopoverContent\r\n className=\"p-0 overflow-hidden rounded-md border shadow-md\"\r\n align=\"start\"\r\n sideOffset={4}\r\n style={{ width: 'var(--radix-popover-trigger-width)' }}\r\n onWheel={(e) => e.stopPropagation()}\r\n >\r\n <div className=\"flex items-center gap-2 border-b border-gray-100 px-3 h-9\">\r\n <SearchIcon className=\"size-4 shrink-0 opacity-50 text-gray-500\" />\r\n <input\r\n autoFocus\r\n placeholder={searchPlaceholder}\r\n value={search}\r\n onChange={(e) => setSearch(e.target.value)}\r\n className=\"flex h-full w-full bg-transparent text-sm outline-none placeholder:text-gray-400 paragraph-small-medium text-gray-950\"\r\n />\r\n </div>\r\n\r\n <div className=\"overflow-y-auto max-h-[280px] p-1\">\r\n {filteredOptions.length === 0 ? (\r\n <p className=\"py-6 text-center paragraph-small-medium text-gray-500\">{emptyMessage}</p>\r\n ) : (\r\n filteredOptions.map((option) => {\r\n const isSelected = value === option.value;\r\n return (\r\n <div\r\n key={option.value}\r\n className={cn(\r\n 'flex items-center gap-2 rounded-sm px-2 h-9 cursor-pointer select-none',\r\n 'paragraph-small-medium text-gray-950',\r\n 'hover:bg-gray-100',\r\n isSelected && 'bg-gray-50'\r\n )}\r\n onClick={() => handleSelect(option.value)}\r\n >\r\n <span className=\"flex-1 truncate\">{option.label}</span>\r\n {isSelected && <CheckIcon className=\"size-4 shrink-0 text-pages-600\" />}\r\n </div>\r\n );\r\n })\r\n )}\r\n </div>\r\n </PopoverContent>\r\n </Popover>\r\n </div>\r\n );\r\n}\r\n\r\nexport default ComboboxField;\r\n"],"mappings":"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","names":[]}
@@ -0,0 +1,103 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { forwardRef } from "react";
4
+ import { Lock, Eye, EyeOff } from "lucide-react";
5
+ import { Input } from "./Input";
6
+ import { cn } from "../../../infra/utils/clsx";
7
+ const FormField = forwardRef(
8
+ ({
9
+ label,
10
+ optional = false,
11
+ required = false,
12
+ leftIcon: LeftIcon,
13
+ rightIcon: RightIcon,
14
+ rightIconColor = "var(--color-gray-400)",
15
+ hintMessage,
16
+ size = "default",
17
+ type = "text",
18
+ error = false,
19
+ errorMessage,
20
+ className,
21
+ classnameContainer,
22
+ showCharCount = false,
23
+ showPassword = false,
24
+ onTogglePassword,
25
+ ...inputProps
26
+ }, ref) => {
27
+ const isPasswordField = type === "password";
28
+ const inputType = isPasswordField && showPassword ? "text" : type;
29
+ const containerHeight = size === "large" ? "h-12" : "h-10";
30
+ const FinalLeftIcon = isPasswordField ? Lock : LeftIcon;
31
+ const FinalRightIcon = isPasswordField ? !showPassword ? EyeOff : Eye : RightIcon;
32
+ const finalMessage = error && errorMessage ? errorMessage : hintMessage;
33
+ const messageColor = error ? "text-red-600" : "text-gray-600";
34
+ const currentLength = typeof inputProps.value === "string" ? inputProps.value.length : 0;
35
+ const shouldShowCharCount = showCharCount && inputProps.maxLength;
36
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 w-full", children: [
37
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 paragraph-xsmall-semibold truncate", children: [
38
+ label && /* @__PURE__ */ jsx("span", { className: "text-gray-600", children: label }),
39
+ optional && /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: "(Opcional)" }),
40
+ required && /* @__PURE__ */ jsx("span", { className: "text-red-600", children: "*" })
41
+ ] }),
42
+ /* @__PURE__ */ jsxs(
43
+ "div",
44
+ {
45
+ className: cn(
46
+ "flex gap-2 px-4 items-center border rounded-lg transition-color",
47
+ containerHeight,
48
+ classnameContainer,
49
+ error ? "border-red-600 hover:border-red-700" : "border-gray-200 hover:border-gray-400 focus-within:border-gray-950"
50
+ ),
51
+ children: [
52
+ FinalLeftIcon && /* @__PURE__ */ jsx(FinalLeftIcon, { size: 20, className: "text-gray-400" }),
53
+ /* @__PURE__ */ jsx(
54
+ Input,
55
+ {
56
+ ref,
57
+ type: inputType,
58
+ className: cn(
59
+ "paragraph-small-medium w-full h-full text-gray-950",
60
+ error && "placeholder:text-red-400",
61
+ className
62
+ ),
63
+ ...inputProps
64
+ }
65
+ ),
66
+ FinalRightIcon && /* @__PURE__ */ jsx(
67
+ "button",
68
+ {
69
+ type: "button",
70
+ onClick: isPasswordField ? onTogglePassword : void 0,
71
+ className: cn(
72
+ "flex items-center justify-center",
73
+ isPasswordField && "cursor-pointer hover:opacity-70 transition-opacity"
74
+ ),
75
+ "aria-label": isPasswordField ? showPassword ? "Ocultar senha" : "Mostrar senha" : void 0,
76
+ children: /* @__PURE__ */ jsx(
77
+ FinalRightIcon,
78
+ {
79
+ size: 20,
80
+ color: isPasswordField ? "var(--color-gray-950)" : rightIconColor
81
+ }
82
+ )
83
+ }
84
+ )
85
+ ]
86
+ }
87
+ ),
88
+ finalMessage && /* @__PURE__ */ jsx("span", { className: cn("paragraph-xsmall-medium", messageColor), children: finalMessage }),
89
+ shouldShowCharCount && /* @__PURE__ */ jsxs("span", { className: "paragraph-xsmall-medium text-gray-600", children: [
90
+ currentLength,
91
+ "/",
92
+ inputProps.maxLength
93
+ ] })
94
+ ] });
95
+ }
96
+ );
97
+ FormField.displayName = "FormField";
98
+ var FormField_default = FormField;
99
+ export {
100
+ FormField,
101
+ FormField_default as default
102
+ };
103
+ //# sourceMappingURL=FormField.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/ui/form/FormField.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { forwardRef, type ComponentPropsWithoutRef } from 'react';\r\nimport { Lock, Eye, EyeOff, type LucideIcon } from 'lucide-react';\r\nimport { Input } from './Input';\r\nimport { cn } from '../../../infra/utils/clsx';\r\n\r\ntype FormFieldSize = 'default' | 'large';\r\n\r\ninterface FormFieldProps extends Omit<ComponentPropsWithoutRef<'input'>, 'size'> {\r\n label?: string;\r\n optional?: boolean;\r\n required?: boolean;\r\n leftIcon?: LucideIcon;\r\n rightIcon?: LucideIcon;\r\n rightIconColor?: string;\r\n hintMessage?: string;\r\n classnameContainer?: string;\r\n size?: FormFieldSize;\r\n error?: boolean;\r\n errorMessage?: string;\r\n showCharCount?: boolean;\r\n showPassword?: boolean;\r\n onTogglePassword?: () => void;\r\n}\r\n\r\nexport const FormField = forwardRef<HTMLInputElement, FormFieldProps>(\r\n (\r\n {\r\n label,\r\n optional = false,\r\n required = false,\r\n leftIcon: LeftIcon,\r\n rightIcon: RightIcon,\r\n rightIconColor = 'var(--color-gray-400)',\r\n hintMessage,\r\n size = 'default',\r\n type = 'text',\r\n error = false,\r\n errorMessage,\r\n className,\r\n classnameContainer,\r\n showCharCount = false,\r\n showPassword = false,\r\n onTogglePassword,\r\n ...inputProps\r\n },\r\n ref\r\n ) => {\r\n const isPasswordField = type === 'password';\r\n const inputType = isPasswordField && showPassword ? 'text' : type;\r\n const containerHeight = size === 'large' ? 'h-12' : 'h-10';\r\n\r\n const FinalLeftIcon = isPasswordField ? Lock : LeftIcon;\r\n const FinalRightIcon = isPasswordField ? (!showPassword ? EyeOff : Eye) : RightIcon;\r\n\r\n const finalMessage = error && errorMessage ? errorMessage : hintMessage;\r\n const messageColor = error ? 'text-red-600' : 'text-gray-600';\r\n\r\n const currentLength = typeof inputProps.value === 'string' ? inputProps.value.length : 0;\r\n const shouldShowCharCount = showCharCount && inputProps.maxLength;\r\n\r\n return (\r\n <div className=\"flex flex-col gap-1.5 w-full\">\r\n <div className=\"flex items-center gap-1 paragraph-xsmall-semibold truncate\">\r\n {label && <span className=\"text-gray-600\">{label}</span>}\r\n {optional && <span className=\"text-gray-500\">(Opcional)</span>}\r\n {required && <span className=\"text-red-600\">*</span>}\r\n </div>\r\n\r\n <div\r\n className={cn(\r\n 'flex gap-2 px-4 items-center border rounded-lg transition-color',\r\n containerHeight,\r\n classnameContainer,\r\n error\r\n ? 'border-red-600 hover:border-red-700'\r\n : 'border-gray-200 hover:border-gray-400 focus-within:border-gray-950'\r\n )}\r\n >\r\n {FinalLeftIcon && <FinalLeftIcon size={20} className=\"text-gray-400\" />}\r\n\r\n <Input\r\n ref={ref}\r\n type={inputType}\r\n className={cn(\r\n 'paragraph-small-medium w-full h-full text-gray-950',\r\n error && 'placeholder:text-red-400',\r\n className\r\n )}\r\n {...inputProps}\r\n />\r\n\r\n {FinalRightIcon && (\r\n <button\r\n type=\"button\"\r\n onClick={isPasswordField ? onTogglePassword : undefined}\r\n className={cn(\r\n 'flex items-center justify-center',\r\n isPasswordField && 'cursor-pointer hover:opacity-70 transition-opacity'\r\n )}\r\n aria-label={\r\n isPasswordField ? (showPassword ? 'Ocultar senha' : 'Mostrar senha') : undefined\r\n }\r\n >\r\n <FinalRightIcon\r\n size={20}\r\n color={isPasswordField ? 'var(--color-gray-950)' : rightIconColor}\r\n />\r\n </button>\r\n )}\r\n </div>\r\n\r\n {finalMessage && (\r\n <span className={cn('paragraph-xsmall-medium', messageColor)}>{finalMessage}</span>\r\n )}\r\n\r\n {shouldShowCharCount && (\r\n <span className=\"paragraph-xsmall-medium text-gray-600\">\r\n {currentLength}/{inputProps.maxLength}\r\n </span>\r\n )}\r\n </div>\r\n );\r\n }\r\n);\r\n\r\nFormField.displayName = 'FormField';\r\n\r\nexport default FormField;\r\n"],"mappings":";AAgEQ,SACY,KADZ;AA9DR,SAAS,kBAAiD;AAC1D,SAAS,MAAM,KAAK,cAA+B;AACnD,SAAS,aAAa;AACtB,SAAS,UAAU;AAqBZ,MAAM,YAAY;AAAA,EACvB,CACE;AAAA,IACE;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,IACV,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB;AAAA,IACA,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf;AAAA,IACA,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,kBAAkB,SAAS;AACjC,UAAM,YAAY,mBAAmB,eAAe,SAAS;AAC7D,UAAM,kBAAkB,SAAS,UAAU,SAAS;AAEpD,UAAM,gBAAgB,kBAAkB,OAAO;AAC/C,UAAM,iBAAiB,kBAAmB,CAAC,eAAe,SAAS,MAAO;AAE1E,UAAM,eAAe,SAAS,eAAe,eAAe;AAC5D,UAAM,eAAe,QAAQ,iBAAiB;AAE9C,UAAM,gBAAgB,OAAO,WAAW,UAAU,WAAW,WAAW,MAAM,SAAS;AACvF,UAAM,sBAAsB,iBAAiB,WAAW;AAExD,WACE,qBAAC,SAAI,WAAU,gCACb;AAAA,2BAAC,SAAI,WAAU,8DACZ;AAAA,iBAAS,oBAAC,UAAK,WAAU,iBAAiB,iBAAM;AAAA,QAChD,YAAY,oBAAC,UAAK,WAAU,iBAAgB,wBAAU;AAAA,QACtD,YAAY,oBAAC,UAAK,WAAU,gBAAe,eAAC;AAAA,SAC/C;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA;AAAA,YACA;AAAA,YACA,QACI,wCACA;AAAA,UACN;AAAA,UAEC;AAAA,6BAAiB,oBAAC,iBAAc,MAAM,IAAI,WAAU,iBAAgB;AAAA,YAErE;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA,MAAM;AAAA,gBACN,WAAW;AAAA,kBACT;AAAA,kBACA,SAAS;AAAA,kBACT;AAAA,gBACF;AAAA,gBACC,GAAG;AAAA;AAAA,YACN;AAAA,YAEC,kBACC;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,kBAAkB,mBAAmB;AAAA,gBAC9C,WAAW;AAAA,kBACT;AAAA,kBACA,mBAAmB;AAAA,gBACrB;AAAA,gBACA,cACE,kBAAmB,eAAe,kBAAkB,kBAAmB;AAAA,gBAGzE;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAM;AAAA,oBACN,OAAO,kBAAkB,0BAA0B;AAAA;AAAA,gBACrD;AAAA;AAAA,YACF;AAAA;AAAA;AAAA,MAEJ;AAAA,MAEC,gBACC,oBAAC,UAAK,WAAW,GAAG,2BAA2B,YAAY,GAAI,wBAAa;AAAA,MAG7E,uBACC,qBAAC,UAAK,WAAU,yCACb;AAAA;AAAA,QAAc;AAAA,QAAE,WAAW;AAAA,SAC9B;AAAA,OAEJ;AAAA,EAEJ;AACF;AAEA,UAAU,cAAc;AAExB,IAAO,oBAAQ;","names":[]}
@@ -0,0 +1,78 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { forwardRef } from "react";
4
+ import Image from "next/image";
5
+ import { Input } from "./Input";
6
+ import { Separator } from "../data-display/Separator";
7
+ import { cn } from "../../../infra/utils/clsx";
8
+ const PhoneInput = forwardRef(
9
+ ({
10
+ label,
11
+ optional = false,
12
+ required = false,
13
+ hintMessage,
14
+ error = false,
15
+ errorMessage,
16
+ countryCode = "+55",
17
+ countryFlagSrc = "/icons/brazil-flag.svg",
18
+ countryFlagAlt = "Brazil flag",
19
+ className,
20
+ classnameContainer,
21
+ ...props
22
+ }, ref) => {
23
+ const finalMessage = error && errorMessage ? errorMessage : hintMessage;
24
+ const showMessage = finalMessage && finalMessage.trim() !== "";
25
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5"), children: [
26
+ label && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 paragraph-xsmall-semibold", children: [
27
+ /* @__PURE__ */ jsx("span", { className: "text-gray-600", children: label }),
28
+ optional && /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: "(Opcional)" }),
29
+ required && /* @__PURE__ */ jsx("span", { className: "text-red-600", children: "*" })
30
+ ] }),
31
+ /* @__PURE__ */ jsxs(
32
+ "div",
33
+ {
34
+ className: cn(
35
+ "flex gap-2 items-center border rounded-lg h-10 transition-colors",
36
+ error ? "border-red-600 hover:border-red-700" : "border-gray-200 hover:border-gray-400 focus-within:border-gray-950",
37
+ classnameContainer
38
+ ),
39
+ children: [
40
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4", children: [
41
+ /* @__PURE__ */ jsx(
42
+ Image,
43
+ {
44
+ src: countryFlagSrc,
45
+ alt: countryFlagAlt,
46
+ width: 20,
47
+ height: 20,
48
+ className: "h-5! w-5! rounded-full"
49
+ }
50
+ ),
51
+ /* @__PURE__ */ jsx("span", { className: "paragraph-small-regular text-gray-950", children: countryCode })
52
+ ] }),
53
+ /* @__PURE__ */ jsx(Separator, { orientation: "vertical" }),
54
+ /* @__PURE__ */ jsx(
55
+ Input,
56
+ {
57
+ ref,
58
+ type: "tel",
59
+ className: cn(
60
+ "paragraph-small-medium w-full h-full text-gray-950 border-0 focus-visible:ring-0 focus-visible:ring-offset-0",
61
+ className
62
+ ),
63
+ ...props
64
+ }
65
+ )
66
+ ]
67
+ }
68
+ ),
69
+ showMessage && /* @__PURE__ */ jsx("span", { className: cn("paragraph-xsmall-medium", error ? "text-red-600" : "text-gray-600"), children: finalMessage })
70
+ ] });
71
+ }
72
+ );
73
+ PhoneInput.displayName = "PhoneInput";
74
+ var PhoneInput_default = PhoneInput;
75
+ export {
76
+ PhoneInput_default as default
77
+ };
78
+ //# sourceMappingURL=PhoneInput.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/ui/form/PhoneInput.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { ComponentPropsWithoutRef, forwardRef } from 'react';\r\nimport Image from 'next/image';\r\nimport { Input } from './Input';\r\nimport { Separator } from '../data-display/Separator';\r\nimport { cn } from '../../../infra/utils/clsx';\r\n\r\ninterface PhoneInputProps extends Omit<ComponentPropsWithoutRef<'input'>, 'type'> {\r\n label?: string;\r\n optional?: boolean;\r\n required?: boolean;\r\n hintMessage?: string;\r\n error?: boolean;\r\n errorMessage?: string;\r\n countryCode?: string;\r\n countryFlagSrc?: string;\r\n countryFlagAlt?: string;\r\n classnameContainer?: string;\r\n}\r\n\r\nconst PhoneInput = forwardRef<HTMLInputElement, PhoneInputProps>(\r\n (\r\n {\r\n label,\r\n optional = false,\r\n required = false,\r\n hintMessage,\r\n error = false,\r\n errorMessage,\r\n countryCode = '+55',\r\n countryFlagSrc = '/icons/brazil-flag.svg',\r\n countryFlagAlt = 'Brazil flag',\r\n className,\r\n classnameContainer,\r\n ...props\r\n },\r\n ref\r\n ) => {\r\n const finalMessage = error && errorMessage ? errorMessage : hintMessage;\r\n const showMessage = finalMessage && finalMessage.trim() !== '';\r\n\r\n return (\r\n <div className={cn('flex flex-col gap-1.5')}>\r\n {label && (\r\n <div className=\"flex items-center gap-1 paragraph-xsmall-semibold\">\r\n <span className=\"text-gray-600\">{label}</span>\r\n {optional && <span className=\"text-gray-500\">(Opcional)</span>}\r\n {required && <span className=\"text-red-600\">*</span>}\r\n </div>\r\n )}\r\n\r\n <div\r\n className={cn(\r\n 'flex gap-2 items-center border rounded-lg h-10 transition-colors',\r\n error\r\n ? 'border-red-600 hover:border-red-700'\r\n : 'border-gray-200 hover:border-gray-400 focus-within:border-gray-950',\r\n classnameContainer\r\n )}\r\n >\r\n <div className=\"flex items-center gap-2 px-4\">\r\n <Image\r\n src={countryFlagSrc}\r\n alt={countryFlagAlt}\r\n width={20}\r\n height={20}\r\n className=\"h-5! w-5! rounded-full\"\r\n />\r\n <span className=\"paragraph-small-regular text-gray-950\">{countryCode}</span>\r\n </div>\r\n\r\n <Separator orientation=\"vertical\" />\r\n\r\n <Input\r\n ref={ref}\r\n type=\"tel\"\r\n className={cn(\r\n 'paragraph-small-medium w-full h-full text-gray-950 border-0 focus-visible:ring-0 focus-visible:ring-offset-0',\r\n className\r\n )}\r\n {...props}\r\n />\r\n </div>\r\n\r\n {showMessage && (\r\n <span className={cn('paragraph-xsmall-medium', error ? 'text-red-600' : 'text-gray-600')}>\r\n {finalMessage}\r\n </span>\r\n )}\r\n </div>\r\n );\r\n }\r\n);\r\n\r\nPhoneInput.displayName = 'PhoneInput';\r\n\r\nexport default PhoneInput;\r\n"],"mappings":";AA6CU,SACE,KADF;AA3CV,SAAmC,kBAAkB;AACrD,OAAO,WAAW;AAClB,SAAS,aAAa;AACtB,SAAS,iBAAiB;AAC1B,SAAS,UAAU;AAenB,MAAM,aAAa;AAAA,EACjB,CACE;AAAA,IACE;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,eAAe,SAAS,eAAe,eAAe;AAC5D,UAAM,cAAc,gBAAgB,aAAa,KAAK,MAAM;AAE5D,WACE,qBAAC,SAAI,WAAW,GAAG,uBAAuB,GACvC;AAAA,eACC,qBAAC,SAAI,WAAU,qDACb;AAAA,4BAAC,UAAK,WAAU,iBAAiB,iBAAM;AAAA,QACtC,YAAY,oBAAC,UAAK,WAAU,iBAAgB,wBAAU;AAAA,QACtD,YAAY,oBAAC,UAAK,WAAU,gBAAe,eAAC;AAAA,SAC/C;AAAA,MAGF;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA,QACI,wCACA;AAAA,YACJ;AAAA,UACF;AAAA,UAEA;AAAA,iCAAC,SAAI,WAAU,gCACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,KAAK;AAAA,kBACL,KAAK;AAAA,kBACL,OAAO;AAAA,kBACP,QAAQ;AAAA,kBACR,WAAU;AAAA;AAAA,cACZ;AAAA,cACA,oBAAC,UAAK,WAAU,yCAAyC,uBAAY;AAAA,eACvE;AAAA,YAEA,oBAAC,aAAU,aAAY,YAAW;AAAA,YAElC;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA,MAAK;AAAA,gBACL,WAAW;AAAA,kBACT;AAAA,kBACA;AAAA,gBACF;AAAA,gBACC,GAAG;AAAA;AAAA,YACN;AAAA;AAAA;AAAA,MACF;AAAA,MAEC,eACC,oBAAC,UAAK,WAAW,GAAG,2BAA2B,QAAQ,iBAAiB,eAAe,GACpF,wBACH;AAAA,OAEJ;AAAA,EAEJ;AACF;AAEA,WAAW,cAAc;AAEzB,IAAO,qBAAQ;","names":[]}
@@ -0,0 +1,80 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ Select,
5
+ SelectContent,
6
+ SelectItem,
7
+ SelectTrigger,
8
+ SelectValue
9
+ } from "./Select";
10
+ import { cn } from "../../../infra/utils/clsx";
11
+ function SelectField({
12
+ label,
13
+ optional = false,
14
+ required = false,
15
+ hintMessage,
16
+ error = false,
17
+ errorMessage,
18
+ placeholder = "Selecione uma op\xE7\xE3o",
19
+ options,
20
+ value,
21
+ defaultValue,
22
+ onChange,
23
+ disabled = false,
24
+ icon,
25
+ className,
26
+ containerClassName
27
+ }) {
28
+ const handleValueChange = (selectedValue) => {
29
+ if (!onChange) return;
30
+ const selectedOption = options.find((option) => String(option.value) === selectedValue);
31
+ if (selectedOption) {
32
+ onChange(selectedOption.value);
33
+ }
34
+ };
35
+ const finalMessage = error && errorMessage ? errorMessage : hintMessage;
36
+ const messageColor = error ? "text-red-600" : "text-gray-600";
37
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", containerClassName), children: [
38
+ label && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 paragraph-xsmall-semibold", children: [
39
+ /* @__PURE__ */ jsx("span", { className: "text-gray-600", children: label }),
40
+ optional && /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: "(Opcional)" }),
41
+ required && /* @__PURE__ */ jsx("span", { className: "text-red-600", children: "*" })
42
+ ] }),
43
+ /* @__PURE__ */ jsxs(
44
+ Select,
45
+ {
46
+ value: value !== void 0 ? String(value) : void 0,
47
+ defaultValue: defaultValue !== void 0 ? String(defaultValue) : void 0,
48
+ onValueChange: handleValueChange,
49
+ disabled,
50
+ children: [
51
+ /* @__PURE__ */ jsx(
52
+ SelectTrigger,
53
+ {
54
+ className: cn(
55
+ "paragraph-small-medium w-full h-10 text-gray-950 px-4 transition-colors",
56
+ error ? "border-red-600 hover:border-red-700 focus:border-red-600" : "border-gray-200 hover:border-gray-400 focus-within:border-gray-950 focus:border-gray-950",
57
+ disabled && "cursor-not-allowed opacity-50",
58
+ className
59
+ ),
60
+ icon,
61
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder, children: value !== void 0 && (() => {
62
+ const selectedOption = options.find((opt) => String(opt.value) === String(value));
63
+ return selectedOption?.displayValue || selectedOption?.label;
64
+ })() })
65
+ }
66
+ ),
67
+ /* @__PURE__ */ jsx(SelectContent, { sideOffset: 4, children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: String(option.value), children: option.label }, String(option.value))) })
68
+ ]
69
+ }
70
+ ),
71
+ finalMessage && /* @__PURE__ */ jsx("span", { className: cn("paragraph-xsmall-medium", messageColor), children: finalMessage })
72
+ ] });
73
+ }
74
+ SelectField.displayName = "SelectField";
75
+ var SelectField_default = SelectField;
76
+ export {
77
+ SelectField,
78
+ SelectField_default as default
79
+ };
80
+ //# sourceMappingURL=SelectField.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/ui/form/SelectField.tsx"],"sourcesContent":["'use client';\r\n\r\nimport React from 'react';\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from './Select';\r\nimport { cn } from '../../../infra/utils/clsx';\r\n\r\ntype SelectOption = {\r\n value: string | number | boolean;\r\n label: React.ReactNode;\r\n displayValue?: string;\r\n};\r\n\r\ninterface SelectFieldProps {\r\n options: SelectOption[];\r\n label?: string;\r\n optional?: boolean;\r\n required?: boolean;\r\n hintMessage?: string;\r\n error?: boolean;\r\n errorMessage?: string;\r\n placeholder?: string;\r\n value?: string | number | boolean;\r\n defaultValue?: string | number | boolean;\r\n onChange?: (value: string | number | boolean) => void;\r\n disabled?: boolean;\r\n icon?: React.ReactNode;\r\n className?: string;\r\n containerClassName?: string;\r\n}\r\n\r\nexport function SelectField({\r\n label,\r\n optional = false,\r\n required = false,\r\n hintMessage,\r\n error = false,\r\n errorMessage,\r\n placeholder = 'Selecione uma opção',\r\n options,\r\n value,\r\n defaultValue,\r\n onChange,\r\n disabled = false,\r\n icon,\r\n className,\r\n containerClassName,\r\n}: SelectFieldProps) {\r\n const handleValueChange = (selectedValue: string) => {\r\n if (!onChange) return;\r\n const selectedOption = options.find((option) => String(option.value) === selectedValue);\r\n if (selectedOption) {\r\n onChange(selectedOption.value);\r\n }\r\n };\r\n\r\n const finalMessage = error && errorMessage ? errorMessage : hintMessage;\r\n const messageColor = error ? 'text-red-600' : 'text-gray-600';\r\n\r\n return (\r\n <div className={cn('flex flex-col gap-1.5', containerClassName)}>\r\n {label && (\r\n <div className=\"flex items-center gap-1 paragraph-xsmall-semibold\">\r\n <span className=\"text-gray-600\">{label}</span>\r\n {optional && <span className=\"text-gray-500\">(Opcional)</span>}\r\n {required && <span className=\"text-red-600\">*</span>}\r\n </div>\r\n )}\r\n\r\n <Select\r\n value={value !== undefined ? String(value) : undefined}\r\n defaultValue={defaultValue !== undefined ? String(defaultValue) : undefined}\r\n onValueChange={handleValueChange}\r\n disabled={disabled}\r\n >\r\n <SelectTrigger\r\n className={cn(\r\n 'paragraph-small-medium w-full h-10 text-gray-950 px-4 transition-colors',\r\n error\r\n ? 'border-red-600 hover:border-red-700 focus:border-red-600'\r\n : 'border-gray-200 hover:border-gray-400 focus-within:border-gray-950 focus:border-gray-950',\r\n disabled && 'cursor-not-allowed opacity-50',\r\n className\r\n )}\r\n icon={icon}\r\n >\r\n <SelectValue placeholder={placeholder}>\r\n {value !== undefined &&\r\n (() => {\r\n const selectedOption = options.find((opt) => String(opt.value) === String(value));\r\n return selectedOption?.displayValue || selectedOption?.label;\r\n })()}\r\n </SelectValue>\r\n </SelectTrigger>\r\n <SelectContent sideOffset={4}>\r\n {options.map((option) => (\r\n <SelectItem key={String(option.value)} value={String(option.value)}>\r\n {option.label}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n\r\n {finalMessage && (\r\n <span className={cn('paragraph-xsmall-medium', messageColor)}>{finalMessage}</span>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\nSelectField.displayName = 'SelectField';\r\n\r\nexport default SelectField;\r\n"],"mappings":";AAmEQ,SACE,KADF;AAhER;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,UAAU;AA0BZ,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,oBAAoB,CAAC,kBAA0B;AACnD,QAAI,CAAC,SAAU;AACf,UAAM,iBAAiB,QAAQ,KAAK,CAAC,WAAW,OAAO,OAAO,KAAK,MAAM,aAAa;AACtF,QAAI,gBAAgB;AAClB,eAAS,eAAe,KAAK;AAAA,IAC/B;AAAA,EACF;AAEA,QAAM,eAAe,SAAS,eAAe,eAAe;AAC5D,QAAM,eAAe,QAAQ,iBAAiB;AAE9C,SACE,qBAAC,SAAI,WAAW,GAAG,yBAAyB,kBAAkB,GAC3D;AAAA,aACC,qBAAC,SAAI,WAAU,qDACb;AAAA,0BAAC,UAAK,WAAU,iBAAiB,iBAAM;AAAA,MACtC,YAAY,oBAAC,UAAK,WAAU,iBAAgB,wBAAU;AAAA,MACtD,YAAY,oBAAC,UAAK,WAAU,gBAAe,eAAC;AAAA,OAC/C;AAAA,IAGF;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,UAAU,SAAY,OAAO,KAAK,IAAI;AAAA,QAC7C,cAAc,iBAAiB,SAAY,OAAO,YAAY,IAAI;AAAA,QAClE,eAAe;AAAA,QACf;AAAA,QAEA;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,QACI,6DACA;AAAA,gBACJ,YAAY;AAAA,gBACZ;AAAA,cACF;AAAA,cACA;AAAA,cAEA,8BAAC,eAAY,aACV,oBAAU,WACR,MAAM;AACL,sBAAM,iBAAiB,QAAQ,KAAK,CAAC,QAAQ,OAAO,IAAI,KAAK,MAAM,OAAO,KAAK,CAAC;AAChF,uBAAO,gBAAgB,gBAAgB,gBAAgB;AAAA,cACzD,GAAG,GACP;AAAA;AAAA,UACF;AAAA,UACA,oBAAC,iBAAc,YAAY,GACxB,kBAAQ,IAAI,CAAC,WACZ,oBAAC,cAAsC,OAAO,OAAO,OAAO,KAAK,GAC9D,iBAAO,SADO,OAAO,OAAO,KAAK,CAEpC,CACD,GACH;AAAA;AAAA;AAAA,IACF;AAAA,IAEC,gBACC,oBAAC,UAAK,WAAW,GAAG,2BAA2B,YAAY,GAAI,wBAAa;AAAA,KAEhF;AAEJ;AAEA,YAAY,cAAc;AAE1B,IAAO,sBAAQ;","names":[]}
@@ -0,0 +1,40 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Switch } from "./Switch";
3
+ function SwitchOptionFieldWithIcon({
4
+ icon: Icon,
5
+ label,
6
+ description,
7
+ checked,
8
+ onCheckedChange,
9
+ disabled = false,
10
+ hideBorderBottom = false,
11
+ id
12
+ }) {
13
+ return /* @__PURE__ */ jsxs(
14
+ "label",
15
+ {
16
+ className: `flex justify-between items-center gap-3 p-5 ${!hideBorderBottom ? "border-b border-gray-200" : ""} ${disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"}`,
17
+ children: [
18
+ /* @__PURE__ */ jsx("div", { className: "size-10 rounded-lg bg-gray-50 flex items-center justify-center text-gray-950", children: /* @__PURE__ */ jsx(Icon, { size: 20 }) }),
19
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 flex-1", children: [
20
+ /* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold text-gray-950", children: label }),
21
+ /* @__PURE__ */ jsx("span", { className: "paragraph-small-regular text-gray-600", children: description })
22
+ ] }),
23
+ /* @__PURE__ */ jsx(
24
+ Switch,
25
+ {
26
+ id,
27
+ checked: disabled ? true : checked,
28
+ onCheckedChange,
29
+ disabled,
30
+ className: disabled ? "opacity-20!" : ""
31
+ }
32
+ )
33
+ ]
34
+ }
35
+ );
36
+ }
37
+ export {
38
+ SwitchOptionFieldWithIcon as default
39
+ };
40
+ //# sourceMappingURL=SwitchOptionFieldWithIcon.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/ui/form/SwitchOptionFieldWithIcon.tsx"],"sourcesContent":["import { LucideIcon } from 'lucide-react';\r\nimport { Switch } from './Switch';\r\n\r\ntype SwitchOptionFieldWithIconProps = {\r\n icon: LucideIcon;\r\n label: string;\r\n description: string;\r\n checked: boolean;\r\n onCheckedChange: (checked: boolean) => void;\r\n disabled?: boolean;\r\n hideBorderBottom?: boolean;\r\n id?: string;\r\n};\r\n\r\nexport default function SwitchOptionFieldWithIcon({\r\n icon: Icon,\r\n label,\r\n description,\r\n checked,\r\n onCheckedChange,\r\n disabled = false,\r\n hideBorderBottom = false,\r\n id,\r\n}: SwitchOptionFieldWithIconProps) {\r\n return (\r\n <label\r\n className={`flex justify-between items-center gap-3 p-5 ${\r\n !hideBorderBottom ? 'border-b border-gray-200' : ''\r\n } ${disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'}`}\r\n >\r\n <div className=\"size-10 rounded-lg bg-gray-50 flex items-center justify-center text-gray-950\">\r\n <Icon size={20} />\r\n </div>\r\n <div className=\"flex flex-col gap-2 flex-1\">\r\n <span className=\"paragraph-small-semibold text-gray-950\">{label}</span>\r\n <span className=\"paragraph-small-regular text-gray-600\">{description}</span>\r\n </div>\r\n <Switch\r\n id={id}\r\n checked={disabled ? true : checked}\r\n onCheckedChange={onCheckedChange}\r\n disabled={disabled}\r\n className={disabled ? 'opacity-20!' : ''}\r\n />\r\n </label>\r\n );\r\n}\r\n"],"mappings":"AA+BQ,cAEF,YAFE;AA9BR,SAAS,cAAc;AAaR,SAAR,0BAA2C;AAAA,EAChD,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,mBAAmB;AAAA,EACnB;AACF,GAAmC;AACjC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,+CACT,CAAC,mBAAmB,6BAA6B,EACnD,IAAI,WAAW,kCAAkC,gBAAgB;AAAA,MAEjE;AAAA,4BAAC,SAAI,WAAU,gFACb,8BAAC,QAAK,MAAM,IAAI,GAClB;AAAA,QACA,qBAAC,SAAI,WAAU,8BACb;AAAA,8BAAC,UAAK,WAAU,0CAA0C,iBAAM;AAAA,UAChE,oBAAC,UAAK,WAAU,yCAAyC,uBAAY;AAAA,WACvE;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,SAAS,WAAW,OAAO;AAAA,YAC3B;AAAA,YACA;AAAA,YACA,WAAW,WAAW,gBAAgB;AAAA;AAAA,QACxC;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { forwardRef } from "react";
4
+ import { Textarea } from "./Textarea";
5
+ import { cn } from "../../../infra/utils/clsx";
6
+ const TextAreaField = forwardRef(
7
+ ({
8
+ label,
9
+ optional = false,
10
+ required = false,
11
+ hintMessage,
12
+ error = false,
13
+ errorMessage,
14
+ className,
15
+ ...textareaProps
16
+ }, ref) => {
17
+ const finalMessage = error && errorMessage ? errorMessage : hintMessage;
18
+ const messageColor = error ? "text-red-600" : "text-gray-600";
19
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
20
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 paragraph-xsmall-semibold", children: [
21
+ label && /* @__PURE__ */ jsx("span", { className: "text-gray-600", children: label }),
22
+ optional && /* @__PURE__ */ jsx("span", { className: "text-gray-500", children: "(Opcional)" }),
23
+ required && /* @__PURE__ */ jsx("span", { className: "text-red-600", children: "*" })
24
+ ] }),
25
+ /* @__PURE__ */ jsx(
26
+ "div",
27
+ {
28
+ className: cn(
29
+ "flex px-4 py-3 border rounded-lg transition-colors overflow-hidden",
30
+ error ? "border-red-600 hover:border-red-700" : "border-gray-200 hover:border-gray-400 focus-within:border-gray-950"
31
+ ),
32
+ children: /* @__PURE__ */ jsx(
33
+ Textarea,
34
+ {
35
+ ref,
36
+ className: cn(
37
+ "paragraph-small-medium w-full text-gray-950 border-none shadow-none focus-visible:ring-0 p-0 resize-none overflow-y-auto field-sizing-fixed! min-h-0! break-words",
38
+ error && "placeholder:text-red-400",
39
+ className
40
+ ),
41
+ ...textareaProps
42
+ }
43
+ )
44
+ }
45
+ ),
46
+ finalMessage && /* @__PURE__ */ jsx("span", { className: cn("paragraph-xsmall-medium", messageColor), children: finalMessage })
47
+ ] });
48
+ }
49
+ );
50
+ TextAreaField.displayName = "TextAreaField";
51
+ var TextAreaField_default = TextAreaField;
52
+ export {
53
+ TextAreaField,
54
+ TextAreaField_default as default
55
+ };
56
+ //# sourceMappingURL=TextAreaField.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/ui/form/TextAreaField.tsx"],"sourcesContent":["'use client';\r\n\r\nimport { forwardRef, type ComponentPropsWithoutRef } from 'react';\r\nimport { Textarea } from './Textarea';\r\nimport { cn } from '../../../infra/utils/clsx';\r\n\r\ninterface TextAreaFieldProps extends ComponentPropsWithoutRef<'textarea'> {\r\n label?: string;\r\n optional?: boolean;\r\n required?: boolean;\r\n hintMessage?: string;\r\n error?: boolean;\r\n errorMessage?: string;\r\n}\r\n\r\nexport const TextAreaField = forwardRef<HTMLTextAreaElement, TextAreaFieldProps>(\r\n (\r\n {\r\n label,\r\n optional = false,\r\n required = false,\r\n hintMessage,\r\n error = false,\r\n errorMessage,\r\n className,\r\n ...textareaProps\r\n },\r\n ref\r\n ) => {\r\n const finalMessage = error && errorMessage ? errorMessage : hintMessage;\r\n const messageColor = error ? 'text-red-600' : 'text-gray-600';\r\n\r\n return (\r\n <div className=\"flex flex-col gap-1.5\">\r\n <div className=\"flex items-center gap-1 paragraph-xsmall-semibold\">\r\n {label && <span className=\"text-gray-600\">{label}</span>}\r\n {optional && <span className=\"text-gray-500\">(Opcional)</span>}\r\n {required && <span className=\"text-red-600\">*</span>}\r\n </div>\r\n\r\n <div\r\n className={cn(\r\n 'flex px-4 py-3 border rounded-lg transition-colors overflow-hidden',\r\n error\r\n ? 'border-red-600 hover:border-red-700'\r\n : 'border-gray-200 hover:border-gray-400 focus-within:border-gray-950'\r\n )}\r\n >\r\n <Textarea\r\n ref={ref}\r\n className={cn(\r\n 'paragraph-small-medium w-full text-gray-950 border-none shadow-none focus-visible:ring-0 p-0 resize-none overflow-y-auto field-sizing-fixed! min-h-0! break-words',\r\n error && 'placeholder:text-red-400',\r\n className\r\n )}\r\n {...textareaProps}\r\n />\r\n </div>\r\n\r\n {finalMessage && (\r\n <span className={cn('paragraph-xsmall-medium', messageColor)}>{finalMessage}</span>\r\n )}\r\n </div>\r\n );\r\n }\r\n);\r\n\r\nTextAreaField.displayName = 'TextAreaField';\r\n\r\nexport default TextAreaField;\r\n"],"mappings":";AAkCQ,SACY,KADZ;AAhCR,SAAS,kBAAiD;AAC1D,SAAS,gBAAgB;AACzB,SAAS,UAAU;AAWZ,MAAM,gBAAgB;AAAA,EAC3B,CACE;AAAA,IACE;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,eAAe,SAAS,eAAe,eAAe;AAC5D,UAAM,eAAe,QAAQ,iBAAiB;AAE9C,WACE,qBAAC,SAAI,WAAU,yBACb;AAAA,2BAAC,SAAI,WAAU,qDACZ;AAAA,iBAAS,oBAAC,UAAK,WAAU,iBAAiB,iBAAM;AAAA,QAChD,YAAY,oBAAC,UAAK,WAAU,iBAAgB,wBAAU;AAAA,QACtD,YAAY,oBAAC,UAAK,WAAU,gBAAe,eAAC;AAAA,SAC/C;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA,QACI,wCACA;AAAA,UACN;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,WAAW;AAAA,gBACT;AAAA,gBACA,SAAS;AAAA,gBACT;AAAA,cACF;AAAA,cACC,GAAG;AAAA;AAAA,UACN;AAAA;AAAA,MACF;AAAA,MAEC,gBACC,oBAAC,UAAK,WAAW,GAAG,2BAA2B,YAAY,GAAI,wBAAa;AAAA,OAEhF;AAAA,EAEJ;AACF;AAEA,cAAc,cAAc;AAE5B,IAAO,wBAAQ;","names":[]}
@@ -0,0 +1,11 @@
1
+ var AccountSectionType = /* @__PURE__ */ ((AccountSectionType2) => {
2
+ AccountSectionType2["MY_PROFILE"] = "my-profile";
3
+ AccountSectionType2["SECURITY"] = "security";
4
+ AccountSectionType2["PREFERENCES"] = "preferences";
5
+ AccountSectionType2["CHANGE_PASSWORD"] = "change-password";
6
+ return AccountSectionType2;
7
+ })(AccountSectionType || {});
8
+ export {
9
+ AccountSectionType
10
+ };
11
+ //# sourceMappingURL=AccountSectionType.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/enums/AccountSectionType.ts"],"sourcesContent":["export enum AccountSectionType {\r\n MY_PROFILE = 'my-profile',\r\n SECURITY = 'security',\r\n PREFERENCES = 'preferences',\r\n CHANGE_PASSWORD = 'change-password',\r\n}\r\n"],"mappings":"AAAO,IAAK,qBAAL,kBAAKA,wBAAL;AACL,EAAAA,oBAAA,gBAAa;AACb,EAAAA,oBAAA,cAAW;AACX,EAAAA,oBAAA,iBAAc;AACd,EAAAA,oBAAA,qBAAkB;AAJR,SAAAA;AAAA,GAAA;","names":["AccountSectionType"]}
@@ -0,0 +1,29 @@
1
+ "use client";
2
+ import { useEffect, useState, useCallback } from "react";
3
+ function useCountdownTimer({
4
+ initialSeconds = 59,
5
+ onExpire
6
+ } = {}) {
7
+ const [seconds, setSeconds] = useState(initialSeconds);
8
+ const [isExpired, setIsExpired] = useState(false);
9
+ useEffect(() => {
10
+ if (seconds > 0) {
11
+ const interval = setInterval(() => {
12
+ setSeconds((prev) => prev - 1);
13
+ }, 1e3);
14
+ return () => clearInterval(interval);
15
+ } else {
16
+ setIsExpired(true);
17
+ onExpire?.();
18
+ }
19
+ }, [seconds, onExpire]);
20
+ const reset = useCallback(() => {
21
+ setSeconds(initialSeconds);
22
+ setIsExpired(false);
23
+ }, [initialSeconds]);
24
+ return { seconds, isExpired, reset };
25
+ }
26
+ export {
27
+ useCountdownTimer as default
28
+ };
29
+ //# sourceMappingURL=useCountdownTimer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/useCountdownTimer.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useEffect, useState, useCallback } from 'react';\r\n\r\ninterface UseCountdownTimerOptions {\r\n initialSeconds?: number;\r\n onExpire?: () => void;\r\n}\r\n\r\ninterface UseCountdownTimerReturn {\r\n seconds: number;\r\n isExpired: boolean;\r\n reset: () => void;\r\n}\r\n\r\nexport default function useCountdownTimer({\r\n initialSeconds = 59,\r\n onExpire,\r\n}: UseCountdownTimerOptions = {}): UseCountdownTimerReturn {\r\n const [seconds, setSeconds] = useState(initialSeconds);\r\n const [isExpired, setIsExpired] = useState(false);\r\n\r\n useEffect(() => {\r\n if (seconds > 0) {\r\n const interval = setInterval(() => {\r\n setSeconds((prev) => prev - 1);\r\n }, 1000);\r\n return () => clearInterval(interval);\r\n } else {\r\n setIsExpired(true);\r\n onExpire?.();\r\n }\r\n }, [seconds, onExpire]);\r\n\r\n const reset = useCallback(() => {\r\n setSeconds(initialSeconds);\r\n setIsExpired(false);\r\n }, [initialSeconds]);\r\n\r\n return { seconds, isExpired, reset };\r\n}\r\n"],"mappings":";AAEA,SAAS,WAAW,UAAU,mBAAmB;AAalC,SAAR,kBAAmC;AAAA,EACxC,iBAAiB;AAAA,EACjB;AACF,IAA8B,CAAC,GAA4B;AACzD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,cAAc;AACrD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,YAAU,MAAM;AACd,QAAI,UAAU,GAAG;AACf,YAAM,WAAW,YAAY,MAAM;AACjC,mBAAW,CAAC,SAAS,OAAO,CAAC;AAAA,MAC/B,GAAG,GAAI;AACP,aAAO,MAAM,cAAc,QAAQ;AAAA,IACrC,OAAO;AACL,mBAAa,IAAI;AACjB,iBAAW;AAAA,IACb;AAAA,EACF,GAAG,CAAC,SAAS,QAAQ,CAAC;AAEtB,QAAM,QAAQ,YAAY,MAAM;AAC9B,eAAW,cAAc;AACzB,iBAAa,KAAK;AAAA,EACpB,GAAG,CAAC,cAAc,CAAC;AAEnB,SAAO,EAAE,SAAS,WAAW,MAAM;AACrC;","names":[]}
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { useEffect, useState } from "react";
3
+ function useIsMobile() {
4
+ const [isMobile, setIsMobile] = useState(false);
5
+ useEffect(() => {
6
+ const checkMobile = () => {
7
+ setIsMobile(window.innerWidth < 1024);
8
+ };
9
+ checkMobile();
10
+ window.addEventListener("resize", checkMobile);
11
+ return () => window.removeEventListener("resize", checkMobile);
12
+ }, []);
13
+ return isMobile;
14
+ }
15
+ export {
16
+ useIsMobile as default
17
+ };
18
+ //# sourceMappingURL=useIsMobile.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/useIsMobile.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useEffect, useState } from 'react';\r\n\r\nexport default function useIsMobile() {\r\n const [isMobile, setIsMobile] = useState(false);\r\n\r\n useEffect(() => {\r\n const checkMobile = () => {\r\n setIsMobile(window.innerWidth < 1024);\r\n };\r\n\r\n checkMobile();\r\n window.addEventListener('resize', checkMobile);\r\n return () => window.removeEventListener('resize', checkMobile);\r\n }, []);\r\n\r\n return isMobile;\r\n}\r\n"],"mappings":";AAEA,SAAS,WAAW,gBAAgB;AAErB,SAAR,cAA+B;AACpC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAE9C,YAAU,MAAM;AACd,UAAM,cAAc,MAAM;AACxB,kBAAY,OAAO,aAAa,IAAI;AAAA,IACtC;AAEA,gBAAY;AACZ,WAAO,iBAAiB,UAAU,WAAW;AAC7C,WAAO,MAAM,OAAO,oBAAoB,UAAU,WAAW;AAAA,EAC/D,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;","names":[]}
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { useState, useCallback } from "react";
3
+ function usePasswordVisibility() {
4
+ const [showPassword, setShowPassword] = useState(false);
5
+ const togglePassword = useCallback(() => {
6
+ setShowPassword((prev) => !prev);
7
+ }, []);
8
+ return { showPassword, togglePassword };
9
+ }
10
+ export {
11
+ usePasswordVisibility as default
12
+ };
13
+ //# sourceMappingURL=usePasswordVisibility.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/usePasswordVisibility.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useState, useCallback } from 'react';\r\n\r\nexport default function usePasswordVisibility() {\r\n const [showPassword, setShowPassword] = useState(false);\r\n\r\n const togglePassword = useCallback(() => {\r\n setShowPassword((prev) => !prev);\r\n }, []);\r\n\r\n return { showPassword, togglePassword };\r\n}\r\n"],"mappings":";AAEA,SAAS,UAAU,mBAAmB;AAEvB,SAAR,wBAAyC;AAC9C,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AAEtD,QAAM,iBAAiB,YAAY,MAAM;AACvC,oBAAgB,CAAC,SAAS,CAAC,IAAI;AAAA,EACjC,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,cAAc,eAAe;AACxC;","names":[]}