Skip to content
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
2 changes: 1 addition & 1 deletion src/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default function Home() {
한 곳에서 관리하는 알바 구인 플랫폼
</p>
{user ? (
<Link href="/albaList">
<Link href="/albalist">
<p className="font-nexon-regular text-black inline-block rounded-lg bg-green-500 px-4 py-2 text-sm sm:px-6 sm:py-3 sm:text-base md:px-8 md:py-4 md:text-lg lg:px-10 lg:py-5 lg:text-xl">
알바 둘러보기
</p>
Expand Down
15 changes: 8 additions & 7 deletions src/app/(pages)/alba/[formId]/page.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -32,18 +32,19 @@ export default function AlbaFormDetailPage() {
if (!albaFormDetailData) return <div>데이터가 없습니다.</div>;

return (
<div className="container flex min-h-screen flex-col">
<div className="h-[562px] bg-black-100">사진영역</div>
<div className="mt-20 flex justify-between">
<div className="container flex min-h-screen flex-col px-4 sm:px-6 md:px-0">
{/* 사진영역 */}
<div className="h-[300px] bg-black-100 sm:h-[400px] md:h-[562px]">사진영역</div>
<div className="mt-4 flex flex-col justify-between sm:mt-10 md:mt-20 md:flex-row">
{/* 왼쪽 영역 */}
<div className="w-[770px] space-y-10">
<div className="w-full space-y-10 sm:w-[600px] md:w-[770px]">
<FormHeader albaFormDetailData={albaFormDetailData} />
<FormDetails albaFormDetailData={albaFormDetailData} />
{/* 지도 영역 */}
<div className="h-[400px] bg-black-100">카카오지도</div>
<div className="h-[200px] bg-black-100 sm:h-[300px] md:h-[400px]">카카오지도</div>
</div>
{/* 오른쪽 영역 */}
<div className="flex w-[640px] flex-col space-y-12">
<div className="flex w-full flex-col space-y-12 sm:w-[400px] md:w-[640px]">
<RecruitInformation albaFormDetailData={albaFormDetailData} />
</div>
</div>
Expand Down
43 changes: 24 additions & 19 deletions src/app/(pages)/alba/components/ApplicationStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <div>지원 현황을 불러오는 중입니다...</div>;
if (error && "status" in error) {
if (error.status === 403) {
return (
<div>
<p>지원 현황을 볼 권한이 없습니다.</p>
<p>{error.message}</p>
</div>
);
}
console.log("지원현황 에러", error);
}
if (error || !applicationStatusData) return <div>지원 현황 데이터를 불러오는데 실패했습니다.</div>;
console.log("applicationStatusData:", applicationStatusData);
// 개발중일 때는 아래 코드를 사용하여 에러를 확인할 수 있습니다.
// if (error || !applicationStatusData) {
// let errorMessage = "로딩 중입니다...";

return (
<div className="space-y-4 text-2xl">
<p className="text-3xl font-bold">지원 현황</p>
// 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);
// }

<ApplicationStatusCard applicationStatusData={applicationStatusData.data} />
return (
<div className="mt-20 space-y-6 border-t-2 pt-20 text-2xl">
{applicationStatusData && (
<>
<p className="text-3xl font-bold">지원 현황</p>
<ApplicationStatusCard applicationStatusData={applicationStatusData.data} />
</>
)}
</div>
);
}
9 changes: 7 additions & 2 deletions src/app/(pages)/alba/components/FormActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ interface FormActionsProps {
export default function FormActions({ isOwner }: FormActionsProps) {
return (
<div className="space-y-4 text-2xl">
<Button className="h-16" width="lg" icon={isOwner ? <FcEditImage /> : <FcFile />}>
<Button className="h-10 sm:h-12 md:h-16" width="lg" icon={isOwner ? <FcEditImage /> : <FcFile />}>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정하기 -> alba/${formId}/edit
지원하기-> apply/${formId}
버튼 클릭했을때 각각 router.push 추가해주세욥 !

{isOwner ? "수정하기" : "지원하기"}
</Button>
<Button className="h-16" width="lg" icon={isOwner ? <FcEmptyTrash /> : <FcSearch />} variant="outlined">
<Button
className="h-10 sm:h-12 md:h-16"
width="lg"
icon={isOwner ? <FcEmptyTrash /> : <FcSearch />}
variant="outlined"
>
{isOwner ? "삭제하기" : "내 지원내역 보기"}
</Button>
</div>
Expand Down
6 changes: 4 additions & 2 deletions src/app/(pages)/alba/components/FormDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ export default function FormDetails({ albaFormDetailData }: FormDetailsProps) {
return (
<>
<div className="mb-4 flex items-end gap-4">
<span className="text-2xl text-black-400 underline">{albaFormDetailData.storeName || "가게명"}</span>
<span className="text-xl text-grayscale-500">
<span className="text-lg text-black-400 underline sm:text-xl md:text-2xl">
{albaFormDetailData.storeName || "가게명"}
</span>
<span className="text-md text-grayscale-500 sm:text-lg md:text-xl">
{albaFormDetailData.location || "위치"} ・ {"경력 정보 없음"}
</span>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/app/(pages)/alba/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Suspense } from "react";

export default function AlbaFormDetailLayout({ children }: { children: React.ReactNode }) {
return (
<div className="mx-auto max-w-screen-2xl px-4 py-8">
<div className="mx-auto max-w-screen-2xl px-4 py-4 sm:px-6 md:py-8">
<Suspense
fallback={
<div className="flex h-[calc(100vh-200px)] items-center justify-center">
Expand Down
2 changes: 1 addition & 1 deletion src/app/(pages)/myAlbaform/(role)/applicant/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
4 changes: 3 additions & 1 deletion src/app/(pages)/myAlbaform/(role)/owner/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,9 @@ export default function AlbaList() {
<React.Fragment key={page.nextCursor}>
{page.data.map((form) => (
<div key={form.id}>
<AlbaListItem {...form} />
<Link href={`/alba/${form.id}`}>
<AlbaListItem {...form} />
</Link>
</div>
))}
</React.Fragment>
Expand Down
91 changes: 45 additions & 46 deletions src/app/(pages)/mypage/components/sections/PostsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => (
<div className="flex h-[calc(100vh-200px)] items-center justify-center">
<p className={className}>{message}</p>
</div>
);

const PostCard = ({ post }: { post: PostListType }) => (
<div className="rounded-lg border p-4 transition-all hover:border-primary-orange-200">
<h3 className="font-bold">{post.title}</h3>
<p className="text-grayscale-600">{post.content}</p>
<div className="mt-2 text-sm text-grayscale-500">
<span>댓글 {post.commentCount}</span>
<span className="mx-2">•</span>
<span>좋아요 {post.likeCount}</span>
</div>
</div>
);

const LoadingSpinner = () => (
<div className="flex justify-center py-4">
<div className="h-6 w-6 animate-spin rounded-full border-2 border-primary-orange-300 border-t-transparent" />
</div>
);

const PostList = ({ pages }: { pages: any[] }) => (
<>
{pages.map((page, index) => (
<React.Fragment key={index}>
{page.data.map((post: PostListType) => (
<PostCard key={post.id} post={post} />
))}
</React.Fragment>
))}
</>
);

export default function PostsSection() {
// 정렬 상태 관리
const { orderBy } = useMySortStore();
useProfileStringValue();

// 무한 스크롤을 위한 Intersection Observer 설정
const { ref, inView } = useInView({
Expand All @@ -34,58 +73,18 @@ export default function PostsSection() {
}, [inView, hasNextPage, fetchNextPage, isFetchingNextPage]);

// 에러 상태 처리
if (error) {
return (
<div className="flex h-[calc(100vh-200px)] items-center justify-center">
<p className="text-red-500">게시글을 불러오는데 실패했습니다.</p>
</div>
);
}

// 로딩 상태 처리
if (isLoading) {
return (
<div className="flex h-[calc(100vh-200px)] items-center justify-center">
<div>로딩 중...</div>
</div>
);
}

if (error) return <StatusMessage message="게시글을 불러오는데 실패했습니다." className="text-red-500" />;
if (isLoading) return <StatusMessage message="로딩 중..." />;
// 데이터가 없는 경우 처리
if (!data?.pages[0]?.data?.length) {
return (
<div className="flex h-[calc(100vh-200px)] items-center justify-center">
<p className="text-grayscale-500">작성한 게시글이 없습니다.</p>
</div>
);
}
if (!data?.pages[0]?.data?.length) return <StatusMessage message="작성한 게시글이 없습니다." />;

return (
<div className="space-y-4">
{/* 게시글 목록 렌더링 */}
{data.pages.map((page, index) => (
<React.Fragment key={index}>
{page.data.map((post: PostListType) => (
<div key={post.id} className="rounded-lg border p-4 transition-all hover:border-primary-orange-200">
<h3 className="font-bold">{post.title}</h3>
<p className="text-grayscale-600">{post.content}</p>
<div className="mt-2 text-sm text-grayscale-500">
<span>댓글 {post.commentCount}</span>
<span className="mx-2">•</span>
<span>좋아요 {post.likeCount}</span>
</div>
</div>
))}
</React.Fragment>
))}
<div className="mt-10 space-y-4">
<PostList pages={data.pages} />

{/* 무한 스크롤 트리거 영역 */}
<div ref={ref} className="h-4 w-full">
{isFetchingNextPage && (
<div className="flex justify-center py-4">
<div className="h-6 w-6 animate-spin rounded-full border-2 border-primary-orange-300 border-t-transparent" />
</div>
)}
{isFetchingNextPage && <LoadingSpinner />}
</div>
</div>
);
Expand Down
57 changes: 47 additions & 10 deletions src/app/components/card/cardList/ApplicationStatusCard.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div>
{applicationStatusData.map((application) => (
<div key={application.id}>{application.name}</div> // 고유 키 추가
))}
<div className="w-[375px] text-xs md:w-[770px] md:text-base">
<div className="flex flex-col">
{/* Thead */}
<div className="sticky grid grid-cols-[1fr_2fr_2fr_1fr] border-b border-line-100 px-6 py-4">
<span className={theadStyle}>이름</span>
<span className={theadStyle}>전화번호</span>
<div className="flex items-center gap-2">
<span className={theadStyle}>경력</span>
<button onClick={() => setExperienceSort((prev) => !prev)}>
<FaSortAmountDown className={cn(sortIconStyle, experienceSort ? "rotate-0" : "rotate-180")} />
</button>
</div>
<div className="flex items-center gap-2">
<span className={theadStyle}>상태</span>
<button onClick={() => setStatusSort((prev) => !prev)}>
<FaSortAmountDown className={cn(sortIconStyle, statusSort ? "rotate-0" : "rotate-180")} />
</button>
</div>
</div>

{/* Tbody */}
<div className="scrollbar-custom h-[360px] overflow-y-auto md:h-[400px]">
{applicationStatusData.map((application) => (
<div key={application.id} className="grid grid-cols-[1fr_2fr_2fr_1fr] border-b border-line-100 px-6 py-4">
<span className={tbodyStyle}>{application.name}</span>
<span className={tbodyStyle}>{application.phoneNumber}</span>
<span className={tbodyStyle}>{application.experienceMonths}개월</span>
<span className={tbodyStyle}>{application.status}</span>
</div>
))}
</div>
</div>
</div>
);
}
};

export default ApplicationStatusCard;
8 changes: 7 additions & 1 deletion src/app/components/chip/Chip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ interface ChipProps {
* @param icon
* @param textStyle - 추가 스타일
*/
const Chip: React.FC<ChipProps> = ({ label = "Label", variant, border, icon, textStyle = "" }: ChipProps) => {
const Chip: React.FC<ChipProps> = ({
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]"
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/layout/forms/SearchSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function SearchSection() {
params.delete("keyword");
}

router.push(`/albaList?${params.toString()}`);
router.push(`/albalist?${params.toString()}`);
};

return (
Expand Down
4 changes: 2 additions & 2 deletions src/app/stories/design-system/components/layout/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ export default function Header() {
</Link>

<div className="ml-4 flex h-16 space-x-2 sm:ml-6 sm:space-x-4 md:ml-10 md:space-x-6">
<Link href="/albaList" className={getLinkClassName("/albaList")}>
<Link href="/albalist" className={getLinkClassName("/albalist")}>
알바 목록
</Link>
<Link href="/albaTalk" className={getLinkClassName("/albaTalk")}>
<Link href="/albatalk" className={getLinkClassName("/albatalk")}>
알바 토크
</Link>
<Link href="/myalbaform" className={getLinkClassName("/myalbaform")}>
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/queries/auth/useLogin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const useLogin = () => {
if (data?.user) {
queryClient.setQueryData(["user"], { user: data.user });
toast.success("로그인되었습니다!");
router.push("/");
router.push("/mypage");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아까 말씀드린대로 이부분은 목록 페이지로 보내는게 자연스러울거같아요 ~

router.refresh();
}
},
Expand Down
1 change: 0 additions & 1 deletion src/hooks/queries/form/detail/useApplicationStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export const useApplicationStatus = (props: UseApplicationStatusProps) => {
enabled: !!props.formId,
});

console.log("지원형황", query.data);
return {
...query,
applicationStatusData: query.data,
Expand Down
Loading
Loading