Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Customizable Error Page Component #93

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions client/app/components/Cards/ElectionDash.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
"use client";
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import Loader from "../Helper/Loader";
import ElectionMini from "../Cards/ElectionMini";
import ElectionInfoCard from "./ElectionInfoCard";
import { useOpenElection } from "../Hooks/GetOpenElections";
import ErrorPage from "../Error-pages/ErrorPage";

const ElectionDash = () => {
const { elections, isLoading } = useOpenElection();
const [electionStatuses, setElectionStatuses] = useState<{
[key: string]: number;
}>({});
const [filterStatus, setFilterStatus] = useState<number>(0); //0: All, 1: Pending, 2: Active, 3: Ended
const [filterStatus, setFilterStatus] = useState<number>(0); // 0: All, 1: Pending, 2: Active, 3: Ended
const [loading, setLoading] = useState<boolean>(true);

// Set the timer for 4 seconds to switch from loader to error or elections
useEffect(() => {
const timer = setTimeout(() => {
setLoading(false);
}, 4000); // 4 seconds

return () => clearTimeout(timer); // Clean up the timer on component unmount
}, []);

const update = (electionAddress: `0x${string}`, status: number) => {
if (electionStatuses[electionAddress] !== status) {
Expand Down Expand Up @@ -44,12 +55,12 @@ const ElectionDash = () => {

return (
<div className="w-screen">
{isLoading || !elections ? (
{loading ? (
<Loader />
) : (
) : elections ? (
<div className="flex flex-col items-center justify-center">
<div className="flex lg:flex-row flex-col w-[80%] overflow-auto lg:space-x-4">
<div className=" flex-col w-[90%] lg:w-[24%] mt-3 h-full inline-block items-center justify-center ">
<div className="flex-col w-[90%] lg:w-[24%] mt-3 h-full inline-block items-center justify-center">
<ElectionInfoCard
counts={counts}
filterStatus={filterStatus}
Expand Down Expand Up @@ -102,13 +113,21 @@ const ElectionDash = () => {
>
Refresh
</button>
</div>


</div>
)}
</div>
</div>
</div>
) : (
<ErrorPage
errorCode={403} // Forbidden error, often due to access restrictions
errorMessage="Oops! Something went wrong."
details="We couldn't load the page you're trying to access. This may be due to a temporary issue with our servers. Please try again later."
redirectPath="#"
redirectLabel="Go to Homepage"
onRetry={() => window.location.reload()}
current_route="/"
/>
)}
</div>
);
Expand Down
10 changes: 5 additions & 5 deletions client/app/components/ChatBot/ChatBot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const ChatBot: React.FC = () => {
onClick={() => setIsOpen(!isOpen)}
className="bg-blue-600 text-white p-4 rounded-full shadow-lg"
>
<ChatBubbleLeftRightIcon className="w-6 h-6" />
<ChatBubbleLeftRightIcon className="w-6 h-6 " />
</motion.button>

<AnimatePresence>
Expand All @@ -72,7 +72,7 @@ const ChatBot: React.FC = () => {
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 20 }}
transition={{ duration: 0.2 }}
className="absolute bottom-16 right-0 w-96 h-[32rem] bg-white rounded-lg shadow-xl overflow-hidden flex flex-col"
className="absolute bottom-16 right-0 w-50 md:pt-40 md:w-96 h-[32rem] bg-white rounded-lg shadow-xl overflow-hidden flex flex-col"
>
<div className="bg-blue-600 text-white p-4 text-center font-semibold">
Agora Chatbot
Expand All @@ -99,8 +99,8 @@ const ChatBot: React.FC = () => {
))}
<div ref={messageEndRef} />
</div>
<form onSubmit={handleSubmit} className="p-4 bg-gray-100">
<div className="flex items-center bg-white rounded-full overflow-hidden shadow">
<form onSubmit={handleSubmit} className="p-4 bg-gray-200">
<div className="flex items-center bg-white rounded-full overflow-hidden shadow-lg">
<input
type="text"
value={inputMessage}
Expand All @@ -123,4 +123,4 @@ const ChatBot: React.FC = () => {
);
};

export default ChatBot;
export default ChatBot;
92 changes: 92 additions & 0 deletions client/app/components/Error-pages/ErrorPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React from 'react';
import Link from 'next/link';
import { FaHome, FaRedoAlt } from 'react-icons/fa';

/**
* ErrorPage Component
*
* A customizable error page component that displays an error code, a message,
* and provides an option for the user to either retry or navigate back to a
* specified page (typically the homepage).
*
* @param {number} [errorCode=404] - The error code to display. Defaults to 404 if not provided.
* @param {string} [errorMessage="The page you're looking for doesn't exist or is unavailable."] - The error message to display. Defaults to a standard 404 message.
* @param {string} [details] - Optional additional details to provide more context about the error.
* @param {string} [redirectPath="/"] - The path to redirect the user to when clicking the redirect button. Defaults to "/" (home).
* @param {string} [redirectLabel="Go to Homepage"] - The label for the redirect button. Defaults to "Go to Homepage".
* @param {() => void} [onRetry] - An optional function that will be executed when the retry button is clicked. Useful for recoverable errors.
* @param {string} [current_route="#"] - The current route to check if the user is on the homepage. Used to prevent redundant redirect button.
*
* @returns {JSX.Element} - A functional component rendering the error page with potential retry and redirect actions.
*/
interface ErrorPageProps {
errorCode?: number; // Optional error code, defaults to 404
errorMessage?: string; // Optional error message
details?: string; // Optional additional details (string)
redirectPath?: string; // Redirect path, defaults to "/"
redirectLabel?: string; // Label for redirect button, defaults to "Go to Homepage"
onRetry?: () => void; // Optional retry handler for recoverable errors
current_route?: string; // The current route to avoid redundant redirects
}

const ErrorPage: React.FC<ErrorPageProps> = ({
errorCode = 404, // Default error code
errorMessage = "The page you're looking for doesn't exist or is unavailable.",
details, // Optional detailed message
redirectPath = "/", // Default redirect path
redirectLabel = "Go to Homepage", // Label for the redirect button
onRetry, // Optional retry handler for recoverable errors
current_route = "#", // The current route to avoid redundant redirects
}) => {
return (
<div className="min-h-screen flex shadow-lg shadow-gray-500 flex-col items-center justify-center px-6 py-12">
<div className="max-w-3xl w-full flex flex-col md:flex-row items-center justify-center bg-white p-8 rounded-lg shadow-xl space-y-8 md:space-y-0">
<div className="text-center md:text-left space-y-6">
{/* Display the error code */}
<h1 className="text-6xl font-bold text-red-600">{errorCode}</h1>

{/* Display the error message */}
<h2 className="text-3xl font-semibold text-gray-800">{errorMessage}</h2>

{/* Display optional details, if provided */}
{details && <p className="text-lg text-gray-500 mt-2">{details}</p>}

<div className="mt-6 flex justify-center md:justify-start space-x-6">
{/* Show a retry button if an onRetry handler is provided */}
{onRetry && (
<button
onClick={onRetry}
className="inline-flex items-center px-6 py-3 bg-green-600 hover:bg-green-700 text-white font-semibold rounded-lg shadow-md transition duration-300 ease-in-out"
>
<FaRedoAlt className="mr-2 text-xl" />
Reload
</button>
)}

{/* Show the redirect button only if the current route is not the homepage */}
{current_route !== "/" && (
<Link
href={redirectPath}
className="inline-flex items-center px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-lg shadow-md transition duration-300 ease-in-out"
>
<FaHome className="mr-2 text-xl" />
{redirectLabel}
</Link>
)}
</div>
</div>

<div className="mt-8 md:mt-0 md:w-1/2 text-center">
{/* Display an image related to the error */}
<img
src="/aossie.png" // Replace with your own image or dynamic source
alt={`${errorCode} Illustration`} // Alt text for the image, based on error code
className="w-full max-w-xs mx-auto md:max-w-md"
/>
</div>
</div>
</div>
);
};

export default ErrorPage;