@greatapps/common 1.1.218 → 1.1.221

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 (117) hide show
  1. package/dist/components/account/ConfigurationsMyAccountModal.mjs +6 -6
  2. package/dist/components/account/ConfigurationsMyAccountModal.mjs.map +1 -1
  3. package/dist/components/account/ConfirmDeleteAccountModal.mjs +2 -2
  4. package/dist/components/account/ConfirmDeleteAccountModal.mjs.map +1 -1
  5. package/dist/components/account/ConfirmGlobalPreferencesModal.mjs +2 -2
  6. package/dist/components/account/ConfirmGlobalPreferencesModal.mjs.map +1 -1
  7. package/dist/components/account/DeleteAccountModal.mjs +3 -3
  8. package/dist/components/account/DeleteAccountModal.mjs.map +1 -1
  9. package/dist/components/account/DisableTwoFactorAuthModal.mjs +2 -2
  10. package/dist/components/account/DisableTwoFactorAuthModal.mjs.map +1 -1
  11. package/dist/components/account/IsntPossibleDeleteAccountModal.mjs +2 -2
  12. package/dist/components/account/IsntPossibleDeleteAccountModal.mjs.map +1 -1
  13. package/dist/components/account/TwoFactorAuthModal.mjs +6 -6
  14. package/dist/components/account/TwoFactorAuthModal.mjs.map +1 -1
  15. package/dist/components/account/sections/ChangeEmailModal.mjs +6 -6
  16. package/dist/components/account/sections/ChangeEmailModal.mjs.map +1 -1
  17. package/dist/components/account/sections/ChangePasswordSection.mjs +4 -4
  18. package/dist/components/account/sections/ChangePasswordSection.mjs.map +1 -1
  19. package/dist/components/account/sections/ChangePhoneModal.mjs +5 -5
  20. package/dist/components/account/sections/ChangePhoneModal.mjs.map +1 -1
  21. package/dist/components/account/sections/MyProfileSection.mjs +3 -3
  22. package/dist/components/account/sections/MyProfileSection.mjs.map +1 -1
  23. package/dist/components/account/sections/PreferencesSection.mjs +6 -6
  24. package/dist/components/account/sections/PreferencesSection.mjs.map +1 -1
  25. package/dist/components/account/sections/SecuritySection.mjs +3 -3
  26. package/dist/components/account/sections/SecuritySection.mjs.map +1 -1
  27. package/dist/components/layouts/AppMobileNavBar.mjs +0 -1
  28. package/dist/components/layouts/AppMobileNavBar.mjs.map +1 -1
  29. package/dist/components/layouts/MdSideBarNavigation.mjs +2 -2
  30. package/dist/components/layouts/MdSideBarNavigation.mjs.map +1 -1
  31. package/dist/components/layouts/NavBar.mjs +2 -2
  32. package/dist/components/layouts/NavBar.mjs.map +1 -1
  33. package/dist/components/layouts/NotificationsPopover.mjs +4 -4
  34. package/dist/components/layouts/NotificationsPopover.mjs.map +1 -1
  35. package/dist/components/layouts/ProfilePopover.mjs +7 -10
  36. package/dist/components/layouts/ProfilePopover.mjs.map +1 -1
  37. package/dist/components/layouts/UsersSelectorPopover.mjs +5 -5
  38. package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
  39. package/dist/components/navigation/ProjectSelectorPopover.mjs +6 -6
  40. package/dist/components/navigation/ProjectSelectorPopover.mjs.map +1 -1
  41. package/dist/components/navigation/subcomponents/ProjectSelector.mjs +5 -5
  42. package/dist/components/navigation/subcomponents/ProjectSelector.mjs.map +1 -1
  43. package/dist/components/pages/notifications/Notifications.mjs +4 -4
  44. package/dist/components/pages/notifications/Notifications.mjs.map +1 -1
  45. package/dist/components/ui/buttons/CopyButton.mjs +2 -2
  46. package/dist/components/ui/buttons/CopyButton.mjs.map +1 -1
  47. package/dist/components/ui/data-display/Accordion.mjs +2 -2
  48. package/dist/components/ui/data-display/Accordion.mjs.map +1 -1
  49. package/dist/components/ui/data-display/Pagination.mjs +7 -7
  50. package/dist/components/ui/data-display/Pagination.mjs.map +1 -1
  51. package/dist/components/ui/feedback/Toast.mjs +7 -7
  52. package/dist/components/ui/feedback/Toast.mjs.map +1 -1
  53. package/dist/components/ui/form/Calendar.mjs +7 -7
  54. package/dist/components/ui/form/Calendar.mjs.map +1 -1
  55. package/dist/components/ui/form/Checkbox.mjs +2 -2
  56. package/dist/components/ui/form/Checkbox.mjs.map +1 -1
  57. package/dist/components/ui/form/ComboboxField.mjs +4 -4
  58. package/dist/components/ui/form/ComboboxField.mjs.map +1 -1
  59. package/dist/components/ui/form/DateRangePicker.mjs +2 -2
  60. package/dist/components/ui/form/DateRangePicker.mjs.map +1 -1
  61. package/dist/components/ui/form/FormField.mjs +3 -3
  62. package/dist/components/ui/form/FormField.mjs.map +1 -1
  63. package/dist/components/ui/form/InputOtp.mjs +2 -2
  64. package/dist/components/ui/form/InputOtp.mjs.map +1 -1
  65. package/dist/components/ui/form/RadioGroup.mjs +2 -2
  66. package/dist/components/ui/form/RadioGroup.mjs.map +1 -1
  67. package/dist/components/ui/form/Select.mjs +5 -5
  68. package/dist/components/ui/form/Select.mjs.map +1 -1
  69. package/dist/components/ui/form/SwitchOptionFieldWithIcon.mjs.map +1 -1
  70. package/dist/components/ui/overlay/Command.mjs +2 -2
  71. package/dist/components/ui/overlay/Command.mjs.map +1 -1
  72. package/dist/components/ui/overlay/Dialog.mjs +2 -2
  73. package/dist/components/ui/overlay/Dialog.mjs.map +1 -1
  74. package/dist/components/ui/overlay/Sheet.mjs +2 -2
  75. package/dist/components/ui/overlay/Sheet.mjs.map +1 -1
  76. package/dist/components/widgets/notifications/NotificationCard.mjs +2 -2
  77. package/dist/components/widgets/notifications/NotificationCard.mjs.map +1 -1
  78. package/package.json +1 -2
  79. package/src/components/account/ConfigurationsMyAccountModal.tsx +150 -150
  80. package/src/components/account/ConfirmDeleteAccountModal.tsx +2 -2
  81. package/src/components/account/ConfirmGlobalPreferencesModal.tsx +66 -66
  82. package/src/components/account/DeleteAccountModal.tsx +3 -3
  83. package/src/components/account/DisableTwoFactorAuthModal.tsx +86 -86
  84. package/src/components/account/IsntPossibleDeleteAccountModal.tsx +2 -2
  85. package/src/components/account/TwoFactorAuthModal.tsx +223 -223
  86. package/src/components/account/sections/ChangeEmailModal.tsx +225 -225
  87. package/src/components/account/sections/ChangePasswordSection.tsx +64 -64
  88. package/src/components/account/sections/ChangePhoneModal.tsx +5 -5
  89. package/src/components/account/sections/MyProfileSection.tsx +327 -327
  90. package/src/components/account/sections/PreferencesSection.tsx +273 -273
  91. package/src/components/account/sections/SecuritySection.tsx +160 -160
  92. package/src/components/layouts/AppMobileNavBar.tsx +0 -1
  93. package/src/components/layouts/MdSideBarNavigation.tsx +54 -54
  94. package/src/components/layouts/NavBar.tsx +2 -2
  95. package/src/components/layouts/NotificationsPopover.tsx +115 -115
  96. package/src/components/layouts/ProfilePopover.tsx +179 -184
  97. package/src/components/layouts/UsersSelectorPopover.tsx +5 -5
  98. package/src/components/navigation/ProjectSelectorPopover.tsx +151 -151
  99. package/src/components/navigation/subcomponents/ProjectSelector.tsx +149 -149
  100. package/src/components/pages/notifications/Notifications.tsx +4 -4
  101. package/src/components/ui/buttons/CopyButton.tsx +2 -2
  102. package/src/components/ui/data-display/Accordion.tsx +2 -2
  103. package/src/components/ui/data-display/Pagination.tsx +7 -7
  104. package/src/components/ui/feedback/Toast.tsx +7 -7
  105. package/src/components/ui/form/Calendar.tsx +7 -7
  106. package/src/components/ui/form/Checkbox.tsx +2 -2
  107. package/src/components/ui/form/ComboboxField.tsx +154 -154
  108. package/src/components/ui/form/DateRangePicker.tsx +2 -2
  109. package/src/components/ui/form/FormField.tsx +131 -130
  110. package/src/components/ui/form/InputOtp.tsx +2 -2
  111. package/src/components/ui/form/RadioGroup.tsx +2 -2
  112. package/src/components/ui/form/Select.tsx +5 -5
  113. package/src/components/ui/form/SwitchOptionFieldWithIcon.tsx +2 -2
  114. package/src/components/ui/overlay/Command.tsx +2 -2
  115. package/src/components/ui/overlay/Dialog.tsx +2 -2
  116. package/src/components/ui/overlay/Sheet.tsx +2 -2
  117. package/src/components/widgets/notifications/NotificationCard.tsx +68 -68
