diff --git a/components/clubs/ClubDetail.tsx b/components/clubs/ClubDetail.tsx index 9aa3fce..80fed7e 100644 --- a/components/clubs/ClubDetail.tsx +++ b/components/clubs/ClubDetail.tsx @@ -1,6 +1,7 @@ 'use client'; import Link from 'next/link'; +import { useRouter } from 'next/navigation'; import { documentToReactComponents } from '@contentful/rich-text-react-renderer'; import { BLOCKS, type TopLevelBlock } from '@contentful/rich-text-types'; import { ArrowLeft, ArrowUpRight } from 'lucide-react'; @@ -11,7 +12,8 @@ import { contentfulImage } from '@/lib/contentful-image'; import ClubLogo from './ClubLogo'; import { useStore } from '@/store/useStore'; -import { Fragment, useEffect } from 'react'; +import { Fragment, useEffect, type MouseEvent } from 'react'; +import { readClubsReturn } from '@/lib/clubs-return'; interface ClubDetailProps { club: ClubItems; @@ -162,6 +164,7 @@ const JoinCard = ({ clubLink, recruiting }: JoinCardProps) => ( const ClubDetail: React.FC = ({ club }) => { const { clubName, clubLogo, clubType, clubLink, description, isActivelyRecruitingMembers, aboutclub, sys } = club; const { addToRecentlyViewed } = useStore(); + const router = useRouter(); useEffect(() => { if (club && sys.id) { @@ -169,6 +172,12 @@ const ClubDetail: React.FC = ({ club }) => { } }, [club, sys.id, addToRecentlyViewed]); + const backToClubs = (event: MouseEvent) => { + if (readClubsReturn()?.clubId !== sys.id) return; + event.preventDefault(); + router.back(); + }; + const assets = aboutclub?.links?.assets?.block ?? []; const options = proseRichTextOptions(assets); const findAsset = (id: string) => assets.find((asset) => asset.sys.id === id); @@ -180,6 +189,7 @@ const ClubDetail: React.FC = ({ club }) => {
diff --git a/components/clubs/ClubsList.tsx b/components/clubs/ClubsList.tsx index a2372f8..4ef4714 100644 --- a/components/clubs/ClubsList.tsx +++ b/components/clubs/ClubsList.tsx @@ -1,5 +1,5 @@ 'use client'; -import { useEffect, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import Container from '@/components/custom/Container'; import { Search } from 'lucide-react'; import Image from 'next/image'; @@ -15,6 +15,7 @@ import EmptyState from '@/components/events/EmptyState'; import { Users } from 'lucide-react'; import { CLUB_TYPES, matchesClubType } from '@/lib/data/taxonomy' +import { clearClubsReturn, readClubsReturn, rememberClubsReturn } from '@/lib/clubs-return' interface ClubsListProps { clubs: ClubItems[]; } @@ -29,6 +30,26 @@ const ClubsList = ({ clubs }: ClubsListProps) => { ] const [filteredClubs, setFilteredClubs] = useState(clubs || []); + const pendingScroll = useRef(null); + + useEffect(() => { + const saved = readClubsReturn(); + clearClubsReturn(); + if (!saved) return; + pendingScroll.current = saved.scrollY; + setCurrentId(saved.tab); + setSearch(saved.search); + }, []); + + useEffect(() => { + if (pendingScroll.current === null) return; + const y = pendingScroll.current; + pendingScroll.current = null; + requestAnimationFrame(() => window.scrollTo({ top: y, behavior: 'instant' })); + }, [filteredClubs]); + + const openClub = (clubId: string) => + rememberClubsReturn({ clubId, scrollY: window.scrollY, tab: currentId, search }); useEffect(() => { let result = clubs || []; @@ -100,7 +121,7 @@ const ClubsList = ({ clubs }: ClubsListProps) => {
{filteredClubs.filter((club) => club.isFeatured)?.map((club, index) => ( - + openClub(club.sys.id)} className='p-6 shadow-lg rounded-xl h-[454px] flex flex-col justify-between'> {

Other Communities

{filteredClubs?.filter(club => !club.isFeatured).map((club, index) => ( - + openClub(club.sys.id)} className='bg-[#F9FAFB] p-6 rounded-xl flex flex-col gap-4 w-full'>
diff --git a/lib/clubs-return.ts b/lib/clubs-return.ts new file mode 100644 index 0000000..32406a1 --- /dev/null +++ b/lib/clubs-return.ts @@ -0,0 +1,33 @@ +const KEY = "clubs-return"; +const MAX_AGE_MS = 30 * 60 * 1000; + +export interface ClubsReturn { + clubId: string; + scrollY: number; + tab: number; + search: string; + at: number; +} + +export function rememberClubsReturn(value: Omit) { + try { + sessionStorage.setItem(KEY, JSON.stringify({ ...value, at: Date.now() })); + } catch {} +} + +export function readClubsReturn(): ClubsReturn | null { + try { + const raw = sessionStorage.getItem(KEY); + if (!raw) return null; + const value = JSON.parse(raw) as ClubsReturn; + return Date.now() - value.at < MAX_AGE_MS ? value : null; + } catch { + return null; + } +} + +export function clearClubsReturn() { + try { + sessionStorage.removeItem(KEY); + } catch {} +}