From 76bcf79da4376c30c1851a631f33d10a5a847544 Mon Sep 17 00:00:00 2001 From: Yunseok Date: Sun, 29 Sep 2024 01:31:31 +0900 Subject: [PATCH 01/13] =?UTF-8?q?[FEAT]=20-=20=EB=93=B1=EB=A1=9D,=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EB=B2=84=ED=8A=BC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Goalpage/MemberList.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/components/Goalpage/MemberList.tsx b/src/components/Goalpage/MemberList.tsx index fdb4e7a6..0412f3da 100644 --- a/src/components/Goalpage/MemberList.tsx +++ b/src/components/Goalpage/MemberList.tsx @@ -1,6 +1,7 @@ import MemberCard from './MemberList/MemberCard'; import { API } from '../../lib/api/index.ts'; import { useState, useEffect } from 'react'; +import cn from '../../lib/cn'; interface Member { id: string; @@ -55,6 +56,20 @@ export default function MemberList() { /> ))} - + + + ); } From 687f63556b0038252e331210bbf4f6f791313b64 Mon Sep 17 00:00:00 2001 From: Yunseok Date: Sun, 29 Sep 2024 01:50:03 +0900 Subject: [PATCH 02/13] =?UTF-8?q?[FEAT]=20-=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EB=AA=A8=EB=8B=AC=EC=B0=BD=20?= =?UTF-8?q?=EB=A7=8C=EB=93=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Goalpage/MemberList.tsx | 14 +++ .../Goalpage/MemberList/ImageUploadModal.tsx | 98 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/components/Goalpage/MemberList/ImageUploadModal.tsx diff --git a/src/components/Goalpage/MemberList.tsx b/src/components/Goalpage/MemberList.tsx index 0412f3da..402fa9e5 100644 --- a/src/components/Goalpage/MemberList.tsx +++ b/src/components/Goalpage/MemberList.tsx @@ -2,6 +2,7 @@ import MemberCard from './MemberList/MemberCard'; import { API } from '../../lib/api/index.ts'; import { useState, useEffect } from 'react'; import cn from '../../lib/cn'; +import ImageUploadModal from './MemberList/ImageUploadModal.tsx'; interface Member { id: string; @@ -9,6 +10,7 @@ interface Member { } export default function MemberList() { + const [isModalVisible, setIsModalVisible] = useState(false); const [members, setMembers] = useState([ { id: '1', username: '김' }, { id: '2', username: '박' }, @@ -37,6 +39,14 @@ export default function MemberList() { fetchMemberList(); }, []); + const openModal = () => { + setIsModalVisible(true); + }; + + const closeModal = () => { + setIsModalVisible(false); + }; + return ( <>
@@ -60,9 +70,13 @@ export default function MemberList() { "w-64 md:w-96 h-12 md:h-16 bg-[#5A82F1] text-white rounded-lg hover:bg-blue-600", "transition text-sm md:text-xl font-semibold mt-10 " )} + onClick={openModal} > 나의 인증 등록하기 + {isModalVisible && ( + + )} +
+ ) : ( +
+ )} + + +
+ + ) : null; +} From 5263ef58e9ea7d5327a2481391ef42d9f97183b9 Mon Sep 17 00:00:00 2001 From: Yunseok Date: Sun, 29 Sep 2024 02:56:37 +0900 Subject: [PATCH 03/13] =?UTF-8?q?[FEAT]=20-=20=EB=AA=A8=EB=8B=AC=EC=B0=BD?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC,=20=EC=95=84=EC=A7=81=20=ED=86=B5?= =?UTF-8?q?=EC=8B=A0=20=EC=95=88=EB=90=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Goalpage/MemberList.tsx | 4 +- .../Goalpage/MemberList/ImageUploadModal.tsx | 98 -------------- .../Goalpage/MemberList/UploadModal.tsx | 124 ++++++++++++++++++ .../MemberList/UploadModal/ImageUpload.tsx | 77 +++++++++++ .../UploadModal/SelectRoutineList.tsx | 94 +++++++++++++ src/lib/api/user/index.ts | 29 ++++ 6 files changed, 326 insertions(+), 100 deletions(-) delete mode 100644 src/components/Goalpage/MemberList/ImageUploadModal.tsx create mode 100644 src/components/Goalpage/MemberList/UploadModal.tsx create mode 100644 src/components/Goalpage/MemberList/UploadModal/ImageUpload.tsx create mode 100644 src/components/Goalpage/MemberList/UploadModal/SelectRoutineList.tsx diff --git a/src/components/Goalpage/MemberList.tsx b/src/components/Goalpage/MemberList.tsx index 402fa9e5..3d809237 100644 --- a/src/components/Goalpage/MemberList.tsx +++ b/src/components/Goalpage/MemberList.tsx @@ -2,7 +2,7 @@ import MemberCard from './MemberList/MemberCard'; import { API } from '../../lib/api/index.ts'; import { useState, useEffect } from 'react'; import cn from '../../lib/cn'; -import ImageUploadModal from './MemberList/ImageUploadModal.tsx'; +import UploadModal from './MemberList/UploadModal.tsx'; interface Member { id: string; @@ -75,7 +75,7 @@ export default function MemberList() { 나의 인증 등록하기 {isModalVisible && ( - + )} - - ) : ( -
- )} - - -
- - ) : null; -} diff --git a/src/components/Goalpage/MemberList/UploadModal.tsx b/src/components/Goalpage/MemberList/UploadModal.tsx new file mode 100644 index 00000000..ee2a78b1 --- /dev/null +++ b/src/components/Goalpage/MemberList/UploadModal.tsx @@ -0,0 +1,124 @@ +import React, { useState } from 'react'; +import ImageUpload from './UploadModal/ImageUpload.tsx'; +import SelectRoutineList from './UploadModal/SelectRoutineList.tsx'; +import cn from '../../../lib/cn.ts'; +import { API } from '../../../lib/api/index.ts'; +import { LiaCloneSolid } from 'react-icons/lia'; + +interface MultiStepModalProps { + isVisible: boolean; + onClose: () => void; +} + +export default function MultiStepModal({ isVisible, onClose }: MultiStepModalProps) { + const [step, setStep] = useState(1); // 1: 이미지 업로드, 2: 루틴 선택 + const [index, setIndex] = useState(0); // 루틴 인덱스 + const [image, setImage] = useState(null); // 이미지 상태 + const [selectedRoutine, setSelectedRoutine] = useState(''); // 선택된 루틴 + + const handleNextStep = () => { + setStep(step + 1); + }; + + const handlePreviousStep = () => { + setStep(step - 1); + }; + + const handleCancel = () => { + onClose(); // 모달 닫기 + }; + + const handleUpload = async () => { + if (!image || !selectedRoutine) return; + + try { + // 여기에 이미지와 루틴 정보를 백엔드에 전송하는 API 호출 로직 추가 + const response = await API.User.uploadRoutine( + index, // 루틴 인덱스 + selectedRoutine, // 선택한 루틴 + image, // 전송할 이미지 파일 + ); + + if (response.status === 'OK') { + setStep(3); // 성공 시 3단계로 이동 + } else { + console.error('업로드 실패:', response); + setStep(4); // 실패 시 4단계로 이동 (재시도 안내) + } + + } catch (error) { + console.error('업로드 중 오류 발생:', error); + setStep(4); // 실패 시 4단계로 이동 (재시도 안내) + } + }; + + return isVisible ? ( +
+
+ {step === 1 && ( + <> +

이미지 업로드

+ + + )} + {step === 2 && ( + <> +

루틴 선택

+ + + )} + {step === 3 && ( +
+

성공적으로 등록되었습니다!

+ +
+ )} + {step === 4 && ( +
+

업로드 실패. 재시도 하세요.

+ +
+ )} +
+
+ ) : null; +} \ No newline at end of file diff --git a/src/components/Goalpage/MemberList/UploadModal/ImageUpload.tsx b/src/components/Goalpage/MemberList/UploadModal/ImageUpload.tsx new file mode 100644 index 00000000..16700a80 --- /dev/null +++ b/src/components/Goalpage/MemberList/UploadModal/ImageUpload.tsx @@ -0,0 +1,77 @@ +// ImageUpload.tsx +import React, { ChangeEvent, useState, useEffect } from 'react'; + +interface ImageUploadProps { + image: File | null; // 이미지 상태 + setImage: (file: File | null) => void; // 이미지 상태를 업데이트하는 함수 + onNext: () => void; // 다음 단계로 이동 + onCancel: () => void; // 취소 시 모달 닫기 +} + +export default function ImageUpload({ image, setImage, onNext, onCancel }: ImageUploadProps) { + const [previewUrl, setPreviewUrl] = useState(null); + + useEffect(() => { + if (image) { + const reader = new FileReader(); + reader.onload = () => { + setPreviewUrl(reader.result as string); + }; + reader.readAsDataURL(image); + } else { + setPreviewUrl(null); + } + }, [image]); + + const handleImageChange = (e: ChangeEvent) => { + const file = e.target.files?.[0]; + if (file) { + setImage(file); + } + }; + + const handleImageDelete = () => { + setImage(null); + }; + + return ( +
+ + {previewUrl ? ( +
+ preview + +
+ ) : ( +
+ )} + + +
+ ); +} diff --git a/src/components/Goalpage/MemberList/UploadModal/SelectRoutineList.tsx b/src/components/Goalpage/MemberList/UploadModal/SelectRoutineList.tsx new file mode 100644 index 00000000..9818dadf --- /dev/null +++ b/src/components/Goalpage/MemberList/UploadModal/SelectRoutineList.tsx @@ -0,0 +1,94 @@ +// SelectRoutineList.tsx +import React, { useEffect, useState } from 'react'; +import { API } from '../../../../lib/api/index.ts'; + +interface SelectRoutineListProps { + index: number; // 루틴 인덱스 + setIndex: (index: number) => void; // 루틴 인덱스를 업데이트하는 함수 + selectedRoutine: string; // 선택된 루틴 + setSelectedRoutine: (routine: string) => void; // 루틴 상태를 업데이트하는 함수 + onNext: () => void; // 다음 단계로 이동 + onPrevious: () => void; // 이전 단계로 이동 + onCancel: () => void; // 취소 시 모달 닫기 +} + +export default function SelectRoutineList({ + index, + setIndex, + selectedRoutine, + setSelectedRoutine, + onNext, + onPrevious, + onCancel, +}: SelectRoutineListProps) { + const [routines, setRoutines] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchRoutines = async () => { + setLoading(true); + try { + const response = await API.User.getUserRoutine(); + + if (response.status === 'OK' && response.data) { + const routineList: string[] = Object.values(response.data); + setRoutines(routineList); + } + } catch (e) { + setError('루틴 목록을 불러오는 중 오류가 발생했습니다.'); + } finally { + setLoading(false); + } + }; + + fetchRoutines(); + }, []); + + const handleSelect = (routine: string, routineIndex: number) => { + setSelectedRoutine(routine); + setIndex(routineIndex); + }; + + return ( +
+
+ {routines.map((routine, i) => ( + + ))} +
+
+ +
+
+ + +
+
+ ); +} diff --git a/src/lib/api/user/index.ts b/src/lib/api/user/index.ts index 196f613e..151bef02 100644 --- a/src/lib/api/user/index.ts +++ b/src/lib/api/user/index.ts @@ -90,4 +90,33 @@ export namespace __User { tokenOn: true, }); } + + export async function uploadRoutine( + routineIndex: number, + routineName: string, + file: File + ) { + const url = `${BASE_URL}/routine/upload`; + + return fetchData({ + url, + method: 'POST', + body: { + routineIndex, + routineName, + file, + }, + tokenOn: true, + }); + } + + export async function getUserRoutine() { + const url = `${BASE_URL}/team/routine-list`; + + return fetchData({ + url, + method: 'GET', + tokenOn: true, + }); + } } From aa25c5cb5885b9f819eda86bdf98c2981e2a546b Mon Sep 17 00:00:00 2001 From: Yunseok Date: Sun, 29 Sep 2024 04:02:59 +0900 Subject: [PATCH 04/13] =?UTF-8?q?[FEAT]=20-=20API=20=EB=B0=94=EA=BF=94?= =?UTF-8?q?=EB=B3=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Goalpage/GoormScreen.tsx | 28 ++++++----------- src/lib/api/user/index.ts | 42 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/components/Goalpage/GoormScreen.tsx b/src/components/Goalpage/GoormScreen.tsx index 897dfac7..cd3928dc 100644 --- a/src/components/Goalpage/GoormScreen.tsx +++ b/src/components/Goalpage/GoormScreen.tsx @@ -16,26 +16,16 @@ interface Cloud { export default function GoormScreen() { const [stage, setStage] = useState(0); - const [myId, setMyId] = useState(''); const [clouds, setClouds] = useState([]); useEffect(() => { const fetchMyData = async () => { try { - const response = await API.User.getMyInfo(); + const response = await API.User.currentStep(); if (response.status === 'OK' && response.data) { - // 사용자 ID 설정 - setMyId(response.data.id); - - // 'data' 배열이 존재하고 배열인지 확인 후 길이 설정 - if (response.data.data && Array.isArray(response.data.data)) { - const dataCount = response.data.data.length; - setStage(dataCount); - } else { - // 'data' 배열이 없거나 배열이 아닌 경우 0으로 설정 - setStage(0); - } + setStage(response.data.currentStep); + console.log('현재 스테이지:', response.data.currentStep); } else { console.error('응답 상태가 OK가 아니거나 데이터가 없습니다.'); setStage(0); @@ -81,16 +71,18 @@ export default function GoormScreen() { }, [stage]); // stage가 변경될 때마다 실행 // 임시로 집어넣은 구름 단계 증가 함수 - const increaseStage = () => { - setStage((prev) => (prev < 4 ? prev + 1 : prev)); + const increaseStage = (stage:number) => { + setStage((prev) => (prev < stage ? prev + 1 : prev)); }; // 구름 증가시키는데 천천히 증가하도록 설정 useEffect(() => { - if (stage < 4) { // 최대 스테이지가 4라면 + if (stage === 0) { + return; + } else if (stage < 4) { // 최대 스테이지가 4라면 const timer = setTimeout(() => { - increaseStage(); - }, 1000); + increaseStage(stage); + }, 1500); return () => clearTimeout(timer); } diff --git a/src/lib/api/user/index.ts b/src/lib/api/user/index.ts index 196f613e..1982ab35 100644 --- a/src/lib/api/user/index.ts +++ b/src/lib/api/user/index.ts @@ -90,4 +90,46 @@ export namespace __User { tokenOn: true, }); } + + export async function currentStep() { + const url = `${BASE_URL}/user/current-step`; + + return fetchData({ + url, + method: 'GET', + tokenOn: true, + }); + } + + export async function uploadRoutine( + routineIndex: string, + routineName: string, + file: File + ) { + const url = `${BASE_URL}/routine/upload`; + + // FormData 객체 생성 + const formData = new FormData(); + formData.append('routineIndex', routineIndex.toString()); + formData.append('routineName', routineName); + formData.append('file', file); + + return fetchData({ + url, + method: 'POST', + body: formData, + tokenOn: true, + isFormData: true, + }); + } + + export async function getUserRoutine() { + const url = `${BASE_URL}/team/routine-list`; + + return fetchData({ + url, + method: 'GET', + tokenOn: true, + }); + } } From 0eb50f508c878389079971cebba18e1fd5c5d215 Mon Sep 17 00:00:00 2001 From: Yunseok Date: Sun, 29 Sep 2024 04:26:46 +0900 Subject: [PATCH 05/13] =?UTF-8?q?[FEAT]=20-=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Goalpage/MemberList/UploadModal.tsx | 22 ++++++++++++------- src/lib/api/user/index.ts | 15 ++++++++----- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/components/Goalpage/MemberList/UploadModal.tsx b/src/components/Goalpage/MemberList/UploadModal.tsx index ee2a78b1..2d5c8865 100644 --- a/src/components/Goalpage/MemberList/UploadModal.tsx +++ b/src/components/Goalpage/MemberList/UploadModal.tsx @@ -32,12 +32,18 @@ export default function MultiStepModal({ isVisible, onClose }: MultiStepModalPro if (!image || !selectedRoutine) return; try { - // 여기에 이미지와 루틴 정보를 백엔드에 전송하는 API 호출 로직 추가 - const response = await API.User.uploadRoutine( - index, // 루틴 인덱스 - selectedRoutine, // 선택한 루틴 - image, // 전송할 이미지 파일 - ); + // FormData 객체 생성 + const formData = new FormData(); + formData.append('routineIndex', index.toString()); // 인덱스 값을 문자열로 변환하여 추가 + formData.append('routineName', selectedRoutine); // 루틴 이름 추가 + formData.append('file', image); // 이미지 파일 추가 + + // API 호출 + const response = await API.User.uploadRoutine( + (index + 1).toString(), // 루틴 인덱스 + selectedRoutine, // 선택한 루틴 + image // 전송할 이미지 파일 + ); if (response.status === 'OK') { setStep(3); // 성공 시 3단계로 이동 @@ -112,9 +118,9 @@ export default function MultiStepModal({ isVisible, onClose }: MultiStepModalPro 'w-full bg-blue-500 text-white rounded-lg', 'py-2 hover:bg-blue-600 mb-4' )} - onClick={handleCancel} // 다시 시도할 경우 이전 단계로 이동 + onClick={handleCancel} > - 재시도 + 닫기
)} diff --git a/src/lib/api/user/index.ts b/src/lib/api/user/index.ts index 151bef02..36827b06 100644 --- a/src/lib/api/user/index.ts +++ b/src/lib/api/user/index.ts @@ -92,21 +92,24 @@ export namespace __User { } export async function uploadRoutine( - routineIndex: number, + routineIndex: string, routineName: string, file: File ) { const url = `${BASE_URL}/routine/upload`; + // FormData 객체 생성 + const formData = new FormData(); + formData.append('routineIndex', routineIndex.toString()); + formData.append('routineName', routineName); + formData.append('file', file); + return fetchData({ url, method: 'POST', - body: { - routineIndex, - routineName, - file, - }, + body: formData, tokenOn: true, + isFormData: true, }); } From 029599baf9761e7b313a5034240dc049954ee54b Mon Sep 17 00:00:00 2001 From: Seyeonnnn <144412217+Seyeonnnn@users.noreply.github.com> Date: Sun, 29 Sep 2024 04:27:40 +0900 Subject: [PATCH 06/13] =?UTF-8?q?=EC=8A=A4=ED=83=80=ED=8A=B8=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/GuideCard.tsx | 2 +- src/components/Mainpage/AdditionalIntroSection.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/GuideCard.tsx b/src/components/GuideCard.tsx index 1fa4efd4..866dfe80 100644 --- a/src/components/GuideCard.tsx +++ b/src/components/GuideCard.tsx @@ -34,7 +34,7 @@ const GuideCard: React.FC = ({ /> )} -
+

-
+
{' '} {/* 로그인 상태에 따라 prop 변경 */}
From 50b540facae3a32ac52b0116792d74112fb23a60 Mon Sep 17 00:00:00 2001 From: liupei8979 Date: Sun, 29 Sep 2024 04:52:13 +0900 Subject: [PATCH 07/13] =?UTF-8?q?[FEAT]=20-=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=9D=BC=EC=B9=98=20=EC=9D=B8=ED=84=B0=EB=9E=99?= =?UTF-8?q?=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Goalpage/MemberList/ShowImageModal.tsx | 16 ++++++------- .../Mainpage/AdditionalIntroSection.tsx | 3 +-- src/components/RandomCloudBackgroud.tsx | 2 +- src/pages/guide.tsx | 3 +-- src/pages/register.tsx | 23 +++++++++++++++++-- 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/components/Goalpage/MemberList/ShowImageModal.tsx b/src/components/Goalpage/MemberList/ShowImageModal.tsx index 394e0c6b..959e7aeb 100644 --- a/src/components/Goalpage/MemberList/ShowImageModal.tsx +++ b/src/components/Goalpage/MemberList/ShowImageModal.tsx @@ -82,15 +82,15 @@ export default function ShowImageModal({
{displayImages.map((image, index) => ( -
- {image.alt} + {image.alt}
))}
diff --git a/src/components/Mainpage/AdditionalIntroSection.tsx b/src/components/Mainpage/AdditionalIntroSection.tsx index 93c043c4..56cfeafc 100644 --- a/src/components/Mainpage/AdditionalIntroSection.tsx +++ b/src/components/Mainpage/AdditionalIntroSection.tsx @@ -73,8 +73,7 @@ export default function AdditionalIntroSection() {
- {' '} - {/* 로그인 상태에 따라 prop 변경 */} + {/* 로그인 상태에 따라 prop 변경 */}
); diff --git a/src/components/RandomCloudBackgroud.tsx b/src/components/RandomCloudBackgroud.tsx index df28724d..f11ca063 100644 --- a/src/components/RandomCloudBackgroud.tsx +++ b/src/components/RandomCloudBackgroud.tsx @@ -66,7 +66,7 @@ const RandomCloudBackground: React.FC = () => { }, [location.pathname]); // 경로 변경 시마다 좌표 세트 변경 return ( -
+
{cloudImages.map((cloud, index) => ( - {' '} - {/* 로그인 상태에 따라 prop 변경 */} + {/* 로그인 상태에 따라 prop 변경 */}
); diff --git a/src/pages/register.tsx b/src/pages/register.tsx index c02f67f8..1e4dda43 100644 --- a/src/pages/register.tsx +++ b/src/pages/register.tsx @@ -14,6 +14,7 @@ export default function Register() { const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [isPending, setIsPending] = useState(true); // 로딩 상태 관리 (처음엔 true) + const [passwordMatch, setPasswordMatch] = useState(true); // 비밀번호 일치 여부 상태 // 컴포넌트가 마운트될 때 0.2초 동안 Pending 표시 useEffect(() => { @@ -51,6 +52,11 @@ export default function Register() { }, 200); }; + // 비밀번호 확인 필드에서 입력할 때마다 일치 여부 확인 + useEffect(() => { + setPasswordMatch(password === confirmPassword); + }, [password, confirmPassword]); + return (
{isPending ? ( @@ -109,8 +115,15 @@ export default function Register() { /> + {!passwordMatch && ( + + 비밀번호가 일치하지 않습니다. + + )}
{/* 확인 및 취소 버튼 영역 */} @@ -133,6 +151,7 @@ export default function Register() { 'hover:bg-[#4A72D1] focus:outline-none focus:ring-2 focus:ring-[#5A82F1]' )} onClick={handleRegister} + disabled={!passwordMatch} // 비밀번호가 일치하지 않으면 버튼 비활성화 > 확인 From 64972986f96d2f14a9164a11f78f5c4142eaa069 Mon Sep 17 00:00:00 2001 From: Yunseok Date: Sun, 29 Sep 2024 04:58:39 +0900 Subject: [PATCH 08/13] =?UTF-8?q?[FEAT]=20-=20=EB=82=98=EC=9D=98=20?= =?UTF-8?q?=EC=9D=B8=EC=A6=9D=20=EC=82=AC=EC=A7=84=20=EC=97=85=EB=A1=9C?= =?UTF-8?q?=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Goalpage/MemberList.tsx | 34 +++++++++++++++++++ .../Goalpage/MemberList/ShowImageModal.tsx | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/components/Goalpage/MemberList.tsx b/src/components/Goalpage/MemberList.tsx index 3d809237..96811387 100644 --- a/src/components/Goalpage/MemberList.tsx +++ b/src/components/Goalpage/MemberList.tsx @@ -3,6 +3,7 @@ import { API } from '../../lib/api/index.ts'; import { useState, useEffect } from 'react'; import cn from '../../lib/cn'; import UploadModal from './MemberList/UploadModal.tsx'; +import ShowImageModal from './MemberList/ShowImageModal.tsx'; interface Member { id: string; @@ -11,6 +12,7 @@ interface Member { export default function MemberList() { const [isModalVisible, setIsModalVisible] = useState(false); + const [isSeeMyImageModalVisible, setIsSeeMyImageModalVisible] = useState(false); const [members, setMembers] = useState([ { id: '1', username: '김' }, { id: '2', username: '박' }, @@ -18,6 +20,22 @@ export default function MemberList() { ]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + const [myId, setMyId] = useState(''); + const [myName, setMyName] = useState(''); + + useEffect(() => { + const fetchMyData = async () => { + try { + const response = await API.User.getMyInfo(); + setMyId(response.username); + setMyName(response.nickname); + console.log(myId, myName); + } catch (error) { + console.error('내 정보를 불러오는 중 오류가 발생했습니다:', error); + } + }; + fetchMyData(); + }, []); useEffect(() => { const fetchMemberList = async () => { @@ -47,6 +65,14 @@ export default function MemberList() { setIsModalVisible(false); }; + const openSeeMyImageModal = () => { + setIsSeeMyImageModalVisible(true); + } + + const closeSeeMyImageModal = () => { + setIsSeeMyImageModalVisible(false); + } + return ( <>
@@ -81,9 +107,17 @@ export default function MemberList() { "w-64 md:w-96 h-12 md:h-16 bg-[#575757] text-white rounded-lg hover:bg-slate-700", "transition text-sm md:text-xl font-semibold mt-3 " )} + onClick={openSeeMyImageModal} > 나의 인증 보러가기 + {isSeeMyImageModalVisible && myId && myName && ( + + )} ); } diff --git a/src/components/Goalpage/MemberList/ShowImageModal.tsx b/src/components/Goalpage/MemberList/ShowImageModal.tsx index 5be0c539..3b5f8e84 100644 --- a/src/components/Goalpage/MemberList/ShowImageModal.tsx +++ b/src/components/Goalpage/MemberList/ShowImageModal.tsx @@ -22,7 +22,7 @@ export default function ShowImageModal({ }: ShowImageModalProps) { // 백엔드에서 가져온 이미지들을 저장할 상태 const [images, setImages] = useState([]); - + // 백엔드에서 이미지 데이터를 가져오는 함수 useEffect(() => { const fetchMemberImages = async () => { From d57fb10d75a6abe84e15d92dc136f093164946d0 Mon Sep 17 00:00:00 2001 From: Seyeonnnn <144412217+Seyeonnnn@users.noreply.github.com> Date: Sun, 29 Sep 2024 05:18:35 +0900 Subject: [PATCH 09/13] =?UTF-8?q?=EA=B5=AC=EB=A6=84=EB=B2=84=ED=8A=BC?= =?UTF-8?q?=ED=98=B8=EB=B2=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/guide.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/guide.tsx b/src/pages/guide.tsx index af668035..5e06a42a 100644 --- a/src/pages/guide.tsx +++ b/src/pages/guide.tsx @@ -70,9 +70,8 @@ export default function Guide() { )} {/* 부모 요소에 flex와 justify-center 추가 */} -
- {' '} - {/* 로그인 상태에 따라 prop 변경 */} +
+ {/* 로그인 상태에 따라 prop 변경 */}
); From a3ed3d5598d71c4b14c30590f3d66626f2f263f8 Mon Sep 17 00:00:00 2001 From: liupei8979 Date: Sun, 29 Sep 2024 05:32:24 +0900 Subject: [PATCH 10/13] [FEAT] --- src/components/Mypage/Goals/MaintenanceGoals.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Mypage/Goals/MaintenanceGoals.tsx b/src/components/Mypage/Goals/MaintenanceGoals.tsx index de4b0788..ad8d5c65 100644 --- a/src/components/Mypage/Goals/MaintenanceGoals.tsx +++ b/src/components/Mypage/Goals/MaintenanceGoals.tsx @@ -54,7 +54,7 @@ const MaintenanceGoals: React.FC = () => { }, [currentDate]); return ( -
+
{loading ? ( // 로딩 중일 때만 Pending 컴포넌트를 표시 ) : error ? ( @@ -74,4 +74,4 @@ const MaintenanceGoals: React.FC = () => { ); }; -export default MaintenanceGoals; +export default MaintenanceGoals; \ No newline at end of file From efcc34567e7faa05482888fbe8ede459dd35282e Mon Sep 17 00:00:00 2001 From: liupei8979 Date: Sun, 29 Sep 2024 05:43:59 +0900 Subject: [PATCH 11/13] [FEAT] --- src/components/Mypage/Goals/SettingGoals.tsx | 12 +++++++++++- src/lib/api/team/index.ts | 10 ++++++++++ src/lib/api/user/index.ts | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/components/Mypage/Goals/SettingGoals.tsx b/src/components/Mypage/Goals/SettingGoals.tsx index 6600d5d0..aae44539 100644 --- a/src/components/Mypage/Goals/SettingGoals.tsx +++ b/src/components/Mypage/Goals/SettingGoals.tsx @@ -9,7 +9,7 @@ const SettingGoals: React.FC = () => { const [showCreateTeam, setShowCreateTeam] = useState(false); const [showInviteCode, setShowInviteCode] = useState(false); - // 화면 렌더될 때 기록 조회 + // 화면 렌더될 때 기록 조회 및 유저 루틴 조회 useEffect(() => { const fetchHistories = async () => { try { @@ -20,7 +20,17 @@ const SettingGoals: React.FC = () => { } }; + const fetchUserRoutine = async () => { + try { + const routineResponse = await API.Team.getUserRoutine(); + console.log('유저 루틴 조회 성공:', routineResponse); + } catch (error) { + console.error('유저 루틴 조회 실패:', error); + } + }; + fetchHistories(); + fetchUserRoutine(); // 유저 루틴을 조회하고 콘솔에 출력 }, []); // 빈 배열을 사용하여 컴포넌트가 처음 렌더링될 때만 실행 const handleCreateTeamClick = () => { diff --git a/src/lib/api/team/index.ts b/src/lib/api/team/index.ts index 14835080..4731b113 100644 --- a/src/lib/api/team/index.ts +++ b/src/lib/api/team/index.ts @@ -69,4 +69,14 @@ export namespace __Team { tokenOn: true, // 인증이 필요한 경우 토큰 포함 }); } + + export async function getUserRoutine() { + const url = `${BASE_URL}/team/routine-list` + + return fetchData({ + url, + method: 'GET', + tokenOn: true, + }); + } } diff --git a/src/lib/api/user/index.ts b/src/lib/api/user/index.ts index 196f613e..8d82b553 100644 --- a/src/lib/api/user/index.ts +++ b/src/lib/api/user/index.ts @@ -90,4 +90,6 @@ export namespace __User { tokenOn: true, }); } + + } From f363656992b0efeec46249598094b86264c67753 Mon Sep 17 00:00:00 2001 From: liupei8979 Date: Sun, 29 Sep 2024 06:14:34 +0900 Subject: [PATCH 12/13] =?UTF-8?q?[FEAT]=20-=20=EB=AA=A9=ED=91=9C=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=A1=B0=ED=9A=8C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Mypage/Goals/MaintenanceGoals.tsx | 2 +- .../Mypage/Goals/Setting/TeamsRoutine.tsx | 55 +++++++++++++++++++ src/components/Mypage/Goals/SettingGoals.tsx | 31 +++++++---- src/lib/api/team/index.ts | 2 +- src/lib/api/user/index.ts | 2 - 5 files changed, 77 insertions(+), 15 deletions(-) create mode 100644 src/components/Mypage/Goals/Setting/TeamsRoutine.tsx diff --git a/src/components/Mypage/Goals/MaintenanceGoals.tsx b/src/components/Mypage/Goals/MaintenanceGoals.tsx index ad8d5c65..711b8ee0 100644 --- a/src/components/Mypage/Goals/MaintenanceGoals.tsx +++ b/src/components/Mypage/Goals/MaintenanceGoals.tsx @@ -74,4 +74,4 @@ const MaintenanceGoals: React.FC = () => { ); }; -export default MaintenanceGoals; \ No newline at end of file +export default MaintenanceGoals; diff --git a/src/components/Mypage/Goals/Setting/TeamsRoutine.tsx b/src/components/Mypage/Goals/Setting/TeamsRoutine.tsx new file mode 100644 index 00000000..80e33fd5 --- /dev/null +++ b/src/components/Mypage/Goals/Setting/TeamsRoutine.tsx @@ -0,0 +1,55 @@ +import React from 'react'; + +interface TeamsRoutineProps { + routineData: { + routine1: string; + routine2: string; + routine3: string; + routine4: string; + }; +} + +const TeamsRoutine: React.FC = ({ routineData }) => { + return ( +
+
+
+

+ 기초 체력 기르기 +

+
+ +
+
+ +
+
+ {routineData.routine1 || '루틴이 없습니다'} +
+
+ {routineData.routine2 || '루틴이 없습니다'} +
+
+ {routineData.routine3 || '루틴이 없습니다'} +
+
+ {routineData.routine4 || '루틴이 없습니다'} +
+
+
+
+
+ +
+ +
+
+ ); +}; + +export default TeamsRoutine; \ No newline at end of file diff --git a/src/components/Mypage/Goals/SettingGoals.tsx b/src/components/Mypage/Goals/SettingGoals.tsx index aae44539..80f7b9ed 100644 --- a/src/components/Mypage/Goals/SettingGoals.tsx +++ b/src/components/Mypage/Goals/SettingGoals.tsx @@ -4,33 +4,32 @@ import { API } from '../../../lib/api'; // API 모듈 경로에 맞게 import import CreateTeam from './Setting/CreateTeam'; // CreateTeam 컴포넌트를 임포트합니다. import InputCodeField from './Setting/InputCodeField'; // InviteCodeField 컴포넌트를 임포트합니다. import NotGood from '../../../assets/NotGood.svg'; +import Pending from '../../Pending/Loading.tsx'; // Pending 컴포넌트 추가 +import TeamsRoutine from './Setting/TeamsRoutine'; // TeamsRoutine 컴포넌트 import const SettingGoals: React.FC = () => { const [showCreateTeam, setShowCreateTeam] = useState(false); const [showInviteCode, setShowInviteCode] = useState(false); + const [userRoutine, setUserRoutine] = useState(null); // 유저 루틴 상태 관리 + const [loading, setLoading] = useState(true); // 로딩 상태 추가 // 화면 렌더될 때 기록 조회 및 유저 루틴 조회 useEffect(() => { - const fetchHistories = async () => { - try { - const response = await API.Team.getHistories(); - console.log('기록 조회 성공:', response); - } catch (error) { - console.error('기록 조회 실패:', error); - } - }; - const fetchUserRoutine = async () => { try { const routineResponse = await API.Team.getUserRoutine(); console.log('유저 루틴 조회 성공:', routineResponse); + if (routineResponse.data) { + setUserRoutine(routineResponse.data); // 루틴이 있으면 상태에 저장 + } } catch (error) { console.error('유저 루틴 조회 실패:', error); + } finally { + setLoading(false); // 데이터가 로드되면 로딩 상태 해제 } }; - fetchHistories(); - fetchUserRoutine(); // 유저 루틴을 조회하고 콘솔에 출력 + fetchUserRoutine(); // 유저 루틴을 조회하고 상태에 저장 }, []); // 빈 배열을 사용하여 컴포넌트가 처음 렌더링될 때만 실행 const handleCreateTeamClick = () => { @@ -41,6 +40,10 @@ const SettingGoals: React.FC = () => { setShowInviteCode(true); }; + if (loading) { + return ; // 로딩 중일 때 Pending 컴포넌트를 표시 + } + if (showCreateTeam) { return ; } @@ -49,6 +52,12 @@ const SettingGoals: React.FC = () => { return ; } + // 유저 루틴이 있으면 TeamsRoutine 컴포넌트를 렌더링 + if (userRoutine) { + return ; + } + + // 유저 루틴이 없으면 팀 생성 UI를 표시 return (
Not Good diff --git a/src/lib/api/team/index.ts b/src/lib/api/team/index.ts index 4731b113..316f1ef3 100644 --- a/src/lib/api/team/index.ts +++ b/src/lib/api/team/index.ts @@ -71,7 +71,7 @@ export namespace __Team { } export async function getUserRoutine() { - const url = `${BASE_URL}/team/routine-list` + const url = `${BASE_URL}/team/routine-list`; return fetchData({ url, diff --git a/src/lib/api/user/index.ts b/src/lib/api/user/index.ts index 8d82b553..196f613e 100644 --- a/src/lib/api/user/index.ts +++ b/src/lib/api/user/index.ts @@ -90,6 +90,4 @@ export namespace __User { tokenOn: true, }); } - - } From c89eb7a4be6e59b35d50048977b0ced18247ebcc Mon Sep 17 00:00:00 2001 From: liupei8979 Date: Sun, 29 Sep 2024 06:27:40 +0900 Subject: [PATCH 13/13] [FEAT] --- src/components/Mypage/Goals/MaintenanceGoals.tsx | 16 +++++++++++++++- .../Mypage/Goals/Setting/TeamsRoutine.tsx | 2 +- src/components/RandomCloudBackgroud.tsx | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/components/Mypage/Goals/MaintenanceGoals.tsx b/src/components/Mypage/Goals/MaintenanceGoals.tsx index 711b8ee0..223e1a60 100644 --- a/src/components/Mypage/Goals/MaintenanceGoals.tsx +++ b/src/components/Mypage/Goals/MaintenanceGoals.tsx @@ -5,6 +5,7 @@ import Calendar from './Calander'; import DDayCounter from './DDayCounter'; import Pending from '../../Pending/Loading.tsx'; // Pending 컴포넌트 추가 import dayjs from 'dayjs'; +import { useNavigate } from 'react-router-dom'; // useNavigate import 추가 const MaintenanceGoals: React.FC = () => { const [dDay, setDDay] = useState(null); @@ -16,6 +17,8 @@ const MaintenanceGoals: React.FC = () => { const [error, setError] = useState(null); const [currentDate, setCurrentDate] = useState(new Date()); + const navigate = useNavigate(); // useNavigate 훅 사용 + useEffect(() => { const fetchCalendar = async () => { try { @@ -53,12 +56,23 @@ const MaintenanceGoals: React.FC = () => { fetchCalendar(); }, [currentDate]); + useEffect(() => { + if (error) { + navigate('?sector=maintenance'); // 에러 발생 시 경로 변경 + } + }, [error, navigate]); + return (
{loading ? ( // 로딩 중일 때만 Pending 컴포넌트를 표시 ) : error ? ( -
{error}
// 에러 메시지 표시 +
+ Empty Data +
// 에러 메시지 대신 Empty Data 표시 ) : ( <> {/* 하위 컴포넌트에 필요한 데이터 전달 */} diff --git a/src/components/Mypage/Goals/Setting/TeamsRoutine.tsx b/src/components/Mypage/Goals/Setting/TeamsRoutine.tsx index 80e33fd5..f103b206 100644 --- a/src/components/Mypage/Goals/Setting/TeamsRoutine.tsx +++ b/src/components/Mypage/Goals/Setting/TeamsRoutine.tsx @@ -52,4 +52,4 @@ const TeamsRoutine: React.FC = ({ routineData }) => { ); }; -export default TeamsRoutine; \ No newline at end of file +export default TeamsRoutine; diff --git a/src/components/RandomCloudBackgroud.tsx b/src/components/RandomCloudBackgroud.tsx index f11ca063..df28724d 100644 --- a/src/components/RandomCloudBackgroud.tsx +++ b/src/components/RandomCloudBackgroud.tsx @@ -66,7 +66,7 @@ const RandomCloudBackground: React.FC = () => { }, [location.pathname]); // 경로 변경 시마다 좌표 세트 변경 return ( -
+
{cloudImages.map((cloud, index) => (