Skip to content

Commit 93a5386

Browse files
committed
Redesign GenSec endorsement page with modern card layout
1 parent 0e6f2d5 commit 93a5386

3 files changed

Lines changed: 240 additions & 136 deletions

File tree

frontend/src/Components/GenSec/AchievementsEndorsementTab.jsx

Lines changed: 98 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@
33
import React, { useEffect, useState } from "react";
44
import { format } from "date-fns";
55
import { AdminContext } from "../../context/AdminContext";
6+
import {
7+
ChevronRight,
8+
User,
9+
Calendar,
10+
Award,
11+
ExternalLink,
12+
} from "lucide-react";
613
import api from "../../utils/api";
14+
715
const AchievementsEndorsementTab = ({ skillType }) => {
816
const { isUserLoggedIn } = React.useContext(AdminContext);
917
const [achievements, setAchievements] = useState([]);
@@ -72,69 +80,119 @@ const AchievementsEndorsementTab = ({ skillType }) => {
7280
};
7381

7482
if (loading) {
75-
return <p className="text-gray-500">Loading achievements...</p>;
83+
return (
84+
<div className="flex justify-center items-center py-12">
85+
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
86+
</div>
87+
);
7688
}
89+
7790
if (error) {
78-
return <p className="text-red-600">{error}</p>;
91+
return (
92+
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
93+
<p className="text-red-800">{error}</p>
94+
</div>
95+
);
7996
}
97+
8098
if (achievements.length === 0) {
8199
return (
82-
<p className="text-gray-500">No achievements pending endorsement.</p>
100+
<div className="text-center py-12">
101+
<div className="w-16 h-16 mx-auto mb-4 bg-gray-100 rounded-full flex items-center justify-center">
102+
<Award className="w-8 h-8 text-gray-400" />
103+
</div>
104+
<h3 className="text-lg font-medium text-gray-900 mb-2">
105+
No Pending Endorsements
106+
</h3>
107+
<p className="text-gray-600">
108+
All achievements have been reviewed and endorsed.
109+
</p>
110+
</div>
83111
);
84112
}
113+
85114
console.log("Achievements:", achievements);
86115
return (
87-
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
116+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
88117
{achievements.map((ach) => (
89118
<div
90119
key={ach._id}
91-
className="bg-white shadow rounded-lg p-4 border border-gray-200"
120+
className="bg-pink-50 border border-pink-100 rounded-lg p-6 hover:shadow-md transition-shadow duration-200"
92121
>
93-
<h3 className="text-lg font-semibold">{ach.title}</h3>
94-
<p className="text-sm text-gray-700 mt-1">{ach.description}</p>
122+
{/* Card Header */}
123+
<div className="flex justify-between items-start mb-4">
124+
<div className="flex-1">
125+
<h3 className="text-lg font-semibold text-gray-900 mb-1">
126+
Achievement Request
127+
</h3>
128+
<h4 className="text-md font-medium text-gray-800 mb-2">
129+
{ach.title}
130+
</h4>
131+
<p className="text-sm text-gray-600 mb-3 line-clamp-2">
132+
"{ach.description}"
133+
</p>
134+
</div>
135+
</div>
95136

96-
{/* User Info */}
137+
{/* User Information */}
97138
{ach.user_id && (
98-
<p className="text-sm text-gray-500">
99-
Submitted by: {ach.user_id.personal_info?.name} (
100-
{ach.user_id.username}) | ID: {ach.user_id.user_id}
101-
</p>
139+
<div className="flex items-center gap-2 mb-3 text-sm text-gray-700">
140+
<User className="w-4 h-4" />
141+
<span className="font-medium">
142+
{ach.user_id.personal_info?.name}
143+
</span>
144+
<span className="text-gray-500">
145+
{ach.user_id.user_id ? `• ${ach.user_id.user_id}` : ""}
146+
</span>
147+
</div>
102148
)}
103149

150+
{/* Event Information */}
104151
{ach.event_id && (
105-
<>
106-
<p className="text-sm text-gray-500 mt-1">
152+
<div className="bg-white rounded-md p-3 mb-3">
153+
<p className="text-sm font-medium text-gray-900">
107154
Event: {ach.event_id.title}
108155
</p>
109-
<p className="text-sm text-gray-500">
110-
{ach.event_id.description}
111-
</p>
112-
</>
156+
{ach.event_id.description && (
157+
<p className="text-sm text-gray-600 mt-1">
158+
{ach.event_id.description}
159+
</p>
160+
)}
161+
</div>
113162
)}
114-
<p className="text-sm text-gray-500">
115-
Date: {format(new Date(ach.date_achieved), "dd MMM yyyy")}
116-
</p>
163+
164+
{/* Date Information */}
165+
<div className="flex items-center gap-2 mb-4 text-sm text-gray-600">
166+
<Calendar className="w-4 h-4" />
167+
<span>{format(new Date(ach.date_achieved), "dd MMM yyyy")}</span>
168+
</div>
169+
170+
{/* Certificate Link */}
117171
{ach.certificate_url && (
118-
<a
119-
href={ach.certificate_url}
120-
target="_blank"
121-
rel="noopener noreferrer"
122-
className="text-sm text-blue-600 underline block mt-1"
123-
>
124-
View Certificate
125-
</a>
172+
<div className="mb-4">
173+
<a
174+
href={ach.certificate_url}
175+
target="_blank"
176+
rel="noopener noreferrer"
177+
className="inline-flex items-center gap-2 text-sm text-blue-600 hover:text-blue-800 transition-colors"
178+
>
179+
<ExternalLink className="w-4 h-4" />
180+
View Certificate
181+
</a>
182+
</div>
126183
)}
127-
<button
128-
onClick={() => handleVerify(ach._id)}
129-
disabled={verifying.has(ach._id)}
130-
className={`mt-2 px-4 py-1 rounded text-white ${
131-
verifying.has(ach._id)
132-
? "bg-gray-400"
133-
: "bg-green-600 hover:bg-green-700"
134-
}`}
135-
>
136-
{verifying.has(ach._id) ? "Verifying..." : "Mark as Verified"}
137-
</button>
184+
185+
{/* Action Button */}
186+
<div className="flex justify-end">
187+
<button
188+
onClick={() => handleVerify(ach._id)}
189+
disabled={verifying.has(ach._id)}
190+
className="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-blue-600 hover:text-blue-800 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
191+
>
192+
<span>{verifying.has(ach._id) ? "Processing..." : "View"}</span>
193+
<ChevronRight className="w-4 h-4" />
194+
</button>
195+
</div>
138196
</div>
139197
))}
140198
</div>

0 commit comments

Comments
 (0)