@greatapps/common 1.1.47 → 1.1.49

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 (31) hide show
  1. package/dist/components/layouts/UsersSelectorPopover.mjs +100 -22
  2. package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
  3. package/dist/index.mjs +3 -0
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/modules/projects/actions/add-project-user.action.mjs +9 -0
  6. package/dist/modules/projects/actions/add-project-user.action.mjs.map +1 -0
  7. package/dist/modules/projects/actions/list-available-users.action.mjs +9 -0
  8. package/dist/modules/projects/actions/list-available-users.action.mjs.map +1 -0
  9. package/dist/modules/projects/actions/list-project-users.action.mjs +9 -0
  10. package/dist/modules/projects/actions/list-project-users.action.mjs.map +1 -0
  11. package/dist/modules/projects/actions/remove-project-user.action.mjs +9 -0
  12. package/dist/modules/projects/actions/remove-project-user.action.mjs.map +1 -0
  13. package/dist/modules/projects/hooks/project-users.hook.mjs +70 -0
  14. package/dist/modules/projects/hooks/project-users.hook.mjs.map +1 -0
  15. package/dist/modules/projects/services/project-users.service.mjs +67 -0
  16. package/dist/modules/projects/services/project-users.service.mjs.map +1 -0
  17. package/dist/modules/projects/types.mjs +22 -0
  18. package/dist/modules/projects/types.mjs.map +1 -0
  19. package/dist/server.mjs +10 -0
  20. package/dist/server.mjs.map +1 -1
  21. package/package.json +1 -1
  22. package/src/components/layouts/UsersSelectorPopover.tsx +167 -64
  23. package/src/index.ts +2 -0
  24. package/src/modules/projects/actions/add-project-user.action.ts +8 -0
  25. package/src/modules/projects/actions/list-available-users.action.ts +8 -0
  26. package/src/modules/projects/actions/list-project-users.action.ts +8 -0
  27. package/src/modules/projects/actions/remove-project-user.action.ts +8 -0
  28. package/src/modules/projects/hooks/project-users.hook.ts +81 -0
  29. package/src/modules/projects/services/project-users.service.ts +94 -0
  30. package/src/modules/projects/types.ts +28 -0
  31. package/src/server.ts +7 -0
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
- import { Plus, Settings, User } from "lucide-react";
4
+ import { Plus, Settings, User, Users } from "lucide-react";
5
5
  import Image from "next/image";
6
6
  import { useRouter } from "next/navigation";
7
7
  import { Popover, PopoverContent, PopoverTrigger } from "../ui/overlay/Popover";
@@ -10,30 +10,30 @@ import { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from ".
10
10
  import { Checkbox } from "../ui/form/Checkbox";
11
11
  import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/overlay/Tooltip";
12
12
  import { cn } from "../../infra/utils/clsx";
13
- function UsersSelectorPopover({
14
- users: externalUsers,
15
- onToggleUser,
16
- addRoute = "/my-teams?createNew=true",
17
- manageRoute = "/my-teams",
18
- userCount = 5,
13
+ import { useProjectUsers } from "../../modules/projects/hooks/project-users.hook";
14
+ function UserItemSkeleton() {
15
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-2 py-1.5 gap-2", children: [
16
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-1", children: [
17
+ /* @__PURE__ */ jsx("div", { className: "size-8 rounded-full bg-gray-100 animate-pulse shrink-0" }),
18
+ /* @__PURE__ */ jsx("div", { className: "h-3.5 w-28 rounded bg-gray-100 animate-pulse" })
19
+ ] }),
20
+ /* @__PURE__ */ jsx("div", { className: "size-4 rounded bg-gray-100 animate-pulse shrink-0" })
21
+ ] });
22
+ }
23
+ function UsersSelectorPopoverContent({
24
+ users,
25
+ isLoading,
26
+ userCount,
27
+ toggleUser,
28
+ addRoute,
29
+ manageRoute,
19
30
  side,
20
31
  align,
21
32
  contentClassName
22
33
  }) {
23
34
  const route = useRouter();
24
35
  const [open, setOpen] = useState(false);
25
- const [internalUsers, setInternalUsers] = useState(externalUsers ?? []);
26
36
  const [hoveredId, setHoveredId] = useState(null);
27
- const users = externalUsers ?? internalUsers;
28
- const toggleUser = (id) => {
29
- if (onToggleUser) {
30
- onToggleUser(id);
31
- } else {
32
- setInternalUsers(
33
- (prev) => prev.map((u) => u.id === id ? { ...u, checked: !u.checked } : u)
34
- );
35
- }
36
- };
37
37
  return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
38
38
  /* @__PURE__ */ jsx(PopoverTrigger, { className: "cursor-pointer", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-gray-950 px-3 py-2 border border-gray-200 rounded-full hover:border-gray-950", children: [
39
39
  /* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold", children: userCount }),
@@ -81,11 +81,23 @@ function UsersSelectorPopover({
81
81
  ] }),
82
82
  /* @__PURE__ */ jsxs(Command, { className: "gap-2", value: "", children: [
83
83
  /* @__PURE__ */ jsx(CommandInput, { placeholder: "Busque aqui" }),
84
- /* @__PURE__ */ jsxs(CommandList, { className: "custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]", children: [
85
- /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
84
+ /* @__PURE__ */ jsx(CommandList, { className: "custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]", children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
85
+ /* @__PURE__ */ jsx(UserItemSkeleton, {}),
86
+ /* @__PURE__ */ jsx(UserItemSkeleton, {}),
87
+ /* @__PURE__ */ jsx(UserItemSkeleton, {})
88
+ ] }) : users.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-2 h-full text-gray-400 py-4", children: [
89
+ /* @__PURE__ */ jsx(Users, { size: 28, className: "text-gray-300" }),
90
+ /* @__PURE__ */ jsxs("span", { className: "paragraph-small-medium text-center text-gray-500", children: [
91
+ "Nenhum usu\xE1rio neste projeto.",
92
+ /* @__PURE__ */ jsx("br", {}),
93
+ "Adicione um usu\xE1rio para come\xE7ar."
94
+ ] })
95
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
96
+ /* @__PURE__ */ jsx(CommandEmpty, { children: "Nenhum resultado encontrado." }),
86
97
  users.map((user) => /* @__PURE__ */ jsx(
87
98
  CommandItem,
88
99
  {
100
+ value: user.name,
89
101
  autoFocus: false,
90
102
  onPointerEnter: () => setHoveredId(user.id),
91
103
  onPointerLeave: () => setHoveredId(null),
@@ -129,13 +141,79 @@ function UsersSelectorPopover({
129
141
  },
130
142
  user.id
131
143
  ))
132
- ] })
144
+ ] }) })
133
145
  ] })
134
146
  ] })
135
147
  }
136
148
  )
137
149
  ] });
138
150
  }
