diff --git a/src/app/(home)/page.tsx b/src/app/(home)/page.tsx index 1d3dcd9b..8f4f15ea 100644 --- a/src/app/(home)/page.tsx +++ b/src/app/(home)/page.tsx @@ -60,7 +60,7 @@ export default function Home() { 한 곳에서 관리하는 알바 구인 플랫폼

{user ? ( - +

알바 둘러보기

diff --git a/src/app/(pages)/alba/[formId]/page.tsx b/src/app/(pages)/alba/[formId]/page.tsx index 3b3d7590..d1d8a2fb 100644 --- a/src/app/(pages)/alba/[formId]/page.tsx +++ b/src/app/(pages)/alba/[formId]/page.tsx @@ -1,5 +1,5 @@ "use client"; - +// 알바폼 상세 페이지 import { useParams } from "next/navigation"; import React, { useEffect, useState } from "react"; import { useUser } from "@/hooks/queries/user/me/useUser"; @@ -32,18 +32,19 @@ export default function AlbaFormDetailPage() { if (!albaFormDetailData) return
데이터가 없습니다.
; return ( -
-
사진영역
-
+
+ {/* 사진영역 */} +
사진영역
+
{/* 왼쪽 영역 */} -
+
{/* 지도 영역 */} -
카카오지도
+
카카오지도
{/* 오른쪽 영역 */} -
+
diff --git a/src/app/(pages)/alba/components/ApplicationStatus.tsx b/src/app/(pages)/alba/components/ApplicationStatus.tsx index e4fa4247..90544cca 100644 --- a/src/app/(pages)/alba/components/ApplicationStatus.tsx +++ b/src/app/(pages)/alba/components/ApplicationStatus.tsx @@ -7,31 +7,36 @@ interface ApplicationStatusProps { } export default function ApplicationStatus({ formId }: ApplicationStatusProps) { - const { applicationStatusData, isLoading, error } = useApplicationStatus({ + const { applicationStatusData } = useApplicationStatus({ formId, limit: 5, // 요청당 데이터 수 제한 }); - if (isLoading) return
지원 현황을 불러오는 중입니다...
; - if (error && "status" in error) { - if (error.status === 403) { - return ( -
-

지원 현황을 볼 권한이 없습니다.

-

{error.message}

-
- ); - } - console.log("지원현황 에러", error); - } - if (error || !applicationStatusData) return
지원 현황 데이터를 불러오는데 실패했습니다.
; - console.log("applicationStatusData:", applicationStatusData); + // 개발중일 때는 아래 코드를 사용하여 에러를 확인할 수 있습니다. + // if (error || !applicationStatusData) { + // let errorMessage = "로딩 중입니다..."; - return ( -
-

지원 현황

+ // if (!error && !applicationStatusData) { + // // 로딩 중 메시지 설정 + // errorMessage = "데이터를 불러오는 중입니다..."; + // } else if (axios.isAxiosError(error)) { + // const axiosError = error as AxiosError; + // errorMessage = (axiosError.response?.data as { message?: string })?.message || axiosError.message; + // } else if (error instanceof Error) { + // errorMessage = error.message; + // } + + // console.log("지원 현황 불러오기 에러: ", errorMessage); + // } - + return ( +
+ {applicationStatusData && ( + <> +

지원 현황

+ + + )}
); } diff --git a/src/app/(pages)/alba/components/FormActions.tsx b/src/app/(pages)/alba/components/FormActions.tsx index acd4b8c5..e66ffe1a 100644 --- a/src/app/(pages)/alba/components/FormActions.tsx +++ b/src/app/(pages)/alba/components/FormActions.tsx @@ -12,10 +12,15 @@ interface FormActionsProps { export default function FormActions({ isOwner }: FormActionsProps) { return (
- -
diff --git a/src/app/(pages)/alba/components/FormDetail.tsx b/src/app/(pages)/alba/components/FormDetail.tsx index 157a19b8..5b3f1d8a 100644 --- a/src/app/(pages)/alba/components/FormDetail.tsx +++ b/src/app/(pages)/alba/components/FormDetail.tsx @@ -15,8 +15,10 @@ export default function FormDetails({ albaFormDetailData }: FormDetailsProps) { return ( <>
- {albaFormDetailData.storeName || "가게명"} - + + {albaFormDetailData.storeName || "가게명"} + + {albaFormDetailData.location || "위치"} ・ {"경력 정보 없음"}
diff --git a/src/app/(pages)/alba/layout.tsx b/src/app/(pages)/alba/layout.tsx index af80a7bd..a6039fe0 100644 --- a/src/app/(pages)/alba/layout.tsx +++ b/src/app/(pages)/alba/layout.tsx @@ -2,7 +2,7 @@ import React, { Suspense } from "react"; export default function AlbaFormDetailLayout({ children }: { children: React.ReactNode }) { return ( -
+
diff --git a/src/app/(pages)/albaFormSupportDetail/layout.tsx b/src/app/(pages)/albaform-support-detail/layout.tsx similarity index 100% rename from src/app/(pages)/albaFormSupportDetail/layout.tsx rename to src/app/(pages)/albaform-support-detail/layout.tsx diff --git a/src/app/(pages)/albaFormSupportDetail/page.tsx b/src/app/(pages)/albaform-support-detail/page.tsx similarity index 100% rename from src/app/(pages)/albaFormSupportDetail/page.tsx rename to src/app/(pages)/albaform-support-detail/page.tsx diff --git a/src/app/(pages)/myAlbaform/(role)/applicant/page.tsx b/src/app/(pages)/myAlbaform/(role)/applicant/page.tsx index 21377c29..9c7af1f2 100644 --- a/src/app/(pages)/myAlbaform/(role)/applicant/page.tsx +++ b/src/app/(pages)/myAlbaform/(role)/applicant/page.tsx @@ -6,10 +6,10 @@ import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { useInView } from "react-intersection-observer"; import { useUser } from "@/hooks/queries/user/me/useUser"; import { userRoles } from "@/constants/userRoles"; -import ApplicantSortSection from "./components/ApplicantSortSection"; import SearchSection from "@/app/components/layout/forms/SearchSection"; import MyApplicationListItem from "@/app/components/card/cardList/MyApplicationListItem"; import { useMyApplications } from "@/hooks/queries/user/me/useMyApplications"; +import ApplicantSortSection from "./components/ApplicantSortSection"; const APPLICATIONS_PER_PAGE = 10; diff --git a/src/app/(pages)/myAlbaform/(role)/owner/page.tsx b/src/app/(pages)/myAlbaform/(role)/owner/page.tsx index 34a4cfe3..5b53baba 100644 --- a/src/app/(pages)/myAlbaform/(role)/owner/page.tsx +++ b/src/app/(pages)/myAlbaform/(role)/owner/page.tsx @@ -205,7 +205,9 @@ export default function AlbaList() { {page.data.map((form) => (
- + + +
))}
diff --git a/src/app/(pages)/mypage/components/sections/PostsSection.tsx b/src/app/(pages)/mypage/components/sections/PostsSection.tsx index d6d4aa8c..f5ffc272 100644 --- a/src/app/(pages)/mypage/components/sections/PostsSection.tsx +++ b/src/app/(pages)/mypage/components/sections/PostsSection.tsx @@ -5,13 +5,52 @@ import { useInView } from "react-intersection-observer"; import { useMyPosts } from "@/hooks/queries/user/me/useMyPosts"; import { useMySortStore } from "@/store/mySortStore"; import type { PostListType } from "@/types/response/post"; +import { useProfileStringValue } from "@/hooks/queries/user/me/useProfileStringValue"; // 한 페이지당 게시글 수 const POSTS_PER_PAGE = 10; +// 컴포넌트 +const StatusMessage = ({ message, className = "text-grayscale-500" }: { message: string; className?: string }) => ( +
+

{message}

+
+); + +const PostCard = ({ post }: { post: PostListType }) => ( +
+

{post.title}

+

{post.content}

+
+ 댓글 {post.commentCount} + + 좋아요 {post.likeCount} +
+
+); + +const LoadingSpinner = () => ( +
+
+
+); + +const PostList = ({ pages }: { pages: any[] }) => ( + <> + {pages.map((page, index) => ( + + {page.data.map((post: PostListType) => ( + + ))} + + ))} + +); + export default function PostsSection() { // 정렬 상태 관리 const { orderBy } = useMySortStore(); + useProfileStringValue(); // 무한 스크롤을 위한 Intersection Observer 설정 const { ref, inView } = useInView({ @@ -34,58 +73,18 @@ export default function PostsSection() { }, [inView, hasNextPage, fetchNextPage, isFetchingNextPage]); // 에러 상태 처리 - if (error) { - return ( -
-

게시글을 불러오는데 실패했습니다.

-
- ); - } - - // 로딩 상태 처리 - if (isLoading) { - return ( -
-
로딩 중...
-
- ); - } - + if (error) return ; + if (isLoading) return ; // 데이터가 없는 경우 처리 - if (!data?.pages[0]?.data?.length) { - return ( -
-

작성한 게시글이 없습니다.

-
- ); - } + if (!data?.pages[0]?.data?.length) return ; return ( -
- {/* 게시글 목록 렌더링 */} - {data.pages.map((page, index) => ( - - {page.data.map((post: PostListType) => ( -
-

{post.title}

-

{post.content}

-
- 댓글 {post.commentCount} - - 좋아요 {post.likeCount} -
-
- ))} -
- ))} +
+ {/* 무한 스크롤 트리거 영역 */}
- {isFetchingNextPage && ( -
-
-
- )} + {isFetchingNextPage && }
); diff --git a/src/app/components/card/cardList/ApplicationStatusCard.tsx b/src/app/components/card/cardList/ApplicationStatusCard.tsx index fcdac9b0..846694fb 100644 --- a/src/app/components/card/cardList/ApplicationStatusCard.tsx +++ b/src/app/components/card/cardList/ApplicationStatusCard.tsx @@ -1,18 +1,55 @@ "use client"; - -import React from "react"; +import React, { useState } from "react"; import { ApplicationResponse } from "@/types/response/application"; - +import { FaSortAmountDown } from "react-icons/fa"; +import { cn } from "@/lib/tailwindUtil"; interface ApplicationStatusCardProps { - applicationStatusData: ApplicationResponse[]; // 전달받는 데이터는 배열 + applicationStatusData: ApplicationResponse[]; } -export default function ApplicationStatusCard({ applicationStatusData }: ApplicationStatusCardProps) { +// 지원현황 카드 컴포넌트 +const ApplicationStatusCard = ({ applicationStatusData }: ApplicationStatusCardProps) => { + const [experienceSort, setExperienceSort] = useState(false); + const [statusSort, setStatusSort] = useState(false); + + const theadStyle = "text-center font-semibold text-grayscale-700"; + const tbodyStyle = "text-center"; + const sortIconStyle = "text-primary-orange-300 transition-transform hover:scale-110"; return ( -
- {applicationStatusData.map((application) => ( -
{application.name}
// 고유 키 추가 - ))} +
+
+ {/* Thead */} +
+ 이름 + 전화번호 +
+ 경력 + +
+
+ 상태 + +
+
+ + {/* Tbody */} +
+ {applicationStatusData.map((application) => ( +
+ {application.name} + {application.phoneNumber} + {application.experienceMonths}개월 + {application.status} +
+ ))} +
+
); -} +}; + +export default ApplicationStatusCard; diff --git a/src/app/components/chip/Chip.tsx b/src/app/components/chip/Chip.tsx index 4c638786..0654736a 100644 --- a/src/app/components/chip/Chip.tsx +++ b/src/app/components/chip/Chip.tsx @@ -16,7 +16,13 @@ interface ChipProps { * @param icon * @param textStyle - 추가 스타일 */ -const Chip: React.FC = ({ label = "Label", variant, border, icon, textStyle = "" }: ChipProps) => { +const Chip: React.FC = ({ + label = "Label", + variant, + border, + icon, + textStyle = "text-sm md:text-base", +}: ChipProps) => { const wrapperStyle = "rounded flex items-center justify-center min-w-[60px] m-1"; const paddingStyle = icon ? "px-[8px] py-1 md:px-[12px] md:py-1 lg:px-[8px] lg:py-[6px]" diff --git a/src/app/components/layout/forms/SearchSection.tsx b/src/app/components/layout/forms/SearchSection.tsx index d5d991bb..eac801fe 100644 --- a/src/app/components/layout/forms/SearchSection.tsx +++ b/src/app/components/layout/forms/SearchSection.tsx @@ -19,7 +19,7 @@ export default function SearchSection() { params.delete("keyword"); } - router.push(`/albaList?${params.toString()}`); + router.push(`/albalist?${params.toString()}`); }; return ( diff --git a/src/app/stories/design-system/components/layout/Header.tsx b/src/app/stories/design-system/components/layout/Header.tsx index 97325074..43fb4e76 100644 --- a/src/app/stories/design-system/components/layout/Header.tsx +++ b/src/app/stories/design-system/components/layout/Header.tsx @@ -30,10 +30,10 @@ export default function Header() {
- + 알바 목록 - + 알바 토크 diff --git a/src/hooks/queries/auth/useLogin.ts b/src/hooks/queries/auth/useLogin.ts index 479414fe..32c7207a 100644 --- a/src/hooks/queries/auth/useLogin.ts +++ b/src/hooks/queries/auth/useLogin.ts @@ -27,7 +27,7 @@ export const useLogin = () => { if (data?.user) { queryClient.setQueryData(["user"], { user: data.user }); toast.success("로그인되었습니다!"); - router.push("/"); + router.push("/mypage"); router.refresh(); } }, diff --git a/src/hooks/queries/form/detail/useApplicationStatus.ts b/src/hooks/queries/form/detail/useApplicationStatus.ts index 694de6c5..9f33013f 100644 --- a/src/hooks/queries/form/detail/useApplicationStatus.ts +++ b/src/hooks/queries/form/detail/useApplicationStatus.ts @@ -37,7 +37,6 @@ export const useApplicationStatus = (props: UseApplicationStatusProps) => { enabled: !!props.formId, }); - console.log("지원형황", query.data); return { ...query, applicationStatusData: query.data, diff --git a/src/hooks/queries/user/me/useProfileStringValue.ts b/src/hooks/queries/user/me/useProfileStringValue.ts new file mode 100644 index 00000000..56d68cc6 --- /dev/null +++ b/src/hooks/queries/user/me/useProfileStringValue.ts @@ -0,0 +1,56 @@ +import { useQueryClient, useQuery, useMutation } from "@tanstack/react-query"; +import toast from "react-hot-toast"; +import type { QueryKey, UseQueryOptions } from "@tanstack/react-query"; + +const PROFILE_STRING_KEY = "profileStringValue"; + +export const useProfileStringValue = () => { + const queryClient = useQueryClient(); + + const { data: hasStringValue = false } = useQuery({ + queryKey: [PROFILE_STRING_KEY], + queryFn: async () => { + const userData = queryClient.getQueryData<{ user: any }>(["user"]); + const user = userData?.user; + + if (!user) return false; + + const hasString = Object.values(user).some( + (value) => value !== null && value !== undefined && value === "string" + ); + + if (hasString) { + toast.error("내 정보를 수정하세요", { + duration: 3000, + position: "top-center", + id: "profile-string-toast", + }); + } + + return hasString; + }, + enabled: !!queryClient.getQueryData(["user"]), + staleTime: 0, + refetchOnMount: true, + }); + + // user 쿼리 변경 감지 + useQuery({ + queryKey: ["user"], + queryFn: () => null, + enabled: false, + onSettled: () => { + // user 데이터가 변경되면 profileStringValue 쿼리 재실행 + queryClient.invalidateQueries({ queryKey: [PROFILE_STRING_KEY] }); + }, + } as UseQueryOptions); + + const { mutate: setHasStringValue } = useMutation({ + mutationFn: (newValue: boolean) => Promise.resolve(newValue), + onSuccess: (newValue) => { + queryClient.setQueryData([PROFILE_STRING_KEY], newValue); + }, + }); + + return { hasStringValue, setHasStringValue }; +}; diff --git a/src/utils/workDayFormatter.ts b/src/utils/workDayFormatter.ts index 0c2be47e..6a2f77bc 100644 --- a/src/utils/workDayFormatter.ts +++ b/src/utils/workDayFormatter.ts @@ -18,7 +18,19 @@ export const getWorkDaysDisplay = (isNegotiableWorkDays: boolean, workDays: stri // 요일 순서 정의 const dayOrder = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"]; - const sortedDays = workDays.sort((a, b) => dayOrder.indexOf(a) - dayOrder.indexOf(b)); + + // 한글 요일을 영어 요일로 변환 + const translatedWorkDays = workDays.map((day) => { + const key = (Object.keys(workDayOptions) as Array).find( + (k) => workDayOptions[k] === day + ); + return key ? key : day; // 변환된 요일 또는 원래 요일 반환 + }); + + // 유효한 요일만 필터링 + const validWorkDays = translatedWorkDays.filter((day) => dayOrder.includes(day)); + const sortedDays = validWorkDays.sort((a, b) => dayOrder.indexOf(a) - dayOrder.indexOf(b)); + console.log("getWorkDaysDisplay", sortedDays); const result: string[] = []; let startDay = sortedDays[0]; @@ -44,5 +56,5 @@ export const getWorkDaysDisplay = (isNegotiableWorkDays: boolean, workDays: stri prevIndex = currentIndex; } - return result.join(", "); + return result.filter((day) => day).join(", "); // 빈 문자열 필터링 후 join };