Skip to content

Commit 765ec5f

Browse files
committed
endorse tabs design upadated to sync with new figma design
1 parent ebd1089 commit 765ec5f

3 files changed

Lines changed: 133 additions & 209 deletions

File tree

frontend/src/Components/GenSec/AchievementsEndorsementTab.jsx

Lines changed: 39 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,7 @@
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";
6+
import { User, Calendar, Award, ExternalLink } from "lucide-react";
137
import api from "../../utils/api";
148

159
const AchievementsEndorsementTab = ({ skillType }) => {
@@ -19,7 +13,6 @@ const AchievementsEndorsementTab = ({ skillType }) => {
1913
const [verifying, setVerifying] = useState(new Set());
2014
const [error, setError] = useState("");
2115

22-
// API call to fetch unendorsed achievements
2316
const fetchUnverifiedAchievements = async (type) => {
2417
try {
2518
const res = await api.get(`/api/achievements/unendorsed/${type}`);
@@ -31,7 +24,7 @@ const AchievementsEndorsementTab = ({ skillType }) => {
3124
throw new Error(message);
3225
}
3326
};
34-
// API call to verify an achievement
27+
3528
const verifyAchievement = async (id) => {
3629
try {
3730
const res = await api.patch(`/api/achievements/verify/${id}`, {
@@ -111,78 +104,59 @@ const AchievementsEndorsementTab = ({ skillType }) => {
111104
);
112105
}
113106

114-
console.log("Achievements:", achievements);
115107
return (
116108
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
117109
{achievements.map((ach) => (
118110
<div
119111
key={ach._id}
120-
className="bg-pink-50 border border-pink-100 rounded-lg p-4 hover:shadow-md transition-shadow duration-200"
112+
className="bg-[#FDFAE2] border border-yellow-200 rounded-xl p-4 flex flex-col h-full shadow-sm transition-shadow hover:shadow-md"
121113
>
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">
114+
<div className="flex-grow">
115+
<h3 className="text-lg font-bold text-gray-800">{ach.title}</h3>
116+
<p className="text-xs text-gray-500 mb-3 line-clamp-2">
128117
"{ach.description}"
129118
</p>
130-
</div>
131-
132-
{/* User Information */}
133-
{ach.user_id && (
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>
143-
)}
144119

145-
{/* Event Information */}
146-
{ach.event_id && (
147-
<div className="bg-white rounded-md p-2 mb-2">
148-
<p className="text-sm font-medium text-gray-900">
149-
Event: {ach.event_id.title}
150-
</p>
151-
{ach.event_id.description && (
152-
<p className="text-xs text-gray-600 mt-1">
153-
{ach.event_id.description}
154-
</p>
120+
<div className="space-y-2 text-sm text-gray-700 border-t border-yellow-200 pt-3 mt-3">
121+
{ach.user_id && (
122+
<div className="flex items-center gap-2">
123+
<User className="w-4 h-4 text-gray-500 flex-shrink-0" />
124+
<span>{ach.user_id.personal_info?.name}</span>
125+
</div>
126+
)}
127+
{ach.event_id && (
128+
<div className="flex items-center gap-2">
129+
<Award className="w-4 h-4 text-gray-500 flex-shrink-0" />
130+
<span>Event: {ach.event_id.title}</span>
131+
</div>
132+
)}
133+
<div className="flex items-center gap-2">
134+
<Calendar className="w-4 h-4 text-gray-500 flex-shrink-0" />
135+
<span>{format(new Date(ach.date_achieved), "dd MMM yyyy")}</span>
136+
</div>
137+
{ach.certificate_url && (
138+
<div className="flex items-center gap-2">
139+
<ExternalLink className="w-4 h-4 text-gray-500 flex-shrink-0" />
140+
<a
141+
href={ach.certificate_url}
142+
target="_blank"
143+
rel="noopener noreferrer"
144+
className="text-blue-600 hover:underline"
145+
>
146+
View Certificate
147+
</a>
148+
</div>
155149
)}
156150
</div>
157-
)}
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-
)}
176151
</div>
177152

178-
{/* Action Button */}
179-
<div className="flex justify-end pt-2 border-t border-pink-200">
153+
<div className="mt-4">
180154
<button
181155
onClick={() => handleVerify(ach._id)}
182156
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"
157+
className="w-full py-2 text-sm font-bold text-sky-800 bg-sky-100 rounded-lg hover:bg-sky-200 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
184158
>
185-
<span>{verifying.has(ach._id) ? "Endorsing..." : "Endorse"}</span>
159+
{verifying.has(ach._id) ? "Endorsing..." : "Endorse"}
186160
</button>
187161
</div>
188162
</div>
@@ -191,4 +165,4 @@ const AchievementsEndorsementTab = ({ skillType }) => {
191165
);
192166
};
193167

194-
export default AchievementsEndorsementTab;
168+
export default AchievementsEndorsementTab;

frontend/src/Components/GenSec/SkillsEndorsementTab.jsx

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"use client";
22

33
import { useState, useEffect } from "react";
4-
import { ChevronRight, Award, Calendar } from "lucide-react";
4+
import { Award, Calendar, Tag } from "lucide-react";
55
import api from "../../utils/api";
6+
67
const fetchUnendorsedSkills = async (skillType) => {
78
try {
89
const res = await api.get(`/api/skills/unendorsed/${skillType}`);
@@ -24,7 +25,6 @@ const endorseSkill = async (skillId) => {
2425
}
2526
};
2627

27-
// Skill Card Component
2828
const SkillCard = ({ skill, onEndorse, isEndorsing }) => {
2929
const formatDate = (dateString) =>
3030
new Date(dateString).toLocaleDateString("en-US", {
@@ -34,41 +34,34 @@ const SkillCard = ({ skill, onEndorse, isEndorsing }) => {
3434
});
3535

3636
return (
37-
<div className="bg-pink-50 border border-pink-100 rounded-lg p-4 hover:shadow-md transition-shadow duration-200">
38-
{/* Card Header */}
39-
<div className="mb-4">
40-
<h3 className="text-lg font-semibold text-gray-900 mb-2">
41-
{skill.name}
42-
</h3>
43-
<p className="text-sm text-gray-600 mb-2">{skill.category}</p>
37+
<div className="bg-[#FDFAE2] border border-yellow-200 rounded-xl p-4 flex flex-col h-full shadow-sm transition-shadow hover:shadow-md">
38+
<div className="flex-grow">
39+
<h3 className="text-lg font-bold text-gray-800">{skill.name}</h3>
4440
{skill.description && (
45-
<p className="text-sm text-gray-600 mb-3 line-clamp-2">
46-
"{skill.description}"
41+
<p className="text-xs text-gray-500 mb-3 line-clamp-2">
42+
{skill.description}
4743
</p>
4844
)}
49-
</div>
5045

51-
{/* Skill ID and Date */}
52-
<div className="flex items-center justify-between mb-2">
53-
{skill.skill_id && (
54-
<span className="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full font-medium">
55-
ID: {skill.skill_id}
56-
</span>
57-
)}
58-
<div className="flex items-center gap-2 text-sm text-gray-600">
59-
<Calendar className="w-4 h-4" />
60-
<span>{formatDate(skill.created_at)}</span>
46+
<div className="space-y-2 text-sm text-gray-700 border-t border-yellow-200 pt-3 mt-3">
47+
<div className="flex items-center gap-2">
48+
<Tag className="w-4 h-4 text-gray-500 flex-shrink-0" />
49+
<span>Category: {skill.category}</span>
50+
</div>
51+
<div className="flex items-center gap-2">
52+
<Calendar className="w-4 h-4 text-gray-500 flex-shrink-0" />
53+
<span>Submitted: {formatDate(skill.created_at)}</span>
54+
</div>
6155
</div>
6256
</div>
6357

64-
{/* Action Button */}
65-
<div className="flex justify-end pt-2 border-t border-pink-200">
58+
<div className="mt-4">
6659
<button
6760
onClick={() => onEndorse(skill._id)}
6861
disabled={isEndorsing}
69-
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"
62+
className="w-full py-2 text-sm font-bold text-sky-800 bg-sky-100 rounded-lg hover:bg-sky-200 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
7063
>
71-
<span>{isEndorsing ? "Endorsing..." : "Endorse"}</span>
64+
{isEndorsing ? "Endorsing..." : "Endorse"}
7265
</button>
7366
</div>
7467
</div>
@@ -102,17 +95,8 @@ const SkillsEndorsementTab = ({ skillType }) => {
10295
const handleEndorse = async (skillId) => {
10396
try {
10497
setEndorsingSkills((prev) => new Set([...prev, skillId]));
105-
106-
// Make the API call
10798
await endorseSkill(skillId);
108-
109-
// --- FIX START ---
110-
// Removed the `if (result.success)` condition.
111-
// Now, we update the state to remove the endorsed skill from the list
112-
// as long as the API call above doesn't fail.
11399
setSkills((prev) => prev.filter((s) => s._id !== skillId));
114-
// --- FIX END ---
115-
116100
} catch (err) {
117101
console.error("Error endorsing skill:", err);
118102
setError("Failed to endorse skill. Please try again.");
@@ -124,7 +108,7 @@ const SkillsEndorsementTab = ({ skillType }) => {
124108
});
125109
}
126110
};
127-
111+
128112
if (loading) {
129113
return (
130114
<div className="flex justify-center items-center py-12">

0 commit comments

Comments
 (0)