Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨Feat(#152): 내 템플릿 API 1차 연동 #163

Merged
merged 8 commits into from
Nov 13, 2023
73 changes: 65 additions & 8 deletions src/app/(user-menu)/mypage/template/create/page.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,109 @@
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { useToast } from "@/components/ui/use-toast";
import { createTemplate } from "@/services/template/createTemplate";
import Button, { buttonSize } from "@/components/_common/Button";
import Icon from "@/components/_common/Icon";

const CreateTemplatePage = () => {
const [question, setQuestion] = useState([{ id: 1 }]);
const [question, setQuestion] = useState([{ id: 1, value: "" }]);
const [content, setContent] = useState("");
const [count, setCount] = useState(2);
const { toast } = useToast();
const router = useRouter();

const validateQuestion = (content: string) => {
Copy link
Member

Choose a reason for hiding this comment

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

단순 validation만 담당하는 함수는 아닌 것 같아요!
handleAddQuestion 이라는 네이밍을 제안드립니다!

if (content === "") {
toast({
description: "질문은 1번에 1개씩 입력해주세요.",
variant: "red",
});
return;
} else {
setContent("");
addQuestion();
}
};

const addQuestion = () => {
setCount(count + 1);
const newQuestion = {
id: count,
value: "",
};
setQuestion((prev) => [...prev, newQuestion]);
setCount(count + 1);
};

const removeQuestion = (id: number) => {
setCount(count - 1);
setQuestion((prev) => prev.filter((item) => item.id !== id));
};

const handlePostTemplate = () => {
const json = {
title: "넥터디 템플릿",
questions: question.map((item) => item.value),
};
createTemplate(json);
router.push("/mypage/template");
};

const handleInputChange = (
event: React.ChangeEvent<HTMLInputElement>,
id: number,
) => {
setContent(event.target.value);
const updatedQuestions = question.map((question) => {
if (question.id === id) {
return { ...question, value: event.target.value };
}
return question;
});
setQuestion(updatedQuestions);
};

return (
<div className="flex gap-30">
<div>
<div className="flex justify-between p-20 text-30 font-bold">
신청서 템플릿 생성
템플릿 생성
<Button
className={`${buttonSize.lg} bg-st-primary text-st-white`}
onClick={addQuestion}
onClick={() => validateQuestion(content)}
>
질문 추가
</Button>
</div>
<div className="h-5 w-full bg-st-gray-400"></div>
<div className="h-750 w-750 overflow-y-scroll">
<div className="flex flex-col gap-20 p-20">
{question.map((item) => (
{question.map((item, index) => (
<div
key={item.id}
key={index}
className="flex h-70 w-full items-center gap-30 rounded-10 p-10 shadow-lg"
>
<div className="h-60 w-10 rounded-full bg-st-skyblue-50"></div>
<input
type="text"
placeholder="질문을 입력해 주세요."
value={item.value}
className="h-50 w-5/6 text-20 text-st-gray-200 outline-none"
onChange={(e) => handleInputChange(e, item.id)}
/>
Comment on lines +93 to 94
Copy link
Member

Choose a reason for hiding this comment

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

저희 컨벤션 중에 event에 대한 네이밍은 e 보다는 event로 쓰기로 했습니당!

<div
className="cursor-pointer"
onClick={() => removeQuestion(item.id)}
onClick={() => {
if (count === 2) {
toast({
description: "질문은 최소 1개 이상이어야 합니다.",
variant: "red",
});
} else {
removeQuestion(item.id);
}
}}
>
<Icon
name="cross"
Expand All @@ -63,7 +117,10 @@ const CreateTemplatePage = () => {
</div>
<div className="h-5 w-full bg-st-gray-400"></div>
<div className="mt-20 flex w-full justify-end">
<Button className={`${buttonSize.lg} bg-st-primary text-st-white`}>
<Button
onClick={() => handlePostTemplate()}
className={`${buttonSize.lg} bg-st-primary text-st-white`}
>
생성하기
</Button>
</div>
Expand Down
80 changes: 28 additions & 52 deletions src/app/(user-menu)/mypage/template/edit/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,98 +1,74 @@
"use client";

import { useState } from "react";
import { usePathname } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import getTemplateDetail from "@/services/template/getTemplateDetail";
import Button, { buttonSize } from "@/components/_common/Button";
import Icon from "@/components/_common/Icon";

const EditTemplatePage = () => {
const [question, setQuestion] = useState([
{
question: "이름이 뭔가요?",
id: 1,
},
{
question: "스테디 지원 동기?",
id: 2,
},
{
question: "스테디로 얻고자하는 것은?",
id: 3,
},
]);
const [count, setCount] = useState(4);

const addQuestion = () => {
setCount(count + 1);
const newQuestion = {
question: "",
id: count,
};
setQuestion((prev) => [...prev, newQuestion]);
};
// import Icon from "@/components/_common/Icon";

const removeQuestion = (id: number) => {
setCount(count - 1);
setQuestion((prev) => prev.filter((item) => item.id !== id));
};
const EditTemplatePage = () => {
const pathname = usePathname();
const templateId = pathname.split("/")[4];

const updateQuestion = (id: number, newValue: string) => {
setQuestion((prev) => {
return prev.map((item) => {
if (item.id === id) {
return { ...item, question: newValue };
}
return item;
});
});
};
const { data } = useQuery({
queryKey: ["template_detail"],
queryFn: () => getTemplateDetail(templateId),
});

return (
<div className="flex gap-30">
<div>
<div className="flex justify-between p-20 text-30 font-bold">
신청서 템플릿 수정
템플릿 상세보기
<Button
className={`${buttonSize.lg} bg-st-primary text-st-white`}
// onClick={addQuestion}
>
수정하기
</Button>
{/* <Button
className={`${buttonSize.lg} bg-st-primary text-st-white`}
onClick={addQuestion}
>
질문 추가
</Button>
</Button> */}
</div>
<div className="h-5 w-full bg-st-gray-400"></div>
<div className="h-750 w-750 overflow-y-scroll">
<div className="flex flex-col gap-20 p-20">
{question.map((item) => (
{data?.questions.map((item, index) => (
<div
key={item.id}
key={index}
className="flex h-70 w-full items-center gap-30 rounded-10 p-10 shadow-lg"
>
<div className="h-60 w-10 rounded-full bg-st-skyblue-50"></div>
<input
type="text"
placeholder="질문을 입력해 주세요."
value={item.question}
onChange={(e) => updateQuestion(item.id, e.target.value)}
value={item}
// onChange={(e) => updateQuestion(item.id, e.target.value)}
className="h-50 w-5/6 text-20 text-st-gray-200 outline-none"
/>
<div
className="cursor-pointer"
onClick={() => removeQuestion(item.id)}
// onClick={() => removeQuestion(item.id)}
>
<Icon
{/* <Icon
name="cross"
size={20}
color=""
/>
/> */}
</div>
</div>
))}
</div>
</div>
<div className="h-5 w-full bg-st-gray-400"></div>
<div className="mt-20 flex w-full justify-end">
<Button className={`${buttonSize.lg} bg-st-primary text-st-white`}>
{/* <Button className={`${buttonSize.lg} bg-st-primary text-st-white`}>
수정완료
</Button>
</Button> */}
</div>
</div>
</div>
Expand Down
70 changes: 29 additions & 41 deletions src/app/(user-menu)/mypage/template/page.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,48 @@
"use client";

import Link from "next/link";
import { useQuery } from "@tanstack/react-query";
import getTemplates from "@/services/template/getTemplates";
import Button, { buttonSize } from "@/components/_common/Button";
import Icon from "@/components/_common/Icon";

const MyTemplatePage = () => {
const myFormItems = [
{
title: "넥터디 양식",
createdAt: "2023.09.27",
id: "1",
},
{
title: "넥터디 양식",
createdAt: "2023.09.27",
id: "2",
},
{
title: "넥터디 양식",
createdAt: "2023.09.27",
id: "3",
},
];
const { data } = useQuery({ queryKey: ["templates"], queryFn: getTemplates });

return (
<div className="flex gap-30">
<div>
<div className="flex justify-between p-20 text-30 font-bold">
내 신청서 양식
<Button className={`${buttonSize.lg} bg-st-primary text-st-white`}>
신청서 생성
</Button>
내 템플릿
<Link href={"/mypage/template/create"}>
<Button className={`${buttonSize.lg} bg-st-primary text-st-white`}>
템플릿 생성
</Button>
</Link>
</div>
<div className="h-5 w-full bg-st-gray-400"></div>
<div className="h-750 w-750">
{myFormItems.map((form, id) => (
<div
{data?.templates.map((form, id) => (
<Link
key={id}
className="group flex items-center justify-between p-50 transition hover:scale-105 hover:bg-st-gray-50"
href={`/mypage/template/edit/${form.id}`}
>
<div className="text-25 font-bold">{form.title}</div>
<div className="group flex">
<div className="transform text-15 font-bold text-st-gray-100 transition group-hover:-translate-x-[30px]">
생성일 {form.createdAt}
</div>
<div className="hidden gap-20 transition duration-500 group-hover:flex">
<Icon
name="pencil"
size={20}
color="text-st-gray-100"
/>
<Icon
name="trash"
size={20}
color="text-st-gray-100"
/>
<div className="group flex items-center justify-between p-50 transition hover:scale-105 hover:bg-st-gray-50">
<div className="text-25 font-bold">{form.title}</div>
<div className="group flex">
<div className="transform text-15 font-bold text-st-gray-100 transition group-hover:-translate-x-[30px]">
생성일 {form.createdAt}
</div>
<div className="hidden gap-20 transition duration-500 group-hover:flex">
<Icon
name="trash"
size={20}
color="text-st-gray-100"
/>
</div>
</div>
</div>
</div>
</Link>
))}
</div>
<div className="h-5 w-full bg-st-gray-400"></div>
Expand Down
2 changes: 1 addition & 1 deletion src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const config = {
"/steady/applicant/:id*",
"/application",
"/mysteady",
"/mypage/:path*",
// "/mypage/:path*",
"/logout",
],
};
6 changes: 6 additions & 0 deletions src/services/template/createTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { axiosInstance } from "..";
import type { CreateTemplateType } from "../types";

export const createTemplate = (payload: CreateTemplateType): Promise<void> => {
return axiosInstance.post("/api/v1/template", payload);
};
17 changes: 17 additions & 0 deletions src/services/template/getTemplateDetail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { axiosInstance } from "@/services";
import type { AxiosResponse } from "axios";
import type { TemplateDetailType } from "../types";

const getTemplateDetail = async (id: string) => {
try {
const response: AxiosResponse<TemplateDetailType> = await axiosInstance.get(
`/api/v1/template/${id}`,
);
return response.data;
} catch (error) {
console.error(error);
throw error;
}
};

export default getTemplateDetail;
16 changes: 16 additions & 0 deletions src/services/template/getTemplates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { axiosInstance } from "@/services";
import type { AxiosResponse } from "axios";
import type { TemplateType } from "../types";

const getTemplates = async () => {
try {
const response: AxiosResponse<TemplateType> =
await axiosInstance.get(`/api/v1/template`);
return response.data;
} catch (error) {
console.error(error);
throw error;
}
};

export default getTemplates;
Loading
Loading