@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.
- package/dist/components/layouts/UsersSelectorPopover.mjs +155 -139
- package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -1
- package/dist/index.mjs +11 -4
- package/dist/index.mjs.map +1 -1
- package/dist/modules/auth/actions/is-two-factor-pending.action.mjs +9 -0
- package/dist/modules/auth/actions/is-two-factor-pending.action.mjs.map +1 -0
- package/dist/modules/auth/actions/verify-two-factor.action.mjs +16 -0
- package/dist/modules/auth/actions/verify-two-factor.action.mjs.map +1 -0
- package/dist/modules/auth/hooks/useUserQuery.mjs +27 -1
- package/dist/modules/auth/hooks/useUserQuery.mjs.map +1 -1
- package/dist/modules/auth/services/auth.service.mjs +55 -18
- package/dist/modules/auth/services/auth.service.mjs.map +1 -1
- package/dist/modules/projects/actions/list-available-users.action.mjs +2 -2
- package/dist/modules/projects/actions/list-available-users.action.mjs.map +1 -1
- package/dist/modules/projects/actions/list-project-users.action.mjs +2 -2
- package/dist/modules/projects/actions/list-project-users.action.mjs.map +1 -1
- package/dist/modules/projects/hooks/list-available-users.hook.mjs +27 -0
- package/dist/modules/projects/hooks/list-available-users.hook.mjs.map +1 -0
- package/dist/modules/projects/hooks/list-project-users.hook.mjs +27 -0
- package/dist/modules/projects/hooks/list-project-users.hook.mjs.map +1 -0
- package/dist/modules/projects/services/project-users.service.mjs +21 -10
- package/dist/modules/projects/services/project-users.service.mjs.map +1 -1
- package/dist/modules/projects/types.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/layouts/UsersSelectorPopover.tsx +119 -126
- package/src/index.ts +5 -4
- package/src/modules/auth/actions/is-two-factor-pending.action.ts +7 -0
- package/src/modules/auth/actions/verify-two-factor.action.ts +15 -0
- package/src/modules/auth/hooks/useUserQuery.ts +28 -1
- package/src/modules/auth/schema.ts +23 -7
- package/src/modules/auth/services/auth.service.ts +75 -19
- package/src/modules/projects/actions/list-available-users.action.ts +3 -3
- package/src/modules/projects/actions/list-project-users.action.ts +3 -3
- package/src/modules/projects/hooks/list-available-users.hook.ts +26 -0
- package/src/modules/projects/hooks/list-project-users.hook.ts +26 -0
- package/src/modules/projects/services/project-users.service.ts +23 -10
- package/src/modules/projects/types.ts +13 -1
- package/dist/modules/projects/hooks/project-users.hook.mjs +0 -70
- package/dist/modules/projects/hooks/project-users.hook.mjs.map +0 -1
- package/src/modules/projects/hooks/project-users.hook.ts +0 -81
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useInfiniteQuery } from '@tanstack/react-query';
|
|
4
|
+
import { listProjectUsersAction } from '../actions/list-project-users.action';
|
|
5
|
+
|
|
6
|
+
const PAGE_SIZE = 20;
|
|
7
|
+
|
|
8
|
+
export const LIST_PROJECT_USERS_BASE_KEY = (projectId: number) => ['project-users', projectId, 'in'];
|
|
9
|
+
export const LIST_PROJECT_USERS_QUERY_KEY = (projectId: number, search: string = '') => [
|
|
10
|
+
...LIST_PROJECT_USERS_BASE_KEY(projectId),
|
|
11
|
+
search,
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export function useListProjectUsers(projectId: number, search: string = '') {
|
|
15
|
+
return useInfiniteQuery({
|
|
16
|
+
queryKey: LIST_PROJECT_USERS_QUERY_KEY(projectId, search),
|
|
17
|
+
queryFn: ({ pageParam }) =>
|
|
18
|
+
listProjectUsersAction(projectId, { search: search || undefined, page: pageParam as number, limit: PAGE_SIZE }),
|
|
19
|
+
getNextPageParam: (lastPage, allPages) => {
|
|
20
|
+
const loaded = allPages.reduce((sum, p) => sum + p.data.length, 0);
|
|
21
|
+
return loaded < lastPage.total ? allPages.length + 1 : undefined;
|
|
22
|
+
},
|
|
23
|
+
initialPageParam: 1,
|
|
24
|
+
enabled: !!projectId,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -2,13 +2,16 @@ import 'server-only';
|
|
|
2
2
|
|
|
3
3
|
import { api } from '../../../infra/api/client';
|
|
4
4
|
import { ApiError } from '../../../infra/api/types';
|
|
5
|
+
import { buildQueryParams } from '../../../infra/utils/params';
|
|
5
6
|
import { getUserContext } from '../../auth/utils/get-user-context';
|
|
6
7
|
import {
|
|
7
8
|
AccountUser,
|
|
8
9
|
AccountUserSchema,
|
|
9
10
|
AddRemoveProjectUsersParams,
|
|
11
|
+
ListUsersParams,
|
|
10
12
|
ProjectUser,
|
|
11
13
|
ProjectUserSchema,
|
|
14
|
+
UsersPage,
|
|
12
15
|
} from '../types';
|
|
13
16
|
|
|
14
17
|
interface ApiListResponse<T> {
|
|
@@ -24,9 +27,10 @@ interface ApiActionResponse {
|
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
class ProjectUsersService {
|
|
27
|
-
async listInProject(
|
|
30
|
+
async listInProject(projectId: number, params: ListUsersParams = {}): Promise<UsersPage<ProjectUser>> {
|
|
28
31
|
const { id_account, id_user } = await getUserContext();
|
|
29
|
-
const
|
|
32
|
+
const query = buildQueryParams(params as Record<string, string | number | boolean | undefined>);
|
|
33
|
+
const url = `/account/${id_account}/user/${id_user}/projects/${projectId}/users${query ? `?${query}` : ''}`;
|
|
30
34
|
|
|
31
35
|
const response = await api.apps.get<ApiListResponse<ProjectUser>>(url);
|
|
32
36
|
|
|
@@ -38,12 +42,17 @@ class ProjectUsersService {
|
|
|
38
42
|
);
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
return
|
|
45
|
+
return {
|
|
46
|
+
data: response.data.map((item) => ProjectUserSchema.parse(item)),
|
|
47
|
+
total: response.total,
|
|
48
|
+
page: params.page ?? 1,
|
|
49
|
+
};
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
async listNotInProject(
|
|
52
|
+
async listNotInProject(projectId: number, params: ListUsersParams = {}): Promise<UsersPage<AccountUser>> {
|
|
45
53
|
const { id_account } = await getUserContext();
|
|
46
|
-
const
|
|
54
|
+
const query = buildQueryParams({ notInProject: projectId, ...params } as Record<string, string | number | boolean | undefined>);
|
|
55
|
+
const url = `/accounts/${id_account}/users${query ? `?${query}` : ''}`;
|
|
47
56
|
|
|
48
57
|
const response = await api.apps.get<ApiListResponse<AccountUser>>(url);
|
|
49
58
|
|
|
@@ -55,12 +64,16 @@ class ProjectUsersService {
|
|
|
55
64
|
);
|
|
56
65
|
}
|
|
57
66
|
|
|
58
|
-
return
|
|
67
|
+
return {
|
|
68
|
+
data: response.data.map((item) => AccountUserSchema.parse(item)),
|
|
69
|
+
total: response.total,
|
|
70
|
+
page: params.page ?? 1,
|
|
71
|
+
};
|
|
59
72
|
}
|
|
60
73
|
|
|
61
|
-
async addToProject({
|
|
74
|
+
async addToProject({ projectId, users }: AddRemoveProjectUsersParams): Promise<void> {
|
|
62
75
|
const { id_account, id_user } = await getUserContext();
|
|
63
|
-
const url = `/account/${id_account}/user/${id_user}/projects/${
|
|
76
|
+
const url = `/account/${id_account}/user/${id_user}/projects/${projectId}/users`;
|
|
64
77
|
|
|
65
78
|
const response = await api.apps.post<ApiActionResponse>(url, { users });
|
|
66
79
|
|
|
@@ -73,9 +86,9 @@ class ProjectUsersService {
|
|
|
73
86
|
}
|
|
74
87
|
}
|
|
75
88
|
|
|
76
|
-
async removeFromProject({
|
|
89
|
+
async removeFromProject({ projectId, users }: AddRemoveProjectUsersParams): Promise<void> {
|
|
77
90
|
const { id_account, id_user } = await getUserContext();
|
|
78
|
-
const url = `/account/${id_account}/user/${id_user}/projects/${
|
|
91
|
+
const url = `/account/${id_account}/user/${id_user}/projects/${projectId}/users`;
|
|
79
92
|
|
|
80
93
|
const response = await api.apps.delete<ApiActionResponse>(url, {
|
|
81
94
|
body: JSON.stringify({ users }),
|
|
@@ -23,6 +23,18 @@ export const AccountUserSchema = z.object({
|
|
|
23
23
|
export type AccountUser = z.infer<typeof AccountUserSchema>;
|
|
24
24
|
|
|
25
25
|
export interface AddRemoveProjectUsersParams {
|
|
26
|
-
|
|
26
|
+
projectId: number;
|
|
27
27
|
users: number[];
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
export interface ListUsersParams {
|
|
31
|
+
search?: string;
|
|
32
|
+
page?: number;
|
|
33
|
+
limit?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface UsersPage<T> {
|
|
37
|
+
data: T[];
|
|
38
|
+
total: number;
|
|
39
|
+
page: number;
|
|
40
|
+
}
|
|
@@ -1,70 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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":[]}
|
|
@@ -1,81 +0,0 @@
|
|
|
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
|
-
}
|