Skip to content

Commit bced8dc

Browse files
committed
api for dynamodb addMember done
* siglead management screen fix choppy nav * moved id -> name record into commons * created add member post route * implemented backend add member to dynamodb * still need to check if member already exists and add to azure
1 parent b93db84 commit bced8dc

File tree

8 files changed

+192
-42
lines changed

8 files changed

+192
-42
lines changed

src/api/functions/siglead.ts

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
import {
2+
AttributeValue,
23
DynamoDBClient,
4+
PutItemCommand,
5+
PutItemCommandInput,
36
QueryCommand,
47
ScanCommand,
58
} from "@aws-sdk/client-dynamodb";
69
import { unmarshall } from "@aws-sdk/util-dynamodb";
7-
import { OrganizationList } from "common/orgs.js";
10+
import { OrganizationList, orgIds2Name } from "common/orgs.js";
811
import {
12+
DynamoDBItem,
913
SigDetailRecord,
1014
SigMemberCount,
1115
SigMemberRecord,
16+
SigMemberUpdateRecord,
1217
} from "common/types/siglead.js";
1318
import { transformSigLeadToURI } from "common/utils.js";
19+
import { KeyObject } from "crypto";
1420
import { string } from "zod";
1521

1622
export async function fetchMemberRecords(
@@ -84,32 +90,44 @@ export async function fetchSigCounts(
8490

8591
const result = await dynamoClient.send(scan);
8692

87-
const ids2Name: Record<string, string> = {};
88-
OrganizationList.forEach((org) => {
89-
const sigid = transformSigLeadToURI(org);
90-
ids2Name[sigid] = org;
91-
});
92-
9393
const counts: Record<string, number> = {};
94+
// Object.entries(orgIds2Name).forEach(([id, _]) => {
95+
// counts[id] = 0;
96+
// });
97+
9498
(result.Items || []).forEach((item) => {
9599
const sigGroupId = item.sigGroupId?.S;
96100
if (sigGroupId) {
97101
counts[sigGroupId] = (counts[sigGroupId] || 0) + 1;
98102
}
99103
});
100104

101-
const joined: Record<string, [string, number]> = {};
102-
Object.keys(counts).forEach((sigid) => {
103-
joined[sigid] = [ids2Name[sigid], counts[sigid]];
104-
});
105-
106-
const countsArray: SigMemberCount[] = Object.entries(joined).map(
107-
([sigid, [signame, count]]) => ({
108-
sigid,
109-
signame,
105+
const countsArray: SigMemberCount[] = Object.entries(counts).map(
106+
([id, count]) => ({
107+
sigid: id,
108+
signame: orgIds2Name[id],
110109
count,
111110
}),
112111
);
113112
console.log(countsArray);
114113
return countsArray;
115114
}
115+
116+
export async function addMemberToSig(
117+
sigMemberTableName: string,
118+
sigMemberUpdateRequest: SigMemberUpdateRecord,
119+
dynamoClient: DynamoDBClient,
120+
) {
121+
const item: Record<string, AttributeValue> = {};
122+
Object.entries(sigMemberUpdateRequest).forEach(([k, v]) => {
123+
item[k] = { S: v };
124+
});
125+
const input: PutItemCommandInput = {
126+
Item: item,
127+
ReturnConsumedCapacity: "TOTAL",
128+
TableName: sigMemberTableName,
129+
};
130+
// console.log(input);
131+
const put = new PutItemCommand(input);
132+
const response = await dynamoClient.send(put);
133+
}

src/api/routes/siglead.ts

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ import {
88
SigleadGetRequest,
99
SigMemberCount,
1010
SigMemberRecord,
11+
SigMemberUpdateRecord,
1112
} from "common/types/siglead.js";
1213
import {
14+
addMemberToSig,
1315
fetchMemberRecords,
1416
fetchSigCounts,
1517
fetchSigDetail,
1618
} from "api/functions/siglead.js";
1719
import { intersection } from "api/plugins/auth.js";
20+
import { request } from "http";
1821

1922
const sigleadRoutes: FastifyPluginAsync = async (fastify, _options) => {
2023
const limitedRoutes: FastifyPluginAsync = async (fastify) => {
@@ -97,36 +100,47 @@ const sigleadRoutes: FastifyPluginAsync = async (fastify, _options) => {
97100
);
98101

99102
// fetch sig count
100-
fastify.get<SigleadGetRequest>(
101-
"/sigcount",
102-
{
103-
onRequest: async (request, reply) => {
104-
/*await fastify.authorize(request, reply, [
105-
AppRoles.LINKS_MANAGER,
106-
AppRoles.LINKS_ADMIN,
107-
]);*/
108-
},
109-
},
103+
fastify.get<SigleadGetRequest>("/sigcount", async (request, reply) => {
104+
// First try-catch: Fetch owner records
105+
let sigMemCounts: SigMemberCount[];
106+
try {
107+
sigMemCounts = await fetchSigCounts(
108+
genericConfig.SigleadDynamoSigMemberTableName,
109+
fastify.dynamoClient,
110+
);
111+
} catch (error) {
112+
request.log.error(
113+
`Failed to fetch sig member counts record: ${error instanceof Error ? error.toString() : "Unknown error"}`,
114+
);
115+
throw new DatabaseFetchError({
116+
message:
117+
"Failed to fetch sig member counts record from Dynamo table.",
118+
});
119+
}
120+
121+
// Send the response
122+
reply.code(200).send(sigMemCounts);
123+
});
124+
125+
// add member
126+
fastify.post<{ Body: SigMemberUpdateRecord }>(
127+
"/addMember",
110128
async (request, reply) => {
111-
// First try-catch: Fetch owner records
112-
let sigMemCounts: SigMemberCount[];
113129
try {
114-
sigMemCounts = await fetchSigCounts(
130+
await addMemberToSig(
115131
genericConfig.SigleadDynamoSigMemberTableName,
132+
request.body,
116133
fastify.dynamoClient,
117134
);
118135
} catch (error) {
119136
request.log.error(
120-
`Failed to fetch sig member counts record: ${error instanceof Error ? error.toString() : "Unknown error"}`,
137+
`Failed to add member: ${error instanceof Error ? error.toString() : "Unknown error"}`,
121138
);
122139
throw new DatabaseFetchError({
123-
message:
124-
"Failed to fetch sig member counts record from Dynamo table.",
140+
message: "Failed to add sig member record to Dynamo table.",
125141
});
126142
}
127-
128-
// Send the response
129-
reply.code(200).send(sigMemCounts);
143+
reply.code(200);
130144
},
131145
);
132146
};

src/common/orgs.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { transformSigLeadToURI } from "./utils.js";
2+
13
export const SIGList = [
24
"SIGPwny",
35
"SIGCHI",
@@ -28,3 +30,10 @@ export const CommitteeList = [
2830
"Marketing Committee",
2931
] as [string, ...string[]];
3032
export const OrganizationList = ["ACM", ...SIGList, ...CommitteeList] as [string, ...string[]];
33+
34+
const orgIds2Name: Record<string, string> = {};
35+
OrganizationList.forEach((org) => {
36+
const sigid = transformSigLeadToURI(org);
37+
orgIds2Name[sigid] = org;
38+
});
39+
export { orgIds2Name };

src/common/types/siglead.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,28 @@ export type SigMemberCount = {
2121
sigid: string;
2222
signame: string;
2323
count: number;
24-
};
24+
};
25+
26+
export type SigMemberUpdateRecord = {
27+
sigGroupId: string;
28+
email: string;
29+
id: string;
30+
memberName: string;
31+
designation: string;
32+
createdAt: string;
33+
updatedAt: string;
34+
}
35+
36+
export type SigMemberUpdateRequest = {
37+
38+
}
39+
40+
export type DynamoDBItem = {
41+
Item: {
42+
[key: string]: {
43+
[key: string]: string;
44+
};
45+
};
46+
ReturnConsumedCapacity: string;
47+
TableName: string;
48+
}

src/common/utils.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,16 @@ export function transformSigLeadToURI(org: string) {
5656
.replace(/-{2,}/g, "-");
5757

5858
return org === "-" ? "" : org;
59+
}
60+
61+
export function getTimeInFormat() {
62+
const date = new Date();
63+
const year = date.getUTCFullYear();
64+
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
65+
const day = String(date.getUTCDate()).padStart(2, '0');
66+
const hours = String(date.getUTCHours()).padStart(2, '0');
67+
const minutes = String(date.getUTCMinutes()).padStart(2, '0');
68+
const seconds = String(date.getUTCSeconds()).padStart(2, '0');
69+
70+
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}Z`;
5971
}

src/ui/Router.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ import { ManageProfilePage } from "./pages/profile/ManageProfile.page";
2525
import { ManageStripeLinksPage } from "./pages/stripe/ViewLinks.page";
2626
import { ManageRoomRequestsPage } from "./pages/roomRequest/RoomRequestLanding.page";
2727
import { ManageSigLeadsPage } from "./pages/siglead/ManageSigLeads.page";
28-
import { ViewSigLeadPage } from "./pages/siglead/ViewSigLead.page";
28+
import {
29+
AddMemberToSigPage,
30+
ViewSigLeadPage,
31+
} from "./pages/siglead/ViewSigLead.page";
2932
import { ViewRoomRequest } from "./pages/roomRequest/ViewRoomRequest.page";
3033
import { ViewLogsPage } from "./pages/logs/ViewLogs.page";
3134
import { TermsOfService } from "./pages/tos/TermsOfService.page";
@@ -197,6 +200,10 @@ const authenticatedRouter = createBrowserRouter([
197200
path: "/siglead-management/:sigId",
198201
element: <ViewSigLeadPage />,
199202
},
203+
{
204+
path: "/siglead-management/:sigId/addMember",
205+
element: <AddMemberToSigPage />,
206+
},
200207
{
201208
path: "/roomRequests",
202209
element: <ManageRoomRequestsPage />,

src/ui/pages/siglead/SigScreenComponents.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import React, { useEffect, useMemo, useState } from "react";
22
import { OrganizationList } from "@common/orgs";
33
import { NavLink, Paper } from "@mantine/core";
44
import { IconUsersGroup } from "@tabler/icons-react";
5-
import { useLocation } from "react-router-dom";
5+
import { useLocation, useNavigate } from "react-router-dom";
66
import { SigMemberCount } from "@common/types/siglead";
77

88
const renderSigLink = (sigMemCount: SigMemberCount, index: number) => {
9+
const navigate = useNavigate();
10+
911
const color =
1012
"light-dark(var(--mantine-color-black), var(--mantine-color-white))";
1113
const size = "18px";
@@ -14,7 +16,7 @@ const renderSigLink = (sigMemCount: SigMemberCount, index: number) => {
1416
const count = sigMemCount.count;
1517
return (
1618
<NavLink
17-
href={`${useLocation().pathname}/${id}`}
19+
onClick={() => navigate(`./${id}`)}
1820
active={index % 2 === 0}
1921
label={name}
2022
color="var(--mantine-color-blue-light)"

src/ui/pages/siglead/ViewSigLead.page.tsx

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,20 @@ import { DateTimePicker } from "@mantine/dates";
1818
import { useForm, zodResolver } from "@mantine/form";
1919
import { notifications } from "@mantine/notifications";
2020
import dayjs from "dayjs";
21-
import React, { useEffect, useState } from "react";
21+
import React, { FC, useEffect, useState } from "react";
2222
import { useNavigate, useParams } from "react-router-dom";
2323
import { z } from "zod";
2424
import { AuthGuard } from "@ui/components/AuthGuard";
2525
import { getRunEnvironmentConfig } from "@ui/config";
2626
import { useApi } from "@ui/util/api";
2727
import { AppRoles } from "@common/roles";
28-
import { SigDetailRecord, SigMemberRecord } from "@common/types/siglead.js";
28+
import {
29+
SigDetailRecord,
30+
SigMemberRecord,
31+
SigMemberUpdateRecord,
32+
} from "@common/types/siglead.js";
33+
import { getTimeInFormat } from "@common/utils";
34+
import { orgIds2Name } from "@common/orgs";
2935

3036
export const ViewSigLeadPage: React.FC = () => {
3137
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
@@ -162,7 +168,9 @@ export const ViewSigLeadPage: React.FC = () => {
162168
<Stack>
163169
<Button variant="white">Member Count: {sigMembers.length}</Button>
164170

165-
<Button>Add Member</Button>
171+
<Button onClick={() => navigate("./addMember")}>
172+
Add Member
173+
</Button>
166174
<Button
167175
onClick={() => navigate("../siglead-management")}
168176
variant="outline"
@@ -191,3 +199,59 @@ export const ViewSigLeadPage: React.FC = () => {
191199
</AuthGuard>
192200
);
193201
};
202+
203+
export const AddMemberToSigPage: FC = () => {
204+
const { sigId } = useParams();
205+
const api = useApi("core");
206+
207+
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
208+
event.preventDefault();
209+
const formData = new FormData(event.currentTarget);
210+
// console.log(formData)
211+
const data = Object.fromEntries(
212+
formData.entries(),
213+
) as SigMemberUpdateRecord;
214+
data.designation = "M";
215+
data.sigGroupId = sigId || "";
216+
data.createdAt = getTimeInFormat();
217+
data.updatedAt = data.createdAt;
218+
// console.log(data)
219+
await api.post(`/api/v1/siglead/addMember`, data);
220+
}
221+
222+
return (
223+
<AuthGuard
224+
resourceDef={{ service: "core", validRoles: [AppRoles.SIGLEAD_MANAGER] }}
225+
>
226+
<h1>Add Member to {orgIds2Name[sigId || "acm"]}</h1>
227+
<form id="form" onSubmit={handleSubmit}>
228+
<label htmlFor="email">email: </label>
229+
<input
230+
type="email"
231+
name="email"
232+
id="email"
233+
placeholder="[email protected]"
234+
/>
235+
<br />
236+
<label htmlFor="id">uuid: </label>
237+
<input
238+
type="text"
239+
name="id"
240+
id="id"
241+
placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
242+
/>
243+
<br />
244+
<label htmlFor="memberName">name: </label>
245+
<input
246+
type="text"
247+
name="memberName"
248+
id="memberName"
249+
placeholder="John Doe"
250+
/>
251+
<br />
252+
{/* <button type="submit" onSubmit={handleSubmit}>Submit</button> */}
253+
<button type="submit">Submit</button>
254+
</form>
255+
</AuthGuard>
256+
);
257+
};

0 commit comments

Comments
 (0)