From 14f48e343aa42348054b4687818a7475bfebdd53 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Thu, 25 Jul 2024 17:23:01 +0900 Subject: [PATCH 001/102] [Fix] href --- src/common/Layout/ProfileMenu/CreateStudyLink.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Layout/ProfileMenu/CreateStudyLink.tsx b/src/common/Layout/ProfileMenu/CreateStudyLink.tsx index 2c88344..9d5f2ac 100644 --- a/src/common/Layout/ProfileMenu/CreateStudyLink.tsx +++ b/src/common/Layout/ProfileMenu/CreateStudyLink.tsx @@ -5,7 +5,7 @@ import { CreateStudyIcon } from "@public/icons"; export default function CreateStudyLink() { return ( create study From 7fc3388ae37bcf9be6e53649915cfcae6eca2f20 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Tue, 30 Jul 2024 16:19:12 +0900 Subject: [PATCH 002/102] =?UTF-8?q?[Chore]=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=ED=8C=8C=EC=9D=BC=20=EC=9C=84=EC=B9=98=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ErrorAlert.tsx => common/Molecules/handleAlert.tsx} | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename src/{app/(auth)/_components/ErrorAlert.tsx => common/Molecules/handleAlert.tsx} (84%) diff --git a/src/app/(auth)/_components/ErrorAlert.tsx b/src/common/Molecules/handleAlert.tsx similarity index 84% rename from src/app/(auth)/_components/ErrorAlert.tsx rename to src/common/Molecules/handleAlert.tsx index b3c426a..285848d 100644 --- a/src/app/(auth)/_components/ErrorAlert.tsx +++ b/src/common/Molecules/handleAlert.tsx @@ -3,7 +3,8 @@ import Notification from "@/common/Molecules/Notification"; export default function handleAlert( type: "success" | "error", - content: string + content: string, + message?: string ) { toast.custom((t: Toast) => ( )); From 5bc082cf2a40b0f9747f136dc016b681a393bcbc Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Tue, 30 Jul 2024 16:19:50 +0900 Subject: [PATCH 003/102] =?UTF-8?q?[Feat]=20Suspense=EB=A5=BC=20=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=ED=95=B4=20dynamic=20import=20=EC=8B=9C=20=EB=8C=80?= =?UTF-8?q?=EC=B2=B4=20UI=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/Atoms/Form/TextEditor.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/common/Atoms/Form/TextEditor.tsx b/src/common/Atoms/Form/TextEditor.tsx index 186dce9..a8e6d18 100644 --- a/src/common/Atoms/Form/TextEditor.tsx +++ b/src/common/Atoms/Form/TextEditor.tsx @@ -1,12 +1,16 @@ import { ReactQuillProps } from "react-quill"; import QuillNoSSR from "./QuillNoSSR"; +import { Suspense } from "react"; +import Skeleton from "../Skeleton"; // type TEditorProps = Partial>; type TEditorProps = ReactQuillProps; export default function TextEditor(props: TEditorProps) { return ( -
- -
+ }> +
+ +
+
); } From da1a552a6d5b328c266265e75f19e582a70f36b5 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Tue, 30 Jul 2024 16:20:20 +0900 Subject: [PATCH 004/102] =?UTF-8?q?[Fix,=20Feat]=20=EA=B3=B5=ED=86=B5=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/Atoms/Form/Button.tsx | 3 +- src/common/Atoms/Form/Field.tsx | 2 +- src/common/Atoms/Image/Icon.tsx | 40 ++++++++++++++++++++++++++ src/common/Atoms/Skeleton.tsx | 12 ++++++++ src/common/Molecules/Notification.tsx | 4 +-- src/common/Molecules/Pagination.tsx | 5 ++-- src/common/Organisms/StudyCardItem.tsx | 4 +-- 7 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 src/common/Atoms/Skeleton.tsx diff --git a/src/common/Atoms/Form/Button.tsx b/src/common/Atoms/Form/Button.tsx index 5b7e498..db053a3 100644 --- a/src/common/Atoms/Form/Button.tsx +++ b/src/common/Atoms/Form/Button.tsx @@ -13,13 +13,14 @@ export default function Button(props: TIconButtonProps | TButtonProps) { children, ...restProps } = props; + const color = `${colors.bg}/0 hover:${colors.bg}/15`; const square = `w-[${size}px] h-[${size}px]`; return ( + ); +} diff --git a/src/app/(route)/post/[postId]/page.tsx b/src/app/(route)/post/[postId]/page.tsx index 65040bf..817b223 100644 --- a/src/app/(route)/post/[postId]/page.tsx +++ b/src/app/(route)/post/[postId]/page.tsx @@ -1,6 +1,5 @@ import Link from "next/link"; import { getPost } from "@/dummies/posts"; -import Button from "@/common/Atoms/Form/Button"; import LinkButton from "@/common/Atoms/LinkButton"; import Profile from "@/common/Molecules/Profile"; import ContentArea from "@/common/Organisms/ContentArea"; @@ -9,6 +8,8 @@ import ShareIconButton from "../../_components/ShareIconButton"; import { getSession } from "@/auth"; import ReturnToListButton from "../_components/ReturnToListButton"; import LinkedStudyCard from "../_components/LinkedStudyCard"; +import LikeIconButton from "../../_components/LikeIconButton"; +import IconButtonActionsInDetail from "../_components/IconButtonActionsInDetail"; export default async function PostDetail({ params: { postId }, @@ -32,7 +33,6 @@ export default async function PostDetail({

1일 전 - {/* 본인이 작성한 글이라면 수정하기 버튼 show */} {session?.user.id === post.writer.userId && (

- - + {post.like}
diff --git a/src/app/(route)/post/_components/IconButtonActionsInDetail.tsx b/src/app/(route)/post/_components/IconButtonActionsInDetail.tsx new file mode 100644 index 0000000..260b181 --- /dev/null +++ b/src/app/(route)/post/_components/IconButtonActionsInDetail.tsx @@ -0,0 +1,17 @@ +"use client"; +import { TPost } from "@/types/model/PostItem"; +import LikeIconButton from "../../_components/LikeIconButton"; +import ShareIconButton from "../../_components/ShareIconButton"; + +export default function IconButtonActionsInDetail({ + postId, +}: { + postId: TPost["postId"]; +}) { + return ( + <> + + console.log(postId)} liked={false} /> + + ); +} From 0a4e4a70af88c81a2ae2b028d2dc1248c89519a9 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Tue, 30 Jul 2024 16:25:14 +0900 Subject: [PATCH 009/102] =?UTF-8?q?[Chore,=20Style]=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EB=B0=8F=20=EC=9D=B4=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(auth)/pw-reset/page.tsx | 5 +++-- .../(route)/post/_components/NonePostItem.tsx | 2 +- src/app/(route)/post/page.tsx | 11 ++++++----- .../CategoryTab/TabButtonsOfGoalSection.tsx | 16 +++++++--------- src/app/_components/NoneContentItemBase.tsx | 2 +- src/app/page.tsx | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/app/(auth)/pw-reset/page.tsx b/src/app/(auth)/pw-reset/page.tsx index 38d6885..4d172bd 100644 --- a/src/app/(auth)/pw-reset/page.tsx +++ b/src/app/(auth)/pw-reset/page.tsx @@ -2,6 +2,7 @@ import Image from "next/image"; import { Logo } from "@public/icons"; import AuthWrap from "../_components/AuthWrap"; import { Input } from "../_components/UserInput"; +import Button from "@/common/Atoms/Form/Button"; export default function PWresetPage() { return ( @@ -18,9 +19,9 @@ export default function PWresetPage() { title="이메일" placeholder="example@chemeet.com" /> - + ); } diff --git a/src/app/(route)/post/_components/NonePostItem.tsx b/src/app/(route)/post/_components/NonePostItem.tsx index 2d10a7a..8e8671e 100644 --- a/src/app/(route)/post/_components/NonePostItem.tsx +++ b/src/app/(route)/post/_components/NonePostItem.tsx @@ -3,7 +3,7 @@ import NoneContentItemBase from "@/app/_components/NoneContentItemBase"; export default function NonePostItem() { return ( -

+

조건에 맞는 글이 존재하지 않습니다.

diff --git a/src/app/(route)/post/page.tsx b/src/app/(route)/post/page.tsx index 9b92b28..041c0a5 100644 --- a/src/app/(route)/post/page.tsx +++ b/src/app/(route)/post/page.tsx @@ -65,13 +65,12 @@ export default async function CommunityPostList({ ))} -
-
+
+

{filteredMenu.label} 글

- {/* */}
-
+
( @@ -102,7 +101,9 @@ export default async function CommunityPostList({
) : ( - +
+ +
)}
diff --git a/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx b/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx index 7689e79..b64beef 100644 --- a/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx +++ b/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx @@ -7,7 +7,7 @@ import StudyCardList from "@/common/Templates/CardList"; import { CategoryTabIcon, categoryIconsName } from "./TabIcons"; import { TStudyCard } from "@/types/model/StudyCard"; import { getStudyCards } from "@/dummies/studies"; -import NoneContentItemBase from "../NoneContentItemBase"; +import Skeleton from "@/common/Atoms/Skeleton"; const GOALS_TAB = GOALS.map((goal, index) => ({ ...goal, @@ -49,18 +49,16 @@ export default function TabButtonsOfGoalSection() { ) : (
- - - - + + + +
)} ); } -function StudyCardSkelton() { - return ( -
- ); +function StudyCardSkeleton() { + return ; } diff --git a/src/app/_components/NoneContentItemBase.tsx b/src/app/_components/NoneContentItemBase.tsx index 55ebe3d..68c080f 100644 --- a/src/app/_components/NoneContentItemBase.tsx +++ b/src/app/_components/NoneContentItemBase.tsx @@ -2,7 +2,7 @@ import { TProps } from "@/types/component/props"; export default function NoneContentItemBase({ children }: TProps) { return ( -
+
{children}
); diff --git a/src/app/page.tsx b/src/app/page.tsx index a03c170..c84461f 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -20,7 +20,7 @@ export default async function Home() { {session?.user && }
- 인기 많은 프로 스터디 추천 + 인기 많은 스터디 추천
From 6d6f647bee7a254c35d42db6f6728be1b0e8367d Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Tue, 30 Jul 2024 16:25:43 +0900 Subject: [PATCH 010/102] =?UTF-8?q?[Chore]=20handleAlert=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(auth)/_components/LoginForm.tsx | 2 +- src/app/(route)/study/create/page.tsx | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/app/(auth)/_components/LoginForm.tsx b/src/app/(auth)/_components/LoginForm.tsx index 0767568..022609f 100644 --- a/src/app/(auth)/_components/LoginForm.tsx +++ b/src/app/(auth)/_components/LoginForm.tsx @@ -5,7 +5,7 @@ import Link from "next/link"; import { Input } from "./UserInput"; import { signIn } from "next-auth/react"; import { useRouter } from "next/navigation"; -import handleAlert from "./ErrorAlert"; +import handleAlert from "../../../common/Molecules/handleAlert"; export default function LoginForm() { const router = useRouter(); diff --git a/src/app/(route)/study/create/page.tsx b/src/app/(route)/study/create/page.tsx index ea031a8..19c2086 100644 --- a/src/app/(route)/study/create/page.tsx +++ b/src/app/(route)/study/create/page.tsx @@ -1,11 +1,10 @@ "use client"; -import SectionTitle from "@/common/Atoms/Text/SectionTitle"; -import { studyAction } from "@/lib/action"; import { FormEvent } from "react"; -import handleAlert from "@/app/(auth)/_components/ErrorAlert"; +import { studyAction } from "@/lib/action"; +import SectionTitle from "@/common/Atoms/Text/SectionTitle"; +import handleAlert from "@/common/Molecules/handleAlert"; import StudyForms from "./_components/StudyForms"; -import { useFormState, useFormStatus } from "react-dom"; export default function page() { // const [state, formAction] = useFormState(studyAction, { message: null }) From f27fb1286606d13079d95edf662104703ee9be88 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Tue, 30 Jul 2024 16:25:58 +0900 Subject: [PATCH 011/102] =?UTF-8?q?[Fix]=20=EC=84=B8=EC=85=98=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=EB=B0=94=EC=9D=B4=EB=8D=94=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/layout.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index aac3d8d..a79fe27 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,8 +2,6 @@ import type { Metadata, Viewport } from "next"; import { Noto_Sans_KR } from "next/font/google"; import "./globals.css"; import { Toaster } from "react-hot-toast"; -import AuthSession from "./_components/AuthSession"; - const notosans = Noto_Sans_KR({ weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"], style: ["normal"], From eb04dfacf163f2916ae39071143264cbe8c08d0f Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Tue, 30 Jul 2024 16:26:15 +0900 Subject: [PATCH 012/102] [Chore] --- src/app/(route)/study/[studyPostId]/page.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/(route)/study/[studyPostId]/page.tsx b/src/app/(route)/study/[studyPostId]/page.tsx index 5d243f2..b7b3973 100644 --- a/src/app/(route)/study/[studyPostId]/page.tsx +++ b/src/app/(route)/study/[studyPostId]/page.tsx @@ -18,7 +18,6 @@ export default function StudyPostComponent() { 비슷한 스터디들 -
); From 46c5156f7ef14bc3edfda95a6d0c4d0472aabc09 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Tue, 30 Jul 2024 16:26:29 +0900 Subject: [PATCH 013/102] =?UTF-8?q?[Feat]=20crud=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(auth)/_components/RegisterForm.tsx | 26 ++++- .../EditProfile/FormEditProfile.tsx | 39 +++++++ .../EditProfile/ProfileFormsAndPreview.tsx | 68 +++++++++++ .../{ => EditProfile}/ProfilePreview.tsx | 9 +- .../FormEditProfileImageWithPreview.tsx} | 42 +++++-- .../ProfileImagePreviewModal.tsx | 0 .../profile/_components/FormEditProfile.tsx | 36 +----- .../my/profile/_components/ProfileForms.tsx | 110 +++++++++--------- .../FormUpdatePassword.tsx | 4 +- .../FormUpdatePhoneNumber.tsx | 2 +- src/app/(route)/my/profile/page.tsx | 17 +-- src/app/_components/SetCategoryFavor.tsx | 108 +++++++++++++++++ 12 files changed, 343 insertions(+), 118 deletions(-) create mode 100644 src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx create mode 100644 src/app/(route)/my/profile/_components/EditProfile/ProfileFormsAndPreview.tsx rename src/app/(route)/my/profile/_components/{ => EditProfile}/ProfilePreview.tsx (78%) rename src/app/(route)/my/profile/_components/{ProfileImageInput.tsx => EditProfileImage/FormEditProfileImageWithPreview.tsx} (63%) rename src/app/(route)/my/profile/_components/{ => EditProfileImage}/ProfileImagePreviewModal.tsx (100%) rename src/app/(route)/my/profile/_components/{ => UpdatePassword}/FormUpdatePassword.tsx (92%) rename src/app/(route)/my/profile/_components/{ => UpdatePhoneNumber}/FormUpdatePhoneNumber.tsx (93%) create mode 100644 src/app/_components/SetCategoryFavor.tsx diff --git a/src/app/(auth)/_components/RegisterForm.tsx b/src/app/(auth)/_components/RegisterForm.tsx index b71896f..75a9604 100644 --- a/src/app/(auth)/_components/RegisterForm.tsx +++ b/src/app/(auth)/_components/RegisterForm.tsx @@ -3,10 +3,32 @@ import { Input } from "./UserInput"; import { ChangeEvent, FormEvent, useState } from "react"; import RegisterCheck from "./RegisterCheck"; -import handleAlert from "./ErrorAlert"; +import handleAlert from "../../../common/Molecules/handleAlert"; import { authAction } from "@/lib/action"; +import useModal from "@/hooks/useModal"; +import SetCategoryFavor from "../../_components/SetCategoryFavor"; +import { useRouter } from "next/navigation"; export default function RegisterForm() { + const router = useRouter(); + const { Modal, open, close } = useModal({ + defaultValue: true, + children: ( + + ), + }); + function closeAndRedirect() { + close(); + router.push("/"); + } + function saveCategory() { + // DB에 저장 + closeAndRedirect(); + } + const [phoneData, setPhoneData] = useState(""); async function register(e: FormEvent) { @@ -17,6 +39,7 @@ export default function RegisterForm() { try { await authAction(formData); handleAlert("success", "회원가입 완료되어 로그인 되었습니다."); + open(); } catch (error: any) { handleAlert("error", error.message); } @@ -70,6 +93,7 @@ export default function RegisterForm() { 가입하기 + {Modal} ); } diff --git a/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx b/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx new file mode 100644 index 0000000..2a6cb37 --- /dev/null +++ b/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx @@ -0,0 +1,39 @@ +import Button from "@/common/Atoms/Form/Button"; + +import { TProfileData } from "../ProfileForms"; +import { profileAction } from "@/lib/action"; +import ProfileFormsAndPreview from "./ProfileFormsAndPreview"; + +type FormEditProfileProps = { + userId: string; + profile: TProfileData; +}; + +export default function FormEditProfile(props: FormEditProfileProps) { + const { userId, profile } = props; + + async function save(formData: FormData) { + "use server"; + // e.preventDefault(); + + // const userId = profile?.userId._id as string; + // const formData = new FormData(e.currentTarget); + + try { + await profileAction(userId, formData); + // handleAlert("success", "프로필 정보가 저장되었습니다."); + } catch (error: any) { + // handleAlert("error", error.message); + console.error("error", error.message); + } + } + + return ( +
+ + + + ); +} diff --git a/src/app/(route)/my/profile/_components/EditProfile/ProfileFormsAndPreview.tsx b/src/app/(route)/my/profile/_components/EditProfile/ProfileFormsAndPreview.tsx new file mode 100644 index 0000000..1b8215f --- /dev/null +++ b/src/app/(route)/my/profile/_components/EditProfile/ProfileFormsAndPreview.tsx @@ -0,0 +1,68 @@ +import Input from "@/common/Molecules/Form/Input"; +import ProfileInputArea from "../ProfileInputArea"; +import { CATEGORIES } from "@/constants/categories/job_category"; +import { CategoryOption } from "@/types/model/Category"; +import { TProfileData } from "../ProfileForms"; +import ProfilePreview from "./ProfilePreview"; + +export default function ProfileFormsAndPreview({ + defaultValue, +}: { + defaultValue?: TProfileData; +}) { + return ( + <> +
+ + + + + + + + + {/* {false && ( +
+ + + *변경 후 재인증이 필요합니다. + +
+ )} */} +
+ + + +
+ + ); +} diff --git a/src/app/(route)/my/profile/_components/ProfilePreview.tsx b/src/app/(route)/my/profile/_components/EditProfile/ProfilePreview.tsx similarity index 78% rename from src/app/(route)/my/profile/_components/ProfilePreview.tsx rename to src/app/(route)/my/profile/_components/EditProfile/ProfilePreview.tsx index a9f0a39..ef90241 100644 --- a/src/app/(route)/my/profile/_components/ProfilePreview.tsx +++ b/src/app/(route)/my/profile/_components/EditProfile/ProfilePreview.tsx @@ -1,7 +1,5 @@ -import ProfileImg from "@/common/Atoms/Image/ProfileImg"; import Keyword from "@/common/Atoms/Text/Keyword"; -import { DummyProfileImg } from "@public/images"; -import { TProfileData } from "./ProfileForms"; +import { TProfileData } from "../ProfileForms"; type TProfilePreviewProps = { name: string | null | undefined; @@ -13,11 +11,6 @@ export default function ProfilePreview({ name, data }: TProfilePreviewProps) { <> {/* TODO: 프로필 미리보기 */}
-

{data.positionTag ? data.positionTag + " " : ""} {name} diff --git a/src/app/(route)/my/profile/_components/ProfileImageInput.tsx b/src/app/(route)/my/profile/_components/EditProfileImage/FormEditProfileImageWithPreview.tsx similarity index 63% rename from src/app/(route)/my/profile/_components/ProfileImageInput.tsx rename to src/app/(route)/my/profile/_components/EditProfileImage/FormEditProfileImageWithPreview.tsx index a0cfbaa..030e46e 100644 --- a/src/app/(route)/my/profile/_components/ProfileImageInput.tsx +++ b/src/app/(route)/my/profile/_components/EditProfileImage/FormEditProfileImageWithPreview.tsx @@ -1,13 +1,24 @@ "use client"; import { ChangeEvent, useEffect, useState } from "react"; - +import ProfileInputArea from "../ProfileInputArea"; import useModal from "@/hooks/useModal"; import ProfileImagePreviewModal from "./ProfileImagePreviewModal"; -import Button from "@/common/Atoms/Form/Button"; +import handleAlert from "@/common/Molecules/handleAlert"; +import ProfileImg from "@/common/Atoms/Image/ProfileImg"; +import { DummyProfileImg } from "@public/images"; import ImageInputWithButton from "@/common/Molecules/Form/ImageInputWithButton"; +import Button from "@/common/Atoms/Form/Button"; -export default function ProfileImageInput() { - const [imageUrl, setImageUrl] = useState(""); +export type ProfileImageFormProps = { + initProfileUrl: string; + saveImage: (imageUrl: string) => any; +}; + +export default function FormEditProfileImageWithPreview({ + initProfileUrl, + saveImage, +}: ProfileImageFormProps) { + const [imageUrl, setImageUrl] = useState(initProfileUrl); const { Modal, open, close } = useModal({ children: ( +

+
{Modal} - + ); } diff --git a/src/app/(route)/my/profile/_components/ProfileImagePreviewModal.tsx b/src/app/(route)/my/profile/_components/EditProfileImage/ProfileImagePreviewModal.tsx similarity index 100% rename from src/app/(route)/my/profile/_components/ProfileImagePreviewModal.tsx rename to src/app/(route)/my/profile/_components/EditProfileImage/ProfileImagePreviewModal.tsx diff --git a/src/app/(route)/my/profile/_components/FormEditProfile.tsx b/src/app/(route)/my/profile/_components/FormEditProfile.tsx index f7b369a..5d882a6 100644 --- a/src/app/(route)/my/profile/_components/FormEditProfile.tsx +++ b/src/app/(route)/my/profile/_components/FormEditProfile.tsx @@ -1,48 +1,21 @@ -import { ActionMeta } from "react-select"; -import { - ChangeEvent, - Dispatch, - FormEvent, - SetStateAction, - useEffect, -} from "react"; +"use client"; +import { FormEvent } from "react"; import Input from "@/common/Molecules/Form/Input"; -import ProfileImageInput from "./ProfileImageInput"; import ProfileInputArea from "./ProfileInputArea"; import Button from "@/common/Atoms/Form/Button"; import { CATEGORIES } from "@/constants/categories/job_category"; -import { Session } from "next-auth"; import { TProfileData } from "./ProfileForms"; import { profileAction } from "@/lib/action"; -import handleAlert from "@/app/(auth)/_components/ErrorAlert"; +import handleAlert from "@/common/Molecules/handleAlert"; export default function FormEditProfile({ userId, profile, - sessionProvider, }: { userId: string; profile: TProfileData; - sessionProvider: string; }) { - // const changeData = ( - // e: ChangeEvent | ChangeEvent - // ) => { - // console.log(e.target.name); - // const name = e.target.name; - // const value = e.target.value; - // setData((p) => ({ ...p, [name]: value })); - // }; - // const changeMultiSelect: ( - // newValue: unknown, - // actionMeta: ActionMeta - // ) => void = (newValue) => { - // // console.log({ newValue }); - // if (Array.isArray(newValue)) setData((p) => ({ ...p, interest: newValue })); - // }; - console.log("?" + userId); - async function save(e: FormEvent) { e.preventDefault(); @@ -79,8 +52,7 @@ export default function FormEditProfile({ name="email" // value={data.email} // onChange={changeData} - placeholder="이메일 주소를 입력하세요" - readOnly={sessionProvider !== "credentials"} + readOnly /> {false && (
diff --git a/src/app/(route)/my/profile/_components/ProfileForms.tsx b/src/app/(route)/my/profile/_components/ProfileForms.tsx index 9201129..78f6953 100644 --- a/src/app/(route)/my/profile/_components/ProfileForms.tsx +++ b/src/app/(route)/my/profile/_components/ProfileForms.tsx @@ -1,36 +1,32 @@ -"use client"; -import ProfileInputArea from "./ProfileInputArea"; -import ProfileImageInput from "./ProfileImageInput"; -import FormEditProfile from "./FormEditProfile"; -import { getUser } from "@/dummies/user"; -import { useEffect, useState } from "react"; import SectionTitle from "@/common/Atoms/Text/SectionTitle"; -import FormUpdatePassword from "./FormUpdatePassword"; -import FormUpdatePhoneNumber from "./FormUpdatePhoneNumber"; +import FormUpdatePassword from "./UpdatePassword/FormUpdatePassword"; +import FormUpdatePhoneNumber from "./UpdatePhoneNumber/FormUpdatePhoneNumber"; import DeleteAccountConfirm from "./DeleteAccountConfirm"; -import ProfilePreview from "./ProfilePreview"; -import { Session } from "next-auth"; import { CategoryOption } from "@/types/model/Category"; -import { ProfileSchema } from "@/types/model/Profile"; +import { ProfileFullDataSchema } from "@/types/model/Profile"; import { CATEGORIES_ALL_OPTIONS } from "@/constants/categories/job_category"; +import FormEditProfileImageWithPreview from "./EditProfileImage/FormEditProfileImageWithPreview"; +import FormEditProfile from "./FormEditProfile"; +import connectDB from "@/lib/db"; +import { User } from "@/lib/schema"; +import { Session } from "next-auth"; export type TProfileData = { - profileUrl: string; positionTag: string; introduce: string; email: string; interest: Array; }; -export default function ProfileForms({ - userId, +export default async function ProfileForms({ + session, profile, - sessionProvider, }: { - userId: string; - profile: ProfileSchema | null; - sessionProvider: string; + session: Session | null; + profile: ProfileFullDataSchema | null; }) { + const userId = session?.user.id as string; + const sessionProvider = session?.account.provider as string; // const user = getUser(); const interestCategory: CategoryOption[] = profile?.my_category && profile.my_category.length > 0 @@ -41,8 +37,8 @@ export default function ProfileForms({ ) as CategoryOption ) : []; + const initProfileUrl = profile?.userId.profile_img || ""; const profileData = { - profileUrl: profile?.userId.profile_img || "", positionTag: profile?.position_tag || "", introduce: profile?.introduce || "", email: profile?.userId.email || "", @@ -50,47 +46,53 @@ export default function ProfileForms({ }; console.log({ profile, profileData }); - const [data, setData] = useState(profileData); - const setProfileImage = (image: string) => { - setData((prev) => ({ ...prev, profileUrl: image })); - }; + async function saveImage(imageUrl: string) { + "use server"; + await connectDB(); + + try { + const updated = await User.findOneAndUpdate( + { userId }, + { image: imageUrl } + ); + return updated; + // handleAlert("success", "프로필 이미지가 저장되었습니다."); + } catch (error: any) { + // handleAlert("error", error.message); + } + } return ( <> -
-
-

{profile?.userId.name}

- - - -
- - {sessionProvider === "credentials" && ( - <> -
- - 비밀번호 수정 - - - - )} -
- - 연락처 수정 - - -
- -
+
+

{session?.user.name}

+ +
+ + {sessionProvider === "credentials" && ( + <> +
+ + 비밀번호 수정 + + + + )} +
+ + 연락처 수정 + + +
+ +
- {/*
+ {/*
*/} -
); } diff --git a/src/app/(route)/my/profile/_components/FormUpdatePassword.tsx b/src/app/(route)/my/profile/_components/UpdatePassword/FormUpdatePassword.tsx similarity index 92% rename from src/app/(route)/my/profile/_components/FormUpdatePassword.tsx rename to src/app/(route)/my/profile/_components/UpdatePassword/FormUpdatePassword.tsx index cb1a984..0571311 100644 --- a/src/app/(route)/my/profile/_components/FormUpdatePassword.tsx +++ b/src/app/(route)/my/profile/_components/UpdatePassword/FormUpdatePassword.tsx @@ -1,10 +1,10 @@ import Input from "@/common/Molecules/Form/Input"; import Button from "@/common/Atoms/Form/Button"; -import ProfileInputArea from "./ProfileInputArea"; +import ProfileInputArea from "../ProfileInputArea"; export default function FormUpdatePassword() { return ( -
+ ; } - const profile: ProfileSchema | null = await getProfile( + const profile: ProfileFullDataSchema | null = await getProfile( session?.user.id as string ); console.log("profile", profile); - // const data: string = await useGetProfile(); - - // console.log("profile data 가져오기" + data); + const profileData: ProfileFullDataSchema = JSON.parse( + JSON.stringify(profile) + ); return ( <> 프로필 수정 - + ); } diff --git a/src/app/_components/SetCategoryFavor.tsx b/src/app/_components/SetCategoryFavor.tsx new file mode 100644 index 0000000..c345c17 --- /dev/null +++ b/src/app/_components/SetCategoryFavor.tsx @@ -0,0 +1,108 @@ +"use client"; +import { MouseEventHandler, useRef, useState } from "react"; +import Button from "@/common/Atoms/Form/Button"; +import { CATEGORIES } from "@/constants/categories/job_category"; +import clsx from "clsx"; +import Input from "@/common/Molecules/Form/Input"; +import { RefreshIcon } from "@/common/Atoms/Image/Icon"; + +export type SetCategoryFavorProps = { + skipThis: MouseEventHandler; + saveCategory: MouseEventHandler; +}; + +export default function SetCategoryFavor({ + skipThis, + saveCategory, +}: SetCategoryFavorProps) { + const categoryGroup = CATEGORIES.map(({ value, label }) => ({ + value, + label, + })); + const [shown, setShown] = useState(0); + const categoryRef = useRef(null); + + return ( +
+
+

+ + 관심 있는 전공 · 직무 카테고리를 선택하세요 + + + 선택한 카테고리와 관련된 스터디를 우선으로 추천해 드립니다.
+ 선택하지 않고 건너뛰어 홈으로 이동할 수도 있습니다. +
+

+ +
+
+
    + {categoryGroup.map((group, index) => ( +
  • + +
  • + ))} +
+
    + + {CATEGORIES.map(({ value, options }, index) => ( +
    + {options.map(({ value, label }) => ( +
  • + +
  • + ))} +
    + ))} + +
+
+
+
+ + +
+
+ ); +} From 52d5ddef35bafe5bed16ef366d2178ea3b6c613b Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Tue, 30 Jul 2024 16:29:59 +0900 Subject: [PATCH 014/102] [Chore] defaultValue blocked --- src/app/(auth)/_components/RegisterForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(auth)/_components/RegisterForm.tsx b/src/app/(auth)/_components/RegisterForm.tsx index 75a9604..1fd1a47 100644 --- a/src/app/(auth)/_components/RegisterForm.tsx +++ b/src/app/(auth)/_components/RegisterForm.tsx @@ -12,7 +12,7 @@ import { useRouter } from "next/navigation"; export default function RegisterForm() { const router = useRouter(); const { Modal, open, close } = useModal({ - defaultValue: true, + // defaultValue: true, children: ( Date: Wed, 31 Jul 2024 13:51:28 +0900 Subject: [PATCH 015/102] =?UTF-8?q?[Chore]=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=20=EB=AF=B8=EB=A6=AC=EB=B3=B4=EA=B8=B0=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EditProfile/ProfilePreview.tsx | 38 ---------------- .../my/profile/_components/ProfileForms.tsx | 45 +++++++++---------- 2 files changed, 20 insertions(+), 63 deletions(-) delete mode 100644 src/app/(route)/my/profile/_components/EditProfile/ProfilePreview.tsx diff --git a/src/app/(route)/my/profile/_components/EditProfile/ProfilePreview.tsx b/src/app/(route)/my/profile/_components/EditProfile/ProfilePreview.tsx deleted file mode 100644 index ef90241..0000000 --- a/src/app/(route)/my/profile/_components/EditProfile/ProfilePreview.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import Keyword from "@/common/Atoms/Text/Keyword"; -import { TProfileData } from "../ProfileForms"; - -type TProfilePreviewProps = { - name: string | null | undefined; - data: TProfileData; -}; - -export default function ProfilePreview({ name, data }: TProfilePreviewProps) { - return ( - <> - {/* TODO: 프로필 미리보기 */} -
-

- {data.positionTag ? data.positionTag + " " : ""} - {name} -

-

- {data.email} - - {data.introduce || 나를 소개할 말을 추가해주세요} - -

-
- {data.interest.map((interestIn) => ( - - #{interestIn.label} - - ))} -
-
- - ); -} diff --git a/src/app/(route)/my/profile/_components/ProfileForms.tsx b/src/app/(route)/my/profile/_components/ProfileForms.tsx index 96b9ee7..7c31369 100644 --- a/src/app/(route)/my/profile/_components/ProfileForms.tsx +++ b/src/app/(route)/my/profile/_components/ProfileForms.tsx @@ -1,58 +1,53 @@ -import ProfileInputArea from "./ProfileInputArea"; import FormEditProfile from "./FormEditProfile"; import SectionTitle from "@/common/Atoms/Text/SectionTitle"; import FormUpdatePassword from "./UpdatePassword/FormUpdatePassword"; import FormUpdatePhoneNumber from "./UpdatePhoneNumber/FormUpdatePhoneNumber"; import DeleteAccountConfirm from "./DeleteAccountConfirm"; -import ProfilePreview from "./EditProfile/ProfilePreview"; import { getProfile } from "@/lib/actions/profileAction"; import { getSession } from "@/auth"; import FormEditProfileImageWithPreview from "./EditProfileImage/FormEditProfileImageWithPreview"; -export default async function ProfileForms({ - userId, - sessionProvider, -}: { - userId: string; - sessionProvider: string; -}) { +export default async function ProfileForms({ userId }: { userId: string }) { const session = await getSession(); + const sessionProvider = session?.account.provider; const userProfile = await getProfile(userId); let profile = userProfile.data; let clientProfile = JSON.parse(JSON.stringify(profile)); - console.log("get 프로필 데이터" + profile); + console.log("get 프로필 데이터" + JSON.stringify(profile)); return ( <>
-

{session?.user.name}

- +

+ {session?.user.name as string} +

+
{sessionProvider === "credentials" && ( <>
- - 비밀번호 수정 - + 비밀번호 수정 )}
- - 연락처 수정 - - {/* 소셜로그인은 휴대폰 번호 x */} - {/* */} -
+ {sessionProvider === "credentials" && ( + <> + + 연락처 수정 + + +
+ + )}
- -
- -
); From 1bd3db5cbdf398e176f5dd2e1a382ff00b517ae2 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 14:31:20 +0900 Subject: [PATCH 016/102] =?UTF-8?q?[Style]=20loading=20spinner=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EA=B3=B5=ED=86=B5=20?= =?UTF-8?q?=EB=A1=9C=EB=94=A9=20=EC=BB=A8=ED=85=8C=EC=9D=B4=EB=84=88=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/loading.tsx | 24 ++++--------------- src/common/Layout/LoadingContainer.tsx | 33 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 20 deletions(-) create mode 100644 src/common/Layout/LoadingContainer.tsx diff --git a/src/app/loading.tsx b/src/app/loading.tsx index b7f5828..5a48284 100644 --- a/src/app/loading.tsx +++ b/src/app/loading.tsx @@ -1,21 +1,5 @@ -export default function loading() { - return ( - <> -
- - - - - -
- - ); +import LoadingContainer from "@/common/Layout/LoadingContainer"; + +export default function Loading() { + return ; } diff --git a/src/common/Layout/LoadingContainer.tsx b/src/common/Layout/LoadingContainer.tsx new file mode 100644 index 0000000..b027f46 --- /dev/null +++ b/src/common/Layout/LoadingContainer.tsx @@ -0,0 +1,33 @@ +import clsx from "clsx"; +import { ComponentProps } from "react"; + +export default function LoadingContainer({ + className, +}: { + className?: ComponentProps<"div">["className"]; +}) { + return ( + <> +
+ + + + + +
+ + ); +} From 4de337534d31e00bb27cf7f759c4324374dd4456 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 14:31:49 +0900 Subject: [PATCH 017/102] [Chore] rm unused component --- .../EditProfile/ProfileFormsAndPreview.tsx | 68 ------------------- 1 file changed, 68 deletions(-) delete mode 100644 src/app/(route)/my/profile/_components/EditProfile/ProfileFormsAndPreview.tsx diff --git a/src/app/(route)/my/profile/_components/EditProfile/ProfileFormsAndPreview.tsx b/src/app/(route)/my/profile/_components/EditProfile/ProfileFormsAndPreview.tsx deleted file mode 100644 index 351d328..0000000 --- a/src/app/(route)/my/profile/_components/EditProfile/ProfileFormsAndPreview.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import Input from "@/common/Molecules/Form/Input"; -import ProfileInputArea from "../ProfileInputArea"; -import { CATEGORIES } from "@/constants/categories/job_category"; -import { CategoryOption } from "@/types/model/Category"; -import { TProfileData } from "@/types/model/Profile"; -import ProfilePreview from "./ProfilePreview"; - -export default function ProfileFormsAndPreview({ - defaultValue, -}: { - defaultValue?: TProfileData; -}) { - return ( - <> -
- - - - - - - - - {/* {false && ( -
- - - *변경 후 재인증이 필요합니다. - -
- )} */} -
- - - -
- - ); -} From 2cb005ca6ec2999b93e71068e160fbc0c67a06a7 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 14:32:18 +0900 Subject: [PATCH 018/102] =?UTF-8?q?[Chore]=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EditProfile/FormEditProfile.tsx | 105 ++++++++++--- .../profile/_components/FormEditProfile.tsx | 142 ------------------ .../my/profile/_components/ProfileForms.tsx | 71 ++++----- 3 files changed, 121 insertions(+), 197 deletions(-) delete mode 100644 src/app/(route)/my/profile/_components/FormEditProfile.tsx diff --git a/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx b/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx index 5075904..89d49f6 100644 --- a/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx +++ b/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx @@ -1,37 +1,102 @@ +"use client"; + +import { ChangeEvent, FormEvent } from "react"; +import Input from "@/common/Molecules/Form/Input"; +import ProfileInputArea from "../ProfileInputArea"; import Button from "@/common/Atoms/Form/Button"; -import ProfileFormsAndPreview from "./ProfileFormsAndPreview"; -import { profileAction } from "@/lib/actions/profileAction"; +import { CATEGORIES } from "@/constants/categories/job_category"; +import { useRouter } from "next/navigation"; +import { profileAction, updateProfile } from "@/lib/actions/profileAction"; import { TProfileData } from "@/types/model/Profile"; +import { Session } from "next-auth"; +import handleAlert from "@/common/Molecules/handleAlert"; -type FormEditProfileProps = { - userId: string; +export default function FormEditProfile({ + session, + profile, +}: { + session: Session | null; profile: TProfileData; -}; +}) { + const router = useRouter(); -export default function FormEditProfile(props: FormEditProfileProps) { - const { userId, profile } = props; + async function handleSubmit(e: FormEvent) { + e.preventDefault(); - async function save(formData: FormData) { - "use server"; - // e.preventDefault(); + const formData = new FormData(e.currentTarget); + const id = session?.user.id; - // const userId = profile?.userId._id as string; - // const formData = new FormData(e.currentTarget); + if (!id) { + handleAlert("error", "사용자 ID가 없습니다."); + return; + } try { - await profileAction(userId, formData); - // handleAlert("success", "프로필 정보가 저장되었습니다."); - } catch (error: any) { - // handleAlert("error", error.message); - console.error("error", error.message); + const result = profile + ? await updateProfile(id, formData) + : await profileAction(id, formData); + + if (result.state) { + handleAlert("success", result.message); + + if (!profile) { + router.replace("/my/profile"); + } + } else { + handleAlert("error", result.message); + } + } catch (error) { + console.log(error); } } return ( -
- + + + + + + + + {session?.account.provider === "credentials" && ( + + +
+ + + *변경 후 재인증이 필요합니다. + +
+
+ )} + + + ); diff --git a/src/app/(route)/my/profile/_components/FormEditProfile.tsx b/src/app/(route)/my/profile/_components/FormEditProfile.tsx deleted file mode 100644 index fc94ef0..0000000 --- a/src/app/(route)/my/profile/_components/FormEditProfile.tsx +++ /dev/null @@ -1,142 +0,0 @@ -"use client"; - -import { ChangeEvent, FormEvent } from "react"; -import Input from "@/common/Molecules/Form/Input"; -import ProfileInputArea from "./ProfileInputArea"; -import Button from "@/common/Atoms/Form/Button"; -import { CATEGORIES } from "@/constants/categories/job_category"; -import { useRouter } from "next/navigation"; -import { profileAction, updateProfile } from "@/lib/actions/profileAction"; -import { TProfileData } from "@/types/model/Profile"; -import { CategoryOption } from "@/types/model/Category"; -import { Session } from "next-auth"; -import handleAlert from "@/common/Molecules/handleAlert"; - -type TProfileType = { - position_tag: string; - introduce: string; - email: string; - interest: Array; -}; - -export default function FormEditProfile({ - session, - profile, -}: { - session: Session | null; - profile: TProfileData; -}) { - const changeData = ( - e: ChangeEvent | ChangeEvent - ) => { - console.log(e.target.name); - const name = e.target.name; - const value = e.target.value; - // setData((p: any) => ({ ...p, [name]: value })); - }; - - const router = useRouter(); - - // const changeMultiSelect: ( - // newValue: unknown, - // actionMeta: ActionMeta - // ) => void = (newValue) => { - // // console.log({ newValue }); - // if (Array.isArray(newValue)) - // setData((p: any) => ({ ...p, interest: newValue })); - // }; - - async function handleSubmit(e: FormEvent) { - e.preventDefault(); - - const formData = new FormData(e.currentTarget); - const id = session?.user.id; - - if (!id) { - handleAlert("error", "사용자 ID가 없습니다."); - return; - } - - try { - const result = profile - ? await updateProfile(id, formData) - : await profileAction(id, formData); - - if (result.state) { - handleAlert("success", result.message); - - if (!profile) { - router.replace("/my/profile"); - } - } else { - handleAlert("error", result.message); - } - } catch (error) { - console.log(error); - } - } - - return ( - // 기존에 profile 정보가 없다면 등록 정보가 있다면 수정 state -
- - - - - - - - - {false && ( -
- - - *변경 후 재인증이 필요합니다. - -
- )} -
- - - - {profile ? ( - - ) : ( - - )} -
- ); -} diff --git a/src/app/(route)/my/profile/_components/ProfileForms.tsx b/src/app/(route)/my/profile/_components/ProfileForms.tsx index 7c31369..b621b16 100644 --- a/src/app/(route)/my/profile/_components/ProfileForms.tsx +++ b/src/app/(route)/my/profile/_components/ProfileForms.tsx @@ -1,4 +1,4 @@ -import FormEditProfile from "./FormEditProfile"; +import FormEditProfile from "./EditProfile/FormEditProfile"; import SectionTitle from "@/common/Atoms/Text/SectionTitle"; import FormUpdatePassword from "./UpdatePassword/FormUpdatePassword"; import FormUpdatePhoneNumber from "./UpdatePhoneNumber/FormUpdatePhoneNumber"; @@ -6,49 +6,50 @@ import DeleteAccountConfirm from "./DeleteAccountConfirm"; import { getProfile } from "@/lib/actions/profileAction"; import { getSession } from "@/auth"; import FormEditProfileImageWithPreview from "./EditProfileImage/FormEditProfileImageWithPreview"; +import NotFound from "@/app/not-found"; -export default async function ProfileForms({ userId }: { userId: string }) { +export default async function ProfileForms() { const session = await getSession(); - const sessionProvider = session?.account.provider; + + if (session === null) { + return ; + } + + const userId = session.user.id; + const sessionProvider = session.account.provider; const userProfile = await getProfile(userId); let profile = userProfile.data; let clientProfile = JSON.parse(JSON.stringify(profile)); + console.log("id", session?.user.id); + console.log("get 프로필 데이터" + JSON.stringify(profile)); return ( - <> -
-
-

- {session?.user.name as string} -

- -
- - {sessionProvider === "credentials" && ( - <> -
- 비밀번호 수정 - - - )} -
- {sessionProvider === "credentials" && ( - <> - - 연락처 수정 - - -
- - )} - -
+
+
+

{session.user.name}

+ +
+ + {sessionProvider === "credentials" && ( + <> +
+ 비밀번호 수정 + +
+ + 연락처 수정 + + +
+ + + )}
- +
); } From 7ba373afedc7bf09f0d58e0f39e7b332cd8bcd93 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 14:32:43 +0900 Subject: [PATCH 019/102] =?UTF-8?q?[Chore]=20=EC=A4=91=EB=B3=B5=20session?= =?UTF-8?q?=20=EA=B2=80=EC=82=AC=20=EC=A0=9C=EA=B1=B0=20=3D>=20ProfileForm?= =?UTF-8?q?s=EC=97=90=EC=84=9C=20session=20=EA=B2=80=EC=82=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(route)/my/profile/page.tsx | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/app/(route)/my/profile/page.tsx b/src/app/(route)/my/profile/page.tsx index 2f2cb08..f15ae96 100644 --- a/src/app/(route)/my/profile/page.tsx +++ b/src/app/(route)/my/profile/page.tsx @@ -1,25 +1,13 @@ import SectionTitle from "@/common/Atoms/Text/SectionTitle"; import ProfileForms from "./_components/ProfileForms"; -import { getSession } from "@/auth"; -import NotFound from "@/app/not-found"; export default async function MyProfilePage() { - const session = await getSession(); - - if (session === null) { - return ; - } - return ( <> 프로필 수정 - - + ); } From 36af18f84e582dd1cc2b6c55cb0f1f87d3385be9 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 14:32:58 +0900 Subject: [PATCH 020/102] [Chore] rm unused size --- src/common/Atoms/Image/ProfileImg.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/common/Atoms/Image/ProfileImg.tsx b/src/common/Atoms/Image/ProfileImg.tsx index 9509834..6ae73c1 100644 --- a/src/common/Atoms/Image/ProfileImg.tsx +++ b/src/common/Atoms/Image/ProfileImg.tsx @@ -3,14 +3,13 @@ import Image from "next/image"; export default function ProfileImg( props: React.ComponentProps & { - size?: "default" | "xxlarge" | "xlarge" | "large" | "small"; + size?: "default" | "xlarge" | "large" | "small"; altText?: string; } ) { const { size = "default", className, alt = "profile", ...restProps } = props; const square = { default: 40, - xxlarge: 80, xlarge: 60, large: 48, small: 20, From bd694f418a335984ebb898cc3e5689fae3ebfc83 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 14:33:40 +0900 Subject: [PATCH 021/102] =?UTF-8?q?[Chore]=20p=20=ED=83=9C=EA=B7=B8=20?= =?UTF-8?q?=EC=95=84=EB=9E=98=20=EC=A4=91=EC=B2=A9=20=ED=83=9C=EA=B7=B8=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EB=B0=A9=EC=A7=80=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20div=20=ED=83=9C=EA=B7=B8=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/Atoms/Text/SectionTitle.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/common/Atoms/Text/SectionTitle.tsx b/src/common/Atoms/Text/SectionTitle.tsx index 0eeb30b..fc60bdc 100644 --- a/src/common/Atoms/Text/SectionTitle.tsx +++ b/src/common/Atoms/Text/SectionTitle.tsx @@ -10,8 +10,11 @@ export default function SectionTitle( lg: "text-H2", }; return ( -

+

{children} -

+
); } From 6d3a9ecc9b5fcfc5ee9da6e24b4290e6aecba9eb Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 14:34:32 +0900 Subject: [PATCH 022/102] [Refactor, Feat] --- .../_components/DeleteAccountConfirm.tsx | 23 ++++++++- .../FormEditProfileImageWithPreview.tsx | 37 ++++++++++----- .../UpdatePassword/FormUpdatePassword.tsx | 47 +++++++++++++++---- 3 files changed, 84 insertions(+), 23 deletions(-) diff --git a/src/app/(route)/my/profile/_components/DeleteAccountConfirm.tsx b/src/app/(route)/my/profile/_components/DeleteAccountConfirm.tsx index 68f2e0a..268f586 100644 --- a/src/app/(route)/my/profile/_components/DeleteAccountConfirm.tsx +++ b/src/app/(route)/my/profile/_components/DeleteAccountConfirm.tsx @@ -1,11 +1,29 @@ "use client"; +import { useState } from "react"; +import { signOut } from "next-auth/react"; import Button from "@/common/Atoms/Form/Button"; import Label from "@/common/Atoms/Form/Label"; import Input from "@/common/Molecules/Form/Input"; -import { useState } from "react"; +import handleAlert from "@/common/Molecules/handleAlert"; +import { unregisterAction } from "@/lib/actions/authAction"; -export default function DeleteAccountConfirm() { +export default function DeleteAccountConfirm({ email }: { email: string }) { const [checked, setChecked] = useState(false); + async function unregister() { + try { + const result = await unregisterAction(email); + + if (result.state) { + signOut({ callbackUrl: "/" }); + handleAlert("success", result.message); + } else { + handleAlert("error", result.message); + } + } catch (error) { + console.log(error); + } + } + return (
@@ -28,6 +46,7 @@ export default function DeleteAccountConfirm() { colors={{ bg: "bg-status-danger", text: "text-status-danger" }} className="border-status-danger" disabled={!checked} + onClick={unregister} > 회원 탈퇴 diff --git a/src/app/(route)/my/profile/_components/EditProfileImage/FormEditProfileImageWithPreview.tsx b/src/app/(route)/my/profile/_components/EditProfileImage/FormEditProfileImageWithPreview.tsx index 030e46e..c28d1ca 100644 --- a/src/app/(route)/my/profile/_components/EditProfileImage/FormEditProfileImageWithPreview.tsx +++ b/src/app/(route)/my/profile/_components/EditProfileImage/FormEditProfileImageWithPreview.tsx @@ -8,15 +8,16 @@ import ProfileImg from "@/common/Atoms/Image/ProfileImg"; import { DummyProfileImg } from "@public/images"; import ImageInputWithButton from "@/common/Molecules/Form/ImageInputWithButton"; import Button from "@/common/Atoms/Form/Button"; +import { saveProfileImage } from "@/lib/actions/profileAction"; export type ProfileImageFormProps = { + id: string; initProfileUrl: string; - saveImage: (imageUrl: string) => any; }; export default function FormEditProfileImageWithPreview({ + id, initProfileUrl, - saveImage, }: ProfileImageFormProps) { const [imageUrl, setImageUrl] = useState(initProfileUrl); const { Modal, open, close } = useModal({ @@ -56,22 +57,36 @@ export default function FormEditProfileImageWithPreview({ async function onSave() { // TODO: DB에 저장 try { - const updated = await saveImage(imageUrl); - close(); - handleAlert("success", "프로필 이미지가 저장되었습니다."); - console.log({ updated }); - } catch (error: any) { - handleAlert("error", error.message); + const result = await saveProfileImage(id, imageUrl); + + if (result.state) { + close(); + handleAlert("success", result.message); + } else { + handleAlert("error", result.message); + } + } catch (error) { + console.log(error); } } async function onDelete() { - await saveImage(""); - setImageUrl(""); + try { + const result = await saveProfileImage(id, ""); + setImageUrl(""); + + if (result.state) { + handleAlert("success", result.message); + } else { + handleAlert("error", result.message); + } + } catch (error) { + console.log(error); + } } return ( - +
+
+ +
+ +

+ ※ 영문 / 숫자 / 특수문자(!, @, #, *)중 1가지 포함 12자 이상 +

+
- +
+
+ ), + key: "confirm-unregister", + }); + async function unregister() { try { const result = await unregisterAction(email); @@ -46,10 +66,11 @@ export default function DeleteAccountConfirm({ email }: { email: string }) { colors={{ bg: "bg-status-danger", text: "text-status-danger" }} className="border-status-danger" disabled={!checked} - onClick={unregister} + onClick={open} > 회원 탈퇴 + {Modal}
); } From 0e367ef759501e1d3496d7cd8562dc1c381ad65e Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 18:35:43 +0900 Subject: [PATCH 026/102] =?UTF-8?q?[Refactor,=20Fix]=20=EA=B4=80=EC=8B=AC?= =?UTF-8?q?=20=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EC=84=A0=ED=83=9D=20?= =?UTF-8?q?=EB=8B=A8=EA=B3=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(auth)/_components/RegisterForm.tsx | 43 +-------------------- 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/src/app/(auth)/_components/RegisterForm.tsx b/src/app/(auth)/_components/RegisterForm.tsx index c0434b9..6ac9018 100644 --- a/src/app/(auth)/_components/RegisterForm.tsx +++ b/src/app/(auth)/_components/RegisterForm.tsx @@ -4,52 +4,13 @@ import { ChangeEvent, FormEvent, useState } from "react"; import { useRouter } from "next/navigation"; import { Input } from "./UserInput"; import RegisterCheck from "./RegisterCheck"; -import useModal from "@/hooks/useModal"; import handleAlert from "@/common/Molecules/handleAlert"; import { authAction } from "@/lib/actions/authAction"; -import SetCategoryFavor from "../../_components/SetCategoryFavor"; export default function RegisterForm() { const router = useRouter(); - const { Modal, open, close } = useModal({ - // defaultValue: true, - children: ( - - ), - }); - function closeAndRedirect() { - close(); - router.push("/"); - } - function saveCategory() { - // DB에 저장 - closeAndRedirect(); - } - -export default function RegisterForm() { - const router = useRouter(); const [phoneData, setPhoneData] = useState(""); - const { Modal, open, close } = useModal({ - // defaultValue: true, - children: ( - - ), - }); - function closeAndRedirect() { - close(); - router.push("/"); - } - function saveCategory() { - // DB에 저장 - closeAndRedirect(); - } async function register(e: FormEvent) { e.preventDefault(); @@ -60,9 +21,8 @@ export default function RegisterForm() { const result = await authAction(formData); if (result.state) { + router.replace("/set-category"); handleAlert("success", result.message); - router.replace("/"); - open(); } else { handleAlert("error", result.message); } @@ -119,7 +79,6 @@ export default function RegisterForm() { 가입하기 - {Modal} ); } From 2160a3c2219aad208e5aa47c5bde9b8bf4c830b9 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 18:38:16 +0900 Subject: [PATCH 027/102] =?UTF-8?q?[Refactor]=20toast=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=82=AC=EC=9A=A9=EC=8B=9C=20han?= =?UTF-8?q?dleAlert=EB=A1=9C=20=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(route)/_components/ShareIconButton.tsx | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/app/(route)/_components/ShareIconButton.tsx b/src/app/(route)/_components/ShareIconButton.tsx index 7912715..a6bed72 100644 --- a/src/app/(route)/_components/ShareIconButton.tsx +++ b/src/app/(route)/_components/ShareIconButton.tsx @@ -2,9 +2,8 @@ import Button from "@/common/Atoms/Form/Button"; import Input from "@/common/Molecules/Form/Input"; import { usePathname } from "next/navigation"; -import toast, { Toast } from "react-hot-toast"; -import Notification from "@/common/Molecules/Notification"; import useModal from "@/hooks/useModal"; +import handleAlert from "@/common/Molecules/handleAlert"; export default function ShareIconButton({ width = "38", @@ -14,8 +13,7 @@ export default function ShareIconButton({ height?: string; }) { const pathname = usePathname(); - // TODO: 추후 도메인 수정 - const fullPathname = "https://chemeet.com" + pathname; + const fullPathname = "https://chemeet.vercel.app" + pathname; const { Modal, open } = useModal({ children: ( @@ -34,16 +32,11 @@ export default function ShareIconButton({ function copyPathname() { navigator.clipboard.writeText(fullPathname); - toast.custom((t: Toast) => ( - - )); + handleAlert( + "success", + "URL이 복사되었어요", + "원하는 곳에 붙여넣기 하여 케밋을 공유해보세요!" + ); } return ( <> From 674cea80736259417e68243e4ba02dc3cac28053 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 18:40:15 +0900 Subject: [PATCH 028/102] [Chore] --- src/app/(auth)/_components/LoginForm.tsx | 1 + .../_components/UpdatePhoneNumber/FormUpdatePhoneNumber.tsx | 5 +++-- src/common/Layout/LoadingContainer.tsx | 2 +- src/types/model/User.ts | 1 + tsconfig.json | 1 + 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/(auth)/_components/LoginForm.tsx b/src/app/(auth)/_components/LoginForm.tsx index 60947b9..281e016 100644 --- a/src/app/(auth)/_components/LoginForm.tsx +++ b/src/app/(auth)/_components/LoginForm.tsx @@ -59,6 +59,7 @@ export default function LoginForm() { 회원가입 diff --git a/src/app/(route)/my/profile/_components/UpdatePhoneNumber/FormUpdatePhoneNumber.tsx b/src/app/(route)/my/profile/_components/UpdatePhoneNumber/FormUpdatePhoneNumber.tsx index 1fc0b32..a35db3a 100644 --- a/src/app/(route)/my/profile/_components/UpdatePhoneNumber/FormUpdatePhoneNumber.tsx +++ b/src/app/(route)/my/profile/_components/UpdatePhoneNumber/FormUpdatePhoneNumber.tsx @@ -16,13 +16,14 @@ export default function FormUpdatePhoneNumber({ placeholder="핸드폰 번호를 입력하세요" className="w-full" defaultValue={defaultValue} + readOnly /> - + */}
diff --git a/src/common/Layout/LoadingContainer.tsx b/src/common/Layout/LoadingContainer.tsx index b027f46..8a5a7b1 100644 --- a/src/common/Layout/LoadingContainer.tsx +++ b/src/common/Layout/LoadingContainer.tsx @@ -18,7 +18,7 @@ export default function LoadingContainer({ Date: Wed, 31 Jul 2024 18:40:33 +0900 Subject: [PATCH 029/102] =?UTF-8?q?[Feat]=20=ED=9A=8C=EC=9B=90=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=82=AD=EC=A0=9C=20=EC=95=A1=EC=85=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/actions/authAction.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/lib/actions/authAction.ts b/src/lib/actions/authAction.ts index 627caad..65a0a2c 100644 --- a/src/lib/actions/authAction.ts +++ b/src/lib/actions/authAction.ts @@ -77,3 +77,25 @@ export async function loginKakao() { export async function loginGithub() { await signIn("github"); } + +/** + * 회원탈퇴: email 값을 전달받아 사용자 데이터 삭제. + * 로그인한 사용자 중 이메일로 가입한 사용자만 회원탈퇴 기능 사용 가능 + */ +export async function unregisterAction(email: string) { + await connectDB(); + + const userCheck = await User.findOne({ email }); + console.log({ userCheck }); + if (!userCheck) { + return { state: false, message: "잘못된 email입니다." }; + } + + try { + await User.findOneAndDelete({ email }); + return { state: true, message: "데이터가 삭제되었습니다." }; + } catch (error) { + console.log("auth error" + error); + return { state: false, message: "데이터 삭제에 실패했습니다." }; + } +} From b3fc2b0cc403c746dabf86108efb747c968989f1 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 18:40:55 +0900 Subject: [PATCH 030/102] =?UTF-8?q?[Feat,=20Fix]=20JSDoc=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20=ED=94=84=EB=A1=9C=ED=95=84=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/actions/profileAction.ts | 111 +++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 7 deletions(-) diff --git a/src/lib/actions/profileAction.ts b/src/lib/actions/profileAction.ts index 73d24dc..d3366b6 100644 --- a/src/lib/actions/profileAction.ts +++ b/src/lib/actions/profileAction.ts @@ -2,18 +2,24 @@ import { revalidatePath } from "next/cache"; import connectDB from "../db"; -import { Profile } from "../schema"; +import { Profile, User } from "../schema"; +import { getSession } from "@/auth"; +import { TUserBase } from "@/types/model/User"; -// post +/** + * userId 값을 이용하여 새로운 사용자 프로필 데이터 추가 + */ export async function profileAction(id: string, formData: FormData) { const position_tag = formData.get("positionTag") as string; const introduce = formData.get("introduce") as string; - const my_category = formData.get("interest") as string; + const my_category = JSON.parse(formData.get("interest") as string); if (!id) { return { state: false, message: "유효한 id가 필요합니다." }; } + console.log({ position_tag, introduce, my_category }); + if (!position_tag || !introduce || !my_category) { return { state: false, @@ -44,7 +50,9 @@ export async function profileAction(id: string, formData: FormData) { } } -// get +/** + * userId 값을 통해 프로필 정보 가져오기 + */ export async function getProfile(userId: string) { await connectDB(); @@ -75,11 +83,15 @@ export async function getProfile(userId: string) { } } -// update +/** + * 사용자 프로필 정보 업데이트 + */ export async function updateProfile(id: string, formData: FormData) { - const position_tag = formData.get("positionTag") as string; + const position_tag = formData.get("position_tag") as string; const introduce = formData.get("introduce") as string; - const my_category = formData.get("interest") as string; + const my_category = JSON.parse(formData.get("my_category") as string); + + console.log({ position_tag, introduce, my_category }); try { const update = await Profile.findOneAndUpdate( @@ -106,3 +118,88 @@ export async function updateProfile(id: string, formData: FormData) { }; } } + +/** + * 사용: `` + * + * 관심 카테고리 저장 + * SetCategoryFavor 모달에서 사용 + */ +export async function saveMyCategory(formData: FormData) { + const session = await getSession(); + const userId = session?.user.id; + + if (!userId) { + return { state: false, message: "유효한 id가 필요합니다." }; + } + + await connectDB(); + + const profileExist = await Profile.findOne({ userId }); + + const position_tag = ""; + const introduce = ""; + const my_category = JSON.parse(formData.get("my_category") as string); + + try { + profileExist + ? await Profile.findOneAndUpdate( + { userId }, + { position_tag, introduce, my_category }, + { new: true } + ) + : await new Profile({ + userId, + position_tag, + introduce, + my_category, + }).save(); + + return { + state: true, + message: "프로필 정보가 저장되었습니다.", + }; + } catch (error) { + console.log("profile error" + error); + return { + state: false, + message: "프로필 저장에 실패했습니다.", + }; + } +} + +/** + * 사용 경로: /my/profile + * + * `updateDoc`으로 업데이트할 사용자 정보를 타입에 맞게 전달하여 + * 사용자 정보 업데이트 + */ +type NonStaticUserData = Pick; +type UpdateDocument = Partial; +export async function updateUserInfo(id: string, updateDoc: UpdateDocument) { + await connectDB(); + + const check = await User.findOne({ _id: id }); + console.log({ exist: check }); + + try { + const update = await User.findOneAndUpdate({ _id: id }, updateDoc, { + new: true, + }); + + if (!update) { + return { state: false, message: "해당 프로필을 찾을 수 없습니다." }; + } + console.log("update", { update }); + + revalidatePath("/my/profile"); + + return { + state: true, + message: "프로필 정보가 변경되었습니다.", + }; + } catch (error: any) { + console.log("get profile" + error); + return { state: false, message: "프로필 정보 로딩에 실패했습니다." }; + } +} From 7f6db12a0c058ba3b23d40348d765a045d3434d7 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 18:41:53 +0900 Subject: [PATCH 031/102] =?UTF-8?q?[Refactor,=20Style]=20props=20=EC=A0=84?= =?UTF-8?q?=EB=8B=AC=20=EC=82=AD=EC=A0=9C,=20=EC=9D=B4=EB=B2=A4=ED=8A=B8?= =?UTF-8?q?=20=ED=95=A8=EC=88=98=20=EB=82=B4=EB=B6=80=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98=20=ED=9B=84=20=EC=8B=A4=ED=96=89,=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/_components/SetCategoryFavor.tsx | 135 +++++++++++++++-------- 1 file changed, 86 insertions(+), 49 deletions(-) diff --git a/src/app/_components/SetCategoryFavor.tsx b/src/app/_components/SetCategoryFavor.tsx index c345c17..dee029e 100644 --- a/src/app/_components/SetCategoryFavor.tsx +++ b/src/app/_components/SetCategoryFavor.tsx @@ -1,20 +1,19 @@ "use client"; -import { MouseEventHandler, useRef, useState } from "react"; -import Button from "@/common/Atoms/Form/Button"; -import { CATEGORIES } from "@/constants/categories/job_category"; +import { FormEvent, MouseEventHandler, useRef, useState } from "react"; +import { useRouter } from "next/navigation"; import clsx from "clsx"; +import Button from "@/common/Atoms/Form/Button"; +import { + CATEGORIES, + CATEGORIES_ALL_OPTIONS, +} from "@/constants/categories/job_category"; import Input from "@/common/Molecules/Form/Input"; import { RefreshIcon } from "@/common/Atoms/Image/Icon"; +import { saveMyCategory } from "@/lib/actions/profileAction"; +import handleAlert from "@/common/Molecules/handleAlert"; -export type SetCategoryFavorProps = { - skipThis: MouseEventHandler; - saveCategory: MouseEventHandler; -}; - -export default function SetCategoryFavor({ - skipThis, - saveCategory, -}: SetCategoryFavorProps) { +export default function SetCategoryFavor() { + const router = useRouter(); const categoryGroup = CATEGORIES.map(({ value, label }) => ({ value, label, @@ -22,8 +21,42 @@ export default function SetCategoryFavor({ const [shown, setShown] = useState(0); const categoryRef = useRef(null); + const skipThis: MouseEventHandler = (e) => { + e.preventDefault(); + router.replace("/"); + }; + + async function saveCategory(e: FormEvent) { + e.preventDefault(); + const checkedData = new FormData(e.currentTarget); + const formData = new FormData(); + const my_category = []; + + for (const [key, value] of checkedData) { + if (key !== "category_group") { + my_category.push( + CATEGORIES_ALL_OPTIONS.find((opt) => opt.value === value) + ); + } + } + + formData.append("my_category", JSON.stringify(my_category)); + + try { + const result = await saveMyCategory(formData); + if (result.state) { + router.replace("/"); + handleAlert("success", result.message); + } else { + handleAlert("error", result.message); + } + } catch (error) { + console.log(error); + } + } + return ( -
+

@@ -45,26 +78,30 @@ export default function SetCategoryFavor({

-
-
    - {categoryGroup.map((group, index) => ( -
  • - -
  • - ))} -
-
    -
    + +
    +
      + {categoryGroup.map((group, index) => ( +
    • + +
    • + ))} +
    +
      {CATEGORIES.map(({ value, options }, index) => (
      ))} - -
    -
    -
    -
    - - -
    +
+
+
+
+ + +
+
); } From 03361b4596cdbc120f06b649d163c2b5af55a88a Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 18:42:18 +0900 Subject: [PATCH 032/102] =?UTF-8?q?[Refactor,=20Feat]=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=20=EA=B0=80=EC=9E=85=20=ED=9B=84=20=EA=B4=80=EC=8B=AC=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EC=84=A0=ED=83=9D=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/set-category/page.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/app/set-category/page.tsx diff --git a/src/app/set-category/page.tsx b/src/app/set-category/page.tsx new file mode 100644 index 0000000..cd32d7b --- /dev/null +++ b/src/app/set-category/page.tsx @@ -0,0 +1,17 @@ +import SetCategoryFavor from "@/app/_components/SetCategoryFavor"; +import { getSession } from "@/auth"; +import NotFound from "../not-found"; + +export default async function SetMyCategory() { + const session = await getSession(); + + if (!session) { + return ; + } + + return ( +
+ +
+ ); +} From 1e40f46395ffdb7c30c616ea1de4bd7620fc6e6c Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 18:42:58 +0900 Subject: [PATCH 033/102] =?UTF-8?q?[Feat,=20Fix]=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=A0=95=EB=B3=B4=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EditProfile/FormEditProfile.tsx | 25 ++++++-- .../FormEditProfileImageWithPreview.tsx | 30 +++++++-- .../my/profile/_components/ProfileForms.tsx | 7 +- .../UpdatePassword/FormUpdatePassword.tsx | 64 +++++++++++++++---- 4 files changed, 100 insertions(+), 26 deletions(-) diff --git a/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx b/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx index 89d49f6..526465e 100644 --- a/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx +++ b/src/app/(route)/my/profile/_components/EditProfile/FormEditProfile.tsx @@ -4,7 +4,10 @@ import { ChangeEvent, FormEvent } from "react"; import Input from "@/common/Molecules/Form/Input"; import ProfileInputArea from "../ProfileInputArea"; import Button from "@/common/Atoms/Form/Button"; -import { CATEGORIES } from "@/constants/categories/job_category"; +import { + CATEGORIES, + CATEGORIES_ALL_OPTIONS, +} from "@/constants/categories/job_category"; import { useRouter } from "next/navigation"; import { profileAction, updateProfile } from "@/lib/actions/profileAction"; import { TProfileData } from "@/types/model/Profile"; @@ -31,6 +34,17 @@ export default function FormEditProfile({ return; } + const my_category = []; + for (const [key, value] of formData) { + if (key === "my_category") { + my_category.push( + CATEGORIES_ALL_OPTIONS.find((opt) => opt.value === value) + ); + } + } + + formData.set("my_category", JSON.stringify(my_category)); + try { const result = profile ? await updateProfile(id, formData) @@ -54,7 +68,7 @@ export default function FormEditProfile({
@@ -72,8 +86,9 @@ export default function FormEditProfile({ name="email" defaultValue={session?.user.email || ""} placeholder="이메일 주소를 입력하세요" + readOnly /> -
+ {/*
+
*/}
)} (initProfileUrl); + const modalClose = () => { + setImageUrl(initProfileUrl); + }; + const { Modal, open, close } = useModal({ + defaultValue: false, + onClose: modalClose, children: ( { - if (imageUrl) { + if (initProfileUrl !== imageUrl) { + if (!imageUrl) { + close(); + return; + } open(); } + + return () => { + close(); + }; }, [imageUrl]); function getImage(e: ChangeEvent) { @@ -52,12 +66,9 @@ export default function FormEditProfileImageWithPreview({ } } - // console.log(imageUrl); - async function onSave() { - // TODO: DB에 저장 try { - const result = await saveProfileImage(id, imageUrl); + const result = await updateUserInfo(id, { profile_img: imageUrl }); if (result.state) { close(); @@ -71,8 +82,13 @@ export default function FormEditProfileImageWithPreview({ } async function onDelete() { + if (!imageUrl) { + handleAlert("error", "저장된 프로필 이미지가 없습니다."); + return; + } + try { - const result = await saveProfileImage(id, ""); + const result = await updateUserInfo(id, { profile_img: "" }); setImageUrl(""); if (result.state) { diff --git a/src/app/(route)/my/profile/_components/ProfileForms.tsx b/src/app/(route)/my/profile/_components/ProfileForms.tsx index b621b16..5446238 100644 --- a/src/app/(route)/my/profile/_components/ProfileForms.tsx +++ b/src/app/(route)/my/profile/_components/ProfileForms.tsx @@ -7,6 +7,7 @@ import { getProfile } from "@/lib/actions/profileAction"; import { getSession } from "@/auth"; import FormEditProfileImageWithPreview from "./EditProfileImage/FormEditProfileImageWithPreview"; import NotFound from "@/app/not-found"; +import { TProfileData } from "@/types/model/Profile"; export default async function ProfileForms() { const session = await getSession(); @@ -18,10 +19,10 @@ export default async function ProfileForms() { const userId = session.user.id; const sessionProvider = session.account.provider; const userProfile = await getProfile(userId); - let profile = userProfile.data; + let profile: TProfileData = userProfile.data; let clientProfile = JSON.parse(JSON.stringify(profile)); - console.log("id", session?.user.id); + console.log("[ session.user.id ]", session.user.id); console.log("get 프로필 데이터" + JSON.stringify(profile)); @@ -31,7 +32,7 @@ export default async function ProfileForms() {

{session.user.name}

diff --git a/src/app/(route)/my/profile/_components/UpdatePassword/FormUpdatePassword.tsx b/src/app/(route)/my/profile/_components/UpdatePassword/FormUpdatePassword.tsx index 1b664a6..3fe2e29 100644 --- a/src/app/(route)/my/profile/_components/UpdatePassword/FormUpdatePassword.tsx +++ b/src/app/(route)/my/profile/_components/UpdatePassword/FormUpdatePassword.tsx @@ -1,15 +1,43 @@ "use client"; -import { useState } from "react"; +import { ChangeEvent, FormEvent, useState } from "react"; import Image from "next/image"; +import { PasswordHide, PasswordShow } from "@public/icons"; import ProfileInputArea from "../ProfileInputArea"; import Button from "@/common/Atoms/Form/Button"; import Input from "@/common/Molecules/Form/Input"; -import { PasswordHide, PasswordShow } from "@public/icons"; +import handleAlert from "@/common/Molecules/handleAlert"; + +type TNewPw = { + currentPassword: string; + newPassword: string; + newPasswordCheck: string; +}; + +const newPwInit = { + currentPassword: "", + newPassword: "", + newPasswordCheck: "", +}; export default function FormUpdatePassword() { const [pwShow, setPwShow] = useState(false); + const [newPw, setNewPw] = useState(newPwInit); + function onChangeNewPw(e: ChangeEvent) { + const { name, value } = e.currentTarget; + setNewPw((prev) => ({ ...prev, [name]: value })); + } + function handleSubmit(e: FormEvent) { + e.preventDefault(); + if (newPw.newPassword.length < 12 && newPw.newPasswordCheck.length < 12) { + handleAlert("error", "비밀번호가 너무 짧습니다."); + return; + } + + const formData = new FormData(e.currentTarget); + handleAlert("error", "비밀번호를 변경할 수 없습니다."); + } return ( - + From 517bb6bd32ea6bdbbdf260312f1821dec877fe82 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 18:46:28 +0900 Subject: [PATCH 034/102] =?UTF-8?q?[Feat]=20=EB=92=A4=EB=A1=9C=20=EB=8F=8C?= =?UTF-8?q?=EC=95=84=EA=B0=80=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/not-found.tsx | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx index 619bd20..a0c7aa9 100644 --- a/src/app/not-found.tsx +++ b/src/app/not-found.tsx @@ -1,7 +1,10 @@ +"use client"; import Image from "next/image"; import Link from "next/link"; +import { useRouter } from "next/navigation"; export default function NotFound() { + const router = useRouter(); return (

페이지를 찾을 수가 없어요

@@ -17,12 +20,20 @@ export default function NotFound() {

페이지 주소를 다시 확인해주세요

- - 홈으로 이동 - +
+ + 홈으로 이동 + + +
); From f878114dc84d6e2496d513de9b318d4491b2fe6d Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 19:07:34 +0900 Subject: [PATCH 035/102] =?UTF-8?q?[Chore]=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=EA=B7=B8=EB=A3=B9=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/categories/job_category.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/constants/categories/job_category.ts b/src/constants/categories/job_category.ts index 8e64c86..fc13b5f 100644 --- a/src/constants/categories/job_category.ts +++ b/src/constants/categories/job_category.ts @@ -209,6 +209,10 @@ export const CATEGORIES: CategoryGroup[] = [ }, ]; +export const CATEGORIES_GROUPS: CategoryOption[] = CATEGORIES.map( + ({ value, label }) => ({ value, label }) +); + export const CATEGORIES_ALL_OPTIONS: CategoryOption[] = CATEGORIES.reduce( (prev: CategoryOption[], curr: CategoryGroup) => { return [...prev, ...curr.options]; From 81b938bd61d13b00cbfa47340dd9867dd1b2b757 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 19:08:05 +0900 Subject: [PATCH 036/102] =?UTF-8?q?[Refactor,=20Feat]=20=EB=A9=94=EC=9D=B8?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=EC=B0=BD=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EB=B6=84=EB=A6=AC,=20=EC=8A=A4=ED=84=B0=EB=94=94?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=20=EA=B2=B0=EA=B3=BC=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/_components/TopBannerSearchbar.tsx | 83 ++++++++++++++++++++++ src/app/_components/TopBannerSection.tsx | 49 +------------ 2 files changed, 85 insertions(+), 47 deletions(-) create mode 100644 src/app/_components/TopBannerSearchbar.tsx diff --git a/src/app/_components/TopBannerSearchbar.tsx b/src/app/_components/TopBannerSearchbar.tsx new file mode 100644 index 0000000..570e8d2 --- /dev/null +++ b/src/app/_components/TopBannerSearchbar.tsx @@ -0,0 +1,83 @@ +"use client"; +import Button from "@/common/Atoms/Form/Button"; +import Input from "@/common/Molecules/Form/Input"; +import handleAlert from "@/common/Molecules/handleAlert"; +import { CATEGORIES_GROUPS } from "@/constants/categories/job_category"; +import { GOALS } from "@/constants/categories/study_goal"; +import { useRouter } from "next/navigation"; +import { FormEvent } from "react"; + +export default function TopBannerSearchbar() { + const router = useRouter(); + function search(e: FormEvent) { + e.preventDefault(); + + const formData = new FormData(e.currentTarget); + const newSearchParams = new URLSearchParams(); + for (const [key, value] of formData) { + console.log({ key, value }); + if (value !== "") { + newSearchParams.set(key, value as string); + } + } + + const paramsString = newSearchParams.toString(); + if (!paramsString) { + handleAlert("error", "검색 조건을 하나 이상 입력해주세요."); + return; + } + router.push(`/study/search?${paramsString}`); + } + return ( + +
+ +
+ +
+
+ + +
+
+ + ); +} + +function SearchIconMain() { + return ( + + + + ); +} diff --git a/src/app/_components/TopBannerSection.tsx b/src/app/_components/TopBannerSection.tsx index 2451cf5..c328fba 100644 --- a/src/app/_components/TopBannerSection.tsx +++ b/src/app/_components/TopBannerSection.tsx @@ -1,9 +1,6 @@ import BannerImage from "./BannerImage"; -import Input from "@/common/Molecules/Form/Input"; -import { CATEGORIES } from "@/constants/categories/job_category"; -import { GOALS } from "@/constants/categories/study_goal"; -import Button from "@/common/Atoms/Form/Button"; import { Container } from "@/common/Layout"; +import TopBannerSearchbar from "./TopBannerSearchbar"; export default function TopBanner() { return ( @@ -19,49 +16,7 @@ export default function TopBanner() {
-
-
- -
- -
-
- - -
-
-
+
); From 49cfe994eaabf689db621d995284e63f4fc91ee5 Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 19:11:59 +0900 Subject: [PATCH 037/102] =?UTF-8?q?[Chore]=20=ED=83=AD=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=ED=81=B4=EB=A6=AD=20=ED=95=B8=EB=93=A4=EB=9F=AC=20?= =?UTF-8?q?=EB=8B=A4=EC=8B=9C=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EA=B0=92=20?= =?UTF-8?q?=EC=97=86=EC=9D=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CategoryTab/TabButtonsOfGoalSection.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx b/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx index b64beef..3e1c4a4 100644 --- a/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx +++ b/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx @@ -25,6 +25,15 @@ export default function TabButtonsOfGoalSection() { setStudies(() => init.filter((s) => s.targetCategory.value === selected)); }, [selected]); + function clickHandler(value: string) { + setSelected((prev) => { + // if (prev === value) { + // return initGoal; + // } + return value; + }); + } + return ( <>
@@ -35,7 +44,7 @@ export default function TabButtonsOfGoalSection() { key={value} label={label} active={active} - onClick={() => setSelected(value)} + onClick={() => clickHandler(value)} > Date: Wed, 31 Jul 2024 19:18:23 +0900 Subject: [PATCH 038/102] =?UTF-8?q?[Feat,=20Fix]=20=ED=95=84=ED=84=B0=20?= =?UTF-8?q?=EC=9E=AC=EC=84=A0=ED=83=9D=20=ED=98=B9=EC=9D=80=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=20=EC=84=A0=ED=83=9D=20=EC=8B=9C=20=ED=95=B4=EB=8B=B9?= =?UTF-8?q?=20=ED=95=84=ED=84=B0=EB=A7=81=20=EC=B7=A8=EC=86=8C=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/_components/StudyCategorySelectBox.tsx | 12 ++++++++---- .../_components/StudyCategoryTabButtonList.tsx | 14 +++++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/app/(route)/study/_components/StudyCategorySelectBox.tsx b/src/app/(route)/study/_components/StudyCategorySelectBox.tsx index 9321dd8..606e459 100644 --- a/src/app/(route)/study/_components/StudyCategorySelectBox.tsx +++ b/src/app/(route)/study/_components/StudyCategorySelectBox.tsx @@ -12,11 +12,11 @@ export default function StudyCategorySelectBox({ }: { searchParams: TQuery; }) { - const jobC = searchParams?.job_c || "default"; + const jobC = searchParams?.job_c || "all"; const categories: CategoryGroup[] = [ { - value: "default", - label: "직무선택", + value: "all", + label: "전체", options: [], }, ...CATEGORIES, @@ -28,6 +28,10 @@ export default function StudyCategorySelectBox({ }); const onClickLink = (value: string) => { + if (value === "all") { + onChangeQuery(""); + return; + } onChangeQuery(value); }; @@ -41,7 +45,7 @@ export default function StudyCategorySelectBox({
( + items={categories.map((item) => (
  • { - onChangeQuery(value); - setSelected(value); + setSelected((prev) => { + if (prev === value) { + return ""; + } + return value; + }); }; + useEffect(() => { + onChangeQuery(select); + }, [select]); + return (
    {studyCategoryIcons.map(({ label, value, iconName }) => { From 8b6d32b4456d07881d87caa36a31ee24a412424c Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 19:29:49 +0900 Subject: [PATCH 039/102] =?UTF-8?q?[Feat]=20=ED=9B=84=EC=97=90=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=EC=9D=98=20=EA=B4=80=EC=8B=AC=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC,=20=EA=B0=80=EC=9E=A5=20=EC=B5=9C?= =?UTF-8?q?=EA=B7=BC=EC=97=90=20=EB=A7=8C=EB=93=A4=EC=96=B4=EC=A7=84=20?= =?UTF-8?q?=EC=8A=A4=ED=84=B0=EB=94=94=EB=93=A4=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EA=B0=80=EC=A0=B8=EC=99=80=EC=84=9C=20=EB=B3=B4?= =?UTF-8?q?=EC=97=AC=EC=A3=BC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CategoryTab/TabButtonsOfGoalSection.tsx | 8 ++------ .../_components/RecommendLatestStudies.tsx | 15 ++++++++++++++- src/app/_components/RecommendProStudies.tsx | 19 ++++++++++++++++++- src/app/page.tsx | 7 ++++++- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx b/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx index 3e1c4a4..8670bd0 100644 --- a/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx +++ b/src/app/_components/CategoryTab/TabButtonsOfGoalSection.tsx @@ -26,12 +26,8 @@ export default function TabButtonsOfGoalSection() { }, [selected]); function clickHandler(value: string) { - setSelected((prev) => { - // if (prev === value) { - // return initGoal; - // } - return value; - }); + // 다시 클릭 시 빈 값으로 돌아갈 필요 없음 + setSelected(value); } return ( diff --git a/src/app/_components/RecommendLatestStudies.tsx b/src/app/_components/RecommendLatestStudies.tsx index f56735d..6942027 100644 --- a/src/app/_components/RecommendLatestStudies.tsx +++ b/src/app/_components/RecommendLatestStudies.tsx @@ -1,7 +1,20 @@ import StudyCardList from "@/common/Templates/CardList"; import { getStudyCards } from "@/dummies/studies"; +import connectDB from "@/lib/db"; +import { Study } from "@/lib/schema"; -export default function RecommendLatestStudies() { +async function getLatestStudies() { + // 1. profile에서 관심 카테고리 가져오기 + // 2. 관심카테고리로 필터링하여 스터디 리스트 가져오기 + await connectDB(); + + const studies = await Study.find({}); + console.log("studies", studies); +} + +export default async function RecommendLatestStudies() { const proStudies = getStudyCards(); + await getLatestStudies(); + return ; } diff --git a/src/app/_components/RecommendProStudies.tsx b/src/app/_components/RecommendProStudies.tsx index 59341b8..5f1dfc1 100644 --- a/src/app/_components/RecommendProStudies.tsx +++ b/src/app/_components/RecommendProStudies.tsx @@ -1,7 +1,24 @@ import StudyCardList from "@/common/Templates/CardList"; import { getStudyCards } from "@/dummies/studies"; +import { getProfile } from "@/lib/actions/profileAction"; +import { Study } from "@/lib/schema"; -export default function RecommendProStudies() { +async function getFavorStudies(userId: string) { + // 1. profile에서 관심 카테고리 가져오기 + // 2. 관심카테고리로 필터링하여 스터디 리스트 가져오기 + const profile = await getProfile(userId); + console.log("profile", profile?.data); + + const studies = await Study.find({}); + console.log("studies", studies); +} + +export default async function RecommendProStudies({ + userId, +}: { + userId: string; +}) { const proStudies = getStudyCards(); + await getFavorStudies(userId); return ; } diff --git a/src/app/page.tsx b/src/app/page.tsx index c84461f..8aaab5e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -8,6 +8,11 @@ import RecommendLatestStudies from "./_components/RecommendLatestStudies"; import MainStatusBoard from "./_components/MainStatusBoard"; import { getSession } from "@/auth"; +/** + * 혹은 모든 스터디 가져오기 후 + * 각 Studies/Section으로 스터디 데이터 전달 + */ + export default async function Home() { const session = await getSession(); @@ -22,7 +27,7 @@ export default async function Home() { 인기 많은 스터디 추천 - +
    From 89208b1e6dac7e8f3291861054469a6911354dff Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 31 Jul 2024 21:25:17 +0900 Subject: [PATCH 040/102] =?UTF-8?q?[Style]=20GridField=20=EA=B7=B8?= =?UTF-8?q?=EB=A6=AC=EB=93=9C=20=EB=AC=B4=EB=84=88=EC=A7=90=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(route)/my/profile/_components/ProfileForms.tsx | 2 +- src/app/globals.css | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/(route)/my/profile/_components/ProfileForms.tsx b/src/app/(route)/my/profile/_components/ProfileForms.tsx index 5446238..c49f3e3 100644 --- a/src/app/(route)/my/profile/_components/ProfileForms.tsx +++ b/src/app/(route)/my/profile/_components/ProfileForms.tsx @@ -27,7 +27,7 @@ export default async function ProfileForms() { console.log("get 프로필 데이터" + JSON.stringify(profile)); return ( -
    +

    {session.user.name}

    Date: Wed, 31 Jul 2024 21:25:33 +0900 Subject: [PATCH 041/102] =?UTF-8?q?[Feat]=20=EA=B4=80=EB=A0=A8=20=EC=8A=A4?= =?UTF-8?q?=ED=84=B0=EB=94=94=20=EB=A7=81=ED=81=AC=20=EA=B2=80=EC=83=89,?= =?UTF-8?q?=20=EC=84=A0=ED=83=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_components/CustomizedStudySelect.tsx | 72 +++++++++++++++++++ .../post/write/_components/PostForm.tsx | 55 ++++++++------ .../post/write/_components/SelectCategory.tsx | 21 ++---- .../write/_components/SelectLinkedStudy.tsx | 26 +++++++ 4 files changed, 139 insertions(+), 35 deletions(-) create mode 100644 src/app/(route)/post/write/_components/CustomizedStudySelect.tsx create mode 100644 src/app/(route)/post/write/_components/SelectLinkedStudy.tsx diff --git a/src/app/(route)/post/write/_components/CustomizedStudySelect.tsx b/src/app/(route)/post/write/_components/CustomizedStudySelect.tsx new file mode 100644 index 0000000..516a7e5 --- /dev/null +++ b/src/app/(route)/post/write/_components/CustomizedStudySelect.tsx @@ -0,0 +1,72 @@ +"use client"; +import { TStudyCard } from "@/types/model/StudyCard"; +import Select, { StylesConfig } from "react-select"; + +const card = (thumbnailUrl = "", creator = "") => ({ + alignItems: "center", + display: "flex", + + ":before": { + content: '" "', + backgroundImage: `url("${thumbnailUrl}")`, + backgroundSize: "cover", + backgroundColor: "#dbdbdd", + display: "block", + marginRight: 16, + height: 40, + width: 60, + }, + + ":after": { + content: `"${creator}"`, + display: "block", + marginLeft: 16, + color: "#aaa", + }, +}); + +const studyCardStyle: StylesConfig = { + control: (baseStyles, state) => ({ + ...baseStyles, + minHeight: "56px", + height: "fit-content", + padding: "9px 4px 9px 8px", + borderRadius: "10px", + borderColor: state.isFocused ? "#2a7ffe" : "#dbdbdd", + ":hover": { + borderColor: "var(--color-label-alt)", + color: baseStyles.color, + }, + }), + option: (styles, { data }) => ({ + ...styles, + ...card(data.thumbnailUrl, `${data.user.position} ${data.user.name}`), + }), + singleValue: (styles, { data }) => ({ + ...styles, + ...card(data.thumbnailUrl, `${data.user.position} ${data.user.name}`), + }), +}; + +export type StudyCardSelectOption = TStudyCard & { + value: string; + label: string; +}; + +export default function CustomizedStudySelect({ + options, + className = "", +}: { + options: StudyCardSelectOption[]; + className?: string; +}) { + return ( + 관련 스터디 링크 - {/* */} - {/* 스터디 검색해서 링크 추가하기 */}
    diff --git a/src/app/(route)/post/write/_components/SelectCategory.tsx b/src/app/(route)/post/write/_components/SelectCategory.tsx index 255a0cd..3034a8b 100644 --- a/src/app/(route)/post/write/_components/SelectCategory.tsx +++ b/src/app/(route)/post/write/_components/SelectCategory.tsx @@ -41,6 +41,7 @@ export default function SelectCategory({ { - // const result = await - const studies: StudyCardSelectOption[] = getStudyCards().map((study) => ({ - ...study, - value: `https://chemeet.vercel.app/study/${study.studyId}`, - label: study.title, - })); - await delay(500); - return studies; -} +// async function getStuides(): Promise { +// const result = await getStudy(); +// +// if (result?.state === false) { +// return []; +// } +// +// const studies: StudyCardSelectOption[] = result.data.map((study: any) => ({ +// ...study, +// value: `https://chemeet.vercel.app/study/${study.studyId}`, +// label: study.title, +// })); +// return studies; +// } -export default async function SelectLinkedStudy() { - const studies = await getStuides(); +export default function SelectLinkedStudy() { + // const studies = await getStuides(); return ( }> - + ); } diff --git a/src/lib/actions/communityAction.ts b/src/lib/actions/communityAction.ts index a12d4e3..9adfbf2 100644 --- a/src/lib/actions/communityAction.ts +++ b/src/lib/actions/communityAction.ts @@ -3,6 +3,7 @@ import { nanoid } from "nanoid"; import connectDB from "../db"; import { Post, Comment } from "../schema"; +import { revalidatePath, revalidateTag } from "next/cache"; // post export async function communityAction(id: string, formData: FormData) { @@ -141,6 +142,7 @@ export async function deleteCommunity(postId: string) { await Post.findOneAndDelete({ postId }); await Comment.deleteMany({ postId }); + revalidatePath("/my/post"); return { success: true, message: "커뮤니티 글이 삭제되었습니다." }; } catch (error) { console.error("delete post error", error); diff --git a/src/lib/actions/studyAction.ts b/src/lib/actions/studyAction.ts index 52b0790..ede9c01 100644 --- a/src/lib/actions/studyAction.ts +++ b/src/lib/actions/studyAction.ts @@ -85,12 +85,14 @@ export async function getStudy(studyId: string | null = null) { if (!study) { return { state: false, message: "해당 스터디를 찾을 수 없습니다." }; } + return { state: true, data: study }; } else { const studyList = await Study.find().populate("writer"); - return { state: true, message: studyList }; + return { state: true, data: studyList }; } } catch (error) { console.log(error); + return { state: false, message: "스터디 목록을 가져오는데 실패했습니다." }; } } From 6e140a20801c779f4a98f43046b9ac00710791ee Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 7 Aug 2024 22:35:24 +0900 Subject: [PATCH 062/102] =?UTF-8?q?[Refacor=20Chore]=20accept=20=EA=B0=92?= =?UTF-8?q?=20=EC=88=98=EC=A0=95,=20type=20=EC=9C=84=EC=B9=98=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Molecules/Form/ImageInputWithButton.tsx | 15 +++++++++++---- src/types/component/props.ts | 7 ------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/common/Molecules/Form/ImageInputWithButton.tsx b/src/common/Molecules/Form/ImageInputWithButton.tsx index 6c2fc29..e172064 100644 --- a/src/common/Molecules/Form/ImageInputWithButton.tsx +++ b/src/common/Molecules/Form/ImageInputWithButton.tsx @@ -1,7 +1,14 @@ "use client"; -import Button from "@/common/Atoms/Form/Button"; -import { TImageInputWithButtonProps } from "@/types/component/props"; -import { MouseEvent, useRef } from "react"; +import Button, { TButtonProps } from "@/common/Atoms/Form/Button"; +import { ComponentProps, MouseEvent, ReactNode, useRef } from "react"; + +export type TImageInputWithButtonProps = { + buttonProps: Omit; + children: ReactNode; // be button's children +} & Omit< + ComponentProps<"input">, + "type" | "accept" | "hidden" | "style" | "ref" +>; export default function ImageInputWithButton( props: TImageInputWithButtonProps @@ -25,7 +32,7 @@ export default function ImageInputWithButton( diff --git a/src/types/component/props.ts b/src/types/component/props.ts index 58a6492..609483f 100644 --- a/src/types/component/props.ts +++ b/src/types/component/props.ts @@ -10,13 +10,6 @@ export type TIconButtonProps = ComponentProps<"button"> & { variation: "icon"; size?: number; }; -export type TImageInputWithButtonProps = { - buttonProps: Omit; - children: ReactNode; // be button's children -} & Omit< - ComponentProps<"input">, - "type" | "accept" | "hidden" | "style" | "ref" ->; export type TLinkButtonProps = React.ComponentProps<"a"> & Omit & { href: string | object; From 51f5df90049c9687d069073fe7fc8201c3c9bb6b Mon Sep 17 00:00:00 2001 From: YI Na-yeon <2n.ayeon.yi@gmail.com> Date: Wed, 7 Aug 2024 22:35:54 +0900 Subject: [PATCH 063/102] [Chore] --- src/app/(route)/my/profile/_components/ProfileForms.tsx | 4 ---- src/common/Atoms/Form/InputElement.tsx | 6 +++++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/(route)/my/profile/_components/ProfileForms.tsx b/src/app/(route)/my/profile/_components/ProfileForms.tsx index 386fca8..c9a32b9 100644 --- a/src/app/(route)/my/profile/_components/ProfileForms.tsx +++ b/src/app/(route)/my/profile/_components/ProfileForms.tsx @@ -24,10 +24,6 @@ export default async function ProfileForms() { let profile: TProfileData = userProfile.data; let clientProfile = JSON.parse(JSON.stringify(profile)); - console.log("[ session.user.id ]", session.user.id); - - // console.log("get 프로필 데이터" + JSON.stringify(profile)); - return (
    diff --git a/src/common/Atoms/Form/InputElement.tsx b/src/common/Atoms/Form/InputElement.tsx index ac4e98c..999aa0d 100644 --- a/src/common/Atoms/Form/InputElement.tsx +++ b/src/common/Atoms/Form/InputElement.tsx @@ -49,7 +49,11 @@ export function Textarea(props: React.ComponentProps<"textarea">) { return ( <>