@@ -1,151 +1,151 @@
1
- 'use client';
2
-
3
- import { Dispatch, RefObject, SetStateAction } from 'react';
4
- import {
5
- Button,
6
- Command,
7
- CommandEmpty,
8
- CommandInput,
9
- CommandItem,
10
- CommandList,
11
- Popover,
12
- PopoverContent,
13
- PopoverTrigger,
14
- Tooltip,
15
- TooltipContent,
16
- TooltipTrigger,
17
- UserAvatar,
18
- } from '../../index';
19
- import { CheckIcon, ChevronDown, FolderOpen, Plus, Settings } from 'lucide-react';
20
- import type { NavigationProject } from './types';
21
-
22
- interface ProjectSelectorPopoverProps {
23
- open: boolean;
24
- setOpen: Dispatch<SetStateAction<boolean>>;
25
- titleRef?: RefObject<HTMLSpanElement | null>;
26
- projects: NavigationProject[];
27
- selectedProject: NavigationProject | null;
28
- onSelectProject: (project: NavigationProject) => void;
29
- onAddProject: () => void;
30
- onManageProjects: () => void;
31
- children?: React.ReactNode;
32
- }
33
-
34
- function ProjectItemSkeleton() {
35
- return (
36
- <div className="flex items-center justify-between px-2 py-1.5 gap-2">
37
- <div className="flex items-center gap-2 flex-1">
38
- <div className="skeleton size-8 rounded-lg shrink-0" />
39
- <div className="skeleton h-3.5 w-32 rounded" />
40
- </div>
41
- <div className="skeleton size-4 rounded-full shrink-0" />
42
- </div>
43
- );
44
- }
45
-
46
- export function ProjectSelectorPopover({
47
- open,
48
- setOpen,
49
- titleRef,
50
- projects,
51
- selectedProject,
52
- onSelectProject,
53
- onAddProject,
54
- onManageProjects,
55
- children,
56
- }: ProjectSelectorPopoverProps) {
57
- return (
58
- <Popover open={open} onOpenChange={setOpen}>
59
- <PopoverTrigger asChild>
60
- {children ?? (
61
- <button className="cursor-pointer">
62
- <ChevronDown
63
- size={20}
64
- className={`transition-transform duration-200 ${open ? 'rotate-180 text-gray-950' : 'text-gray-400'}`}
65
- />
66
- </button>
67
- )}
68
- </PopoverTrigger>
69
- <PopoverContent
70
- className="w-[296px] p-0 bg-white rounded-2xl shadow-md border border-gray-200"
71
- align="start"
72
- sideOffset={8}
73
- onOpenAutoFocus={(e: Event) => e.preventDefault()}
74
- onInteractOutside={(event: Event) => {
75
- if (titleRef?.current?.contains(event.target as Node)) {
76
- event.preventDefault();
77
- }
78
- }}
79
- >
80
- <div className="flex flex-col p-3 gap-2">
81
- <div className="flex items-center justify-between">
82
- <span className="paragraph-small-semibold">Projetos</span>
83
- <div className="flex items-center gap-1.5">
84
- <Button
85
- variant="secondary"
86
- className="h-8! paragraph-small-semibold text-gray-950"
87
- onClick={onAddProject}
88
- >
89
- <Plus size={16} />
90
- Adicionar
91
- </Button>
92
- <Tooltip>
93
- <TooltipTrigger asChild>
94
- <Button variant="secondary" className="p-0 size-8" onClick={onManageProjects}>
95
- <Settings size={18} />
96
- </Button>
97
- </TooltipTrigger>
98
- <TooltipContent className="z-[1002]">Visualizar todos projetos</TooltipContent>
99
- </Tooltip>
100
- </div>
101
- </div>
102
- <Command className="gap-2">
103
- <CommandInput placeholder="Busque aqui" />
104
- <CommandList className="custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]">
105
- {projects.length === 0 ? (
106
- <div className="flex flex-col items-center justify-center gap-2 h-full text-gray-400 py-4">
107
- <FolderOpen size={28} className="text-gray-300" />
108
- <span className="paragraph-small-medium text-center text-gray-500">
109
- Nenhum projeto encontrado.
110
- <br />
111
- Crie um projeto para começar.
112
- </span>
113
- </div>
114
- ) : (
115
- <>
116
- <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
117
- {projects.map((project) => {
118
- const isSelected = selectedProject?.id === project.id;
119
- return (
120
- <CommandItem
121
- key={project.id}
122
- value={`${project.title}-${project.id}`}
123
- keywords={[project.title]}
124
- className={isSelected ? 'bg-gray-50' : ''}
125
- onSelect={() => onSelectProject(project)}
126
- >
127
- <div className="flex items-center justify-between w-full cursor-pointer">
128
- <div className="flex items-center gap-2 w-full">
129
- <UserAvatar
130
- photo={project.photo}
131
- name={project.title}
132
- size={32}
133
- />
134
- {project.title}
135
- </div>
136
- {isSelected && (
137
- <CheckIcon className="size-4 text-gray-950" />
138
- )}
139
- </div>
140
- </CommandItem>
141
- );
142
- })}
143
- </>
144
- )}
145
- </CommandList>
146
- </Command>
147
- </div>
148
- </PopoverContent>
149
- </Popover>
150
- );
151
- }
1
+ 'use client';
2
+
3
+ import { Dispatch, RefObject, SetStateAction } from 'react';
4
+ import {
5
+ Button,
6
+ Command,
7
+ CommandEmpty,
8
+ CommandInput,
9
+ CommandItem,
10
+ CommandList,
11
+ Popover,
12
+ PopoverContent,
13
+ PopoverTrigger,
14
+ Tooltip,
15
+ TooltipContent,
16
+ TooltipTrigger,
17
+ UserAvatar,
18
+ } from '../../index';
19
+ import { IconCheck, IconChevronDown, IconFolderOpen, IconPlus, IconSettings } from '@tabler/icons-react';
20
+ import type { NavigationProject } from './types';
21
+
22
+ interface ProjectSelectorPopoverProps {
23
+ open: boolean;
24
+ setOpen: Dispatch<SetStateAction<boolean>>;
25
+ titleRef?: RefObject<HTMLSpanElement | null>;
26
+ projects: NavigationProject[];
27
+ selectedProject: NavigationProject | null;
28
+ onSelectProject: (project: NavigationProject) => void;
29
+ onAddProject: () => void;
30
+ onManageProjects: () => void;
31
+ children?: React.ReactNode;
32
+ }
33
+
34
+ function ProjectItemSkeleton() {
35
+ return (
36
+ <div className="flex items-center justify-between px-2 py-1.5 gap-2">
37
+ <div className="flex items-center gap-2 flex-1">
38
+ <div className="skeleton size-8 rounded-lg shrink-0" />
39
+ <div className="skeleton h-3.5 w-32 rounded" />
40
+ </div>
41
+ <div className="skeleton size-4 rounded-full shrink-0" />
42
+ </div>
43
+ );
44
+ }
45
+
46
+ export function ProjectSelectorPopover({
47
+ open,
48
+ setOpen,
49
+ titleRef,
50
+ projects,
51
+ selectedProject,
52
+ onSelectProject,
53
+ onAddProject,
54
+ onManageProjects,
55
+ children,
56
+ }: ProjectSelectorPopoverProps) {
57
+ return (
58
+ <Popover open={open} onOpenChange={setOpen}>
59
+ <PopoverTrigger asChild>
60
+ {children ?? (
61
+ <button className="cursor-pointer">
62
+ <IconChevronDown
63
+ size={20}
64
+ className={`transition-transform duration-200 ${open ? 'rotate-180 text-gray-950' : 'text-gray-400'}`}
65
+ />
66
+ </button>
67
+ )}
68
+ </PopoverTrigger>
69
+ <PopoverContent
70
+ className="w-[296px] p-0 bg-white rounded-2xl shadow-md border border-gray-200"
71
+ align="start"
72
+ sideOffset={8}
73
+ onOpenAutoFocus={(e: Event) => e.preventDefault()}
74
+ onInteractOutside={(event: Event) => {
75
+ if (titleRef?.current?.contains(event.target as Node)) {
76
+ event.preventDefault();
77
+ }
78
+ }}
79
+ >
80
+ <div className="flex flex-col p-3 gap-2">
81
+ <div className="flex items-center justify-between">
82
+ <span className="paragraph-small-semibold">Projetos</span>
83
+ <div className="flex items-center gap-1.5">
84
+ <Button
85
+ variant="secondary"
86
+ className="h-8! paragraph-small-semibold text-gray-950"
87
+ onClick={onAddProject}
88
+ >
89
+ <IconPlus size={16} />
90
+ Adicionar
91
+ </Button>
92
+ <Tooltip>
93
+ <TooltipTrigger asChild>
94
+ <Button variant="secondary" className="p-0 size-8" onClick={onManageProjects}>
95
+ <IconSettings size={18} />
96
+ </Button>
97
+ </TooltipTrigger>
98
+ <TooltipContent className="z-[1002]">Visualizar todos projetos</TooltipContent>
99
+ </Tooltip>
100
+ </div>
101
+ </div>
102
+ <Command className="gap-2">
103
+ <CommandInput placeholder="Busque aqui" />
104
+ <CommandList className="custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]">
105
+ {projects.length === 0 ? (
106
+ <div className="flex flex-col items-center justify-center gap-2 h-full text-gray-400 py-4">
107
+ <IconFolderOpen size={28} className="text-gray-300" />
108
+ <span className="paragraph-small-medium text-center text-gray-500">
109
+ Nenhum projeto encontrado.
110
+ <br />
111
+ Crie um projeto para começar.
112
+ </span>
113
+ </div>
114
+ ) : (
115
+ <>
116
+ <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
117
+ {projects.map((project) => {
118
+ const isSelected = selectedProject?.id === project.id;
119
+ return (
120
+ <CommandItem
121
+ key={project.id}
122
+ value={`${project.title}-${project.id}`}
123
+ keywords={[project.title]}
124
+ className={isSelected ? 'bg-gray-50' : ''}
125
+ onSelect={() => onSelectProject(project)}
126
+ >
127
+ <div className="flex items-center justify-between w-full cursor-pointer">
128
+ <div className="flex items-center gap-2 w-full">
129
+ <UserAvatar
130
+ photo={project.photo}
131
+ name={project.title}
132
+ size={32}
133
+ />
134
+ {project.title}
135
+ </div>
136
+ {isSelected && (
137
+ <IconCheck className="size-4 text-gray-950" />
138
+ )}
139
+ </div>
140
+ </CommandItem>
141
+ );
142
+ })}
143
+ </>
144
+ )}
145
+ </CommandList>
146
+ </Command>
147
+ </div>
148
+ </PopoverContent>
149
+ </Popover>
150
+ );
151
+ }
@@ -1,149 +1,149 @@
1
- 'use client';
2
-
3
- import { useState, useRef, useEffect, RefObject } from 'react';
4
- import { useMobileNavbarSheet } from '../../../store/useMobileNavbarSheet';
5
- import { useAppNavigationContext } from '../AppNavigationContext';
6
- import { ProjectSelectorPopover } from '../ProjectSelectorPopover';
7
- import { UsersSelectorPopover } from '../../layouts/UsersSelectorPopover';
8
- import { Button, Command, CommandEmpty, CommandInput, CommandItem, CommandList, UserAvatar } from '../../../index';
9
- import { ChevronDown, Plus, Settings } from 'lucide-react';
10
- import type { NavigationProject } from '../types';
11
-
12
- export interface ProjectSelectorProps {
13
- projects: NavigationProject[];
14
- selectedProject: NavigationProject | null;
15
- isLoading?: boolean;
16
- onSelectProject: (project: NavigationProject) => void;
17
- onAddProject: () => void;
18
- onManageProjects: () => void;
19
- }
20
-
21
- function ProjectItemSkeleton() {
22
- return (
23
- <div className="flex items-center gap-2 p-2">
24
- <div className="skeleton size-8 rounded-lg shrink-0" />
25
- <div className="skeleton h-3.5 w-32 rounded" />
26
- </div>
27
- );
28
- }
29
-
30
- export function ProjectSelector({
31
- projects,
32
- selectedProject,
33
- isLoading,
34
- onSelectProject,
35
- onAddProject,
36
- onManageProjects,
37
- }: ProjectSelectorProps) {
38
- const { breakpoint } = useAppNavigationContext();
39
- const [isPopoverOpen, setIsPopoverOpen] = useState(false);
40
- const [activeSection, setActiveSection] = useState<'projects' | null>(null);
41
- const titleRef = useRef<HTMLDivElement>(null);
42
- const { openProjectList, clearProjectList } = useMobileNavbarSheet();
43
-
44
- useEffect(() => {
45
- if (openProjectList && breakpoint === 'mobile') {
46
- setActiveSection('projects');
47
- clearProjectList();
48
- }
49
- }, [openProjectList, breakpoint, clearProjectList]);
50
-
51
- // Desktop and md: title + popover + users selector (same visual as current gpages sidebars)
52
- if (breakpoint === 'desktop' || breakpoint === 'md') {
53
- return (
54
- <div className="flex items-center justify-between">
55
- <ProjectSelectorPopover
56
- open={isPopoverOpen}
57
- setOpen={setIsPopoverOpen}
58
- titleRef={titleRef as unknown as RefObject<HTMLSpanElement | null>}
59
- projects={projects}
60
- selectedProject={selectedProject}
61
- onSelectProject={onSelectProject}
62
- onAddProject={onAddProject}
63
- onManageProjects={onManageProjects}
64
- >
65
- <div className="flex items-center gap-2 truncate select-none cursor-pointer" ref={titleRef}>
66
- {isLoading ? (
67
- <div className="skeleton h-4 w-32 rounded" />
68
- ) : (
69
- <span className="paragraph-medium-semibold text-gray-600 truncate max-w-[120px] inline-block">
70
- {selectedProject?.title}
71
- </span>
72
- )}
73
- <ChevronDown
74
- size={20}
75
- className={`transition-transform duration-200 ${isPopoverOpen ? 'rotate-180 text-gray-950' : 'text-gray-400'}`}
76
- />
77
- </div>
78
- </ProjectSelectorPopover>
79
- <div className="flex items-center gap-2">
80
- <UsersSelectorPopover projectId={selectedProject?.id} />
81
- </div>
82
- </div>
83
- );
84
- }
85
-
86
- // Mobile: inline collapsible accordion
87
- return (
88
- <div className="flex flex-col gap-2.5">
89
- <div className="flex items-center justify-between">
90
- <div className="flex items-center gap-1">
91
- <span className="paragraph-medium-semibold text-gray-600">{selectedProject?.title}</span>
92
- <ChevronDown
93
- size={20}
94
- onClick={() => setActiveSection(activeSection === 'projects' ? null : 'projects')}
95
- className={`transition-transform duration-200 cursor-pointer ${
96
- activeSection === 'projects' ? 'rotate-180 text-gray-950' : 'text-gray-400'
97
- }`}
98
- />
99
- </div>
100
- <UsersSelectorPopover projectId={selectedProject?.id} />
101
- </div>
102
- {activeSection === 'projects' && (
103
- <div className="flex flex-col p-3 gap-2 border border-gray-200 rounded-lg animate-in fade-in duration-400">
104
- <div className="flex items-center justify-between">
105
- <span className="paragraph-small-semibold">Projetos</span>
106
- <div className="flex items-center gap-1.5">
107
- <Button variant="secondary" className="h-8! paragraph-small-semibold text-gray-950" onClick={onAddProject}>
108
- <Plus size={16} />
109
- Adicionar
110
- </Button>
111
- <Button variant="secondary" className="p-0 size-8" onClick={onManageProjects}>
112
- <Settings size={18} />
113
- </Button>
114
- </div>
115
- </div>
116
- <Command className="gap-2">
117
- <CommandInput placeholder="Busque aqui" />
118
- <CommandList className="custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]">
119
- <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
120
- {isLoading ? (
121
- <>
122
- <ProjectItemSkeleton />
123
- <ProjectItemSkeleton />
124
- </>
125
- ) : (
126
- projects.map((project) => (
127
- <CommandItem
128
- key={project.id}
129
- value={`${project.title}-${project.id}`}
130
- keywords={[project.title]}
131
- className={selectedProject?.id === project.id ? 'bg-gray-50' : ''}
132
- onSelect={() => { onSelectProject(project); setActiveSection(null); }}
133
- >
134
- <UserAvatar
135
- photo={project.photo}
136
- name={project.title}
137
- size={32}
138
- />
139
- {project.title}
140
- </CommandItem>
141
- ))
142
- )}
143
- </CommandList>
144
- </Command>
145
- </div>
146
- )}
147
- </div>
148
- );
149
- }
1
+ 'use client';
2
+
3
+ import { useState, useRef, useEffect, RefObject } from 'react';
4
+ import { useMobileNavbarSheet } from '../../../store/useMobileNavbarSheet';
5
+ import { useAppNavigationContext } from '../AppNavigationContext';
6
+ import { ProjectSelectorPopover } from '../ProjectSelectorPopover';
7
+ import { UsersSelectorPopover } from '../../layouts/UsersSelectorPopover';
8
+ import { Button, Command, CommandEmpty, CommandInput, CommandItem, CommandList, UserAvatar } from '../../../index';
9
+ import { IconChevronDown, IconPlus, IconSettings } from '@tabler/icons-react';
10
+ import type { NavigationProject } from '../types';
11
+
12
+ export interface ProjectSelectorProps {
13
+ projects: NavigationProject[];
14
+ selectedProject: NavigationProject | null;
15
+ isLoading?: boolean;
16
+ onSelectProject: (project: NavigationProject) => void;
17
+ onAddProject: () => void;
18
+ onManageProjects: () => void;
19
+ }
20
+
21
+ function ProjectItemSkeleton() {
22
+ return (
23
+ <div className="flex items-center gap-2 p-2">
24
+ <div className="skeleton size-8 rounded-lg shrink-0" />
25
+ <div className="skeleton h-3.5 w-32 rounded" />
26
+ </div>
27
+ );
28
+ }
29
+
30
+ export function ProjectSelector({
31
+ projects,
32
+ selectedProject,
33
+ isLoading,
34
+ onSelectProject,
35
+ onAddProject,
36
+ onManageProjects,
37
+ }: ProjectSelectorProps) {
38
+ const { breakpoint } = useAppNavigationContext();
39
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
40
+ const [activeSection, setActiveSection] = useState<'projects' | null>(null);
41
+ const titleRef = useRef<HTMLDivElement>(null);
42
+ const { openProjectList, clearProjectList } = useMobileNavbarSheet();
43
+
44
+ useEffect(() => {
45
+ if (openProjectList && breakpoint === 'mobile') {
46
+ setActiveSection('projects');
47
+ clearProjectList();
48
+ }
49
+ }, [openProjectList, breakpoint, clearProjectList]);
50
+
51
+ // Desktop and md: title + popover + users selector (same visual as current gpages sidebars)
52
+ if (breakpoint === 'desktop' || breakpoint === 'md') {
53
+ return (
54
+ <div className="flex items-center justify-between">
55
+ <ProjectSelectorPopover
56
+ open={isPopoverOpen}
57
+ setOpen={setIsPopoverOpen}
58
+ titleRef={titleRef as unknown as RefObject<HTMLSpanElement | null>}
59
+ projects={projects}
60
+ selectedProject={selectedProject}
61
+ onSelectProject={onSelectProject}
62
+ onAddProject={onAddProject}
63
+ onManageProjects={onManageProjects}
64
+ >
65
+ <div className="flex items-center gap-2 truncate select-none cursor-pointer" ref={titleRef}>
66
+ {isLoading ? (
67
+ <div className="skeleton h-4 w-32 rounded" />
68
+ ) : (
69
+ <span className="paragraph-medium-semibold text-gray-600 truncate max-w-[120px] inline-block">
70
+ {selectedProject?.title}
71
+ </span>
72
+ )}
73
+ <IconChevronDown
74
+ size={20}
75
+ className={`transition-transform duration-200 ${isPopoverOpen ? 'rotate-180 text-gray-950' : 'text-gray-400'}`}
76
+ />
77
+ </div>
78
+ </ProjectSelectorPopover>
79
+ <div className="flex items-center gap-2">
80
+ <UsersSelectorPopover projectId={selectedProject?.id} />
81
+ </div>
82
+ </div>
83
+ );
84
+ }
85
+
86
+ // Mobile: inline collapsible accordion
87
+ return (
88
+ <div className="flex flex-col gap-2.5">
89
+ <div className="flex items-center justify-between">
90
+ <div className="flex items-center gap-1">
91
+ <span className="paragraph-medium-semibold text-gray-600">{selectedProject?.title}</span>
92
+ <IconChevronDown
93
+ size={20}
94
+ onClick={() => setActiveSection(activeSection === 'projects' ? null : 'projects')}
95
+ className={`transition-transform duration-200 cursor-pointer ${
96
+ activeSection === 'projects' ? 'rotate-180 text-gray-950' : 'text-gray-400'
97
+ }`}
98
+ />
99
+ </div>
100
+ <UsersSelectorPopover projectId={selectedProject?.id} />
101
+ </div>
102
+ {activeSection === 'projects' && (
103
+ <div className="flex flex-col p-3 gap-2 border border-gray-200 rounded-lg animate-in fade-in duration-400">
104
+ <div className="flex items-center justify-between">
105
+ <span className="paragraph-small-semibold">Projetos</span>
106
+ <div className="flex items-center gap-1.5">
107
+ <Button variant="secondary" className="h-8! paragraph-small-semibold text-gray-950" onClick={onAddProject}>
108
+ <IconPlus size={16} />
109
+ Adicionar
110
+ </Button>
111
+ <Button variant="secondary" className="p-0 size-8" onClick={onManageProjects}>
112
+ <IconSettings size={18} />
113
+ </Button>
114
+ </div>
115
+ </div>
116
+ <Command className="gap-2">
117
+ <CommandInput placeholder="Busque aqui" />
118
+ <CommandList className="custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]">
119
+ <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
120
+ {isLoading ? (
121
+ <>
122
+ <ProjectItemSkeleton />
123
+ <ProjectItemSkeleton />
124
+ </>
125
+ ) : (
126
+ projects.map((project) => (
127
+ <CommandItem
128
+ key={project.id}
129
+ value={`${project.title}-${project.id}`}
130
+ keywords={[project.title]}
131
+ className={selectedProject?.id === project.id ? 'bg-gray-50' : ''}
132
+ onSelect={() => { onSelectProject(project); setActiveSection(null); }}
133
+ >
134
+ <UserAvatar
135
+ photo={project.photo}
136
+ name={project.title}
137
+ size={32}
138
+ />
139
+ {project.title}
140
+ </CommandItem>
141
+ ))
142
+ )}
143
+ </CommandList>
144
+ </Command>
145
+ </div>
146
+ )}
147
+ </div>
148
+ );
149
+ }
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { Bell, Check, Loader2 } from "lucide-react";
3
+ import { IconBell, IconCheck, IconLoader2 } from '@tabler/icons-react';
4
4
  import { Button } from "../../ui/buttons/Button";
