+
나의 멘티
- {/* 전체보기 버튼 */}
{isMyMenteeTab && myMenteeList.length > 2 && (
전체보기
@@ -43,10 +41,8 @@ const MentorPage = () => {
)}
- {/* 멘티 보기 탭일때 */}
{isMyMenteeTab ? (
<>
- {/* 나의 멘티 */}
{isMyMenteeListPending ? (
) : myMenteeList.length === 0 ? (
@@ -66,13 +62,14 @@ const MentorPage = () => {
);
})
)}
- {/* 중간 밑줄 */}
-
- {/* 나의 멘토 페이지 */}
-
+ {!isDesktop && (
+ <>
+
+
+ >
+ )}
>
) : (
- // 멘티 신청 보기 탭일때
)}
@@ -80,4 +77,31 @@ const MentorPage = () => {
);
};
-export default MentorPage;
+export const MentorDesktopPage = () => {
+ return (
+
+ );
+};
+
+export const MentorMobilePage = () => {
+ return
;
+};
+
+export default MentorMobilePage;
diff --git a/apps/web/src/app/mentor/_ui/MentorClient/index.tsx b/apps/web/src/app/mentor/_ui/MentorClient/index.tsx
index 2d44a9367..de8830633 100644
--- a/apps/web/src/app/mentor/_ui/MentorClient/index.tsx
+++ b/apps/web/src/app/mentor/_ui/MentorClient/index.tsx
@@ -7,13 +7,15 @@ import { useGetMyInfo } from "@/apis/MyPage";
import CloudSpinnerPage from "@/components/ui/CloudSpinnerPage";
import useAuthStore from "@/lib/zustand/useAuthStore";
import { UserRole } from "@/types/mentor";
+import useIsDesktopViewport from "@/utils/useIsDesktopViewport";
import MentorPageSkeleton from "../MentorPageSkeleton";
-import MenteePage from "./_ui/MenteePage";
-import MentorPage from "./_ui/MentorPage";
+import { MenteeDesktopPage, MenteeMobilePage } from "./_ui/MenteePage";
+import { MentorDesktopPage, MentorMobilePage } from "./_ui/MentorPage";
const MentorClient = () => {
const router = useRouter();
const clientRole = useAuthStore((state) => state.clientRole);
+ const isDesktop = useIsDesktopViewport();
const { data: myInfo, isLoading, isFetching, isError, error, refetch } = useGetMyInfo();
const role = myInfo?.role;
const status = (error as AxiosError | null)?.response?.status;
@@ -27,7 +29,7 @@ const MentorClient = () => {
}
}, [isAuthResolving, isUnauthorized, isError, role, router]);
- if (isAuthResolving) {
+ if (isAuthResolving || isDesktop === null) {
return
;
}
@@ -50,11 +52,13 @@ const MentorClient = () => {
);
}
- if (role === UserRole.ADMIN) {
- return clientRole === UserRole.MENTEE ?
:
;
+ const shouldRenderMentorPage = role === UserRole.ADMIN ? clientRole !== UserRole.MENTEE : role === UserRole.MENTOR;
+
+ if (shouldRenderMentorPage) {
+ return isDesktop ?
:
;
}
- return role === UserRole.MENTOR ?
:
;
+ return isDesktop ?
:
;
};
export default MentorClient;
diff --git a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx
index 9293a7007..205b928cd 100644
--- a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx
+++ b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx
@@ -2,14 +2,16 @@
import clsx from "clsx";
import Link from "next/link";
+import type { ReactNode, Ref, RefObject } from "react";
import { useGetPartnerInfo } from "@/apis/chat";
import { useUploadChatImages } from "@/apis/image-upload";
import ProfileWithBadge from "@/components/ui/ProfileWithBadge";
import { showIconToast } from "@/lib/toast/showIconToast";
import useAuthStore from "@/lib/zustand/useAuthStore";
-import { ConnectionStatus } from "@/types/chat";
+import { type ChatMessage, ConnectionStatus } from "@/types/chat";
import { UserRole } from "@/types/mentor";
import { tokenParse } from "@/utils/jwtUtils";
+import useIsDesktopViewport from "@/utils/useIsDesktopViewport";
import useChatListHandler from "./_hooks/useChatListHandler";
import usePutChatReadHandler from "./_hooks/usePutChatReadHandler";
import { formatDateSeparator, isSameDay } from "./_lib/dateUtils";
@@ -27,6 +29,7 @@ const ChatContent = ({ chatId }: ChatContentProps) => {
const isMentor = parsedData?.role === UserRole.MENTOR || parsedData?.role === UserRole.ADMIN;
const isPartnerMentor = !isMentor;
+ const isDesktop = useIsDesktopViewport();
// 채팅 읽음 상태 업데이트 훅 진입시 자동으로
usePutChatReadHandler(chatId);
@@ -57,155 +60,291 @@ const ChatContent = ({ chatId }: ChatContentProps) => {
const { partnerId, nickname, profileUrl, university } = partnerInfo ?? {};
- return (
-
-
-
- {/* 하단 여백 추가 */}
- {/* Floating 멘토 정보 영역 */}
-
-
-
-
-
-
{nickname}
-
-
{university ? university : "예비솔커"}
-
-
-
- {isMentor ? "멘티 페이지" : "멘토 페이지"}
-
-
-
-
- {connectionStatus === ConnectionStatus.Connected ? (
-
- 멘토링이 연결되었습니다! 채팅을 시작해보세요!
-
- ) : connectionStatus === ConnectionStatus.Pending ? (
-
연결 대기 중입니다. 잠시만 기다려주세요.
- ) : connectionStatus === ConnectionStatus.Error ? (
-
연결 중 오류가 발생했습니다. 다시 시도해주세요.
- ) : connectionStatus === ConnectionStatus.Disconnected ? (
-
연결이 끊어졌습니다. 잠시 후 다시 시도해주세요.
- ) : null}
-
-
-
- {/* 채팅 메시지 영역 - 항상 스크롤 가능, 스크롤바 숨김 */}
-
- {/* 초기 로딩 표시 - 상단 고정 */}
- {isLoading && (
-
- 채팅 기록을 불러오는 중...
-
- )}
+ if (isDesktop === null) return null;
-
- {/* 상단 무한 스크롤 로딩 표시 */}
- {isFetchingNextPage && (
-
- )}
-
- {/* 첫 번째 메시지에 ref 부착하여 위로 스크롤 시 더 오래된 메시지 로드 */}
- {messages.map((message, index) => {
- const showDateSeparator = index === 0 || !isSameDay(messages[index - 1].createdAt, message.createdAt);
- const previewMessageKey = message.attachments
- .map((attachment) => attachment.previewUrl)
- .find((previewUrl): previewUrl is string => Boolean(previewUrl));
- const messageKey = previewMessageKey
- ? `preview-${previewMessageKey}`
- : message.id > 0
- ? `message-${message.id}`
- : `message-${message.senderId}-${message.createdAt}-${message.content}-${index}`;
-
- return (
-
- {/* 날짜 구분선 */}
- {showDateSeparator && (
-
-
- {formatDateSeparator(message.createdAt)}
-
-
- )}
- {/* 일반 채팅 메시지 */}
-
-
- );
- })}
-
- {/* 스크롤 타겟 - 메시지 목록 끝 */}
-
-
-
-
-
+ const inputBar = (
+
{
+ sendTextMessage(data.message, userId);
+ }}
+ onSendImages={async (data) => {
+ const previewUrls = addImageMessagePreview(data.images, userId);
- {/* 메시지 입력 영역 - 항상 하단 고정 */}
- {
- sendTextMessage(data.message, userId);
- }}
- onSendImages={async (data) => {
- const previewUrls = addImageMessagePreview(data.images, userId);
-
- try {
- const imageUrls = await uploadChatImagesMutation.mutateAsync(data.images);
- const isSent = sendImageMessage(imageUrls, previewUrls);
-
- if (!isSent) {
- removeImageMessagePreviews(previewUrls);
- showIconToast("logo", "채팅 연결이 원활하지 않아 이미지를 전송하지 못했어요.");
- }
- } catch {
+ try {
+ const imageUrls = await uploadChatImagesMutation.mutateAsync(data.images);
+ const isSent = sendImageMessage(imageUrls, previewUrls);
+
+ if (!isSent) {
removeImageMessagePreviews(previewUrls);
- showIconToast("logo", "이미지 전송에 실패했어요. 다시 시도해주세요.");
+ showIconToast("logo", "채팅 연결이 원활하지 않아 이미지를 전송하지 못했어요.");
}
- }}
- onSendFiles={(data) => {
- addImageMessagePreview(data.files, userId);
- }}
- />
-
+ } catch {
+ removeImageMessagePreviews(previewUrls);
+ showIconToast("logo", "이미지 전송에 실패했어요. 다시 시도해주세요.");
+ }
+ }}
+ onSendFiles={(data) => {
+ addImageMessagePreview(data.files, userId);
+ }}
+ />
);
+
+ const viewProps: ChatContentViewProps = {
+ userId,
+ isMentor,
+ isPartnerMentor,
+ partnerId,
+ nickname,
+ profileUrl,
+ university,
+ messages,
+ connectionStatus,
+ isLoading,
+ isFetchingNextPage,
+ scrollContainerRef,
+ messagesEndRef,
+ topDetectorRef,
+ inputBar,
+ };
+
+ return isDesktop ?
:
;
+};
+
+type ChatContentViewProps = {
+ userId: number;
+ isMentor: boolean;
+ isPartnerMentor: boolean;
+ partnerId?: number;
+ nickname?: string;
+ profileUrl?: string | null;
+ university?: string | null;
+ messages: ChatMessage[];
+ connectionStatus: ConnectionStatus;
+ isLoading: boolean;
+ isFetchingNextPage: boolean;
+ scrollContainerRef: RefObject
;
+ messagesEndRef: RefObject;
+ topDetectorRef: Ref;
+ inputBar: ReactNode;
+};
+
+type ChatContentViewBaseProps = ChatContentViewProps & {
+ isDesktop: boolean;
+};
+
+const ChatContentViewBase = ({
+ userId,
+ isMentor,
+ isPartnerMentor,
+ partnerId,
+ nickname,
+ profileUrl,
+ university,
+ messages,
+ connectionStatus,
+ isLoading,
+ isFetchingNextPage,
+ scrollContainerRef,
+ messagesEndRef,
+ topDetectorRef,
+ inputBar,
+ isDesktop,
+}: ChatContentViewBaseProps) => (
+
+);
+
+const DesktopChatContentView = (props: ChatContentViewProps) => ;
+
+const MobileChatContentView = (props: ChatContentViewProps) => ;
+
+type PartnerSummaryProps = {
+ isMentor: boolean;
+ isPartnerMentor: boolean;
+ partnerId?: number;
+ nickname?: string;
+ profileUrl?: string | null;
+ university?: string | null;
+ connectionStatus: ConnectionStatus;
+ isDesktop: boolean;
+};
+
+const PartnerSummary = ({
+ isMentor,
+ isPartnerMentor,
+ partnerId,
+ nickname,
+ profileUrl,
+ university,
+ connectionStatus,
+ isDesktop,
+}: PartnerSummaryProps) => (
+
+
+
+
+
+
{nickname}
+
+
{university ? university : "예비솔커"}
+
+
+
+ {isMentor ? "멘티 페이지" : "멘토 페이지"}
+
+
+
+
+ {connectionStatus === ConnectionStatus.Connected ? (
+
+ 멘토링이 연결되었습니다! 채팅을 시작해보세요!
+
+ ) : connectionStatus === ConnectionStatus.Pending ? (
+
연결 대기 중입니다. 잠시만 기다려주세요.
+ ) : connectionStatus === ConnectionStatus.Error ? (
+
연결 중 오류가 발생했습니다. 다시 시도해주세요.
+ ) : connectionStatus === ConnectionStatus.Disconnected ? (
+
연결이 끊어졌습니다. 잠시 후 다시 시도해주세요.
+ ) : null}
+
+
+
+);
+
+type ChatMessageListProps = {
+ userId: number;
+ isPartnerMentor: boolean;
+ nickname?: string;
+ profileUrl?: string | null;
+ messages: ChatMessage[];
+ isLoading: boolean;
+ isFetchingNextPage: boolean;
+ scrollContainerRef: RefObject;
+ messagesEndRef: RefObject;
+ topDetectorRef: Ref;
+ isDesktop: boolean;
};
+const ChatMessageList = ({
+ userId,
+ isPartnerMentor,
+ nickname,
+ profileUrl,
+ messages,
+ isLoading,
+ isFetchingNextPage,
+ scrollContainerRef,
+ messagesEndRef,
+ topDetectorRef,
+ isDesktop,
+}: ChatMessageListProps) => (
+
+ {isLoading && (
+
+ 채팅 기록을 불러오는 중...
+
+ )}
+
+
+ {isFetchingNextPage && (
+
+ )}
+
+ {messages.map((message, index) => {
+ const showDateSeparator = index === 0 || !isSameDay(messages[index - 1].createdAt, message.createdAt);
+ const previewMessageKey = message.attachments
+ .map((attachment) => attachment.previewUrl)
+ .find((previewUrl): previewUrl is string => Boolean(previewUrl));
+ const messageKey = previewMessageKey
+ ? `preview-${previewMessageKey}`
+ : message.id > 0
+ ? `message-${message.id}`
+ : `message-${message.senderId}-${message.createdAt}-${message.content}-${index}`;
+
+ return (
+
+ {showDateSeparator && (
+
+
+ {formatDateSeparator(message.createdAt)}
+
+
+ )}
+
+
+ );
+ })}
+
+
+
+
+);
+
export default ChatContent;
diff --git a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatNavBar/index.tsx b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatNavBar/index.tsx
index 9d172d731..e4328f979 100644
--- a/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatNavBar/index.tsx
+++ b/apps/web/src/app/mentor/chat/[chatId]/_ui/ChatNavBar/index.tsx
@@ -11,16 +11,21 @@ import useAuthStore from "@/lib/zustand/useAuthStore";
import { IconAlert, IconAlertSubC, IconDirectionRight, IconSetting } from "@/public/svgs/mentor";
import { UserRole } from "@/types/mentor";
import { tokenParse } from "@/utils/jwtUtils";
+import useIsDesktopViewport from "@/utils/useIsDesktopViewport";
import ReportPanel from "../../../../../../components/ui/ReportPanel";
interface ChatNavBarProps {
chatId: number;
}
+type PartnerInfo = NonNullable["data"]>;
+type MyInfo = NonNullable["data"]>;
+
const ChatNavBar = ({ chatId }: ChatNavBarProps) => {
const [isExpanded, setIsExpanded] = useState(false);
const [isAnimating, setIsAnimating] = useState(false);
const accessToken = useAuthStore((state) => state.accessToken);
+ const isDesktop = useIsDesktopViewport();
const result = tokenParse(accessToken);
const isMentor = result?.role === UserRole.MENTOR || result?.role === UserRole.ADMIN;
const isPartnerMentor = !isMentor;
@@ -50,129 +55,192 @@ const ChatNavBar = ({ chatId }: ChatNavBarProps) => {
}, 300);
};
- return (
-
-
-
- {/* 오버레이 (패널 외부 클릭 시 닫기) */}
- {(isExpanded || isAnimating) && (
-
- )}
- {/* 확장된 설정 패널 */}
- {(isExpanded || isAnimating) && (
-
- {/* 상대방 프로필 섹션 */}
-
-
-
-
-
-
{partnerInfo?.nickname || "상대방"}
-
- {partnerInfo?.university || "예비솔커"}
-
-
-
- {isMentor ? "멘티 페이지 가기" : "멘토 페이지 가기"}
-
-
+ if (isDesktop === null) return null;
-
- {/* 알림 설정 */}
-
-
- {isMentor ? : }
- 알림
-
-
+ const viewProps: ChatNavBarViewProps = {
+ chatId,
+ isMentor,
+ isPartnerMentor,
+ partnerInfo,
+ myInfo,
+ isExpanded,
+ isAnimating,
+ handleSettingsClick,
+ handleClose,
+ };
+
+ return isDesktop ?
:
;
+};
+
+type ChatNavBarViewProps = {
+ chatId: number;
+ isMentor: boolean;
+ isPartnerMentor: boolean;
+ partnerInfo?: PartnerInfo;
+ myInfo?: MyInfo;
+ isExpanded: boolean;
+ isAnimating: boolean;
+ handleSettingsClick: () => void;
+ handleClose: () => void;
+};
+
+const DesktopChatNavBarView = (props: ChatNavBarViewProps) => (
+
+
+
+
+
Mentor
+
멘토 채팅
+
+ 멘토링 상대와 실시간으로 대화하며 궁금한 점을 해결하세요.
+
+
+
+
+
+
+
+);
+
+const MobileChatNavBarView = (props: ChatNavBarViewProps) => (
+
+
+
+
+);
+
+const ChatSettingsButton = ({ onClick, size }: { onClick: () => void; size: "desktop" | "mobile" }) => (
+
+);
+
+const ChatSettingsPanel = ({
+ chatId,
+ isMentor,
+ isPartnerMentor,
+ partnerInfo,
+ myInfo,
+ isExpanded,
+ isAnimating,
+ handleClose,
+}: ChatNavBarViewProps) => (
+ <>
+ {(isExpanded || isAnimating) && (
+
+ )}
+ {(isExpanded || isAnimating) && (
+
+
+
+
+
+
+
{partnerInfo?.nickname || "상대방"}
+
+ {partnerInfo?.university || "예비솔커"}
+
+
+
+ {isMentor ? "멘티 페이지 가기" : "멘토 페이지 가기"}
+
+
+
+
+
+
+ {isMentor ? : }
+ 알림
-
- {/* 참여자 섹션 */}
-
참여자 2
-
- {/* 현재 사용자 */}
-
-
- {/* '나' 표시 div */}
-
- 나
-
-
-
- {myInfo?.nickname || "나"} ({myInfo?.role === UserRole.ADMIN ? "어드민" : isMentor ? "멘토" : "멘티"})
-
-
+
+
+
+
참여자 2
+
+
+
+
+ 나
-
- {/* 상대방 */}
-
-
+
- {partnerInfo?.nickname || "상대방"} ({isMentor ? "멘티" : "멘토"})
+ {myInfo?.nickname || "나"} ({myInfo?.role === UserRole.ADMIN ? "어드민" : isMentor ? "멘토" : "멘티"})
-
-
+
+
+
+
+ {partnerInfo?.nickname || "상대방"} ({isMentor ? "멘티" : "멘토"})
+
- )}
-
- );
-};
+
+
+
+
+ )}
+ >
+);
+
export default ChatNavBar;
diff --git a/apps/web/src/app/mentor/chat/[chatId]/page.tsx b/apps/web/src/app/mentor/chat/[chatId]/page.tsx
index 4e5dc3e6e..ebc62b2ba 100644
--- a/apps/web/src/app/mentor/chat/[chatId]/page.tsx
+++ b/apps/web/src/app/mentor/chat/[chatId]/page.tsx
@@ -21,9 +21,11 @@ const ChatDetailPage = async ({ params }: ChatDetailPageProps) => {
if (Number.isNaN(chatId)) notFound();
return (
-
+
);
};
diff --git a/apps/web/src/app/mentor/chat/_ui/ChatPageClient/index.tsx b/apps/web/src/app/mentor/chat/_ui/ChatPageClient/index.tsx
index cf67d213f..e30bf730b 100644
--- a/apps/web/src/app/mentor/chat/_ui/ChatPageClient/index.tsx
+++ b/apps/web/src/app/mentor/chat/_ui/ChatPageClient/index.tsx
@@ -1,5 +1,6 @@
"use client";
+import clsx from "clsx";
import Link from "next/link";
import { useGetChatRooms } from "@/apis/chat";
import { useGetMyInfo } from "@/apis/MyPage";
@@ -7,111 +8,204 @@ import ProfileWithBadge from "@/components/ui/ProfileWithBadge";
import { IconSearchBlue, IconSolidConnentionLogo } from "@/public/svgs/mentor";
import { UserRole } from "@/types/mentor";
import { convertISODateToKoreanTime } from "@/utils/datetimeUtils";
+import useIsDesktopViewport from "@/utils/useIsDesktopViewport";
+
+type ChatRoom = NonNullable
["data"]>[number];
const ChatPageClient = () => {
- const { data: chatRooms = [] } = useGetChatRooms();
- const { data: myInfo } = useGetMyInfo();
+ const { data: chatRooms = [], isPending: isChatRoomsPending } = useGetChatRooms();
+ const { data: myInfo, isError: isMyInfoError, isLoading: isMyInfoLoading } = useGetMyInfo();
+ const isDesktop = useIsDesktopViewport();
const isMentee = myInfo?.role === UserRole.MENTEE;
const isPartnerMentor = isMentee;
+ const listTitle = isMentee ? "나의 멘토" : "나의 멘티";
+ const isProfilePending = isMyInfoLoading || (!isMyInfoError && !myInfo?.role);
+
+ if (isDesktop === null || isProfilePending || isChatRoomsPending) {
+ return ;
+ }
+
+ if (chatRooms.length === 0) {
+ return isDesktop ? : ;
+ }
+
+ const viewProps = {
+ chatRooms,
+ isMentee,
+ isPartnerMentor,
+ listTitle,
+ };
+
+ return isDesktop ? : ;
+};
+
+type ChatPageViewProps = {
+ chatRooms: ChatRoom[];
+ isMentee: boolean;
+ isPartnerMentor: boolean;
+ listTitle: string;
+};
+
+const DesktopChatPageView = ({ chatRooms, isMentee, isPartnerMentor, listTitle }: ChatPageViewProps) => (
+
+
- // 연결된 멘토가 없을 때의 처리 (멘티만)
- if (chatRooms.length === 0 && isMentee) {
- return (
-
-
-
+
+
+
+
+
+
+);
+
+const MobileChatPageView = ({ chatRooms, isMentee, isPartnerMentor, listTitle }: ChatPageViewProps) => (
+
+ {isMentee && (
+
+
+
+
+
+
+ 멘토를 찾으러 가볼까요?
+
+
나의 멘토 찾으러가기
+
+
+ ›
-
+
+ )}
+
+
+
+
+
+
+);
+
+const ChatEmptyStateBase = ({ isDesktop, isMentee }: { isDesktop: boolean; isMentee: boolean }) => (
+
+
+
+
+
+ {isMentee ? (
+ <>
현재 매칭된 멘토가 없어요.
멘토부터 찾아볼까요?
-
-
- 멘토 찾으러 가볼까요?
-
-
- );
- }
+ >
+ ) : (
+ "현재 진행 중인 채팅이 없어요."
+ )}
+
+ {isMentee && (
+
+ 멘토 찾으러 가볼까요?
+
+ )}
+
+);
- // 멘토/어드민이고 채팅방이 없을 때
- if (chatRooms.length === 0) {
- return (
-
-
-
-
-
현재 진행 중인 채팅이 없어요.
-
- );
- }
+const DesktopChatEmptyState = ({ isMentee }: { isMentee: boolean }) => (
+
+);
- return (
-
- {/* 헤더 - 멘티일 때만 표시 */}
- {isMentee && (
-
-
-
-
-
-
-
멘토를 찾으러 가볼까요?
+const MobileChatEmptyState = ({ isMentee }: { isMentee: boolean }) => (
+
+);
+
+const ChatListHeader = ({ title, count }: { title: string; count: number }) => (
+
+
{title}
+
+ {count}
+
+
+);
+
+type ChatRoomListProps = {
+ chatRooms: ChatRoom[];
+ isPartnerMentor: boolean;
+};
+
+type ChatRoomListBaseProps = ChatRoomListProps & {
+ isDesktop: boolean;
+};
+
+const ChatRoomListBase = ({ chatRooms, isPartnerMentor, isDesktop }: ChatRoomListBaseProps) => (
+
+ {chatRooms.map((chat) => {
+ const { nickname, profileUrl } = chat.partner;
+ const { lastChatMessage, lastReceivedTime, unReadCount } = chat;
+
+ return (
+
+
+
+
+
{nickname}
+
{lastChatMessage}
-
나의 멘토 찾으러가기
-
-
›
+
+
{convertISODateToKoreanTime(lastReceivedTime)}
+ {unReadCount > 0 && (
+
+ {unReadCount > 9 ? "9+" : unReadCount}
+
+ )}
- )}
+ );
+ })}
+
+);
- {/* 채팅 리스트 섹션 */}
-
-
-
{isMentee ? "나의 멘토" : "나의 멘티"}
-
- {chatRooms.length}
-
-
+const DesktopChatRoomList = (props: ChatRoomListProps) =>
;
- {/* 채팅 리스트 */}
-
- {chatRooms.map((chat) => {
- const { nickname, profileUrl } = chat.partner;
- const { lastChatMessage, lastReceivedTime, unReadCount } = chat;
-
- return (
-
-
-
-
-
{nickname}
-
{lastChatMessage}
-
-
-
-
{convertISODateToKoreanTime(lastReceivedTime)}
- {unReadCount > 0 && (
-
- {unReadCount > 9 ? "9+" : unReadCount}
-
- )}
-
-
- );
- })}
-
-
-
- );
-};
+const MobileChatRoomList = (props: ChatRoomListProps) =>
;
+
+const DesktopQuickLink = ({ href, title, description }: { href: string; title: string; description: string }) => (
+
+
{title}
+
{description}
+
+);
export default ChatPageClient;
diff --git a/apps/web/src/app/mentor/chat/page.tsx b/apps/web/src/app/mentor/chat/page.tsx
index eab30e153..5ca779f3e 100644
--- a/apps/web/src/app/mentor/chat/page.tsx
+++ b/apps/web/src/app/mentor/chat/page.tsx
@@ -11,7 +11,7 @@ export const metadata: Metadata = {
const ChatPage = () => {
return (
-
+
);
diff --git a/apps/web/src/app/mentor/loading.tsx b/apps/web/src/app/mentor/loading.tsx
index f78863043..f9614a585 100644
--- a/apps/web/src/app/mentor/loading.tsx
+++ b/apps/web/src/app/mentor/loading.tsx
@@ -1,7 +1,7 @@
import MentorPageSkeleton from "./_ui/MentorPageSkeleton";
const MentorLoading = () => (
-
+
);
diff --git a/apps/web/src/app/mentor/modify/_ui/ModifyContent/index.tsx b/apps/web/src/app/mentor/modify/_ui/ModifyContent/index.tsx
index 885bacbf7..38957d90b 100644
--- a/apps/web/src/app/mentor/modify/_ui/ModifyContent/index.tsx
+++ b/apps/web/src/app/mentor/modify/_ui/ModifyContent/index.tsx
@@ -6,6 +6,7 @@ import { useGetArticleList } from "@/apis/news";
import StudyDate from "@/components/mentor/StudyDate";
import CloudSpinnerPage from "@/components/ui/CloudSpinnerPage";
import MentoProfile from "@/components/ui/ProfileWithBadge";
+import useIsDesktopViewport from "@/utils/useIsDesktopViewport";
import useModifyHookForm from "./_hooks/useModifyHookForm";
import usePutMyMentorProfileHandler from "./_hooks/usePutMyMentorProfileHandler";
import AddArticleCard from "./_ui/AddArticleCard";
@@ -15,24 +16,152 @@ import ChannelBox from "./_ui/ChannelBox";
const ModifyContent = () => {
const { data: myMentorProfile = null } = useGetMentorMyProfile();
const { data: articleList = [] } = useGetArticleList(myMentorProfile?.id || 0);
+ const isDesktop = useIsDesktopViewport();
const method = useModifyHookForm(myMentorProfile);
+ const { onSubmit } = usePutMyMentorProfileHandler();
+
+ if (!myMentorProfile || isDesktop === null) return
;
+
+ const viewProps: ModifyContentViewProps = {
+ method,
+ onSubmit,
+ myMentorProfile,
+ articleList,
+ };
+
+ return isDesktop ?
:
;
+};
+
+type ModifyContentViewProps = {
+ method: ReturnType
;
+ onSubmit: ReturnType["onSubmit"];
+ myMentorProfile: NonNullable["data"]>;
+ articleList: NonNullable["data"]>;
+};
+
+const ModifyDesktopView = ({ method, onSubmit, myMentorProfile, articleList }: ModifyContentViewProps) => {
const {
handleSubmit,
formState: { errors },
register,
} = method;
+ const { profileImageUrl, hasBadge, nickname, country, universityName, term, channels } = myMentorProfile;
- const { onSubmit } = usePutMyMentorProfileHandler();
- // 채널 타입들을 감시
- if (!myMentorProfile) return ;
+ return (
+
+
+
+ );
+};
+
+const ModifyMobileView = ({ method, onSubmit, myMentorProfile, articleList }: ModifyContentViewProps) => {
+ const {
+ handleSubmit,
+ formState: { errors },
+ register,
+ } = method;
const { profileImageUrl, hasBadge, nickname, country, universityName, term, channels } = myMentorProfile;
return (