Skip to content

Commit

Permalink
feat(ui): recaptcha page
Browse files Browse the repository at this point in the history
  • Loading branch information
virtual-designer committed Dec 6, 2023
1 parent e89323a commit 8eabd7a
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 27 deletions.
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,26 @@
"date-fns": "^2.30.0",
"discord-api-types": "^0.37.56",
"eslint": "8.46.0",
"eslint-config-next": "13.4.12",
"eslint-config-next": "^14.0.3",
"framer-motion": "^10.15.0",
"next": "13.4.12",
"next": "^14.0.3",
"postcss": "8.4.31",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.45.4",
"react-icons": "^4.10.1",
"react-markdown": "^8.0.7",
"react-remark": "^2.1.0",
"remark-breaks": "^3.0.3",
"remark-gfm": "^3.0.1",
"tailwind-merge": "^1.14.0",
"tailwindcss": "3.3.3",
"typescript": "5.1.6"
"tailwindcss": "^3.3.6",
"typescript": "^5.3.2"
},
"devDependencies": {
"@commitlint/cli": "^17.6.7",
"@commitlint/config-conventional": "^17.6.7",
"husky": "^8.0.0",
"sharp": "^0.32.4"
}
}
}
12 changes: 12 additions & 0 deletions src/api/routes/verify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { API } from "@/utils/api";
import axios from "axios";

type ValidateCaptchaResponseType = {
success: boolean;
};

export function validateCaptchaResponse(response: string) {
return axios.post<ValidateCaptchaResponseType>(API.verify(), {
responseToken: response,
});
}
63 changes: 63 additions & 0 deletions src/app/challenge/verify/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* This file is part of SudoBot Dashboard.
*
* Copyright (C) 2021-2023 OSN Developers.
*
* SudoBot Dashboard is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SudoBot Dashboard is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with SudoBot Dashboard. If not, see <https://www.gnu.org/licenses/>.
*/

import Captcha from "@/components/Verify/Captcha";
import { Metadata } from "next";
import Script from "next/script";
import { FC } from "react";

export const metadata: Metadata = {
title: "Verify - SudoBot",
description: "Log into SudoBot's control panel.",
};

const VerifyPage: FC = () => {
return (
<main className="min-h-[90vh] flex justify-center items-center">
<Script
src="https://www.google.com/recaptcha/api.js"
async
defer
></Script>

<div>
<h1 className="text-3xl md:text-4xl text-center pt-5 md:pt-0">
Verify
</h1>
<p className="text-center text-[#999] pb-[20px] md:pb-[50px] pt-3">
Please verify yourself to continue.
</p>

<div className="flex justify-center items-center">
<form
method="POST"
action="#"
className="bg-[#222] rounded-lg p-3"
>
<div className="flex">
<Captcha />
</div>
</form>
</div>
</div>
</main>
);
};

export default VerifyPage;
43 changes: 23 additions & 20 deletions src/components/Home/ReviewList.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
/*
* This file is part of SudoBot Dashboard.
*
* Copyright (C) 2021-2023 OSN Developers.
*
* SudoBot Dashboard is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SudoBot Dashboard is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with SudoBot Dashboard. If not, see <https://www.gnu.org/licenses/>.
*/
* This file is part of SudoBot Dashboard.
*
* Copyright (C) 2021-2023 OSN Developers.
*
* SudoBot Dashboard is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SudoBot Dashboard is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with SudoBot Dashboard. If not, see <https://www.gnu.org/licenses/>.
*/

"use client";

Expand Down Expand Up @@ -52,9 +52,12 @@ const ReviewList: FC = () => {
<br className="hidden md:block" />
<br />
<div className="flex justify-center pt-3">
{query.isSuccess && (
<Reviews reviews={query.data?.data ?? []} />
)}
{query.isSuccess &&
(!query.data?.data || query.data?.data?.length === 0 ? (
<div>No reviews yet.</div>
) : (
<Reviews reviews={query.data?.data ?? []} />
))}

{query.isLoading && (
<div className="h-[10px] w-[100%] md:w-[350px] block">
Expand Down
108 changes: 108 additions & 0 deletions src/components/Verify/Captcha.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"use client";

import { validateCaptchaResponse } from "@/api/routes/verify";
import {
Alert,
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from "@mui/material";
import { AxiosError } from "axios";
import { FC, useEffect, useState } from "react";

const recaptchaSuccessCallbackName = "recaptchaSuccess";

declare global {
interface Window
extends Record<
typeof recaptchaSuccessCallbackName,
Function | undefined
> {}
}

const Captcha: FC = () => {
const [isSuccess, setIsSuccess] = useState(false);
const [isAlertOpen, setIsAlertOpen] = useState(true);
const [error, setError] = useState<string | null>(null);

const onSuccess = async (responseToken: string) => {
try {
const response = await validateCaptchaResponse(responseToken);

if (!response.data.success) {
throw new AxiosError(
"Request unsuccessful",
response.status.toString(),
undefined,
undefined,
response
);
}

setIsSuccess(true);
} catch (error) {
if (error instanceof AxiosError) {
setError(
error.response?.data.error ??
"We were unable to verify you."
);
} else {
console.log(error);
setError(
"An internal error has occurred. Please try again later."
);
}
}
};

useEffect(() => {
window[recaptchaSuccessCallbackName] = onSuccess;

return () => {
delete window[recaptchaSuccessCallbackName];
};
}, []);

return (
<div className=" flex justify-center items-center w-[100%] flex-col gap-5">
{error && (
<Alert severity="error" className="w-[100%]">
{error}
</Alert>
)}
{isSuccess && (
<Dialog
open={isAlertOpen}
onClose={() => setIsAlertOpen(false)}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Verification Completed"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
We've successfully verified that you're not a robot.
You&rsquo;ll be authorized shortly.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() => setIsAlertOpen(false)}>
OK
</Button>
</DialogActions>
</Dialog>
)}
<div
className="g-recaptcha invert"
data-sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}
data-callback="recaptchaSuccess"
></div>
</div>
);
};

export default Captcha;
4 changes: 4 additions & 0 deletions src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@

const API_URL = process.env.NEXT_PUBLIC_API_URL;
export class API {
static verify(): string {
return `${API_URL}/challenge/verify`;
}

static announcements(): string {
return `${API_URL}/announcements`;
}
Expand Down

0 comments on commit 8eabd7a

Please sign in to comment.