Skip to content

Commit 5aab367

Browse files
🚸 Prevent duplicate reports on frontend
1 parent 21645e5 commit 5aab367

10 files changed

+180
-52
lines changed

.xata/migrations/.ledger

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ mig_ckigrcrvn469mi28pt9g_aa35d5b2
44
mig_ckigrgpfnfidu9ddkpmg_4092bb4d
55
mig_ckigtv3vn469mi28pteg_2f6a2f77
66
mig_ckigu5vukcu8m9898t2g_e8236a00
7+
mig_ckihebkujsmuf8reoo90_68477443
8+
mig_ckihejc6f7ng5inpnc0g_89f03279
9+
mig_ckiher46f7ng5inpnc1g_3942320d
10+
mig_ckihf8cujsmuf8reooj0_8e780a6d
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"id": "mig_ckihebkujsmuf8reoo90",
3+
"parentID": "mig_ckigu5vukcu8m9898t2g",
4+
"checksum": "1:68477443af8fd485fb2b256afa1ad9f4da782478fdb30eaf037cf298dc6e997e",
5+
"operations": [
6+
{
7+
"addTable": {
8+
"table": "invalid_repos"
9+
}
10+
}
11+
]
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"id": "mig_ckihejc6f7ng5inpnc0g",
3+
"parentID": "mig_ckihebkujsmuf8reoo90",
4+
"checksum": "1:89f032792639265df34734d37d011a368819d71d96374f593862e4c795689371",
5+
"operations": [
6+
{
7+
"removeTable": {
8+
"table": "invalid_repos"
9+
}
10+
}
11+
]
12+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"id": "mig_ckiher46f7ng5inpnc1g",
3+
"parentID": "mig_ckihejc6f7ng5inpnc0g",
4+
"checksum": "1:3942320d04fa23e14e14aa2993f449ce87d98ab4d248adf42e2f76388b6aa672",
5+
"operations": [
6+
{
7+
"addColumn": {
8+
"column": {
9+
"name": "valid",
10+
"type": "bool",
11+
"notNull": true,
12+
"defaultValue": "true"
13+
},
14+
"table": "reports"
15+
}
16+
}
17+
]
18+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"id": "mig_ckihf8cujsmuf8reooj0",
3+
"parentID": "mig_ckiher46f7ng5inpnc1g",
4+
"checksum": "1:8e780a6da11c4614b6a214ab8e5ea89b3124035adccfa0bc4a3dcab801bb8145",
5+
"operations": [
6+
{
7+
"addColumn": {
8+
"column": {
9+
"name": "repoUrl",
10+
"type": "string",
11+
"unique": true
12+
},
13+
"table": "reports"
14+
}
15+
}
16+
]
17+
}

components/ReportModal.tsx

Lines changed: 61 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ import axios from 'axios';
22
import { useAtom } from 'jotai';
33
import { signIn, useSession } from 'next-auth/react';
44
import { SendReportSchema } from 'pages/api/send-report';
5-
import { FormEvent } from 'react';
5+
import { FormEvent, use } from 'react';
66
import { useState } from 'react';
77
import toast from 'react-hot-toast';
88
import { BsGithub } from 'react-icons/bs';
99
import { GoStop } from 'react-icons/go';
10+
import { useGetRepo } from 'utils/hooks/use-get-repo';
1011
import { repoAtom } from 'utils/state/repoAtom';
11-
import { getXataClient } from 'xata';
1212

