@greatapps/common 1.1.50 → 1.1.52

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 (40) hide show
  1. package/dist/components/layouts/UsersSelectorPopover.mjs +155 -139
  2. package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
  3. package/dist/index.mjs +11 -4
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/modules/auth/actions/is-two-factor-pending.action.mjs +9 -0
  6. package/dist/modules/auth/actions/is-two-factor-pending.action.mjs.map +1 -0
  7. package/dist/modules/auth/actions/verify-two-factor.action.mjs +16 -0
  8. package/dist/modules/auth/actions/verify-two-factor.action.mjs.map +1 -0
  9. package/dist/modules/auth/hooks/useUserQuery.mjs +27 -1
  10. package/dist/modules/auth/hooks/useUserQuery.mjs.map +1 -1
  11. package/dist/modules/auth/services/auth.service.mjs +55 -18
  12. package/dist/modules/auth/services/auth.service.mjs.map +1 -1
  13. package/dist/modules/projects/actions/list-available-users.action.mjs +2 -2
  14. package/dist/modules/projects/actions/list-available-users.action.mjs.map +1 -1
  15. package/dist/modules/projects/actions/list-project-users.action.mjs +2 -2
  16. package/dist/modules/projects/actions/list-project-users.action.mjs.map +1 -1
  17. package/dist/modules/projects/hooks/list-available-users.hook.mjs +27 -0
  18. package/dist/modules/projects/hooks/list-available-users.hook.mjs.map +1 -0
  19. package/dist/modules/projects/hooks/list-project-users.hook.mjs +27 -0
  20. package/dist/modules/projects/hooks/list-project-users.hook.mjs.map +1 -0
  21. package/dist/modules/projects/services/project-users.service.mjs +21 -10
  22. package/dist/modules/projects/services/project-users.service.mjs.map +1 -1
  23. package/dist/modules/projects/types.mjs.map +1 -1
  24. package/package.json +1 -1
  25. package/src/components/layouts/UsersSelectorPopover.tsx +119 -126
  26. package/src/index.ts +5 -4
  27. package/src/modules/auth/actions/is-two-factor-pending.action.ts +7 -0
  28. package/src/modules/auth/actions/verify-two-factor.action.ts +15 -0
  29. package/src/modules/auth/hooks/useUserQuery.ts +28 -1
  30. package/src/modules/auth/schema.ts +23 -7
  31. package/src/modules/auth/services/auth.service.ts +75 -19
  32. package/src/modules/projects/actions/list-available-users.action.ts +3 -3
  33. package/src/modules/projects/actions/list-project-users.action.ts +3 -3
  34. package/src/modules/projects/hooks/list-available-users.hook.ts +26 -0
  35. package/src/modules/projects/hooks/list-project-users.hook.ts +26 -0
  36. package/src/modules/projects/services/project-users.service.ts +23 -10
  37. package/src/modules/projects/types.ts +13 -1
  38. package/dist/modules/projects/hooks/project-users.hook.mjs +0 -70
  39. package/dist/modules/projects/hooks/project-users.hook.mjs.map +0 -1
  40. package/src/modules/projects/hooks/project-users.hook.ts +0 -81
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { useQuery, useQueryClient } from "@tanstack/react-query";
2
+ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3
3
  const USER_QUERY_KEY = ["user"];
4
4
  async function fetchUser() {
5
5
  const { findUserById: getUserDataAction } = await import("../../users/action/find-user-by-id.action");
@@ -30,6 +30,30 @@ function useUserValidateSession(options) {
30
30
  refetchOnWindowFocus: true
31
31
  });
32
32
  }
33
+ function useTwoFactorVerify() {
34
+ const queryClient = useQueryClient();
35
+ return useMutation({
36
+ mutationFn: async (code) => {
37
+ const { verifyTwoFactorAction } = await import("../actions/verify-two-factor.action");
38
+ return verifyTwoFactorAction(code);
39
+ },
40
+ onSuccess: () => {
41
+ queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });
42
+ queryClient.invalidateQueries({ queryKey: ["two-factor-pending"] });
43
+ }
44
+ });
45
+ }
46
+ function useTwoFactorPending() {
47
+ return useQuery({
48
+ queryKey: ["two-factor-pending"],
49
+ queryFn: async () => {
50
+ const { isTwoFactorPendingAction } = await import("../actions/is-two-factor-pending.action");
51
+ return isTwoFactorPendingAction();
52
+ },
53
+ staleTime: 10 * 1e3,
54
+ retry: false
55
+ });
56
+ }
33
57
  function useInvalidateUser() {
34
58
  const queryClient = useQueryClient();
35
59
  return () => queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });
