@greatapps/common 1.1.234 → 1.1.237

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 (227) hide show
  1. package/dist/components/account/ConfigurationsMyAccountModal.mjs +1 -1
  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 +3 -3
  23. package/dist/components/layouts/NavBar.mjs.map +1 -1
  24. package/dist/components/layouts/NotificationsPopover.mjs.map +1 -1
  25. package/dist/components/layouts/ProfilePopover.mjs.map +1 -1
  26. package/dist/components/layouts/UsersSelectorPopover.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/Pagination.mjs.map +1 -1
  40. package/dist/components/ui/data-display/ScrollArea.mjs.map +1 -1
  41. package/dist/components/ui/data-display/Separator.mjs.map +1 -1
  42. package/dist/components/ui/data-display/Table.mjs.map +1 -1
  43. package/dist/components/ui/data-display/Tabs.mjs.map +1 -1
  44. package/dist/components/ui/feedback/CircularProgress.mjs.map +1 -1
  45. package/dist/components/ui/feedback/DefaultCircularProgress.mjs.map +1 -1
  46. package/dist/components/ui/feedback/LoadingOverlay.mjs.map +1 -1
  47. package/dist/components/ui/feedback/Progress.mjs.map +1 -1
  48. package/dist/components/ui/feedback/Toast.mjs.map +1 -1
  49. package/dist/components/ui/form/Calendar.mjs.map +1 -1
  50. package/dist/components/ui/form/Checkbox.mjs.map +1 -1
  51. package/dist/components/ui/form/ComboboxField.mjs.map +1 -1
  52. package/dist/components/ui/form/DatePicker.mjs.map +1 -1
  53. package/dist/components/ui/form/DateRangePicker.mjs.map +1 -1
  54. package/dist/components/ui/form/FormField.mjs.map +1 -1
  55. package/dist/components/ui/form/Input.mjs.map +1 -1
  56. package/dist/components/ui/form/InputOtp.mjs.map +1 -1
  57. package/dist/components/ui/form/PhoneInput.mjs.map +1 -1
  58. package/dist/components/ui/form/RadioGroup.mjs.map +1 -1
  59. package/dist/components/ui/form/Select.mjs +1 -1
  60. package/dist/components/ui/form/Select.mjs.map +1 -1
  61. package/dist/components/ui/form/Switch.mjs.map +1 -1
  62. package/dist/components/ui/form/Textarea.mjs.map +1 -1
  63. package/dist/components/ui/overlay/Command.mjs.map +1 -1
  64. package/dist/components/ui/overlay/Dialog.mjs.map +1 -1
  65. package/dist/components/ui/overlay/Popover.mjs.map +1 -1
  66. package/dist/components/ui/overlay/Sheet.mjs.map +1 -1
  67. package/dist/components/ui/overlay/Tooltip.mjs.map +1 -1
  68. package/dist/hooks/copy-to-clipboard.hook.mjs.map +1 -1
  69. package/dist/index.mjs.map +1 -1
  70. package/dist/middleware.mjs.map +1 -1
  71. package/dist/modules/accounts/actions/account-management.action.mjs +1 -0
  72. package/dist/modules/accounts/actions/account-management.action.mjs.map +1 -1
  73. package/dist/modules/accounts/actions/find-current-account.action.mjs.map +1 -1
  74. package/dist/modules/accounts/actions/list-currencies.action.mjs.map +1 -1
  75. package/dist/modules/accounts/actions/list-timezones.action.mjs.map +1 -1
  76. package/dist/modules/accounts/hooks/current-account.hook.mjs.map +1 -1
  77. package/dist/modules/accounts/hooks/useAccountManagement.mjs.map +1 -1
  78. package/dist/modules/accounts/hooks/useCurrencies.mjs.map +1 -1
  79. package/dist/modules/accounts/hooks/useTimezones.mjs.map +1 -1
  80. package/dist/modules/accounts/services/account.service.mjs.map +1 -1
  81. package/dist/modules/auth/hooks/login.hook.mjs.map +1 -1
  82. package/dist/modules/auth/hooks/logout.hook.mjs.map +1 -1
  83. package/dist/modules/auth/hooks/register.hook.mjs.map +1 -1
  84. package/dist/modules/ia-credits/actions/list-ia-credits.action.mjs.map +1 -1
  85. package/dist/modules/projects/actions/add-project-user.action.mjs.map +1 -1
  86. package/dist/modules/projects/actions/list-all-account-users.action.mjs.map +1 -1
  87. package/dist/modules/projects/actions/list-available-users.action.mjs.map +1 -1
  88. package/dist/modules/projects/actions/list-project-users.action.mjs.map +1 -1
  89. package/dist/modules/projects/actions/remove-project-user.action.mjs.map +1 -1
  90. package/dist/modules/projects/hooks/add-project-user.hook.mjs.map +1 -1
  91. package/dist/modules/projects/hooks/list-all-account-users.hook.mjs.map +1 -1
  92. package/dist/modules/projects/hooks/list-available-users.hook.mjs.map +1 -1
  93. package/dist/modules/projects/hooks/list-project-users.hook.mjs.map +1 -1
  94. package/dist/modules/projects/hooks/remove-project-user.hook.mjs.map +1 -1
  95. package/dist/modules/subscriptions/actions/find-plan-by-id.action.mjs.map +1 -1
  96. package/dist/modules/subscriptions/actions/list-subscriptions.action.mjs.map +1 -1
  97. package/dist/modules/subscriptions/hooks/find-active-subscription.hook.mjs.map +1 -1
  98. package/dist/modules/subscriptions/hooks/list-subscriptions.hook.mjs.map +1 -1
  99. package/dist/modules/subscriptions/hooks/use-has-plan-addon.hook.mjs.map +1 -1
  100. package/dist/modules/subscriptions/hooks/use-plan-by-id.hook.mjs.map +1 -1
  101. package/dist/modules/subscriptions/services/plans.service.mjs.map +1 -1
  102. package/dist/modules/subscriptions/types/plan.type.mjs.map +1 -1
  103. package/dist/modules/users/action/find-user-by-id.action.mjs.map +1 -1
  104. package/dist/modules/users/action/list-messages.action.mjs.map +1 -1
  105. package/dist/modules/users/action/mark-all-messages-as-read.action.mjs.map +1 -1
  106. package/dist/modules/users/action/mark-message-as-read.action.mjs.map +1 -1
  107. package/dist/modules/users/hooks/messages.hook.mjs.map +1 -1
  108. package/dist/modules/whitelabel/actions/find-whitelabel-styles.action.mjs.map +1 -1
  109. package/dist/modules/whitelabel/actions/find-whitelabel.action.mjs.map +1 -1
  110. package/dist/modules/whitelabel/services/whitelabel-styles.service.mjs.map +1 -1
  111. package/dist/providers/whitelabel.provider.mjs.map +1 -1
  112. package/dist/utils/countries.mjs.map +1 -1
  113. package/dist/utils/safeServerAction.mjs.map +1 -1
  114. package/dist/utils/withAction.mjs.map +1 -1
  115. package/package.json +89 -89
  116. package/src/components/account/ConfigurationsMyAccountModal.tsx +150 -150
  117. package/src/components/account/ConfirmDeleteAccountModal.tsx +55 -55
  118. package/src/components/account/ConfirmGlobalPreferencesModal.tsx +66 -66
  119. package/src/components/account/DeleteAccountModal.tsx +130 -130
  120. package/src/components/account/DisableTwoFactorAuthModal.tsx +86 -86
  121. package/src/components/account/IsntPossibleDeleteAccountModal.tsx +49 -49
  122. package/src/components/account/TwoFactorAuthModal.tsx +223 -223
  123. package/src/components/account/hooks/useChangePhoneForm.tsx +81 -81
  124. package/src/components/account/hooks/useTwoFactorAuthForm.tsx +101 -101
  125. package/src/components/account/sections/ChangeEmailModal.tsx +225 -225
  126. package/src/components/account/sections/ChangePasswordSection.tsx +64 -64
  127. package/src/components/account/sections/ChangePhoneModal.tsx +231 -231
  128. package/src/components/account/sections/MyProfileSection.tsx +327 -327
  129. package/src/components/account/sections/PreferencesSection.tsx +273 -273
  130. package/src/components/account/sections/SecuritySection.tsx +160 -160
  131. package/src/components/embeds/CrispEmbed.tsx +101 -101
  132. package/src/components/embeds/FrillEmbed.tsx +119 -119
  133. package/src/components/layouts/AppMobileNavBar.tsx +110 -110
  134. package/src/components/layouts/AppNavBar.tsx +57 -57
  135. package/src/components/layouts/MdSideBarNavigation.tsx +56 -56
  136. package/src/components/layouts/NavBar.tsx +120 -120
  137. package/src/components/layouts/NotificationsPopover.tsx +115 -115
  138. package/src/components/layouts/ProfilePopover.tsx +167 -167
  139. package/src/components/layouts/UsersSelectorPopover.tsx +238 -238
  140. package/src/components/navigation/CancelledSubscriptionBanner.tsx +69 -69
  141. package/src/components/navigation/NavItemsContext.ts +20 -20
  142. package/src/components/navigation/ProjectSelectorPopover.tsx +157 -157
  143. package/src/components/navigation/shells/TabsMobileShell.tsx +72 -72
  144. package/src/components/navigation/subcomponents/ProjectSelector.tsx +154 -154
  145. package/src/components/pages/notifications/Notifications.tsx +160 -160
  146. package/src/components/ui/buttons/Button.tsx +57 -57
  147. package/src/components/ui/buttons/CancelButton.tsx +14 -14
  148. package/src/components/ui/buttons/CopyButton.tsx +54 -54
  149. package/src/components/ui/data-display/Accordion.tsx +81 -81
  150. package/src/components/ui/data-display/Badge.tsx +47 -47
  151. package/src/components/ui/data-display/Card.tsx +93 -93
  152. package/src/components/ui/data-display/Pagination.tsx +126 -126
  153. package/src/components/ui/data-display/ScrollArea.tsx +59 -59
  154. package/src/components/ui/data-display/Separator.tsx +29 -29
  155. package/src/components/ui/data-display/Table.tsx +117 -117
  156. package/src/components/ui/data-display/Tabs.tsx +67 -67
  157. package/src/components/ui/feedback/CircularProgress.tsx +75 -75
  158. package/src/components/ui/feedback/DefaultCircularProgress.tsx +61 -61
  159. package/src/components/ui/feedback/LoadingOverlay.tsx +31 -31
  160. package/src/components/ui/feedback/Progress.tsx +40 -40
  161. package/src/components/ui/feedback/Toast.tsx +101 -101
  162. package/src/components/ui/form/Calendar.tsx +228 -228
  163. package/src/components/ui/form/Checkbox.tsx +31 -31
  164. package/src/components/ui/form/ComboboxField.tsx +154 -154
  165. package/src/components/ui/form/DatePicker.tsx +97 -97
  166. package/src/components/ui/form/DateRangePicker.tsx +108 -108
  167. package/src/components/ui/form/FormField.tsx +131 -131
  168. package/src/components/ui/form/Input.tsx +20 -20
  169. package/src/components/ui/form/InputOtp.tsx +80 -80
  170. package/src/components/ui/form/PhoneInput.tsx +205 -205
  171. package/src/components/ui/form/RadioGroup.tsx +45 -45
  172. package/src/components/ui/form/Select.tsx +200 -200
  173. package/src/components/ui/form/Switch.tsx +32 -32
  174. package/src/components/ui/form/Textarea.tsx +19 -19
  175. package/src/components/ui/overlay/Command.tsx +185 -185
  176. package/src/components/ui/overlay/Dialog.tsx +151 -151
  177. package/src/components/ui/overlay/Popover.tsx +49 -49
  178. package/src/components/ui/overlay/Sheet.tsx +166 -166
  179. package/src/components/ui/overlay/Tooltip.tsx +62 -62
  180. package/src/hooks/copy-to-clipboard.hook.tsx +67 -67
  181. package/src/index.ts +359 -359
  182. package/src/middleware.ts +4 -4
  183. package/src/modules/accounts/actions/account-management.action.ts +91 -90
  184. package/src/modules/accounts/actions/find-current-account.action.ts +9 -9
  185. package/src/modules/accounts/actions/list-currencies.action.ts +8 -8
  186. package/src/modules/accounts/actions/list-timezones.action.ts +8 -8
  187. package/src/modules/accounts/hooks/current-account.hook.tsx +22 -22
  188. package/src/modules/accounts/hooks/useAccountManagement.ts +85 -85
  189. package/src/modules/accounts/hooks/useCurrencies.ts +15 -15
  190. package/src/modules/accounts/hooks/useTimezones.ts +15 -15
  191. package/src/modules/accounts/services/account.service.ts +236 -236
  192. package/src/modules/accounts/types.ts +214 -214
  193. package/src/modules/auth/hooks/login.hook.tsx +13 -13
  194. package/src/modules/auth/hooks/logout.hook.tsx +11 -11
  195. package/src/modules/auth/hooks/register.hook.tsx +11 -11
  196. package/src/modules/ia-credits/actions/list-ia-credits.action.ts +8 -8
  197. package/src/modules/projects/actions/add-project-user.action.ts +9 -9
  198. package/src/modules/projects/actions/list-all-account-users.action.ts +9 -9
  199. package/src/modules/projects/actions/list-available-users.action.ts +9 -9
  200. package/src/modules/projects/actions/list-project-users.action.ts +9 -9
  201. package/src/modules/projects/actions/remove-project-user.action.ts +9 -9
  202. package/src/modules/projects/hooks/add-project-user.hook.ts +69 -69
  203. package/src/modules/projects/hooks/list-all-account-users.hook.ts +34 -34
  204. package/src/modules/projects/hooks/list-available-users.hook.ts +33 -33
  205. package/src/modules/projects/hooks/list-project-users.hook.ts +33 -33
  206. package/src/modules/projects/hooks/remove-project-user.hook.ts +69 -69
  207. package/src/modules/subscriptions/actions/find-plan-by-id.action.ts +8 -8
  208. package/src/modules/subscriptions/actions/list-subscriptions.action.ts +9 -9
  209. package/src/modules/subscriptions/hooks/find-active-subscription.hook.ts +19 -19
  210. package/src/modules/subscriptions/hooks/list-subscriptions.hook.ts +17 -17
  211. package/src/modules/subscriptions/hooks/use-has-plan-addon.hook.ts +17 -17
  212. package/src/modules/subscriptions/hooks/use-plan-by-id.hook.ts +13 -13
  213. package/src/modules/subscriptions/services/plans.service.ts +36 -36
  214. package/src/modules/subscriptions/types/plan.type.ts +21 -21
  215. package/src/modules/users/action/find-user-by-id.action.ts +8 -8
  216. package/src/modules/users/action/list-messages.action.ts +12 -12
  217. package/src/modules/users/action/mark-all-messages-as-read.action.ts +8 -8
  218. package/src/modules/users/action/mark-message-as-read.action.ts +8 -8
  219. package/src/modules/users/hooks/messages.hook.ts +60 -60
  220. package/src/modules/whitelabel/actions/find-whitelabel-styles.action.ts +14 -14
  221. package/src/modules/whitelabel/actions/find-whitelabel.action.ts +23 -23
  222. package/src/modules/whitelabel/services/whitelabel-styles.service.ts +98 -98
  223. package/src/modules/whitelabel/styles-schema.ts +37 -37
  224. package/src/providers/whitelabel.provider.tsx +46 -46
  225. package/src/utils/countries.ts +224 -224
  226. package/src/utils/safeServerAction.ts +21 -21
  227. package/src/utils/withAction.ts +13 -13