1313
function ReportModal() {
14+
const isReported = useGetRepo();
1415
const session = useSession();
1516
const [isLoading, setIsLoading] = useState(false);
1617
const [repo, setRepo] = useAtom(repoAtom);
@@ -30,16 +31,19 @@ function ReportModal() {
3031
message,
3132
repoAuthor,
3233
repoId,
33-
userEmail: session.data.user.email as string
34+
repoUrl: repo.html_url
3435
} satisfies SendReportSchema;
3536
try {
3637
const res = await axios.post('/api/send-report', data, {
3738
validateStatus: status =>
3839
(status >= 200 && status < 300) || status === 409
3940
});
40-
console.log(res.status);
41-
if (res.status === 200) toast.success('Report sent successfully');
42-
else toast.error(res.data.message);
41+
if (res.status === 200) {
42+
toast.success('Report sent successfully');
43+
setRepo(null);
44+
} else {
45+
toast.error(res.data.message);
46+
}
4347
} catch (e: any) {
4448
} finally {
4549
setIsLoading(false);
@@ -59,50 +63,58 @@ function ReportModal() {
5963
Report This Repository
6064
</h3>
6165
{session.data ? (
62-
<div className="modal-action flex flex-col">
63-
<p className="text-2023-manga-3 text-lg">
64-
Please provide as much detail as possible to explain why you are
65-
reporting this repository.
66-
<span className="flex gap-2 items-center font-extralight text-sm mt-2 text-2023-bavarian-red-1">
67-
<GoStop className="font-extrabold" />
68-
Note that we may remove the repository
69-
</span>
70-
</p>
66+
!isReported ? (
67+
<div className="modal-action flex flex-col">
68+
<p className="text-2023-manga-3 text-lg">
69+
Please provide as much detail as possible to explain why you are
70+
reporting this repository.
71+
<span className="flex gap-2 items-center font-extralight text-sm mt-2 text-2023-bavarian-red-1">
72+
<GoStop className="font-extrabold" />
73+
Note that we may remove the repository
74+
</span>
75+
</p>
7176

72-
<form method="dialog" onSubmit={handleSubmit}>
73-
<textarea
74-
name="message"
75-
placeholder="Why do want to report this repository..."
76-
className="textarea-lg textarea textarea-bordered textarea-ghost rounded-md w-full p-2 focus:outline-2023-bavarian-red-1 mt-6 -ml-2 text-white"
77-
required
78-
/>
79-
<div className="flex mt-4 justify-end items-center ml-6 p-2 space-x-4">
80-
<button
81-
type="submit"
82-
className={`btn glass shadow-md bg-2023-bavarian-red-2 text-xl text-2023-manga-2 hover:bg-2023-bavarian-red-3 ${
83-
isLoading
84-
? 'disabled cursor-not-allowed pointer-events-none'
85-
: ''
86-
}`}
87-
>
88-
{isLoading ? (
89-
<>
90-
<span className="loading loading-spinner"></span>
91-
Sending report...
92-
</>
93-
) : (
94-
'Report'
95-
)}
96-
</button>
97-
</div>
98-
</form>
99-
<button
100-
className="btn btn-md text-sxl btn-circle btn-ghost absolute right-2 top-2"
101-
onClick={handleCloseClick}
102-
>
103-
104-
</button>
105-
</div>
77+
<form method="dialog" onSubmit={handleSubmit}>
78+
<textarea
79+
name="message"
80+
placeholder="Why do want to report this repository..."
81+
className="textarea-lg textarea textarea-bordered textarea-ghost rounded-md w-full p-2 focus:outline-2023-bavarian-red-1 mt-6 -ml-2 text-white"
82+
required
83+
/>
84+
<div className="flex mt-4 justify-end items-center ml-6 p-2 space-x-4">
85+
<button
86+
type="submit"
87+
className={`btn glass shadow-md bg-2023-bavarian-red-2 text-xl text-2023-manga-2 hover:bg-2023-bavarian-red-3 ${
88+
isLoading
89+
? 'disabled cursor-not-allowed pointer-events-none'
90+
: ''
91+
}`}
92+
>
93+
{isLoading ? (
94+
<>
95+
<span className="loading loading-spinner"></span>
96+
Sending report...
97+
</>
98+
) : (
99+
'Report'
100+
)}
101+
</button>
102+
</div>
103+
</form>
104+
<button
105+
className="btn btn-md text-sxl btn-circle btn-ghost absolute right-2 top-2"
106+
onClick={handleCloseClick}
107+
>
108+
109+
</button>
110+
</div>
111+
) : (
112+
<div className="flex justify-center items-center mt-5">
113+
<span className="text-2023-bavarian-gold-1">
114+
This repository is already reported and in review
115+
</span>
116+
</div>
117+
)
106118
) : (
107119
<div className="flex justify-center items-center mt-5">
108120
<button

pages/api/check-repo.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { NextApiRequest, NextApiResponse } from 'next';
2+
import { getXataClient } from 'xata';
3+
4+
export default async function checkRepo(
5+
req: NextApiRequest,
6+
res: NextApiResponse
7+
) {
8+
if (req.method === 'GET') {
9+
const repoId = req.query.repoId;
10+
if (typeof repoId !== 'string') return res.status(400).end();
11+
12+
const client = getXataClient();
13+
14+
const repo = await client.db.reports
15+
.filter({ repoId: Number(repoId) })
16+
.getFirst();
17+
18+
return res.send(repo);
19+
}
20+
}

pages/api/send-report.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { XataError } from '@xata.io/client';
21
import { NextApiRequest, NextApiResponse } from 'next';
2+
import { getServerSession } from 'next-auth';
33
import { getXataClient } from 'xata';
44
import { ZodError, z } from 'zod';
5+
import { authOptions } from './auth/[...nextauth]';
56

67
const sendReportSchema = z.object({
78
message: z.string().trim().nonempty(),
89
repoId: z.number().positive(),
910
repoAuthor: z.string().trim().nonempty(),
10-
userEmail: z.string().trim().email().nonempty()
11+
repoUrl: z.string().trim().nonempty()
1112
});
1213

1314
export default async function sendReport(
@@ -17,9 +18,15 @@ export default async function sendReport(
1718
if (req.method !== 'POST') return res.status(405).end();
1819
try {
1920
const body = sendReportSchema.parse(req.body);
21+
const session = await getServerSession(req, res, authOptions);
22+
23+
if (!session) {
24+
return res.status(401).json({ message: 'You must be logged in.' });
25+
}
26+
2027
const client = getXataClient();
2128
const user = await client.db.nextauth_users
22-
.filter({ email: body.userEmail })
29+
.filter({ email: session.user?.email })
2330
.getFirst();
2431

2532
if (!user) return res.status(400).json({ code: 'USER_NOT_FOUND' });

utils/hooks/use-get-repo.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import axios from 'axios';
2+
import { useAtomValue } from 'jotai';
3+
import { useEffect, useState } from 'react';
4+
import { repoAtom } from 'utils/state/repoAtom';
5+
6+
export function useGetRepo() {
7+
const [isReported, setIsReported] = useState(false);
8+
const repo = useAtomValue(repoAtom);
9+
10+
useEffect(() => {
11+
async function checkRepo() {
12+
const repoId = repo?.id;
13+
const res = await axios.get(`/api/check-repo?repoId=${repoId}`);
14+
if (!res.data) {
15+
return setIsReported(false);
16+
}
17+
return setIsReported(true);
18+
}
19+
checkRepo();
20+
}, [repo]);
21+
22+
console.log(isReported);
23+
return isReported;
24+
}

xata.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const tables = [
1919
defaultValue: "No Message",
2020
},
2121
{ name: "user", type: "link", link: { table: "nextauth_users" } },
22+
{ name: "valid", type: "bool", notNull: true, defaultValue: "true" },
23+
{ name: "repoUrl", type: "string", unique: true },
2224
],
2325
},
2426
{

0 commit comments

Comments
 (0)