Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ed1ab85
Merge branch 'refactor/layout' into refactor/form
hongggyelim Dec 14, 2024
0f2b9a4
chore: 알바폼 상세 태블릿 수정
yyezzzy Dec 14, 2024
b01b6bb
Merge remote-tracking branch 'origin/dev' into refactor/form
hongggyelim Dec 14, 2024
11f26c7
chore: 버튼크기 조정
hongggyelim Dec 14, 2024
2734784
feat: 이미지 초기값 로드 작업중
hongggyelim Dec 14, 2024
d9f0860
Merge remote-tracking branch 'origin/dev' into refactor/form
hongggyelim Dec 14, 2024
103a022
feat: 이미지 프리뷰 불러오기
hongggyelim Dec 14, 2024
d5b1149
fix: 이미지파일 데이터 없는경우 처리
hongggyelim Dec 14, 2024
9aab4a9
feat: edit에서도 이미지 잘 가져옴
hongggyelim Dec 14, 2024
e6d63ff
bug: sdk 로드안됨
yyezzzy Dec 15, 2024
ac022d0
Merge branch 'dev' of https://github.com/FE9-2/workroot into feat/app…
yyezzzy Dec 15, 2024
12232b4
chore: 공유버튼 z-index 제거
yyezzzy Dec 15, 2024
92c0167
feat: 카카오 SDK 초기화 로직 useEffect => <
yyezzzy Dec 15, 2024
ff03db0
fix: 버튼 위치 수정
hongggyelim Dec 15, 2024
25659b4
refactor: 이미지 업로드 로직 위치 인풋 핸들러로 변경
hongggyelim Dec 15, 2024
25aefa2
feat: addform 동작 확인
hongggyelim Dec 15, 2024
993ae17
feat: 삭제 핸들러 수정
hongggyelim Dec 15, 2024
eb71f07
Merge remote-tracking branch 'origin/dev' into refactor/form
hongggyelim Dec 15, 2024
88114f4
chore: 필터드롭다운 mousedown으로 변경
hongggyelim Dec 15, 2024
8289952
feat: edit 페이지 동작 확인
hongggyelim Dec 15, 2024
49a7681
fix: 내가 쓴 글 > 내 정보 수정, 비밀번호 변경 대신 정렬 드롭다운이 나오는 버그 수정
cccwon2 Dec 15, 2024
14a781c
chore: 콘솔 출력 삭제
hongggyelim Dec 15, 2024
4567497
refactor: 각 컴포넌트 버튼 색, 폰트 사이즈 변경, LinkBtn 추가 및 연동
cccwon2 Dec 15, 2024
eefbb9d
chore: 공유 버튼 외부 클릭시 닫힘
yyezzzy Dec 15, 2024
cf27434
chore: 기간이 아닌 Item은 중앙 정렬
yyezzzy Dec 15, 2024
ff58188
chore: 모바일, 태블릿일 때 contents를 중앙로 정렬
yyezzzy Dec 15, 2024
852f26c
bugfix
yyezzzy Dec 15, 2024
32d3873
feat: 이미 지원한 공고일 경우 "이미 지원한 공고"
yyezzzy Dec 15, 2024
0c809c6
chore: 이미 지원한 공고인지 확인 로직 수정
yyezzzy Dec 15, 2024
0dd7b7f
chore: github account yyezzzyy
yyezzzy Dec 15, 2024
d964eed
refactor: 넥슨 lv.1 폰트, 학교안심 둥근미소 cnd 대신 로컬 폰트로 변경
cccwon2 Dec 16, 2024
0a6709b
chore: button 관련 수정
cccwon2 Dec 16, 2024
32c71a5
Merge pull request #163 from FE9-2/fix/bug-won
yyezzzyy Dec 16, 2024
fb08541
feat: 폼작성 페이지에서 유저 권한 확인
hongggyelim Dec 16, 2024
094ae16
Merge remote-tracking branch 'origin/dev' into refactor/form
hongggyelim Dec 16, 2024
bd390b3
Merge pull request #164 from FE9-2/refactor/form
hongggyelim Dec 16, 2024
876d46f
Merge branch 'dev' of https://github.com/FE9-2/workroot into feat/app…
yyezzzy Dec 16, 2024
6791c39
chore: 상세페이지로 이동할 때 !user 로딩 스피너 제거
yyezzzy Dec 16, 2024
eb913b8
Merge pull request #168 from FE9-2/feat/applicationStatusCard-sorting
hongggyelim Dec 16, 2024
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
Binary file not shown.
Binary file not shown.
Binary file added public/fonts/nexon/NexonLv1GothicOTF-B.woff
Binary file not shown.
Binary file added public/fonts/nexon/NexonLv1GothicOTF-R.woff
Binary file not shown.
70 changes: 62 additions & 8 deletions src/app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,62 @@
"use client";
import Button from "@/app/components/button/default/Button";
import DotLoadingSpinner from "@/app/components/loading-spinner/DotLoadingSpinner";
import { useLogin } from "@/hooks/queries/auth/useLogin";
import { type LoginSchema, loginSchema } from "@/schemas/authSchema";
import { zodResolver } from "@hookform/resolvers/zod";
import Image from "next/image";
import Link from "next/link";
import { useForm } from "react-hook-form";
import { UserRole, userRoles } from "@/constants/userRoles";

