Skip to content

Commit 0ce767c

Browse files
Merge pull request #131 from princyballabh/main
Redesign GenSec endorsement page with modern card layout
2 parents 05581f2 + 331045d commit 0ce767c

3 files changed

Lines changed: 220 additions & 154 deletions

File tree

frontend/src/Components/GenSec/AchievementsEndorsementTab.jsx

Lines changed: 91 additions & 41 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,111 @@ 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-4 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="mb-4">
124+
<h3 className="text-lg font-semibold text-gray-900 mb-2">
125+
{ach.title}
126+
</h3>
127+
<p className="text-sm text-gray-600 mb-3 line-clamp-2">
128+
"{ach.description}"
129+
</p>
130+
</div>
95131

96-
{/* User Info */}
132+
{/* User Information */}
97133
{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>
134+
<div className="flex items-center gap-2 mb-2 text-sm text-gray-700">
135+
<User className="w-4 h-4" />
136+
<span className="font-medium">
137+
{ach.user_id.personal_info?.name}
138+
</span>
139+
<span className="text-gray-500">
140+
{ach.user_id.user_id ? `• ${ach.user_id.user_id}` : ""}
141+
</span>
142+
</div>
102143
)}
103144

145+
{/* Event Information */}
104146
{ach.event_id && (
105-
<>
106-
<p className="text-sm text-gray-500 mt-1">
147+
<div className="bg-white rounded-md p-2 mb-2">
148+
<p className="text-sm font-medium text-gray-900">
107149
Event: {ach.event_id.title}
108150
</p>
109-
<p className="text-sm text-gray-500">
110-
{ach.event_id.description}
111-
</p>
112-
</>
151+
{ach.event_id.description && (
152+
<p className="text-xs text-gray-600 mt-1">
153+
{ach.event_id.description}
154+
</p>
155+
)}
156+
</div>
113157
)}
114-
<p className="text-sm text-gray-500">
115-
Date: {format(new Date(ach.date_achieved), "dd MMM yyyy")}
116-
</p>
117-
{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"
158+
159+
{/* Date and Certificate */}
160+
<div className="flex items-center justify-between mb-2 text-sm">
161+
<div className="flex items-center gap-2 text-gray-600">
162+
<Calendar className="w-4 h-4" />
163+
<span>{format(new Date(ach.date_achieved), "dd MMM yyyy")}</span>
164+
</div>
165+
{ach.certificate_url && (
166+
<a
167+
href={ach.certificate_url}
168+
target="_blank"
169+
rel="noopener noreferrer"
170+
className="inline-flex items-center gap-1 text-sm text-blue-600 hover:text-blue-800 transition-colors"
171+
>
172+
<ExternalLink className="w-3 h-3" />
173+
Certificate
174+
</a>
175+
)}
176+
</div>
177+
178+
{/* Action Button */}
179+
<div className="flex justify-end pt-2 border-t border-pink-200">
180+
<button
181+
onClick={() => handleVerify(ach._id)}
182+
disabled={verifying.has(ach._id)}
183+
className="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white text-sm font-medium rounded-md hover:bg-blue-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
123184
>
124-
View Certificate
125-
</a>
126-
)}
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>
185+
<span>{verifying.has(ach._id) ? "Endorsing..." : "Endorse"}</span>
186+
</button>
187+
</div>
138188
</div>
139189
))}
140190
</div>

0 commit comments

Comments
 (0)