@greatapps/common 1.1.256 → 1.1.258

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 (271) hide show
  1. package/dist/components/account/ConfigurationsMyAccountModal.mjs +2 -2
  2. package/dist/components/account/ConfigurationsMyAccountModal.mjs.map +1 -1
  3. package/dist/components/account/ConfirmDeleteAccountModal.mjs.map +1 -1
  4. package/dist/components/account/ConfirmGlobalPreferencesModal.mjs.map +1 -1
  5. package/dist/components/account/DeleteAccountModal.mjs.map +1 -1
  6. package/dist/components/account/DisableTwoFactorAuthModal.mjs.map +1 -1
  7. package/dist/components/account/IsntPossibleDeleteAccountModal.mjs.map +1 -1
  8. package/dist/components/account/TwoFactorAuthModal.mjs.map +1 -1
  9. package/dist/components/account/hooks/useChangePhoneForm.mjs.map +1 -1
  10. package/dist/components/account/hooks/useTwoFactorAuthForm.mjs.map +1 -1
  11. package/dist/components/account/sections/ChangeEmailModal.mjs.map +1 -1
  12. package/dist/components/account/sections/ChangePasswordSection.mjs.map +1 -1
  13. package/dist/components/account/sections/ChangePhoneModal.mjs.map +1 -1
  14. package/dist/components/account/sections/MyProfileSection.mjs.map +1 -1
  15. package/dist/components/account/sections/PreferencesSection.mjs.map +1 -1
  16. package/dist/components/account/sections/SecuritySection.mjs.map +1 -1
  17. package/dist/components/embeds/CrispEmbed.mjs.map +1 -1
  18. package/dist/components/embeds/FrillEmbed.mjs.map +1 -1
  19. package/dist/components/layouts/AppMobileNavBar.mjs.map +1 -1
  20. package/dist/components/layouts/AppNavBar.mjs.map +1 -1
  21. package/dist/components/layouts/MdSideBarNavigation.mjs.map +1 -1
  22. package/dist/components/layouts/NavBar.mjs.map +1 -1
  23. package/dist/components/layouts/NotificationsPopover.mjs.map +1 -1
  24. package/dist/components/layouts/ProfilePopover.mjs.map +1 -1
  25. package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
  26. package/dist/components/modals/BuyCreditsModal.mjs.map +1 -1
  27. package/dist/components/navigation/CancelledSubscriptionBanner.mjs.map +1 -1
  28. package/dist/components/navigation/NavItemsContext.mjs.map +1 -1
  29. package/dist/components/navigation/ProjectSelectorPopover.mjs.map +1 -1
  30. package/dist/components/navigation/shells/TabsMobileShell.mjs.map +1 -1
  31. package/dist/components/navigation/subcomponents/ProjectSelector.mjs.map +1 -1
  32. package/dist/components/pages/notifications/Notifications.mjs.map +1 -1
  33. package/dist/components/ui/buttons/Button.mjs.map +1 -1
  34. package/dist/components/ui/buttons/CancelButton.mjs.map +1 -1
  35. package/dist/components/ui/buttons/CopyButton.mjs.map +1 -1
  36. package/dist/components/ui/data-display/Accordion.mjs.map +1 -1
  37. package/dist/components/ui/data-display/Badge.mjs.map +1 -1
  38. package/dist/components/ui/data-display/Card.mjs.map +1 -1
  39. package/dist/components/ui/data-display/CardBrandIcons.mjs.map +1 -1
  40. package/dist/components/ui/data-display/CardItem.mjs.map +1 -1
  41. package/dist/components/ui/data-display/Pagination.mjs.map +1 -1
  42. package/dist/components/ui/data-display/PaymentInfoCard.mjs.map +1 -1
  43. package/dist/components/ui/data-display/ScrollArea.mjs.map +1 -1
  44. package/dist/components/ui/data-display/Separator.mjs.map +1 -1
  45. package/dist/components/ui/data-display/Table.mjs.map +1 -1
  46. package/dist/components/ui/data-display/Tabs.mjs.map +1 -1
  47. package/dist/components/ui/feedback/CircularProgress.mjs.map +1 -1
  48. package/dist/components/ui/feedback/DefaultCircularProgress.mjs.map +1 -1
  49. package/dist/components/ui/feedback/LoadingOverlay.mjs.map +1 -1
  50. package/dist/components/ui/feedback/Progress.mjs.map +1 -1
  51. package/dist/components/ui/feedback/Skeleton.mjs.map +1 -1
  52. package/dist/components/ui/feedback/Toast.mjs.map +1 -1
  53. package/dist/components/ui/form/Calendar.mjs.map +1 -1
  54. package/dist/components/ui/form/Checkbox.mjs.map +1 -1
  55. package/dist/components/ui/form/ComboboxField.mjs.map +1 -1
  56. package/dist/components/ui/form/DatePicker.mjs.map +1 -1
  57. package/dist/components/ui/form/DateRangePicker.mjs.map +1 -1
  58. package/dist/components/ui/form/FormField.mjs.map +1 -1
  59. package/dist/components/ui/form/Input.mjs.map +1 -1
  60. package/dist/components/ui/form/InputOtp.mjs.map +1 -1
  61. package/dist/components/ui/form/PhoneInput.mjs.map +1 -1
  62. package/dist/components/ui/form/RadioGroup.mjs.map +1 -1
  63. package/dist/components/ui/form/Select.mjs +1 -1
  64. package/dist/components/ui/form/Select.mjs.map +1 -1
  65. package/dist/components/ui/form/Switch.mjs.map +1 -1
  66. package/dist/components/ui/form/Textarea.mjs.map +1 -1
  67. package/dist/components/ui/overlay/Command.mjs.map +1 -1
  68. package/dist/components/ui/overlay/Dialog.mjs.map +1 -1
  69. package/dist/components/ui/overlay/Popover.mjs.map +1 -1
  70. package/dist/components/ui/overlay/Sheet.mjs.map +1 -1
  71. package/dist/components/ui/overlay/Tooltip.mjs.map +1 -1
  72. package/dist/hooks/copy-to-clipboard.hook.mjs.map +1 -1
  73. package/dist/index.mjs.map +1 -1
  74. package/dist/middleware.mjs.map +1 -1
  75. package/dist/modules/accounts/actions/account-management.action.mjs.map +1 -1
  76. package/dist/modules/accounts/actions/find-current-account.action.mjs.map +1 -1
  77. package/dist/modules/accounts/actions/list-currencies.action.mjs.map +1 -1
  78. package/dist/modules/accounts/actions/list-timezones.action.mjs.map +1 -1
  79. package/dist/modules/accounts/hooks/current-account.hook.mjs.map +1 -1
  80. package/dist/modules/accounts/hooks/useAccountManagement.mjs.map +1 -1
  81. package/dist/modules/accounts/hooks/useCurrencies.mjs.map +1 -1
  82. package/dist/modules/accounts/hooks/useTimezones.mjs.map +1 -1
  83. package/dist/modules/accounts/services/account.service.mjs.map +1 -1
  84. package/dist/modules/auth/actions/validate-session.action.mjs.map +1 -1
  85. package/dist/modules/auth/hooks/login.hook.mjs.map +1 -1
  86. package/dist/modules/auth/hooks/logout.hook.mjs.map +1 -1
  87. package/dist/modules/auth/hooks/register.hook.mjs.map +1 -1
  88. package/dist/modules/cards/actions/list-cards.action.mjs.map +1 -1
  89. package/dist/modules/cards/hooks/cards.hook.mjs.map +1 -1
  90. package/dist/modules/cards/services/cards.service.mjs.map +1 -1
  91. package/dist/modules/cards/types.mjs.map +1 -1
  92. package/dist/modules/ia-credits/actions/list-ia-credits.action.mjs.map +1 -1
  93. package/dist/modules/plans/actions/find-plan-by-id.action.mjs.map +1 -1
  94. package/dist/modules/plans/hooks/use-has-plan-addon.hook.mjs.map +1 -1
  95. package/dist/modules/plans/hooks/use-plan-by-id.hook.mjs.map +1 -1
  96. package/dist/modules/plans/services/plans.service.mjs.map +1 -1
  97. package/dist/modules/plans/types/plan.type.mjs.map +1 -1
  98. package/dist/modules/projects/actions/add-project-user.action.mjs.map +1 -1
  99. package/dist/modules/projects/actions/list-all-account-users.action.mjs.map +1 -1
  100. package/dist/modules/projects/actions/list-available-users.action.mjs.map +1 -1
  101. package/dist/modules/projects/actions/list-project-users.action.mjs.map +1 -1
  102. package/dist/modules/projects/actions/remove-project-user.action.mjs.map +1 -1
  103. package/dist/modules/projects/hooks/add-project-user.hook.mjs.map +1 -1
  104. package/dist/modules/projects/hooks/list-all-account-users.hook.mjs.map +1 -1
  105. package/dist/modules/projects/hooks/list-available-users.hook.mjs.map +1 -1
  106. package/dist/modules/projects/hooks/list-project-users.hook.mjs.map +1 -1
  107. package/dist/modules/projects/hooks/remove-project-user.hook.mjs.map +1 -1
  108. package/dist/modules/subscriptions/actions/calculate-subscription.action.mjs.map +1 -1
  109. package/dist/modules/subscriptions/actions/list-subscriptions.action.mjs.map +1 -1
  110. package/dist/modules/subscriptions/actions/update-subscription-plan.action.mjs.map +1 -1
  111. package/dist/modules/subscriptions/constants/query-keys.constants.mjs.map +1 -1
  112. package/dist/modules/subscriptions/hooks/calculate-subscription.hook.mjs.map +1 -1
  113. package/dist/modules/subscriptions/hooks/find-active-subscription.hook.mjs.map +1 -1
  114. package/dist/modules/subscriptions/hooks/list-subscriptions.hook.mjs.map +1 -1
  115. package/dist/modules/subscriptions/hooks/update-subscription-plan.hook.mjs.map +1 -1
  116. package/dist/modules/subscriptions/types/calculate-subscription.type.mjs.map +1 -1
  117. package/dist/modules/subscriptions/utils/build-plan-extras.mjs.map +1 -1
  118. package/dist/modules/subscriptions/utils/periodicity.mjs.map +1 -1
  119. package/dist/modules/subscriptions/utils/resolve-plan-extras-prices.mjs.map +1 -1
  120. package/dist/modules/users/action/find-user-by-id.action.mjs.map +1 -1
  121. package/dist/modules/users/action/list-messages.action.mjs.map +1 -1
  122. package/dist/modules/users/action/mark-all-messages-as-read.action.mjs.map +1 -1
  123. package/dist/modules/users/action/mark-message-as-read.action.mjs.map +1 -1
  124. package/dist/modules/users/hooks/messages.hook.mjs.map +1 -1
  125. package/dist/modules/whitelabel/actions/find-whitelabel-styles.action.mjs.map +1 -1
  126. package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs.map +1 -1
  127. package/dist/modules/whitelabel/actions/revalidate-whitelabel-styles.action.mjs.map +1 -1
  128. package/dist/modules/whitelabel/actions/revalidate-whitelabel.action.mjs.map +1 -1
  129. package/dist/modules/whitelabel/services/whitelabel-styles.service.mjs.map +1 -1
  130. package/dist/providers/whitelabel.provider.mjs.map +1 -1
  131. package/dist/store/useBuyCreditsModal.mjs.map +1 -1
  132. package/dist/utils/countries.mjs.map +1 -1
  133. package/dist/utils/safeServerAction.mjs.map +1 -1
  134. package/dist/utils/withAction.mjs.map +1 -1
  135. package/package.json +89 -89
  136. package/src/components/account/ConfigurationsMyAccountModal.tsx +150 -150
  137. package/src/components/account/ConfirmDeleteAccountModal.tsx +55 -55
  138. package/src/components/account/ConfirmGlobalPreferencesModal.tsx +66 -66
  139. package/src/components/account/DeleteAccountModal.tsx +130 -130
  140. package/src/components/account/DisableTwoFactorAuthModal.tsx +86 -86
  141. package/src/components/account/IsntPossibleDeleteAccountModal.tsx +49 -49
  142. package/src/components/account/TwoFactorAuthModal.tsx +223 -223
  143. package/src/components/account/hooks/useChangePhoneForm.tsx +81 -81
  144. package/src/components/account/hooks/useTwoFactorAuthForm.tsx +101 -101
  145. package/src/components/account/sections/ChangeEmailModal.tsx +225 -225
  146. package/src/components/account/sections/ChangePasswordSection.tsx +64 -64
  147. package/src/components/account/sections/ChangePhoneModal.tsx +231 -231
  148. package/src/components/account/sections/MyProfileSection.tsx +327 -327
  149. package/src/components/account/sections/PreferencesSection.tsx +273 -273
  150. package/src/components/account/sections/SecuritySection.tsx +160 -160
  151. package/src/components/embeds/CrispEmbed.tsx +101 -101
  152. package/src/components/embeds/FrillEmbed.tsx +119 -119
  153. package/src/components/layouts/AppMobileNavBar.tsx +118 -118
  154. package/src/components/layouts/AppNavBar.tsx +51 -51
  155. package/src/components/layouts/MdSideBarNavigation.tsx +56 -56
  156. package/src/components/layouts/NavBar.tsx +120 -120
  157. package/src/components/layouts/NotificationsPopover.tsx +115 -115
  158. package/src/components/layouts/ProfilePopover.tsx +164 -164
  159. package/src/components/layouts/UsersSelectorPopover.tsx +238 -238
  160. package/src/components/modals/BuyCreditsModal.tsx +301 -301
  161. package/src/components/navigation/CancelledSubscriptionBanner.tsx +69 -69
  162. package/src/components/navigation/NavItemsContext.ts +20 -20
  163. package/src/components/navigation/ProjectSelectorPopover.tsx +157 -157
  164. package/src/components/navigation/shells/TabsMobileShell.tsx +72 -72
  165. package/src/components/navigation/subcomponents/ProjectSelector.tsx +156 -156
  166. package/src/components/pages/notifications/Notifications.tsx +160 -160
  167. package/src/components/ui/buttons/Button.tsx +57 -57
  168. package/src/components/ui/buttons/CancelButton.tsx +14 -14
  169. package/src/components/ui/buttons/CopyButton.tsx +54 -54
  170. package/src/components/ui/data-display/Accordion.tsx +81 -81
  171. package/src/components/ui/data-display/Badge.tsx +47 -47
  172. package/src/components/ui/data-display/Card.tsx +93 -93
  173. package/src/components/ui/data-display/CardBrandIcons.tsx +336 -336
  174. package/src/components/ui/data-display/CardItem.tsx +75 -75
  175. package/src/components/ui/data-display/Pagination.tsx +126 -126
  176. package/src/components/ui/data-display/PaymentInfoCard.tsx +186 -186
  177. package/src/components/ui/data-display/ScrollArea.tsx +59 -59
  178. package/src/components/ui/data-display/Separator.tsx +29 -29
  179. package/src/components/ui/data-display/Table.tsx +117 -117
  180. package/src/components/ui/data-display/Tabs.tsx +67 -67
  181. package/src/components/ui/feedback/CircularProgress.tsx +75 -75
  182. package/src/components/ui/feedback/DefaultCircularProgress.tsx +61 -61
  183. package/src/components/ui/feedback/LoadingOverlay.tsx +31 -31
  184. package/src/components/ui/feedback/Progress.tsx +40 -40
  185. package/src/components/ui/feedback/Skeleton.tsx +5 -5
  186. package/src/components/ui/feedback/Toast.tsx +101 -101
  187. package/src/components/ui/form/Calendar.tsx +228 -228
  188. package/src/components/ui/form/Checkbox.tsx +31 -31
  189. package/src/components/ui/form/ComboboxField.tsx +154 -154
  190. package/src/components/ui/form/DatePicker.tsx +97 -97
  191. package/src/components/ui/form/DateRangePicker.tsx +108 -108
  192. package/src/components/ui/form/FormField.tsx +131 -131
  193. package/src/components/ui/form/Input.tsx +20 -20
  194. package/src/components/ui/form/InputOtp.tsx +80 -80
  195. package/src/components/ui/form/PhoneInput.tsx +205 -205
  196. package/src/components/ui/form/RadioGroup.tsx +45 -45
  197. package/src/components/ui/form/Select.tsx +200 -200
  198. package/src/components/ui/form/Switch.tsx +32 -32
  199. package/src/components/ui/form/Textarea.tsx +19 -19
  200. package/src/components/ui/overlay/Command.tsx +185 -185
  201. package/src/components/ui/overlay/Dialog.tsx +151 -151
  202. package/src/components/ui/overlay/Popover.tsx +49 -49
  203. package/src/components/ui/overlay/Sheet.tsx +166 -166
  204. package/src/components/ui/overlay/Tooltip.tsx +62 -62
  205. package/src/hooks/copy-to-clipboard.hook.tsx +67 -67
  206. package/src/index.ts +376 -376
  207. package/src/middleware.ts +4 -4
  208. package/src/modules/accounts/actions/account-management.action.ts +91 -91
  209. package/src/modules/accounts/actions/find-current-account.action.ts +9 -9
  210. package/src/modules/accounts/actions/list-currencies.action.ts +8 -8
  211. package/src/modules/accounts/actions/list-timezones.action.ts +8 -8
  212. package/src/modules/accounts/hooks/current-account.hook.tsx +22 -22
  213. package/src/modules/accounts/hooks/useAccountManagement.ts +85 -85
  214. package/src/modules/accounts/hooks/useCurrencies.ts +15 -15
  215. package/src/modules/accounts/hooks/useTimezones.ts +15 -15
  216. package/src/modules/accounts/services/account.service.ts +236 -236
  217. package/src/modules/accounts/types.ts +214 -214
  218. package/src/modules/auth/actions/validate-session.action.ts +56 -56
  219. package/src/modules/auth/hooks/login.hook.tsx +13 -13
  220. package/src/modules/auth/hooks/logout.hook.tsx +11 -11
  221. package/src/modules/auth/hooks/register.hook.tsx +11 -11
  222. package/src/modules/cards/actions/list-cards.action.ts +8 -8
  223. package/src/modules/cards/hooks/cards.hook.ts +14 -14
  224. package/src/modules/cards/services/cards.service.ts +32 -32
  225. package/src/modules/cards/types.ts +32 -32
  226. package/src/modules/ia-credits/actions/list-ia-credits.action.ts +8 -8
  227. package/src/modules/plans/actions/find-plan-by-id.action.ts +8 -8
  228. package/src/modules/plans/hooks/use-has-plan-addon.hook.ts +17 -17
  229. package/src/modules/plans/hooks/use-plan-by-id.hook.ts +13 -13
  230. package/src/modules/plans/services/plans.service.ts +36 -36
  231. package/src/modules/plans/types/plan.type.ts +21 -21
  232. package/src/modules/projects/actions/add-project-user.action.ts +9 -9
  233. package/src/modules/projects/actions/list-all-account-users.action.ts +9 -9
  234. package/src/modules/projects/actions/list-available-users.action.ts +9 -9
  235. package/src/modules/projects/actions/list-project-users.action.ts +9 -9
  236. package/src/modules/projects/actions/remove-project-user.action.ts +9 -9
  237. package/src/modules/projects/hooks/add-project-user.hook.ts +69 -69
  238. package/src/modules/projects/hooks/list-all-account-users.hook.ts +34 -34
  239. package/src/modules/projects/hooks/list-available-users.hook.ts +33 -33
  240. package/src/modules/projects/hooks/list-project-users.hook.ts +33 -33
  241. package/src/modules/projects/hooks/remove-project-user.hook.ts +69 -69
  242. package/src/modules/subscriptions/actions/calculate-subscription.action.ts +9 -9
  243. package/src/modules/subscriptions/actions/list-subscriptions.action.ts +9 -9
  244. package/src/modules/subscriptions/actions/update-subscription-plan.action.ts +26 -26
  245. package/src/modules/subscriptions/constants/query-keys.constants.ts +1 -1
  246. package/src/modules/subscriptions/hooks/calculate-subscription.hook.ts +13 -13
  247. package/src/modules/subscriptions/hooks/find-active-subscription.hook.ts +19 -19
  248. package/src/modules/subscriptions/hooks/list-subscriptions.hook.ts +16 -16
  249. package/src/modules/subscriptions/hooks/update-subscription-plan.hook.ts +25 -25
  250. package/src/modules/subscriptions/types/billing-period.type.ts +1 -1
  251. package/src/modules/subscriptions/types/calculate-subscription.type.ts +75 -75
  252. package/src/modules/subscriptions/utils/build-plan-extras.ts +56 -56
  253. package/src/modules/subscriptions/utils/periodicity.ts +52 -52
  254. package/src/modules/subscriptions/utils/resolve-plan-extras-prices.ts +23 -23
  255. package/src/modules/users/action/find-user-by-id.action.ts +8 -8
  256. package/src/modules/users/action/list-messages.action.ts +12 -12
  257. package/src/modules/users/action/mark-all-messages-as-read.action.ts +8 -8
  258. package/src/modules/users/action/mark-message-as-read.action.ts +8 -8
  259. package/src/modules/users/hooks/messages.hook.ts +60 -60
  260. package/src/modules/whitelabel/actions/find-whitelabel-styles.action.ts +14 -14
  261. package/src/modules/whitelabel/actions/find-whitelabel.action.ts +23 -23
  262. package/src/modules/whitelabel/actions/revalidate-whitelabel-styles.action.ts +10 -10
  263. package/src/modules/whitelabel/actions/revalidate-whitelabel.action.ts +19 -19
  264. package/src/modules/whitelabel/schema.ts +83 -81
  265. package/src/modules/whitelabel/services/whitelabel-styles.service.ts +129 -129
  266. package/src/modules/whitelabel/styles-schema.ts +37 -37
  267. package/src/providers/whitelabel.provider.tsx +54 -54
  268. package/src/store/useBuyCreditsModal.ts +25 -25
  269. package/src/utils/countries.ts +224 -224
  270. package/src/utils/safeServerAction.ts +21 -21
  271. package/src/utils/withAction.ts +13 -13
