From 9b9b13c622d77635b0cde0c9abec75f550d0f127 Mon Sep 17 00:00:00 2001 From: llddang <77055208+llddang@users.noreply.github.com> Date: Sun, 24 Nov 2024 22:41:20 +0900 Subject: [PATCH] =?UTF-8?q?Feature/#354=20QA=EC=97=90=EC=84=9C=20=EB=B0=9C?= =?UTF-8?q?=EA=B2=AC=EB=90=9C=20UX=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20(#356)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 학습자료 생성 모달이 닫히면, 남아있던 data 초기화 #354 * feat: 팀페이지에서 학습자료 갯수를 넘어 페이지네비게이션 되는 오류 해결 #354 * feat: 팀원이 아닌 사람이 스터디에 들어올 수 없도록 수정 #354 * feat: 10MB 이내의 파일만 등록 가능하도록 수정 #354 * fix: 학습자료 첨부에서 첨부파일에 null이 들어가는 빌드 오류 해결 #354 --- src/app/team/[teamId]/page.tsx | 11 ++- .../team/[teamId]/study/[studyId]/page.tsx | 15 +++- .../study/CreateDocumentModal/index.tsx | 76 +++++++++++++------ 3 files changed, 70 insertions(+), 32 deletions(-) diff --git a/src/app/team/[teamId]/page.tsx b/src/app/team/[teamId]/page.tsx index f85c0b24..40b0e2b1 100644 --- a/src/app/team/[teamId]/page.tsx +++ b/src/app/team/[teamId]/page.tsx @@ -61,7 +61,7 @@ const Page = ({ params }: { params: { teamId: number } }) => { getDocumentList('teams', params.teamId, page, size).then((res) => { if (res.ok) { setDocumentArray(res.body.content); - setDocumentLength(res.body.numberOfElements); + setDocumentLength(res.body.totalElements); } }); } @@ -75,10 +75,6 @@ const Page = ({ params }: { params: { teamId: number } }) => { TEAM_CATEGORY_INFOS[1].page = `/team/${params.teamId}/document`; }, []); - useEffect(() => { - getCardData(cardIdx); - }, [cardIdx]); - useEffect(() => { getCardData(0); }, [category]); @@ -98,6 +94,7 @@ const Page = ({ params }: { params: { teamId: number } }) => { const handlePrevClick = () => { if (cardIdx - CARD_PER_PAGE < 0) return; + getCardData(cardIdx - CARD_PER_PAGE); setCardIdx((idx) => idx - CARD_PER_PAGE); }; @@ -115,13 +112,15 @@ const Page = ({ params }: { params: { teamId: number } }) => { } }); } else if (category === '학습자료') { - if (cardIdx + CARD_PER_PAGE > documentLength) return; + if (cardIdx + CARD_PER_PAGE >= documentLength) return; const nextPage = Math.floor((cardIdx + CARD_PER_PAGE) / CARD_PER_PAGE); const size = CARD_PER_PAGE; getDocumentList('teams', params.teamId, nextPage, size).then((res) => { if (res.ok) { + setDocumentArray(res.body.content); + setDocumentLength(res.body.totalElements); setCardIdx((idx) => idx + CARD_PER_PAGE); } }); diff --git a/src/app/team/[teamId]/study/[studyId]/page.tsx b/src/app/team/[teamId]/study/[studyId]/page.tsx index 548a6abe..b472e015 100644 --- a/src/app/team/[teamId]/study/[studyId]/page.tsx +++ b/src/app/team/[teamId]/study/[studyId]/page.tsx @@ -1,12 +1,15 @@ 'use client'; import { Flex, Grid, IconButton, Text, Link, Card } from '@chakra-ui/react'; +import { useAtomValue } from 'jotai'; import NextLink from 'next/link'; +import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { MdOutlineArrowForwardIos } from 'react-icons/md'; import { getDocumentList } from '@/app/api/document'; import { getStudy, getStudyMembers } from '@/app/api/study'; +import { myTeamAtom } from '@/atom'; import DocumentCard from '@/components/DocumentCard'; import Title from '@/components/Title'; import CurriculumCard from '@/containers/study/CurriculumCard'; @@ -28,7 +31,11 @@ const Page = ({ params }: { params: { teamId: number; studyId: number } }) => { const [isTerminateModalOpen, setIsTerminateModalOpen] = useState(false); const [documentArray, setDocumentArray] = useState([]); + const router = useRouter(); const user = useGetUser(); + const myTeam = useAtomValue(myTeamAtom); + if (user && !user.isLogin) router.replace(`/team/${params.teamId}`); + if (user && !myTeam.some((id) => id === +params.teamId)) router.replace(`/team/${params.teamId}`); const participantData = useGetFetchWithToken(getStudyMembers, [params?.studyId])?.map( (data: StudyMember) => @@ -67,7 +74,7 @@ const Page = ({ params }: { params: { teamId: number; studyId: number } }) => { )} - {studyData && studyData?.status !== 'ENDED' && user?.memberId === studyData?.studyLeaderId && ( + {studyData && studyData?.status !== 'ENDED' && user && user.memberId === studyData?.studyLeaderId && ( { )} - {studyData && ( + {studyData && user && user.memberId !== -1 && ( )} @@ -129,7 +136,7 @@ const Page = ({ params }: { params: { teamId: number; studyId: number } }) => { {/* */} - {studyData && user?.memberId === studyData.studyLeaderId && ( + {studyData && user && user.memberId === studyData.studyLeaderId && ( , }; +const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB + const CreateDocumentModal = ({ isOpen, onClose, categoryData, category }: DocumentModalProps) => { const [doctype, setDocType] = useState('IMAGE'); const [docList, setDocList] = useState({ @@ -51,6 +53,20 @@ const CreateDocumentModal = ({ isOpen, onClose, categoryData, category }: Docume const handleChange = (value: string) => { setSelectedValue(value as DocumentAccessType); }; + + const handleCloseModal = () => { + onClose(); + setTitle(''); + setDescription(''); + setSelectedValue('ALL'); + setDocList({ + IMAGE: [], + DOCUMENT: [], + URL: [], + }); + setDocType('IMAGE'); + }; + const user = useGetUser(); const onConfirmButtonClick = () => { @@ -84,48 +100,64 @@ const CreateDocumentModal = ({ isOpen, onClose, categoryData, category }: Docume const categoryDatas = categoryData as CreateDocument; createDocs(categoryDatas.groupType, categoryDatas.groupId, documentForm).then((response) => { if (response.ok) { - onClose(); + handleCloseModal(); } }); } else if (category === 'update') { const categoryDatas = categoryData as DocumentDetail; postDocs(categoryDatas.id, { title, description, accessType: selectedValue }).then((response) => { if (response.ok) { - onClose(); + handleCloseModal(); } }); } else { - onClose(); + handleCloseModal(); } }; const handleGetDoc = { IMAGE: (e: ChangeEvent) => { - const imgs = Array.from(e.target.files || []); + const images = Array.from(e.target.files || []); + let alertFlag = false; + const filteredImages = images.reduce( + (r, img) => { + if (img.size >= MAX_FILE_SIZE) alertFlag = true; + else + r.push({ + key: img.name, + name: img.name, + content: img, + }); + return r; + }, + [] as { key: string; name: string; content: File }[], + ); + if (alertFlag) alert('10MB 이내의 파일을 첨부해주세요.'); setDocList((prev) => ({ ...prev, - IMAGE: [ - ...prev.IMAGE, - ...imgs.map((img) => ({ - key: img.name, - name: img.name, - content: img, - })), - ], + IMAGE: [...prev.IMAGE, ...filteredImages], })); }, DOCUMENT: (e: ChangeEvent) => { const files = Array.from(e.target.files || []); + let alertFlag = false; + const filteredFiles = files.reduce( + (r, file) => { + if (file.size >= MAX_FILE_SIZE) alertFlag = true; + else + r.push({ + key: file.name, + name: file.name, + content: file, + }); + return r; + }, + [] as { key: string; name: string; content: File }[], + ); + if (alertFlag) alert('10MB 이내의 파일을 첨부해주세요.'); setDocList((prev) => ({ ...prev, - DOCUMENT: [ - ...prev.DOCUMENT, - ...files.map((file) => ({ - key: file.name.toString(), - name: file.name, - content: file, - })), - ], + DOCUMENT: [...prev.DOCUMENT, ...filteredFiles], })); }, URL: () => { @@ -179,10 +211,10 @@ const CreateDocumentModal = ({ isOpen, onClose, categoryData, category }: Docume