처음에 이 부분의 헤더 작업을 맡게 되었음.
(현재는 북클럽 선택이 모달로 바뀌었지만, 처음에는 select 디자인을 받았음 -> 그래서 select 태그로 작업)
하나의 app 폴더를 만들어서 그 안에서 해결
/myclubinfo url하나로 useState활용해서 탭을 구현했다
'use client';
import React from 'react';
import { getClubInfo, getUserId } from '@/utils/userAPIs/authAPI';
import { getUserClubIds } from '@/utils/userAPIs/authAPI';
import { useState } from 'react';
import { useEffect } from 'react';
import HomeTab from '@/components/myclubinfo2/HomeTab';
import Board from '@/components/myclubinfo/Board';
import { Tables } from '@/lib/types/supabase';
import SentenceStorage from '@/components/myclubinfo2/SentenceStorage';
import NonMyClub from '@/components/myclubinfo2/NonMyClub';
type Clubs = Tables<'clubs'>;
const MyClubInfo = () => {
const [loading, setLoading] = useState(true);
const [clubInfo, setClubInfo] = useState<Clubs[]>([]);
const [userId, setUserId] = useState<string | null>(null);
const [selectedTab, setSelectedTab] = useState('home');
const [selectedClubId, setSelectedClubId] = useState<string>('');
useEffect(() => {
const fetchData = async () => {
try {
const fetchedUserId = await getUserId();
setUserId(fetchedUserId);
if (fetchedUserId) {
const fetchedClubIds = await getUserClubIds(fetchedUserId);
const fetchClubInfo = await getClubInfo(fetchedClubIds);
setClubInfo(fetchClubInfo);
if (fetchedClubIds.length > 0) {
setSelectedClubId(fetchedClubIds[0]);
}
}
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
}, []);
const handleClubChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedClubId(event.target.value);
};
const handleTabChange = (tab: string) => {
setSelectedTab(tab);
};
const getSelectClasses = () => {
if (clubInfo.length <= 1) {
return 'appearance-none w-[200px] font-bold p-2 text-lg';
}
return ' p-2 w-[200px] font-bold';
};
const renderSelectedTab = () => {
const selectedClub = clubInfo.find((club) => club.id === selectedClubId);
if (!selectedClub) {
return <NonMyClub />;
}
switch (
selectedTab //quiz tab 추가해야함.
) {
case 'home':
return <HomeTab club={selectedClub} />;
case 'sentenceStorage':
return <SentenceStorage clubId={selectedClubId} userId={userId} />;
case 'board':
return <Board club={selectedClub} />;
default:
return null;
}
};
return (
<div>
<div className='sticky top-0 left-0 right-0 z-10 bg-white flex flex-col justify-between'>
{/* 북클럽 셀렉트 박스 */}
<select
value={selectedClubId || ''}
onChange={handleClubChange}
className={getSelectClasses()}
// disabled={clubInfo.length <= 1}
>
{clubInfo.length === 0 && (
<option value='' className='w-[200px]'>
내 북클럽
</option>
)}
{clubInfo.map((club) => (
<option key={club.id} value={club.id} className='w-[200px]'>
{club.name}
</option>
))}
</select>
{/* 탭 버튼들 */}
<div className='flex flex-row justify-between w-full border-b-2 border-gray-200 font-bold'>
<button
className={`flex-1 px-4 py-2 focus:outline-none ${
selectedTab === 'home' ? ' border-b-2 border-black' : ''
}`}
onClick={() => handleTabChange('home')}>
홈
</button>
<button
className={`flex-1 px-4 py-2 focus:outline-none ${
selectedTab === 'sentenceStorage' ? 'border-b-2 border-black' : ''
}`}
onClick={() => handleTabChange('sentenceStorage')}>
문장 저장소
</button>
<button
className={`flex-1 px-4 py-2 focus:outline-none ${
selectedTab === 'board' ? 'border-b-2 border-black' : ''
}`}
onClick={() => handleTabChange('board')}>
자유 게시판
</button>
</div>
</div>
{/* 탭 컨텐츠 */}
<div>{renderSelectedTab()}</div>
</div>
);
};
export default MyClubInfo;
선택한 클럽을 state로 관리하기 때문에 이 안에서 renderSelectedTab으로 관리해야했다.
'use client';
import NonMyClub from '@/components/my-clubs/info/NonMyClub';
import { Tables } from '@/lib/types/supabase';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';
import useMyClubInfo from '@/hooks/info/useMyClubInfo';
import Image from 'next/image';
type Clubs = Tables<'clubs'>;
import Animation from '@/components/common/LoadingAnimation';
type Props = {};
const Page = () => {
// TODO: 내 북클럽 찾아서 첫번째 녀석으로 리다이렉션
const router = useRouter();
const { clubs, isLoading } = useMyClubInfo();
const nonArchivedClubs = clubs.filter((club) => !club.archive);
const club = nonArchivedClubs[0];
useEffect(() => {
if (club) {
router.push(`/my-clubs/${club.id}/info`);
}
}, [club, router]);
if (isLoading) {
return (
<div className='h-screen flex justify-center items-center align-middle '>
<div className='w-[250px]'>
<Animation />
</div>
</div>
);
}
if (!club) {
return (
<>
<div className='flex items-center h-[56px] '>
<p className='px-4 text-[22px] font-bold text-[#292929]'>내 북클럽</p>
</div>
<div className='border-b-2 h-[40px] flex'>
<div className='flex-1 text-center py-2 border-gray-200'>
<span className='text-[16px] text-[#3A3B42] text-opacity-50'>
정보
</span>
</div>
<div className='flex-1 text-center py-2 border-gray-200'>
<span className='text-[16px] text-[#3A3B42] text-opacity-50'>
문장 저장소
</span>
</div>
<div className='flex-1 text-center py-2 border-gray-200'>
<span className='text-[16px] text-[#3A3B42] text-opacity-50'>
퀴즈
</span>
</div>
<div className='flex-1 text-center py-2'>
<span className='text-[16px] text-[#3A3B42] text-opacity-50'>
자유 게시판
</span>
</div>
</div>
<NonMyClub />
</>
);
}
return null;
};
export default Page;
단순하게 클럽들 가져와서 진행중인 클럽중에 첫번째 선택해서 info 탭으로 보내버림
그리고 헤더탭은 Layout으로 my-clubs에 항상 있을 수 있게 했다!
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import React from 'react';
import ClubSelector from './ClubSelector';
import useMyClubInfo from '@/hooks/info/useMyClubInfo';
import Animation from '@/components/common/LoadingAnimation';
type Props = {
children: React.ReactNode;
params: {
clubId: string;
};
};
const Layout = ({ children, params }: Props) => {
const pathname = usePathname();
const isSelected = (path: string) => pathname.includes(path);
const { clubs, isLoading } = useMyClubInfo();
if (isLoading) {
return (
<div className='h-screen flex justify-center items-center align-middle '>
<div className='w-[250px]'>
<Animation />
</div>
</div>
);
}
return (
<div>
<div className='sticky top-0 left-0 right-0 z-10 bg-white flex flex-col justify-between'>
{/* 북클럽 셀렉트 박스 */}
<div className='relative inline-block'>
<ClubSelector clubs={clubs} currentClubId={params.clubId} />
</div>
<div className='flex flex-row justify-between w-full font-bold'>
<Link
prefetch={true}
href={`/my-clubs/${params.clubId}/info`}
className={`flex flex-1 px-2 py-2 focus:outline-none justify-center ${
isSelected('info')
? 'border-b-2 border-[#3A3B42] text-[#3A3B42]'
: 'border-b-2 border-[#DBE3EB] text-[#3A3B42] opacity-50 font-medium'
}`}>
<span>정보</span>
</Link>
<Link
prefetch={true}
href={`/my-clubs/${params.clubId}/sentences`}
className={`flex flex-1 px-2 py-2 focus:outline-none justify-center ${
isSelected('sentences')
? 'border-b-2 border-[#3A3B42] text-[#3A3B42]'
: 'border-b-2 border-[#DBE3EB] text-[#3A3B42] opacity-50 font-medium'
}`}>
<span>문장 저장소</span>
</Link>
<Link
prefetch={true}
href={`/my-clubs/${params.clubId}/quizzes`}
className={`flex flex-1 px-2 py-2 focus:outline-none justify-center ${
isSelected('quizzes')
? 'border-b-2 border-[#3A3B42] text-[#3A3B42]'
: 'border-b-2 border-[#DBE3EB] text-[#3A3B42] opacity-50 font-medium'
}`}>
<span>퀴즈</span>
</Link>
<Link
prefetch={true}
href={`/my-clubs/${params.clubId}/posts`}
className={`flex flex-1 px-2 py-2 focus:outline-none justify-center ${
isSelected('posts')
? 'border-b-2 border-[#3A3B42] text-[#3A3B42]'
: 'border-b-2 border-[#DBE3EB] text-[#3A3B42] opacity-50 font-medium'
}`}>
<span>자유 게시판</span>
</Link>
</div>
</div>
<div>
{/* 탭 컨텐츠 */}
{children}
</div>
</div>
);
};
export default Layout;
북클럽을 선택하는 ClubSelector부분에서는 생각할 것들이 많았다.
1. 내 북클럽들 중에 진행중인 것이 있고, 종료인 것이 있다. (애초에 진행중인것만 가져올수가 없었던게, 마이페이지에서 종료된 북클럽도 누르면 이동할수있게 해야했기 때문!)
2. 북클럽선택 모달에는 진행중인 북클럽 목록들만 나와야했다.(가져오는 데이터에는 진행중,종료가 다 있음)
북클럽이 한개이면 화살표가 생기지 않고, 두개이상부터 화살표가 생겨야했다. 또한 북클럽 한개이면 셀렉트바 눌러도 모달이 뜨면 안됐다.
3. 마이페이지에서 종료된 북클럽을 눌러서 /my-clubs/[종료된 북클럽아이디]/info로 넘어오면, 색을 회색처리하고, 종료된 북클럽으로 들어가면 진행중북클럽이 여러개라도 셀렉트 모달이 나오면 안됐다.그니까 셀렉트바가 눌리면 안됐다!
'use client';
import { IoIosArrowDown } from 'react-icons/io';
import { useParams, useRouter } from 'next/navigation';
import React from 'react';
import ResignModal from '@/components/my-clubs/info/ResignModal';
import { useState } from 'react';
import SelectModal from '@/components/my-clubs/info/SelectModal';
type Props = {
clubs: { id: string; name: string; archive: string }[];
currentClubId: string;
};
const ClubSelector = ({ clubs, currentClubId }: Props) => {
const router = useRouter();
const [resignModalOpen, setResignModalOpen] = useState(false); // ResignModal 상태 추가
const [selectModalOpen, setSelectModalOpen] = useState(false);
const ActiveClubs = clubs.filter((club) => !club.archive);
const nonActiveClub = !ActiveClubs.map((club) => club.id).includes(
currentClubId
);
const currentClub = clubs.find((club) => club.id === currentClubId);
const handleClubSelect = (clubId: string) => {
router.push(`/my-clubs/${clubId}/info`);
setSelectModalOpen(false);
};
if (!clubs || clubs.length === 0) {
return <div className='h-[49px]'></div>;
}
return (
<div className='font-bold text-[22px] whitespace-nowrap '>
<div className='px-4 py-2 flex max-w-[350px] '>
<div
className='flex flex-row items-center overflow-hidden'
onClick={() => {
//진행중클럽이 1개이상이여도 현재클럽이 종료되었으면 모달 안뜨게함
if (ActiveClubs.length > 1 && !nonActiveClub) {
setSelectModalOpen(true);
}
}}>
<span
className={`font-bold truncate cursor-pointer ${
currentClub && currentClub.archive ? 'text-fontGray' : ''
}`}>
{currentClub?.name}
</span>
{
//종료된거 눌렀을때 어캐할지 정해야함. 종료된 북클럽이면 진행중인 클럽이 1개 이상이어도 화살표안뜨게함.
!nonActiveClub && ActiveClubs.length > 1 && (
<div className='w-5 h-5 ml-1'>
<IoIosArrowDown />
</div>
)
}
</div>
</div>
{!nonActiveClub && (
<div
className='absolute top-0 right-0 h-full flex items-center mr-2 cursor-pointer'
onClick={() => {
setResignModalOpen(true);
}}>
<svg
width='22'
height='22'
viewBox='0 0 22 22'
fill='none'
xmlns='http://www.w3.org/2000/svg'>
<circle cx='11' cy='5' r='2' fill='#8A9DB3' />
<circle cx='11' cy='11' r='2' fill='#8A9DB3' />
<circle cx='11' cy='17' r='2' fill='#8A9DB3' />
</svg>
</div>
)}
<ResignModal
clubId={currentClubId}
isModal={resignModalOpen}
onClose={() => {
setResignModalOpen(false);
}}
/>
<SelectModal
isModal={selectModalOpen}
onClose={() => {
setSelectModalOpen(false);
}}
clubs={ActiveClubs}
currentClubId={currentClubId}
onSelectClub={handleClubSelect}
/>
</div>
);
};
export default ClubSelector;
생각할것들이 많아서 다 끝났나????? 해도 계속 이러면안되는데.. 이런것들이 많이 생겼다...
그래도 만들고 나니까 디자인도 이쁘고 맘에들어서 기분 좋았당 ㅎㅎ