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

Env: 여정 중간배포 #190

Merged
merged 9 commits into from
Jan 18, 2024
18 changes: 17 additions & 1 deletion src/api/trips.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@ export const getTripsLike = async (

// 우리의 관심 목록 등록
export const postTripsLike = async (tripId: number, tourItemIds: number[]) => {
const res = await client.post(`trips/${tripId}/tripLikedTours`, tourItemIds);
const requestBody = {
tourItemIds: tourItemIds,
};
const res = await authClient.post(
`trips/${tripId}/tripLikedTours`,
requestBody,
);
return res;
};

Expand All @@ -68,3 +74,13 @@ export const getTripsSurvey = async (tripId: number) => {
const res = await client.get(`trips/${tripId}/survey`);
return res;
};
// 우리의 여행취향 참여/미참여 회원 조회
export const getTripsSurveyMembers = async (tripId: number) => {
const res = await client.get(`trips/${tripId}/survey/members`);
return res;
};
// 여정을 공유하고 있는 회원 조회
export const getTripsMembers = async (tripId: number) => {
const res = await client.get(`trips/${tripId}/members`);
return res;
};
16 changes: 11 additions & 5 deletions src/components/Trip/PlanTripButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import { PlanIcon, RightIcon } from '@components/common/icons/Icons';

const PlanTripButton = () => {
return (
<button className="body3 my-6 flex w-full items-center justify-between rounded-[8px] bg-[#F3F4F5] px-[15px] py-[15px] text-gray7 text-main1">
<div className="flex items-center justify-start">
<PlanIcon />
<span className="ml-[3px]">여행 계획하기</span>

<button className="body3 mb-10 mt-6 flex w-full items-center justify-between rounded-[8px] bg-[#F3F4F5] px-[15px] py-[15px] text-gray7 text-main1">
<div className="flex items-center justify-start ">
<div>
<PlanIcon />
</div>
<p className="ml-1.5 text-gray5">여행 계획하기</p>
</div>
<div>
<RightIcon fill="#888888" />

</div>
<RightIcon />
</button>
);
};
Expand Down
134 changes: 117 additions & 17 deletions src/components/Trip/TripInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,128 @@
import { UserIcon } from '@components/common/icons/Icons';
import { socketContext } from '@hooks/useSocket';
import { useContext } from 'react';
import { useRecoilValue, useRecoilState } from 'recoil';
import { isModalOpenState, modalChildrenState } from '@recoil/modal';
import TripSurveyMember from '@components/common/modal/children/TripSurveyMember';
import { Modal } from '@components/common/modal';
import { useQuery } from '@tanstack/react-query';
import { getTripsMembers } from '@api/trips';
import { tripIdState } from '@recoil/socket';
import { ReactComponent as NullUser } from '@assets/images/NullUser.svg';
import { DownIcon } from '@components/common/icons/Icons';
import { useState } from 'react';

const ShareList = () => {
const tripId = Number(useRecoilValue(tripIdState));
const { data: tripsMembers } = useQuery({
queryKey: ['tripsMembers', tripId],
queryFn: () => getTripsMembers(tripId),
});
const members = tripsMembers?.data?.data?.tripMemberSimpleInfos;

return (
<>
<hr className="my-3 border-solid border-gray2" />
<div>
{members.map((member: any, index: number) => {
return (
<div
className={`mb-2 flex cursor-pointer items-center text-gray5`}
key={index}>
{member.profileImageUrl &&
member.profileImageUrl !== 'http://asiduheimage.jpg' ? (
<img
src={member.profileImageUrl}
alt="유저 프로필"
className="h-[32px] w-[32px] rounded-full"
/>
) : (
<NullUser className="h-[32px] w-[32px]" />
)}
<div className="ml-3">{member.nickname}</div>
</div>
);
})}
</div>
</>
);
};

const TripInfo = () => {
const { tripInfo } = useContext(socketContext);
const trip = tripInfo?.data;
const modalChildren = useRecoilValue(modalChildrenState);
const [isModalOpen, setIsModalOpen] = useRecoilState(isModalOpenState);
const tripId = Number(useRecoilValue(tripIdState));
const [isAccordion, setIsAccordion] = useState(false);

const { data: tripsMembers } = useQuery({
queryKey: ['tripsMembers', tripId],
queryFn: () => getTripsMembers(tripId),
});
const members = tripsMembers?.data?.data?.tripMemberSimpleInfos;

const closeModal = () => {
setIsModalOpen(false);
};

const handleClickButton = () => {
setIsAccordion((prev) => !prev);
};

return (
<div className="my-5">
<div className="flex items-center justify-between">
<div className="flex items-center">
<div className="title1 mb-[10px] mr-1">{trip?.tripName}</div>
<div className="flex items-center pb-[10px]">
<UserIcon size={20} fill="#888" color="#888" />
<span className="body4 pt-[1px] text-gray4">
{trip?.numberOfPeople}
</span>
<>
<div className="my-5">
<div className="flex items-center justify-between">
<div className="flex space-x-[-17.5px]">
{members?.map((member: any, index: number) => (
<div key={index}>
{member.profileImageUrl &&
member.profileImageUrl !== 'http://asiduheimage.jpg' ? (
<img
src={member.profileImageUrl}
alt="유저 프로필"
className="h-[32px] w-[32px] rounded-full border-2 border-solid border-white"
/>
) : (
<NullUser className="h-[32px] w-[32px] border-2 border-solid border-white" />
)}
</div>
))}
</div>

<div className="flex items-center gap-1">
<p className="body1 text-[13px] text-gray7">
{members?.length}명과 공유중
</p>
<div
style={{
transform: isAccordion ? 'rotate(180deg)' : 'rotate(0deg)',
transition: 'transform 0.3s ease',
}}
onClick={handleClickButton}
className="pt-0.5">
<DownIcon color="#888888" size={20} />
</div>
</div>
</div>

{isAccordion && <ShareList />}
<hr className="mb-6 mt-3 border-solid border-gray2" />
<div className="flex items-center justify-between">
<div className="flex items-center">
<div className="title1 mb-[10px] mr-1">강릉 여행 일정</div>
<div className="flex items-center pb-[10px]">
<UserIcon size={20} fill="#888" color="#888" />
<span className="body4 pt-[1px] text-gray4">5</span>
</div>
</div>
<button className="body3 rounded-lg border-2 border-solid border-gray2 p-2 text-gray4">
편집
</button>
</div>
<span className="body1 text-gray4">23.12.23 - 23.12.25</span>
</div>
<span className="body1 text-gray4">
{trip?.startDate} ~ {trip?.endDate}
</span>
</div>
<Modal isOpen={isModalOpen} closeModal={closeModal}>
{modalChildren === 'TripSurveyMember' && <TripSurveyMember />}
</Modal>
</>
);
};

Expand Down
51 changes: 51 additions & 0 deletions src/components/Trip/TripParticipant.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ReactComponent as NullUser } from '@assets/images/NullUser.svg';
import { useRecoilValue } from 'recoil';
import { participantsState } from '@recoil/trip';

