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

Certificate Generation for Users #76

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9d1341d
initialise template for certificate generation
sambuaneesh Jun 23, 2024
75fc135
build a seperate form component and better error handling
sambuaneesh Jun 23, 2024
44b5aea
added a new item in navigation bar to open certificate requests page
sambuaneesh Jun 26, 2024
87f9334
added gql queries and mutations for certificates in members subgraph
sambuaneesh Jun 30, 2024
0c9ba63
make actions for certificates usecase for members subgraph
sambuaneesh Jun 30, 2024
ce2ee06
sending vanilla certificate request working
sambuaneesh Jul 2, 2024
01fec54
add table for request certificate page and fix typos in gql queries
sambuaneesh Jul 2, 2024
896e37d
fix certificate page access roles
sambuaneesh Jul 3, 2024
723277f
Add certificate requests table and form components
sambuaneesh Jul 4, 2024
c76fb38
generating and sending certificate data for the backend (memberships)
sambuaneesh Jul 12, 2024
570a574
improved pending certificates table, added pop up when pressed on tab…
sambuaneesh Jul 12, 2024
d5c332f
make ui for certificate verification
sambuaneesh Jul 12, 2024
a5ef36d
Merge branch 'master' into cert-gen
bhavberi Jul 13, 2024
59f5d7b
disable generate certificate if no memberships #69
sambuaneesh Jul 16, 2024
a57fba7
Certificate reason length set maximum
bhavberi Jul 16, 2024
e194116
Merge branch 'cert-gen' of github.com:Clubs-Council-IIITH/web into ce…
sambuaneesh Jul 17, 2024
f674491
new schema changes (working request certificate)
sambuaneesh Jul 18, 2024
1ba5233
update tables based on new schema for cert-gen
sambuaneesh Jul 18, 2024
ee1c8e8
new schema updates for actions on certificates
sambuaneesh Jul 19, 2024
72795dc
misc fixes and cleanup wrt to previous commit (couldnt amend as alrea…
sambuaneesh Jul 19, 2024
813233f
Move basic components of Certificate Form to Server Side, and hide ne…
bhavberi Jul 20, 2024
6418b5d
Re-Use ISOToHuman in Certificate pages
bhavberi Jul 20, 2024
f9c3ce4
Update verify certificate page
bhavberi Jul 20, 2024
1c9b718
Update routes.js
bhavberi Aug 1, 2024
708e36e
update user_id to full user name in the tables
sambuaneesh Aug 4, 2024
1374aab
initialize downloading logic
sambuaneesh Aug 4, 2024
71772f9
Add route and component for displaying all certificates and cleanup c…
sambuaneesh Aug 4, 2024
b7b0ff3
Added buttons to switch between certificate admin pages
bhavberi Aug 5, 2024
af6fc6a
use page size as constant
bhavberi Aug 5, 2024
4693cfb
fetch user certificates from server
bhavberi Aug 5, 2024
5ab4d1d
Fix All Certificates Table Formatting and show user name rather than …
bhavberi Aug 5, 2024
34f03a3
Display pagination when total pages > 1
bhavberi Aug 5, 2024
ce76d5f
fix #79
sambuaneesh Aug 10, 2024
c481965
fixed #77 and removed public download action for certificate
sambuaneesh Aug 11, 2024
d7ad2d4
cleaning handleCerificateDownload
sambuaneesh Aug 11, 2024
4bc8ba4
Use server actions in place of fetch calls for certificate paths
bhavberi Aug 12, 2024
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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
"framer-motion": "^11.2.4",
"graphql": "^16.8.1",
"graphql-tag": "^2.12.6",
"html2canvas": "^1.4.1",
"jwt-decode": "^4.0.0",
"jspdf": "^2.5.1",
"libphonenumber-js": "^1.11.1",
"next": "^14.2.3",
"next-mdx-remote": "^4.4.1",
Expand Down
4 changes: 4 additions & 0 deletions src/acl/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ const routes = {
"/manage/holidays": ["slo"],
"/manage/holidays/new": ["slo"], // has to be higher to not conflict with :id
"/manage/holidays/:id": ["slo"],

"/certificate-requests": ["cc", "slo"],
"/certificate-requests/all": ["cc", "slo"],
"/profile/[id]/generate-certificate": ["public"],
};

export default routes;
46 changes: 46 additions & 0 deletions src/app/actions/certificates/all/server_action.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use server";

import { getClient } from "gql/client";
import { GET_ALL_CERTIFICATES } from "gql/queries/members";

export async function getAllCertificates(page = 1, pageSize = 10) {
const response = { ok: false, data: null, error: null };

try {
const { error, data } = await getClient().query(GET_ALL_CERTIFICATES, {
page,
pageSize,
});

if (error) {
response.error = {
title: error.name,
messages: error?.graphQLErrors?.map((ge) => ge?.message) || [
"An unknown error occurred",
],
};

return response;
}

if (!data || !data.getAllCertificates) {
response.error = {
title: "Error",
messages: ["No certificate data found"],
};

return response;
}

response.ok = true;
response.data = data.getAllCertificates;
} catch (err) {
console.error("Error fetching all certificates:", err);
response.error = {
title: "Error",
messages: [err.message || "An unexpected error occurred"],
};
}

return response;
}
24 changes: 24 additions & 0 deletions src/app/actions/certificates/approve/server_action.jsx
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;
}
54 changes: 54 additions & 0 deletions src/app/actions/certificates/fetch/server_action.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"use server";

