Skip to content

Commit bf43009

Browse files
committed
refactor: cleaned up and optimized code
1 parent d4670c5 commit bf43009

File tree

8 files changed

+170
-69
lines changed

8 files changed

+170
-69
lines changed

client/src/api.ts

+82
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ import {
2929
TableOfContents,
3030
User,
3131
UserSearchParams,
32+
BaseInvitation,
33+
Sender,
34+
ProjectSummary,
35+
InvitationsResponse,
3236
} from "./types";
3337
import {
3438
AddableProjectTeamMember,
@@ -1019,6 +1023,84 @@ class API {
10191023
params,
10201024
});
10211025
}
1026+
1027+
// Project Invitations
1028+
async createProjectInvitation(
1029+
projectID: string,
1030+
email: string,
1031+
role: string
1032+
) {
1033+
const res = await axios.post<{
1034+
responseInvitation: BaseInvitation
1035+
} & ConductorBaseResponse>(
1036+
`/project-invitations/${projectID}`,
1037+
{
1038+
email,
1039+
role
1040+
}
1041+
);
1042+
return res.data;
1043+
}
1044+
1045+
async getAllProjectInvitations(
1046+
projectID: string,
1047+
page: number = 1,
1048+
limit: number
1049+
) {
1050+
const res = await axios.get<{
1051+
data: InvitationsResponse;
1052+
} & ConductorBaseResponse>(`/project-invitations/project/${projectID}`, {
1053+
params: { page, limit },
1054+
});
1055+
return res.data;
1056+
}
1057+
1058+
async getProjectInvitation(
1059+
inviteID: string,
1060+
token: string | null
1061+
) {
1062+
const res = await axios.get<{
1063+
invitation: BaseInvitation & {sender: Sender} & {project: ProjectSummary};
1064+
} & ConductorBaseResponse>(`/project-invitations/${inviteID}`, {
1065+
params: { token },
1066+
});
1067+
return res.data;
1068+
}
1069+
1070+
async deleteInvitation(invitationId: string) {
1071+
const res = await axios.delete<
1072+
{
1073+
deleted: boolean;
1074+
} & ConductorBaseResponse
1075+
>(`/project-invitations/${invitationId}`);
1076+
1077+
return res.data;
1078+
}
1079+
1080+
async updateInvitationRole(inviteID: string, role: string) {
1081+
const res = await axios.put<
1082+
{
1083+
updatedInvitation: BaseInvitation;
1084+
} & ConductorBaseResponse
1085+
>(`/project-invitations/${inviteID}/update`, { role });
1086+
1087+
return res.data;
1088+
}
1089+
1090+
async acceptProjectInvitation(inviteID: string | null, token: string | null){
1091+
const res = await axios.post<{
1092+
data: string
1093+
} & ConductorBaseResponse>(
1094+
`/project-invitation/${inviteID}/accept`,
1095+
{},
1096+
{
1097+
params: {token},
1098+
}
1099+
);
1100+
1101+
return res.data;
1102+
}
1103+
10221104
}
10231105

10241106
export default new API();

client/src/components/projects/ManageTeamModal.tsx

