Skip to content

Commit

Permalink
Merge pull request #1490 from 42organization/Feat/#1484-left-pages
Browse files Browse the repository at this point in the history
[Feat] left pages #1484
  • Loading branch information
JeongRon authored Aug 21, 2024
2 parents 6a3c71a + 3f8376c commit ff9fa04
Show file tree
Hide file tree
Showing 21 changed files with 737 additions and 130 deletions.
2 changes: 1 addition & 1 deletion Layout/LayoutProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const LayoutProvider = ({ children }: LayoutProviderProps) => {
// case "admin" :
// return <AdminAppLayout>{children}</AdminAppLayout>;
default:
return <>{children}</>;
return <AgendaAppLayout>{children}</AgendaAppLayout>;
}
};

Expand Down
46 changes: 31 additions & 15 deletions components/agenda/Home/AgendaTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,37 @@ import styles from 'styles/agenda/Home/AgendaTitle.module.scss';
const AgendaTitle = () => {
return (
<div className={styles.agendaTitleContainer}>
<div>AGENDA</div>
<Link href={`/agenda/create`}>
<button className={styles.agendaCreateBtn}>
<div>개최신청</div>
<div className={styles.imageWrapper}>
<Image
src='/image/agenda/ArrowRight.svg'
width={35}
height={35}
alt='Create Agenda'
className={styles.imageBox}
/>
</div>
</button>
</Link>
<div className={styles.agendaTitleButtonContainer}>AGENDA</div>
<div className={styles.agendaTitleButtonContainer}>
<Link href={`/agenda/create`}>
<button className={styles.agendaCreateBtn}>
<div>개최신청</div>
<div className={styles.imageWrapper}>
<Image
src='/image/agenda/ArrowRight.svg'
width={35}
height={35}
alt='Create Agenda'
className={styles.imageBox}
/>
</div>
</button>
</Link>
<Link href={`/agenda/ticket`}>
<button className={styles.agendaCreateBtn}>
<div>티켓 확인하기</div>
<div className={styles.imageWrapper}>
<Image
src='/image/agenda/ArrowRight.svg'
width={35}
height={35}
alt='Create Agenda'
className={styles.imageBox}
/>
</div>
</button>
</Link>
</div>
</div>
);
};
Expand Down
83 changes: 83 additions & 0 deletions components/agenda/Ticket/Ticket.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import Link from 'next/link';
import { instanceInAgenda } from 'utils/axios';
import useFetchGet from 'hooks/agenda/useFetchGet';
import styles from 'styles/agenda/Ticket/Ticket.module.scss';
interface TicketProps {
ticketCount: number;
setupTicket: boolean;
}

const Ticket = ({ type }: { type: string }) => {
const { data } = useFetchGet<TicketProps>('/ticket');
return type === 'page' ? (
<div className={styles.container}>
<h1 className={styles.h1}>내 티켓</h1>
<div className={styles.ticketSection}>
<div className={styles.ticketFrame}>
<h1>{data && data.ticketCount}</h1>
</div>
<h1></h1>
</div>
<div className={styles.section}>
<h3>발급 방법</h3>
<div className={styles.line} />
<p>발급 시작 누르기</p>
<div className={styles.arrowDown} />
<p>
평가 포인트 기부하기
<br />
{`(최대 2개까지 반영)`}
</p>
<div className={styles.arrowDown} />
<p>현재 페이지로 돌아와 발급완료 누르기</p>
</div>
{data && data.setupTicket ? (
<button
className={styles.submitButton}
onClick={() => {
instanceInAgenda.patch('/ticket').then((res) => {
console.log(res);
});
}}
>
발급 완료
</button>
) : (
<button
className={styles.submitButton}
onClick={() => {
instanceInAgenda.post('/ticket').then(() => {
alert('티켓 발급 시작');
location.href = 'https://profile.intra.42.fr/';
});
}}
>
발급 시작
</button>
)}
<Link href='/agenda/ticket/history' style={{ width: '100%' }}>
<button className={styles.logButton}>내역 보기</button>
</Link>
</div>
) : (
<div className={styles.container}>
<h1 className={styles.h1}>내 티켓</h1>
<div
className={styles.ticketSection}
style={{ gap: '2rem', alignItems: 'center' }}
>
<Link href='/agenda/ticket'>
<button className={styles.submitButton}>발급하러가기</button>
</Link>
<div className={styles.ticketSection}>
<div className={styles.ticketFrame}>
<h1>{data && data.ticketCount}</h1>
</div>
<h1></h1>
</div>
</div>
</div>
);
};

export default Ticket;
55 changes: 55 additions & 0 deletions components/agenda/Ticket/TicketHistory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {
TableCell,
TableRow,
Table,
TableHead,
TableBody,
} from '@mui/material';
import { TicketHistoryProps } from 'types/aganda/ticketTypes';
import styles from 'styles/agenda/Ticket/Ticket.module.scss';