export default function LoginPage() {
// 로그인 훅과 로딩 상태 관리
const { login, isPending } = useLogin();

// 폼 유효성 검사 및 상태 관리
const {
register,
handleSubmit,
formState: { errors },
setValue,
} = useForm<LoginSchema>({
resolver: zodResolver(loginSchema),
});

// 일반 로그인 제출 핸들러
const onSubmit = (data: LoginSchema) => {
login(data);
};

// 테스트 계정 로그인 핸들러 - 폼 유효성 검사 통과
const handleTestLogin = (role: UserRole) => {
const testCredentials = {
// 지원자 테스트 계정 정보
[userRoles.APPLICANT]: {
email: process.env.NEXT_PUBLIC_TEST_APPLICANT_ID as string,
password: process.env.NEXT_PUBLIC_TEST_APPLICANT_PASSWORD as string,
},
// 사장님 테스트 계정 정보
[userRoles.OWNER]: {
email: process.env.NEXT_PUBLIC_TEST_OWNER_ID as string,
password: process.env.NEXT_PUBLIC_TEST_OWNER_PASSWORD as string,
},
};

// setValue를 통해 폼 값을 직접 설정
const credentials = testCredentials[role];
setValue("email", credentials.email);
setValue("password", credentials.password);

// 설정된 값으로 폼 제출
handleSubmit((data) => login(data))();
};

return (
<div className="flex min-h-screen items-center justify-center bg-gradient-to-r from-lime-200 to-lime-300 px-4 py-12 sm:px-6 lg:px-8">
<div className="w-full max-w-md space-y-8 rounded-lg bg-white p-8 shadow-lg">
<div>
<h2 className="text-grayscale-900 text-center text-3xl font-bold tracking-tight">로그인</h2>
<div className="text-grayscale-900 text-center text-3xl font-bold tracking-tight">로그인</div>
<p className="text-grayscale-600 mt-2 text-center text-sm">
아직 계정이 없으신가요?{" "}
<Link href="/signup" className="font-medium text-lime-600 hover:text-lime-500">
Expand Down Expand Up @@ -55,14 +86,10 @@ export default function LoginPage() {
</div>
</div>

<div>
<button
type="submit"
disabled={isPending}
className="group relative flex w-full justify-center rounded-lg bg-lime-600 px-4 py-2 text-sm font-medium text-white hover:bg-lime-700 focus:outline-none focus:ring-2 focus:ring-lime-500 focus:ring-offset-2 disabled:bg-lime-300"
>
<div className="flex justify-center">
<Button type="submit" variant="solid" color="lime" width="md" disabled={isPending}>
{isPending ? <DotLoadingSpinner /> : "로그인"}
</button>
</Button>
</div>
<div className="flex items-center justify-center">
<hr className="flex-grow border-t border-grayscale-200" />
Expand All @@ -85,6 +112,33 @@ export default function LoginPage() {
<Image src="/icons/social/social_kakao.svg" width={72} height={72} alt="카카오 로그인" />
</Link>
</div>
<div className="flex items-center justify-center">
<hr className="flex-grow border-t border-grayscale-200" />
<span className="mx-4 text-sm text-grayscale-400">테스트 계정으로 로그인하기</span>
<hr className="flex-grow border-t border-grayscale-200" />
</div>
<div className="flex justify-center space-x-6">
<Button
type="button"
variant="outlined"
width="sm"
color="lime"
onClick={() => handleTestLogin(userRoles.APPLICANT)}
disabled={isPending}
>
지원자로 로그인
</Button>
<Button
type="button"
variant="solid"
width="sm"
color="lime"
onClick={() => handleTestLogin(userRoles.OWNER)}
disabled={isPending}
>
사장님으로 로그인
</Button>
</div>
</form>
</div>
</div>
Expand Down
13 changes: 5 additions & 8 deletions src/app/(auth)/signup/applicant/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Link from "next/link";
import { useForm } from "react-hook-form";
import Image from "next/image";
import DotLoadingSpinner from "@/app/components/loading-spinner/DotLoadingSpinner";
import Button from "@/app/components/button/default/Button";

export default function ApplicantSignupPage() {
const { signup, isPending } = useSignup();
Expand All @@ -32,7 +33,7 @@ export default function ApplicantSignupPage() {
<div className="flex min-h-screen items-center justify-center bg-gradient-to-r from-lime-200 to-lime-300 px-4 py-12 sm:px-6 lg:px-8">
<div className="w-full max-w-md space-y-8 rounded-lg bg-white p-8 shadow-lg">
<div>
<h2 className="text-grayscale-900 text-center text-3xl font-bold tracking-tight">지원자 회원가입</h2>
<div className="text-grayscale-900 text-center text-3xl font-bold tracking-tight">지원자 회원가입</div>
<p className="text-grayscale-600 mt-2 text-center text-sm">
이미 계정이 있으신가요?{" "}
<Link href="/login" className="font-medium text-lime-600 hover:text-lime-500">
Expand Down Expand Up @@ -98,14 +99,10 @@ export default function ApplicantSignupPage() {
{errors.phoneNumber && <p className="mt-1 text-sm text-red-600">{errors.phoneNumber.message}</p>}
</div>
</div>
<div>
<button
type="submit"
disabled={isPending}
className="group relative flex w-full justify-center rounded-lg bg-lime-600 px-4 py-2 text-sm font-medium text-white hover:bg-lime-700 focus:outline-none focus:ring-2 focus:ring-lime-500 focus:ring-offset-2 disabled:bg-lime-300"
>
<div className="flex justify-center">
<Button type="submit" variant="solid" color="lime" width="md" disabled={isPending}>
{isPending ? <DotLoadingSpinner /> : "회원가입"}
</button>
</Button>
</div>
<div className="flex items-center justify-center">
<hr className="flex-grow border-t border-grayscale-200" />
Expand Down
13 changes: 5 additions & 8 deletions src/app/(auth)/signup/owner/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Link from "next/link";
import { useForm } from "react-hook-form";
import Image from "next/image";
import DotLoadingSpinner from "@/app/components/loading-spinner/DotLoadingSpinner";
import Button from "@/app/components/button/default/Button";

export default function OwnerSignupPage() {
const { signup, isPending } = useSignup();
Expand All @@ -34,7 +35,7 @@ export default function OwnerSignupPage() {
<div className="flex min-h-screen items-center justify-center bg-gradient-to-r from-lime-200 to-lime-300 px-4 py-12 sm:px-6 lg:px-8">
<div className="w-full max-w-md space-y-8 rounded-lg bg-white p-8 shadow-lg">
<div>
<h2 className="text-grayscale-900 text-center text-3xl font-bold tracking-tight">사장님 회원가입</h2>
<div className="text-grayscale-900 text-center text-3xl font-bold tracking-tight">사장님 회원가입</div>
<p className="text-grayscale-600 mt-2 text-center text-sm">
이미 계정이 있으신가요?{" "}
<Link href="/login" className="font-medium text-lime-600 hover:text-lime-500">
Expand Down Expand Up @@ -120,14 +121,10 @@ export default function OwnerSignupPage() {
{errors.location && <p className="mt-1 text-sm text-red-600">{errors.location.message}</p>}
</div>
</div>
<div>
<button
type="submit"
disabled={isPending}
className="group relative flex w-full justify-center rounded-lg bg-lime-600 px-4 py-2 text-sm font-medium text-white hover:bg-lime-700 focus:outline-none focus:ring-2 focus:ring-lime-500 focus:ring-offset-2 disabled:bg-lime-300"
>
<div className="flex justify-center">
<Button type="submit" variant="solid" color="lime" width="md" disabled={isPending}>
{isPending ? <DotLoadingSpinner /> : "회원가입"}
</button>
</Button>
</div>
<div className="flex items-center justify-center">
<hr className="flex-grow border-t border-grayscale-200" />
Expand Down
30 changes: 20 additions & 10 deletions src/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useEffect, useState, useRef } from "react";
import Link from "next/link";
import Image from "next/image";
import { useUser } from "@/hooks/queries/user/me/useUser";
import LinkBtn from "../components/button/default/LinkBtn";

export default function Home() {
const [visibleSections, setVisibleSections] = useState(new Set<string>());
Expand All @@ -16,16 +17,27 @@ export default function Home() {
observer.current = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const element = entry.target as HTMLElement;
const id = element.dataset.id ?? ""; // 기본값 설정
if (id) {
const element = entry.target as HTMLElement;
const id = element.dataset.id ?? "";
if (id) {
if (entry.isIntersecting) {
// 요소가 보일 때 애니메이션 적용
setVisibleSections((prev) => new Set(prev).add(id));
} else {
// 요소가 보이지 않을 때 애니메이션 제거
setVisibleSections((prev) => {
const newSet = new Set(prev);
newSet.delete(id);
return newSet;
});
}
}
});
},
{ threshold: 0.5 }
{
threshold: 0.2, // 임계값을 낮춰서 더 일찍 감지
rootMargin: "50px", // 여유 공간 추가
}
);

// 감시할 요소 선택 및 등록
Expand Down Expand Up @@ -59,11 +71,9 @@ export default function Home() {
한 곳에서 관리하는 알바 구인 플랫폼
</p>
{user ? (
<Link href="/alba-list">
<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>
</Link>
<LinkBtn href="/alba-list" variant="solid" width="lg" fontSize="lg" color="lime" disabled={false}>
알바 둘러보기
</LinkBtn>
) : (
<Link href="/login">
<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">
Expand Down
66 changes: 18 additions & 48 deletions src/app/(pages)/(albaform)/addform/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import { SubmitFormDataType } from "@/types/addform";
import CustomFormModal from "@/app/components/modal/modals/confirm/CustomFormModal";
import tempSave from "@/utils/tempSave";
import DotLoadingSpinner from "@/app/components/loading-spinner/DotLoadingSpinner";
import useUploadImages from "@/hooks/queries/user/me/useImageUpload";
import { useUser } from "@/hooks/queries/user/me/useUser";
import LoadingSpinner from "@/app/components/loading-spinner/LoadingSpinner";

export default function AddFormPage() {
const router = useRouter();
Expand Down Expand Up @@ -43,7 +44,6 @@ export default function AddFormPage() {
description: "",
title: "",
imageUrls: [],
imageFiles: [],
},
});

Expand All @@ -57,12 +57,9 @@ export default function AddFormPage() {
const currentValues: SubmitFormDataType = methods.watch();

// 이미지 업로드 api 처리를 위해 별도 변수에 할당
const imageFiles = currentValues.imageFiles;
const [, setSelectedOption] = useState<string>("");
const [showTempDataModal, setShowTempDataModal] = useState(false);

const { uploadImages } = useUploadImages();

// 각각의 탭 작성중 여부
const { isEditingRecruitContent, isEditingRecruitCondition, isEditingWorkCondition } = useEditing(currentValues);

Expand All @@ -77,32 +74,8 @@ export default function AddFormPage() {
const mutation = useMutation({
mutationFn: async () => {
setLoading(true);
// 이미지 필수 체크
if (!imageFiles || imageFiles.length === 0) {
toast.error("이미지를 첨부해주세요.");
throw new Error("이미지는 필수입니다.");
}

// 이미지 업로드 처리
let uploadedUrls: string[] = [];
try {
if (currentValues.imageUrls.length !== currentValues.imageFiles.length) {
uploadedUrls = await uploadImages(Array.from(imageFiles));
} else {
uploadedUrls = currentValues.imageUrls;
}
if (!uploadedUrls.length) {
toast.error("이미지 업로드에 실패했습니다.");
throw new Error("이미지 업로드 실패");
}
setValue("imageUrls", uploadedUrls);
} catch (error) {
console.error("이미지 업로드 중 오류 발생:", error);
toast.error("이미지 업로드 중 오류가 발생했습니다.");
throw error;
}

const excludedKeys = ["displayDate", "workDateRange", "recruitDateRange", "imageFiles"];
const excludedKeys = ["displayDate", "workDateRange", "recruitDateRange"];

// 원하는 필드만 포함된 새로운 객체 만들기
const filteredData = Object.entries(currentValues)
Expand All @@ -113,9 +86,6 @@ export default function AddFormPage() {
} else if (key === "hourlyWage") {
// 문자열이면 콤마 제거 후 숫자로 변환
acc[key] = typeof value === "string" ? String(Number(value.replace(/,/g, ""))) : String(Number(value));
} else if (key === "imageUrls") {
// 업로드된 이미지 URL 사용
acc[key] = uploadedUrls;
} else {
acc[key as keyof SubmitFormDataType] = value;
}
Expand Down Expand Up @@ -149,20 +119,6 @@ export default function AddFormPage() {

// 폼데이터 임시 저장 함수
const onTempSave = async () => {
// 이미지 처리 로직
if (currentValues.imageUrls.length !== currentValues.imageFiles.length) {
try {
const uploadedUrls = await uploadImages(Array.from(imageFiles));
if (uploadedUrls && uploadedUrls.length > 0) {
setValue("imageUrls", [...uploadedUrls]);
} else {
setValue("imageUrls", [...currentValues.imageUrls]);
}
} catch (error) {
console.error("임시저장 - 이미지 업로드 중 오류 발생:", error);
setValue("imageUrls", []);
}
}
tempSave("addformData", currentValues);
};

Expand All @@ -177,7 +133,7 @@ export default function AddFormPage() {
"모집 조건": "recruit-condition",
"근무 조건": "work-condition",
}[option];
router.push(`/addform?tab=${params}`);
router.replace(`/addform?tab=${params}`);
};

useEffect(() => {
Expand Down Expand Up @@ -265,6 +221,20 @@ export default function AddFormPage() {
setShowTempDataModal(false);
};

// 유저 권한 확인
const { user, isLoading } = useUser();

useEffect(() => {
if (user?.role !== "OWNER") {
toast.error("사장님만 알바폼을 작성할 수 있습니다.");
router.push("/alba-list");
}
}, [user, router]);

if (isLoading) {
return <LoadingSpinner />;
}

return (
<FormProvider {...methods}>
<div className="relative pb-10 lg:pb-0">
Expand Down
Loading
Loading