+11-26
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,8 @@ const ManageTeamModal: React.FC<ManageTeamModalProps> = ({
107107
}
108108

109109
setLoading(true);
110-
const res = await axios.post(`/project-invitations/${project.projectID}`, {
111-
email: inviteEmail,
112-
role: "member"
113-
});
110+
const res = await api.createProjectInvitation(project.projectID, inviteEmail, "member");
114111

115-
if (res.data.err) {
116-
handleGlobalError(res.data.errMsg);
117-
return;
118-
}
119112

120113
setInviteEmail("");
121114
setCurrentPage(1);
@@ -131,14 +124,12 @@ const ManageTeamModal: React.FC<ManageTeamModalProps> = ({
131124
const fetchPendingInvitations = async (page: number = 1) => {
132125
try {
133126
setInvitationsLoading(true);
134-
const res = await axios.get(`/project-invitations/project/${project.projectID}?page=${page}&limit=${ITEMS_PER_PAGE}`);
135127

136-
if (res.data.err) {
137-
throw new Error(res.data.errMsg);
138-
}
128+
const res = await api.getAllProjectInvitations(project.projectID, page, ITEMS_PER_PAGE);
129+
139130

140-
setPendingInvitations(res.data.data.invitations || []);
141-
setTotalPages(Math.ceil(res.data.data.total / ITEMS_PER_PAGE));
131+
setPendingInvitations(res.data.invitations || []);
132+
setTotalPages(Math.ceil(res.data.total / ITEMS_PER_PAGE));
142133
} catch (err) {
143134
handleGlobalError(err);
144135
} finally {
@@ -149,10 +140,7 @@ const ManageTeamModal: React.FC<ManageTeamModalProps> = ({
149140
const handleDeleteInvitation = async (invitationId: string) => {
150141
try {
151142
setLoading(true);
152-
const res = await axios.delete(`/project-invitations/${invitationId}`);
153-
if (res.data.err) {
154-
throw new Error(res.data.errMsg);
155-
}
143+
const res = await api.deleteInvitation(invitationId);
156144
await fetchPendingInvitations();
157145
} catch (err) {
158146
handleGlobalError(err);
@@ -163,11 +151,13 @@ const ManageTeamModal: React.FC<ManageTeamModalProps> = ({
163151

164152
useEffect(() => {
165153
const fetchData = async () => {
166-
await fetchPendingInvitations();
154+
if (show) { // Only fetch if modal is shown
155+
await fetchPendingInvitations();
156+
}
167157
};
168158

169159
fetchData();
170-
}, []);
160+
}, [show]);
171161

172162
/**
173163
* Retrieves a list of users that can be added as team members to the
@@ -260,12 +250,7 @@ const ManageTeamModal: React.FC<ManageTeamModalProps> = ({
260250
throw new Error("Invalid invite ID or role. This may be caused by an internal error.");
261251
}
262252
setLoading(true);
263-
const res = await axios.put(`/project-invitations/${inviteID}/update`, { role });
264-
265-
if (res.data.err) {
266-
handleGlobalError(res.data.errMsg);
267-
return;
268-
}
253+
const res = await api.updateInvitationRole(inviteID, role);
269254

270255
await fetchPendingInvitations(currentPage);
271256
onDataChanged();

client/src/screens/conductor/Projects/AcceptProjectInviteScreen.tsx

+11-10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useLocation, Link } from "react-router-dom";
33
import { Image, Button, Grid, Container } from "semantic-ui-react";
44
import axios from "axios";
55
import useGlobalError from "../../../components/error/ErrorHooks";
6+
import api from "../../../api";
67

78
function AcceptProjectInviteScreen() {
89
const location = useLocation();
@@ -29,26 +30,26 @@ function AcceptProjectInviteScreen() {
2930

3031
const checkInviteStatus = async (inviteID: string, token: string | null) => {
3132
try {
32-
const response = await axios.get(`/project-invitations/${inviteID}?token=${token}`);
33-
const projectID = response.data.data.projectID;
33+
const response = await api.getProjectInvitation(inviteID, token);
34+
const projectID = response.invitation.projectID;
3435

35-
if (response.data.data.accepted) {
36+
if (response.invitation.accepted) {
3637
window.location.href = `/projects/${projectID}`;
3738
return;
3839
}
3940

40-
setProjectTitle(response.data.data.project.title);
41-
} catch (error: any) {
42-
handleGlobalError(error.response?.data?.errMsg || "An unexpected error occurred.");
41+
setProjectTitle(response.invitation.project.title);
42+
} catch (error) {
43+
handleGlobalError(error);
4344
}
4445
};
4546

4647
const handleAccept = async () => {
4748
try {
48-
const response = await axios.post(`/project-invitation/${inviteID}/accept?token=${token}`);
49-
window.location.href = `/projects/${response.data.data}`; // Redirect after accepting
50-
} catch (error: any) {
51-
handleGlobalError(error.response?.data?.errMsg || "An unexpected error occurred.");
49+
const response = await api.acceptProjectInvitation(inviteID, token);
50+
window.location.href = `/projects/${response.data}`; // Redirect after accepting
51+
} catch (error) {
52+
handleGlobalError(error);
5253
}
5354
};
5455

client/src/types/ProjectInvitation.ts

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
export type Sender = {
2+
uuid: string;
3+
firstName: string;
4+
lastName: string;
5+
};
6+
7+
export type ProjectSummary = {
8+
projectID: string;
9+
title: string;
10+
};
11+
12+
export type BaseInvitation = {
13+
projectID: string;
14+
senderID: string;
15+
email: string;
16+
role: string;
17+
accepted: boolean;
18+
expires: string;
19+
inviteID: string;
20+
createdAt: string;
21+
updatedAt: string;
22+
};
23+
24+
export type Invitation = BaseInvitation & {
25+
sender: Sender;
26+
};
27+
28+
export type GetInvitationResponse = BaseInvitation & {
29+
project: ProjectSummary;
30+
sender: Sender;
31+
};
32+
33+
export type InvitationsResponse = {
34+
invitations: Invitation[];
35+
total: number;
36+
pagination: {
37+
page: number;
38+
limit: number;
39+
};
40+
};

client/src/types/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export * from "./OrgEvent";
2020
export * from "./PeerReview";
2121
export * from "./PeerReviewRubric";
2222
export * from "./Project";
23+
export * from "./ProjectInvitation"
2324
export * from "./support";
2425
export * from "./Search";
2526
export * from "./User";

package-lock.json

+2-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/api.js

+8-11
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import orgEventsAPI from "./api/orgevents.js";
3636
import paymentsAPI from "./api/payments.js";
3737
import kbAPI from "./api/kb.js";
3838
import supportAPI from "./api/support.js";
39-
import projectInvitationsAPI from "./api/projectinvitations.ts";
39+
import projectInvitationsAPI from "./api/projectinvitations.js";
4040

4141
import * as centralIdentityValidators from "./api/validators/central-identity.js";
4242
import * as collectionValidators from "./api/validators/collections.js";
@@ -49,7 +49,7 @@ import * as AssetTagFrameworkValidators from "./api/validators/assettagframework
4949
import * as AuthorsValidators from "./api/validators/authors.js";
5050
import * as BookValidators from "./api/validators/book.js";
5151
import * as UserValidators from "./api/validators/user.js";
52-
import * as ProjectInvitationValidators from "./api/validators/project-invitations.ts";
52+
import * as ProjectInvitationValidators from "./api/validators/project-invitations.js";
5353

5454
const router = express.Router();
5555

@@ -2297,6 +2297,12 @@ router
22972297
middleware.validateZod(ProjectInvitationValidators.getProjectInvitationSchema),
22982298
projectInvitationsAPI.getProjectInvitation
22992299
)
2300+
.delete(
2301+
authAPI.verifyRequest,
2302+
authAPI.getUserAttributes,
2303+
middleware.validateZod(ProjectInvitationValidators.deleteProjectInvitationSchema),
2304+
projectInvitationsAPI.deleteProjectInvitation
2305+
)
23002306

23012307
router
23022308
.route("/project-invitations/project/:projectID")
@@ -2307,15 +2313,6 @@ router
23072313
projectInvitationsAPI.getAllInvitationsForProject
23082314
)
23092315

2310-
router
2311-
.route("/project-invitations/:inviteID")
2312-
.delete(
2313-
authAPI.verifyRequest,
2314-
authAPI.getUserAttributes,
2315-
middleware.validateZod(ProjectInvitationValidators.deleteProjectInvitationSchema),
2316-
projectInvitationsAPI.deleteProjectInvitation
2317-
)
2318-
23192316
router
23202317
.route("/project-invitation/:inviteID/accept")
23212318
.post(

0 commit comments

Comments
 (0)