import { getClient } from "gql/client";
import { GET_CERTIFICATE_BY_NUMBER } from "gql/queries/members";

export async function fetchCertificate(certificateNumber) {
let response = { ok: false, data: null, error: null };

if (!certificateNumber) {
response.error = {
title: "Error",
messages: ["Certificate number is required"],
};

return response;
}

try {
const { error, data } = await getClient().query(GET_CERTIFICATE_BY_NUMBER, {
certificateNumber,
});

if (error) {
response.error = {
title: error.name,
messages: error?.graphQLErrors?.map((ge) => ge?.message) || [
"An unknown error occurred",
],
};

return response;
}

if (!data || !data.getCertificateByNumber) {
response.error = {
title: "Error",
messages: ["Certificate not found"],
};

return response;
}

response.ok = true;
response.data = data.getCertificateByNumber;
} catch (err) {
console.error("Error fetching certificate:", err);
response.error = {
title: "Error",
messages: [err.message || "An unexpected error occurred"],
};
}

return response;
}
24 changes: 24 additions & 0 deletions src/app/actions/certificates/pending/server_action.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use server";

import { getClient } from "gql/client";
import { GET_PENDING_CERTIFICATES } from "gql/queries/members";

export async function getPendingCertificates() {
const response = { ok: false, data: null, error: null };

const {
error,
data: { getPendingCertificates },
} = await getClient().query(GET_PENDING_CERTIFICATES);
if (error) {
response.error = {
title: error.name,
messages: error?.graphQLErrors?.map((ge) => ge?.message),
};
} else {
response.ok = true;
response.data = [...getPendingCertificates];
}

return response;
}
24 changes: 24 additions & 0 deletions src/app/actions/certificates/reject/server_action.jsx
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;
}
29 changes: 29 additions & 0 deletions src/app/actions/certificates/request/server_action.jsx
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 };
}
}
37 changes: 37 additions & 0 deletions src/app/actions/certificates/verify/server_action.jsx
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;
}
22 changes: 22 additions & 0 deletions src/app/actions/users/get/full/server_action.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use server";

import { getClient } from "gql/client";
import { GET_USER_PROFILE } from "gql/queries/users";

export async function getFullUser(uid) {
const response = { ok: false, data: null, error: null };

const { error, data: { userMeta, userProfile } = {} } =
await getClient().query(GET_USER_PROFILE, { userInput: { uid } });
if (error) {
response.error = {
title: error.name,
messages: error?.graphQLErrors?.map((ge) => ge?.message),
};
} else {
response.ok = true;
response.data = { ...userMeta, ...userProfile };
}

return response;
}
28 changes: 28 additions & 0 deletions src/app/certificate-requests/all/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Suspense } from "react";
import { Box, Button, Grid, Typography } from "@mui/material";

import AllCertificatesTable from "components/certificates/AllCertificatesTable";

export default function AllCertificatesPage() {
return (
<div>
<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="/certificate-requests">
View Pending Certificate Requests
</Button>
</Box>
</Grid>
<Suspense fallback={<div>Loading...</div>}>
<AllCertificatesTable />
</Suspense>
</div>
);
}
28 changes: 28 additions & 0 deletions src/app/certificate-requests/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Suspense } from "react";
import { Box, Button, Grid, Typography } from "@mui/material";

import PendingCertificatesTable from "components/certificates/PendingCertificatesTable";

export default function CertificateRequestsPage() {
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="/certificate-requests/all">
View All Certificates
</Button>
</Box>
</Grid>
<Suspense fallback={<div>Loading...</div>}>
<PendingCertificatesTable />
</Suspense>
</div>
);
}
Loading