const TicketHistory = ({ data }: { data: TicketHistoryProps[] | null }) => {
return (
<div className={styles.container}>
<h1 className={styles.h1}>티켓 발급 내역</h1>
<Table sx={{ minWidth: 340 }} aria-label='simple table'>
<TableHead>
<TableRow>
<TableCell>idx</TableCell>
<TableCell align='center'>발급요청일</TableCell>
<TableCell align='center'>승인여부</TableCell>
<TableCell align='center'>승인일</TableCell>
<TableCell align='center'>사용여부</TableCell>
<TableCell align='center'>사용처</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data &&
data.map((d, index) => {
return (
<TableRow
key={index}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell component='th' scope='row'>
{d.idx}
</TableCell>
<TableCell align='center'>{d.createdAt}</TableCell>
<TableCell align='center'>
{d.approved ? '✔︎' : '✕'}
</TableCell>
<TableCell align='center'>{d.approvedAt}</TableCell>
<TableCell align='center'>{d.isUsed ? '✔︎' : '✕'}</TableCell>
<TableCell align='center'>
{d.usedAt ? d.usedAt : ''}
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
);
};

export default TicketHistory;
114 changes: 114 additions & 0 deletions components/agenda/utils/PageController.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { useEffect, useState } from 'react';
import { AgendaDataProps } from 'types/agenda/agendaDetail/agendaTypes';
import { instanceInAgenda } from 'utils/axios';
import styles from 'styles/agenda/utils/PageController.module.scss';
import AgendaInfo from '../Home/AgendaInfo';

interface PageControllerNavigatorProps {
currentPage: number;
maxPage: number;
onClick: (page: number) => void;
}

const PageControllerNavigator = ({
currentPage,
maxPage,
onClick,
}: PageControllerNavigatorProps) => {
const buttons = [];
for (let i = 0; i < maxPage; i++) {
if (i === currentPage)
buttons.push(
<button key={i} onClick={() => onClick(i)} className={styles.current} />
);
else
buttons.push(
<button key={i} onClick={() => onClick(i)} className={styles.rest} />
);
}
return (
<div className={styles.navContainer}>{buttons.map((button) => button)}</div>
);
};

const PageController = ({
handleNavigation,
}: {
handleNavigation: (path: string) => void;
}) => {
const [current, setCurrent] = useState(0);
const [data, setData] = useState<AgendaDataProps[]>([]);
const max = data.length;

const fetchAgendaList = async () => {
const url = '/list';
const data = await instanceInAgenda
.get(url)
.then((res) => {
return res.data;
})
.catch((error) => {
if (error.view === 403) return [];
else return []; // 에러처리 필요 ERROR
});
return data;
};

useEffect(() => {
fetchAgendaList().then((data) => {
setData(data);
});
}, []);
useEffect(() => {
const interval = setInterval(moveNext, 2000);
return () => clearInterval(interval);
});

function moveNext() {
setCurrent(current + 1 < max ? current + 1 : 0);
}
function movePrev() {
setCurrent(current - 1 >= 0 ? current - 1 : max - 1);
}

return (
<div className={styles.container}>
<button
className={styles.agendaInfoContainer}
onClick={(e) => {
const target = e.target as HTMLElement;
console.log(target);
if (
target.className.includes(styles.moveButton) ||
target.closest(styles.moveButton)
)
return;
data.length && data[current]
? handleNavigation('/agenda/' + data[current].agendaKey)
: null;
}}
>
<button
onClick={movePrev}
className={`${styles.moveButton} ${styles.moveButtonPrev}`}
>
<div className={styles.prev} />
</button>
<button
className={`${styles.moveButton} ${styles.moveButtonNext}`}
onClick={moveNext}
>
<div className={styles.next} />
</button>
<AgendaInfo agendaInfo={data[current]} key={current || 0} />
</button>
<PageControllerNavigator
currentPage={current}
maxPage={data.length}
onClick={setCurrent}
/>
</div>
);
};

export default PageController;
58 changes: 58 additions & 0 deletions hooks/agenda/usePageNation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useEffect, useRef, useState } from 'react';
import { instanceInAgenda } from 'utils/axios';

const usePageNation = <T>({
url,
size,
useIdx,
}: {
url: string;
size?: number; // 페이지 사이즈
useIdx?: boolean; // 인덱싱 추가 여부 : 해당 데이터 타입에 idx?: number; 추가 필요
}) => {
if (!size) size = 20;
const getData = async (page: number) => {
const res = await instanceInAgenda.get(`${url}?page=${page}&size=${size}`);
res.data.totalSize ? res.data.totalSize : 0;
res.data.content ? res.data.content : [];
if (useIdx) {
res.data.content = res.data.content.map((c: T, idx: number) => {
const temp = c as T & { idx: number };
temp.idx = idx + 1 + size * (page - 1);
return temp;
});
}
return res.data as { totalSize: number; content: T[] };
};
// const data = getData(0);
const [currentPage, setCurrentPage] = useState<number>(1);
const [content, setContent] = useState<T[] | null>(null);
const totalPages = useRef(1);

const pageChangeHandler = async (pageNumber: number) => {
if (pageNumber < 1 || pageNumber > totalPages.current) return;
await getData(pageNumber).then((res) => {
setCurrentPage(pageNumber);
setContent(res.content);
});
};

useEffect(() => {
const fetchData = async () => {
const data = await getData(currentPage);
totalPages.current = Math.ceil(data.totalSize / size);
setContent(data.content);
};
fetchData();
});

const PagaNationElementProps = {
curPage: currentPage,
totalPages: totalPages.current,
pageChangeHandler: pageChangeHandler,
};

return { content, PagaNationElementProps };
};

export default usePageNation;
Loading

0 comments on commit ff9fa04

Please sign in to comment.