@@ -1,157 +1,157 @@
1
- 'use client';
2
-
3
- import { Dispatch, RefObject, SetStateAction } from 'react';
4
- import { ADDON_IDS } from '../../modules/subscriptions/constants/addons.constants';
5
- import { useHasPlanAddon } from '../../modules/subscriptions/hooks/use-has-plan-addon.hook';
6
- import {
7
- Button,
8
- Command,
9
- CommandEmpty,
10
- CommandInput,
11
- CommandItem,
12
- CommandList,
13
- Popover,
14
- PopoverContent,
15
- PopoverTrigger,
16
- Tooltip,
17
- TooltipContent,
18
- TooltipTrigger,
19
- UserAvatar,
20
- } from '../../index';
21
- import { IconCheck, IconChevronDown, IconFolderOpen, IconPlus, IconSettings } from '@tabler/icons-react';
22
- import type { NavigationProject } from './types';
23
-
24
- interface ProjectSelectorPopoverProps {
25
- open: boolean;
26
- setOpen: Dispatch<SetStateAction<boolean>>;
27
- titleRef?: RefObject<HTMLSpanElement | null>;
28
- projects: NavigationProject[];
29
- selectedProject: NavigationProject | null;
30
- onSelectProject: (project: NavigationProject) => void;
31
- onAddProject: () => void;
32
- onManageProjects: () => void;
33
- children?: React.ReactNode;
34
- }
35
-
36
- function ProjectItemSkeleton() {
37
- return (
38
- <div className="flex items-center justify-between px-2 py-1.5 gap-2">
39
- <div className="flex items-center gap-2 flex-1">
40
- <div className="skeleton size-8 rounded-lg shrink-0" />
41
- <div className="skeleton h-3.5 w-32 rounded" />
42
- </div>
43
- <div className="skeleton size-4 rounded-full shrink-0" />
44
- </div>
45
- );
46
- }
47
-
48
- export function ProjectSelectorPopover({
49
- open,
50
- setOpen,
51
- titleRef,
52
- projects,
53
- selectedProject,
54
- onSelectProject,
55
- onAddProject,
56
- onManageProjects,
57
- children,
58
- }: ProjectSelectorPopoverProps) {
59
- const { hasAddon: canAddProject } = useHasPlanAddon(ADDON_IDS.PROJECTS);
60
-
61
- return (
62
- <Popover open={open} onOpenChange={setOpen}>
63
- <PopoverTrigger asChild>
64
- {children ?? (
65
- <button className="cursor-pointer">
66
- <IconChevronDown
67
- size={20}
68
- className={`transition-transform duration-200 ${open ? 'rotate-180 text-gray-950' : 'text-gray-400'}`}
69
- />
70
- </button>
71
- )}
72
- </PopoverTrigger>
73
- <PopoverContent
74
- className="w-[296px] p-0 bg-white rounded-2xl shadow-md border border-gray-200"
75
- align="start"
76
- sideOffset={8}
77
- onOpenAutoFocus={(e: Event) => e.preventDefault()}
78
- onInteractOutside={(event: Event) => {
79
- if (titleRef?.current?.contains(event.target as Node)) {
80
- event.preventDefault();
81
- }
82
- }}
83
- >
84
- <div className="flex flex-col p-3 gap-2">
85
- <div className="flex items-center justify-between">
86
- <span className="paragraph-small-semibold">Projetos</span>
87
- <div className="flex items-center gap-1.5">
88
- {canAddProject && (
89
- <Button
90
- variant="secondary"
91
- className="h-8! paragraph-small-semibold text-gray-950"
92
- onClick={onAddProject}
93
- >
94
- <IconPlus size={16} />
95
- Adicionar
96
- </Button>
97
- )}
98
- <Tooltip>
99
- <TooltipTrigger asChild>
100
- <Button variant="secondary" className="p-0 size-8" onClick={onManageProjects}>
101
- <IconSettings size={18} />
102
- </Button>
103
- </TooltipTrigger>
104
- <TooltipContent className="z-[1002]">Visualizar todos projetos</TooltipContent>
105
- </Tooltip>
106
- </div>
107
- </div>
108
- <Command className="gap-2">
109
- <CommandInput placeholder="Busque aqui" />
110
- <CommandList className="custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]">
111
- {projects.length === 0 ? (
112
- <div className="flex flex-col items-center justify-center gap-2 h-full text-gray-400 py-4">
113
- <IconFolderOpen size={28} className="text-gray-300" />
114
- <span className="paragraph-small-medium text-center text-gray-500">
115
- Nenhum projeto encontrado.
116
- <br />
117
- Crie um projeto para começar.
118
- </span>
119
- </div>
120
- ) : (
121
- <>
122
- <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
123
- {projects.map((project) => {
124
- const isSelected = selectedProject?.id === project.id;
125
- return (
126
- <CommandItem
127
- key={project.id}
128
- value={`${project.title}-${project.id}`}
129
- keywords={[project.title]}
130
- className={isSelected ? 'bg-gray-50' : ''}
131
- onSelect={() => onSelectProject(project)}
132
- >
133
- <div className="flex items-center justify-between w-full cursor-pointer">
134
- <div className="flex items-center gap-2 w-full">
135
- <UserAvatar
136
- photo={project.photo}
137
- name={project.title}
138
- size={32}
139
- />
140
- {project.title}
141
- </div>
142
- {isSelected && (
143
- <IconCheck className="size-4 text-gray-950" />
144
- )}
145
- </div>
146
- </CommandItem>
147
- );
148
- })}
149
- </>
150
- )}
151
- </CommandList>
152
- </Command>
153
- </div>
154
- </PopoverContent>
155
- </Popover>
156
- );
157
- }
1
+ 'use client';
2
+
3
+ import { Dispatch, RefObject, SetStateAction } from 'react';
4
+ import { ADDON_IDS } from '../../modules/subscriptions/constants/addons.constants';
5
+ import { useHasPlanAddon } from '../../modules/subscriptions/hooks/use-has-plan-addon.hook';
6
+ import {
7
+ Button,
8
+ Command,
9
+ CommandEmpty,
10
+ CommandInput,
11
+ CommandItem,
12
+ CommandList,
13
+ Popover,
14
+ PopoverContent,
15
+ PopoverTrigger,
16
+ Tooltip,
17
+ TooltipContent,
18
+ TooltipTrigger,
19
+ UserAvatar,
20
+ } from '../../index';
21
+ import { IconCheck, IconChevronDown, IconFolderOpen, IconPlus, IconSettings } from '@tabler/icons-react';
22
+ import type { NavigationProject } from './types';
23
+
24
+ interface ProjectSelectorPopoverProps {
25
+ open: boolean;
26
+ setOpen: Dispatch<SetStateAction<boolean>>;
27
+ titleRef?: RefObject<HTMLSpanElement | null>;
28
+ projects: NavigationProject[];
29
+ selectedProject: NavigationProject | null;
30
+ onSelectProject: (project: NavigationProject) => void;
31
+ onAddProject: () => void;
32
+ onManageProjects: () => void;
33
+ children?: React.ReactNode;
34
+ }
35
+
36
+ function ProjectItemSkeleton() {
37
+ return (
38
+ <div className="flex items-center justify-between px-2 py-1.5 gap-2">
39
+ <div className="flex items-center gap-2 flex-1">
40
+ <div className="skeleton size-8 rounded-lg shrink-0" />
41
+ <div className="skeleton h-3.5 w-32 rounded" />
42
+ </div>
43
+ <div className="skeleton size-4 rounded-full shrink-0" />
44
+ </div>
45
+ );
46
+ }
47
+
48
+ export function ProjectSelectorPopover({
49
+ open,
50
+ setOpen,
51
+ titleRef,
52
+ projects,
53
+ selectedProject,
54
+ onSelectProject,
55
+ onAddProject,
56
+ onManageProjects,
57
+ children,
58
+ }: ProjectSelectorPopoverProps) {
59
+ const { hasAddon: canAddProject } = useHasPlanAddon(ADDON_IDS.PROJECTS);
60
+
61
+ return (
62
+ <Popover open={open} onOpenChange={setOpen}>
63
+ <PopoverTrigger asChild>
64
+ {children ?? (
65
+ <button className="cursor-pointer">
66
+ <IconChevronDown
67
+ size={20}
68
+ className={`transition-transform duration-200 ${open ? 'rotate-180 text-gray-950' : 'text-gray-400'}`}
69
+ />
70
+ </button>
71
+ )}
72
+ </PopoverTrigger>
73
+ <PopoverContent
74
+ className="w-[296px] p-0 bg-white rounded-2xl shadow-md border border-gray-200"
75
+ align="start"
76
+ sideOffset={8}
77
+ onOpenAutoFocus={(e: Event) => e.preventDefault()}
78
+ onInteractOutside={(event: Event) => {
79
+ if (titleRef?.current?.contains(event.target as Node)) {
80
+ event.preventDefault();
81
+ }
82
+ }}
83
+ >
84
+ <div className="flex flex-col p-3 gap-2">
85
+ <div className="flex items-center justify-between">
86
+ <span className="paragraph-small-semibold">Projetos</span>
87
+ <div className="flex items-center gap-1.5">
88
+ {canAddProject && (
89
+ <Button
90
+ variant="secondary"
91
+ className="h-8! paragraph-small-semibold text-gray-950"
92
+ onClick={onAddProject}
93
+ >
94
+ <IconPlus size={16} />
95
+ Adicionar
96
+ </Button>
97
+ )}
98
+ <Tooltip>
99
+ <TooltipTrigger asChild>
100
+ <Button variant="secondary" className="p-0 size-8" onClick={onManageProjects}>
101
+ <IconSettings size={18} />
102
+ </Button>
103
+ </TooltipTrigger>
104
+ <TooltipContent className="z-[1002]">Visualizar todos projetos</TooltipContent>
105
+ </Tooltip>
106
+ </div>
107
+ </div>
108
+ <Command className="gap-2">
109
+ <CommandInput placeholder="Busque aqui" />
110
+ <CommandList className="custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]">
111
+ {projects.length === 0 ? (
112
+ <div className="flex flex-col items-center justify-center gap-2 h-full text-gray-400 py-4">
113
+ <IconFolderOpen size={28} className="text-gray-300" />
114
+ <span className="paragraph-small-medium text-center text-gray-500">
115
+ Nenhum projeto encontrado.
116
+ <br />
117
+ Crie um projeto para começar.
118
+ </span>
119
+ </div>
120
+ ) : (
121
+ <>
122
+ <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
123
+ {projects.map((project) => {
124
+ const isSelected = selectedProject?.id === project.id;
125
+ return (
126
+ <CommandItem
127
+ key={project.id}
128
+ value={`${project.title}-${project.id}`}
129
+ keywords={[project.title]}
130
+ className={isSelected ? 'bg-gray-50' : ''}
131
+ onSelect={() => onSelectProject(project)}
132
+ >
133
+ <div className="flex items-center justify-between w-full cursor-pointer">
134
+ <div className="flex items-center gap-2 w-full">
135
+ <UserAvatar
136
+ photo={project.photo}
137
+ name={project.title}
138
+ size={32}
139
+ />
140
+ {project.title}
141
+ </div>
142
+ {isSelected && (
143
+ <IconCheck className="size-4 text-gray-950" />
144
+ )}
145
+ </div>
146
+ </CommandItem>
147
+ );
148
+ })}
149
+ </>
150
+ )}
151
+ </CommandList>
152
+ </Command>
153
+ </div>
154
+ </PopoverContent>
155
+ </Popover>
156
+ );
157
+ }
@@ -1,72 +1,72 @@
1
- 'use client';
2
-
3
- import { ReactNode, useRef, useEffect } from 'react';
4
- import { AppNavigationContext } from '../AppNavigationContext';
5
- import { useNavItemsContext } from '../NavItemsContext';
6
-
7
- function InternalTabsBar({ topOffset = '72px' }: { topOffset?: string }) {
8
- const { navItems } = useNavItemsContext();
9
- const tabsListRef = useRef<HTMLDivElement>(null);
10
- const activeTabRef = useRef<HTMLButtonElement>(null);
11
-
12
- const activeLabel = navItems.find((i) => i.isActive)?.label;
13
-
14
- // Scroll active tab into center when active item changes
15
- useEffect(() => {
16
- if (activeTabRef.current && tabsListRef.current) {
17
- const tabsList = tabsListRef.current;
18
- const activeTabElement = activeTabRef.current;
19
- const tabsListRect = tabsList.getBoundingClientRect();
20
- const activeTabRect = activeTabElement.getBoundingClientRect();
21
- const scrollLeft =
22
- activeTabElement.offsetLeft - tabsListRect.width / 2 + activeTabRect.width / 2;
23
- tabsList.scrollTo({ left: Math.max(0, scrollLeft), behavior: 'smooth' });
24
- }
25
- }, [activeLabel]);
26
-
27
- if (!navItems.length) return null;
28
-
29
- return (
30
- <div
31
- ref={tabsListRef}
32
- className="md:hidden fixed left-0 right-0 z-40 bg-white border-b border-gray-200 flex overflow-x-auto scrollbar-hide"
33
- style={{ top: topOffset }}
34
- >
35
- {navItems.map((item) => (
36
- <button
37
- key={item.label}
38
- ref={item.isActive ? activeTabRef : undefined}
39
- onClick={item.onClick}
40
- className={`flex items-center gap-2 px-4 py-3 shrink-0 border-b-2 transition-colors ${
41
- item.isActive
42
- ? 'border-gray-950 text-gray-950'
43
- : 'border-transparent text-gray-500 hover:text-gray-900'
44
- }`}
45
- >
46
- {item.icon && <item.icon size={16} className="shrink-0" />}
47
- <span
48
- className={
49
- item.isActive ? 'paragraph-small-semibold' : 'paragraph-small-medium'
50
- }
51
- >
52
- {item.label}
53
- </span>
54
- </button>
55
- ))}
56
- </div>
57
- );
58
- }
59
-
60
- export function TabsMobileShell({ children, topOffset }: { children: ReactNode; topOffset?: string }) {
61
- return (
62
- <AppNavigationContext.Provider value={{ breakpoint: 'mobile' }}>
63
- {/*
64
- Children are hidden visually, but NavItems' useEffect still fires inside
65
- display:none — React effects are tied to commit phase, not layout visibility.
66
- This registers navItems in NavItemsContext so InternalTabsBar can read them.
67
- */}
68
- <div className="hidden">{children}</div>
69
- <InternalTabsBar topOffset={topOffset} />
70
- </AppNavigationContext.Provider>
71
- );
72
- }
1
+ 'use client';
2
+
3
+ import { ReactNode, useRef, useEffect } from 'react';
4
+ import { AppNavigationContext } from '../AppNavigationContext';
5
+ import { useNavItemsContext } from '../NavItemsContext';
6
+
7
+ function InternalTabsBar({ topOffset = '72px' }: { topOffset?: string }) {
8
+ const { navItems } = useNavItemsContext();
9
+ const tabsListRef = useRef<HTMLDivElement>(null);
10
+ const activeTabRef = useRef<HTMLButtonElement>(null);
11
+
12
+ const activeLabel = navItems.find((i) => i.isActive)?.label;
13
+
14
+ // Scroll active tab into center when active item changes
15
+ useEffect(() => {
16
+ if (activeTabRef.current && tabsListRef.current) {
17
+ const tabsList = tabsListRef.current;
18
+ const activeTabElement = activeTabRef.current;
19
+ const tabsListRect = tabsList.getBoundingClientRect();
20
+ const activeTabRect = activeTabElement.getBoundingClientRect();
21
+ const scrollLeft =
22
+ activeTabElement.offsetLeft - tabsListRect.width / 2 + activeTabRect.width / 2;
23
+ tabsList.scrollTo({ left: Math.max(0, scrollLeft), behavior: 'smooth' });
24
+ }
25
+ }, [activeLabel]);
26
+
27
+ if (!navItems.length) return null;
28
+
29
+ return (
30
+ <div
31
+ ref={tabsListRef}
32
+ className="md:hidden fixed left-0 right-0 z-40 bg-white border-b border-gray-200 flex overflow-x-auto scrollbar-hide"
33
+ style={{ top: topOffset }}
34
+ >
35
+ {navItems.map((item) => (
36
+ <button
37
+ key={item.label}
38
+ ref={item.isActive ? activeTabRef : undefined}
39
+ onClick={item.onClick}
40
+ className={`flex items-center gap-2 px-4 py-3 shrink-0 border-b-2 transition-colors ${
41
+ item.isActive
42
+ ? 'border-gray-950 text-gray-950'
43
+ : 'border-transparent text-gray-500 hover:text-gray-900'
44
+ }`}
45
+ >
46
+ {item.icon && <item.icon size={16} className="shrink-0" />}
47
+ <span
48
+ className={
49
+ item.isActive ? 'paragraph-small-semibold' : 'paragraph-small-medium'
50
+ }
51
+ >
52
+ {item.label}
53
+ </span>
54
+ </button>
55
+ ))}
56
+ </div>
57
+ );
58
+ }
59
+
60
+ export function TabsMobileShell({ children, topOffset }: { children: ReactNode; topOffset?: string }) {
61
+ return (
62
+ <AppNavigationContext.Provider value={{ breakpoint: 'mobile' }}>
63
+ {/*
64
+ Children are hidden visually, but NavItems' useEffect still fires inside
65
+ display:none — React effects are tied to commit phase, not layout visibility.
66
+ This registers navItems in NavItemsContext so InternalTabsBar can read them.
67
+ */}
68
+ <div className="hidden">{children}</div>
69
+ <InternalTabsBar topOffset={topOffset} />
70
+ </AppNavigationContext.Provider>
71
+ );
72
+ }