fix: persist like counts across refreshes and remove social links card from non-RAISE centers

This commit is contained in:
Amudieshwar
2026-08-19 08:52:20 +05:30
parent 7cd28fa974
commit 774ae7e7ae

View File

@@ -150,10 +150,37 @@ export default function Events() {
return { totalCount: CLUBS_DATA.length, centersCount: centers, clubsCount: clubs };
}, []);
// ─── Database-Backed Interactive Like System ─────────────────────────────
// ─── Database & LocalStorage Persisted Interactive Like System ───────────
const loadSavedLikesMap = (): Record<string, number> => {
const initialMap: Record<string, number> = {};
CLUBS_DATA.forEach((c) => {
initialMap[c.id] = 0;
});
try {
const savedCounts = localStorage.getItem('rit_freshers_likes_count_v3');
if (savedCounts) {
const parsed = JSON.parse(savedCounts);
Object.assign(initialMap, parsed);
}
} catch {}
try {
const savedLikedList = localStorage.getItem('rit_freshers_liked_clubs_v3');
if (savedLikedList) {
const likedArray: string[] = JSON.parse(savedLikedList);
likedArray.forEach((id) => {
if (!initialMap[id] || initialMap[id] < 1) {
initialMap[id] = 1;
}
});
}
} catch {}
return initialMap;
};
const [likedClubs, setLikedClubs] = useState<Set<string>>(() => {
try {
localStorage.removeItem('rit_freshers_liked_clubs');
const saved = localStorage.getItem('rit_freshers_liked_clubs_v3');
return saved ? new Set(JSON.parse(saved)) : new Set();
} catch {
@@ -161,38 +188,38 @@ export default function Events() {
}
});
const [likesMap, setLikesMap] = useState<Record<string, number>>(() => {
const initialMap: Record<string, number> = {};
CLUBS_DATA.forEach((c) => {
initialMap[c.id] = 0;
});
return initialMap;
});
const [likesMap, setLikesMap] = useState<Record<string, number>>(loadSavedLikesMap);
// Sync likes with database backend on mount and when user identity changes
useEffect(() => {
let isMounted = true;
async function syncWithDatabase() {
// Fetch total like counts for all clubs from database
// 1. Fetch total like counts for all clubs from database
const dbLikesMap = await fetchClubLikes();
if (isMounted && Object.keys(dbLikesMap).length > 0) {
setLikesMap((prev) => {
const merged = { ...prev };
Object.entries(dbLikesMap).forEach(([id, count]) => {
merged[id] = count;
merged[id] = Math.max(merged[id] || 0, Number(count) || 0);
});
try {
localStorage.setItem('rit_freshers_likes_count_v3', JSON.stringify(merged));
} catch {}
return merged;
});
}
// Fetch user's liked clubs from database
// 2. Fetch user's liked clubs from database
const userLikedList = await fetchUserLikedClubs(userIdentifier);
if (isMounted && userLikedList.length > 0) {
setLikedClubs(new Set(userLikedList));
try {
localStorage.setItem('rit_freshers_liked_clubs_v3', JSON.stringify(userLikedList));
} catch {}
if (isMounted && userLikedList && userLikedList.length > 0) {
setLikedClubs((prev) => {
const mergedSet = new Set([...Array.from(prev), ...userLikedList]);
try {
localStorage.setItem('rit_freshers_liked_clubs_v3', JSON.stringify(Array.from(mergedSet)));
} catch {}
return mergedSet;
});
}
}
@@ -206,32 +233,53 @@ export default function Events() {
const toggleLike = async (clubId: string) => {
const isCurrentlyLiked = likedClubs.has(clubId);
const next = new Set(likedClubs);
let newCount = likesMap[clubId] || 0;
// Optimistic UI update
if (isCurrentlyLiked) {
next.delete(clubId);
setLikesMap((l) => ({ ...l, [clubId]: Math.max(0, (l[clubId] || 1) - 1) }));
newCount = Math.max(0, newCount - 1);
} else {
next.add(clubId);
setLikesMap((l) => ({ ...l, [clubId]: (l[clubId] || 0) + 1 }));
newCount = newCount + 1;
}
const updatedLikesMap = { ...likesMap, [clubId]: newCount };
setLikedClubs(next);
setLikesMap(updatedLikesMap);
try {
localStorage.setItem('rit_freshers_liked_clubs_v3', JSON.stringify(Array.from(next)));
localStorage.setItem('rit_freshers_likes_count_v3', JSON.stringify(updatedLikesMap));
} catch {}
// Persist like directly in PostgreSQL database backend
// Persist like directly in PostgreSQL database backend if available
const dbResult = await toggleClubLikeInDb(clubId, userIdentifier);
if (dbResult) {
setLikesMap((l) => ({ ...l, [clubId]: dbResult.count }));
setLikesMap((l) => {
const freshMap = { ...l, [clubId]: dbResult.count };
try {
localStorage.setItem('rit_freshers_likes_count_v3', JSON.stringify(freshMap));
} catch {}
return freshMap;
});
if (dbResult.liked) {
setLikedClubs((prev) => new Set([...prev, clubId]));
setLikedClubs((prev) => {
const s = new Set([...Array.from(prev), clubId]);
try {
localStorage.setItem('rit_freshers_liked_clubs_v3', JSON.stringify(Array.from(s)));
} catch {}
return s;
});
} else {
setLikedClubs((prev) => {
const updated = new Set(prev);
updated.delete(clubId);
return updated;
const s = new Set(prev);
s.delete(clubId);
try {
localStorage.setItem('rit_freshers_liked_clubs_v3', JSON.stringify(Array.from(s)));
} catch {}
return s;
});
}
}
@@ -929,15 +977,14 @@ export default function Events() {
{/* Social & Community Links */}
{(() => {
const isRaiseIncubator = selectedClub.id === 'center_raise' || selectedClub.socialLinks?.website === '/raise';
const hasSocials = Boolean(
const hasSpecificSocials = Boolean(
selectedClub.socialLinks?.instagram ||
selectedClub.socialLinks?.linkedin ||
selectedClub.socialLinks?.whatsapp ||
selectedClub.socialLinks?.youtube ||
selectedClub.socialLinks?.website
selectedClub.socialLinks?.youtube
);
if (!hasSocials) return null;
if (!isRaiseIncubator && !hasSpecificSocials) return null;
return (
<div className="mb-6 bg-orange-50/60 border border-orange-200/80 rounded-2xl p-4">
@@ -950,9 +997,9 @@ export default function Events() {
</div>
<div className="grid grid-cols-2 gap-2.5">
{isRaiseIncubator && selectedClub.socialLinks?.website && (
{isRaiseIncubator && (
<Link
to={selectedClub.socialLinks.website}
to="/raise"
onClick={() => setSelectedClub(null)}
className="flex items-center gap-2 p-2.5 rounded-xl bg-gradient-to-r from-[#EC4899] via-[#F43F5E] to-[#E11D48] text-white hover:from-pink-600 hover:to-rose-600 transition-all text-xs font-bold shadow-xs col-span-2 justify-center"
>
@@ -961,69 +1008,57 @@ export default function Events() {
</Link>
)}
{!isRaiseIncubator && selectedClub.socialLinks?.website && selectedClub.socialLinks.website.startsWith('http') && (
{!isRaiseIncubator && selectedClub.socialLinks?.instagram && (
<a
href={selectedClub.socialLinks.website}
href={selectedClub.socialLinks.instagram}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 p-2.5 rounded-xl bg-white border border-slate-200 hover:border-orange-500 hover:text-orange-600 transition-all text-xs font-medium text-slate-700"
className="flex items-center gap-2 p-2.5 rounded-xl bg-white border border-slate-200 hover:border-pink-500 hover:text-pink-600 transition-all text-xs font-medium text-slate-700"
>
<Globe className="w-4 h-4 text-orange-500 shrink-0" />
<span className="truncate">Official Website</span>
<InstagramIcon className="w-4 h-4 text-pink-500 shrink-0" />
<span className="truncate">Instagram</span>
</a>
)}
{selectedClub.socialLinks?.instagram && (
<a
href={selectedClub.socialLinks.instagram}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 p-2.5 rounded-xl bg-white border border-slate-200 hover:border-pink-500 hover:text-pink-600 transition-all text-xs font-medium text-slate-700"
>
<InstagramIcon className="w-4 h-4 text-pink-500 shrink-0" />
<span className="truncate">Instagram</span>
</a>
)}
{!isRaiseIncubator && selectedClub.socialLinks?.linkedin && (
<a
href={selectedClub.socialLinks.linkedin}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 p-2.5 rounded-xl bg-white border border-slate-200 hover:border-blue-600 hover:text-blue-600 transition-all text-xs font-medium text-slate-700"
>
<LinkedinIcon className="w-4 h-4 text-blue-600 shrink-0" />
<span className="truncate">LinkedIn</span>
</a>
)}
{selectedClub.socialLinks?.linkedin && (
<a
href={selectedClub.socialLinks.linkedin}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 p-2.5 rounded-xl bg-white border border-slate-200 hover:border-blue-600 hover:text-blue-600 transition-all text-xs font-medium text-slate-700"
>
<LinkedinIcon className="w-4 h-4 text-blue-600 shrink-0" />
<span className="truncate">LinkedIn</span>
</a>
)}
{!isRaiseIncubator && selectedClub.socialLinks?.whatsapp && (
<a
href={selectedClub.socialLinks.whatsapp}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 p-2.5 rounded-xl bg-white border border-slate-200 hover:border-emerald-500 hover:text-emerald-600 transition-all text-xs font-medium text-slate-700"
>
<MessageCircle className="w-4 h-4 text-emerald-500 shrink-0" />
<span className="truncate">WhatsApp Group</span>
</a>
)}
{selectedClub.socialLinks?.whatsapp && (
<a
href={selectedClub.socialLinks.whatsapp}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 p-2.5 rounded-xl bg-white border border-slate-200 hover:border-emerald-500 hover:text-emerald-600 transition-all text-xs font-medium text-slate-700"
>
<MessageCircle className="w-4 h-4 text-emerald-500 shrink-0" />
<span className="truncate">WhatsApp Group</span>
</a>
)}
{selectedClub.socialLinks?.youtube && (
<a
href={selectedClub.socialLinks.youtube}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 p-2.5 rounded-xl bg-white border border-slate-200 hover:border-red-600 hover:text-red-600 transition-all text-xs font-medium text-slate-700"
>
<YoutubeIcon className="w-4 h-4 text-red-600 shrink-0" />
<span className="truncate">YouTube Channel</span>
</a>
)}
{!isRaiseIncubator && selectedClub.socialLinks?.youtube && (
<a
href={selectedClub.socialLinks.youtube}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 p-2.5 rounded-xl bg-white border border-slate-200 hover:border-red-600 hover:text-red-600 transition-all text-xs font-medium text-slate-700"
>
<YoutubeIcon className="w-4 h-4 text-red-600 shrink-0" />
<span className="truncate">YouTube Channel</span>
</a>
)}
</div>
</div>
</div>
);
})()}
);
})()}
{/* Close Button */}
<div>