Skip to content

Commit

Permalink
Merge pull request #188 from FinalDoubleTen/FE-90--feat/ConnectedTrip…
Browse files Browse the repository at this point in the history
…Members/dev

Fe 90  feat/connected trip members/dev
  • Loading branch information
seungjun222 authored Jan 17, 2024
2 parents a16886c + e90bf3a commit 24bae03
Show file tree
Hide file tree
Showing 12 changed files with 298 additions and 31 deletions.
10 changes: 10 additions & 0 deletions src/api/trips.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,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;
};
14 changes: 9 additions & 5 deletions src/components/Trip/PlanTripButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ 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 />
여행 계획하기
<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
128 changes: 118 additions & 10 deletions src/components/Trip/TripInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,128 @@
import { UserIcon } from '@components/common/icons/Icons';
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 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">강릉 여행 일정</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 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>
<button className="body3 text-gray3">편집</button>
<span className="body1 text-gray4">23.12.23 - 23.12.25</span>
</div>
<span className="body1 text-gray4">23.12.23 ~ 23.12.25</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
20 changes: 20 additions & 0 deletions src/components/common/modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,25 @@ export const getModalStyles = (modalChildren: string) => {
zIndex: 1, // 이거 해줘야 kakao-map도 dimmed됨
},
};
} else if (modalChildren === 'TripSurveyMember') {
return {
content: {
top: 'auto',
left: '50%',
right: 'auto',
bottom: '0',
marginRight: '-50%',
transform: 'translate(-50%, 0)',
maxWidth: '412px',
width: '100%',
height: '280px',
borderTopLeftRadius: '2rem',
borderTopRightRadius: '2rem',
},
overlay: {
backgroundColor: 'rgba(0, 0, 0, 0.25)',
zIndex: 1, // 이거 해줘야 kakao-map도 dimmed됨
},
};
}
};
19 changes: 19 additions & 0 deletions src/components/common/modal/children/TripSurveyMember.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { ParticipantStatus } from '@components/Trip/TripParticipant';
import Tab from '@components/common/tab/Tab';

const TripSurveyMember: React.FC = () => {
return (
<div className="mt-2">
<Tab
lists={['참여', '미참여']}
contents={[
<ParticipantStatus status="참여" />,
<ParticipantStatus status="미참여" />,
]}
/>
</div>
);
};

export default TripSurveyMember;
6 changes: 3 additions & 3 deletions src/components/common/nav/InputComment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ export const InputComment: React.FC<InputCommentProps> = () => {
};

return (
<div className="fixed bottom-0 mt-auto flex flex h-[64px] w-full items-center justify-center border border-solid border-[#EDEDED] bg-white ">
<div className="ml-4 mr-4 flex h-[40px] w-full items-center rounded-md border border-solid border-[#EDEDED]">
<div className="fixed bottom-0 mt-auto flex flex h-[64px] w-[412px] items-center justify-center border border-solid border-[#EDEDED] bg-white ">
<div className="ml-4 mr-4 flex h-[40px] w-[375px] items-center rounded-md border border-solid border-[#EDEDED]">
<div className="pl-1 pr-0.5 text-sm font-bold text-[#29ddf6]"></div>
<div className="flex w-full ">
<input
Expand All @@ -120,7 +120,7 @@ export const InputComment: React.FC<InputCommentProps> = () => {
onKeyPress={handleKeyPress}
/>
</div>
<div className="ml-auto mr-1 min-w-[2rem] ">
<div className="ml-auto mr-3 min-w-[2rem] ">
<button
onClick={handleSubmit}
className=" text-sm font-bold text-[#29ddf6]">
Expand Down
2 changes: 1 addition & 1 deletion src/recoil/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const tripIdState = atom<string | null>({

export const visitDateState = atom<{ visitDate: string } | null>({
key: 'visitDateState',
default: { visitDate: '2024-01-05' },
default: { visitDate: '2024-01-03' },
});

export const memberIdState = atom<{ memberId: number } | null>({
Expand Down
Loading

0 comments on commit 24bae03

Please sign in to comment.