@@ -42,6 +66,8 @@ export {
42
66
  USER_QUERY_KEY,
43
67
  useInvalidateUser,
44
68
  useSetUserData,
69
+ useTwoFactorPending,
70
+ useTwoFactorVerify,
45
71
  useUserQuery,
46
72
  useUserValidateSession
47
73
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/auth/hooks/useUserQuery.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query';\r\nimport { User } from '../../users/schema';\r\n\r\nexport const USER_QUERY_KEY = ['user'];\r\n\r\nasync function fetchUser(): Promise<User | null> {\r\n const { findUserById: getUserDataAction } = await import('../../users/action/find-user-by-id.action');\r\n const result = await getUserDataAction();\r\n return result.success && result.data ? result.data : null;\r\n}\r\n\r\nasync function validateUserSession(): Promise<boolean> {\r\n const { validateSessionAction } = await import('../actions/validate-session.action');\r\n return await validateSessionAction();\r\n}\r\n\r\nexport function useUserQuery() {\r\n return useQuery({\r\n queryKey: USER_QUERY_KEY,\r\n queryFn: fetchUser,\r\n staleTime: 5 * 60 * 1000,\r\n gcTime: 10 * 60 * 1000,\r\n retry: false,\r\n });\r\n}\r\n\r\nexport function useUserValidateSession(options?: UseQueryOptions) {\r\n return useQuery({\r\n queryKey: ['user-validate-session'],\r\n queryFn: validateUserSession,\r\n retry: false,\r\n staleTime: 5 * 60 * 1000,\r\n ...options,\r\n refetchOnMount: 'always',\r\n refetchOnWindowFocus: true,\r\n });\r\n}\r\n\r\nexport function useInvalidateUser() {\r\n const queryClient = useQueryClient();\r\n return () => queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });\r\n}\r\n\r\nexport function useSetUserData() {\r\n const queryClient = useQueryClient();\r\n return (user: User | null) => queryClient.setQueryData(USER_QUERY_KEY, user);\r\n}\r\n"],"mappings":";AAEA,SAAS,UAAU,sBAAuC;AAGnD,MAAM,iBAAiB,CAAC,MAAM;AAErC,eAAe,YAAkC;AAC/C,QAAM,EAAE,cAAc,kBAAkB,IAAI,MAAM,OAAO,2CAA2C;AACpG,QAAM,SAAS,MAAM,kBAAkB;AACvC,SAAO,OAAO,WAAW,OAAO,OAAO,OAAO,OAAO;AACvD;AAEA,eAAe,sBAAwC;AACrD,QAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,oCAAoC;AACnF,SAAO,MAAM,sBAAsB;AACrC;AAEO,SAAS,eAAe;AAC7B,SAAO,SAAS;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,WAAW,IAAI,KAAK;AAAA,IACpB,QAAQ,KAAK,KAAK;AAAA,IAClB,OAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,uBAAuB,SAA2B;AAChE,SAAO,SAAS;AAAA,IACd,UAAU,CAAC,uBAAuB;AAAA,IAClC,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,IAAI,KAAK;AAAA,IACpB,GAAG;AAAA,IACH,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,EACxB,CAAC;AACH;AAEO,SAAS,oBAAoB;AAClC,QAAM,cAAc,eAAe;AACnC,SAAO,MAAM,YAAY,kBAAkB,EAAE,UAAU,eAAe,CAAC;AACzE;AAEO,SAAS,iBAAiB;AAC/B,QAAM,cAAc,eAAe;AACnC,SAAO,CAAC,SAAsB,YAAY,aAAa,gBAAgB,IAAI;AAC7E;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/auth/hooks/useUserQuery.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useMutation, useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query';\r\nimport { User } from '../../users/schema';\r\n\r\nexport const USER_QUERY_KEY = ['user'];\r\n\r\nasync function fetchUser(): Promise<User | null> {\r\n const { findUserById: getUserDataAction } = await import('../../users/action/find-user-by-id.action');\r\n const result = await getUserDataAction();\r\n return result.success && result.data ? result.data : null;\r\n}\r\n\r\nasync function validateUserSession(): Promise<boolean> {\r\n const { validateSessionAction } = await import('../actions/validate-session.action');\r\n return await validateSessionAction();\r\n}\r\n\r\nexport function useUserQuery() {\r\n return useQuery({\r\n queryKey: USER_QUERY_KEY,\r\n queryFn: fetchUser,\r\n staleTime: 5 * 60 * 1000,\r\n gcTime: 10 * 60 * 1000,\r\n retry: false,\r\n });\r\n}\r\n\r\nexport function useUserValidateSession(options?: UseQueryOptions) {\r\n return useQuery({\r\n queryKey: ['user-validate-session'],\r\n queryFn: validateUserSession,\r\n retry: false,\r\n staleTime: 5 * 60 * 1000,\r\n ...options,\r\n refetchOnMount: 'always',\r\n refetchOnWindowFocus: true,\r\n });\r\n}\r\n\r\nexport function useTwoFactorVerify() {\r\n const queryClient = useQueryClient();\r\n\r\n return useMutation({\r\n mutationFn: async (code: number) => {\r\n const { verifyTwoFactorAction } = await import('../actions/verify-two-factor.action');\r\n return verifyTwoFactorAction(code);\r\n },\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });\r\n queryClient.invalidateQueries({ queryKey: ['two-factor-pending'] });\r\n },\r\n });\r\n}\r\n\r\nexport function useTwoFactorPending() {\r\n return useQuery({\r\n queryKey: ['two-factor-pending'],\r\n queryFn: async () => {\r\n const { isTwoFactorPendingAction } = await import('../actions/is-two-factor-pending.action');\r\n return isTwoFactorPendingAction();\r\n },\r\n staleTime: 10 * 1000,\r\n retry: false,\r\n });\r\n}\r\n\r\nexport function useInvalidateUser() {\r\n const queryClient = useQueryClient();\r\n return () => queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });\r\n}\r\n\r\nexport function useSetUserData() {\r\n const queryClient = useQueryClient();\r\n return (user: User | null) => queryClient.setQueryData(USER_QUERY_KEY, user);\r\n}\r\n"],"mappings":";AAEA,SAAS,aAAa,UAAU,sBAAuC;AAGhE,MAAM,iBAAiB,CAAC,MAAM;AAErC,eAAe,YAAkC;AAC/C,QAAM,EAAE,cAAc,kBAAkB,IAAI,MAAM,OAAO,2CAA2C;AACpG,QAAM,SAAS,MAAM,kBAAkB;AACvC,SAAO,OAAO,WAAW,OAAO,OAAO,OAAO,OAAO;AACvD;AAEA,eAAe,sBAAwC;AACrD,QAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,oCAAoC;AACnF,SAAO,MAAM,sBAAsB;AACrC;AAEO,SAAS,eAAe;AAC7B,SAAO,SAAS;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,WAAW,IAAI,KAAK;AAAA,IACpB,QAAQ,KAAK,KAAK;AAAA,IAClB,OAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,uBAAuB,SAA2B;AAChE,SAAO,SAAS;AAAA,IACd,UAAU,CAAC,uBAAuB;AAAA,IAClC,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,IAAI,KAAK;AAAA,IACpB,GAAG;AAAA,IACH,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,EACxB,CAAC;AACH;AAEO,SAAS,qBAAqB;AACnC,QAAM,cAAc,eAAe;AAEnC,SAAO,YAAY;AAAA,IACjB,YAAY,OAAO,SAAiB;AAClC,YAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,qCAAqC;AACpF,aAAO,sBAAsB,IAAI;AAAA,IACnC;AAAA,IACA,WAAW,MAAM;AACf,kBAAY,kBAAkB,EAAE,UAAU,eAAe,CAAC;AAC1D,kBAAY,kBAAkB,EAAE,UAAU,CAAC,oBAAoB,EAAE,CAAC;AAAA,IACpE;AAAA,EACF,CAAC;AACH;AAEO,SAAS,sBAAsB;AACpC,SAAO,SAAS;AAAA,IACd,UAAU,CAAC,oBAAoB;AAAA,IAC/B,SAAS,YAAY;AACnB,YAAM,EAAE,yBAAyB,IAAI,MAAM,OAAO,yCAAyC;AAC3F,aAAO,yBAAyB;AAAA,IAClC;AAAA,IACA,WAAW,KAAK;AAAA,IAChB,OAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,oBAAoB;AAClC,QAAM,cAAc,eAAe;AACnC,SAAO,MAAM,YAAY,kBAAkB,EAAE,UAAU,eAAe,CAAC;AACzE;AAEO,SAAS,iBAAiB;AAC/B,QAAM,cAAc,eAAe;AACnC,SAAO,CAAC,SAAsB,YAAY,aAAa,gBAAgB,IAAI;AAC7E;","names":[]}
@@ -2,33 +2,41 @@ import { cookies } from "next/headers";
2
2
  import { apiClient } from "../../../infra/api/client";
