Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] left pages #1484 #1490

Merged
merged 22 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
caac3df
feat: index ui
cweedlee Aug 19, 2024
a6feeab
feat: pageController ui
cweedlee Aug 19, 2024
091f092
feat: api μ—°κ²° 및 μˆ˜μ •
cweedlee Aug 19, 2024
2e35a78
fix: ui 및 λ¦¬λ‹€μ΄λ ‰μ…˜
cweedlee Aug 19, 2024
1ff71bc
fix: 메인 νŽ˜μ΄μ§€ 색 및 ui
cweedlee Aug 19, 2024
4a58021
feat: agena λ°”λ‘œκ°€κΈ° 생성
cweedlee Aug 19, 2024
a190232
fix: agendaList λ‚΄λΆ€ width 잘λͺ» μˆ˜μ •ν•¨
cweedlee Aug 19, 2024
899bc5b
feat: ticket page UI
cweedlee Aug 19, 2024
da86508
feat: profile intraid λ°›μ•„μ˜€λ„λ‘ μˆ˜μ •
cweedlee Aug 19, 2024
1fb9f18
feat: μ»΄ν¬λ„ŒνŠΈ ui 및 ν‹°μΌ“λ°œκΈ‰ api μ—°κ²°
cweedlee Aug 20, 2024
95f02e8
feat: ν‹°μΌ“ νžˆμŠ€ν† λ¦¬ 쑰회
cweedlee Aug 20, 2024
9632c9e
feat: 메인 리슀트 티켓확인 μΆ”κ°€
cweedlee Aug 20, 2024
06fcba3
style: λ§ˆμ΄μ•„μ  λ‹€ μš°μ •λ ¬
cweedlee Aug 20, 2024
3e28f36
feat: ν‹°μΌ“λ‚΄μ—­ λ°”λ‘œκ°€κΈ° μΆ”κ°€
cweedlee Aug 20, 2024
3cb5f61
style: λ„˜κΈ°λŠ” λͺ¨μ–‘
cweedlee Aug 20, 2024
913f284
feat: μΊλŸ¬μ…€ μžλ™μ „ν™˜ 및 쀑볡클릭 방지
cweedlee Aug 20, 2024
95e5461
Merge branch 'agenda' of https://github.com/42organization/42gg.clien…
cweedlee Aug 20, 2024
a5e5c8d
fix: conflict
cweedlee Aug 20, 2024
ec35ee3
fix: νŽ˜μ΄μ§€λ„€μ΄μ…˜μœΌλ‘œ λ°”λ€Œμ–΄μ„œ νŒŒμ‹± 터진 λΆ€λΆ„
cweedlee Aug 21, 2024
a879d07
feat: usePageNation
cweedlee Aug 21, 2024
eb494cc
feat: μ½”λ“œ λ‹¨μˆœν™”
cweedlee Aug 21, 2024
3f8376c
feat: ν‹°μΌ“ λ°œκΈ‰μ€‘μΈμ§€ ν™•μΈν•˜λŠ” 둜직 apiμ—μ„œ λ°›μ•„μ˜€λŠ” κ²ƒμœΌλ‘œ λ³€κ²½
cweedlee Aug 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
87 changes: 87 additions & 0 deletions components/agenda/Ticket/Ticket.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
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;
}

const Ticket = ({ type }: { type: string }) => {
const { data } = useFetchGet<TicketProps>('/ticket');
let status = localStorage.getItem('ticket-issue-status') || false;
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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

λ°œκΈ‰ μ™„λ£Œλ§Œ λˆŒλŸ¬λ„ ν‹°μΌ“ κ°œμˆ˜κ°€ λŠ˜μ–΄λ‚˜λŠ” λΆ€λΆ„ λ°±μ—”λ“œμͺ½μ— ν™•μΈν•„μš”!

</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>
{status ? (
<button
className={styles.submitButton}
onClick={() => {
instanceInAgenda.patch('/ticket').then((res) => {
console.log(res);
localStorage.removeItem('ticket-issue-status');
status = false;
});
}}
>
λ°œκΈ‰ μ™„λ£Œ
</button>
) : (
<button
className={styles.submitButton}
onClick={() => {
instanceInAgenda.post('/ticket').then(() => {
alert('ν‹°μΌ“ λ°œκΈ‰ μ‹œμž‘');
status = true;
localStorage.setItem('ticket-issue-status', 'true');
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