-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
certfication generation initial version
- Loading branch information
1 parent
bc8330e
commit 888ac0d
Showing
22 changed files
with
2,675 additions
and
412 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
"use server"; | ||
|
||
import { getClient } from "gql/client"; | ||
import { APPROVE_CERTIFICATE } from "gql/mutations/members"; | ||
|
||
export async function approveCertificate(certificateNumber) { | ||
const response = { ok: false, error: null }; | ||
|
||
const { data, error } = await getClient().mutation(APPROVE_CERTIFICATE, { | ||
certificateNumber, | ||
}); | ||
|
||
if (error) { | ||
response.error = { | ||
title: error.name, | ||
messages: error?.graphQLErrors?.map((ge) => ge?.message), | ||
}; | ||
} else { | ||
response.ok = true; | ||
response.data = data.approveCertificate; | ||
} | ||
|
||
return response; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
"use server"; | ||
|
||
import { getClient } from "gql/client"; | ||
import { REJECT_CERTIFICATE } from "gql/mutations/members"; | ||
|
||
export async function rejectCertificate(certificateNumber) { | ||
const response = { ok: false, error: null }; | ||
|
||
const { data, error } = await getClient().mutation(REJECT_CERTIFICATE, { | ||
certificateNumber, | ||
}); | ||
|
||
if (error) { | ||
response.error = { | ||
title: error.name, | ||
messages: error?.graphQLErrors?.map((ge) => ge?.message), | ||
}; | ||
} else { | ||
response.ok = true; | ||
response.data = data.rejectCertificate; | ||
} | ||
|
||
return response; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
"use server"; | ||
|
||
import { getClient } from "gql/client"; | ||
import { REQUEST_CERTIFICATE } from "gql/mutations/members"; | ||
|
||
export async function requestCertificate(requestReason) { | ||
try { | ||
const client = getClient(); | ||
|
||
const variables = { | ||
certificateInput: { | ||
requestReason, | ||
}, | ||
}; | ||
|
||
const { data, error } = await client.mutation( | ||
REQUEST_CERTIFICATE, | ||
variables | ||
); | ||
|
||
if (error) { | ||
return { ok: false, error }; | ||
} else { | ||
return { ok: true, data: data.requestCertificate }; | ||
} | ||
} catch (err) { | ||
return { ok: false, error: err }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
"use server"; | ||
|
||
import { getClient } from "gql/client"; | ||
import { VERIFY_CERTIFICATE } from "gql/queries/members"; | ||
|
||
export async function verifyCertificate(certificateNumber, key) { | ||
const response = { ok: false, data: null, error: null }; | ||
|
||
try { | ||
const { error, data } = await getClient().query(VERIFY_CERTIFICATE, { | ||
certificateNumber, | ||
key, | ||
}); | ||
|
||
if (error) { | ||
response.error = { | ||
title: error.name, | ||
messages: error?.graphQLErrors?.map((ge) => ge?.message) || [ | ||
"An unknown error occurred", | ||
], | ||
}; | ||
} else if (data && data.verifyCertificate) { | ||
response.ok = true; | ||
response.data = data.verifyCertificate; | ||
} else { | ||
throw new Error("No data returned from the server"); | ||
} | ||
} catch (err) { | ||
console.error("Error verifying certificate:", err); | ||
response.error = { | ||
title: "Error", | ||
messages: [err.message || "An unexpected error occurred"], | ||
}; | ||
} | ||
|
||
return response; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
"use client"; | ||
|
||
import { useState, useEffect, useRef } from "react"; | ||
import { | ||
Container, | ||
Typography, | ||
TextField, | ||
Button, | ||
Box, | ||
Paper, | ||
CircularProgress, | ||
} from "@mui/material"; | ||
import { useSearchParams } from "next/navigation"; | ||
|
||
import { getFullUser } from "actions/users/get/full/server_action"; | ||
import { verifyCertificate } from "actions/certificates/verify/server_action"; | ||
import { useToast } from "components/Toast"; | ||
import { ISOtoHuman } from "utils/formatTime"; | ||
|
||
export default function VerifyCertificatePage() { | ||
const searchParams = useSearchParams(); | ||
const [certificateNumber, setCertificateNumber] = useState(""); | ||
const [key, setKey] = useState(""); | ||
const [loading, setLoading] = useState(false); | ||
const [error, setError] = useState(null); | ||
const [certificate, setCertificate] = useState(null); | ||
const [user, setUser] = useState(null); | ||
const { triggerToast } = useToast(); | ||
|
||
const autoSubmitTriggered = useRef(false); | ||
|
||
useEffect(() => { | ||
const certificateId = searchParams.get("certificateId"); | ||
const validationKey = searchParams.get("validationKey"); | ||
|
||
if (certificateId && validationKey) { | ||
setCertificateNumber(certificateId); | ||
setKey(validationKey); | ||
} | ||
}, [searchParams]); | ||
|
||
useEffect(() => { | ||
if (certificateNumber && key && !autoSubmitTriggered.current) { | ||
autoSubmitTriggered.current = true; // Ensure it runs only once | ||
handleSubmit(); | ||
} | ||
}, [certificateNumber, key]); | ||
|
||
const handleSubmit = async () => { | ||
setLoading(true); | ||
setError(null); | ||
setCertificate(null); | ||
|
||
|
||
try { | ||
const result = await verifyCertificate(certificateNumber, key); | ||
|
||
if (result.ok && result.data) { | ||
setCertificate(result.data); | ||
|
||
const res = await getFullUser(result.data.userId); | ||
|
||
if (!res.ok) { | ||
triggerToast({ | ||
title: "Unable to fetch user data", | ||
messages: res.error.messages, | ||
severity: "error", | ||
}); | ||
} else { | ||
console.log(res.data); | ||
setUser(res.data); | ||
} | ||
} else { | ||
setError(result.error?.messages?.[0] || "Failed to verify certificate"); | ||
} | ||
} catch (err) { | ||
// console.error("Error verifying certificate:", err); | ||
setError("An error occurred while verifying the certificate"); | ||
} finally { | ||
setLoading(false); | ||
} | ||
}; | ||
|
||
return ( | ||
<Container maxWidth="md"> | ||
<Box sx={{ my: 4 }}> | ||
<Typography variant="h4" component="h1" gutterBottom> | ||
Verify Certificate | ||
</Typography> | ||
<Paper elevation={3} sx={{ p: 3 }}> | ||
<TextField | ||
fullWidth | ||
label="Certificate Number" | ||
variant="outlined" | ||
value={certificateNumber} | ||
onChange={(e) => setCertificateNumber(e.target.value)} | ||
margin="normal" | ||
required | ||
/> | ||
<TextField | ||
fullWidth | ||
label="Verification Key" | ||
variant="outlined" | ||
value={key} | ||
onChange={(e) => setKey(e.target.value)} | ||
margin="normal" | ||
required | ||
/> | ||
<Button | ||
variant="contained" | ||
color="primary" | ||
size="large" | ||
fullWidth | ||
sx={{ mt: 2 }} | ||
disabled={loading} | ||
onClick={handleSubmit} | ||
> | ||
{loading ? <CircularProgress size={24} /> : "Verify Certificate"} | ||
</Button> | ||
</Paper> | ||
|
||
{error ? ( | ||
<Typography | ||
variant="body1" | ||
color="error" | ||
sx={{ mt: 2, textTransform: "capitalize" }} | ||
> | ||
<center>{error}</center> | ||
</Typography> | ||
) : null} | ||
|
||
{certificate && ( | ||
<Paper elevation={3} sx={{ mt: 3, p: 3 }}> | ||
<Typography variant="h6" gutterBottom> | ||
Certificate Details | ||
</Typography> | ||
<Box | ||
sx={{ | ||
display: "grid", | ||
gridTemplateColumns: "auto 1fr", | ||
gap: 2, | ||
alignItems: "baseline", | ||
mt: 3, | ||
}} | ||
> | ||
<Typography variant="subtitle2" fontWeight="bold"> | ||
Certificate Number: | ||
</Typography> | ||
<Typography variant="body1"> | ||
{certificate.certificateNumber} | ||
</Typography> | ||
|
||
<Typography variant="subtitle2" fontWeight="bold"> | ||
Name: | ||
</Typography> | ||
<Typography variant="body1"> | ||
{user?.firstName} {user?.lastName} | ||
</Typography> | ||
|
||
<Typography variant="subtitle2" fontWeight="bold"> | ||
Email: | ||
</Typography> | ||
<Typography variant="body1">{user?.email}</Typography> | ||
|
||
<Typography variant="subtitle2" fontWeight="bold"> | ||
Roll Number: | ||
</Typography> | ||
<Typography variant="body1">{user?.rollno}</Typography> | ||
|
||
<Typography variant="subtitle2" fontWeight="bold"> | ||
Batch: | ||
</Typography> | ||
<Typography variant="body1"> | ||
{user?.batch.toUpperCase()} · {user?.stream.toUpperCase()} | ||
</Typography> | ||
|
||
<Typography variant="subtitle2" fontWeight="bold"> | ||
Issued Date: | ||
</Typography> | ||
<Typography variant="body1"> | ||
{ISOtoHuman(certificate.status.requestedAt)} | ||
</Typography> | ||
</Box> | ||
</Paper> | ||
)} | ||
</Box> | ||
</Container> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { getClient } from "gql/client"; | ||
|
||
import { Box, Button, Grid, Typography } from "@mui/material"; | ||
import AllCertificatesTable from "components/certificates/AllCertificatesTable"; | ||
import { GET_ALL_CERTIFICATES } from "gql/queries/members" | ||
|
||
export default async function AllCertificates() { | ||
const { error, data : { getAllCertificates } = {} } = await getClient().query(GET_ALL_CERTIFICATES); | ||
return ( | ||
<div className="container mx-auto p-4"> | ||
<Grid | ||
container | ||
item | ||
sx={{ display: "flex", justifyContent: "space-between" }} | ||
> | ||
<Typography variant="h3" gutterBottom mt={2}> | ||
All Certificates | ||
</Typography> | ||
<Box mt={3} mb={4}> | ||
<Button variant="contained" color="primary" href="/manage/certificates"> | ||
View Pending Certificates | ||
</Button> | ||
</Box> | ||
</Grid> | ||
<AllCertificatesTable Certs={getAllCertificates} /> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { getClient } from "gql/client"; | ||
|
||
import { Box, Button, Grid, Typography } from "@mui/material"; | ||
import PendingCertificatesTable from "components/certificates/PendingCertificatesTable"; | ||
import { GET_PENDING_CERTIFICATES } from "gql/queries/members" | ||
|
||
export default async function PendingCertificates() { | ||
const { data: { getPendingCertificates } = {} } = await getClient().query(GET_PENDING_CERTIFICATES); | ||
return ( | ||
<div className="container mx-auto p-4"> | ||
<Grid | ||
container | ||
item | ||
sx={{ display: "flex", justifyContent: "space-between" }} | ||
> | ||
<Typography variant="h3" gutterBottom mt={2}> | ||
Pending Certificate Requests | ||
</Typography> | ||
<Box mt={3} mb={4}> | ||
<Button variant="contained" color="primary" href="/manage/certificates/all"> | ||
View All Certificates | ||
</Button> | ||
</Box> | ||
</Grid> | ||
<PendingCertificatesTable pendingCerts={getPendingCertificates} /> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.