From 53468045aa8faa33d7198c1f78448c3e0f8faae3 Mon Sep 17 00:00:00 2001 From: sinamong0620 Date: Thu, 28 Nov 2024 16:18:16 +0900 Subject: [PATCH] #116 fix : v2 2nd sprint fix --- src/App.tsx | 10 +- src/api/ChallengeApi.ts | 2 - src/api/MyPageApi.ts | 37 ++++- src/api/PersonalBlockApi.ts | 8 ++ src/components/AlarmBlock.tsx | 29 ++-- src/components/DashBoardLayout.tsx | 4 - src/components/DeleteButton.tsx | 71 ++++++++- src/components/Friend/Friend.tsx | 10 +- src/components/Navbar.tsx | 1 + src/components/PersonalDashboard.tsx | 30 ++-- src/components/Wrapper.tsx | 22 +++ src/hooks/useItems.ts | 1 + src/hooks/useSSE.ts | 4 +- src/hooks/useTeamItems.ts | 2 + src/pages/ChallengeDetailPage.tsx | 41 +++++- src/pages/CreateTeamBoardPage.tsx | 41 +++++- src/pages/FriendPage.tsx | 206 +++++++++++++++++++++++++++ src/pages/MyPage.tsx | 8 +- src/pages/TeamDocument.tsx | 5 - src/styles/ChallengeStyled.tsx | 2 + src/styles/CreateBoardPageStyled.tsx | 8 ++ src/styles/DashboardStyled.tsx | 4 +- src/styles/MainPageStyled.tsx | 32 ++++- src/styles/MyPageStyled.tsx | 1 + src/types/ChallengeType.ts | 1 + src/types/MyPage.ts | 16 +++ src/types/UserInfo.ts | 3 +- src/utils/columnsConfig.ts | 2 +- 28 files changed, 527 insertions(+), 74 deletions(-) create mode 100644 src/components/Wrapper.tsx create mode 100644 src/pages/FriendPage.tsx diff --git a/src/App.tsx b/src/App.tsx index 7c69e6d..01e91eb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useState } from 'react'; import { Routes, Route } from 'react-router-dom'; -// import MainPage from './pages/MainPage'; import LoginPage from './pages/LoginPage'; import MyPage from './pages/MyPage'; import CreateBoard from './pages/CreateBoardPage'; @@ -36,6 +35,7 @@ import { useSSE } from './hooks/useSSE'; import FriendsPage from './pages/FriendsPage/FriendsPage'; import FriendsSearchPage from './pages/FriendsSearchPage/FriendsSearchPage'; import RecommendedFriendsPage from './pages/RecommendedFriendsPage/RecommendedFriendsPage'; +import FriendPage from './pages/FriendPage'; const queryClient = new QueryClient(); @@ -196,6 +196,14 @@ const App = () => { } /> + + + + } + /> => { try { const response = await axiosInstance.get(`/challenges/${challengeId}`); - // console.log(response.data.data); - return response.data.data; } catch (error) { console.error('Error fetching data:', error); diff --git a/src/api/MyPageApi.ts b/src/api/MyPageApi.ts index a12010d..2af24bb 100644 --- a/src/api/MyPageApi.ts +++ b/src/api/MyPageApi.ts @@ -1,4 +1,10 @@ -import { NotificationResponse, ProfileInfo, ReturnData } from '../types/MyPage'; +import { + FriendBlock, + FrinedProfile, + NotificationResponse, + ProfileInfo, + ReturnData, +} from '../types/MyPage'; import { axiosInstance } from '../utils/apiConfig'; // * 마이페이지 프로필 조회 @@ -20,13 +26,28 @@ export const fetchBlockData = async ( const res = await axiosInstance.get( `/members/mypage/dashboard-challenges?requestEmail=${email}&page=${pageNum}&size=6` ); - console.log(res); return res.data as ReturnData; } catch (error) { console.error('Error fetching data:', error); } }; +// * 친구 마이페이지에서 개인,팀,챌린지 블록 데이터 받아오기 +export const fetchFriendBlockData = async ( + pageNum: number, + friendId: string +): Promise => { + try { + const res = await axiosInstance.get( + `/members/mypage/${friendId}/dashboard-challenges?page=${pageNum}&size=6` + ); + console.log(res.data.data); + return res.data.data as FriendBlock; + } catch (error) { + console.error('Error fetching data:', error); + } +}; + // * 알람 리스트 전체 조회 export const getAlarmList = async (): Promise => { try { @@ -63,8 +84,18 @@ export const updateAlarmIsRead = async () => { export const acceptFriendAlarm = async (followId: string) => { try { const response = await axiosInstance.post(`/member/follow/accept/${followId}`); - console.log(response); } catch (error) { console.error('Error fetching data :', error); + throw error; + } +}; + +// * 친구 마이페이지 프로필 조회 +export const friendProfile = async (friendId: string) => { + try { + const res = await axiosInstance.get(`/members/mypage/${friendId}`); + return res.data; + } catch (error) { + console.error('Error fetching data:', error); } }; diff --git a/src/api/PersonalBlockApi.ts b/src/api/PersonalBlockApi.ts index e219336..3bdd31a 100644 --- a/src/api/PersonalBlockApi.ts +++ b/src/api/PersonalBlockApi.ts @@ -99,3 +99,11 @@ export const restoreBlockFunc = async (blockId: string) => { console.error('Error fetching data:', error); } }; + +export const entireDeleteBlock = async (dashboardId: string) => { + try { + await axiosInstance.delete(`/blocks/permanent?dashboardId=${dashboardId}`); + } catch (error) { + console.error('Error fetching data:', error); + } +}; diff --git a/src/components/AlarmBlock.tsx b/src/components/AlarmBlock.tsx index 75a8dd7..672eca6 100644 --- a/src/components/AlarmBlock.tsx +++ b/src/components/AlarmBlock.tsx @@ -6,12 +6,14 @@ import { customErrToast } from '../utils/customErrorToast'; import { useAtom } from 'jotai'; import { navbarUpdateTriggerAtom } from '../contexts/atoms'; import { acceptFriendAlarm } from '../api/MyPageApi'; +import axios from 'axios'; type Props = { message: string; isRead: boolean; }; const AlarmBlock = ({ message, isRead }: Props) => { + console.log(message); let modifiedMessage = ''; let followerIdMatch: string = ''; @@ -44,19 +46,22 @@ const AlarmBlock = ({ message, isRead }: Props) => { const index = message.indexOf('챌린지 블록이 생성되었습니다'); nameMatch = message.slice(0, index).trim(); description = '챌린지 블록이 생성됐어요'; - } else if (message.includes('친구 신청을 보냈습니다.')) { - nameMatch = `${message.split('님')[0]}님이`; + } else if (message.includes('친구 추가 요청')) { + nameMatch = `${message.split(':')[1].split('님')[0].trim()}님이`; description = `친구 요청을 보냈어요!`; + } else if (message.includes('친구 추가 수락')) { + nameMatch = `${message.split(':')[1].split('님')[0].trim()}님이`; + description = `친구 요청을 수락했어요!`; } else { const index = message.indexOf('님'); nameMatch = `반가워요! ${message.slice(message.indexOf(' ') + 5, index)}님이`; description = `챌린지에 참여했어요`; } const numberMatch = modifiedMessage.match(/\d+$/); - const name = nameMatch ? nameMatch : null; const dashboard = dashboardMatch ? dashboardMatch[0] : null; const number = numberMatch ? numberMatch[0] : ''; + const [, setUpdate] = useAtom(navbarUpdateTriggerAtom); const onAcceptHandler = async () => { @@ -68,8 +73,16 @@ const AlarmBlock = ({ message, isRead }: Props) => { }; const onAcceptFriend = async () => { - await acceptFriendAlarm(followerIdMatch); - customErrToast(`${message.split('님')[0]}님의 친구요청을 수락했어요!`); + try { + const response = await acceptFriendAlarm(followerIdMatch); + customErrToast(`${message.split('님')[0]}님의 친구요청을 수락했어요!`); + } catch (error) { + if (axios.isAxiosError(error)) { + if (error.response?.status === 403) { + customErrToast(`친구요청을 이미 수락했어요!`); + } + } + } }; return ( @@ -80,11 +93,7 @@ const AlarmBlock = ({ message, isRead }: Props) => {

