@greatapps/common 1.1.44 → 1.1.48
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.
- package/dist/components/layouts/UsersSelectorPopover.mjs +92 -21
- package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -1
- package/dist/modules/accounts/actions/account-management.action.mjs +80 -29
- package/dist/modules/accounts/actions/account-management.action.mjs.map +1 -1
- package/dist/modules/projects/actions/add-project-user.action.mjs +9 -0
- package/dist/modules/projects/actions/add-project-user.action.mjs.map +1 -0
- package/dist/modules/projects/actions/list-available-users.action.mjs +9 -0
- package/dist/modules/projects/actions/list-available-users.action.mjs.map +1 -0
- package/dist/modules/projects/actions/list-project-users.action.mjs +9 -0
- package/dist/modules/projects/actions/list-project-users.action.mjs.map +1 -0
- package/dist/modules/projects/actions/remove-project-user.action.mjs +9 -0
- package/dist/modules/projects/actions/remove-project-user.action.mjs.map +1 -0
- package/dist/modules/projects/hooks/project-users.hook.mjs +70 -0
- package/dist/modules/projects/hooks/project-users.hook.mjs.map +1 -0
- package/dist/modules/projects/services/project-users.service.mjs +67 -0
- package/dist/modules/projects/services/project-users.service.mjs.map +1 -0
- package/dist/modules/projects/types.mjs +22 -0
- package/dist/modules/projects/types.mjs.map +1 -0
- package/dist/server.mjs +10 -0
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/layouts/UsersSelectorPopover.tsx +163 -63
- package/src/index.ts +2 -0
- package/src/modules/accounts/actions/account-management.action.ts +112 -48
- package/src/modules/accounts/types.ts +1 -0
- package/src/modules/projects/actions/add-project-user.action.ts +8 -0
- package/src/modules/projects/actions/list-available-users.action.ts +8 -0
- package/src/modules/projects/actions/list-project-users.action.ts +8 -0
- package/src/modules/projects/actions/remove-project-user.action.ts +8 -0
- package/src/modules/projects/hooks/project-users.hook.ts +81 -0
- package/src/modules/projects/services/project-users.service.ts +94 -0
- package/src/modules/projects/types.ts +28 -0
- package/src/server.ts +7 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
"use server";
|
|
2
2
|
|
|
3
|
-
import { accountService } from
|
|
4
|
-
import { ApiError } from
|
|
3
|
+
import { accountService } from "../services/account.service";
|
|
4
|
+
import { ApiError } from "../../../infra/api/types";
|
|
5
5
|
import type {
|
|
6
6
|
AccountUsersPaginationParams,
|
|
7
7
|
AccountUsersActionResult,
|
|
@@ -17,8 +17,8 @@ import type {
|
|
|
17
17
|
UpdateAccountRequest,
|
|
18
18
|
UpdateAccountUserRequest,
|
|
19
19
|
UpdateUserActionResult,
|
|
20
|
-
} from
|
|
21
|
-
import { twoFactorService } from
|
|
20
|
+
} from "../types";
|
|
21
|
+
import { twoFactorService } from "../services/two-factor.service";
|
|
22
22
|
|
|
23
23
|
export async function listAccountUsersAction(
|
|
24
24
|
params?: AccountUsersPaginationParams
|
|
@@ -27,8 +27,12 @@ export async function listAccountUsersAction(
|
|
|
27
27
|
const { users, total } = await accountService.listAccountUsers(params);
|
|
28
28
|
return { success: true, data: users, total };
|
|
29
29
|
} catch (error) {
|
|
30
|
-
if (error instanceof ApiError)
|
|
31
|
-
|
|
30
|
+
if (error instanceof ApiError)
|
|
31
|
+
return { success: false, error: error.message };
|
|
32
|
+
return {
|
|
33
|
+
success: false,
|
|
34
|
+
error: "Erro ao listar usuários. Tente novamente.",
|
|
35
|
+
};
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
|
|
@@ -39,8 +43,12 @@ export async function updateUserAction(
|
|
|
39
43
|
const result = await accountService.updateAccountUser(user);
|
|
40
44
|
return { success: true, data: result };
|
|
41
45
|
} catch (error) {
|
|
42
|
-
if (error instanceof ApiError)
|
|
43
|
-
|
|
46
|
+
if (error instanceof ApiError)
|
|
47
|
+
return { success: false, error: error.message };
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
error: "Erro ao atualizar usuário. Tente novamente.",
|
|
51
|
+
};
|
|
44
52
|
}
|
|
45
53
|
}
|
|
46
54
|
|
|
@@ -52,8 +60,12 @@ export async function updateAccountUserByIdAction(
|
|
|
52
60
|
const result = await accountService.updateAccountUserById(userId, user);
|
|
53
61
|
return { success: true, data: result };
|
|
54
62
|
} catch (error) {
|
|
55
|
-
if (error instanceof ApiError)
|
|
56
|
-
|
|
63
|
+
if (error instanceof ApiError)
|
|
64
|
+
return { success: false, error: error.message };
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
error: "Erro ao atualizar usuário. Tente novamente.",
|
|
68
|
+
};
|
|
57
69
|
}
|
|
58
70
|
}
|
|
59
71
|
|
|
@@ -64,18 +76,28 @@ export async function updateAccountAction(
|
|
|
64
76
|
await accountService.updateAccount(data);
|
|
65
77
|
return { success: true };
|
|
66
78
|
} catch (error) {
|
|
67
|
-
if (error instanceof ApiError)
|
|
68
|
-
|
|
79
|
+
if (error instanceof ApiError)
|
|
80
|
+
return { success: false, error: error.message };
|
|
81
|
+
return {
|
|
82
|
+
success: false,
|
|
83
|
+
error: "Erro ao atualizar conta. Tente novamente.",
|
|
84
|
+
};
|
|
69
85
|
}
|
|
70
86
|
}
|
|
71
87
|
|
|
72
|
-
export async function deleteAccountUserAction(
|
|
88
|
+
export async function deleteAccountUserAction(
|
|
89
|
+
userId: number
|
|
90
|
+
): Promise<DeleteUserActionResult> {
|
|
73
91
|
try {
|
|
74
92
|
await accountService.deleteAccountUser(userId);
|
|
75
93
|
return { success: true };
|
|
76
94
|
} catch (error) {
|
|
77
|
-
if (error instanceof ApiError)
|
|
78
|
-
|
|
95
|
+
if (error instanceof ApiError)
|
|
96
|
+
return { success: false, error: error.message };
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
error: "Erro ao remover usuário. Tente novamente.",
|
|
100
|
+
};
|
|
79
101
|
}
|
|
80
102
|
}
|
|
81
103
|
|
|
@@ -84,8 +106,9 @@ export async function deleteAccountAction(): Promise<DeleteAccountActionResult>
|
|
|
84
106
|
await accountService.deleteAccount();
|
|
85
107
|
return { success: true };
|
|
86
108
|
} catch (error) {
|
|
87
|
-
if (error instanceof ApiError)
|
|
88
|
-
|
|
109
|
+
if (error instanceof ApiError)
|
|
110
|
+
return { success: false, error: error.message };
|
|
111
|
+
return { success: false, error: "Erro ao excluir conta. Tente novamente." };
|
|
89
112
|
}
|
|
90
113
|
}
|
|
91
114
|
|
|
@@ -96,8 +119,9 @@ export async function createAccountUserAction(
|
|
|
96
119
|
const result = await accountService.createAccountUser(user);
|
|
97
120
|
return { success: true, data: result.data };
|
|
98
121
|
} catch (error) {
|
|
99
|
-
if (error instanceof ApiError)
|
|
100
|
-
|
|
122
|
+
if (error instanceof ApiError)
|
|
123
|
+
return { success: false, error: error.message };
|
|
124
|
+
return { success: false, error: "Erro ao criar usuário. Tente novamente." };
|
|
101
125
|
}
|
|
102
126
|
}
|
|
103
127
|
|
|
@@ -108,18 +132,26 @@ export async function changePasswordAction(
|
|
|
108
132
|
await accountService.changePassword(data);
|
|
109
133
|
return { success: true };
|
|
110
134
|
} catch (error) {
|
|
111
|
-
if (error instanceof ApiError)
|
|
112
|
-
|
|
135
|
+
if (error instanceof ApiError)
|
|
136
|
+
return { success: false, error: error.message };
|
|
137
|
+
return { success: false, error: "Erro ao alterar senha. Tente novamente." };
|
|
113
138
|
}
|
|
114
139
|
}
|
|
115
140
|
|
|
116
|
-
export async function requestEmailChangeAction(
|
|
141
|
+
export async function requestEmailChangeAction(
|
|
142
|
+
newEmail: string
|
|
143
|
+
): Promise<ContactResetResult> {
|
|
117
144
|
try {
|
|
118
|
-
await accountService.requestContactReset(
|
|
145
|
+
await accountService.requestContactReset("email", newEmail);
|
|
119
146
|
return { success: true };
|
|
120
147
|
} catch (error) {
|
|
121
|
-
if (error instanceof ApiError)
|
|
122
|
-
|
|
148
|
+
if (error instanceof ApiError)
|
|
149
|
+
return { success: false, error: error.message };
|
|
150
|
+
return {
|
|
151
|
+
success: false,
|
|
152
|
+
error:
|
|
153
|
+
"E-mail já existente ou ocorreu um erro. Tente novamente mais tarde.",
|
|
154
|
+
};
|
|
123
155
|
}
|
|
124
156
|
}
|
|
125
157
|
|
|
@@ -128,21 +160,32 @@ export async function confirmEmailChangeAction(
|
|
|
128
160
|
newEmail: string
|
|
129
161
|
): Promise<ContactResetResult> {
|
|
130
162
|
try {
|
|
131
|
-
await accountService.confirmContactReset(
|
|
163
|
+
await accountService.confirmContactReset("email", token, newEmail);
|
|
132
164
|
return { success: true };
|
|
133
165
|
} catch (error) {
|
|
134
|
-
if (error instanceof ApiError)
|
|
135
|
-
|
|
166
|
+
if (error instanceof ApiError)
|
|
167
|
+
return { success: false, error: error.message };
|
|
168
|
+
return {
|
|
169
|
+
success: false,
|
|
170
|
+
error: "Código inválido ou expirado. Tente novamente.",
|
|
171
|
+
};
|
|
136
172
|
}
|
|
137
173
|
}
|
|
138
174
|
|
|
139
|
-
export async function requestPhoneChangeAction(
|
|
175
|
+
export async function requestPhoneChangeAction(
|
|
176
|
+
newPhone: string
|
|
177
|
+
): Promise<ContactResetResult> {
|
|
140
178
|
try {
|
|
141
|
-
await accountService.requestContactReset(
|
|
179
|
+
await accountService.requestContactReset("phone", newPhone);
|
|
142
180
|
return { success: true };
|
|
143
181
|
} catch (error) {
|
|
144
|
-
if (error instanceof ApiError)
|
|
145
|
-
|
|
182
|
+
if (error instanceof ApiError)
|
|
183
|
+
return { success: false, error: error.message };
|
|
184
|
+
return {
|
|
185
|
+
success: false,
|
|
186
|
+
error:
|
|
187
|
+
"Número já existente ou ocorreu um erro. Tente novamente mais tarde.",
|
|
188
|
+
};
|
|
146
189
|
}
|
|
147
190
|
}
|
|
148
191
|
|
|
@@ -151,47 +194,68 @@ export async function confirmPhoneChangeAction(
|
|
|
151
194
|
newPhone: string
|
|
152
195
|
): Promise<ContactResetResult> {
|
|
153
196
|
try {
|
|
154
|
-
await accountService.confirmContactReset(
|
|
197
|
+
await accountService.confirmContactReset("phone", token, newPhone);
|
|
155
198
|
return { success: true };
|
|
156
199
|
} catch (error) {
|
|
157
|
-
if (error instanceof ApiError)
|
|
158
|
-
|
|
200
|
+
if (error instanceof ApiError)
|
|
201
|
+
return { success: false, error: error.message };
|
|
202
|
+
return {
|
|
203
|
+
success: false,
|
|
204
|
+
error: "Código inválido ou expirado. Tente novamente.",
|
|
205
|
+
};
|
|
159
206
|
}
|
|
160
207
|
}
|
|
161
208
|
|
|
162
209
|
export async function generateTwoFactorAction(): Promise<TwoFactorGenerateResult> {
|
|
163
210
|
try {
|
|
164
211
|
const result = await twoFactorService.generate();
|
|
165
|
-
return {
|
|
212
|
+
return {
|
|
213
|
+
success: true,
|
|
214
|
+
qrcode: result.data.qrcode,
|
|
215
|
+
backupCodes: result.data.backup_codes,
|
|
216
|
+
};
|
|
166
217
|
} catch (error) {
|
|
167
|
-
if (error instanceof ApiError)
|
|
168
|
-
|
|
218
|
+
if (error instanceof ApiError)
|
|
219
|
+
return { success: false, error: error.message };
|
|
220
|
+
return { success: false, error: "Erro ao gerar QR Code. Tente novamente." };
|
|
169
221
|
}
|
|
170
222
|
}
|
|
171
223
|
|
|
172
|
-
export async function confirmTwoFactorAction(
|
|
224
|
+
export async function confirmTwoFactorAction(
|
|
225
|
+
code: string
|
|
226
|
+
): Promise<TwoFactorActionResult> {
|
|
173
227
|
try {
|
|
174
228
|
await twoFactorService.confirm(code);
|
|
175
|
-
|
|
229
|
+
await accountService.updateAccountUser({ two_factor_authentication: true });
|
|
176
230
|
} catch (error) {
|
|
177
|
-
if (error instanceof ApiError)
|
|
178
|
-
|
|
231
|
+
if (error instanceof ApiError)
|
|
232
|
+
return { success: false, error: error.message };
|
|
233
|
+
return { success: false, error: "Código inválido. Tente novamente." };
|
|
179
234
|
}
|
|
235
|
+
|
|
236
|
+
return { success: true };
|
|
180
237
|
}
|
|
181
238
|
|
|
182
|
-
export async function disableTwoFactorAction(
|
|
239
|
+
export async function disableTwoFactorAction(
|
|
240
|
+
code: string
|
|
241
|
+
): Promise<TwoFactorActionResult> {
|
|
183
242
|
try {
|
|
184
243
|
await twoFactorService.verify(code);
|
|
185
244
|
} catch (error) {
|
|
186
|
-
if (error instanceof ApiError)
|
|
187
|
-
|
|
245
|
+
if (error instanceof ApiError)
|
|
246
|
+
return { success: false, error: error.message };
|
|
247
|
+
return { success: false, error: "Código inválido. Tente novamente." };
|
|
188
248
|
}
|
|
189
249
|
|
|
190
250
|
try {
|
|
191
251
|
await twoFactorService.disable();
|
|
192
252
|
return { success: true };
|
|
193
253
|
} catch (error) {
|
|
194
|
-
if (error instanceof ApiError)
|
|
195
|
-
|
|
254
|
+
if (error instanceof ApiError)
|
|
255
|
+
return { success: false, error: error.message };
|
|
256
|
+
return {
|
|
257
|
+
success: false,
|
|
258
|
+
error: "Erro ao desabilitar 2FA. Tente novamente.",
|
|
259
|
+
};
|
|
196
260
|
}
|
|
197
261
|
}
|
|
@@ -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';
|