Skip to content

Commit

Permalink
Merge pull request #90 from boostcampwm-2022/feat/write-course-request
Browse files Browse the repository at this point in the history
feat ์ฝ”์Šค ๋“ฑ๋ก API ์—ฐ๋™ / ์ฝ”์Šค ์ •๋ณด์— hName ์ €์žฅํ•˜๋„๋ก ์ˆ˜์ •
  • Loading branch information
pushedrumex authored Nov 24, 2022
2 parents 9304394 + cddcf19 commit 833fa2b
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 30 deletions.
17 changes: 17 additions & 0 deletions client/src/hooks/useLocalAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Axios, { AxiosResponse } from "axios";
import { useCallback } from "react";
type RequestParams = { [key: string]: any };
const axios = Axios.create({
baseURL: "https://dapi.kakao.com/v2/local",
headers: {
Authorization: `KakaoAK ${process.env.REACT_APP_KAKAO_REST_KEY}`,
},
});
const useLocalAPI = <D>(url: string) => {
const query = useCallback((params: RequestParams): Promise<D> => {
return axios.get<RequestParams, AxiosResponse<D>>(url, { params }).then((res) => res.data);
}, []);

return query;
};
export default useLocalAPI;
20 changes: 20 additions & 0 deletions client/src/pages/NewCourse/NewCourse.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import styled from "styled-components";
import { COLOR } from "styles/color";
import { flexColumn } from "styles/flex";

export const CourseForm = styled.div`
${flexColumn};
align-items: center;
width: 100%;
height: "240px";
box-shadow: 0px -4px 4px rgba(0, 0, 0, 0.25);
padding: 15px 27px;
div {
margin-bottom: 10px;
width: 100%;
p {
padding: 16px;
border-bottom: 1px solid ${COLOR.BABY_BLUE};
}
}
`;
71 changes: 47 additions & 24 deletions client/src/pages/NewCourse/NewCourse.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,57 @@
//#region import
import Button from "#components/Button/Button";
import Header from "#components/Header/Header";
import Input from "#components/Input/Input";
import { PLACEHOLDER } from "#constants/placeholder";
import styled from "styled-components";
import { COLOR } from "styles/color";
import { flexColumn } from "styles/flex";
import useWriteMap from "#hooks/useWriteMap";
const CourseForm = styled.div`
${flexColumn};
align-items: center;
width: 100%;
height: "240px";
box-shadow: 0px -4px 4px rgba(0, 0, 0, 0.25);
padding: 15px 27px;
div {
margin-bottom: 10px;
width: 100%;
p {
padding: 16px;
border-bottom: 1px solid ${COLOR.BABY_BLUE};
}
}
`;