{description}

{number !== '' ? : ''} - {message.includes('친구 신청을 보냈습니다.') === true ? ( - - ) : ( - '' - )} + {followerIdMatch !== '' ? : ''} ); diff --git a/src/components/DashBoardLayout.tsx b/src/components/DashBoardLayout.tsx index 1cbb531..d4bb438 100644 --- a/src/components/DashBoardLayout.tsx +++ b/src/components/DashBoardLayout.tsx @@ -1,9 +1,5 @@ -import { Helmet } from 'react-helmet-async'; import Navbar from './Navbar'; -import Header from './Header'; import * as S from '../styles/MainPageStyled'; -import { DeleteButton } from '@blocknote/react'; -import { DragDropContext } from 'react-beautiful-dnd'; interface DashBoardLayoutProps { children: React.ReactNode; // children의 타입을 명시합니다. diff --git a/src/components/DeleteButton.tsx b/src/components/DeleteButton.tsx index c11f97e..59d007e 100644 --- a/src/components/DeleteButton.tsx +++ b/src/components/DeleteButton.tsx @@ -3,7 +3,14 @@ import deleteicon from '../img/delete2.png'; import * as S from '../styles/MainPageStyled'; import { Droppable } from 'react-beautiful-dnd'; import Block from './Block'; -import { BlockListResDto, DeletedBlockList } from '../types/PersonalBlock'; +import { BlockListResDto } from '../types/PersonalBlock'; +import Flex from './Flex'; +import useModal from '../hooks/useModal'; +import CustomModal from './CustomModal'; +import { useLocation } from 'react-router-dom'; +import { entireDeleteBlock } from '../api/PersonalBlockApi'; +import { useAtom } from 'jotai'; +import { fetchTriggerAtom } from '../contexts/atoms'; interface Props { id: string; @@ -11,8 +18,13 @@ interface Props { removeValue: boolean; } const DeleteButton = ({ id, list, removeValue }: Props) => { + const [isHovering, setIsHovering] = useState(false); + const { isModalOpen, openModal, handleYesClick, handleNoClick } = useModal(); const [value, setValue] = useState(false); - const [blockId, setBlockId] = useState(''); + const [, setBlockId] = useState(''); + const [, setFetchTrigger] = useAtom(fetchTriggerAtom); + const location = useLocation(); + const dashboardId = location.pathname.split('/')[2]; const onValueFunction = () => { setValue(value => !value); @@ -22,13 +34,35 @@ const DeleteButton = ({ id, list, removeValue }: Props) => { if (num) setBlockId(num); }; + const onEntireDeleteBlock = async () => { + if (dashboardId) await entireDeleteBlock(dashboardId); + setFetchTrigger(prev => prev + 1); // 상태를 변경하여 MainPage에서 데이터를 다시 불러오도록 트리거 + }; + const onDeleteHandler = () => { + openModal('yes', onEntireDeleteBlock); + }; + const onDragEnter = () => { + setIsHovering(true); + console.log('아니 되는거 맞음?'); + }; + + const onDragLeave = () => { + setIsHovering(false); + }; + useEffect(() => { + handleNoClick(); + }, [location]); + return ( {value && ( {provided => ( -

휴지통

+ +

휴지통

+ +
{list.map( ( @@ -60,9 +94,34 @@ const DeleteButton = ({ id, list, removeValue }: Props) => { )}
)} - - 휴지통아이콘 - + + {(provided, snapshot) => ( +
+ + 휴지통아이콘 + + {provided.placeholder} +
+ )} +
+ {isModalOpen && ( + + )}
); }; diff --git a/src/components/Friend/Friend.tsx b/src/components/Friend/Friend.tsx index a930003..236088f 100644 --- a/src/components/Friend/Friend.tsx +++ b/src/components/Friend/Friend.tsx @@ -4,6 +4,7 @@ import CustomModal from '../CustomModal'; import useModal from '../../hooks/useModal'; import { useState } from 'react'; import { useDeleteFollow, usePostFollow } from '../../hooks/useFollowersList'; +import { useNavigate } from 'react-router-dom'; interface FriendProps { follower: FollowInfo; @@ -15,9 +16,11 @@ const Friend = ({ follower }: FriendProps) => { const { mutate: followMutate } = usePostFollow(follower.memberId!, follower.name!); const { mutate: unFollowMutate } = useDeleteFollow(follower.memberId!, follower.name!); + const navigate = useNavigate(); - const follow = async () => { + const follow = async (e: React.MouseEvent) => { followMutate(); + e.stopPropagation(); }; const unFollow = async () => { @@ -25,15 +28,16 @@ const Friend = ({ follower }: FriendProps) => { }; // 친구 삭제를 모달창으로 확인 - const submitUnFollow = () => { + const submitUnFollow = (e: React.MouseEvent) => { setIsDelModalOpen(true); const handleModalClose = () => setIsDelModalOpen(false); openModal('yes', unFollow, handleModalClose); + e.stopPropagation(); }; return ( <> - + navigate(`/friendpage/${follower.memberId}`)}>

{follower.name}

diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 73fe1c0..e52294a 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -27,6 +27,7 @@ const Navbar = () => { queryKey: ['userinfo'], queryFn: userInfoApi, }); + const [nickname, setNickname] = useAtom(nicknameAtom); const [update] = useAtom(navbarUpdateTriggerAtom); diff --git a/src/components/PersonalDashboard.tsx b/src/components/PersonalDashboard.tsx index e8589da..37808b5 100644 --- a/src/components/PersonalDashboard.tsx +++ b/src/components/PersonalDashboard.tsx @@ -1,15 +1,14 @@ -import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { getPersonalBlock, getPersonalDashboard } from '../api/BoardApi'; +import { useQuery } from '@tanstack/react-query'; +import { getPersonalDashboard } from '../api/BoardApi'; import { deleteBlock, - getDeleteBlock, restoreBlockFunc, updateOrderBlock, updatePersonalBlock, } from '../api/PersonalBlockApi'; import DashBoardLayout from './DashBoardLayout'; import Header from './Header'; -import { Outlet, useLocation } from 'react-router-dom'; +import { Outlet, useLocation, useSearchParams } from 'react-router-dom'; import NotStartedDashboard from './NotStartedDashboard'; import InProgressDashboard from './InProgressDashboard'; import CompletedDashboard from './CompletedDashboard'; @@ -20,7 +19,7 @@ import DeleteButton from './DeleteButton'; import { TItems, TItemStatus } from '../utils/columnsConfig'; import useItems from '../hooks/useItems'; import { BlockListResDto } from '../types/PersonalBlock'; -import { useSSE } from '../hooks/useSSE'; +import Wrapper from './Wrapper'; type PageState = { todo: number; // 할 일 페이지 번호 @@ -30,8 +29,8 @@ type PageState = { const PersonalDashBoard = () => { const location = useLocation(); + const isWrapperTrue = location.state?.wrapper; const dashboardId = location.pathname.split('/')[2]; - // const [page, setPage] = useState(0); const [todoPage, setTodoPage] = useState(0); const [doingPage, setDoingPage] = useState(0); const [page, setPage] = useState({ @@ -100,6 +99,7 @@ const PersonalDashBoard = () => { const blockId = targetItem.blockId; if (blockId) { + if (destinationKey === 'icon') return; if (destinationKey !== 'delete') { updatePersonalBlock(blockId, status(destinationKey)); // 블록 상태 업데이트 } else { @@ -136,13 +136,19 @@ const PersonalDashBoard = () => { return; } const [targetItem] = _items[sourceKey].splice(source.index, 1); - _items[destinationKey].splice(destination.index, 0, targetItem); + if (destinationKey === 'icon') { + _items['delete'].splice(destination.index, 0, targetItem); + } else { + _items[destinationKey].splice(destination.index, 0, targetItem); + } setItems(_items); if (sourceKey !== destinationKey) { updateState(destinationKey, sourceKey, targetItem); } - + if (destination.droppableId === 'icon') { + console.log('icon'); + } //시작점 상태에서 종착지가 시작점 상태와는 다른 상태일때 그 아이템 개수 -1 if (source.droppableId === 'todo' && destination.droppableId !== 'todo') setBlockTotal(prev => ({ @@ -176,8 +182,8 @@ const PersonalDashBoard = () => { }; return ( - <> - + +
{ - - + + ); }; export default PersonalDashBoard; diff --git a/src/components/Wrapper.tsx b/src/components/Wrapper.tsx new file mode 100644 index 0000000..15e10a0 --- /dev/null +++ b/src/components/Wrapper.tsx @@ -0,0 +1,22 @@ +import { useState } from 'react'; +import * as S from '../styles/MainPageStyled'; + +const Wrapper = ({ + children, + isWrapperTrue, +}: { + children: React.ReactNode; + isWrapperTrue: boolean; +}) => { + return ( +
+ {isWrapperTrue && 보기 권한만 있습니다} + {children} +
+ ); +}; +export default Wrapper; diff --git a/src/hooks/useItems.ts b/src/hooks/useItems.ts index c942b04..db88319 100644 --- a/src/hooks/useItems.ts +++ b/src/hooks/useItems.ts @@ -81,6 +81,7 @@ export default function useItems(dashboardId: string, pageParam: PageState, path doing: InProgress?.pages[0]?.blockListResDto || [], completed: Completed?.pages[0]?.blockListResDto || [], delete: DeletedBlock?.blockListResDto || [], + icon: DeletedBlock?.blockListResDto || [], }); const [blockTotal, setBlockTotal] = useState({ diff --git a/src/hooks/useSSE.ts b/src/hooks/useSSE.ts index 64c2f5d..4e62f17 100644 --- a/src/hooks/useSSE.ts +++ b/src/hooks/useSSE.ts @@ -45,8 +45,8 @@ export const useSSE = () => { ); eventSourceRef.current.onmessage = event => { - if (!event.data.includes('연결')) { - const modifiedMessage = event.data.replace(/^[^:]+: /, '').replace(/\d+$/, ''); + if (!event.data.includes('연결') || window.location.href === 'http://localhost:3000/') { + const modifiedMessage = event.data.split('.')[0]; customErrToast(modifiedMessage); setUnReadCount(prev => prev + 1); } diff --git a/src/hooks/useTeamItems.ts b/src/hooks/useTeamItems.ts index f770954..54c5759 100644 --- a/src/hooks/useTeamItems.ts +++ b/src/hooks/useTeamItems.ts @@ -30,6 +30,7 @@ export default function useItems(dashboardId: string) { doing: InProgress?.blockListResDto || [], completed: COMPLETED?.blockListResDto || [], delete: DeletedBlock?.blockListResDto || [], + icon: DeletedBlock?.blockListResDto || [], }); // Update items whenever the fetched data changes @@ -39,6 +40,7 @@ export default function useItems(dashboardId: string) { doing: InProgress?.blockListResDto || [], completed: COMPLETED?.blockListResDto || [], delete: DeletedBlock?.blockListResDto || [], + icon: DeletedBlock?.blockListResDto || [], }); }, [NotStarted, InProgress, COMPLETED, DeletedBlock]); diff --git a/src/pages/ChallengeDetailPage.tsx b/src/pages/ChallengeDetailPage.tsx index 4e16d62..83a81ed 100644 --- a/src/pages/ChallengeDetailPage.tsx +++ b/src/pages/ChallengeDetailPage.tsx @@ -19,6 +19,8 @@ import CustomModal from '../components/CustomModal'; import useModal from '../hooks/useModal'; import JoinChallengeModal from '../components/JoinChallengeModal'; import { Helmet } from 'react-helmet-async'; +import { userInfoApi } from '../api/UserApi'; +import { useQuery } from '@tanstack/react-query'; const ChallengeDetailPage = () => { const navigate = useNavigate(); @@ -34,6 +36,11 @@ const ChallengeDetailPage = () => { const [isDelModalOpen, setIsDelModalOpen] = useState(false); const [isWithdrawModalOpen, setIsWithdrawModalOpen] = useState(false); + const { data: UserInfo, refetch: refetchTeamDashboard } = useQuery({ + queryKey: ['userinfo'], + queryFn: userInfoApi, + }); + // * 챌린지 상세보기 데이터 받아오기 const fetchedData = async () => { if (challengeId) { @@ -112,6 +119,15 @@ const ChallengeDetailPage = () => { const isWithdrawModalOpen = () => setIsWithdrawModalOpen(false); openModal('yes', cancelChallenge, isWithdrawModalOpen); }; + const onMypage = () => { + navigate(`/mypage`); + }; + + const onFriendPage = (id: string) => { + navigate(`/friendpage/${id}`, { + state: { wrapper: true }, + }); + }; return ( <> @@ -249,8 +265,18 @@ const ChallengeDetailPage = () => { 챌린지 장 - - {challengeData.authorName} + { + if (challengeData.authorId) + String(UserInfo?.data.memberId) === String(challengeData.authorId) + ? onMypage() + : onFriendPage(challengeData.authorId); + }} + > + + {challengeData.authorName} + @@ -263,7 +289,16 @@ const ChallengeDetailPage = () => { {challengeData?.completedMembers && challengeData.completedMembers.length > 0 ? ( challengeData.completedMembers.map((member, index) => ( - + { + if (member.memberId) { + String(UserInfo?.data.memberId) === String(member.memberId) + ? onMypage() + : onFriendPage(member.memberId); + } + }} + > {member.nickname} diff --git a/src/pages/CreateTeamBoardPage.tsx b/src/pages/CreateTeamBoardPage.tsx index 8d60426..f91fa67 100644 --- a/src/pages/CreateTeamBoardPage.tsx +++ b/src/pages/CreateTeamBoardPage.tsx @@ -24,6 +24,7 @@ import { LastLabel, MemberWrapperMemberView, ImgWrapper, + MemberInfo, } from '../styles/CreateBoardPageStyled'; import Flex from '../components/Flex'; import { TeamDashboardInfoResDto } from '../types/TeamDashBoard'; @@ -39,6 +40,8 @@ import { quitTeamDashboard } from '../api/BoardApi'; import { ProfileData } from '../types/UserInfo'; import userDefault from '../img/userDefault.png'; import { Helmet } from 'react-helmet-async'; +import { useQuery } from '@tanstack/react-query'; +import { userInfoApi } from '../api/UserApi'; const CreateTeamBoard = () => { const navigate = useNavigate(); // 페이지 이동을 위한 훅 @@ -180,7 +183,15 @@ const CreateTeamBoard = () => { } else navigate(-1); }; - console.log(formData, '저장된 팀 대시보드 정보'); + const onMypage = () => { + navigate(`/mypage`); + }; + + const onFriendPage = (id: number) => { + navigate(`/friendpage/${id}`, { + state: { wrapper: true }, + }); + }; return ( <> @@ -251,10 +262,18 @@ const CreateTeamBoard = () => { ))} {joinMembers?.map((member, index) => ( - - {member.name} + { + String(isCreator.myId) === String(member.id) + ? onMypage() + : onFriendPage(member.id); + }} + > + + {member.name} + - {member.id !== isCreator.creatorId ? '멤버' : '방장'} + {String(member.id) !== isCreator.creatorId ? '멤버' : '방장'} ))} @@ -288,10 +307,18 @@ const CreateTeamBoard = () => { ))} {joinMembers?.map((member, index) => ( - - {member.name} + { + String(isCreator.myId) === String(member.id) + ? onMypage() + : onFriendPage(member.id); + }} + > + + {member.name} + - {member.id !== isCreator.creatorId ? '멤버' : '방장'} + {String(member.id) !== isCreator.creatorId ? '멤버' : '방장'} ))} diff --git a/src/pages/FriendPage.tsx b/src/pages/FriendPage.tsx new file mode 100644 index 0000000..725fb3b --- /dev/null +++ b/src/pages/FriendPage.tsx @@ -0,0 +1,206 @@ +import { useEffect, useState } from 'react'; +import { useNavigate, useSearchParams } from 'react-router-dom'; +import Navbar from '../components/Navbar'; +import Flex from '../components/Flex'; +import ChallengeBlock from '../components/ChallengeBlock'; +import Profile from '../components/Profile'; +import googleicon from '../img/googleicon.png'; +import kakaologo from '../img/kakaologo.png'; +import * as S from '../styles/MyPageStyled'; +import { ChallengeList, PersonalDashboardList } from '../types/MyPage'; +import { fetchFriendBlockData, friendProfile } from '../api/MyPageApi'; +import { useQuery } from '@tanstack/react-query'; +import Pagination from '@mui/material/Pagination'; +import { Helmet } from 'react-helmet-async'; + +const FriendPage = () => { + const navigate = useNavigate(); + const currentUrl = window.location.href; + const friendId = currentUrl.split('/').pop() || ''; + + const { data } = useQuery({ + queryKey: ['friendProfile', friendId], + queryFn: () => friendProfile(friendId), + }); + + const { data: friendBlock } = useQuery({ + queryKey: ['friendBlock'], + queryFn: () => fetchFriendBlockData(0, friendId), + }); + + const [teamBool, setTeamBool] = useState('personal'); // 기본값으로 팀 탭을 보여줌 + const [pageNumber, setPageNumber] = useState(1); // 페이지네이션 변수 + + //* 개인,팀,챌린지 정보 담는 변수들 + const [personalBlockData, setPersonalBlockData] = useState(); + const [challengeBlockData, setChallengeBlockData] = useState(); + + //* 페이지네이션 변경 시 동작하는 함수 + const onChangePageNation = async (event: React.ChangeEvent, page: number) => { + setPageNumber(page); + const fetchData = await fetchFriendBlockData(page - 1, friendId); + if (teamBool === 'personal') setPersonalBlockData(fetchData?.personalDashboardList); + else if (teamBool === 'challenge') setChallengeBlockData(fetchData?.challengeList); + }; + + //* 개인 버튼 클릭 시 데이터 로드 + const onOpenPersonalFunc = async () => { + setTeamBool('personal'); + setPageNumber(1); + const fetchData = await fetchFriendBlockData(0, friendId); // 첫 페이지 데이터 + setPersonalBlockData(fetchData?.personalDashboardList); + }; + + //* 챌린지 버튼 클릭 시 데이터 로드 + const onOpenChallengeFunc = async () => { + setTeamBool('challenge'); + setPageNumber(1); + const fetchData = await fetchFriendBlockData(0, friendId); // 첫 페이지 데이터 + setChallengeBlockData(fetchData?.challengeList); + }; + + //* 처음 렌더링 시 팀 탭 데이터 호출 + useEffect(() => { + setPersonalBlockData(friendBlock?.personalDashboardList); + setChallengeBlockData(friendBlock?.challengeList); + }, [friendBlock]); + + let content; + if (teamBool === 'personal') { + content = ( + + {personalBlockData?.personalDashboardInfoResDto.length === 0 ? ( + NoContentComponent + ) : ( +
+ + {personalBlockData?.personalDashboardInfoResDto.map((item, idx) => { + const { dashboardId, title, description } = item; + return ( + { + navigate(`/personal/${dashboardId}`, { state: { wrapper: true } }); + }} + > + + + ); + })} + + + + + +
+ )} +
+ ); + } else if (teamBool === 'challenge') { + content = ( + + {challengeBlockData?.challengeInfoResDto.length === 0 ? ( + NoContentComponent + ) : ( +
+ + {challengeBlockData?.challengeInfoResDto.map((item, idx) => { + const { title, contents, cycle, challengeId } = item; + + return ( +
{ + navigate(`/challenge/${challengeId}`, { state: { title: title } }); + }} + > + +
+ ); + })} +
+ + + +
+ )} +
+ ); + } + + return ( + <> + + 끄적끄적 | 마이페이지 + + + + + + + + + + + + {data?.data.name} + + + {data?.data.introduction ? ( + data?.data.introduction + ) : ( + 자기 소개를 작성해주세요 + )} + + + + + + + + + + + + + {content} + + + + + ); +}; + +export default FriendPage; + +const NoContentComponent = ( + + + 참여 내역이 없습니다. + + +); diff --git a/src/pages/MyPage.tsx b/src/pages/MyPage.tsx index d936918..fcd73b7 100644 --- a/src/pages/MyPage.tsx +++ b/src/pages/MyPage.tsx @@ -6,13 +6,10 @@ import AlarmBlock from '../components/AlarmBlock'; import ProfileUpdateModal from '../components/ProfileUpdateModal'; import ChallengeBlock from '../components/ChallengeBlock'; import Profile from '../components/Profile'; - import googleicon from '../img/googleicon.png'; import kakaologo from '../img/kakaologo.png'; import bell from '../img/bell.png'; - import * as S from '../styles/MyPageStyled'; - import { ChallengeList, PersonalDashboardList, TeamDashboardList } from '../types/MyPage'; import { fetchBlockData, fetchData, getAlarmList, updateAlarmIsRead } from '../api/MyPageApi'; import { useAtom } from 'jotai'; @@ -29,9 +26,9 @@ const MyPage = () => { queryKey: ['alarmNoti'], queryFn: getAlarmList, }); + console.log(alarmNoti); const { data: followersList } = useFollowersList(0, 8); - console.log(alarmNoti); const [teamBool, setTeamBool] = useState('personal'); // 기본값으로 팀 탭을 보여줌 const [pageNumber, setPageNumber] = useState(1); // 페이지네이션 변수 @@ -183,7 +180,6 @@ const MyPage = () => { {teamBlockData?.teamDashboardInfoResDto.map((item, idx) => { const { dashboardId, title, joinMembers, description } = item; - console.log(dashboardId, title); return ( - 챌린지 참여 내역이 없습니다. + 참여 내역이 없습니다. ); diff --git a/src/pages/TeamDocument.tsx b/src/pages/TeamDocument.tsx index 94fb86f..3499447 100644 --- a/src/pages/TeamDocument.tsx +++ b/src/pages/TeamDocument.tsx @@ -29,10 +29,6 @@ import { import * as S from '../styles/TeamDocumentStyled'; import { useTeamDocument } from '../hooks/useTeamDocument'; import { BlockNoteView } from '@blocknote/mantine'; -import useInterval from '../hooks/useInterval'; -import { getPersonalBlock } from '../api/PersonalBlockApi'; -import { BlockListResDto } from '../types/PersonalBlock'; -import Navbar from '../components/Navbar'; import useInfo from '../hooks/useInfo'; import { deleteTeamDocument } from '../api/TeamDocumentApi'; import useModal from '../hooks/useModal'; @@ -49,7 +45,6 @@ const TeamDocument = () => { const teamDocumentId = segments[3]; // Assuming /15 is the teamDocumentId const { progress } = location.state || {}; - const { info } = useInfo(); const { data, categories, handleInputChange, onChange, editor, SubmitData } = useTeamDocument( teamDashboardId, diff --git a/src/styles/ChallengeStyled.tsx b/src/styles/ChallengeStyled.tsx index cb508f9..cbc7e8f 100644 --- a/src/styles/ChallengeStyled.tsx +++ b/src/styles/ChallengeStyled.tsx @@ -659,6 +659,7 @@ export const ChallengeCreatorContainer = styled.div` font-size: ${theme.font.size.caption}; color: ${theme.color.gray}; font-weight: ${theme.font.weight.light}; + cursor: pointer; } `; @@ -691,6 +692,7 @@ export const RealTimeComponent = styled.div` flex-direction: column; justify-content: center; align-items: center; + cursor: pointer; `; export const RealTimeUserImg = styled.img` diff --git a/src/styles/CreateBoardPageStyled.tsx b/src/styles/CreateBoardPageStyled.tsx index eef26ce..d3b027b 100644 --- a/src/styles/CreateBoardPageStyled.tsx +++ b/src/styles/CreateBoardPageStyled.tsx @@ -269,6 +269,14 @@ export const MemberEmail = styled.p` color: ${theme.color.black}; `; +export const MemberInfo = styled.div` + display: flex; + align-items: center; + cursor: pointer; + justify-content: space-evenly; + width: 100%; +`; + export const MemberState = styled.p` font-size: 0.75rem; color: ${theme.color.gray}; diff --git a/src/styles/DashboardStyled.tsx b/src/styles/DashboardStyled.tsx index 0bd939d..c881fd4 100644 --- a/src/styles/DashboardStyled.tsx +++ b/src/styles/DashboardStyled.tsx @@ -102,8 +102,8 @@ export const TeamDashboardItem = styled.article` `; export const CardContainer = styled.div` - width: 19.875rem; - height: 39.0625rem; + width: 17.875vw; + height: calc(100vh - 35vh); padding: 1rem 1rem; flex-shrink: 0; border-radius: 10px; diff --git a/src/styles/MainPageStyled.tsx b/src/styles/MainPageStyled.tsx index 29e9009..7cf794d 100644 --- a/src/styles/MainPageStyled.tsx +++ b/src/styles/MainPageStyled.tsx @@ -10,7 +10,7 @@ export const MainDashBoardLayout = styled.div` export const MainDashBoardContainer = styled.section` width: 100%; - padding: 4.3125rem 2.5rem; + padding: 4.3125vw 2.5vw; overflow: hidden; hr { @@ -21,11 +21,11 @@ export const MainDashBoardContainer = styled.section` export const CardContainer = styled.section` display: flex; justify-content: space-between; - padding: 4.5rem 3.8125rem; + padding: 4.5vw 3.8125vw; gap: 39px; @media screen and (min-width: 1700px) { - justify-content: center; + justify-content: space-evenly; } `; @@ -47,8 +47,16 @@ export const DeleteDiv = styled.div` bottom: 20px; right: 20px; border-radius: 0.625rem; - h1 { - margin-bottom: 1rem; + + button { + color: #858585; + background-color: #f4f4f4; + padding: 0.2rem 0.2rem; + border-radius: 0.2rem; + } + + button:not(:first-of-type) { + margin-top: 0.5rem; } `; @@ -81,7 +89,19 @@ export const BoxContainer = styled.section` export const BlockEntireContainer = styled.div` display: grid; grid-template-columns: 85% 5%; - grid-gap: 10px; + grid-gap: 8px; margin-bottom: 1rem; align-items: center; `; + +export const IsReadOnly = styled.div` + position: absolute; + width: calc(100% - 12.5rem); + right: 0px; + top: 0px; + background-color: rgba(0, 0, 0, 0.5); + color: #fff; + padding: 1rem; + border-radius: 0 0 0.5rem 0.5rem; + text-align: center; +`; diff --git a/src/styles/MyPageStyled.tsx b/src/styles/MyPageStyled.tsx index 8acd8bb..cab3a58 100644 --- a/src/styles/MyPageStyled.tsx +++ b/src/styles/MyPageStyled.tsx @@ -78,6 +78,7 @@ export const ChallengeLayout = styled.div` border: 1px solid ${theme.color.stroke2}; padding: 1.1875rem 1.625rem 2.625rem 1.625rem; border-radius: 0.625rem; + cursor: pointer; `; export const ChallengeBoxTitle = styled.span` diff --git a/src/types/ChallengeType.ts b/src/types/ChallengeType.ts index ec9f48b..ce2a21e 100644 --- a/src/types/ChallengeType.ts +++ b/src/types/ChallengeType.ts @@ -16,6 +16,7 @@ export interface Challenge { isParticipant?: false; isAuthor?: true; completedMembers?: completedMember[]; + authorId?: string; } // * 실시간 완료 멤버 타입 diff --git a/src/types/MyPage.ts b/src/types/MyPage.ts index 5d2ec12..4b70252 100644 --- a/src/types/MyPage.ts +++ b/src/types/MyPage.ts @@ -30,6 +30,12 @@ export interface ReturnData { }; } +//* 친구 마이페이지 개인,팀,챌린지 대시보드 타입 +export interface FriendBlock { + personalDashboardList: PersonalDashboardList; + challengeList: ChallengeList; +} + //* 팀 대시보드 정보 타입 interface TeamDashboardInfoResDto { blockProgress: number; @@ -92,3 +98,13 @@ export type NotificationResponse = { notificationInfoResDto: NotificationInfoResDto[]; }; }; + +// * 친구 프로필 조회 +export type FrinedProfile = { + picture: string; + email: string; + name: string; + nickName: string; + socialType: string; + introduction: string; +}; diff --git a/src/types/UserInfo.ts b/src/types/UserInfo.ts index ce292a6..42010a0 100644 --- a/src/types/UserInfo.ts +++ b/src/types/UserInfo.ts @@ -1,11 +1,12 @@ export interface ProfileData { - id?: string; + id: number; picture: string; email: string; name: string; nickName: string; socialType: 'GOOGLE' | 'KAKAO'; introduction: string; + memberId?: number; } export interface UserInfo { diff --git a/src/utils/columnsConfig.ts b/src/utils/columnsConfig.ts index edc2339..732e084 100644 --- a/src/utils/columnsConfig.ts +++ b/src/utils/columnsConfig.ts @@ -3,7 +3,7 @@ import InProgressDashboard from '../components/InProgressDashboard'; import CompletedDashboard from '../components/CompletedDashboard'; import { BlockListResDto } from '../types/PersonalBlock'; -export type TItemStatus = 'todo' | 'doing' | 'completed' | 'delete'; +export type TItemStatus = 'todo' | 'doing' | 'completed' | 'delete' | 'icon'; export type TItems = { [key in TItemStatus]: BlockListResDto[];