diff --git a/components/molecules/cards/PostThumbnailCard.tsx b/components/molecules/cards/PostThumbnailCard.tsx index f5343d25b..e046a6324 100644 --- a/components/molecules/cards/PostThumbnailCard.tsx +++ b/components/molecules/cards/PostThumbnailCard.tsx @@ -2,11 +2,16 @@ import { Box, Flex } from "@chakra-ui/react"; import dayjs from "dayjs"; import Image from "next/image"; import Link from "next/link"; +import { useEffect, useState } from "react"; import styled from "styled-components"; +import { STUDY_PREFERENCE_LOCAL } from "../../../constants/keys/queryKeys"; +import { useToast } from "../../../hooks/custom/CustomToast"; +import { useStudyPreferenceMutation } from "../../../hooks/study/mutations"; import { SingleLineText } from "../../../styles/layout/components"; import { IImageProps } from "../../../types/components/assetTypes"; import { ITextAndColorSchemes } from "../../../types/components/propTypes"; +import { IStudyVotePlaces } from "../../../types/models/studyTypes/studyInterActions"; import { IUserSummary } from "../../../types/models/userTypes/userInfoTypes"; import { dayjsToFormat } from "../../../utils/dateTimeUtils"; import OutlineBadge from "../../atoms/badges/OutlineBadge"; @@ -23,8 +28,9 @@ export interface IPostThumbnailCard { statusText?: string; maxCnt?: number; func?: () => void; - registerDate?: string; + isPreferPlace?: boolean; + id?: string; } interface IPostThumbnailCardObj { @@ -43,8 +49,13 @@ export function PostThumbnailCard({ func = undefined, type, registerDate, + isPreferPlace, + id, }, }: IPostThumbnailCardObj) { + const toast = useToast(); + + const userAvatarArr = participants ?.filter((par) => par) .map((par) => ({ @@ -54,6 +65,45 @@ export function PostThumbnailCard({ const CLOSED_TEXT_ARR = ["모집 마감", "닫힘"]; + const [isHeart, setIsHeart] = useState(isPreferPlace); + + useEffect(() => { + setIsHeart(isPreferPlace); + }, [isPreferPlace]); + + const { mutate: setStudyPreference } = useStudyPreferenceMutation({ + onSuccess() { + toast("success", "변경되었습니다."); + }, + }); + + const toggleHeart = (e: React.MouseEvent) => { + e.preventDefault(); + const preferenceStorage = localStorage.getItem(STUDY_PREFERENCE_LOCAL); + const savedPrefer = JSON.parse(preferenceStorage) as IStudyVotePlaces; + + const newPrefer = { ...savedPrefer }; + if (isHeart) { + if (savedPrefer.place === id) { + newPrefer.place = savedPrefer.subPlace?.[0]; + newPrefer.subPlace = savedPrefer.subPlace.filter((sub) => sub !== newPrefer.place); + } else { + newPrefer.subPlace = savedPrefer.subPlace.filter((sub) => sub !== id); + } + } else { + if (newPrefer?.place) { + newPrefer.subPlace = [...savedPrefer.subPlace, id]; + } else { + newPrefer.place = id; + } + } + setIsHeart((old) => !old); + + localStorage.setItem(STUDY_PREFERENCE_LOCAL, JSON.stringify(newPrefer as IStudyVotePlaces)); + + setStudyPreference(newPrefer); + }; + return ( @@ -72,6 +122,23 @@ export function PostThumbnailCard({ sizes="100px" priority={image.priority} /> + {type === "study" && ( + + {isHeart ? ( + + ) : ( + + )} + + )} diff --git a/components/organisms/Calendar.tsx b/components/organisms/Calendar.tsx index 709ebe8f2..9a30a3b1a 100644 --- a/components/organisms/Calendar.tsx +++ b/components/organisms/Calendar.tsx @@ -119,7 +119,7 @@ function Calendar({ monthFirstDate, calendarContents }: CalendarProps) { const isToday = false; const contentArr = getDaySchedules(item); - console.log(5, Object.values(daySchedules)); + const dateInfo = Object.values(daySchedules).map((title) => { return contentArr?.find((c) => c.content === title); // return contentArr[index]; // 순서를 고려하여 index에 해당하는 요소를 선택 @@ -127,7 +127,7 @@ function Calendar({ monthFirstDate, calendarContents }: CalendarProps) { endingSchedules.forEach((item) => deleteSchedule(item)); endingSchedules = []; - console.log(dateInfo); + return ( void; } export function CardColumnLayout({ cardDataArr, url, func }: ICardColumnLayout) { + return ( {cardDataArr.map((cardData, idx) => ( diff --git a/libs/study/sortStudyVoteData.ts b/libs/study/sortStudyVoteData.ts index 9df451ef1..814da094d 100644 --- a/libs/study/sortStudyVoteData.ts +++ b/libs/study/sortStudyVoteData.ts @@ -1,6 +1,11 @@ import { IParticipation, StudyStatus } from "../../types/models/studyTypes/studyDetails"; +import { IStudyVotePlaces } from "../../types/models/studyTypes/studyInterActions"; -export const sortStudyVoteData = (participations: IParticipation[], isConfirmed?: boolean) => { +export const sortStudyVoteData = ( + participations: IParticipation[], + preferPlaces?: IStudyVotePlaces, + isConfirmed?: boolean, +) => { const getCount = (participation: IParticipation) => { if (!isConfirmed) return participation.attendences.length; return participation.attendences.filter((who) => who.firstChoice).length; @@ -16,6 +21,13 @@ export const sortStudyVoteData = (participations: IParticipation[], isConfirmed? } }; + const getPlacePriority = (placeId: string) => { + if (!preferPlaces) return; + if (placeId === preferPlaces.place) return 1; // main이면 가장 높은 우선순위 + if (preferPlaces.subPlace.includes(placeId)) return 2; // sub 배열에 있으면 그다음 우선순위 + return 3; // 그 외는 낮은 우선순위 + }; + const sortedData = participations .map((par) => ({ ...par, @@ -25,8 +37,12 @@ export const sortStudyVoteData = (participations: IParticipation[], isConfirmed? const aStatusPriority = getStatusPriority(a.status); const bStatusPriority = getStatusPriority(b.status); if (aStatusPriority !== bStatusPriority) return aStatusPriority - bStatusPriority; + const countDiff = getCount(b) - getCount(a); + if (countDiff !== 0) return countDiff; + const aPlacePriority = getPlacePriority(a.place._id); + const bPlacePriority = getPlacePriority(b.place._id); - return getCount(b) - getCount(a); + return aPlacePriority - bPlacePriority; }); return isConfirmed ? sortedData : sortedData.filter((par) => par.place.brand !== "자유 신청"); diff --git a/pageTemplates/home/study/HomeNewStudySpace.tsx b/pageTemplates/home/study/HomeNewStudySpace.tsx index 915d0f541..bbcee93ba 100644 --- a/pageTemplates/home/study/HomeNewStudySpace.tsx +++ b/pageTemplates/home/study/HomeNewStudySpace.tsx @@ -25,6 +25,7 @@ function HomeNewStudySpace({ places }: HomeNewStudySpaceProps) { badge: { text: "신규 오픈", colorScheme: "red" }, type: "study", registerDate: place.registerDate, + id: place._id, })); return ( diff --git a/pageTemplates/home/study/HomeStudyCol.tsx b/pageTemplates/home/study/HomeStudyCol.tsx index 8e16c4daa..6ce28b5e3 100644 --- a/pageTemplates/home/study/HomeStudyCol.tsx +++ b/pageTemplates/home/study/HomeStudyCol.tsx @@ -14,6 +14,7 @@ import { CardColumnLayoutSkeleton, } from "../../../components/organisms/CardColumnLayout"; import { STUDY_CHECK_POP_UP, STUDY_VOTING_TABLE } from "../../../constants/keys/localStorage"; +import { STUDY_PREFERENCE_LOCAL } from "../../../constants/keys/queryKeys"; import { LOCATION_RECRUITING, LOCATION_TO_FULLNAME } from "../../../constants/location"; import { STUDY_DATE_START_HOUR, @@ -29,7 +30,10 @@ import { studyDateStatusState, } from "../../../recoils/studyRecoils"; import { IParticipation, StudyStatus } from "../../../types/models/studyTypes/studyDetails"; -import { StudyVotingSave } from "../../../types/models/studyTypes/studyInterActions"; +import { + IStudyVotePlaces, + StudyVotingSave, +} from "../../../types/models/studyTypes/studyInterActions"; import { InactiveLocation, LocationEn } from "../../../types/services/locationTypes"; import { convertLocationLangTo } from "../../../utils/convertUtils/convertDatas"; import { dayjsToStr } from "../../../utils/dateTimeUtils"; @@ -57,15 +61,28 @@ function HomeStudyCol({ studyVoteData, isLoading }: HomeStudyColProps) { const { mutate: decideStudyResult } = useStudyResultDecideMutation(date); + const preferenceStorage = JSON.parse( + localStorage.getItem(STUDY_PREFERENCE_LOCAL), + ) as IStudyVotePlaces; + useEffect(() => { if (!studyVoteData || !studyVoteData.length || !session?.user || !studyDateStatus) { setMyStudy(undefined); setStudyCardColData(null); return; } - const sortedData = sortStudyVoteData(studyVoteData, studyDateStatus !== "not passed"); + const sortedData = sortStudyVoteData( + studyVoteData, + preferenceStorage, + studyDateStatus !== "not passed", + ); - const cardList = setStudyDataToCardCol(sortedData, date as string, session?.user.uid); + const cardList = setStudyDataToCardCol( + sortedData, + date as string, + session?.user.uid, + preferenceStorage ? [preferenceStorage?.place, ...(preferenceStorage?.subPlace || [])] : [], + ); setStudyCardColData(cardList.slice(0, 3)); setSortedStudyCardList(cardList); @@ -172,6 +189,7 @@ export const setStudyDataToCardCol = ( studyData: IParticipation[], urlDateParam: string, uid: string, + preferPlaces: string[], ): IPostThumbnailCard[] => { const privateStudy = studyData.find((par) => par.place.brand === "자유 신청"); const filteredData = studyData.filter((par) => par.place.brand !== "자유 신청"); @@ -192,6 +210,8 @@ export const setStudyDataToCardCol = ( type: "study", statusText: data.status === "pending" && data.attendences.some((who) => who.user.uid === uid) && "GOOD", + isPreferPlace: preferPlaces?.includes(data.place._id), + id: data.place._id, })); return cardColData; diff --git a/pageTemplates/vote/VoteDrawer.tsx b/pageTemplates/vote/VoteDrawer.tsx index e939c779f..1599cb88d 100644 --- a/pageTemplates/vote/VoteDrawer.tsx +++ b/pageTemplates/vote/VoteDrawer.tsx @@ -4,7 +4,7 @@ import { useEffect, useState } from "react"; import BottomDrawerLg from "../../components/organisms/drawer/BottomDrawerLg"; import { STUDY_PREFERENCE_LOCAL } from "../../constants/keys/queryKeys"; import { useStudyPreferenceQuery } from "../../hooks/study/queries"; -import { PreferStorageProps, StudyVoteMapActionType } from "../../pages/vote"; +import { StudyVoteMapActionType } from "../../pages/vote"; import { DispatchType } from "../../types/hooks/reactTypes"; import { IParticipation, IPlace } from "../../types/models/studyTypes/studyDetails"; import { @@ -34,13 +34,14 @@ function VoteDrawer({ studyVoteData, myVote, setMyVote, setActionType }: VoteDra const { data: studyPreference } = useStudyPreferenceQuery({ enabled: !preferenceStorage, - onSuccess() { + onSuccess(data) { + localStorage.setItem(STUDY_PREFERENCE_LOCAL, JSON.stringify(data)); setMyVote(null); }, }); const savedPrefer = preferenceStorage - ? (JSON.parse(preferenceStorage) as PreferStorageProps)?.prefer + ? (JSON.parse(preferenceStorage) as IStudyVotePlaces) : studyPreference; const savedPreferPlace: { place: IPlace; subPlace: IPlace[] } = savedPrefer && { diff --git a/pageTemplates/vote/voteDrawer/VoteDrawerItem.tsx b/pageTemplates/vote/voteDrawer/VoteDrawerItem.tsx index 93f067722..ec343b4bc 100644 --- a/pageTemplates/vote/voteDrawer/VoteDrawerItem.tsx +++ b/pageTemplates/vote/voteDrawer/VoteDrawerItem.tsx @@ -1,19 +1,15 @@ import { Box, Flex } from "@chakra-ui/react"; -import dayjs from "dayjs"; import styled from "styled-components"; import { STUDY_PREFERENCE_LOCAL } from "../../../constants/keys/queryKeys"; import { useToast } from "../../../hooks/custom/CustomToast"; import { useStudyPreferenceMutation } from "../../../hooks/study/mutations"; -import { PreferStorageProps } from "../../../pages/vote"; import { DispatchType } from "../../../types/hooks/reactTypes"; import { IStudyVotePlaces, IStudyVoteWithPlace, } from "../../../types/models/studyTypes/studyInterActions"; -import { dayjsToStr } from "../../../utils/dateTimeUtils"; import { VoteDrawerItemProps as ItemProps } from "../VoteDrawer"; - interface VoteDrawerItemProps { item: ItemProps; savedPrefer: IStudyVotePlaces; @@ -97,17 +93,11 @@ function VoteDrawerItem({ } } - localStorage.setItem( - STUDY_PREFERENCE_LOCAL, - JSON.stringify({ - prefer: newPrefer, - date: dayjsToStr(dayjs()), - } as PreferStorageProps), - ); + localStorage.setItem(STUDY_PREFERENCE_LOCAL, JSON.stringify(newPrefer as IStudyVotePlaces)); setStudyPreference(newPrefer); }; - console.log(item.place); + return ( (); - console.log(gather); + const [transferGather, setTransferGather] = useRecoilState(transferGatherDataState); const { data: gatherData } = useGatherIDQuery(+id, { enabled: !!id && !transferGather }); - console.log(23, gatherData); + useEffect(() => { if (gatherData) { setGather(gatherData); diff --git a/pages/gather/[id]/setting.tsx b/pages/gather/[id]/setting.tsx index 042f6102e..aef408802 100644 --- a/pages/gather/[id]/setting.tsx +++ b/pages/gather/[id]/setting.tsx @@ -107,7 +107,7 @@ function Setting() { {modalType === "inviteMember" && setModalType(null)} />} {modalType === "waitingMember" && ( - setModalType(null)}> + setModalType(null)}> {waitingMembers?.map((who, idx) => ( { if (!studyVoteData || !myVote?.place || myVote?.subPlace) return; @@ -105,7 +103,6 @@ export default function StudyVoteMap() { handleMarker={(place) => setMyVote((old) => setVotePlaceInfo(place, old))} /> - {studyVoteData && ( )} -