151
+ function ConnectedUsersSelectorPopover({
152
+ projectId,
153
+ addRoute,
154
+ manageRoute,
155
+ side,
156
+ align,
157
+ contentClassName
158
+ }) {
159
+ const { users, isLoading, userCount, toggleUser } = useProjectUsers(projectId);
160
+ return /* @__PURE__ */ jsx(
161
+ UsersSelectorPopoverContent,
162
+ {
163
+ users,
164
+ isLoading,
165
+ userCount,
166
+ toggleUser,
167
+ addRoute: addRoute ?? "/my-teams?createNew=true",
168
+ manageRoute: manageRoute ?? "/my-teams",
169
+ side,
170
+ align,
171
+ contentClassName
172
+ }
173
+ );
174
+ }
175
+ function StaticUsersSelectorPopover({
176
+ users: externalUsers = [],
177
+ onToggleUser,
178
+ userCount = 5,
179
+ addRoute = "/my-teams?createNew=true",
180
+ manageRoute = "/my-teams",
181
+ side,
182
+ align,
183
+ contentClassName
184
+ }) {
185
+ const [internalUsers, setInternalUsers] = useState(externalUsers);
186
+ const users = externalUsers.length > 0 ? externalUsers : internalUsers;
187
+ const toggleUser = (id) => {
188
+ if (onToggleUser) {
189
+ onToggleUser(id);
190
+ } else {
191
+ setInternalUsers(
192
+ (prev) => prev.map((u) => u.id === id ? { ...u, checked: !u.checked } : u)
193
+ );
194
+ }
195
+ };
196
+ return /* @__PURE__ */ jsx(
197
+ UsersSelectorPopoverContent,
198
+ {
199
+ users,
200
+ isLoading: false,
201
+ userCount,
202
+ toggleUser,
203
+ addRoute,
204
+ manageRoute,
205
+ side,
206
+ align,
207
+ contentClassName
208
+ }
209
+ );
210
+ }
211
+ function UsersSelectorPopover(props) {
212
+ if (props.projectId != null) {
213
+ return /* @__PURE__ */ jsx(ConnectedUsersSelectorPopover, { ...props, projectId: props.projectId });
214
+ }
215
+ return /* @__PURE__ */ jsx(StaticUsersSelectorPopover, { ...props });
216
+ }
139
217
  export {
140
218
  UsersSelectorPopover
141
219
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/layouts/UsersSelectorPopover.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { useState } from 'react';\r\nimport { Plus, Settings, User } from 'lucide-react';\r\nimport Image from 'next/image';\r\nimport { useRouter } from 'next/navigation';\r\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/overlay/Popover';\r\nimport { Button } from '../ui/buttons/Button';\r\nimport { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from '../ui/overlay/Command';\r\nimport { Checkbox } from '../ui/form/Checkbox';\r\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';\r\nimport { cn } from '../../infra/utils/clsx';\r\n\r\nexport interface UserSelectorItem {\r\n id: number;\r\n name: string;\r\n avatar: string;\r\n checked: boolean;\r\n}\r\n\r\nexport interface UsersSelectorPopoverProps {\r\n users?: UserSelectorItem[];\r\n onToggleUser?: (id: number) => void;\r\n addRoute?: string;\r\n manageRoute?: string;\r\n userCount?: number;\r\n side?: 'top' | 'bottom' | 'left' | 'right';\r\n align?: 'start' | 'center' | 'end';\r\n contentClassName?: string;\r\n}\r\n\r\nfunction UsersSelectorPopover({\r\n users: externalUsers,\r\n onToggleUser,\r\n addRoute = '/my-teams?createNew=true',\r\n manageRoute = '/my-teams',\r\n userCount = 5,\r\n side,\r\n align,\r\n contentClassName,\r\n}: UsersSelectorPopoverProps) {\r\n const route = useRouter();\r\n const [open, setOpen] = useState(false);\r\n const [internalUsers, setInternalUsers] = useState<UserSelectorItem[]>(externalUsers ?? []);\r\n const [hoveredId, setHoveredId] = useState<number | null>(null);\r\n\r\n const users = externalUsers ?? internalUsers;\r\n\r\n const toggleUser = (id: number) => {\r\n if (onToggleUser) {\r\n onToggleUser(id);\r\n } else {\r\n setInternalUsers((prev) =>\r\n prev.map((u) => (u.id === id ? { ...u, checked: !u.checked } : u))\r\n );\r\n }\r\n };\r\n\r\n return (\r\n <Popover open={open} onOpenChange={setOpen}>\r\n <PopoverTrigger className=\"cursor-pointer\">\r\n <div className=\"flex items-center gap-2 text-gray-950 px-3 py-2 border border-gray-200 rounded-full hover:border-gray-950\">\r\n <span className=\"paragraph-small-semibold\">{userCount}</span>\r\n <User size={16} />\r\n </div>\r\n </PopoverTrigger>\r\n\r\n <PopoverContent\r\n className={cn(\r\n 'absolute right-[-88px] w-[273px] p-0 bg-white rounded-2xl shadow-md border border-gray-200',\r\n contentClassName\r\n )}\r\n side={side}\r\n align={align}\r\n sideOffset={8}\r\n >\r\n <div className=\"flex flex-col p-3 gap-2\">\r\n <div className=\"flex items-center justify-between\">\r\n <span className=\"paragraph-small-semibold\">Usuários</span>\r\n <div className=\"flex items-center gap-1.5\">\r\n <Button\r\n variant=\"secondary\"\r\n className=\"h-8 paragraph-small-semibold text-gray-950\"\r\n onClick={() => route.push(addRoute)}\r\n >\r\n <Plus size={16} />\r\n Adicionar\r\n </Button>\r\n\r\n <Tooltip>\r\n <TooltipTrigger asChild>\r\n <Button\r\n variant=\"secondary\"\r\n className=\"p-0 size-8\"\r\n onClick={() => route.push(manageRoute)}\r\n >\r\n <Settings size={18} />\r\n </Button>\r\n </TooltipTrigger>\r\n <TooltipContent>Visualizar todos usuários</TooltipContent>\r\n </Tooltip>\r\n </div>\r\n </div>\r\n\r\n <Command className=\"gap-2\" value=\"\">\r\n <CommandInput placeholder=\"Busque aqui\" />\r\n <CommandList className=\"custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]\">\r\n <CommandEmpty>No results found.</CommandEmpty>\r\n {users.map((user) => (\r\n <CommandItem\r\n key={user.id}\r\n autoFocus={false}\r\n onPointerEnter={() => setHoveredId(user.id)}\r\n onPointerLeave={() => setHoveredId(null)}\r\n onFocus={() => setHoveredId(user.id)}\r\n onBlur={() => setHoveredId(null)}\r\n onSelect={() => toggleUser(user.id)}\r\n className=\"cursor-pointer\"\r\n >\r\n <div className=\"flex items-center justify-between w-full\">\r\n <div className=\"flex items-center gap-2\">\r\n <Image\r\n alt=\"Avatar\"\r\n src={user.avatar}\r\n width={32}\r\n height={32}\r\n className=\"rounded-full\"\r\n />\r\n {user.name}\r\n </div>\r\n\r\n <Tooltip open={hoveredId === user.id}>\r\n <TooltipTrigger\r\n onClick={(e) => e.stopPropagation()}\r\n onPointerDown={(e) => e.stopPropagation()}\r\n >\r\n <Checkbox\r\n checked={user.checked}\r\n onCheckedChange={() => toggleUser(user.id)}\r\n className={hoveredId === user.id ? 'border-gray-950' : ''}\r\n />\r\n </TooltipTrigger>\r\n <TooltipContent>\r\n {user.checked ? 'Remover do projeto' : 'Adicionar ao projeto'}\r\n </TooltipContent>\r\n </Tooltip>\r\n </div>\r\n </CommandItem>\r\n ))}\r\n </CommandList>\r\n </Command>\r\n </div>\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n\r\nexport { UsersSelectorPopover };\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/layouts/UsersSelectorPopover.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { useState } from 'react';\r\nimport { Plus, Settings, User, Users } from 'lucide-react';\r\nimport Image from 'next/image';\r\nimport { useRouter } from 'next/navigation';\r\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/overlay/Popover';\r\nimport { Button } from '../ui/buttons/Button';\r\nimport { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from '../ui/overlay/Command';\r\nimport { Checkbox } from '../ui/form/Checkbox';\r\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';\r\nimport { cn } from '../../infra/utils/clsx';\r\nimport { useProjectUsers } from '../../modules/projects/hooks/project-users.hook';\r\n\r\nexport interface UserSelectorItem {\r\n id: number;\r\n name: string;\r\n avatar: string;\r\n checked: boolean;\r\n}\r\n\r\nfunction UserItemSkeleton() {\r\n return (\r\n <div className=\"flex items-center justify-between px-2 py-1.5 gap-2\">\r\n <div className=\"flex items-center gap-2 flex-1\">\r\n <div className=\"size-8 rounded-full bg-gray-100 animate-pulse shrink-0\" />\r\n <div className=\"h-3.5 w-28 rounded bg-gray-100 animate-pulse\" />\r\n </div>\r\n <div className=\"size-4 rounded bg-gray-100 animate-pulse shrink-0\" />\r\n </div>\r\n );\r\n}\r\n\r\nexport interface UsersSelectorPopoverProps {\r\n projectId?: number;\r\n users?: UserSelectorItem[];\r\n onToggleUser?: (id: number) => void;\r\n addRoute?: string;\r\n manageRoute?: string;\r\n userCount?: number;\r\n side?: 'top' | 'bottom' | 'left' | 'right';\r\n align?: 'start' | 'center' | 'end';\r\n contentClassName?: string;\r\n}\r\n\r\ninterface ContentProps {\r\n users: UserSelectorItem[];\r\n isLoading: boolean;\r\n userCount: number;\r\n toggleUser: (id: number) => void;\r\n addRoute: string;\r\n manageRoute: string;\r\n side?: UsersSelectorPopoverProps['side'];\r\n align?: UsersSelectorPopoverProps['align'];\r\n contentClassName?: string;\r\n}\r\n\r\nfunction UsersSelectorPopoverContent({\r\n users,\r\n isLoading,\r\n userCount,\r\n toggleUser,\r\n addRoute,\r\n manageRoute,\r\n side,\r\n align,\r\n contentClassName,\r\n}: ContentProps) {\r\n const route = useRouter();\r\n const [open, setOpen] = useState(false);\r\n const [hoveredId, setHoveredId] = useState<number | null>(null);\r\n\r\n return (\r\n <Popover open={open} onOpenChange={setOpen}>\r\n <PopoverTrigger className=\"cursor-pointer\">\r\n <div className=\"flex items-center gap-2 text-gray-950 px-3 py-2 border border-gray-200 rounded-full hover:border-gray-950\">\r\n <span className=\"paragraph-small-semibold\">{userCount}</span>\r\n <User size={16} />\r\n </div>\r\n </PopoverTrigger>\r\n\r\n <PopoverContent\r\n className={cn(\r\n 'absolute right-[-88px] w-[273px] p-0 bg-white rounded-2xl shadow-md border border-gray-200',\r\n contentClassName\r\n )}\r\n side={side}\r\n align={align}\r\n sideOffset={8}\r\n >\r\n <div className=\"flex flex-col p-3 gap-2\">\r\n <div className=\"flex items-center justify-between\">\r\n <span className=\"paragraph-small-semibold\">Usuários</span>\r\n <div className=\"flex items-center gap-1.5\">\r\n <Button\r\n variant=\"secondary\"\r\n className=\"h-8 paragraph-small-semibold text-gray-950\"\r\n onClick={() => route.push(addRoute)}\r\n >\r\n <Plus size={16} />\r\n Adicionar\r\n </Button>\r\n <Tooltip>\r\n <TooltipTrigger asChild>\r\n <Button\r\n variant=\"secondary\"\r\n className=\"p-0 size-8\"\r\n onClick={() => route.push(manageRoute)}\r\n >\r\n <Settings size={18} />\r\n </Button>\r\n </TooltipTrigger>\r\n <TooltipContent>Visualizar todos usuários</TooltipContent>\r\n </Tooltip>\r\n </div>\r\n </div>\r\n\r\n <Command className=\"gap-2\" value=\"\">\r\n <CommandInput placeholder=\"Busque aqui\" />\r\n <CommandList className=\"custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]\">\r\n {isLoading ? (\r\n <>\r\n <UserItemSkeleton />\r\n <UserItemSkeleton />\r\n <UserItemSkeleton />\r\n </>\r\n ) : users.length === 0 ? (\r\n <div className=\"flex flex-col items-center justify-center gap-2 h-full text-gray-400 py-4\">\r\n <Users size={28} className=\"text-gray-300\" />\r\n <span className=\"paragraph-small-medium text-center text-gray-500\">\r\n Nenhum usuário neste projeto.\r\n <br />\r\n Adicione um usuário para começar.\r\n </span>\r\n </div>\r\n ) : (\r\n <>\r\n <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>\r\n {users.map((user) => (\r\n <CommandItem\r\n key={user.id}\r\n value={user.name}\r\n autoFocus={false}\r\n onPointerEnter={() => setHoveredId(user.id)}\r\n onPointerLeave={() => setHoveredId(null)}\r\n onFocus={() => setHoveredId(user.id)}\r\n onBlur={() => setHoveredId(null)}\r\n onSelect={() => toggleUser(user.id)}\r\n className=\"cursor-pointer\"\r\n >\r\n <div className=\"flex items-center justify-between w-full\">\r\n <div className=\"flex items-center gap-2\">\r\n <Image\r\n alt=\"Avatar\"\r\n src={user.avatar}\r\n width={32}\r\n height={32}\r\n className=\"rounded-full\"\r\n />\r\n {user.name}\r\n </div>\r\n <Tooltip open={hoveredId === user.id}>\r\n <TooltipTrigger\r\n onClick={(e) => e.stopPropagation()}\r\n onPointerDown={(e) => e.stopPropagation()}\r\n >\r\n <Checkbox\r\n checked={user.checked}\r\n onCheckedChange={() => toggleUser(user.id)}\r\n className={hoveredId === user.id ? 'border-gray-950' : ''}\r\n />\r\n </TooltipTrigger>\r\n <TooltipContent>\r\n {user.checked ? 'Remover do projeto' : 'Adicionar ao projeto'}\r\n </TooltipContent>\r\n </Tooltip>\r\n </div>\r\n </CommandItem>\r\n ))}\r\n </>\r\n )}\r\n </CommandList>\r\n </Command>\r\n </div>\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n\r\nfunction ConnectedUsersSelectorPopover({\r\n projectId,\r\n addRoute,\r\n manageRoute,\r\n side,\r\n align,\r\n contentClassName,\r\n}: Required<Pick<UsersSelectorPopoverProps, 'projectId'>> &\r\n Pick<UsersSelectorPopoverProps, 'addRoute' | 'manageRoute' | 'side' | 'align' | 'contentClassName'>) {\r\n const { users, isLoading, userCount, toggleUser } = useProjectUsers(projectId);\r\n return (\r\n <UsersSelectorPopoverContent\r\n users={users}\r\n isLoading={isLoading}\r\n userCount={userCount}\r\n toggleUser={toggleUser}\r\n addRoute={addRoute ?? '/my-teams?createNew=true'}\r\n manageRoute={manageRoute ?? '/my-teams'}\r\n side={side}\r\n align={align}\r\n contentClassName={contentClassName}\r\n />\r\n );\r\n}\r\n\r\nfunction StaticUsersSelectorPopover({\r\n users: externalUsers = [],\r\n onToggleUser,\r\n userCount = 5,\r\n addRoute = '/my-teams?createNew=true',\r\n manageRoute = '/my-teams',\r\n side,\r\n align,\r\n contentClassName,\r\n}: Omit<UsersSelectorPopoverProps, 'projectId'>) {\r\n const [internalUsers, setInternalUsers] = useState<UserSelectorItem[]>(externalUsers);\r\n\r\n const users = externalUsers.length > 0 ? externalUsers : internalUsers;\r\n\r\n const toggleUser = (id: number) => {\r\n if (onToggleUser) {\r\n onToggleUser(id);\r\n } else {\r\n setInternalUsers((prev) =>\r\n prev.map((u) => (u.id === id ? { ...u, checked: !u.checked } : u))\r\n );\r\n }\r\n };\r\n\r\n return (\r\n <UsersSelectorPopoverContent\r\n users={users}\r\n isLoading={false}\r\n userCount={userCount}\r\n toggleUser={toggleUser}\r\n addRoute={addRoute}\r\n manageRoute={manageRoute}\r\n side={side}\r\n align={align}\r\n contentClassName={contentClassName}\r\n />\r\n );\r\n}\r\n\r\nfunction UsersSelectorPopover(props: UsersSelectorPopoverProps) {\r\n if (props.projectId != null) {\r\n return <ConnectedUsersSelectorPopover {...props} projectId={props.projectId} />;\r\n }\r\n return <StaticUsersSelectorPopover {...props} />;\r\n}\r\n\r\nexport { UsersSelectorPopover };\r\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -5,6 +5,7 @@ export * from "./infra/api/types";
5
5
  export * from "./providers/query.provider";
6
6
  export * from "./providers/auth.provider";
7
7
  export * from "./providers/whitelabel.provider";
8
+ import { useProjectUsers, projectUsersQueryKey } from "./modules/projects/hooks/project-users.hook";
8
9
  import { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from "./modules/auth/hooks/useUserQuery";
9
10
  import { useSubscriptions, SUBSCRIPTIONS_QUERY_KEY } from "./modules/subscriptions/hooks/list-subscriptions.hook";
10
11
  import { useActiveSubscription } from "./modules/subscriptions/hooks/find-active-subscription.hook";
@@ -268,6 +269,7 @@ export {
268
269
  formatTimer,
269
270
  parseResult,
270
271
  parseSchema,
272
+ projectUsersQueryKey,
271
273
  readFromClipboard,
272
274
  stopChain,
273
275
  timezoneService,
@@ -284,6 +286,7 @@ export {
284
286
  useMdSidebarStore,
285
287
  useModalManager,
286
288
  default5 as usePasswordVisibility,
289
+ useProjectUsers,
287
290
  useSetUserData,
288
291
  useSubscriptions,
289
292
  useUpdateAccount,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Types\nexport * from './modules/auth/schema';\nexport * from './modules/users/schema';\nexport * from './modules/whitelabel/schema';\nexport * from './infra/api/types';\n\n// Contexts\nexport * from './providers/query.provider';\nexport * from './providers/auth.provider';\nexport * from './providers/whitelabel.provider';\n\n// Hooks\nexport { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';\nexport { useSubscriptions, SUBSCRIPTIONS_QUERY_KEY } from './modules/subscriptions/hooks/list-subscriptions.hook';\nexport { useActiveSubscription } from './modules/subscriptions/hooks/find-active-subscription.hook';\nexport { useIaCredits } from './modules/ia-credits/hooks/ia-credits.hook';\nexport type { IaCreditsSummary, IaCreditOperation } from './modules/ia-credits/types';\nexport type { Subscription, SubscriptionItem, FindSubscriptionsParams } from './modules/subscriptions/types';\nexport { SubscriptionSchema, SubscriptionItemSchema } from './modules/subscriptions/types';\nexport { ADDON_IDS } from './modules/subscriptions/constants/addons.constants';\nexport type { AddonKindEnum } from './modules/subscriptions/constants/addons.constants';\n\n// Providers\nexport { QueryProvider } from './providers/query.provider';\n\n// Middleware\nexport { createAuthMiddleware } from './middlewares/create-auth-middleware';\nexport { createMiddlewareChain } from './middlewares/chain';\nexport { continueChain, stopChain } from './middlewares/types';\nexport type { MiddlewareFunction, MiddlewareConfig, MiddlewareResult } from './middlewares/types';\n\n// Utils\nexport { cn } from './infra/utils/clsx';\nexport { buildQueryParams } from './infra/utils/params';\nexport { parseSchema, parseResult } from './infra/utils/parser';\n\n// Layout\nexport { MainLayout, MainLayoutContent, MainLayoutSpacer, MainLayoutMain } from './components/layouts/MainLayout';\nexport { NavBar } from './components/layouts/NavBar';\nexport type { NavBarProps } from './components/layouts/NavBar';\nexport { AppNavBar } from './components/layouts/AppNavBar';\nexport type { AppNavBarProps } from './components/layouts/AppNavBar';\nexport { AppMobileNavBar } from './components/layouts/AppMobileNavBar';\nexport type { AppMobileNavBarProps } from './components/layouts/AppMobileNavBar';\nexport { SideBarNavigation } from './components/layouts/SideBarNavigation';\nexport { MdSideBarNavigation } from './components/layouts/MdSideBarNavigation';\nexport { NotificationItem } from './components/layouts/NotificationItem';\nexport type { NotificationItemProps } from './components/layouts/NotificationItem';\nexport { NotificationsPopover } from './components/layouts/NotificationsPopover';\nexport type { NotificationsPopoverProps, NotificationData } from './components/layouts/NotificationsPopover';\nexport { UsersSelectorPopover } from './components/layouts/UsersSelectorPopover';\nexport type { UsersSelectorPopoverProps, UserSelectorItem } from './components/layouts/UsersSelectorPopover';\nexport { ProfilePopover } from './components/layouts/ProfilePopover';\nexport type { ProfilePopoverProps, ProfileMenuItem } from './components/layouts/ProfilePopover';\nexport { NavBarItem } from './components/layouts/NavBarItem';\nexport type { NavBarItemProps } from './components/layouts/NavBarItem';\n\n// UI - Buttons\nexport { Button, buttonVariants } from './components/ui/buttons/Button';\nexport { CopyButton } from './components/ui/buttons/CopyButton';\nexport { default as CancelButton } from './components/ui/buttons/CancelButton';\n\n// UI - Data Display\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './components/ui/data-display/Accordion';\nexport { Badge, badgeVariants } from './components/ui/data-display/Badge';\nexport { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } from './components/ui/data-display/Card';\nexport { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from './components/ui/data-display/Pagination';\nexport { ScrollArea, ScrollBar } from './components/ui/data-display/ScrollArea';\nexport { Separator } from './components/ui/data-display/Separator';\nexport { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from './components/ui/data-display/Table';\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from './components/ui/data-display/Tabs';\nexport { UserAvatar } from './components/ui/data-display/UserAvatar';\nexport type { UserAvatarProps } from './components/ui/data-display/UserAvatar';\n\n// UI - Feedback\nexport { default as CircularProgress } from './components/ui/feedback/CircularProgress';\nexport { default as DefaultCircularProgress } from './components/ui/feedback/DefaultCircularProgress';\nexport { Progress } from './components/ui/feedback/Progress';\nexport { LoadingOverlay } from './components/ui/feedback/LoadingOverlay';\nexport { Toast, toastVariants, toastIconContainerVariants } from './components/ui/feedback/Toast';\nexport type { ToastProps } from './components/ui/feedback/Toast';\n\n// UI - Form\nexport { Calendar, CalendarDayButton } from './components/ui/form/Calendar';\nexport { Checkbox } from './components/ui/form/Checkbox';\nexport { DatePicker } from './components/ui/form/DatePicker';\nexport { DateRangePicker } from './components/ui/form/DateRangePicker';\nexport { Input } from './components/ui/form/Input';\nexport { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from './components/ui/form/InputOtp';\nexport { RadioGroup, RadioGroupItem } from './components/ui/form/RadioGroup';\nexport { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from './components/ui/form/Select';\nexport { Switch } from './components/ui/form/Switch';\nexport { Textarea } from './components/ui/form/Textarea';\n\n// UI - Overlay\nexport { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator } from './components/ui/overlay/Command';\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './components/ui/overlay/Dialog';\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } from './components/ui/overlay/Popover';\nexport { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from './components/ui/overlay/Sheet';\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './components/ui/overlay/Tooltip';\n\n// Store\nexport { useMdSidebarStore } from './store/useMdSidebarStore';\nexport { useModalManager } from './store/useModalManager';\nexport type { ModalData } from './store/useModalManager';\n\n// Enums\nexport { AccountSectionType } from './enums/AccountSectionType';\n\n// Hooks\nexport { default as usePasswordVisibility } from './hooks/usePasswordVisibility';\nexport { default as useCountdownTimer } from './hooks/useCountdownTimer';\nexport { default as useIsMobile } from './hooks/useIsMobile';\n\n// Utils\nexport { formatPhone, formatTimer, formatFullName, formatCPF, formatCardNumber } from './utils/format/masks';\nexport { timezoneService } from './modules/accounts/services/timezone.service';\nexport type { TimezoneOption } from './modules/accounts/services/timezone.service';\nexport { buildLocaleOptions, LANGUAGE_OPTIONS as LOCALE_LANGUAGE_OPTIONS } from './utils/intl/locales';\nexport type { LocaleOption } from './utils/intl/locales';\nexport { copyToClipboard, readFromClipboard } from './utils/browser/clipboard';\n\n// UI - Form (new widgets)\nexport { FormField } from './components/ui/form/FormField';\nexport { SelectField } from './components/ui/form/SelectField';\nexport { ComboboxField } from './components/ui/form/ComboboxField';\nexport type { ComboboxOption } from './components/ui/form/ComboboxField';\nexport { default as PhoneInput } from './components/ui/form/PhoneInput';\nexport { default as SwitchOptionFieldWithIcon } from './components/ui/form/SwitchOptionFieldWithIcon';\nexport { TextAreaField } from './components/ui/form/TextAreaField';\n\n// Account Module - Hooks\nexport {\n useUpdateAccount,\n useUpdateAccountUser,\n useUpdateAccountUserById,\n useDeleteAccountUser,\n useDeleteAccount,\n} from './modules/accounts/hooks/useAccountManagement';\n\n// Account Types\nexport type {\n UpdateAccountRequest,\n UpdateAccountUserRequest,\n ChangePasswordRequest,\n DeleteAccountActionResult,\n DeleteUserActionResult,\n UpdateAccountActionResult,\n UpdateUserActionResult,\n TwoFactorGenerateResult,\n TwoFactorActionResult,\n ContactResetResult,\n} from './modules/accounts/types';\n\nexport { default as AccountModals } from './components/account/AccountModals';\nexport { useAccountModals } from './store/useAccountModals';\nexport type { AccountModalsConfig } from './store/useAccountModals';\n\nexport { ModalManager } from './components/modals/ModalManager';\nexport { Modals } from './components/modals/Modals';\n\nexport { default as TwoFactorAuthModal } from './components/account/TwoFactorAuthModal';\nexport { default as DisableTwoFactorAuthModal } from './components/account/DisableTwoFactorAuthModal';\nexport { default as ConfirmGlobalPreferencesModal } from './components/account/ConfirmGlobalPreferencesModal';\nexport { MyProfileSection } from './components/account/sections/MyProfileSection';\nexport { PreferencesSection } from './components/account/sections/PreferencesSection';\nexport { SecuritySection } from './components/account/sections/SecuritySection';\nexport { ChangePasswordSection } from './components/account/sections/ChangePasswordSection';\nexport { ChangeEmailModal } from './components/account/sections/ChangeEmailModal';\nexport { ChangePhoneModal } from './components/account/sections/ChangePhoneModal';\n\n// Account Constants\nexport {\n GENDER_OPTIONS,\n CURRENCY_OPTIONS,\n TIME_FORMAT_OPTIONS,\n NOTIFICATION_TYPES,\n LANGUAGE_OPTIONS,\n} from './components/account/constants';\n"],"mappings":"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","names":["default","LANGUAGE_OPTIONS"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Types\nexport * from './modules/auth/schema';\nexport * from './modules/users/schema';\nexport * from './modules/whitelabel/schema';\nexport * from './infra/api/types';\n\n// Contexts\nexport * from './providers/query.provider';\nexport * from './providers/auth.provider';\nexport * from './providers/whitelabel.provider';\n\n// Hooks\nexport { useProjectUsers, projectUsersQueryKey } from './modules/projects/hooks/project-users.hook';\nexport type { ProjectUser, AccountUser, AddRemoveProjectUsersParams } from './modules/projects/types';\nexport { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';\nexport { useSubscriptions, SUBSCRIPTIONS_QUERY_KEY } from './modules/subscriptions/hooks/list-subscriptions.hook';\nexport { useActiveSubscription } from './modules/subscriptions/hooks/find-active-subscription.hook';\nexport { useIaCredits } from './modules/ia-credits/hooks/ia-credits.hook';\nexport type { IaCreditsSummary, IaCreditOperation } from './modules/ia-credits/types';\nexport type { Subscription, SubscriptionItem, FindSubscriptionsParams } from './modules/subscriptions/types';\nexport { SubscriptionSchema, SubscriptionItemSchema } from './modules/subscriptions/types';\nexport { ADDON_IDS } from './modules/subscriptions/constants/addons.constants';\nexport type { AddonKindEnum } from './modules/subscriptions/constants/addons.constants';\n\n// Providers\nexport { QueryProvider } from './providers/query.provider';\n\n// Middleware\nexport { createAuthMiddleware } from './middlewares/create-auth-middleware';\nexport { createMiddlewareChain } from './middlewares/chain';\nexport { continueChain, stopChain } from './middlewares/types';\nexport type { MiddlewareFunction, MiddlewareConfig, MiddlewareResult } from './middlewares/types';\n\n// Utils\nexport { cn } from './infra/utils/clsx';\nexport { buildQueryParams } from './infra/utils/params';\nexport { parseSchema, parseResult } from './infra/utils/parser';\n\n// Layout\nexport { MainLayout, MainLayoutContent, MainLayoutSpacer, MainLayoutMain } from './components/layouts/MainLayout';\nexport { NavBar } from './components/layouts/NavBar';\nexport type { NavBarProps } from './components/layouts/NavBar';\nexport { AppNavBar } from './components/layouts/AppNavBar';\nexport type { AppNavBarProps } from './components/layouts/AppNavBar';\nexport { AppMobileNavBar } from './components/layouts/AppMobileNavBar';\nexport type { AppMobileNavBarProps } from './components/layouts/AppMobileNavBar';\nexport { SideBarNavigation } from './components/layouts/SideBarNavigation';\nexport { MdSideBarNavigation } from './components/layouts/MdSideBarNavigation';\nexport { NotificationItem } from './components/layouts/NotificationItem';\nexport type { NotificationItemProps } from './components/layouts/NotificationItem';\nexport { NotificationsPopover } from './components/layouts/NotificationsPopover';\nexport type { NotificationsPopoverProps, NotificationData } from './components/layouts/NotificationsPopover';\nexport { UsersSelectorPopover } from './components/layouts/UsersSelectorPopover';\nexport type { UsersSelectorPopoverProps, UserSelectorItem } from './components/layouts/UsersSelectorPopover';\nexport { ProfilePopover } from './components/layouts/ProfilePopover';\nexport type { ProfilePopoverProps, ProfileMenuItem } from './components/layouts/ProfilePopover';\nexport { NavBarItem } from './components/layouts/NavBarItem';\nexport type { NavBarItemProps } from './components/layouts/NavBarItem';\n\n// UI - Buttons\nexport { Button, buttonVariants } from './components/ui/buttons/Button';\nexport { CopyButton } from './components/ui/buttons/CopyButton';\nexport { default as CancelButton } from './components/ui/buttons/CancelButton';\n\n// UI - Data Display\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './components/ui/data-display/Accordion';\nexport { Badge, badgeVariants } from './components/ui/data-display/Badge';\nexport { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } from './components/ui/data-display/Card';\nexport { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from './components/ui/data-display/Pagination';\nexport { ScrollArea, ScrollBar } from './components/ui/data-display/ScrollArea';\nexport { Separator } from './components/ui/data-display/Separator';\nexport { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from './components/ui/data-display/Table';\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from './components/ui/data-display/Tabs';\nexport { UserAvatar } from './components/ui/data-display/UserAvatar';\nexport type { UserAvatarProps } from './components/ui/data-display/UserAvatar';\n\n// UI - Feedback\nexport { default as CircularProgress } from './components/ui/feedback/CircularProgress';\nexport { default as DefaultCircularProgress } from './components/ui/feedback/DefaultCircularProgress';\nexport { Progress } from './components/ui/feedback/Progress';\nexport { LoadingOverlay } from './components/ui/feedback/LoadingOverlay';\nexport { Toast, toastVariants, toastIconContainerVariants } from './components/ui/feedback/Toast';\nexport type { ToastProps } from './components/ui/feedback/Toast';\n\n// UI - Form\nexport { Calendar, CalendarDayButton } from './components/ui/form/Calendar';\nexport { Checkbox } from './components/ui/form/Checkbox';\nexport { DatePicker } from './components/ui/form/DatePicker';\nexport { DateRangePicker } from './components/ui/form/DateRangePicker';\nexport { Input } from './components/ui/form/Input';\nexport { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from './components/ui/form/InputOtp';\nexport { RadioGroup, RadioGroupItem } from './components/ui/form/RadioGroup';\nexport { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from './components/ui/form/Select';\nexport { Switch } from './components/ui/form/Switch';\nexport { Textarea } from './components/ui/form/Textarea';\n\n// UI - Overlay\nexport { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator } from './components/ui/overlay/Command';\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './components/ui/overlay/Dialog';\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } from './components/ui/overlay/Popover';\nexport { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from './components/ui/overlay/Sheet';\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './components/ui/overlay/Tooltip';\n\n// Store\nexport { useMdSidebarStore } from './store/useMdSidebarStore';\nexport { useModalManager } from './store/useModalManager';\nexport type { ModalData } from './store/useModalManager';\n\n// Enums\nexport { AccountSectionType } from './enums/AccountSectionType';\n\n// Hooks\nexport { default as usePasswordVisibility } from './hooks/usePasswordVisibility';\nexport { default as useCountdownTimer } from './hooks/useCountdownTimer';\nexport { default as useIsMobile } from './hooks/useIsMobile';\n\n// Utils\nexport { formatPhone, formatTimer, formatFullName, formatCPF, formatCardNumber } from './utils/format/masks';\nexport { timezoneService } from './modules/accounts/services/timezone.service';\nexport type { TimezoneOption } from './modules/accounts/services/timezone.service';\nexport { buildLocaleOptions, LANGUAGE_OPTIONS as LOCALE_LANGUAGE_OPTIONS } from './utils/intl/locales';\nexport type { LocaleOption } from './utils/intl/locales';\nexport { copyToClipboard, readFromClipboard } from './utils/browser/clipboard';\n\n// UI - Form (new widgets)\nexport { FormField } from './components/ui/form/FormField';\nexport { SelectField } from './components/ui/form/SelectField';\nexport { ComboboxField } from './components/ui/form/ComboboxField';\nexport type { ComboboxOption } from './components/ui/form/ComboboxField';\nexport { default as PhoneInput } from './components/ui/form/PhoneInput';\nexport { default as SwitchOptionFieldWithIcon } from './components/ui/form/SwitchOptionFieldWithIcon';\nexport { TextAreaField } from './components/ui/form/TextAreaField';\n\n// Account Module - Hooks\nexport {\n useUpdateAccount,\n useUpdateAccountUser,\n useUpdateAccountUserById,\n useDeleteAccountUser,\n useDeleteAccount,\n} from './modules/accounts/hooks/useAccountManagement';\n\n// Account Types\nexport type {\n UpdateAccountRequest,\n UpdateAccountUserRequest,\n ChangePasswordRequest,\n DeleteAccountActionResult,\n DeleteUserActionResult,\n UpdateAccountActionResult,\n UpdateUserActionResult,\n TwoFactorGenerateResult,\n TwoFactorActionResult,\n ContactResetResult,\n} from './modules/accounts/types';\n\nexport { default as AccountModals } from './components/account/AccountModals';\nexport { useAccountModals } from './store/useAccountModals';\nexport type { AccountModalsConfig } from './store/useAccountModals';\n\nexport { ModalManager } from './components/modals/ModalManager';\nexport { Modals } from './components/modals/Modals';\n\nexport { default as TwoFactorAuthModal } from './components/account/TwoFactorAuthModal';\nexport { default as DisableTwoFactorAuthModal } from './components/account/DisableTwoFactorAuthModal';\nexport { default as ConfirmGlobalPreferencesModal } from './components/account/ConfirmGlobalPreferencesModal';\nexport { MyProfileSection } from './components/account/sections/MyProfileSection';\nexport { PreferencesSection } from './components/account/sections/PreferencesSection';\nexport { SecuritySection } from './components/account/sections/SecuritySection';\nexport { ChangePasswordSection } from './components/account/sections/ChangePasswordSection';\nexport { ChangeEmailModal } from './components/account/sections/ChangeEmailModal';\nexport { ChangePhoneModal } from './components/account/sections/ChangePhoneModal';\n\n// Account Constants\nexport {\n GENDER_OPTIONS,\n CURRENCY_OPTIONS,\n TIME_FORMAT_OPTIONS,\n NOTIFICATION_TYPES,\n LANGUAGE_OPTIONS,\n} from './components/account/constants';\n"],"mappings":"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","names":["default","LANGUAGE_OPTIONS"]}
@@ -0,0 +1,9 @@
1
+ "use server";
2
+ import { projectUsersService } from "../services/project-users.service";
3
+ async function addProjectUserAction(params) {
4
+ return projectUsersService.addToProject(params);
5
+ }
6
+ export {
7
+ addProjectUserAction
8
+ };
9
+ //# sourceMappingURL=add-project-user.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/projects/actions/add-project-user.action.ts"],"sourcesContent":["'use server';\r\n\r\nimport { projectUsersService } from '../services/project-users.service';\r\nimport type { AddRemoveProjectUsersParams } from '../types';\r\n\r\nexport async function addProjectUserAction(params: AddRemoveProjectUsersParams): Promise<void> {\r\n return projectUsersService.addToProject(params);\r\n}\r\n"],"mappings":";AAEA,SAAS,2BAA2B;AAGpC,eAAsB,qBAAqB,QAAoD;AAC7F,SAAO,oBAAoB,aAAa,MAAM;AAChD;","names":[]}
@@ -0,0 +1,9 @@
1
+ "use server";
2
+ import { projectUsersService } from "../services/project-users.service";
3
+ async function listAvailableUsersAction(id_project) {
4
+ return projectUsersService.listNotInProject(id_project);
5
+ }
6
+ export {
7
+ listAvailableUsersAction
8
+ };
9
+ //# sourceMappingURL=list-available-users.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/projects/actions/list-available-users.action.ts"],"sourcesContent":["'use server';\r\n\r\nimport { projectUsersService } from '../services/project-users.service';\r\nimport type { AccountUser } from '../types';\r\n\r\nexport async function listAvailableUsersAction(id_project: number): Promise<AccountUser[]> {\r\n return projectUsersService.listNotInProject(id_project);\r\n}\r\n"],"mappings":";AAEA,SAAS,2BAA2B;AAGpC,eAAsB,yBAAyB,YAA4C;AACzF,SAAO,oBAAoB,iBAAiB,UAAU;AACxD;","names":[]}
@@ -0,0 +1,9 @@
1
+ "use server";
2
+ import { projectUsersService } from "../services/project-users.service";
3
+ async function listProjectUsersAction(id_project) {
4
+ return projectUsersService.listInProject(id_project);
5
+ }
6
+ export {
7
+ listProjectUsersAction
8
+ };
9
+ //# sourceMappingURL=list-project-users.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/projects/actions/list-project-users.action.ts"],"sourcesContent":["'use server';\r\n\r\nimport { projectUsersService } from '../services/project-users.service';\r\nimport type { ProjectUser } from '../types';\r\n\r\nexport async function listProjectUsersAction(id_project: number): Promise<ProjectUser[]> {\r\n return projectUsersService.listInProject(id_project);\r\n}\r\n"],"mappings":";AAEA,SAAS,2BAA2B;AAGpC,eAAsB,uBAAuB,YAA4C;AACvF,SAAO,oBAAoB,cAAc,UAAU;AACrD;","names":[]}
@@ -0,0 +1,9 @@
1
+ "use server";
2
+ import { projectUsersService } from "../services/project-users.service";
3
+ async function removeProjectUserAction(params) {
4
+ return projectUsersService.removeFromProject(params);
5
+ }
6
+ export {
7
+ removeProjectUserAction
8
+ };
9
+ //# sourceMappingURL=remove-project-user.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/projects/actions/remove-project-user.action.ts"],"sourcesContent":["'use server';\r\n\r\nimport { projectUsersService } from '../services/project-users.service';\r\nimport type { AddRemoveProjectUsersParams } from '../types';\r\n\r\nexport async function removeProjectUserAction(params: AddRemoveProjectUsersParams): Promise<void> {\r\n return projectUsersService.removeFromProject(params);\r\n}\r\n"],"mappings":";AAEA,SAAS,2BAA2B;AAGpC,eAAsB,wBAAwB,QAAoD;AAChG,SAAO,oBAAoB,kBAAkB,MAAM;AACrD;","names":[]}
@@ -0,0 +1,70 @@
1
+ "use client";
2
+ import { useMemo } from "react";
3
+ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
4
+ import { addProjectUserAction } from "../actions/add-project-user.action";
5
+ import { listAvailableUsersAction } from "../actions/list-available-users.action";
6
+ import { listProjectUsersAction } from "../actions/list-project-users.action";
7
+ import { removeProjectUserAction } from "../actions/remove-project-user.action";
8
+ const DEFAULT_AVATAR = "/images/Logomark.png";
9
+ const projectUsersQueryKey = (id_project) => ["project-users", id_project];
10
+ function useProjectUsers(id_project) {
11
+ const queryClient = useQueryClient();
12
+ const { data: inProject = [], isLoading: isLoadingIn } = useQuery({
13
+ queryKey: [...projectUsersQueryKey(id_project), "in"],
14
+ queryFn: () => listProjectUsersAction(id_project),
15
+ enabled: !!id_project
16
+ });
17
+ const { data: notInProject = [], isLoading: isLoadingOut } = useQuery({
18
+ queryKey: [...projectUsersQueryKey(id_project), "out"],
19
+ queryFn: () => listAvailableUsersAction(id_project),
20
+ enabled: !!id_project
21
+ });
22
+ const invalidate = () => {
23
+ queryClient.invalidateQueries({ queryKey: projectUsersQueryKey(id_project) });
24
+ };
25
+ const addMutation = useMutation({
26
+ mutationFn: (user_id) => addProjectUserAction({ id_project, users: [user_id] }),
27
+ onSuccess: invalidate
28
+ });
29
+ const removeMutation = useMutation({
30
+ mutationFn: (user_id) => removeProjectUserAction({ id_project, users: [user_id] }),
31
+ onSuccess: invalidate
32
+ });
33
+ const users = useMemo(
34
+ () => [
35
+ ...inProject.map((u) => ({
36
+ id: u.id_user,
37
+ name: u.name,
38
+ avatar: u.photo ?? DEFAULT_AVATAR,
39
+ checked: true
40
+ })),
41
+ ...notInProject.map((u) => ({
42
+ id: u.id,
43
+ name: u.name,
44
+ avatar: u.photo ?? DEFAULT_AVATAR,
45
+ checked: false
46
+ }))
47
+ ],
48
+ [inProject, notInProject]
49
+ );
50
+ const toggleUser = (id) => {
51
+ const user = users.find((u) => u.id === id);
52
+ if (!user) return;
53
+ if (user.checked) {
54
+ removeMutation.mutate(id);
55
+ } else {
56
+ addMutation.mutate(id);
57
+ }
58
+ };
59
+ return {
60
+ users,
61
+ isLoading: isLoadingIn || isLoadingOut,
62
+ userCount: inProject.length,
63
+ toggleUser
64
+ };
65
+ }
66
+ export {
67
+ projectUsersQueryKey,
68
+ useProjectUsers
69
+ };
70
+ //# sourceMappingURL=project-users.hook.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/projects/hooks/project-users.hook.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useMemo } from 'react';\r\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\r\n\r\nimport type { UserSelectorItem } from '../../../components/layouts/UsersSelectorPopover';\r\nimport { addProjectUserAction } from '../actions/add-project-user.action';\r\nimport { listAvailableUsersAction } from '../actions/list-available-users.action';\r\nimport { listProjectUsersAction } from '../actions/list-project-users.action';\r\nimport { removeProjectUserAction } from '../actions/remove-project-user.action';\r\n\r\nconst DEFAULT_AVATAR = '/images/Logomark.png';\r\n\r\nexport const projectUsersQueryKey = (id_project: number) => ['project-users', id_project];\r\n\r\nexport function useProjectUsers(id_project: number) {\r\n const queryClient = useQueryClient();\r\n\r\n const { data: inProject = [], isLoading: isLoadingIn } = useQuery({\r\n queryKey: [...projectUsersQueryKey(id_project), 'in'],\r\n queryFn: () => listProjectUsersAction(id_project),\r\n enabled: !!id_project,\r\n });\r\n\r\n const { data: notInProject = [], isLoading: isLoadingOut } = useQuery({\r\n queryKey: [...projectUsersQueryKey(id_project), 'out'],\r\n queryFn: () => listAvailableUsersAction(id_project),\r\n enabled: !!id_project,\r\n });\r\n\r\n const invalidate = () => {\r\n queryClient.invalidateQueries({ queryKey: projectUsersQueryKey(id_project) });\r\n };\r\n\r\n const addMutation = useMutation({\r\n mutationFn: (user_id: number) =>\r\n addProjectUserAction({ id_project, users: [user_id] }),\r\n onSuccess: invalidate,\r\n });\r\n\r\n const removeMutation = useMutation({\r\n mutationFn: (user_id: number) =>\r\n removeProjectUserAction({ id_project, users: [user_id] }),\r\n onSuccess: invalidate,\r\n });\r\n\r\n const users: UserSelectorItem[] = useMemo(\r\n () => [\r\n ...inProject.map((u) => ({\r\n id: u.id_user,\r\n name: u.name,\r\n avatar: u.photo ?? DEFAULT_AVATAR,\r\n checked: true,\r\n })),\r\n ...notInProject.map((u) => ({\r\n id: u.id,\r\n name: u.name,\r\n avatar: u.photo ?? DEFAULT_AVATAR,\r\n checked: false,\r\n })),\r\n ],\r\n [inProject, notInProject]\r\n );\r\n\r\n const toggleUser = (id: number) => {\r\n const user = users.find((u) => u.id === id);\r\n if (!user) return;\r\n if (user.checked) {\r\n removeMutation.mutate(id);\r\n } else {\r\n addMutation.mutate(id);\r\n }\r\n };\r\n\r\n return {\r\n users,\r\n isLoading: isLoadingIn || isLoadingOut,\r\n userCount: inProject.length,\r\n toggleUser,\r\n };\r\n}\r\n"],"mappings":";AAEA,SAAS,eAAe;AACxB,SAAS,aAAa,UAAU,sBAAsB;AAGtD,SAAS,4BAA4B;AACrC,SAAS,gCAAgC;AACzC,SAAS,8BAA8B;AACvC,SAAS,+BAA+B;AAExC,MAAM,iBAAiB;AAEhB,MAAM,uBAAuB,CAAC,eAAuB,CAAC,iBAAiB,UAAU;AAEjF,SAAS,gBAAgB,YAAoB;AAClD,QAAM,cAAc,eAAe;AAEnC,QAAM,EAAE,MAAM,YAAY,CAAC,GAAG,WAAW,YAAY,IAAI,SAAS;AAAA,IAChE,UAAU,CAAC,GAAG,qBAAqB,UAAU,GAAG,IAAI;AAAA,IACpD,SAAS,MAAM,uBAAuB,UAAU;AAAA,IAChD,SAAS,CAAC,CAAC;AAAA,EACb,CAAC;AAED,QAAM,EAAE,MAAM,eAAe,CAAC,GAAG,WAAW,aAAa,IAAI,SAAS;AAAA,IACpE,UAAU,CAAC,GAAG,qBAAqB,UAAU,GAAG,KAAK;AAAA,IACrD,SAAS,MAAM,yBAAyB,UAAU;AAAA,IAClD,SAAS,CAAC,CAAC;AAAA,EACb,CAAC;AAED,QAAM,aAAa,MAAM;AACvB,gBAAY,kBAAkB,EAAE,UAAU,qBAAqB,UAAU,EAAE,CAAC;AAAA,EAC9E;AAEA,QAAM,cAAc,YAAY;AAAA,IAC9B,YAAY,CAAC,YACX,qBAAqB,EAAE,YAAY,OAAO,CAAC,OAAO,EAAE,CAAC;AAAA,IACvD,WAAW;AAAA,EACb,CAAC;AAED,QAAM,iBAAiB,YAAY;AAAA,IACjC,YAAY,CAAC,YACX,wBAAwB,EAAE,YAAY,OAAO,CAAC,OAAO,EAAE,CAAC;AAAA,IAC1D,WAAW;AAAA,EACb,CAAC;AAED,QAAM,QAA4B;AAAA,IAChC,MAAM;AAAA,MACJ,GAAG,UAAU,IAAI,CAAC,OAAO;AAAA,QACvB,IAAI,EAAE;AAAA,QACN,MAAM,EAAE;AAAA,QACR,QAAQ,EAAE,SAAS;AAAA,QACnB,SAAS;AAAA,MACX,EAAE;AAAA,MACF,GAAG,aAAa,IAAI,CAAC,OAAO;AAAA,QAC1B,IAAI,EAAE;AAAA,QACN,MAAM,EAAE;AAAA,QACR,QAAQ,EAAE,SAAS;AAAA,QACnB,SAAS;AAAA,MACX,EAAE;AAAA,IACJ;AAAA,IACA,CAAC,WAAW,YAAY;AAAA,EAC1B;AAEA,QAAM,aAAa,CAAC,OAAe;AACjC,UAAM,OAAO,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC1C,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,SAAS;AAChB,qBAAe,OAAO,EAAE;AAAA,IAC1B,OAAO;AACL,kBAAY,OAAO,EAAE;AAAA,IACvB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAW,eAAe;AAAA,IAC1B,WAAW,UAAU;AAAA,IACrB;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,67 @@
1
+ import "server-only";
2
+ import { api } from "../../../infra/api/client";
3
+ import { ApiError } from "../../../infra/api/types";
4
+ import { getUserContext } from "../../auth/utils/get-user-context";
5
+ import {
6
+ AccountUserSchema,
7
+ ProjectUserSchema
8
+ } from "../types";
9
+ class ProjectUsersService {
10
+ async listInProject(id_project) {
11
+ const { id_account, id_user } = await getUserContext();
12
+ const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;
13
+ const response = await api.pages.get(url);
14
+ if (response.status === 0) {
15
+ throw new ApiError(
16
+ response.message || "Erro ao listar usu\xE1rios do projeto",
17
+ "LIST_PROJECT_USERS_FAILED",
18
+ 400
19
+ );
20
+ }
21
+ return response.data.map((item) => ProjectUserSchema.parse(item));
22
+ }
23
+ async listNotInProject(id_project) {
24
+ const { id_account } = await getUserContext();
25
+ const url = `/accounts/${id_account}/users?notInProject=${id_project}`;
26
+ const response = await api.apps.get(url);
27
+ if (response.status === 0) {
28
+ throw new ApiError(
29
+ response.message || "Erro ao listar usu\xE1rios dispon\xEDveis",
30
+ "LIST_AVAILABLE_USERS_FAILED",
31
+ 400
32
+ );
33
+ }
34
+ return response.data.map((item) => AccountUserSchema.parse(item));
35
+ }
36
+ async addToProject({ id_project, users }) {
37
+ const { id_account, id_user } = await getUserContext();
38
+ const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;
39
+ const response = await api.pages.post(url, { users });
40
+ if (response.status === 0) {
41
+ throw new ApiError(
42
+ response.message || "Erro ao adicionar usu\xE1rio ao projeto",
43
+ "ADD_PROJECT_USER_FAILED",
44
+ 400
45
+ );
46
+ }
47
+ }
48
+ async removeFromProject({ id_project, users }) {
49
+ const { id_account, id_user } = await getUserContext();
50
+ const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;
51
+ const response = await api.pages.delete(url, {
52
+ body: JSON.stringify({ users })
53
+ });
54
+ if (response.status === 0) {
55
+ throw new ApiError(
56
+ response.message || "Erro ao remover usu\xE1rio do projeto",
57
+ "REMOVE_PROJECT_USER_FAILED",
58
+ 400
59
+ );
60
+ }
61
+ }
62
+ }
63
+ const projectUsersService = new ProjectUsersService();
64
+ export {
65
+ projectUsersService
66
+ };
67
+ //# sourceMappingURL=project-users.service.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/projects/services/project-users.service.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport { api } from '../../../infra/api/client';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { getUserContext } from '../../auth/utils/get-user-context';\r\nimport {\r\n AccountUser,\r\n AccountUserSchema,\r\n AddRemoveProjectUsersParams,\r\n ProjectUser,\r\n ProjectUserSchema,\r\n} from '../types';\r\n\r\ninterface ApiListResponse<T> {\r\n data: T[];\r\n total: number;\r\n status: number;\r\n message?: string;\r\n}\r\n\r\ninterface ApiActionResponse {\r\n status: number;\r\n message?: string;\r\n}\r\n\r\nclass ProjectUsersService {\r\n async listInProject(id_project: number): Promise<ProjectUser[]> {\r\n const { id_account, id_user } = await getUserContext();\r\n const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;\r\n\r\n const response = await api.pages.get<ApiListResponse<ProjectUser>>(url);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || 'Erro ao listar usuários do projeto',\r\n 'LIST_PROJECT_USERS_FAILED',\r\n 400\r\n );\r\n }\r\n\r\n return response.data.map((item) => ProjectUserSchema.parse(item));\r\n }\r\n\r\n async listNotInProject(id_project: number): Promise<AccountUser[]> {\r\n const { id_account } = await getUserContext();\r\n const url = `/accounts/${id_account}/users?notInProject=${id_project}`;\r\n\r\n const response = await api.apps.get<ApiListResponse<AccountUser>>(url);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || 'Erro ao listar usuários disponíveis',\r\n 'LIST_AVAILABLE_USERS_FAILED',\r\n 400\r\n );\r\n }\r\n\r\n return response.data.map((item) => AccountUserSchema.parse(item));\r\n }\r\n\r\n async addToProject({ id_project, users }: AddRemoveProjectUsersParams): Promise<void> {\r\n const { id_account, id_user } = await getUserContext();\r\n const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;\r\n\r\n const response = await api.pages.post<ApiActionResponse>(url, { users });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || 'Erro ao adicionar usuário ao projeto',\r\n 'ADD_PROJECT_USER_FAILED',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n async removeFromProject({ id_project, users }: AddRemoveProjectUsersParams): Promise<void> {\r\n const { id_account, id_user } = await getUserContext();\r\n const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;\r\n\r\n const response = await api.pages.delete<ApiActionResponse>(url, {\r\n body: JSON.stringify({ users }),\r\n });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || 'Erro ao remover usuário do projeto',\r\n 'REMOVE_PROJECT_USER_FAILED',\r\n 400\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport const projectUsersService = new ProjectUsersService();\r\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,WAAW;AACpB,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AAC/B;AAAA,EAEE;AAAA,EAGA;AAAA,OACK;AAcP,MAAM,oBAAoB;AAAA,EACxB,MAAM,cAAc,YAA4C;AAC9D,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AACrD,UAAM,MAAM,YAAY,UAAU,SAAS,OAAO,aAAa,UAAU;AAEzE,UAAM,WAAW,MAAM,IAAI,MAAM,IAAkC,GAAG;AAEtE,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,WAAO,SAAS,KAAK,IAAI,CAAC,SAAS,kBAAkB,MAAM,IAAI,CAAC;AAAA,EAClE;AAAA,EAEA,MAAM,iBAAiB,YAA4C;AACjE,UAAM,EAAE,WAAW,IAAI,MAAM,eAAe;AAC5C,UAAM,MAAM,aAAa,UAAU,uBAAuB,UAAU;AAEpE,UAAM,WAAW,MAAM,IAAI,KAAK,IAAkC,GAAG;AAErE,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,WAAO,SAAS,KAAK,IAAI,CAAC,SAAS,kBAAkB,MAAM,IAAI,CAAC;AAAA,EAClE;AAAA,EAEA,MAAM,aAAa,EAAE,YAAY,MAAM,GAA+C;AACpF,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AACrD,UAAM,MAAM,YAAY,UAAU,SAAS,OAAO,aAAa,UAAU;AAEzE,UAAM,WAAW,MAAM,IAAI,MAAM,KAAwB,KAAK,EAAE,MAAM,CAAC;AAEvE,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB,EAAE,YAAY,MAAM,GAA+C;AACzF,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AACrD,UAAM,MAAM,YAAY,UAAU,SAAS,OAAO,aAAa,UAAU;AAEzE,UAAM,WAAW,MAAM,IAAI,MAAM,OAA0B,KAAK;AAAA,MAC9D,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;AAAA,IAChC,CAAC;AAED,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,MAAM,sBAAsB,IAAI,oBAAoB;","names":[]}
@@ -0,0 +1,22 @@
1
+ import { z } from "zod";
2
+ const ProjectUserSchema = z.object({
3
+ id_user: z.union([z.number(), z.string()]).transform(Number),
4
+ id_account: z.union([z.number(), z.string()]).transform(Number),
5
+ id_project: z.union([z.number(), z.string()]).transform(Number),
6
+ name: z.string(),
7
+ email: z.string(),
8
+ profile: z.string().optional(),
9
+ photo: z.string().nullable().optional()
10
+ });
11
+ const AccountUserSchema = z.object({
12
+ id: z.union([z.number(), z.string()]).transform(Number),
13
+ name: z.string(),
14
+ email: z.string(),
15
+ profile: z.string().optional(),
16
+ photo: z.string().nullable().optional()
17
+ });
18
+ export {
19
+ AccountUserSchema,
20
+ ProjectUserSchema
21
+ };
22
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/modules/projects/types.ts"],"sourcesContent":["import { z } from 'zod';\r\n\r\nexport const ProjectUserSchema = z.object({\r\n id_user: z.union([z.number(), z.string()]).transform(Number),\r\n id_account: z.union([z.number(), z.string()]).transform(Number),\r\n id_project: z.union([z.number(), z.string()]).transform(Number),\r\n name: z.string(),\r\n email: z.string(),\r\n profile: z.string().optional(),\r\n photo: z.string().nullable().optional(),\r\n});\r\n\r\nexport type ProjectUser = z.infer<typeof ProjectUserSchema>;\r\n\r\nexport const AccountUserSchema = z.object({\r\n id: z.union([z.number(), z.string()]).transform(Number),\r\n name: z.string(),\r\n email: z.string(),\r\n profile: z.string().optional(),\r\n photo: z.string().nullable().optional(),\r\n});\r\n\r\nexport type AccountUser = z.infer<typeof AccountUserSchema>;\r\n\r\nexport interface AddRemoveProjectUsersParams {\r\n id_project: number;\r\n users: number[];\r\n}\r\n"],"mappings":"AAAA,SAAS,SAAS;AAEX,MAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,SAAS,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,UAAU,MAAM;AAAA,EAC3D,YAAY,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,UAAU,MAAM;AAAA,EAC9D,YAAY,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,UAAU,MAAM;AAAA,EAC9D,MAAM,EAAE,OAAO;AAAA,EACf,OAAO,EAAE,OAAO;AAAA,EAChB,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AACxC,CAAC;AAIM,MAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,UAAU,MAAM;AAAA,EACtD,MAAM,EAAE,OAAO;AAAA,EACf,OAAO,EAAE,OAAO;AAAA,EAChB,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AACxC,CAAC;","names":[]}
package/dist/server.mjs CHANGED
@@ -8,6 +8,11 @@ import { findWhitelabel } from "./modules/whitelabel/actions/find-whitelabel.act
8
8
  import { validateSessionAction } from "./modules/auth/actions/validate-session.action";
9
9
  import { listSubscriptionsAction } from "./modules/subscriptions/actions/list-subscriptions.action";
10
10
  import { listIaCreditsAction } from "./modules/ia-credits/actions/list-ia-credits.action";
11
+ import { projectUsersService } from "./modules/projects/services/project-users.service";
12
+ import { listProjectUsersAction } from "./modules/projects/actions/list-project-users.action";
13
+ import { listAvailableUsersAction } from "./modules/projects/actions/list-available-users.action";
14
+ import { addProjectUserAction } from "./modules/projects/actions/add-project-user.action";
15
+ import { removeProjectUserAction } from "./modules/projects/actions/remove-project-user.action";
11
16
  import { accountService } from "./modules/accounts/services/account.service";
12
17
  import { twoFactorService } from "./modules/accounts/services/two-factor.service";
13
18
  import {
@@ -32,6 +37,7 @@ import { getUserContext } from "./modules/auth/utils/get-user-context";
32
37
  export {
33
38
  ApiClient,
34
39
  accountService,
40
+ addProjectUserAction,
35
41
  api,
36
42
  apiClient,
37
43
  authService,
@@ -49,8 +55,12 @@ export {
49
55
  getUserContext,
50
56
  iaCreditsService,
51
57
  listAccountUsersAction,
58
+ listAvailableUsersAction,
52
59
  listIaCreditsAction,
60
+ listProjectUsersAction,
53
61
  listSubscriptionsAction,
62
+ projectUsersService,
63
+ removeProjectUserAction,
54
64
  requestEmailChangeAction,
55
65
  requestPhoneChangeAction,
56
66
  subscriptionsService,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only';\r\n\r\n// API Client\r\nexport { ApiClient, api, apiClient } from './infra/api/client';\r\n\r\n// Services\r\nexport { authService } from './modules/auth/services/auth.service';\r\nexport { whitelabelService } from './modules/whitelabel/services/whitelabel.service';\r\nexport { subscriptionsService } from './modules/subscriptions/services/subscriptions.service';\r\nexport { iaCreditsService } from './modules/ia-credits/services/ia-credits.service';\r\n\r\n// Actions\r\nexport { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';\r\nexport { validateSessionAction } from './modules/auth/actions/validate-session.action';\r\nexport { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';\r\nexport { listIaCreditsAction } from './modules/ia-credits/actions/list-ia-credits.action';\r\n\r\n// Account Services & Actions (server-only)\r\nexport { accountService } from './modules/accounts/services/account.service';\r\nexport { twoFactorService } from './modules/accounts/services/two-factor.service';\r\nexport {\r\n listAccountUsersAction,\r\n updateUserAction,\r\n updateAccountAction,\r\n updateAccountUserByIdAction,\r\n deleteAccountUserAction,\r\n deleteAccountAction,\r\n createAccountUserAction,\r\n changePasswordAction,\r\n requestEmailChangeAction,\r\n confirmEmailChangeAction,\r\n requestPhoneChangeAction,\r\n confirmPhoneChangeAction,\r\n generateTwoFactorAction,\r\n confirmTwoFactorAction,\r\n disableTwoFactorAction,\r\n} from './modules/accounts/actions/account-management.action';\r\n\r\n// Server Utils\r\nexport { getClientInfoFromRequest } from './infra/utils/client-info';\r\nexport { getUserContext } from './modules/auth/utils/get-user-context';\r\n"],"mappings":"AAAA,OAAO;AAGP,SAAS,WAAW,KAAK,iBAAiB;AAG1C,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,wBAAwB;AAGjC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,2BAA2B;AAGpC,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;","names":[]}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import 'server-only';\r\n\r\n// API Client\r\nexport { ApiClient, api, apiClient } from './infra/api/client';\r\n\r\n// Services\r\nexport { authService } from './modules/auth/services/auth.service';\r\nexport { whitelabelService } from './modules/whitelabel/services/whitelabel.service';\r\nexport { subscriptionsService } from './modules/subscriptions/services/subscriptions.service';\r\nexport { iaCreditsService } from './modules/ia-credits/services/ia-credits.service';\r\n\r\n// Actions\r\nexport { findWhitelabel } from './modules/whitelabel/actions/find-whitelabel.action';\r\nexport { validateSessionAction } from './modules/auth/actions/validate-session.action';\r\nexport { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';\r\nexport { listIaCreditsAction } from './modules/ia-credits/actions/list-ia-credits.action';\r\n\r\n// Project Users Services & Actions (server-only)\r\nexport { projectUsersService } from './modules/projects/services/project-users.service';\r\nexport { listProjectUsersAction } from './modules/projects/actions/list-project-users.action';\r\nexport { listAvailableUsersAction } from './modules/projects/actions/list-available-users.action';\r\nexport { addProjectUserAction } from './modules/projects/actions/add-project-user.action';\r\nexport { removeProjectUserAction } from './modules/projects/actions/remove-project-user.action';\r\n\r\n// Account Services & Actions (server-only)\r\nexport { accountService } from './modules/accounts/services/account.service';\r\nexport { twoFactorService } from './modules/accounts/services/two-factor.service';\r\nexport {\r\n listAccountUsersAction,\r\n updateUserAction,\r\n updateAccountAction,\r\n updateAccountUserByIdAction,\r\n deleteAccountUserAction,\r\n deleteAccountAction,\r\n createAccountUserAction,\r\n changePasswordAction,\r\n requestEmailChangeAction,\r\n confirmEmailChangeAction,\r\n requestPhoneChangeAction,\r\n confirmPhoneChangeAction,\r\n generateTwoFactorAction,\r\n confirmTwoFactorAction,\r\n disableTwoFactorAction,\r\n} from './modules/accounts/actions/account-management.action';\r\n\r\n// Server Utils\r\nexport { getClientInfoFromRequest } from './infra/utils/client-info';\r\nexport { getUserContext } from './modules/auth/utils/get-user-context';\r\n"],"mappings":"AAAA,OAAO;AAGP,SAAS,WAAW,KAAK,iBAAiB;AAG1C,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,wBAAwB;AAGjC,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AACtC,SAAS,+BAA+B;AACxC,SAAS,2BAA2B;AAGpC,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,gCAAgC;AACzC,SAAS,4BAA4B;AACrC,SAAS,+BAA+B;AAGxC,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,gCAAgC;AACzC,SAAS,sBAAsB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/common",
3
- "version": "1.1.47",
3
+ "version": "1.1.49",
4
4
  "description": "Shared library for GreatApps frontend applications",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./src/index.ts",
@@ -1,7 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import { useState } from 'react';
4
- import { Plus, Settings, User } from 'lucide-react';
4
+ import { Plus, Settings, User, Users } from 'lucide-react';
5
5
  import Image from 'next/image';
6
6
  import { useRouter } from 'next/navigation';
7
7
  import { Popover, PopoverContent, PopoverTrigger } from '../ui/overlay/Popover';
@@ -10,6 +10,7 @@ import { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from '.
10
10
  import { Checkbox } from '../ui/form/Checkbox';
11
11
  import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';
12
12
  import { cn } from '../../infra/utils/clsx';
13
+ import { useProjectUsers } from '../../modules/projects/hooks/project-users.hook';
13
14
 
14
15
  export interface UserSelectorItem {
15
16
  id: number;
@@ -18,7 +19,20 @@ export interface UserSelectorItem {
18
19
  checked: boolean;
19
20
  }
20
21
 
22
+ function UserItemSkeleton() {
23
+ return (
24
+ <div className="flex items-center justify-between px-2 py-1.5 gap-2">
25
+ <div className="flex items-center gap-2 flex-1">
26
+ <div className="size-8 rounded-full bg-gray-100 animate-pulse shrink-0" />
27
+ <div className="h-3.5 w-28 rounded bg-gray-100 animate-pulse" />
28
+ </div>
29
+ <div className="size-4 rounded bg-gray-100 animate-pulse shrink-0" />
30
+ </div>
31
+ );
32
+ }
33
+
21
34
  export interface UsersSelectorPopoverProps {
35
+ projectId?: number;
22
36
  users?: UserSelectorItem[];
23
37
  onToggleUser?: (id: number) => void;
24
38
  addRoute?: string;
@@ -29,33 +43,33 @@ export interface UsersSelectorPopoverProps {
29
43
  contentClassName?: string;
30
44
  }
31
45
 
32
- function UsersSelectorPopover({
33
- users: externalUsers,
34
- onToggleUser,
35
- addRoute = '/my-teams?createNew=true',
36
- manageRoute = '/my-teams',
37
- userCount = 5,
46
+ interface ContentProps {
47
+ users: UserSelectorItem[];
48
+ isLoading: boolean;
49
+ userCount: number;
50
+ toggleUser: (id: number) => void;
51
+ addRoute: string;
52
+ manageRoute: string;
53
+ side?: UsersSelectorPopoverProps['side'];
54
+ align?: UsersSelectorPopoverProps['align'];
55
+ contentClassName?: string;
56
+ }
57
+
58
+ function UsersSelectorPopoverContent({
59
+ users,
60
+ isLoading,
61
+ userCount,
62
+ toggleUser,
63
+ addRoute,
64
+ manageRoute,
38
65
  side,
39
66
  align,
40
67
  contentClassName,
41
- }: UsersSelectorPopoverProps) {
68
+ }: ContentProps) {
42
69
  const route = useRouter();
43
70
  const [open, setOpen] = useState(false);
44
- const [internalUsers, setInternalUsers] = useState<UserSelectorItem[]>(externalUsers ?? []);
45
71
  const [hoveredId, setHoveredId] = useState<number | null>(null);
46
72
 
47
- const users = externalUsers ?? internalUsers;
48
-
49
- const toggleUser = (id: number) => {
50
- if (onToggleUser) {
51
- onToggleUser(id);
52
- } else {
53
- setInternalUsers((prev) =>
54
- prev.map((u) => (u.id === id ? { ...u, checked: !u.checked } : u))
55
- );
56
- }
57
- };
58
-
59
73
  return (
60
74
  <Popover open={open} onOpenChange={setOpen}>
61
75
  <PopoverTrigger className="cursor-pointer">
@@ -86,7 +100,6 @@ function UsersSelectorPopover({
86
100
  <Plus size={16} />
87
101
  Adicionar
88
102
  </Button>
89
-
90
103
  <Tooltip>
91
104
  <TooltipTrigger asChild>
92
105
  <Button
@@ -105,48 +118,67 @@ function UsersSelectorPopover({
105
118
  <Command className="gap-2" value="">
106
119
  <CommandInput placeholder="Busque aqui" />
107
120
  <CommandList className="custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]">
108
- <CommandEmpty>No results found.</CommandEmpty>
109
- {users.map((user) => (
110
- <CommandItem
111
- key={user.id}
112
- autoFocus={false}
113
- onPointerEnter={() => setHoveredId(user.id)}
114
- onPointerLeave={() => setHoveredId(null)}
115
- onFocus={() => setHoveredId(user.id)}
116
- onBlur={() => setHoveredId(null)}
117
- onSelect={() => toggleUser(user.id)}
118
- className="cursor-pointer"
119
- >
120
- <div className="flex items-center justify-between w-full">
121
- <div className="flex items-center gap-2">
122
- <Image
123
- alt="Avatar"
124
- src={user.avatar}
125
- width={32}
126
- height={32}
127
- className="rounded-full"
128
- />
129
- {user.name}
130
- </div>
131
-
132
- <Tooltip open={hoveredId === user.id}>
133
- <TooltipTrigger
134
- onClick={(e) => e.stopPropagation()}
135
- onPointerDown={(e) => e.stopPropagation()}
136
- >
137
- <Checkbox
138
- checked={user.checked}
139
- onCheckedChange={() => toggleUser(user.id)}
140
- className={hoveredId === user.id ? 'border-gray-950' : ''}
141
- />
142
- </TooltipTrigger>
143
- <TooltipContent>
144
- {user.checked ? 'Remover do projeto' : 'Adicionar ao projeto'}
145
- </TooltipContent>
146
- </Tooltip>
147
- </div>
148
- </CommandItem>
149
- ))}
121
+ {isLoading ? (
122
+ <>
123
+ <UserItemSkeleton />
124
+ <UserItemSkeleton />
125
+ <UserItemSkeleton />
126
+ </>
127
+ ) : users.length === 0 ? (
128
+ <div className="flex flex-col items-center justify-center gap-2 h-full text-gray-400 py-4">
129
+ <Users size={28} className="text-gray-300" />
130
+ <span className="paragraph-small-medium text-center text-gray-500">
131
+ Nenhum usuário neste projeto.
132
+ <br />
133
+ Adicione um usuário para começar.
134
+ </span>
135
+ </div>
136
+ ) : (
137
+ <>
138
+ <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
139
+ {users.map((user) => (
140
+ <CommandItem
141
+ key={user.id}
142
+ value={user.name}
143
+ autoFocus={false}
144
+ onPointerEnter={() => setHoveredId(user.id)}
145
+ onPointerLeave={() => setHoveredId(null)}
146
+ onFocus={() => setHoveredId(user.id)}
147
+ onBlur={() => setHoveredId(null)}
148
+ onSelect={() => toggleUser(user.id)}
149
+ className="cursor-pointer"
150
+ >
151
+ <div className="flex items-center justify-between w-full">
152
+ <div className="flex items-center gap-2">
153
+ <Image
154
+ alt="Avatar"
155
+ src={user.avatar}
156
+ width={32}
157
+ height={32}
158
+ className="rounded-full"
159
+ />
160
+ {user.name}
161
+ </div>
162
+ <Tooltip open={hoveredId === user.id}>
163
+ <TooltipTrigger
164
+ onClick={(e) => e.stopPropagation()}
165
+ onPointerDown={(e) => e.stopPropagation()}
166
+ >
167
+ <Checkbox
168
+ checked={user.checked}
169
+ onCheckedChange={() => toggleUser(user.id)}
170
+ className={hoveredId === user.id ? 'border-gray-950' : ''}
171
+ />
172
+ </TooltipTrigger>
173
+ <TooltipContent>
174
+ {user.checked ? 'Remover do projeto' : 'Adicionar ao projeto'}
175
+ </TooltipContent>
176
+ </Tooltip>
177
+ </div>
178
+ </CommandItem>
179
+ ))}
180
+ </>
181
+ )}
150
182
  </CommandList>
151
183
  </Command>
152
184
  </div>
@@ -155,4 +187,75 @@ function UsersSelectorPopover({
155
187
  );
156
188
  }
157
189
 
190
+ function ConnectedUsersSelectorPopover({
191
+ projectId,
192
+ addRoute,
193
+ manageRoute,
194
+ side,
195
+ align,
196
+ contentClassName,
197
+ }: Required<Pick<UsersSelectorPopoverProps, 'projectId'>> &
198
+ Pick<UsersSelectorPopoverProps, 'addRoute' | 'manageRoute' | 'side' | 'align' | 'contentClassName'>) {
199
+ const { users, isLoading, userCount, toggleUser } = useProjectUsers(projectId);
200
+ return (
201
+ <UsersSelectorPopoverContent
202
+ users={users}
203
+ isLoading={isLoading}
204
+ userCount={userCount}
205
+ toggleUser={toggleUser}
206
+ addRoute={addRoute ?? '/my-teams?createNew=true'}
207
+ manageRoute={manageRoute ?? '/my-teams'}
208
+ side={side}
209
+ align={align}
210
+ contentClassName={contentClassName}
211
+ />
212
+ );
213
+ }
214
+
215
+ function StaticUsersSelectorPopover({
216
+ users: externalUsers = [],
217
+ onToggleUser,
218
+ userCount = 5,
219
+ addRoute = '/my-teams?createNew=true',
220
+ manageRoute = '/my-teams',
221
+ side,
222
+ align,
223
+ contentClassName,
224
+ }: Omit<UsersSelectorPopoverProps, 'projectId'>) {
225
+ const [internalUsers, setInternalUsers] = useState<UserSelectorItem[]>(externalUsers);
226
+
227
+ const users = externalUsers.length > 0 ? externalUsers : internalUsers;
228
+
229
+ const toggleUser = (id: number) => {
230
+ if (onToggleUser) {
231
+ onToggleUser(id);
232
+ } else {
233
+ setInternalUsers((prev) =>
234
+ prev.map((u) => (u.id === id ? { ...u, checked: !u.checked } : u))
235
+ );
236
+ }
237
+ };
238
+
239
+ return (
240
+ <UsersSelectorPopoverContent
241
+ users={users}
242
+ isLoading={false}
243
+ userCount={userCount}
244
+ toggleUser={toggleUser}
245
+ addRoute={addRoute}
246
+ manageRoute={manageRoute}
247
+ side={side}
248
+ align={align}
249
+ contentClassName={contentClassName}
250
+ />
251
+ );
252
+ }
253
+
254
+ function UsersSelectorPopover(props: UsersSelectorPopoverProps) {
255
+ if (props.projectId != null) {
256
+ return <ConnectedUsersSelectorPopover {...props} projectId={props.projectId} />;
257
+ }
258
+ return <StaticUsersSelectorPopover {...props} />;
259
+ }
260
+
158
261
  export { UsersSelectorPopover };
package/src/index.ts CHANGED
@@ -10,6 +10,8 @@ export * from './providers/auth.provider';
10
10
  export * from './providers/whitelabel.provider';
11
11
 
12
12
  // Hooks
13
+ export { useProjectUsers, projectUsersQueryKey } from './modules/projects/hooks/project-users.hook';
14
+ export type { ProjectUser, AccountUser, AddRemoveProjectUsersParams } from './modules/projects/types';
13
15
  export { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';
14
16
  export { useSubscriptions, SUBSCRIPTIONS_QUERY_KEY } from './modules/subscriptions/hooks/list-subscriptions.hook';
15
17
  export { useActiveSubscription } from './modules/subscriptions/hooks/find-active-subscription.hook';
@@ -0,0 +1,8 @@
1
+ 'use server';
2
+
3
+ import { projectUsersService } from '../services/project-users.service';
4
+ import type { AddRemoveProjectUsersParams } from '../types';
5
+
6
+ export async function addProjectUserAction(params: AddRemoveProjectUsersParams): Promise<void> {
7
+ return projectUsersService.addToProject(params);
8
+ }
@@ -0,0 +1,8 @@
1
+ 'use server';
2
+
3
+ import { projectUsersService } from '../services/project-users.service';
4
+ import type { AccountUser } from '../types';
5
+
6
+ export async function listAvailableUsersAction(id_project: number): Promise<AccountUser[]> {
7
+ return projectUsersService.listNotInProject(id_project);
8
+ }
@@ -0,0 +1,8 @@
1
+ 'use server';
2
+
3
+ import { projectUsersService } from '../services/project-users.service';
4
+ import type { ProjectUser } from '../types';
5
+
6
+ export async function listProjectUsersAction(id_project: number): Promise<ProjectUser[]> {
7
+ return projectUsersService.listInProject(id_project);
8
+ }
@@ -0,0 +1,8 @@
1
+ 'use server';
2
+
3
+ import { projectUsersService } from '../services/project-users.service';
4
+ import type { AddRemoveProjectUsersParams } from '../types';
5
+
6
+ export async function removeProjectUserAction(params: AddRemoveProjectUsersParams): Promise<void> {
7
+ return projectUsersService.removeFromProject(params);
8
+ }
@@ -0,0 +1,81 @@
1
+ 'use client';
2
+
3
+ import { useMemo } from 'react';
4
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
5
+
6
+ import type { UserSelectorItem } from '../../../components/layouts/UsersSelectorPopover';
7
+ import { addProjectUserAction } from '../actions/add-project-user.action';
8
+ import { listAvailableUsersAction } from '../actions/list-available-users.action';
9
+ import { listProjectUsersAction } from '../actions/list-project-users.action';
10
+ import { removeProjectUserAction } from '../actions/remove-project-user.action';
11
+
12
+ const DEFAULT_AVATAR = '/images/Logomark.png';
13
+
14
+ export const projectUsersQueryKey = (id_project: number) => ['project-users', id_project];
15
+
16
+ export function useProjectUsers(id_project: number) {
17
+ const queryClient = useQueryClient();
18
+
19
+ const { data: inProject = [], isLoading: isLoadingIn } = useQuery({
20
+ queryKey: [...projectUsersQueryKey(id_project), 'in'],
21
+ queryFn: () => listProjectUsersAction(id_project),
22
+ enabled: !!id_project,
23
+ });
24
+
25
+ const { data: notInProject = [], isLoading: isLoadingOut } = useQuery({
26
+ queryKey: [...projectUsersQueryKey(id_project), 'out'],
27
+ queryFn: () => listAvailableUsersAction(id_project),
28
+ enabled: !!id_project,
29
+ });
30
+
31
+ const invalidate = () => {
32
+ queryClient.invalidateQueries({ queryKey: projectUsersQueryKey(id_project) });
33
+ };
34
+
35
+ const addMutation = useMutation({
36
+ mutationFn: (user_id: number) =>
37
+ addProjectUserAction({ id_project, users: [user_id] }),
38
+ onSuccess: invalidate,
39
+ });
40
+
41
+ const removeMutation = useMutation({
42
+ mutationFn: (user_id: number) =>
43
+ removeProjectUserAction({ id_project, users: [user_id] }),
44
+ onSuccess: invalidate,
45
+ });
46
+
47
+ const users: UserSelectorItem[] = useMemo(
48
+ () => [
49
+ ...inProject.map((u) => ({
50
+ id: u.id_user,
51
+ name: u.name,
52
+ avatar: u.photo ?? DEFAULT_AVATAR,
53
+ checked: true,
54
+ })),
55
+ ...notInProject.map((u) => ({
56
+ id: u.id,
57
+ name: u.name,
58
+ avatar: u.photo ?? DEFAULT_AVATAR,
59
+ checked: false,
60
+ })),
61
+ ],
62
+ [inProject, notInProject]
63
+ );
64
+
65
+ const toggleUser = (id: number) => {
66
+ const user = users.find((u) => u.id === id);
67
+ if (!user) return;
68
+ if (user.checked) {
69
+ removeMutation.mutate(id);
70
+ } else {
71
+ addMutation.mutate(id);
72
+ }
73
+ };
74
+
75
+ return {
76
+ users,
77
+ isLoading: isLoadingIn || isLoadingOut,
78
+ userCount: inProject.length,
79
+ toggleUser,
80
+ };
81
+ }
@@ -0,0 +1,94 @@
1
+ import 'server-only';
2
+
3
+ import { api } from '../../../infra/api/client';
4
+ import { ApiError } from '../../../infra/api/types';
5
+ import { getUserContext } from '../../auth/utils/get-user-context';
6
+ import {
7
+ AccountUser,
8
+ AccountUserSchema,
9
+ AddRemoveProjectUsersParams,
10
+ ProjectUser,
11
+ ProjectUserSchema,
12
+ } from '../types';
13
+
14
+ interface ApiListResponse<T> {
15
+ data: T[];
16
+ total: number;
17
+ status: number;
18
+ message?: string;
19
+ }
20
+
21
+ interface ApiActionResponse {
22
+ status: number;
23
+ message?: string;
24
+ }
25
+
26
+ class ProjectUsersService {
27
+ async listInProject(id_project: number): Promise<ProjectUser[]> {
28
+ const { id_account, id_user } = await getUserContext();
29
+ const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;
30
+
31
+ const response = await api.pages.get<ApiListResponse<ProjectUser>>(url);
32
+
33
+ if (response.status === 0) {
34
+ throw new ApiError(
35
+ response.message || 'Erro ao listar usuários do projeto',
36
+ 'LIST_PROJECT_USERS_FAILED',
37
+ 400
38
+ );
39
+ }
40
+
41
+ return response.data.map((item) => ProjectUserSchema.parse(item));
42
+ }
43
+
44
+ async listNotInProject(id_project: number): Promise<AccountUser[]> {
45
+ const { id_account } = await getUserContext();
46
+ const url = `/accounts/${id_account}/users?notInProject=${id_project}`;
47
+
48
+ const response = await api.apps.get<ApiListResponse<AccountUser>>(url);
49
+
50
+ if (response.status === 0) {
51
+ throw new ApiError(
52
+ response.message || 'Erro ao listar usuários disponíveis',
53
+ 'LIST_AVAILABLE_USERS_FAILED',
54
+ 400
55
+ );
56
+ }
57
+
58
+ return response.data.map((item) => AccountUserSchema.parse(item));
59
+ }
60
+
61
+ async addToProject({ id_project, users }: AddRemoveProjectUsersParams): Promise<void> {
62
+ const { id_account, id_user } = await getUserContext();
63
+ const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;
64
+
65
+ const response = await api.pages.post<ApiActionResponse>(url, { users });
66
+
67
+ if (response.status === 0) {
68
+ throw new ApiError(
69
+ response.message || 'Erro ao adicionar usuário ao projeto',
70
+ 'ADD_PROJECT_USER_FAILED',
71
+ 400
72
+ );
73
+ }
74
+ }
75
+
76
+ async removeFromProject({ id_project, users }: AddRemoveProjectUsersParams): Promise<void> {
77
+ const { id_account, id_user } = await getUserContext();
78
+ const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;
79
+
80
+ const response = await api.pages.delete<ApiActionResponse>(url, {
81
+ body: JSON.stringify({ users }),
82
+ });
83
+
84
+ if (response.status === 0) {
85
+ throw new ApiError(
86
+ response.message || 'Erro ao remover usuário do projeto',
87
+ 'REMOVE_PROJECT_USER_FAILED',
88
+ 400
89
+ );
90
+ }
91
+ }
92
+ }
93
+
94
+ export const projectUsersService = new ProjectUsersService();
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod';
2
+
3
+ export const ProjectUserSchema = z.object({
4
+ id_user: z.union([z.number(), z.string()]).transform(Number),
5
+ id_account: z.union([z.number(), z.string()]).transform(Number),
6
+ id_project: z.union([z.number(), z.string()]).transform(Number),
7
+ name: z.string(),
8
+ email: z.string(),
9
+ profile: z.string().optional(),
10
+ photo: z.string().nullable().optional(),
11
+ });
12
+
13
+ export type ProjectUser = z.infer<typeof ProjectUserSchema>;
14
+
15
+ export const AccountUserSchema = z.object({
16
+ id: z.union([z.number(), z.string()]).transform(Number),
17
+ name: z.string(),
18
+ email: z.string(),
19
+ profile: z.string().optional(),
20
+ photo: z.string().nullable().optional(),
21
+ });
22
+
23
+ export type AccountUser = z.infer<typeof AccountUserSchema>;
24
+
25
+ export interface AddRemoveProjectUsersParams {
26
+ id_project: number;
27
+ users: number[];
28
+ }
package/src/server.ts CHANGED
@@ -15,6 +15,13 @@ export { validateSessionAction } from './modules/auth/actions/validate-session.a
15
15
  export { listSubscriptionsAction } from './modules/subscriptions/actions/list-subscriptions.action';
16
16
  export { listIaCreditsAction } from './modules/ia-credits/actions/list-ia-credits.action';
17
17
 
18
+ // Project Users Services & Actions (server-only)
19
+ export { projectUsersService } from './modules/projects/services/project-users.service';
20
+ export { listProjectUsersAction } from './modules/projects/actions/list-project-users.action';
21
+ export { listAvailableUsersAction } from './modules/projects/actions/list-available-users.action';
22
+ export { addProjectUserAction } from './modules/projects/actions/add-project-user.action';
23
+ export { removeProjectUserAction } from './modules/projects/actions/remove-project-user.action';
24
+
18
25
  // Account Services & Actions (server-only)
19
26
  export { accountService } from './modules/accounts/services/account.service';
20
27
  export { twoFactorService } from './modules/accounts/services/two-factor.service';