Skip to content

Commit 95bde7b

Browse files
committed
feat: intigrate the backend with frontend for email and notifications
1 parent cb95355 commit 95bde7b

File tree

6 files changed

+126
-4
lines changed

6 files changed

+126
-4
lines changed

backend/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
"main": "index.js",
55
"source": "dist/index.js",
66
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
7+
"test": "echo \"Error: no test specified\" && exit 1",
8+
"start-local": "nodemon ./dist/index.js"
89
},
910
"keywords": [],
1011
"author": "",
1112
"license": "ISC",
1213
"dependencies": {
1314
"body-parser": "^1.20.2",
15+
"cors": "^2.8.5",
1416
"express": "^4.18.2",
1517
"express-async-handler": "^1.2.0",
1618
"nodemailer": "^6.9.4",

backend/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import bodyParser from "body-parser";
33
import { connectToDatabase, pool } from "./config/connectDb";
44
import dbrouter from "./routes/dbroutes";
55
import mailrouter from "./routes/mailroutes";
6+
const cors = require("cors");
67

78
const app = express();
89

910
connectToDatabase();
1011

1112
app.use(bodyParser.json());
13+
app.use(cors());
1214

1315
app.use("/api/users", dbrouter);
1416
app.use("/api/sendmail", mailrouter);

web/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"browserslist": "> 0.5%, not dead",
66
"repository": "",
77
"author": "",
8+
"proxy": "http://localhost:3000",
89
"license": "MIT",
910
"alias": {
1011
"src": "./src",

web/src/hooks/useRelationalDB.ts

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { useState } from "react";
2+
3+
interface UserData {
4+
email: string;
5+
options: string;
6+
walletaddress: string;
7+
}
8+
9+
interface FetchResponse {
10+
loading: boolean;
11+
error: Error | null;
12+
data: any;
13+
}
14+
15+
export const useRelationalDB = () => {
16+
const [fetchResponse, setFetchResponse] = useState<FetchResponse>({
17+
loading: false,
18+
error: null,
19+
data: null,
20+
});
21+
22+
const createUser = async (userData: UserData) => {
23+
setFetchResponse({ loading: true, error: null, data: null });
24+
try {
25+
const response = await fetch("http://localhost:3000/api/users", {
26+
method: "POST",
27+
headers: {
28+
"Content-Type": "application/json",
29+
},
30+
body: JSON.stringify(userData),
31+
});
32+
const result = await response.json();
33+
setFetchResponse({ loading: false, error: null, data: result });
34+
} catch (err) {
35+
setFetchResponse({ loading: false, error: err as Error, data: null });
36+
}
37+
};
38+
39+
const getUser = async (walletaddress: string) => {
40+
setFetchResponse({ loading: true, error: null, data: null });
41+
try {
42+
const response = await fetch(`http://localhost:3000/api/users?walletaddress=${walletaddress}`);
43+
const result = await response.json();
44+
setFetchResponse({ loading: false, error: null, data: result });
45+
return result;
46+
} catch (err) {
47+
setFetchResponse({ loading: false, error: err as Error, data: null });
48+
}
49+
};
50+
51+
const updateUser = async (walletaddress: string, userData: UserData) => {
52+
setFetchResponse({ loading: true, error: null, data: null });
53+
try {
54+
const response = await fetch(`http://localhost:3000/api/users/${walletaddress}`, {
55+
method: "PUT",
56+
headers: {
57+
"Content-Type": "application/json",
58+
},
59+
body: JSON.stringify(userData),
60+
});
61+
const result = await response.json();
62+
setFetchResponse({ loading: false, error: null, data: result });
63+
} catch (err) {
64+
setFetchResponse({ loading: false, error: err as Error, data: null });
65+
}
66+
};
67+
68+
return { ...fetchResponse, createUser, getUser, updateUser };
69+
};

web/src/layout/Header/navbar/Menu/Settings/SendMeNotifications/FormNotifs/index.tsx

+38-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
import React, { useState } from "react";
1+
import React, { useState, useEffect } from "react";
22
import styled from "styled-components";
33
import { Checkbox, Button } from "@kleros/ui-components-library";
44
import FormEmail from "./FormEmail";
5+
import { useAccount } from "wagmi";
6+
import { useRelationalDB } from "hooks/useRelationalDB";
7+
8+
interface UserData {
9+
email: string;
10+
options: string;
11+
walletaddress: string;
12+
}
513

614
const FormContainer = styled.div`
715
position: relative;
@@ -38,19 +46,48 @@ const FormNotifs: React.FC = () => {
3846
const [checkboxStates, setCheckboxStates] = useState<boolean[]>(new Array(OPTIONS.length).fill(false));
3947
const [emailInput, setEmailInput] = useState<string>("");
4048
const [emailIsValid, setEmailIsValid] = useState<boolean>(false);
49+
const [userExists, setUserExists] = useState<boolean>(false); // TODO: use this to determine whether to use createUser or updateUser
50+
const { address } = useAccount();
51+
const { createUser, getUser, updateUser } = useRelationalDB();
4152

4253
const handleCheckboxChange = (index: number) => (e: React.ChangeEvent<HTMLInputElement>) => {
4354
const newCheckboxStates = [...checkboxStates];
4455
newCheckboxStates[index] = e.target.checked;
4556
setCheckboxStates(newCheckboxStates);
4657
};
4758

59+
useEffect(() => {
60+
const fetchUser = async () => {
61+
const data = await getUser(address + "");
62+
if (data[0]) {
63+
setUserExists(true);
64+
setEmailInput(data[0].email);
65+
setCheckboxStates(
66+
OPTIONS.map(({ label }) => {
67+
return data[0].options[label];
68+
})
69+
);
70+
}
71+
};
72+
fetchUser();
73+
}, []);
74+
4875
const handleClick = async () => {
4976
const optionsObject: object = {};
5077
OPTIONS.forEach(({ label }, index: number) => {
5178
optionsObject[label] = checkboxStates[index];
5279
});
5380
const jsonData = JSON.stringify(optionsObject, null, 2);
81+
const userData: UserData = {
82+
email: emailInput,
83+
options: jsonData,
84+
walletaddress: address + "",
85+
};
86+
if (userExists) {
87+
await updateUser(address + "", userData);
88+
} else {
89+
await createUser(userData);
90+
}
5491
};
5592

5693
return (

yarn.lock

+13-2
Original file line numberDiff line numberDiff line change
@@ -5147,6 +5147,7 @@ __metadata:
51475147
"@types/nodemailer": ^6.4.9
51485148
"@types/pg": ^8.10.2
51495149
body-parser: ^1.20.2
5150+
cors: ^2.8.5
51505151
express: ^4.18.2
51515152
express-async-handler: ^1.2.0
51525153
nodemailer: ^6.9.4
@@ -13482,6 +13483,16 @@ __metadata:
1348213483
languageName: node
1348313484
linkType: hard
1348413485

13486+
"cors@npm:^2.8.5":
13487+
version: 2.8.5
13488+
resolution: "cors@npm:2.8.5"
13489+
dependencies:
13490+
object-assign: ^4
13491+
vary: ^1
13492+
checksum: ced838404ccd184f61ab4fdc5847035b681c90db7ac17e428f3d81d69e2989d2b680cc254da0e2554f5ed4f8a341820a1ce3d1c16b499f6e2f47a1b9b07b5006
13493+
languageName: node
13494+
linkType: hard
13495+
1348513496
"cosmiconfig-typescript-loader@npm:^4.0.0":
1348613497
version: 4.3.0
1348713498
resolution: "cosmiconfig-typescript-loader@npm:4.3.0"
@@ -23875,7 +23886,7 @@ __metadata:
2387523886
languageName: node
2387623887
linkType: hard
2387723888

23878-
"object-assign@npm:^4.0.1, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1":
23889+
"object-assign@npm:^4, object-assign@npm:^4.0.1, object-assign@npm:^4.1.0, object-assign@npm:^4.1.1":
2387923890
version: 4.1.1
2388023891
resolution: "object-assign@npm:4.1.1"
2388123892
checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f
@@ -31062,7 +31073,7 @@ __metadata:
3106231073
languageName: node
3106331074
linkType: hard
3106431075

31065-
"vary@npm:~1.1.2":
31076+
"vary@npm:^1, vary@npm:~1.1.2":
3106631077
version: 1.1.2
3106731078
resolution: "vary@npm:1.1.2"
3106831079
checksum: ae0123222c6df65b437669d63dfa8c36cee20a504101b2fcd97b8bf76f91259c17f9f2b4d70a1e3c6bbcee7f51b28392833adb6b2770b23b01abec84e369660b

0 commit comments

Comments
 (0)