@@ -1,154 +1,154 @@
1
- 'use client';
2
-
3
- import { useState, useMemo } from 'react';
4
- import { IconCheck, IconChevronDown, IconSearch } from '@tabler/icons-react';
5
- import { Popover, PopoverContent, PopoverTrigger } from '../overlay/Popover';
6
- import { cn } from '../../../infra/utils/clsx';
7
-
8
- export type ComboboxOption = {
9
- value: string;
10
- label: string;
11
- displayValue?: string;
12
- };
13
-
14
- interface ComboboxFieldProps {
15
- options: ComboboxOption[];
16
- label?: string;
17
- placeholder?: string;
18
- searchPlaceholder?: string;
19
- emptyMessage?: string;
20
- value?: string;
21
- onChange?: (value: string) => void;
22
- disabled?: boolean;
23
- icon?: React.ReactNode;
24
- className?: string;
25
- containerClassName?: string;
26
- }
27
-
28
- export function ComboboxField({
29
- options,
30
- label,
31
- placeholder = 'Selecione uma opção',
32
- searchPlaceholder = 'Buscar...',
33
- emptyMessage = 'Nenhuma opção encontrada.',
34
- value,
35
- onChange,
36
- disabled = false,
37
- icon,
38
- className,
39
- containerClassName,
40
- }: ComboboxFieldProps) {
41
- const [open, setOpen] = useState(false);
42
- const [search, setSearch] = useState('');
43
-
44
- const selectedOption = useMemo(
45
- () => options.find((o) => o.value === value),
46
- [options, value]
47
- );
48
-
49
- const filteredOptions = useMemo(() => {
50
- const q = search.trim().toLowerCase();
51
- if (!q) return options;
52
- return options.filter((o) => o.label.toLowerCase().includes(q));
53
- }, [options, search]);
54
-
55
- const handleSelect = (optionValue: string) => {
56
- onChange?.(optionValue);
57
- setOpen(false);
58
- setSearch('');
59
- };
60
-
61
- return (
62
- <div className={cn('flex flex-col gap-1.5', containerClassName)}>
63
- {label && (
64
- <div className="flex items-center gap-1 paragraph-xsmall-semibold">
65
- <span className="text-gray-600">{label}</span>
66
- </div>
67
- )}
68
-
69
- <Popover
70
- open={open}
71
- onOpenChange={(v) => {
72
- if (!disabled) {
73
- setOpen(v);
74
- if (!v) setSearch('');
75
- }
76
- }}
77
- >
78
- <PopoverTrigger asChild>
79
- <button
80
- type="button"
81
- disabled={disabled}
82
- className={cn(
83
- 'paragraph-small-medium w-full h-10 text-gray-950 px-4 transition-colors',
84
- 'flex items-center justify-between gap-2 rounded-md border bg-transparent',
85
- 'border-gray-200 hover:border-gray-400 focus:border-gray-950 focus:outline-none',
86
- disabled && 'cursor-not-allowed opacity-50',
87
- className
88
- )}
89
- >
90
- <span className={cn('truncate text-left', !selectedOption && 'text-gray-400')}>
91
- {selectedOption
92
- ? (selectedOption.displayValue ?? selectedOption.label)
93
- : placeholder}
94
- </span>
95
- {icon ?? (
96
- <IconChevronDown
97
- className={cn(
98
- 'size-4 opacity-50 shrink-0 transition-all duration-200',
99
- open && 'rotate-180 opacity-100 text-gray-950'
100
- )}
101
- />
102
- )}
103
- </button>
104
- </PopoverTrigger>
105
-
106
- <PopoverContent
107
- className="p-0 overflow-hidden rounded-md border shadow-md"
108
- align="start"
109
- sideOffset={4}
110
- style={{ width: 'var(--radix-popover-trigger-width)' }}
111
- onWheel={(e) => e.stopPropagation()}
112
- >
113
- <div className="flex items-center gap-2 border-b border-gray-100 px-3 h-9">
114
- <IconSearch className="size-4 shrink-0 opacity-50 text-gray-500" />
115
- <input
116
- autoFocus
117
- placeholder={searchPlaceholder}
118
- value={search}
119
- onChange={(e) => setSearch(e.target.value)}
120
- className="flex h-full w-full bg-transparent text-sm outline-none placeholder:text-gray-400 paragraph-small-medium text-gray-950"
121
- />
122
- </div>
123
-
124
- <div className="overflow-y-auto max-h-[280px] p-1">
125
- {filteredOptions.length === 0 ? (
126
- <p className="py-6 text-center paragraph-small-medium text-gray-500">{emptyMessage}</p>
127
- ) : (
128
- filteredOptions.map((option) => {
129
- const isSelected = value === option.value;
130
- return (
131
- <div
132
- key={option.value}
133
- className={cn(
134
- 'flex items-center gap-2 rounded-sm px-2 h-9 cursor-pointer select-none',
135
- 'paragraph-small-medium text-gray-950',
136
- 'hover:bg-gray-100',
137
- isSelected && 'bg-gray-50'
138
- )}
139
- onClick={() => handleSelect(option.value)}
140
- >
141
- <span className="flex-1 truncate">{option.label}</span>
142
- {isSelected && <IconCheck className="size-4 shrink-0 text-pages-600" />}
143
- </div>
144
- );
145
- })
146
- )}
147
- </div>
148
- </PopoverContent>
149
- </Popover>
150
- </div>
151
- );
152
- }
153
-
154
- export default ComboboxField;
1
+ 'use client';
2
+
3
+ import { useState, useMemo } from 'react';
4
+ import { IconCheck, IconChevronDown, IconSearch } from '@tabler/icons-react';
5
+ import { Popover, PopoverContent, PopoverTrigger } from '../overlay/Popover';
6
+ import { cn } from '../../../infra/utils/clsx';
7
+
8
+ export type ComboboxOption = {
9
+ value: string;
10
+ label: string;
11
+ displayValue?: string;
12
+ };
13
+
14
+ interface ComboboxFieldProps {
15
+ options: ComboboxOption[];
16
+ label?: string;
17
+ placeholder?: string;
18
+ searchPlaceholder?: string;
19
+ emptyMessage?: string;
20
+ value?: string;
21
+ onChange?: (value: string) => void;
22
+ disabled?: boolean;
23
+ icon?: React.ReactNode;
24
+ className?: string;
25
+ containerClassName?: string;
26
+ }
27
+
28
+ export function ComboboxField({
29
+ options,
30
+ label,
31
+ placeholder = 'Selecione uma opção',
32
+ searchPlaceholder = 'Buscar...',
33
+ emptyMessage = 'Nenhuma opção encontrada.',
34
+ value,
35
+ onChange,
36
+ disabled = false,
37
+ icon,
38
+ className,
39
+ containerClassName,
40
+ }: ComboboxFieldProps) {
41
+ const [open, setOpen] = useState(false);
42
+ const [search, setSearch] = useState('');
43
+
44
+ const selectedOption = useMemo(
45
+ () => options.find((o) => o.value === value),
46
+ [options, value]
47
+ );
48
+
49
+ const filteredOptions = useMemo(() => {
50
+ const q = search.trim().toLowerCase();
51
+ if (!q) return options;
52
+ return options.filter((o) => o.label.toLowerCase().includes(q));
53
+ }, [options, search]);
54
+
55
+ const handleSelect = (optionValue: string) => {
56
+ onChange?.(optionValue);
57
+ setOpen(false);
58
+ setSearch('');
59
+ };
60
+
61
+ return (
62
+ <div className={cn('flex flex-col gap-1.5', containerClassName)}>
63
+ {label && (
64
+ <div className="flex items-center gap-1 paragraph-xsmall-semibold">
65
+ <span className="text-gray-600">{label}</span>
66
+ </div>
67
+ )}
68
+
69
+ <Popover
70
+ open={open}
71
+ onOpenChange={(v) => {
72
+ if (!disabled) {
73
+ setOpen(v);
74
+ if (!v) setSearch('');
75
+ }
76
+ }}
77
+ >
78
+ <PopoverTrigger asChild>
79
+ <button
80
+ type="button"
81
+ disabled={disabled}
82
+ className={cn(
83
+ 'paragraph-small-medium w-full h-10 text-gray-950 px-4 transition-colors',
84
+ 'flex items-center justify-between gap-2 rounded-md border bg-transparent',
85
+ 'border-gray-200 hover:border-gray-400 focus:border-gray-950 focus:outline-none',
86
+ disabled && 'cursor-not-allowed opacity-50',
87
+ className
88
+ )}
89
+ >
90
+ <span className={cn('truncate text-left', !selectedOption && 'text-gray-400')}>
91
+ {selectedOption
92
+ ? (selectedOption.displayValue ?? selectedOption.label)
93
+ : placeholder}
94
+ </span>
95
+ {icon ?? (
96
+ <IconChevronDown
97
+ className={cn(
98
+ 'size-4 opacity-50 shrink-0 transition-all duration-200',
99
+ open && 'rotate-180 opacity-100 text-gray-950'
100
+ )}
101
+ />
102
+ )}
103
+ </button>
104
+ </PopoverTrigger>
105
+
106
+ <PopoverContent
107
+ className="p-0 overflow-hidden rounded-md border shadow-md"
108
+ align="start"
109
+ sideOffset={4}
110
+ style={{ width: 'var(--radix-popover-trigger-width)' }}
111
+ onWheel={(e) => e.stopPropagation()}
112
+ >
113
+ <div className="flex items-center gap-2 border-b border-gray-100 px-3 h-9">
114
+ <IconSearch className="size-4 shrink-0 opacity-50 text-gray-500" />
115
+ <input
116
+ autoFocus
117
+ placeholder={searchPlaceholder}
118
+ value={search}
119
+ onChange={(e) => setSearch(e.target.value)}
120
+ className="flex h-full w-full bg-transparent text-sm outline-none placeholder:text-gray-400 paragraph-small-medium text-gray-950"
121
+ />
122
+ </div>
123
+
124
+ <div className="overflow-y-auto max-h-[280px] p-1">
125
+ {filteredOptions.length === 0 ? (
126
+ <p className="py-6 text-center paragraph-small-medium text-gray-500">{emptyMessage}</p>
127
+ ) : (
128
+ filteredOptions.map((option) => {
129
+ const isSelected = value === option.value;
130
+ return (
131
+ <div
132
+ key={option.value}
133
+ className={cn(
134
+ 'flex items-center gap-2 rounded-sm px-2 h-9 cursor-pointer select-none',
135
+ 'paragraph-small-medium text-gray-950',
136
+ 'hover:bg-gray-100',
137
+ isSelected && 'bg-gray-50'
138
+ )}
139
+ onClick={() => handleSelect(option.value)}
140
+ >
141
+ <span className="flex-1 truncate">{option.label}</span>
142
+ {isSelected && <IconCheck className="size-4 shrink-0 text-pages-600" />}
143
+ </div>
144
+ );
145
+ })
146
+ )}
147
+ </div>
148
+ </PopoverContent>
149
+ </Popover>
150
+ </div>
151
+ );
152
+ }
153
+
154
+ export default ComboboxField;
@@ -1,97 +1,97 @@
1
- "use client";
2
-
3
- import { useState, forwardRef, useEffect } from "react";
4
- import { format } from "date-fns";
5
- import { Calendar } from "./Calendar";
6
- import { Popover, PopoverContent, PopoverTrigger } from "../overlay/Popover";
7
- import { cn } from "../../../infra/utils/clsx";
8
-
9
- // Converte string ISO (yyyy-MM-dd) para Date no fuso horário local
10
- // Evita bug de timezone onde new Date("2025-08-02") interpreta como UTC
11
- const isoParaDataLocal = (iso: string): Date => {
12
- const [ano, mes, dia] = iso.split("-").map(Number);
13
- return new Date(ano, mes - 1, dia);
14
- };
15
-
16
- interface DatePickerProps {
17
- value?: string;
18
- onChange?: (date: string | undefined) => void;
19
- placeholder?: string;
20
- className?: string;
21
- disabled?: boolean;
22
- }
23
-
24
- export const DatePicker = forwardRef<HTMLButtonElement, DatePickerProps>(
25
- (
26
- { value, onChange, placeholder = "Selecione a data", className, disabled },
27
- ref,
28
- ) => {
29
- const [open, setOpen] = useState(false);
30
- const [date, setDate] = useState<Date | undefined>(() => {
31
- return value ? isoParaDataLocal(value) : undefined;
32
- });
33
-
34
- // Sincroniza estado interno quando value mudar externamente
35
- useEffect(() => {
36
- if (value) {
37
- setDate(isoParaDataLocal(value));
38
- } else {
39
- setDate(undefined);
40
- }
41
- }, [value]);
42
-
43
- const handleDateSelect = (selectedDate: Date | undefined) => {
44
- setDate(selectedDate);
45
-
46
- if (selectedDate) {
47
- onChange?.(format(selectedDate, "yyyy-MM-dd"));
48
- setOpen(false); // Fecha o popover após seleção
49
- } else {
50
- onChange?.(undefined);
51
- }
52
- };
53
-
54
- const displayText = date ? format(date, "dd/MM/yyyy") : placeholder;
55
-
56
- return (
57
- <Popover open={open} onOpenChange={setOpen}>
58
- <PopoverTrigger asChild>
59
- <button
60
- ref={ref}
61
- disabled={disabled}
62
- className={cn(
63
- "flex items-center gap-2 px-4 h-10 border rounded-lg transition-colors w-full justify-start",
64
- "border-gray-200 hover:border-gray-400 focus-within:border-gray-950",
65
- "disabled:opacity-50 disabled:cursor-not-allowed",
66
- className,
67
- )}
68
- >
69
- <span
70
- className={cn(
71
- "paragraph-small-medium",
72
- date ? "text-gray-950" : "text-gray-500",
73
- )}
74
- >
75
- {displayText}
76
- </span>
77
- </button>
78
- </PopoverTrigger>
79
- <PopoverContent
80
- className="w-auto p-0 bg-white rounded-2xl shadow-md border border-gray-200"
81
- align="start"
82
- sideOffset={8}
83
- >
84
- <div className="p-3">
85
- <Calendar
86
- mode="single"
87
- selected={date}
88
- onSelect={handleDateSelect}
89
- />
90
- </div>
91
- </PopoverContent>
92
- </Popover>
93
- );
94
- },
95
- );
96
-
97
- DatePicker.displayName = "DatePicker";
1
+ "use client";
2
+
3
+ import { useState, forwardRef, useEffect } from "react";
4
+ import { format } from "date-fns";
5
+ import { Calendar } from "./Calendar";
6
+ import { Popover, PopoverContent, PopoverTrigger } from "../overlay/Popover";
7
+ import { cn } from "../../../infra/utils/clsx";
8
+
9
+ // Converte string ISO (yyyy-MM-dd) para Date no fuso horário local
10
+ // Evita bug de timezone onde new Date("2025-08-02") interpreta como UTC
11
+ const isoParaDataLocal = (iso: string): Date => {
12
+ const [ano, mes, dia] = iso.split("-").map(Number);
13
+ return new Date(ano, mes - 1, dia);
14
+ };
15
+
16
+ interface DatePickerProps {
17
+ value?: string;
18
+ onChange?: (date: string | undefined) => void;
19
+ placeholder?: string;
20
+ className?: string;
21
+ disabled?: boolean;
22
+ }
23
+
24
+ export const DatePicker = forwardRef<HTMLButtonElement, DatePickerProps>(
25
+ (
26
+ { value, onChange, placeholder = "Selecione a data", className, disabled },
27
+ ref,
28
+ ) => {
29
+ const [open, setOpen] = useState(false);
30
+ const [date, setDate] = useState<Date | undefined>(() => {
31
+ return value ? isoParaDataLocal(value) : undefined;
32
+ });
33
+
34
+ // Sincroniza estado interno quando value mudar externamente
35
+ useEffect(() => {
36
+ if (value) {
37
+ setDate(isoParaDataLocal(value));
38
+ } else {
39
+ setDate(undefined);
40
+ }
41
+ }, [value]);
42
+
43
+ const handleDateSelect = (selectedDate: Date | undefined) => {
44
+ setDate(selectedDate);
45
+
46
+ if (selectedDate) {
47
+ onChange?.(format(selectedDate, "yyyy-MM-dd"));
48
+ setOpen(false); // Fecha o popover após seleção
49
+ } else {
50
+ onChange?.(undefined);
51
+ }
52
+ };
53
+
54
+ const displayText = date ? format(date, "dd/MM/yyyy") : placeholder;
55
+
56
+ return (
57
+ <Popover open={open} onOpenChange={setOpen}>
58
+ <PopoverTrigger asChild>
59
+ <button
60
+ ref={ref}
61
+ disabled={disabled}
62
+ className={cn(
63
+ "flex items-center gap-2 px-4 h-10 border rounded-lg transition-colors w-full justify-start",
64
+ "border-gray-200 hover:border-gray-400 focus-within:border-gray-950",
65
+ "disabled:opacity-50 disabled:cursor-not-allowed",
66
+ className,
67
+ )}
68
+ >
69
+ <span
70
+ className={cn(
71
+ "paragraph-small-medium",
72
+ date ? "text-gray-950" : "text-gray-500",
73
+ )}
74
+ >
75
+ {displayText}
76
+ </span>
77
+ </button>
78
+ </PopoverTrigger>
79
+ <PopoverContent
80
+ className="w-auto p-0 bg-white rounded-2xl shadow-md border border-gray-200"
81
+ align="start"
82
+ sideOffset={8}
83
+ >
84
+ <div className="p-3">
85
+ <Calendar
86
+ mode="single"
87
+ selected={date}
88
+ onSelect={handleDateSelect}
89
+ />
90
+ </div>
91
+ </PopoverContent>
92
+ </Popover>
93
+ );
94
+ },
95
+ );
96
+
97
+ DatePicker.displayName = "DatePicker";