interface ParticipantStatusProps {
status: string;
}

const ParticipantList: React.FC<{ infos: any[] }> = ({ infos }) => (
<div className="grid grid-cols-2 gap-3.5">
{infos.map((info: any) => (
<div
key={info.memberId}
className={`flex h-[40px] cursor-pointer items-center text-gray5`}>
{info.thumbnail && info.thumbnail !== 'http://asiduheimage.jpg' ? (
<img
src={info.thumbnail}
alt="유저 프로필"
className="h-[32px] w-[32px] rounded-full"
/>
) : (
<NullUser className="h-[32px] w-[32px]" />
)}
<div className="ml-3">{info.nickname}</div>
</div>
))}
</div>
);

export const ParticipantStatus: React.FC<ParticipantStatusProps> = ({
status,
}) => {
const participants = useRecoilValue(participantsState);

return (
<div className="flex flex-col">
<div className="mb-4 ml-auto mr-2 text-xs text-gray5">
{status == '참여' ? (
<>{participants?.tripSurveyMemberCount}명 참여</>
) : (
<>{participants?.nonTripSurveySetMemberInfos?.length}명 미참여</>
)}
</div>
{status == '참여' ? (
<ParticipantList infos={participants?.tripSurveySetMemberInfos} />
) : (
<ParticipantList infos={participants?.nonTripSurveySetMemberInfos} />
)}
</div>
);
};
48 changes: 38 additions & 10 deletions src/components/Trip/TripPreference.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React, { useState, useEffect } from 'react';
import { getTripsSurvey } from '@api/trips';
import { useQuery } from '@tanstack/react-query';
import { useParams } from 'react-router-dom';
import { MoreIcon } from '@components/common/icons/Icons';
import { RightIcon } from '@components/common/icons/Icons';
import { MoreIcon, RightIcon, HeartIcon } from '@components/common/icons/Icons';
import {
calculatePercentage,
calculatePercentageRemain,
} from '@utils/calculatePercentage';

