Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
146 changes: 32 additions & 114 deletions src/app/(user-page)/my-meeting/_features/CardRightSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,14 @@

import { Button } from '@/components/ui/Button';
import { Tag } from '@/components/ui/Tag';
import Modal from '@/components/ui/modal/Modal';
import {
useExpelMutation,
useMemberStatusMutation,
} from '@/hooks/mutations/useMyMeetingMutation';
import { myMeetingKeys } from '@/hooks/queries/useMyMeetingQueries';
import { useBannerQueries } from '@/hooks/queries/useMyPageQueries';
import { useQueryClient } from '@tanstack/react-query';
import Image from 'next/image';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { getMyMeetingMemberProfile } from 'service/api/mymeeting';
import type { Member } from 'types/myMeeting';

import ModalProfile from './ModalProfile';
import ModalUserList from './ModalUserList';
import PublicSelect from './PublicDropdown';

const CardRightSection = ({
Expand All @@ -32,63 +25,20 @@ const CardRightSection = ({
meetingId: number;
showPublicSelect?: boolean;
}) => {
const [isUserListModalOpen, setIsUserListModalOpen] = useState(false);
const handleConfirm = () => {
setIsUserListModalOpen(false);
};

const [isUserProfileModalOpen, setIsUserProfileModalOpen] = useState(false);

// 가입 승인 / 거절
const { mutate: statusMutate } = useMemberStatusMutation(meetingId);

// 내보내기
const { mutate: expelMutate } = useExpelMutation(meetingId);

const handleSecondModalConfirm = () => {
// 가입 확인 api 연동
// 만약, status가 approved라면 -> 내보내기 활성화
// 만약, status가 pending이 아니라면 -> 닫기만 활성화

if (selectedUser && selectedUser.memberStatus === 'PENDING') {
statusMutate({
setMemberStatus: 'APPROVED',
userId: selectedUser?.userId,
});
}

setIsUserProfileModalOpen(false);
};

const handleSecondModalCancel = () => {
// 가입 거절 api 연동
if (selectedUser && selectedUser.memberStatus === 'PENDING') {
statusMutate({
setMemberStatus: 'REJECTED',
userId: selectedUser?.userId,
});
} else if (selectedUser && selectedUser.memberStatus === 'APPROVED') {
expelMutate({
setMemberStatus: 'EXPEL',
userId: selectedUser?.userId,
});
}

setIsUserProfileModalOpen(false);
};
const router = useRouter();
const queryClient = useQueryClient();

// 데스크탑 뷰에서 유저 프로필 보기
const handleOpenProfileModal = (
e: React.MouseEvent<HTMLButtonElement>,
member: Member,
) => {
e.stopPropagation();
setSelectedUser(member);
setIsUserProfileModalOpen(true);
router.push(
`/my-meeting/my/profile?meetingId=${meetingId}&userId=${member.userId}&memberStatus=${member.memberStatus}`,
);
};

const queryClient = useQueryClient();

const handlePrefetchProfile = async (member: Member) => {
const queryKey = myMeetingKeys.memberProfile(meetingId, member.userId);

Expand All @@ -104,10 +54,18 @@ const CardRightSection = ({
}
};

// 프로필 보기 할 유저
const [selectedUser, setSelectedUser] = useState<Member | null>(null);
// 맴버 명단 보기
const handleShowMemberList = () => {
queryClient.setQueryData(
['mymeeting', 'memberList', meetingId],
memberList,
);
router.push(
`/my-meeting/my/user-list?meetingId=${meetingId}&type=${showPublicSelect ? 'created' : 'joined'}`,
);
};

const { data: currentUser, isLoading, error } = useBannerQueries();
const { data: currentUser, isLoading } = useBannerQueries();
if (isLoading || !currentUser) {
return;
}
Expand Down Expand Up @@ -142,7 +100,10 @@ const CardRightSection = ({
{member.userId !== currentUser?.userId && (
<div className="flex h-[40px] gap-[6px]">
{showPublicSelect && (
<Tag variant={member.memberStatus} className="w-[49px]" />
<Tag
variant={member.memberStatus}
className="w-[49px] justify-center"
/>
)}
<Button
variant={'outline'}
Expand All @@ -159,62 +120,19 @@ const CardRightSection = ({
</div>
</div>

<div className="flex flex-1 gap-[16px]">
<Button
variant="outline"
className="flex h-[40px] flex-1 md:h-[46px] lg:hidden"
onClick={() => setIsUserListModalOpen(true)}
>
맴버 명단 보기
</Button>
{showPublicSelect && (
<PublicSelect isPublic={isPublic} meetingId={meetingId} />
)}
</div>

<Modal
isOpen={isUserProfileModalOpen}
onClose={handleSecondModalCancel}
onConfirm={handleSecondModalConfirm}
confirmText={
selectedUser?.memberStatus === 'PENDING' ? '가입승인' : '닫기'
}
cancelText={
selectedUser?.memberStatus === 'PENDING'
? '가입거절'
: selectedUser?.memberStatus === 'APPROVED'
? '내보내기'
: '닫기'
}
closeOnly={
!(
selectedUser?.memberStatus === 'PENDING' ||
selectedUser?.memberStatus === 'APPROVED'
)
}
modalClassName="w-[450px] overflow-hidden bg-BG_2"
buttonClassName="w-full"
>
<ModalProfile userId={selectedUser?.userId} meetingId={meetingId} />
</Modal>
<Modal
isOpen={isUserListModalOpen}
onClose={() => setIsUserListModalOpen(false)}
onConfirm={handleConfirm}
showOnly
modalClassName="h-[590px] w-[520px] overflow-y-auto"
{/* <div className="flex flex-1 gap-[16px]"> */}
<Button
variant="outline"
className="flex h-[40px] flex-1 md:h-[46px] lg:hidden"
onClick={handleShowMemberList}
>
<ModalUserList
memberList={memberList}
setSelectedUser={setSelectedUser}
setIsUserProfileModalOpen={setIsUserProfileModalOpen}
setIsUserListModalOpen={setIsUserListModalOpen}
currentUser={currentUser}
handlePrefetchProfile={handlePrefetchProfile}
showPublicSelect={showPublicSelect}
/>
</Modal>
맴버 명단 보기
</Button>
{showPublicSelect && (
<PublicSelect isPublic={isPublic} meetingId={meetingId} />
)}
</div>
// </div>
);
};

Expand Down
6 changes: 3 additions & 3 deletions src/app/(user-page)/my-meeting/_features/Created.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
hasNextPage,
isFetchingNextPage,
isLoading,
error,

Check warning on line 20 in src/app/(user-page)/my-meeting/_features/Created.tsx

View workflow job for this annotation

GitHub Actions / check

'error' is assigned a value but never used. Allowed unused vars must match /^_/u
} = useInfiniteMyMeetingManageQueries();

const lastMeetingRef = useInfiniteScroll({
Expand Down Expand Up @@ -53,7 +53,6 @@
>
<HorizonCard
onClick={handleMoveDetailPage}
key={meeting.meetingId}
title={meeting.title}
thumbnailUrl={meeting.thumbnail}
location={meeting.location}
Expand All @@ -68,6 +67,7 @@
isPublic={meeting.isPublic}
className="hidden lg:flex"
meetingId={meeting.meetingId}
showPublicSelect={true}
/>
</HorizonCard>
</div>
Expand All @@ -81,7 +81,6 @@
>
<HorizonCard
onClick={handleMoveDetailPage}
key={meeting.meetingId}
title={meeting.title}
thumbnailUrl={meeting.thumbnail}
location={meeting.location}
Expand All @@ -98,6 +97,7 @@
isPublic={meeting.isPublic}
className="flex lg:hidden"
meetingId={meeting.meetingId}
showPublicSelect={true}
/>
</div>

Expand All @@ -110,7 +110,6 @@
>
<HorizonCard
onClick={handleMoveDetailPage}
key={meeting.meetingId}
title={meeting.title}
thumbnailUrl={meeting.thumbnail}
location={meeting.location}
Expand All @@ -127,6 +126,7 @@
isPublic={meeting.isPublic}
className="flex lg:hidden"
meetingId={meeting.meetingId}
showPublicSelect={true}
/>
</div>
</div>
Expand Down
58 changes: 20 additions & 38 deletions src/app/(user-page)/my-meeting/_features/ModalProfile.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,11 @@
import Description from '@/components/common/Description';
import { useMyMeetingMemberProfileQuries } from '@/hooks/queries/useMyMeetingQueries';
import TechButton from '@/components/ui/tech-stack/tech-stack-components/TechButton';
import { getIconComponent } from '@/util/getIconDetail';
import Image from 'next/image';
import React from 'react';
import { IMemberProfile } from 'types/myMeeting';

import SkeletonProfile from './skeletons/SkeletonProfile';

const ModalProfile = ({
userId,
meetingId,
}: {
userId: number | undefined;
meetingId: number;
}) => {
const {
data: user,
isLoading,
error,
} = useMyMeetingMemberProfileQuries({
meetingId,
userId: userId!,
});

if (isLoading || !user) {
return <SkeletonProfile />;
}

const ModalProfile = ({ user }: { user: IMemberProfile }) => {
return (
<div className="p-4">
<div className="mb-4 flex gap-4">
Expand All @@ -50,21 +31,22 @@ const ModalProfile = ({
<div className="flex flex-col gap-2 pl-2">
<Description label="포지션" value={user.position} />
<Description label="기술스택">
<div className=" flex flex-wrap gap-[6px] text-Cgray500">
<div className="typo-caption1 rounded-[8px] bg-disable px-[8px] py-[4px]">
자바스크립트
</div>
<div className="typo-caption1 rounded-[8px] bg-disable px-[8px] py-[4px]">
자바스크립트
</div>
<div className="typo-caption1 rounded-[8px] bg-disable px-[8px] py-[4px]">
자바스크립트
</div>
<div className="typo-caption1 rounded-[8px] bg-disable px-[8px] py-[4px]">
자바스크립트
</div>
<div className="typo-caption1 rounded-[8px] bg-disable px-[8px] py-[4px]">
자바스크립트
<div className="ml-[8px] flex gap-[6px] text-Cgray500">
<div className="flex flex-wrap gap-2">
{user.skillArray &&
user.skillArray?.length > 0 &&
user.skillArray.map((skill) => (
<TechButton
className="h-6"
key={skill}
name={skill}
icon={getIconComponent(skill)}
color={'#333'}
isClicked={true}
isMaxReached={false}
onClick={() => {}}
/>
))}
</div>
</div>
</Description>
Expand Down
37 changes: 24 additions & 13 deletions src/app/(user-page)/my-meeting/_features/ModalUserList.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
import { Tag } from '@/components/ui/Tag';
import Image from 'next/image';
import { useRouter } from 'next/navigation';
import React from 'react';
import { Dispatch, SetStateAction } from 'react';
import type { IBanner, Member } from 'types/myMeeting';

import { Button } from '../../../../components/ui/Button';

const ModalUserList = ({
memberList,
setIsUserProfileModalOpen,
setIsUserListModalOpen,
setSelectedUser,
currentUser,
className,
meetingId,
currentUser,
handlePrefetchProfile,
showPublicSelect = false,
}: {
memberList: Member[];
setSelectedUser: Dispatch<React.SetStateAction<Member | null>>;
setIsUserProfileModalOpen: Dispatch<SetStateAction<boolean>>;
setIsUserListModalOpen: Dispatch<SetStateAction<boolean>>;
currentUser: IBanner;
className?: string;
handlePrefetchProfile: (member: Member) => Promise<void>;
showPublicSelect?: boolean;
meetingId: number;
}) => {
const router = useRouter();

const handleProfileClick = (user: Member) => {
setSelectedUser(user);
setIsUserProfileModalOpen(true);
setIsUserListModalOpen(false);
router.push(
`/my-meeting/my/profile?meetingId=${meetingId}&userId=${user.userId}&memberStatus=${user.memberStatus}`,
);
};

return (
<div className="flex flex-col">
<div
className="flex flex-col overflow-y-auto rounded-lg bg-BG_2 "
onClick={(e) => e.stopPropagation()}
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.stopPropagation();
}
}}
>
<h3 className={`typo-head3 mb-2 text-main`}>맴버 리스트</h3>
<div className={className}>
{memberList.map((user) => (
Expand All @@ -53,7 +61,10 @@ const ModalUserList = ({
{user.userId !== currentUser?.userId && (
<div className="flex gap-[6px]">
{showPublicSelect && (
<Tag variant={user.memberStatus} className="w-[49px]" />
<Tag
variant={user.memberStatus}
className="w-[49px] justify-center"
/>
)}
<div>
<Button
Expand Down
5 changes: 5 additions & 0 deletions src/app/(user-page)/my-meeting/my/(modal)/profile/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { redirect } from 'next/navigation';

export default function DefaultModal() {
redirect('/my-meeting/my?type=created');
}
Loading
Loading