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

Fe 90 feat/connected trip members/dev #188

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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