3
3
  import { ApiError } from "../../../infra/api/types";
4
4
  const AUTH_COOKIE_NAME = "greatapps";
5
+ const PENDING_2FA_COOKIE_NAME = "greatapps_2fa_pending";
5
6
  const COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
7
+ const PENDING_2FA_MAX_AGE = 60 * 10;
8
+ const COOKIE_OPTIONS = {
9
+ httpOnly: true,
10
+ secure: process.env.NODE_ENV === "production",
11
+ sameSite: "lax",
12
+ path: "/",
13
+ domain: process.env.DOMAIN_COOKIE
14
+ };
6
15
  async function setAuthCookie(token) {
7
16
  const cookieStore = await cookies();
8
- cookieStore.set(AUTH_COOKIE_NAME, token, {
9
- httpOnly: true,
10
- secure: process.env.NODE_ENV === "production",
11
- sameSite: "lax",
12
- maxAge: COOKIE_MAX_AGE,
13
- path: "/",
14
- domain: process.env.DOMAIN_COOKIE
15
- });
17
+ cookieStore.set(AUTH_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: COOKIE_MAX_AGE });
16
18
  }
17
19
  async function removeAuthCookie() {
18
20
  const cookieStore = await cookies();
19
- cookieStore.delete({
20
- name: AUTH_COOKIE_NAME,
21
- path: "/",
22
- secure: process.env.NODE_ENV === "production",
23
- sameSite: "lax",
24
- domain: process.env.DOMAIN_COOKIE
25
- });
21
+ cookieStore.delete({ name: AUTH_COOKIE_NAME, ...COOKIE_OPTIONS });
26
22
  }
27
23
  async function getAuthCookie() {
28
24
  if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;
29
25
  const cookieStore = await cookies();
30
26
  return cookieStore.get(AUTH_COOKIE_NAME)?.value;
31
27
  }
