diff --git a/app/(auth)/_widgets/.gitkeep b/app/(auth)/_widgets/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/(auth)/signin/page.json b/app/(auth)/signin/page.json index 0de4a55fd..c34ade41f 100644 --- a/app/(auth)/signin/page.json +++ b/app/(auth)/signin/page.json @@ -1,8 +1,8 @@ [ { - "id": "이메일", "type": "email", "pattern": "[^@\\s]+@[^@\\s]+\\.[^@\\s]+", "required": true, "placeholder": "이메일을 입력해주세요", "autocomplete": "email" + "id": "email", "label": "이메일", "type": "email", "pattern": "[^@\\s]+@[^@\\s]+\\.[^@\\s]+", "required": true, "placeholder": "이메일을 입력해주세요", "autocomplete": "email" }, { - "id": "비밀번호", "type": "password", "minlength": 8, "maxlength": 16, "required": true, "placeholder": "비밀번호를 입력해주세요", "autocomplete": "password" + "id": "password", "label": "비밀번호", "type": "password", "minlength": 8, "maxlength": 16, "required": true, "placeholder": "비밀번호를 입력해주세요", "autocomplete": "password" } ] diff --git a/app/(auth)/signin/page.tsx b/app/(auth)/signin/page.tsx index 2c91abf42..623d40903 100644 --- a/app/(auth)/signin/page.tsx +++ b/app/(auth)/signin/page.tsx @@ -1,5 +1,7 @@ "use client"; +import API from "@/app/_api"; + import json from "./page.json"; import Link from "next/link"; @@ -9,15 +11,27 @@ import useForm, { Cause, Trigger } from "@/app/_hooks/useForm"; export default function Page() { - const { errors, verify, disabled } = useForm("signin", - // onSubmit - (data) => + const signin = useForm("signin", [Trigger.BLUR, Trigger.CHANGE], (data) => { - console.log(data); - }, - // onCheck - (input, values, causes) => + API["auth/signIn"].POST( + { + email: data.get("이메일") as string, + password: data.get("비밀번호") as string, + }) + .then((response) => + { + document.cookie = response.accessToken; + }) + .catch((error) => + { + console.error(error); + }); + }); + + signin.verify(({ input, trigger }) => { + const causes = signin.causes(input); + if (causes.has(Cause.REQUIRED)) { return `${input.name}을(를) 입력해주세요`; @@ -35,9 +49,7 @@ export default function Page() return `${input.name}을(를) ${input.maxLength}자 이하 입력해주세요`; } return null; - }, - // triggers - [Trigger.BLUR, Trigger.INPUT]); + }); return ( <> @@ -49,11 +61,11 @@ export default function Page()
- + { args.type === "password" && visibility { @@ -78,12 +90,12 @@ export default function Page() }
{ - errors[args.id] &&
{errors[args.id]}
+ signin.errors[args.label] &&
{signin.errors[args.label]}
}
))} - diff --git a/app/(auth)/signup/page.json b/app/(auth)/signup/page.json index d2bbad261..69f6a21dd 100644 --- a/app/(auth)/signup/page.json +++ b/app/(auth)/signup/page.json @@ -1,14 +1,14 @@ [ { - "id": "이메일"," type": "email", "pattern": "[^@\\s]+@[^@\\s]+\\.[^@\\s]+", "required": true, "placeholder": "이메일을 입력해주세요", "autocomplete": "email" + "id": "email", "label": "이메일", "type": "email", "pattern": "[^@\\s]+@[^@\\s]+\\.[^@\\s]+", "required": true, "placeholder": "이메일을 입력해주세요", "autocomplete": "email" }, { - "id": "닉네임", "type": "text", "minlength": 2, "maxlength": 8, "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", "required": true, "placeholder": "닉네임을 입력해주세요" + "id": "nickname", "label": "닉네임", "type": "text", "minlength": 2, "maxlength": 8, "pattern": "^[a-zA-Z][a-zA-Z0-9_]*$", "required": true, "placeholder": "닉네임을 입력해주세요" }, { - "id": "비밀번호", "type": "password", "minlength": 8, "maxlength": 16, "required": true, "placeholder": "비밀번호를 입력해주세요", "autocomplete": "new-password" + "id": "password", "label": "비밀번호", "type": "password", "minlength": 8, "maxlength": 16, "required": true, "placeholder": "비밀번호를 입력해주세요", "autocomplete": "new-password" }, { - "id": "비밀번호 확인", "type": "password", "minlength": 8, "maxlength": 16, "required": true, "placeholder": "비밀번호를 다시 한번 입력해주세요", "autocomplete": "new-password" + "id": "passwordConfirmation", "label": "비밀번호 확인", "type": "password", "minlength": 8, "maxlength": 16, "required": true, "placeholder": "비밀번호를 다시 한번 입력해주세요", "autocomplete": "new-password" } ] diff --git a/app/(auth)/signup/page.tsx b/app/(auth)/signup/page.tsx index 9b41903c0..ff151a9b3 100644 --- a/app/(auth)/signup/page.tsx +++ b/app/(auth)/signup/page.tsx @@ -1,5 +1,7 @@ "use client"; +import API from "@/app/_api"; + import json from "./page.json"; import Link from "next/link"; @@ -9,60 +11,53 @@ import useForm, { Cause, Trigger } from "@/app/_hooks/useForm"; export default function Page() { - const { errors, verify, disabled } = useForm("signup", - // onSubmit - (data) => + const signup = useForm("signup", [Trigger.BLUR, Trigger.CHANGE], (data) => { - console.log(data); - }, - // onCheck - (input, values, causes) => + API["auth/signUp"].POST( + { + email: data.get("이메일") as string, + nickname: data.get("닉네임") as string, + password: data.get("비밀번호") as string, + passwordConfirmation: data.get("비밀번호 확인") as string, + }) + .then((response) => + { + document.cookie = response.accessToken; + }) + .catch((error) => + { + console.error(error); + }); + }); + + signup.effect(({ input, trigger }) => { switch (input.name) { case "비밀번호": { - if (values["비밀번호 확인"]) + if (signup.values["비밀번호 확인"]) { - // - // anti-pattern - // - if (causes.has(Cause.REQUIRED)) - { - errors[input.name] = `${input.name}을(를) 입력해주세요`; - } - else if (causes.has(Cause.PATTERN)) - { - errors[input.name] = `올바른 ${input.name}을(를) 입력해주세요`; - } - else if (causes.has(Cause.MINLENGTH)) - { - errors[input.name] = `${input.name}을(를) ${input.minLength}자 이상 입력해주세요`; - } - else if (causes.has(Cause.MAXLENGTH)) - { - errors[input.name] = `${input.name}을(를) ${input.maxLength}자 이하 입력해주세요`; - } - else - { - errors[input.name] = null; - } - // - // sync - // - verify("비밀번호 확인"); - - return errors[input.name] ? errors[input.name] : null; + signup.notify("비밀번호 확인"); } break; } + } + }); + + signup.verify(({ input, trigger }) => + { + const causes = signup.causes(input); + + switch (input.name) + { case "비밀번호 확인": { - if (errors["비밀번호"]) + if (signup.errors["비밀번호"]) { return "비밀번호를 확인해주세요"; } - if (values["비밀번호"] !== values["비밀번호 확인"]) + if (signup.values["비밀번호"] !== signup.values["비밀번호 확인"]) { return "비밀번호가 일치하지 않습니다"; } @@ -86,9 +81,7 @@ export default function Page() return `${input.name}을(를) ${input.maxLength}자 이하 입력해주세요`; } return null; - }, - // triggers - [Trigger.BLUR, Trigger.INPUT]); + }); return ( <> @@ -100,11 +93,11 @@ export default function Page()
- + { args.type === "password" && visibility { @@ -129,12 +122,12 @@ export default function Page() }
{ - errors[args.id] &&
{errors[args.id]}
+ signup.errors[args.label] &&
{signup.errors[args.label]}
}
))} - diff --git a/app/(forum)/addboard/[id]/page.tsx b/app/(forum)/addboard/[id]/page.tsx new file mode 100644 index 000000000..2427977d0 --- /dev/null +++ b/app/(forum)/addboard/[id]/page.tsx @@ -0,0 +1,157 @@ +"use client"; + +import API from "@/app/_api"; + +import { useCallback, useEffect, useRef, useState } from "react"; + +import Link from "next/link"; +import Image from "next/image"; + +import { useParams } from "next/navigation"; + +export default function Page() +{ + const { id } = useParams(); + + const [article, set_article] = useState>>(); + const [comments, set_comments] = useState>["list"]>([]); + + const [my_comment, set_my_comment] = useState(""); + + useEffect(() => + { + API["articles/{articleId}"].GET({ articleId: Number(id) }).then((response) => + { + set_article(response); + }); + API["articles/{articleId}/comments"].GET({ articleId: Number(id), limit: 3 }).then((response) => + { + set_comments(response.list); + }); + }, + [id]); + + const post_comment = useCallback((event: React.FormEvent) => + { + API["articles/{articleId}/comments"].POST({ articleId: Number(id), content: my_comment }, { "Authorization": `Bearer ${document.cookie}` }).then((response) => + { + set_comments((comments) => [...comments, response]); + }); + event.preventDefault(); + }, + [id, my_comment]); + + if (!article) + { + return (<>불러오는중...); + } + return ( + <> +
+
+ { + article.title + } + likes +
+
+
+ likes +
+ { + article.writer.nickname + } +
+
+ { + new Date(article.createdAt).toLocaleDateString() + } +
+
+
+
+ likes +
+ { + article.likeCount + } +
+
+
+
+
+ { + article.content + } +
+
+ +
+