import { modalChildrenState, isModalOpenState } from '@recoil/modal';
import { getTripsSurveyMembers } from '@api/trips';
import { tripIdState } from '@recoil/socket';
import { useRecoilValue, useSetRecoilState, useRecoilState } from 'recoil';
import { participantsState } from '@recoil/trip';
interface RatioBarParams {
value: number;
total: number;
Expand All @@ -26,7 +28,12 @@ interface PercentageParams {
const TripPreferenceButton: React.FC = () => {
return (
<button className="mb-[17.5px] mt-[20px] flex w-[335px] items-center rounded-full bg-white px-6 py-4 text-sm">
<div className="text-gray6">내 여행 취향 설정하러 가기</div>
<div className="flex items-center text-gray6">
<div>
<HeartIcon fill="#888888" color="#888888" size={20} />
</div>
<p className="ml-1.5">내 여행 취향 설정하러 가기</p>
</div>
<div className="ml-auto">
<RightIcon fill="#5E5E5E" />
</div>
Expand Down Expand Up @@ -87,13 +94,25 @@ const Percentage = ({ value, total, color }: PercentageParams) => (
);

const TripPreference: React.FC = () => {
const params = useParams();
const tripId = Number(params.id);
const [A, setA] = useState<[number, number]>([0, 0]);
const [B, setB] = useState<[number, number]>([0, 0]);
const [C, setC] = useState<[number, number]>([0, 0]);
const [D, setD] = useState<[number, number]>([0, 0]);
const [E, setE] = useState<[number, number]>([0, 0]);
const setModalChildren = useSetRecoilState(modalChildrenState);
const setIsModalOpen = useSetRecoilState(isModalOpenState);
const tripId = Number(useRecoilValue(tripIdState));
const [participants, setParticipants] = useRecoilState(participantsState);

const { data: tripsSurveyMembers } = useQuery({
queryKey: ['tripsSurveyMembers', tripId],
queryFn: () => getTripsSurveyMembers(tripId),
});

useEffect(() => {
const participants = tripsSurveyMembers?.data?.data;
setParticipants(participants);
}, [tripsSurveyMembers]);

const { data: tripPreference, isLoading } = useQuery({
queryKey: ['tripPreference', tripId],
Expand Down Expand Up @@ -129,11 +148,20 @@ const TripPreference: React.FC = () => {
return <div>Loading...</div>;
}

const handleButtonClick = () => {
setModalChildren('TripSurveyMember');
setIsModalOpen(true);
};

return (
<div className=" mb-[-20px] ml-[-40px] mr-[-40px] mt-[-20px] flex flex-col items-center bg-gray1 ">
<div className=" m-[-20px] flex flex-col items-center bg-gray1 pb-[20px] ">
<TripPreferenceButton />
<div className="mb-[20px] ml-auto mr-[40px] flex items-center text-sm ">
<div>n명 참여</div>
<div
onClick={handleButtonClick}
className="mb-[20px] ml-auto mr-[40px] flex cursor-pointer items-center text-sm ">
<div className="text-gray6">
{participants?.tripSurveyMemberCount}명 참여
</div>
<div className="mt-0.5">
<MoreIcon size={20} color="none" fill="#888888" />
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/accordion/Accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const Accordion: React.FC<AccordionProps> = ({ title, content }) => {
<accordion.Item value="item-1">
<accordion.Header className="flex">
{title}
<accordion.Trigger className="ml-auto">
<DownIcon size={17} className="rotate-on-open" />
<accordion.Trigger>
<DownIcon size={17} className="rotate-on-open ml-1" />
</accordion.Trigger>
</accordion.Header>
<accordion.Content>{content}</accordion.Content>
Expand Down
Loading