-
Notifications
You must be signed in to change notification settings - Fork 30
Certificate page UI #72 #82
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
base: main
Are you sure you want to change the base?
Conversation
…rtificate management interface with search, filter, and CRUD operations - Add modern responsive design with animations and glassmorphism effects - Include certificate viewing modal with detailed information - Add download and share functionality for certificates - Update navigation to include Certificates page - Enhance user experience with loading states and empty states - Fix issue RamakrushnaBiswal#72: Certificate page UI implementation
…rtificate management interface with search, filter, and CRUD operations - Add modern responsive design with animations and glassmorphism effects - Include certificate viewing modal with detailed information - Add download and share functionality for certificates - Update navigation to include Certificates page - Enhance user experience with loading states and empty states - Fix issue RamakrushnaBiswal#72: Certificate page UI implementation
|
Someone is attempting to deploy a commit to the bunty's projects Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughA new Certificate Management UI is introduced in the frontend, including a dedicated React component, new navigation route, and updates to documentation and navigation. The component provides search, filter, view, download, and share features for certificates. The Navbar and README are updated to reflect these additions. No backend or unrelated changes are present. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Navbar
participant Router
participant CertificateComponent
participant BackendAPI
User->>Navbar: Clicks "Certificates"
Navbar->>Router: Navigates to /certificates
Router->>CertificateComponent: Renders Certificate component
CertificateComponent->>BackendAPI: Fetch certificates
BackendAPI-->>CertificateComponent: Returns certificate data
CertificateComponent-->>User: Displays certificate list with search/filter
User->>CertificateComponent: Selects certificate/view details/download/share
CertificateComponent->>BackendAPI: (If download) Fetch certificate image
CertificateComponent-->>User: Shows modal/download/share actions
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~15–20 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Suggested labels
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🔭 Outside diff range comments (2)
tatus (1)
1-315: Remove unrelated file from the PR.This file contains help documentation for the "less" command-line pager utility, which is completely unrelated to the Certificate Management UI feature being implemented in this PR. This appears to be an accidentally committed file that should be removed.
-Delete the entire file as it's not related to the PR's purposeh origin main (1)
1-2: Remove accidentally committed git output.This file appears to contain git log output showing commit information, which should not be committed to the repository. This looks like accidental output from a
git logor similar command.Remove this file as it's not meant to be part of the codebase.
🧹 Nitpick comments (2)
Frontend/src/components/Certificate.jsx (2)
106-110: Avoid mixing inline styles with Tailwind classes.Using both inline styles and Tailwind classes reduces maintainability and consistency.
-<div style={{ width: '100%', minHeight: '100vh', position: 'relative', overflow: 'visible' }}> - <div style={{ position: 'absolute', inset: 0, zIndex: 0 }}> +<div className="w-full min-h-screen relative overflow-visible"> + <div className="absolute inset-0 z-0"> <DarkVeil /> </div> - <div style={{ position: 'relative', zIndex: 1 }} className="min-h-screen py-12 px-4"> + <div className="relative z-10 min-h-screen py-12 px-4">
1-336: Consider adding TypeScript or PropTypes for type safety.The component lacks type definitions which could lead to runtime errors.
Consider migrating to TypeScript or adding PropTypes to ensure type safety. Would you like me to help generate TypeScript interfaces for this component?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
Frontend/README.md(2 hunks)Frontend/src/App.jsx(2 hunks)Frontend/src/components/Certificate.jsx(1 hunks)Frontend/src/components/Navbar.jsx(2 hunks)h origin main(1 hunks)tatus(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: cherylpinto
PR: RamakrushnaBiswal/HonorBox#79
File: Frontend/src/components/Navbar.jsx:0-0
Timestamp: 2025-08-04T18:51:46.896Z
Learning: In the HonorBox project Frontend/src/components/Navbar.jsx, the password change functionality in confirmChangePassword() intentionally only logs to console as this was a UI-only enhancement PR, with backend integration planned for future implementation.
Learnt from: cherylpinto
PR: RamakrushnaBiswal/HonorBox#79
File: Frontend/src/components/Navbar.jsx:153-157
Timestamp: 2025-08-04T18:52:03.885Z
Learning: In the HonorBox project Frontend/src/components/Navbar.jsx, the account deletion functionality in handleDeleteAccount() intentionally only logs to console as this was a UI-only enhancement PR, with backend integration planned for future implementation.
Learnt from: cherylpinto
PR: RamakrushnaBiswal/HonorBox#79
File: Frontend/src/components/Navbar.jsx:0-0
Timestamp: 2025-08-04T19:02:27.830Z
Learning: In the HonorBox project Frontend/src/components/Navbar.jsx, the email change functionality includes a confirmation modal triggered by clicking the "Change" button, which calls setShowConfirmEmailChange(true) and displays a modal asking for user confirmation before applying the email change via handleEmailChange().
📚 Learning: 2025-08-04T18:51:46.896Z
Learnt from: cherylpinto
PR: RamakrushnaBiswal/HonorBox#79
File: Frontend/src/components/Navbar.jsx:0-0
Timestamp: 2025-08-04T18:51:46.896Z
Learning: In the HonorBox project Frontend/src/components/Navbar.jsx, the password change functionality in confirmChangePassword() intentionally only logs to console as this was a UI-only enhancement PR, with backend integration planned for future implementation.
Applied to files:
Frontend/src/components/Navbar.jsxh origin mainFrontend/README.mdFrontend/src/App.jsxFrontend/src/components/Certificate.jsx
📚 Learning: 2025-08-04T18:52:03.885Z
Learnt from: cherylpinto
PR: RamakrushnaBiswal/HonorBox#79
File: Frontend/src/components/Navbar.jsx:153-157
Timestamp: 2025-08-04T18:52:03.885Z
Learning: In the HonorBox project Frontend/src/components/Navbar.jsx, the account deletion functionality in handleDeleteAccount() intentionally only logs to console as this was a UI-only enhancement PR, with backend integration planned for future implementation.
Applied to files:
Frontend/src/components/Navbar.jsxFrontend/README.mdFrontend/src/App.jsxFrontend/src/components/Certificate.jsx
📚 Learning: 2025-08-04T19:02:27.830Z
Learnt from: cherylpinto
PR: RamakrushnaBiswal/HonorBox#79
File: Frontend/src/components/Navbar.jsx:0-0
Timestamp: 2025-08-04T19:02:27.830Z
Learning: In the HonorBox project Frontend/src/components/Navbar.jsx, the email change functionality includes a confirmation modal triggered by clicking the "Change" button, which calls setShowConfirmEmailChange(true) and displays a modal asking for user confirmation before applying the email change via handleEmailChange().
Applied to files:
Frontend/src/components/Navbar.jsxFrontend/README.mdFrontend/src/App.jsxFrontend/src/components/Certificate.jsx
🔇 Additional comments (6)
Frontend/src/components/Navbar.jsx (2)
114-119: LGTM!The new "Certificates" navigation link is properly integrated into the desktop menu with consistent styling and hover effects matching the existing "Home" link.
163-169: LGTM!The "Certificates" link is correctly added to the mobile menu with proper onClick handler to close the menu after navigation, maintaining consistency with the existing mobile navigation pattern.
Frontend/src/App.jsx (2)
5-5: LGTM!The Certificate component import follows the established pattern and is correctly placed with other component imports.
53-53: LGTM!The new route for "/certificates" is properly configured and follows the existing route structure. The path is logical and the component reference is correct.
Frontend/README.md (2)
6-6: LGTM!The Certificate Management feature is properly documented with a clear description of its capabilities (view, search, filter, and manage certificates).
47-50: LGTM!The project structure documentation is updated correctly to include the new Certificate.jsx component and accurately describes its purpose as the certificate management page. The correction to the Generate.jsx comment also improves clarity.
| const fetchCertificates = async () => { | ||
| try { | ||
| const response = await fetch(`${BACKEND_URL}/api/certificates`); | ||
| if (response.ok) { | ||
| const data = await response.json(); | ||
| setCertificates(data); | ||
| } | ||
| } catch (error) { | ||
| console.error("Error fetching certificates:", error); | ||
| } finally { | ||
| setLoading(false); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Improve error handling and add authentication.
The fetch operation has several issues:
- Errors are only logged to console - users won't be notified if the fetch fails
- No authentication headers are being sent with the request
- Response data is not validated before setting state
Consider adding error state management and authentication:
const fetchCertificates = async () => {
try {
- const response = await fetch(`${BACKEND_URL}/api/certificates`);
+ const response = await fetch(`${BACKEND_URL}/api/certificates`, {
+ headers: {
+ 'Authorization': `Bearer ${localStorage.getItem('token')}`, // Add auth if required
+ 'Content-Type': 'application/json',
+ },
+ });
if (response.ok) {
const data = await response.json();
+ // Validate data structure
+ if (Array.isArray(data)) {
setCertificates(data);
+ } else {
+ console.error("Invalid data format received");
+ // Set error state
+ }
+ } else {
+ console.error(`Failed to fetch: ${response.status}`);
+ // Set error state
}
} catch (error) {
console.error("Error fetching certificates:", error);
+ // Set error state to show user-friendly message
} finally {
setLoading(false);
}
};Let me verify if authentication is implemented elsewhere in the codebase:
🏁 Script executed:
#!/bin/bash
# Check if authentication is used in other API calls
rg -A 3 "fetch.*api" --type jsx --type jsLength of output: 71
🏁 Script executed:
#!/bin/bash
# Search for fetch calls and any usage of Authorization headers in .js and .jsx files
rg -n "fetch" --glob "*.{js,jsx}" -A3
rg -n "Authorization" --glob "*.{js,jsx}"Length of output: 5913
#!/bin/bash
# Display the authentication utility implementation
sed -n '1,200p' Frontend/src/utils/auth.js🏁 Script executed:
#!/bin/bash
# Display the authentication utility to see how auth headers are applied
sed -n '1,200p' Frontend/src/utils/auth.jsLength of output: 1096
Use the existing authenticatedFetch, add error state, and validate the response in Certificate.jsx
To ensure users see failures, credentials are sent, and data is well-formed, update fetchCertificates as follows:
• In Frontend/src/components/Certificate.jsx (around lines 1–19), import and track an error state alongside loading:
import { authenticatedFetch } from '../utils/auth';
const [certificates, setCertificates] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);• Rewrite fetchCertificates (lines 20–32) to:
- const fetchCertificates = async () => {
- try {
- const response = await fetch(`${BACKEND_URL}/api/certificates`);
- if (response.ok) {
- const data = await response.json();
- setCertificates(data);
- }
- } catch (error) {
- console.error("Error fetching certificates:", error);
- } finally {
- setLoading(false);
- }
- };
+ const fetchCertificates = async () => {
+ setLoading(true);
+ setError(null);
+ try {
+ const res = await authenticatedFetch(`${BACKEND_URL}/api/certificates`);
+ if (!res.ok) {
+ throw new Error(`Fetch failed: ${res.status} ${res.statusText}`);
+ }
+ const data = await res.json();
+ if (!Array.isArray(data)) {
+ throw new Error('Unexpected response format');
+ }
+ setCertificates(data);
+ } catch (err) {
+ console.error('Error fetching certificates:', err);
+ setError(err.message);
+ } finally {
+ setLoading(false);
+ }
+ };• In your render, show a user-friendly message when error is non-null.
These changes:
- Reuse the project’s
authenticatedFetch(adds the Bearer token). - Expose failures via an
errorstate. - Guard against invalid payloads.
🤖 Prompt for AI Agents
In Frontend/src/components/Certificate.jsx around lines 1 to 32, import
authenticatedFetch from '../utils/auth' and add an error state using
useState(null) alongside certificates and loading states. Update
fetchCertificates to use authenticatedFetch instead of fetch, set error state to
null at the start, and after fetching, validate the response data before setting
certificates; if invalid, set an appropriate error message. In the catch block,
set the error state with the caught error message. Finally, in the component
render, display a user-friendly error message when error state is non-null to
inform users of failures.
| const filteredCertificates = certificates.filter(cert => { | ||
| const matchesSearch = cert.name.toLowerCase().includes(searchTerm.toLowerCase()) || | ||
| cert.email.toLowerCase().includes(searchTerm.toLowerCase()) || | ||
| cert.uniqueId.toLowerCase().includes(searchTerm.toLowerCase()); | ||
| const matchesFilter = filterType === "all" || cert.certificateType === filterType; | ||
| return matchesSearch && matchesFilter; | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add null safety checks and optimize filtering with useMemo.
The filtering logic could throw errors if certificate properties are undefined and should be memoized for better performance.
+import { useState, useEffect, useMemo } from "react";
-const filteredCertificates = certificates.filter(cert => {
- const matchesSearch = cert.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
- cert.email.toLowerCase().includes(searchTerm.toLowerCase()) ||
- cert.uniqueId.toLowerCase().includes(searchTerm.toLowerCase());
+const filteredCertificates = useMemo(() => {
+ return certificates.filter(cert => {
+ const matchesSearch =
+ (cert.name?.toLowerCase().includes(searchTerm.toLowerCase()) || false) ||
+ (cert.email?.toLowerCase().includes(searchTerm.toLowerCase()) || false) ||
+ (cert.uniqueId?.toLowerCase().includes(searchTerm.toLowerCase()) || false);
const matchesFilter = filterType === "all" || cert.certificateType === filterType;
return matchesSearch && matchesFilter;
-});
+ });
+}, [certificates, searchTerm, filterType]);Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In Frontend/src/components/Certificate.jsx around lines 34 to 40, the filtering
logic lacks null safety checks for certificate properties, which can cause
runtime errors if any property is undefined. Add checks to ensure cert.name,
cert.email, and cert.uniqueId exist before calling toLowerCase on them.
Additionally, wrap the filtering logic inside a useMemo hook with dependencies
on certificates, searchTerm, and filterType to optimize performance by memoizing
the filtered results.
| const handleDownload = async (cert) => { | ||
| try { | ||
| const response = await fetch(`${BACKEND_URL}/api/certificate/${cert.uniqueId}`); | ||
| if (response.ok) { | ||
| const blob = await response.blob(); | ||
| const url = window.URL.createObjectURL(blob); | ||
| const a = document.createElement('a'); | ||
| a.href = url; | ||
| a.download = `certificate-${cert.uniqueId}.png`; | ||
| document.body.appendChild(a); | ||
| a.click(); | ||
| window.URL.revokeObjectURL(url); | ||
| document.body.removeChild(a); | ||
| } | ||
| } catch (error) { | ||
| console.error("Error downloading certificate:", error); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve download error handling and add loading state.
The download function needs better error handling and user feedback.
-const handleDownload = async (cert) => {
+const [downloading, setDownloading] = useState(false);
+
+const handleDownload = async (cert) => {
+ setDownloading(true);
try {
const response = await fetch(`${BACKEND_URL}/api/certificate/${cert.uniqueId}`);
if (response.ok) {
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `certificate-${cert.uniqueId}.png`;
document.body.appendChild(a);
a.click();
- window.URL.revokeObjectURL(url);
document.body.removeChild(a);
+ window.URL.revokeObjectURL(url);
+ } else {
+ throw new Error(`Download failed: ${response.status}`);
}
} catch (error) {
console.error("Error downloading certificate:", error);
+ // Show user-friendly error message instead of just logging
+ } finally {
+ setDownloading(false);
}
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const handleDownload = async (cert) => { | |
| try { | |
| const response = await fetch(`${BACKEND_URL}/api/certificate/${cert.uniqueId}`); | |
| if (response.ok) { | |
| const blob = await response.blob(); | |
| const url = window.URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = `certificate-${cert.uniqueId}.png`; | |
| document.body.appendChild(a); | |
| a.click(); | |
| window.URL.revokeObjectURL(url); | |
| document.body.removeChild(a); | |
| } | |
| } catch (error) { | |
| console.error("Error downloading certificate:", error); | |
| } | |
| }; | |
| // add loading state for download | |
| const [downloading, setDownloading] = useState(false); | |
| const handleDownload = async (cert) => { | |
| setDownloading(true); | |
| try { | |
| const response = await fetch(`${BACKEND_URL}/api/certificate/${cert.uniqueId}`); | |
| if (response.ok) { | |
| const blob = await response.blob(); | |
| const url = window.URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = `certificate-${cert.uniqueId}.png`; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| window.URL.revokeObjectURL(url); | |
| } else { | |
| throw new Error(`Download failed: ${response.status}`); | |
| } | |
| } catch (error) { | |
| console.error("Error downloading certificate:", error); | |
| // TODO: show user‐friendly error message (e.g. set an error state or toast) | |
| } finally { | |
| setDownloading(false); | |
| } | |
| }; |
🤖 Prompt for AI Agents
In Frontend/src/components/Certificate.jsx around lines 47 to 64, improve the
handleDownload function by adding a loading state to indicate progress to the
user and enhance error handling by providing user feedback on failure. Implement
a state variable to track loading, set it to true at the start of the download
and false at the end or on error, and display a loading indicator in the UI.
Also, handle non-ok responses by throwing an error or notifying the user, and
ensure errors are caught and communicated clearly.
| const handleShare = async (cert) => { | ||
| const shareUrl = `${BACKEND_URL}/api/certificate/${cert.uniqueId}`; | ||
| if (navigator.share) { | ||
| try { | ||
| await navigator.share({ | ||
| title: `Certificate - ${cert.name}`, | ||
| text: `Check out this certificate for ${cert.name}`, | ||
| url: shareUrl | ||
| }); | ||
| } catch (error) { | ||
| console.error("Error sharing:", error); | ||
| } | ||
| } else { | ||
| // Fallback to copying to clipboard | ||
| navigator.clipboard.writeText(shareUrl); | ||
| alert("Certificate link copied to clipboard!"); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Replace alert() with proper notification system and handle clipboard errors.
Using alert() provides poor UX. Also, clipboard operations can fail and should be handled properly.
const handleShare = async (cert) => {
const shareUrl = `${BACKEND_URL}/api/certificate/${cert.uniqueId}`;
if (navigator.share) {
try {
await navigator.share({
title: `Certificate - ${cert.name}`,
text: `Check out this certificate for ${cert.name}`,
url: shareUrl
});
} catch (error) {
- console.error("Error sharing:", error);
+ if (error.name !== 'AbortError') {
+ console.error("Error sharing:", error);
+ // Show error notification
+ }
}
} else {
// Fallback to copying to clipboard
- navigator.clipboard.writeText(shareUrl);
- alert("Certificate link copied to clipboard!");
+ try {
+ await navigator.clipboard.writeText(shareUrl);
+ // Use a toast notification library instead of alert
+ // Example: showToast("Certificate link copied to clipboard!");
+ } catch (error) {
+ console.error("Error copying to clipboard:", error);
+ // Show error notification
+ }
}
};Consider using a toast notification library like react-toastify for better UX.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const handleShare = async (cert) => { | |
| const shareUrl = `${BACKEND_URL}/api/certificate/${cert.uniqueId}`; | |
| if (navigator.share) { | |
| try { | |
| await navigator.share({ | |
| title: `Certificate - ${cert.name}`, | |
| text: `Check out this certificate for ${cert.name}`, | |
| url: shareUrl | |
| }); | |
| } catch (error) { | |
| console.error("Error sharing:", error); | |
| } | |
| } else { | |
| // Fallback to copying to clipboard | |
| navigator.clipboard.writeText(shareUrl); | |
| alert("Certificate link copied to clipboard!"); | |
| } | |
| }; | |
| const handleShare = async (cert) => { | |
| const shareUrl = `${BACKEND_URL}/api/certificate/${cert.uniqueId}`; | |
| if (navigator.share) { | |
| try { | |
| await navigator.share({ | |
| title: `Certificate - ${cert.name}`, | |
| text: `Check out this certificate for ${cert.name}`, | |
| url: shareUrl | |
| }); | |
| } catch (error) { | |
| if (error.name !== 'AbortError') { | |
| console.error("Error sharing:", error); | |
| // Show error notification | |
| } | |
| } | |
| } else { | |
| // Fallback to copying to clipboard | |
| try { | |
| await navigator.clipboard.writeText(shareUrl); | |
| // Use a toast notification library instead of alert | |
| // Example: showToast("Certificate link copied to clipboard!"); | |
| } catch (error) { | |
| console.error("Error copying to clipboard:", error); | |
| // Show error notification | |
| } | |
| } | |
| }; |
🤖 Prompt for AI Agents
In Frontend/src/components/Certificate.jsx around lines 66 to 83, replace the
alert() call used for notifying the user about the copied certificate link with
a proper toast notification from a library like react-toastify. Additionally,
add error handling for the clipboard.writeText operation by using try-catch or
promise catch to handle failures gracefully and show an error toast notification
if copying fails.
| <option value="Achievement">Achievement</option> | ||
| </select> | ||
| <button | ||
| onClick={() => window.location.href = '/generate'} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use React Router for navigation instead of window.location.href.
Direct navigation with window.location.href causes full page reload, losing application state.
+import { useNavigate } from 'react-router-dom';
+const navigate = useNavigate();
<button
- onClick={() => window.location.href = '/generate'}
+ onClick={() => navigate('/generate')}Also applies to: 188-188
🤖 Prompt for AI Agents
In Frontend/src/components/Certificate.jsx at lines 158 and 188, replace the
direct navigation using window.location.href with React Router's navigation
method to prevent full page reloads and preserve application state. Import the
useNavigate hook from react-router-dom, initialize it in the component, and use
the navigate function inside the onClick handlers to navigate to '/generate'
instead of setting window.location.href.
| > | ||
| <div className="flex items-start justify-between mb-4"> | ||
| <div className="flex items-center gap-3"> | ||
| <div className={`text-2xl ${getCertificateIcon(cert.certificateType)}`}></div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix emoji display issue in certificate icon.
The template literal syntax is incorrect for displaying the emoji.
-<div className={`text-2xl ${getCertificateIcon(cert.certificateType)}`}></div>
+<div className="text-2xl">{getCertificateIcon(cert.certificateType)}</div>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div className={`text-2xl ${getCertificateIcon(cert.certificateType)}`}></div> | |
| <div className="text-2xl">{getCertificateIcon(cert.certificateType)}</div> |
🤖 Prompt for AI Agents
In Frontend/src/components/Certificate.jsx at line 211, the template literal
used to combine the text size class and the certificate icon is incorrect for
displaying the emoji. Fix this by ensuring the emoji returned from
getCertificateIcon is properly included in the JSX, either by rendering it
directly inside the div or by correctly concatenating the className string
without using template literals for the emoji display.
| {showModal && selectedCertificate && ( | ||
| <div className="fixed inset-0 z-50 flex items-center justify-center p-4"> | ||
| <div className="absolute inset-0 bg-black/60 backdrop-blur-sm" onClick={() => setShowModal(false)}></div> | ||
| <motion.div | ||
| initial={{ opacity: 0, scale: 0.9 }} | ||
| animate={{ opacity: 1, scale: 1 }} | ||
| exit={{ opacity: 0, scale: 0.9 }} | ||
| className="bg-[rgba(30,30,40,0.98)] backdrop-blur-md border border-[rgba(180,120,255,0.18)] rounded-2xl p-8 max-w-2xl w-full max-h-[90vh] overflow-y-auto shadow-2xl" | ||
| > | ||
| <div className="flex items-center justify-between mb-6"> | ||
| <h2 className="text-2xl font-bold text-white">Certificate Details</h2> | ||
| <button | ||
| onClick={() => setShowModal(false)} | ||
| className="text-white/60 hover:text-white text-2xl" | ||
| > | ||
| × | ||
| </button> | ||
| </div> | ||
|
|
||
| <div className="space-y-4 text-white"> | ||
| <div className="grid grid-cols-2 gap-4"> | ||
| <div> | ||
| <label className="text-white/60 text-sm">Name</label> | ||
| <p className="font-semibold">{selectedCertificate.name}</p> | ||
| </div> | ||
| <div> | ||
| <label className="text-white/60 text-sm">Email</label> | ||
| <p className="font-semibold">{selectedCertificate.email}</p> | ||
| </div> | ||
| <div> | ||
| <label className="text-white/60 text-sm">Certificate Type</label> | ||
| <p className="font-semibold">{selectedCertificate.certificateType}</p> | ||
| </div> | ||
| <div> | ||
| <label className="text-white/60 text-sm">Unique ID</label> | ||
| <p className="font-mono font-semibold">{selectedCertificate.uniqueId}</p> | ||
| </div> | ||
| <div> | ||
| <label className="text-white/60 text-sm">Created Date</label> | ||
| <p className="font-semibold">{new Date(selectedCertificate.createdAt).toLocaleDateString()}</p> | ||
| </div> | ||
| <div> | ||
| <label className="text-white/60 text-sm">Status</label> | ||
| <p className="font-semibold text-green-400">✓ Valid</p> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div className="flex gap-3 pt-4"> | ||
| <button | ||
| onClick={() => handleDownload(selectedCertificate)} | ||
| className="flex-1 flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-green-500 to-green-600 rounded-lg text-white hover:scale-105 transition-transform" | ||
| > | ||
| <FaDownload /> | ||
| Download Certificate | ||
| </button> | ||
| <button | ||
| onClick={() => handleShare(selectedCertificate)} | ||
| className="flex-1 flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-blue-500 to-blue-600 rounded-lg text-white hover:scale-105 transition-transform" | ||
| > | ||
| <FaShare /> | ||
| Share Certificate | ||
| </button> | ||
| </div> | ||
| </div> | ||
| </motion.div> | ||
| </div> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve modal accessibility with focus trap and keyboard handling.
The modal lacks proper accessibility features like focus trapping and escape key handling.
{showModal && selectedCertificate && (
- <div className="fixed inset-0 z-50 flex items-center justify-center p-4">
+ <div
+ className="fixed inset-0 z-50 flex items-center justify-center p-4"
+ role="dialog"
+ aria-modal="true"
+ aria-labelledby="modal-title"
+ onKeyDown={(e) => {
+ if (e.key === 'Escape') {
+ setShowModal(false);
+ }
+ }}
+ >
<div className="absolute inset-0 bg-black/60 backdrop-blur-sm" onClick={() => setShowModal(false)}></div>
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9 }}
className="bg-[rgba(30,30,40,0.98)] backdrop-blur-md border border-[rgba(180,120,255,0.18)] rounded-2xl p-8 max-w-2xl w-full max-h-[90vh] overflow-y-auto shadow-2xl"
>
<div className="flex items-center justify-between mb-6">
- <h2 className="text-2xl font-bold text-white">Certificate Details</h2>
+ <h2 id="modal-title" className="text-2xl font-bold text-white">Certificate Details</h2>Consider using a library like react-focus-lock for proper focus management.
🤖 Prompt for AI Agents
In Frontend/src/components/Certificate.jsx around lines 263 to 329, the modal
component lacks accessibility features such as focus trapping and handling the
Escape key to close the modal. To fix this, integrate a focus management library
like react-focus-lock to trap keyboard focus within the modal while it is open,
and add an event listener to detect the Escape key press to close the modal by
calling setShowModal(false). This will improve keyboard navigation and overall
accessibility of the modal.
| </div> | ||
| <div> | ||
| <label className="text-white/60 text-sm">Status</label> | ||
| <p className="font-semibold text-green-400">✓ Valid</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't hard-code certificate status.
The certificate status is hard-coded as "Valid" regardless of actual certificate state.
-<p className="font-semibold text-green-400">✓ Valid</p>
+<p className={`font-semibold ${selectedCertificate.isValid !== false ? 'text-green-400' : 'text-red-400'}`}>
+ {selectedCertificate.isValid !== false ? '✓ Valid' : '✗ Invalid'}
+</p>🤖 Prompt for AI Agents
In Frontend/src/components/Certificate.jsx at line 306, the certificate status
is hard-coded as "Valid". Replace this static text with a dynamic expression
that reflects the actual certificate status from the component's state or props,
ensuring the displayed status updates correctly based on the certificate's real
validity.
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
@shanurajpoot001 its not woking like the img not showing after download and the certificate should be show the perticular user |

🎉 Certificate Management Page UI - Feature Implementation
�� Issue Reference
Fixes: #72 - [FEATURE]: Certificate page UI
🚀 Overview
This PR implements a comprehensive Certificate Management page that provides users with a modern, intuitive interface to view, search, filter, and manage all their generated certificates in one centralized location.
✨ Features Implemented
🎨 Modern UI/UX Design
🔍 Advanced Search & Filter
📋 Certificate Management
🎯 Key Functionalities
🛠 Technical Implementation
Frontend Components
/certificatesBackend Integration
/api/certificatesendpointDesign System
�� Responsive Design
�� UI/UX Enhancements
🔧 Code Quality
�� Testing Scenarios
�� Deployment Ready
📝 Documentation Updates
🎯 User Experience Improvements
�� Related Links
/api/certificatesendpoint🧪 Testing Instructions
/certificatespage📸 Screenshots
[Screenshots will be added after deployment]
Ready for Review! 🚀
This implementation provides a complete certificate management solution that enhances the user experience significantly while maintaining the existing design system and code quality standards.
Summary by CodeRabbit
New Features
Documentation