28
+ async function setPending2FACookie(token) {
29
+ const cookieStore = await cookies();
30
+ cookieStore.set(PENDING_2FA_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: PENDING_2FA_MAX_AGE });
31
+ }
32
+ async function removePending2FACookie() {
33
+ const cookieStore = await cookies();
34
+ cookieStore.delete({ name: PENDING_2FA_COOKIE_NAME, ...COOKIE_OPTIONS });
35
+ }
36
+ async function getPending2FACookie() {
37
+ const cookieStore = await cookies();
38
+ return cookieStore.get(PENDING_2FA_COOKIE_NAME)?.value;
39
+ }
32
40
  class AuthService {
33
41
  async login(credentials, clientInfo) {
34
42
  const response = await apiClient.post("/auth/login", {
@@ -45,15 +53,45 @@ class AuthService {
45
53
  if (!response.cookie) {
46
54
  throw new ApiError("Resposta de autentica\xE7\xE3o inv\xE1lida", "INVALID_RESPONSE", 500);
47
55
  }
56
+ if (response.two_factor_authentication) {
57
+ await setPending2FACookie(response.cookie);
58
+ return { twoFactorRequired: true };
59
+ }
48
60
  await setAuthCookie(response.cookie);
49
61
  return {
50
62
  user: {},
51
- // Placeholder, será preenchido pelo AuthProvider
52
63
  accessToken: response.cookie,
53
64
  refreshToken: "",
54
65
  expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1e3).toISOString()
55
66
  };
56
67
  }
68
+ async verifyTwoFactor(code, clientInfo) {
69
+ const pendingCookie = await getPending2FACookie();
70
+ if (!pendingCookie) {
71
+ throw new ApiError("Nenhuma autentica\xE7\xE3o 2FA pendente", "NO_PENDING_2FA", 400);
72
+ }
73
+ const payload = {
74
+ location: clientInfo.location,
75
+ ip: clientInfo.ip,
76
+ timezone: clientInfo.timezone,
77
+ agent: clientInfo.agent,
78
+ cookie: pendingCookie,
79
+ code
80
+ };
81
+ const response = await apiClient.post("/auth/code", payload);
82
+ if (response.status === 0) {
83
+ throw new ApiError(response.message || "C\xF3digo 2FA inv\xE1lido", "TWO_FACTOR_FAILED", 401);
84
+ }
85
+ if (!response.cookie) {
86
+ throw new ApiError("Resposta de autentica\xE7\xE3o inv\xE1lida ap\xF3s 2FA", "INVALID_RESPONSE", 500);
87
+ }
88
+ await Promise.all([setAuthCookie(response.cookie), removePending2FACookie()]);
89
+ return { success: true };
90
+ }
91
+ async isTwoFactorPending() {
92
+ const pending = await getPending2FACookie();
93
+ return !!pending;
94
+ }
57
95
  async register(data) {
58
96
  const today = /* @__PURE__ */ new Date();
59
97
  const trialEndDate = new Date(today);
@@ -120,8 +158,7 @@ class AuthService {
120
158
  throw new ApiError(response.message || "Erro ao realizar logout", "LOGOUT_FAILED", 400);
121
159
  }
122
160
  } finally {
123
- console.log("[AuthService] Logout - removendo cookie localmente");
124
- await removeAuthCookie();
161
+ await Promise.all([removeAuthCookie(), removePending2FACookie()]);
125
162
  }
126
163
  return {
127
164
  success: true
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/auth/services/auth.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { apiClient } from '../../../infra/api/client';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { User } from '../../users/schema';\r\nimport {\r\n ClientInfo,\r\n ForgotPasswordRequest,\r\n ForgotPasswordResponse,\r\n GeoLocation,\r\n LoginApiResponse,\r\n LoginRequest,\r\n LoginResponse,\r\n LogoutApiResponse,\r\n LogoutRequest,\r\n LogoutResponse,\r\n RegisterApiRequest,\r\n RegisterApiResponse,\r\n RegisterRequest,\r\n RegisterResponse,\r\n ResendVerificationRequest,\r\n ResendVerificationResponse,\r\n ResetPasswordRequest,\r\n ResetPasswordResponse,\r\n SessionKeepRequest,\r\n SessionKeepResponse,\r\n VerifyEmailRequest,\r\n VerifyEmailResponse,\r\n} from '../schema';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 30;\r\n\r\nasync function setAuthCookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(AUTH_COOKIE_NAME, token, {\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'lax',\r\n maxAge: COOKIE_MAX_AGE,\r\n path: '/',\r\n domain: process.env.DOMAIN_COOKIE\r\n });\r\n}\r\n\r\nasync function removeAuthCookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({\r\n name: AUTH_COOKIE_NAME,\r\n path: \"/\",\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'lax',\r\n domain: process.env.DOMAIN_COOKIE,\r\n });\r\n}\r\n\r\nasync function getAuthCookie(): Promise<string | undefined> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n return cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n}\r\n\r\nclass AuthService {\r\n async login(credentials: LoginRequest, clientInfo: ClientInfo): Promise<LoginResponse> {\r\n const response = await apiClient.post<LoginApiResponse>('/auth/login', {\r\n email: credentials.email,\r\n password: credentials.password,\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'E-mail ou senha incorretos', 'LOGIN_FAILED', 401);\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError('Resposta de autenticação inválida', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n await setAuthCookie(response.cookie);\r\n\r\n // O usuário completo será carregado pelo AuthProvider via getUserDataAction\r\n return {\r\n user: {} as User, // Placeholder, será preenchido pelo AuthProvider\r\n accessToken: response.cookie,\r\n refreshToken: '',\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n };\r\n }\r\n\r\n async register(data: RegisterRequest): Promise<RegisterResponse> {\r\n const today = new Date();\r\n const trialEndDate = new Date(today);\r\n trialEndDate.setDate(today.getDate() + 7); // 7 dias de trial\r\n\r\n const payload: RegisterApiRequest = {\r\n name: data.accountName,\r\n bussiness_type: data.businessType,\r\n language: 'pt-br',\r\n timezone: 'America/Sao_Paulo',\r\n currency: 'BRL',\r\n user: {\r\n id_api: '',\r\n name: data.name,\r\n last_name: data.lastName || '',\r\n rg: data.rg || '',\r\n cpf: data.cpf || '',\r\n gender: data.gender,\r\n email: data.email,\r\n phone: data.phone,\r\n password: data.password,\r\n profile: 'owner',\r\n language: 'pt-br',\r\n },\r\n subscription: {\r\n type: 'trial',\r\n id_cupom: '',\r\n id_plan: 1,\r\n due_date: trialEndDate.toISOString().split('T')[0],\r\n id_product: 1,\r\n },\r\n };\r\n\r\n const response = await apiClient.post<RegisterApiResponse>('/accounts', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao criar conta', 'REGISTER_FAILED', 400);\r\n }\r\n\r\n if (!response.data || response.data.length === 0) {\r\n throw new ApiError('Resposta de registro inválida', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n const accountData = response.data[0];\r\n\r\n // Retornar sem token pois o registro não retorna cookie diretamente\r\n // O usuário precisará fazer login após o registro\r\n // O usuário completo será carregado após o login\r\n return {\r\n user: {} as User, // Placeholder, será preenchido após login\r\n accessToken: '',\r\n refreshToken: '',\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n requiresEmailVerification: !accountData.verified,\r\n };\r\n }\r\n\r\n async logout(clientInfo: ClientInfo): Promise<LogoutResponse> {\r\n const cookie = await getAuthCookie();\r\n\r\n if (!cookie) {\r\n throw new ApiError('Usuário não autenticado', 'NOT_AUTHENTICATED', 401);\r\n }\r\n\r\n const payload: LogoutRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n try {\r\n const response = await apiClient.post<LogoutApiResponse>('/auth/logout', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao realizar logout', 'LOGOUT_FAILED', 400);\r\n }\r\n } finally {\r\n console.log('[AuthService] Logout - removendo cookie localmente');\r\n await removeAuthCookie();\r\n }\r\n\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n async forgotPassword(_data: ForgotPasswordRequest): Promise<ForgotPasswordResponse> {\r\n throw new ApiError('Recuperação de senha não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async resetPassword(_data: ResetPasswordRequest): Promise<ResetPasswordResponse> {\r\n throw new ApiError('Redefinição de senha não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async verifyEmail(_data: VerifyEmailRequest): Promise<VerifyEmailResponse> {\r\n throw new ApiError('Verificação de email não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async resendVerification(_data: ResendVerificationRequest): Promise<ResendVerificationResponse> {\r\n throw new ApiError('Reenvio de verificação não implementado', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async validateSession(clientInfo: ClientInfo): Promise<boolean> {\r\n const cookie = await getAuthCookie();\r\n\r\n if (!cookie) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload: SessionKeepRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n const response = await apiClient.post<SessionKeepResponse>('/auth/keep', payload);\r\n\r\n return response.status === 1;\r\n } catch (error) {\r\n console.error('[AuthService] validateSession error', error);\r\n return false;\r\n }\r\n }\r\n\r\n async isAuthenticated(): Promise<boolean> {\r\n const token = await getAuthCookie();\r\n return !!token;\r\n }\r\n\r\n async getToken(): Promise<string | undefined> {\r\n return getAuthCookie();\r\n }\r\n}\r\n\r\nexport const authService = new AuthService();\r\n\r\nexport type { ClientInfo, GeoLocation };\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/auth/services/auth.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { apiClient } from '../../../infra/api/client';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { User } from '../../users/schema';\r\nimport {\r\n ClientInfo,\r\n ForgotPasswordRequest,\r\n ForgotPasswordResponse,\r\n GeoLocation,\r\n LoginApiResponse,\r\n LoginRequest,\r\n LoginResponse,\r\n LogoutApiResponse,\r\n LogoutRequest,\r\n LogoutResponse,\r\n RegisterApiRequest,\r\n RegisterApiResponse,\r\n RegisterRequest,\r\n RegisterResponse,\r\n ResendVerificationRequest,\r\n ResendVerificationResponse,\r\n ResetPasswordRequest,\r\n ResetPasswordResponse,\r\n SessionKeepRequest,\r\n SessionKeepResponse,\r\n TwoFactorApiResponse,\r\n TwoFactorRequest,\r\n TwoFactorResponse,\r\n VerifyEmailRequest,\r\n VerifyEmailResponse,\r\n} from '../schema';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst PENDING_2FA_COOKIE_NAME = 'greatapps_2fa_pending';\r\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 30;\r\nconst PENDING_2FA_MAX_AGE = 60 * 10; // 10 minutos para completar o 2FA\r\n\r\nconst COOKIE_OPTIONS = {\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'lax' as const,\r\n path: '/',\r\n domain: process.env.DOMAIN_COOKIE,\r\n};\r\n\r\nasync function setAuthCookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(AUTH_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: COOKIE_MAX_AGE });\r\n}\r\n\r\nasync function removeAuthCookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({ name: AUTH_COOKIE_NAME, ...COOKIE_OPTIONS });\r\n}\r\n\r\nasync function getAuthCookie(): Promise<string | undefined> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n return cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n}\r\n\r\nasync function setPending2FACookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(PENDING_2FA_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: PENDING_2FA_MAX_AGE });\r\n}\r\n\r\nasync function removePending2FACookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({ name: PENDING_2FA_COOKIE_NAME, ...COOKIE_OPTIONS });\r\n}\r\n\r\nasync function getPending2FACookie(): Promise<string | undefined> {\r\n const cookieStore = await cookies();\r\n return cookieStore.get(PENDING_2FA_COOKIE_NAME)?.value;\r\n}\r\n\r\nclass AuthService {\r\n async login(credentials: LoginRequest, clientInfo: ClientInfo): Promise<LoginResponse> {\r\n const response = await apiClient.post<LoginApiResponse>('/auth/login', {\r\n email: credentials.email,\r\n password: credentials.password,\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'E-mail ou senha incorretos', 'LOGIN_FAILED', 401);\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError('Resposta de autenticação inválida', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n if (response.two_factor_authentication) {\r\n // Armazena o cookie temporariamente até o 2FA ser concluído.\r\n // O cookie principal NÃO é setado aqui para evitar falso positivo em isAuthenticated().\r\n await setPending2FACookie(response.cookie);\r\n return { twoFactorRequired: true };\r\n }\r\n\r\n await setAuthCookie(response.cookie);\r\n\r\n return {\r\n user: {} as User,\r\n accessToken: response.cookie,\r\n refreshToken: '',\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n };\r\n }\r\n\r\n async verifyTwoFactor(code: number, clientInfo: ClientInfo): Promise<TwoFactorResponse> {\r\n const pendingCookie = await getPending2FACookie();\r\n\r\n if (!pendingCookie) {\r\n throw new ApiError('Nenhuma autenticação 2FA pendente', 'NO_PENDING_2FA', 400);\r\n }\r\n\r\n const payload: TwoFactorRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie: pendingCookie,\r\n code,\r\n };\r\n\r\n const response = await apiClient.post<TwoFactorApiResponse>('/auth/code', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Código 2FA inválido', 'TWO_FACTOR_FAILED', 401);\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError('Resposta de autenticação inválida após 2FA', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n await Promise.all([setAuthCookie(response.cookie), removePending2FACookie()]);\r\n\r\n return { success: true };\r\n }\r\n\r\n async isTwoFactorPending(): Promise<boolean> {\r\n const pending = await getPending2FACookie();\r\n return !!pending;\r\n }\r\n\r\n async register(data: RegisterRequest): Promise<RegisterResponse> {\r\n const today = new Date();\r\n const trialEndDate = new Date(today);\r\n trialEndDate.setDate(today.getDate() + 7); // 7 dias de trial\r\n\r\n const payload: RegisterApiRequest = {\r\n name: data.accountName,\r\n bussiness_type: data.businessType,\r\n language: 'pt-br',\r\n timezone: 'America/Sao_Paulo',\r\n currency: 'BRL',\r\n user: {\r\n id_api: '',\r\n name: data.name,\r\n last_name: data.lastName || '',\r\n rg: data.rg || '',\r\n cpf: data.cpf || '',\r\n gender: data.gender,\r\n email: data.email,\r\n phone: data.phone,\r\n password: data.password,\r\n profile: 'owner',\r\n language: 'pt-br',\r\n },\r\n subscription: {\r\n type: 'trial',\r\n id_cupom: '',\r\n id_plan: 1,\r\n due_date: trialEndDate.toISOString().split('T')[0],\r\n id_product: 1,\r\n },\r\n };\r\n\r\n const response = await apiClient.post<RegisterApiResponse>('/accounts', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao criar conta', 'REGISTER_FAILED', 400);\r\n }\r\n\r\n if (!response.data || response.data.length === 0) {\r\n throw new ApiError('Resposta de registro inválida', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n const accountData = response.data[0];\r\n\r\n // Retornar sem token pois o registro não retorna cookie diretamente\r\n // O usuário precisará fazer login após o registro\r\n // O usuário completo será carregado após o login\r\n return {\r\n user: {} as User, // Placeholder, será preenchido após login\r\n accessToken: '',\r\n refreshToken: '',\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n requiresEmailVerification: !accountData.verified,\r\n };\r\n }\r\n\r\n async logout(clientInfo: ClientInfo): Promise<LogoutResponse> {\r\n const cookie = await getAuthCookie();\r\n\r\n if (!cookie) {\r\n throw new ApiError('Usuário não autenticado', 'NOT_AUTHENTICATED', 401);\r\n }\r\n\r\n const payload: LogoutRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n try {\r\n const response = await apiClient.post<LogoutApiResponse>('/auth/logout', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao realizar logout', 'LOGOUT_FAILED', 400);\r\n }\r\n } finally {\r\n await Promise.all([removeAuthCookie(), removePending2FACookie()]);\r\n }\r\n\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n async forgotPassword(_data: ForgotPasswordRequest): Promise<ForgotPasswordResponse> {\r\n throw new ApiError('Recuperação de senha não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async resetPassword(_data: ResetPasswordRequest): Promise<ResetPasswordResponse> {\r\n throw new ApiError('Redefinição de senha não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async verifyEmail(_data: VerifyEmailRequest): Promise<VerifyEmailResponse> {\r\n throw new ApiError('Verificação de email não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async resendVerification(_data: ResendVerificationRequest): Promise<ResendVerificationResponse> {\r\n throw new ApiError('Reenvio de verificação não implementado', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async validateSession(clientInfo: ClientInfo): Promise<boolean> {\r\n const cookie = await getAuthCookie();\r\n\r\n if (!cookie) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload: SessionKeepRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n const response = await apiClient.post<SessionKeepResponse>('/auth/keep', payload);\r\n\r\n return response.status === 1;\r\n } catch (error) {\r\n console.error('[AuthService] validateSession error', error);\r\n return false;\r\n }\r\n }\r\n\r\n async isAuthenticated(): Promise<boolean> {\r\n const token = await getAuthCookie();\r\n return !!token;\r\n }\r\n\r\n async getToken(): Promise<string | undefined> {\r\n return getAuthCookie();\r\n }\r\n}\r\n\r\nexport const authService = new AuthService();\r\n\r\nexport type { ClientInfo, GeoLocation };\r\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  "use server";
2
2
  import { projectUsersService } from "../services/project-users.service";
3
- async function listAvailableUsersAction(id_project) {
4
- return projectUsersService.listNotInProject(id_project);
3
+ async function listAvailableUsersAction(projectId, params = {}) {
4
+ return projectUsersService.listNotInProject(projectId, params);
5
5
  }
6
6
  export {
7
7
  listAvailableUsersAction
@@ -1 +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":[]}
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, ListUsersParams, UsersPage } from '../types';\r\n\r\nexport async function listAvailableUsersAction(projectId: number, params: ListUsersParams = {}): Promise<UsersPage<AccountUser>> {\r\n return projectUsersService.listNotInProject(projectId, params);\r\n}\r\n"],"mappings":";AAEA,SAAS,2BAA2B;AAGpC,eAAsB,yBAAyB,WAAmB,SAA0B,CAAC,GAAoC;AAC/H,SAAO,oBAAoB,iBAAiB,WAAW,MAAM;AAC/D;","names":[]}
@@ -1,7 +1,7 @@
1
1
  "use server";
2
2
  import { projectUsersService } from "../services/project-users.service";
3
- async function listProjectUsersAction(id_project) {
4
- return projectUsersService.listInProject(id_project);
3
+ async function listProjectUsersAction(projectId, params = {}) {
4
+ return projectUsersService.listInProject(projectId, params);
5
5
  }
6
6
  export {
7
7
  listProjectUsersAction
@@ -1 +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":[]}
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 { ListUsersParams, ProjectUser, UsersPage } from '../types';\r\n\r\nexport async function listProjectUsersAction(projectId: number, params: ListUsersParams = {}): Promise<UsersPage<ProjectUser>> {\r\n return projectUsersService.listInProject(projectId, params);\r\n}\r\n"],"mappings":";AAEA,SAAS,2BAA2B;AAGpC,eAAsB,uBAAuB,WAAmB,SAA0B,CAAC,GAAoC;AAC7H,SAAO,oBAAoB,cAAc,WAAW,MAAM;AAC5D;","names":[]}
@@ -0,0 +1,27 @@
1
+ "use client";
2
+ import { useInfiniteQuery } from "@tanstack/react-query";
3
+ import { listAvailableUsersAction } from "../actions/list-available-users.action";
4
+ const PAGE_SIZE = 20;
5
+ const LIST_AVAILABLE_USERS_BASE_KEY = (projectId) => ["project-users", projectId, "out"];
6
+ const LIST_AVAILABLE_USERS_QUERY_KEY = (projectId, search = "") => [
7
+ ...LIST_AVAILABLE_USERS_BASE_KEY(projectId),
8
+ search
9
+ ];
10
+ function useListAvailableUsers(projectId, search = "") {
11
+ return useInfiniteQuery({
12
+ queryKey: LIST_AVAILABLE_USERS_QUERY_KEY(projectId, search),
13
+ queryFn: ({ pageParam }) => listAvailableUsersAction(projectId, { search: search || void 0, page: pageParam, limit: PAGE_SIZE }),
14
+ getNextPageParam: (lastPage, allPages) => {
15
+ const loaded = allPages.reduce((sum, p) => sum + p.data.length, 0);
16
+ return loaded < lastPage.total ? allPages.length + 1 : void 0;
17
+ },
18
+ initialPageParam: 1,
19
+ enabled: !!projectId
20
+ });
21
+ }
22
+ export {
23
+ LIST_AVAILABLE_USERS_BASE_KEY,
24
+ LIST_AVAILABLE_USERS_QUERY_KEY,
25
+ useListAvailableUsers
26
+ };
27
+ //# sourceMappingURL=list-available-users.hook.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/projects/hooks/list-available-users.hook.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useInfiniteQuery } from '@tanstack/react-query';\r\nimport { listAvailableUsersAction } from '../actions/list-available-users.action';\r\n\r\nconst PAGE_SIZE = 20;\r\n\r\nexport const LIST_AVAILABLE_USERS_BASE_KEY = (projectId: number) => ['project-users', projectId, 'out'];\r\nexport const LIST_AVAILABLE_USERS_QUERY_KEY = (projectId: number, search: string = '') => [\r\n ...LIST_AVAILABLE_USERS_BASE_KEY(projectId),\r\n search,\r\n];\r\n\r\nexport function useListAvailableUsers(projectId: number, search: string = '') {\r\n return useInfiniteQuery({\r\n queryKey: LIST_AVAILABLE_USERS_QUERY_KEY(projectId, search),\r\n queryFn: ({ pageParam }) =>\r\n listAvailableUsersAction(projectId, { search: search || undefined, page: pageParam as number, limit: PAGE_SIZE }),\r\n getNextPageParam: (lastPage, allPages) => {\r\n const loaded = allPages.reduce((sum, p) => sum + p.data.length, 0);\r\n return loaded < lastPage.total ? allPages.length + 1 : undefined;\r\n },\r\n initialPageParam: 1,\r\n enabled: !!projectId,\r\n });\r\n}\r\n"],"mappings":";AAEA,SAAS,wBAAwB;AACjC,SAAS,gCAAgC;AAEzC,MAAM,YAAY;AAEX,MAAM,gCAAgC,CAAC,cAAsB,CAAC,iBAAiB,WAAW,KAAK;AAC/F,MAAM,iCAAiC,CAAC,WAAmB,SAAiB,OAAO;AAAA,EACxF,GAAG,8BAA8B,SAAS;AAAA,EAC1C;AACF;AAEO,SAAS,sBAAsB,WAAmB,SAAiB,IAAI;AAC5E,SAAO,iBAAiB;AAAA,IACtB,UAAU,+BAA+B,WAAW,MAAM;AAAA,IAC1D,SAAS,CAAC,EAAE,UAAU,MACpB,yBAAyB,WAAW,EAAE,QAAQ,UAAU,QAAW,MAAM,WAAqB,OAAO,UAAU,CAAC;AAAA,IAClH,kBAAkB,CAAC,UAAU,aAAa;AACxC,YAAM,SAAS,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,KAAK,QAAQ,CAAC;AACjE,aAAO,SAAS,SAAS,QAAQ,SAAS,SAAS,IAAI;AAAA,IACzD;AAAA,IACA,kBAAkB;AAAA,IAClB,SAAS,CAAC,CAAC;AAAA,EACb,CAAC;AACH;","names":[]}
@@ -0,0 +1,27 @@
1
+ "use client";
2
+ import { useInfiniteQuery } from "@tanstack/react-query";
3
+ import { listProjectUsersAction } from "../actions/list-project-users.action";
4
+ const PAGE_SIZE = 20;
5
+ const LIST_PROJECT_USERS_BASE_KEY = (projectId) => ["project-users", projectId, "in"];
6
+ const LIST_PROJECT_USERS_QUERY_KEY = (projectId, search = "") => [
7
+ ...LIST_PROJECT_USERS_BASE_KEY(projectId),
8
+ search
9
+ ];
10
+ function useListProjectUsers(projectId, search = "") {
11
+ return useInfiniteQuery({
12
+ queryKey: LIST_PROJECT_USERS_QUERY_KEY(projectId, search),
13
+ queryFn: ({ pageParam }) => listProjectUsersAction(projectId, { search: search || void 0, page: pageParam, limit: PAGE_SIZE }),
14
+ getNextPageParam: (lastPage, allPages) => {
15
+ const loaded = allPages.reduce((sum, p) => sum + p.data.length, 0);
16
+ return loaded < lastPage.total ? allPages.length + 1 : void 0;
17
+ },
18
+ initialPageParam: 1,
19
+ enabled: !!projectId
20
+ });
21
+ }
22
+ export {
23
+ LIST_PROJECT_USERS_BASE_KEY,
24
+ LIST_PROJECT_USERS_QUERY_KEY,
25
+ useListProjectUsers
26
+ };
27
+ //# sourceMappingURL=list-project-users.hook.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/projects/hooks/list-project-users.hook.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useInfiniteQuery } from '@tanstack/react-query';\r\nimport { listProjectUsersAction } from '../actions/list-project-users.action';\r\n\r\nconst PAGE_SIZE = 20;\r\n\r\nexport const LIST_PROJECT_USERS_BASE_KEY = (projectId: number) => ['project-users', projectId, 'in'];\r\nexport const LIST_PROJECT_USERS_QUERY_KEY = (projectId: number, search: string = '') => [\r\n ...LIST_PROJECT_USERS_BASE_KEY(projectId),\r\n search,\r\n];\r\n\r\nexport function useListProjectUsers(projectId: number, search: string = '') {\r\n return useInfiniteQuery({\r\n queryKey: LIST_PROJECT_USERS_QUERY_KEY(projectId, search),\r\n queryFn: ({ pageParam }) =>\r\n listProjectUsersAction(projectId, { search: search || undefined, page: pageParam as number, limit: PAGE_SIZE }),\r\n getNextPageParam: (lastPage, allPages) => {\r\n const loaded = allPages.reduce((sum, p) => sum + p.data.length, 0);\r\n return loaded < lastPage.total ? allPages.length + 1 : undefined;\r\n },\r\n initialPageParam: 1,\r\n enabled: !!projectId,\r\n });\r\n}\r\n"],"mappings":";AAEA,SAAS,wBAAwB;AACjC,SAAS,8BAA8B;AAEvC,MAAM,YAAY;AAEX,MAAM,8BAA8B,CAAC,cAAsB,CAAC,iBAAiB,WAAW,IAAI;AAC5F,MAAM,+BAA+B,CAAC,WAAmB,SAAiB,OAAO;AAAA,EACtF,GAAG,4BAA4B,SAAS;AAAA,EACxC;AACF;AAEO,SAAS,oBAAoB,WAAmB,SAAiB,IAAI;AAC1E,SAAO,iBAAiB;AAAA,IACtB,UAAU,6BAA6B,WAAW,MAAM;AAAA,IACxD,SAAS,CAAC,EAAE,UAAU,MACpB,uBAAuB,WAAW,EAAE,QAAQ,UAAU,QAAW,MAAM,WAAqB,OAAO,UAAU,CAAC;AAAA,IAChH,kBAAkB,CAAC,UAAU,aAAa;AACxC,YAAM,SAAS,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,KAAK,QAAQ,CAAC;AACjE,aAAO,SAAS,SAAS,QAAQ,SAAS,SAAS,IAAI;AAAA,IACzD;AAAA,IACA,kBAAkB;AAAA,IAClB,SAAS,CAAC,CAAC;AAAA,EACb,CAAC;AACH;","names":[]}
@@ -1,15 +1,17 @@
1
1
  import "server-only";
2
2
  import { api } from "../../../infra/api/client";
3
3
  import { ApiError } from "../../../infra/api/types";
4
+ import { buildQueryParams } from "../../../infra/utils/params";
4
5
  import { getUserContext } from "../../auth/utils/get-user-context";
5
6
  import {
6
7
  AccountUserSchema,
7
8
  ProjectUserSchema
8
9
  } from "../types";
9
10
  class ProjectUsersService {
10
- async listInProject(id_project) {
11
+ async listInProject(projectId, params = {}) {
11
12
  const { id_account, id_user } = await getUserContext();
12
- const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;
13
+ const query = buildQueryParams(params);
14
+ const url = `/account/${id_account}/user/${id_user}/projects/${projectId}/users${query ? `?${query}` : ""}`;
13
15
  const response = await api.apps.get(url);
14
16
  if (response.status === 0) {
15
17
  throw new ApiError(
@@ -18,11 +20,16 @@ class ProjectUsersService {
18
20
  400
19
21
  );
20
22
  }
21
- return response.data.map((item) => ProjectUserSchema.parse(item));
23
+ return {
24
+ data: response.data.map((item) => ProjectUserSchema.parse(item)),
25
+ total: response.total,
26
+ page: params.page ?? 1
27
+ };
22
28
  }
23
- async listNotInProject(id_project) {
29
+ async listNotInProject(projectId, params = {}) {
24
30
  const { id_account } = await getUserContext();
25
- const url = `/accounts/${id_account}/users?notInProject=${id_project}`;
31
+ const query = buildQueryParams({ notInProject: projectId, ...params });
32
+ const url = `/accounts/${id_account}/users${query ? `?${query}` : ""}`;
26
33
  const response = await api.apps.get(url);
27
34
  if (response.status === 0) {
28
35
  throw new ApiError(
@@ -31,11 +38,15 @@ class ProjectUsersService {
31
38
  400
32
39
  );
33
40
  }
34
- return response.data.map((item) => AccountUserSchema.parse(item));
41
+ return {
42
+ data: response.data.map((item) => AccountUserSchema.parse(item)),
43
+ total: response.total,
44
+ page: params.page ?? 1
45
+ };
35
46
  }
36
- async addToProject({ id_project, users }) {
47
+ async addToProject({ projectId, users }) {
37
48
  const { id_account, id_user } = await getUserContext();
38
- const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;
49
+ const url = `/account/${id_account}/user/${id_user}/projects/${projectId}/users`;
39
50
  const response = await api.apps.post(url, { users });
40
51
  if (response.status === 0) {
41
52
  throw new ApiError(
@@ -45,9 +56,9 @@ class ProjectUsersService {
45
56
  );
46
57
  }
47
58
  }
48
- async removeFromProject({ id_project, users }) {
59
+ async removeFromProject({ projectId, users }) {
49
60
  const { id_account, id_user } = await getUserContext();
50
- const url = `/account/${id_account}/user/${id_user}/projects/${id_project}/users`;
61
+ const url = `/account/${id_account}/user/${id_user}/projects/${projectId}/users`;
51
62
  const response = await api.apps.delete(url, {
52
63
  body: JSON.stringify({ users })
53
64
  });
@@ -1 +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.apps.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.apps.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.apps.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,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,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,KAAK,KAAwB,KAAK,EAAE,MAAM,CAAC;AAEtE,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,KAAK,OAA0B,KAAK;AAAA,MAC7D,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":[]}
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 { buildQueryParams } from '../../../infra/utils/params';\r\nimport { getUserContext } from '../../auth/utils/get-user-context';\r\nimport {\r\n AccountUser,\r\n AccountUserSchema,\r\n AddRemoveProjectUsersParams,\r\n ListUsersParams,\r\n ProjectUser,\r\n ProjectUserSchema,\r\n UsersPage,\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(projectId: number, params: ListUsersParams = {}): Promise<UsersPage<ProjectUser>> {\r\n const { id_account, id_user } = await getUserContext();\r\n const query = buildQueryParams(params as Record<string, string | number | boolean | undefined>);\r\n const url = `/account/${id_account}/user/${id_user}/projects/${projectId}/users${query ? `?${query}` : ''}`;\r\n\r\n const response = await api.apps.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 {\r\n data: response.data.map((item) => ProjectUserSchema.parse(item)),\r\n total: response.total,\r\n page: params.page ?? 1,\r\n };\r\n }\r\n\r\n async listNotInProject(projectId: number, params: ListUsersParams = {}): Promise<UsersPage<AccountUser>> {\r\n const { id_account } = await getUserContext();\r\n const query = buildQueryParams({ notInProject: projectId, ...params } as Record<string, string | number | boolean | undefined>);\r\n const url = `/accounts/${id_account}/users${query ? `?${query}` : ''}`;\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 {\r\n data: response.data.map((item) => AccountUserSchema.parse(item)),\r\n total: response.total,\r\n page: params.page ?? 1,\r\n };\r\n }\r\n\r\n async addToProject({ projectId, users }: AddRemoveProjectUsersParams): Promise<void> {\r\n const { id_account, id_user } = await getUserContext();\r\n const url = `/account/${id_account}/user/${id_user}/projects/${projectId}/users`;\r\n\r\n const response = await api.apps.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({ projectId, users }: AddRemoveProjectUsersParams): Promise<void> {\r\n const { id_account, id_user } = await getUserContext();\r\n const url = `/account/${id_account}/user/${id_user}/projects/${projectId}/users`;\r\n\r\n const response = await api.apps.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,wBAAwB;AACjC,SAAS,sBAAsB;AAC/B;AAAA,EAEE;AAAA,EAIA;AAAA,OAEK;AAcP,MAAM,oBAAoB;AAAA,EACxB,MAAM,cAAc,WAAmB,SAA0B,CAAC,GAAoC;AACpG,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AACrD,UAAM,QAAQ,iBAAiB,MAA+D;AAC9F,UAAM,MAAM,YAAY,UAAU,SAAS,OAAO,aAAa,SAAS,SAAS,QAAQ,IAAI,KAAK,KAAK,EAAE;AAEzG,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;AAAA,MACL,MAAM,SAAS,KAAK,IAAI,CAAC,SAAS,kBAAkB,MAAM,IAAI,CAAC;AAAA,MAC/D,OAAO,SAAS;AAAA,MAChB,MAAM,OAAO,QAAQ;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,MAAM,iBAAiB,WAAmB,SAA0B,CAAC,GAAoC;AACvG,UAAM,EAAE,WAAW,IAAI,MAAM,eAAe;AAC5C,UAAM,QAAQ,iBAAiB,EAAE,cAAc,WAAW,GAAG,OAAO,CAA0D;AAC9H,UAAM,MAAM,aAAa,UAAU,SAAS,QAAQ,IAAI,KAAK,KAAK,EAAE;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;AAAA,MACL,MAAM,SAAS,KAAK,IAAI,CAAC,SAAS,kBAAkB,MAAM,IAAI,CAAC;AAAA,MAC/D,OAAO,SAAS;AAAA,MAChB,MAAM,OAAO,QAAQ;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,EAAE,WAAW,MAAM,GAA+C;AACnF,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AACrD,UAAM,MAAM,YAAY,UAAU,SAAS,OAAO,aAAa,SAAS;AAExE,UAAM,WAAW,MAAM,IAAI,KAAK,KAAwB,KAAK,EAAE,MAAM,CAAC;AAEtE,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,WAAW,MAAM,GAA+C;AACxF,UAAM,EAAE,YAAY,QAAQ,IAAI,MAAM,eAAe;AACrD,UAAM,MAAM,YAAY,UAAU,SAAS,OAAO,aAAa,SAAS;AAExE,UAAM,WAAW,MAAM,IAAI,KAAK,OAA0B,KAAK;AAAA,MAC7D,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":[]}
@@ -1 +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":[]}
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 projectId: number;\r\n users: number[];\r\n}\r\n\r\nexport interface ListUsersParams {\r\n search?: string;\r\n page?: number;\r\n limit?: number;\r\n}\r\n\r\nexport interface UsersPage<T> {\r\n data: T[];\r\n total: number;\r\n page: 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/common",
3
- "version": "1.1.50",
3
+ "version": "1.1.52",
4
4
  "description": "Shared library for GreatApps frontend applications",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./src/index.ts",