5
5
  import {
6
6
  Tabs,
@@ -47,7 +47,7 @@ function NotificationsList({
47
47
  {notifications.map((notification, index) => (
48
48
  <NotificationCard
49
49
  key={notification.id}
50
- icon={<Bell size={20} className="text-pages-600" />}
50
+ icon={<IconBell size={20} className="text-pages-600" />}
51
51
  iconBgColor="bg-pages-100"
52
52
  title={notification.subject}
53
53
  description={notification.message}
@@ -62,7 +62,7 @@ function NotificationsList({
62
62
  ))}
63
63
  {isFetchingNextPage && (
64
64
  <div className="flex items-center justify-center py-4">
65
- <Loader2 size={20} className="animate-spin text-gray-400" />
65
+ <IconLoader2 size={20} className="animate-spin text-gray-400" />
66
66
  </div>
67
67
  )}
68
68
  </div>
@@ -117,7 +117,7 @@ export function NotificationPageContent() {
117
117
  onClick={handleMarkAllAsRead}
118
118
  disabled={isMarkingAll || totalUnread === 0}
119
119
  >
120
- {isMarkingAll ? <Loader2 size={20} className="animate-spin" /> : <Check size={20} />}
120
+ {isMarkingAll ? <IconLoader2 size={20} className="animate-spin" /> : <IconCheck size={20} />}
121
121
  <span className="lg:block hidden">Marcar todos como lidos</span>
122
122
  <span className="lg:hidden">Marcar como lidos</span>
123
123
  </Button>
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { Check, Copy } from "lucide-react";
3
+ import { IconCheck, IconCopy } from '@tabler/icons-react';
4
4
  import { toast } from "sonner";
5
5
  import { Toast } from "../feedback/Toast";
6
6
  import { Tooltip, TooltipContent, TooltipTrigger } from "../overlay/Tooltip";
@@ -45,7 +45,7 @@ export function CopyButton({
45
45
  }}
46
46
  >
47
47
  <span className={cn("cursor-pointer text-gray-500", className)}>
48
- {isCopied ? <Check size={size} /> : <Copy size={size} />}
48
+ {isCopied ? <IconCheck size={size} /> : <IconCopy size={size} />}
49
49
  </span>
50
50
  </TooltipTrigger>
51
51
  <TooltipContent>{isCopied ? "Copiado!" : tooltipText}</TooltipContent>