import useHttpPost from "#hooks/http/useHttpPost";
import useInput from "#hooks/useInput";
import useLocalAPI from "#hooks/useLocalAPI";
import getLatLngByXY from "#utils/mapUtils";
import { PLACEHOLDER } from "#constants/placeholder";
import { useCallback } from "react";
import { useRecoilValue } from "recoil";
import { userState } from "#atoms/userState";
import { useNavigate } from "react-router-dom";
import { courseTitleValidator } from "#utils/valitationUtils";
import { RegionResponse } from "#types/Region";
import { CourseForm } from "./NewCourse.styles";
//#endregion
const img =
"https://kr.object.ncloudstorage.com/j199/img/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202022-11-20%20%EC%98%A4%ED%9B%84%204.01.56.png";
const NewCourse = () => {
const { renderMap, pathLength } = useWriteMap({
const { userIdx: userId } = useRecoilValue(userState);
const [title, onChangeTitle] = useInput(courseTitleValidator);
const query = useLocalAPI<RegionResponse>("/geo/coord2regioncode.json");
const { post } = useHttpPost();
const navigate = useNavigate();

const { renderMap, pathLength, path } = useWriteMap({
height: `${window.innerHeight - 307}px`,
center: { lat: 33.450701, lng: 126.570667 },
});

const onClickInsertButton = useCallback(async () => {
if (!title || !path.length) return;
try {
const { lng: x, lat: y } = getLatLngByXY(path[0]);
const regions = await query({ x, y });
// [0]: BCode, [1]: HCode
const { code: hCode, region_3depth_name: name } = regions.documents[1];
const response = await post("/course", {
title,
path: path.map(getLatLngByXY),
img,
pathLength,
userId,
hCode,
name,
});
navigate(`/course/${response.courseId}`);
} catch (error: any) {
alert(error.message);
}
}, [path]);

return (
<div style={{ height: "100vh", maxHeight: "100vh" }}>
<Header text="์ฝ”์Šค ๋“ฑ๋ก" loggedIn={true} />
Expand All @@ -40,9 +63,9 @@ const NewCourse = () => {
</div>
<div>
<span>์ฝ”์Šค๋ช…</span>
<Input placeholder={PLACEHOLDER.COURSE_NAME}></Input>
<Input onChange={onChangeTitle} placeholder={PLACEHOLDER.COURSE_NAME}></Input>
</div>
<Button width="fit" onClick={console.log}>
<Button width="fit" onClick={onClickInsertButton}>
์ฝ”์Šค ๋“ฑ๋ก
</Button>
</CourseForm>
Expand Down
16 changes: 16 additions & 0 deletions client/src/types/Region.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export interface RegionResponse {
documents: Region[];
meta: { total_count: number };
}

interface Region {
address_name: string;
code: string;
region_1depth_name: string;
region_2depth_name: string;
region_3depth_name: string;
region_4depth_name: string;
region_type: string;
x: string;
y: string;
}
7 changes: 7 additions & 0 deletions client/src/utils/mapUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { LatLng } from "#types/LatLng";

const getLatLngByPoint = (point: kakao.maps.LatLng): LatLng => {
return { lat: point.getLat(), lng: point.getLng() };
};

export default getLatLngByPoint;
7 changes: 6 additions & 1 deletion client/src/utils/valitationUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ export const idValidator = (id: string) => {
export const passwordValidator = (password: string) => {
return password.length < 10 || password.length > 100 ? "๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 10์ž ์ด์ƒ 100์ž ์ดํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค" : "";
};

export const confirmPasswordValidator = (password: string) => (confirmPassword: string) => {
return password !== confirmPassword || !confirmPassword ? "๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค" : "";
};

export const hCodeValidator = (hCode: string) => {
return hCode.length === 5 ? "" : "์ง€์—ญ์„ ์ž…๋ ฅํ•˜์„ธ์š”";
return hCode.length === 10 ? "" : "์ง€์—ญ์„ ์ž…๋ ฅํ•˜์„ธ์š”";
};

export const courseTitleValidator = (title: string) => {
return !title ? "์ œ๋ชฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”" : "";
};
7 changes: 4 additions & 3 deletions server/src/course/dto/create-course.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Type } from "class-transformer";
import { IsNumber, IsNumberString, IsString } from "class-validator";
import { isValidPath } from "src/common/decorator/path.validator";
import { LatLng } from "src/common/type/lat-lng";
Expand All @@ -17,14 +16,16 @@ export class CreateCourseDto {
@IsNumber()
private pathLength: number;

@Type(() => Number)
@IsNumber()
private userId: number;

@IsString()
private name: string;

@IsNumberString()
private hCode: string;

toEntity() {
return Course.of(this.title, this.img, this.path, this.pathLength, this.hCode, this.userId);
return Course.of(this.title, this.img, this.path, this.pathLength, this.hCode, this.userId, this.name);
}
}
13 changes: 11 additions & 2 deletions server/src/entities/course.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class Course {
@Column()
pathLength: number;

@Column({ type: "varchar", length: 10 })
@Column({ type: "varchar", length: 10, nullable: true })
name: string;

@CreateDateColumn()
Expand All @@ -39,14 +39,23 @@ export class Course {
@JoinColumn({ name: "userId", referencedColumnName: "id" })
user: User;

static of(title: string, img: string, path: LatLng[], pathLength: number, hCode: string, userId: number) {
static of(
title: string,
img: string,
path: LatLng[],
pathLength: number,
hCode: string,
userId: number,
name: string,
) {
const course = new Course();
course.title = title;
course.img = img;
course.path = JSON.stringify(path);
course.hCode = hCode;
course.pathLength = pathLength;
course.userId = userId;
course.name = name;
return course;
}
}

0 comments on commit 833fa2b

Please sign in to comment.