diff --git a/.eslintrc.json b/.eslintrc.json index bffb357a7..fedbe5990 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,57 @@ { - "extends": "next/core-web-vitals" + "root": true, + "parser": "@typescript-eslint/parser", + + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": 12, + "sourceType": "module", + "project": "./tsconfig.json" + }, + "env": { + // 전역객체를 eslint가 인식하는 구간 + "browser": true, // document나 window 인식되게 함 + "node": true, + "es6": true + }, + "extends": [ + "next/core-web-vitals", + "eslint:recommended", + "plugin:react/recommended", + "plugin:@typescript-eslint/recommended", + "prettier" + ], + "plugins": [ + "eslint-plugin-simple-import-sort", + "prettier", + "react", + "@typescript-eslint" + ], + + "rules": { + "react/react-in-jsx-scope": "off", + "react/prop-types": "off", + "@typescript-eslint/no-explicit-any": "off", + "react/no-unescaped-entities": "off", + "@next/next/no-page-custom-font": "off", + "react/self-closing-comp": [ + "error", + { + "component": true, + "html": true + } + ], + "react/jsx-first-prop-new-line": "error", + "indent": ["error", 2, { "SwitchCase": 1 }], + "eol-last": "error", + "no-multiple-empty-lines": ["error", { "max": 1 }], + "semi": ["error", "always"], + "simple-import-sort/imports": "error", + "simple-import-sort/exports": "error", + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "off", + "comma-spacing": ["error", { "before": false, "after": true }] + } } diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..52135555f --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,16 @@ +{ + "arrowParens": "always", + "bracketSameLine": false, + "bracketSpacing": true, + "insertPragma": false, + "printWidth": 80, + "proseWrap": "preserve", + "quoteProps": "as-needed", + "requirePragma": false, + "semi": true, + "singleAttributePerLine": false, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "all", + "useTabs": false +} diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 000000000..f91284705 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "windows-gcc-x86", + "includePath": [ + "${workspaceFolder}/**" + ], + "compilerPath": "C:/MinGW/bin/gcc.exe", + "cStandard": "${default}", + "cppStandard": "${default}", + "intelliSenseMode": "windows-gcc-x86", + "compilerArgs": [ + "" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..d436b4b8d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C/C++ Runner: Debug Session", + "type": "cppdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "externalConsole": true, + "cwd": "c:/Users/hansw/과제/C언어", + "program": "c:/Users/hansw/과제/C언어/build/Debug/outDebug", + "MIMode": "gdb", + "miDebuggerPath": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..bb879da5a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,59 @@ +{ + "C_Cpp_Runner.cCompilerPath": "gcc", + "C_Cpp_Runner.cppCompilerPath": "g++", + "C_Cpp_Runner.debuggerPath": "gdb", + "C_Cpp_Runner.cStandard": "", + "C_Cpp_Runner.cppStandard": "", + "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": false +} \ No newline at end of file diff --git a/app/apis/Axios.ts b/app/apis/Axios.ts index a9fe31b44..12b709d49 100644 --- a/app/apis/Axios.ts +++ b/app/apis/Axios.ts @@ -1,9 +1,10 @@ -import axios, { AxiosInstance } from "axios"; -import { refreshAccessToken } from "./refreshToken"; +import axios, { AxiosInstance } from 'axios'; + +import { refreshAccessToken } from './refreshToken'; const getAccessToken = () => { - if (typeof window !== "undefined") { - return localStorage.getItem("accessToken"); + if (typeof window !== 'undefined') { + return localStorage.getItem('accessToken'); } return null; }; @@ -11,7 +12,7 @@ const getAccessToken = () => { export const instance: AxiosInstance = axios.create({ baseURL: process.env.NEXT_PUBLIC_BASE_URL, headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', Authorization: `Bearer ${getAccessToken()}`, }, }); diff --git a/app/apis/SignUpUser.ts b/app/apis/SignUpUser.ts index d1141f597..8feaa8324 100644 --- a/app/apis/SignUpUser.ts +++ b/app/apis/SignUpUser.ts @@ -1,5 +1,6 @@ -import { AxiosError } from "axios"; -import { instance } from "./Axios"; +import { AxiosError } from 'axios'; + +import { instance } from './Axios'; type SignUpData = { email: string; @@ -14,23 +15,23 @@ type SignUpResponse = { const fetchData = async ( url: string, - data?: SignUpData + data?: SignUpData, ): Promise => { try { const response = await instance.post(url, JSON.stringify(data)); return response.data; } catch (error) { if (error instanceof AxiosError) { - console.error("요청 실패 (Axios error):", error.message); + console.error('요청 실패 (Axios error):', error.message); } else { - console.error("요청 실패 (Unknown error):", error); + console.error('요청 실패 (Unknown error):', error); } return undefined; } }; export const signUpUser = ( - data: SignUpData + data: SignUpData, ): Promise => { - return fetchData("/auth/signup", data); + return fetchData('/auth/signup', data); }; diff --git a/app/apis/getArticleDetail.ts b/app/apis/getArticleDetail.ts index 0f66f950c..e071fa9f7 100644 --- a/app/apis/getArticleDetail.ts +++ b/app/apis/getArticleDetail.ts @@ -1,4 +1,4 @@ -import { instance } from "./Axios"; +import { instance } from './Axios'; export interface RootObject { id: number; @@ -27,6 +27,6 @@ export async function getArticleDetail(articleId: number): Promise { const data = res.data; return data; } catch (error) { - throw error; + throw new Error('게시글 조회 중 오류 발생'); } } diff --git a/app/apis/getProducts.ts b/app/apis/getProducts.ts new file mode 100644 index 000000000..c35ad4fbf --- /dev/null +++ b/app/apis/getProducts.ts @@ -0,0 +1,54 @@ +import { AxiosError } from 'axios'; + +import { instance } from './Axios'; + +export interface Product { + id: string; + name: string; + description: string; + price: number; + tags: string[]; + images: string[]; + favoriteCount: number; + createdAt: string; + ownerId: string; +} + +export interface ProductResponse { + totalCount: number; + list: Product[]; +} + +export interface GetProductsParams { + page?: number; + pageSize?: number; + orderBy?: 'favorite' | 'recent'; + keyword?: string; +} + +const handleAxiosError = (error: unknown) => { + if (error instanceof AxiosError) { + console.error('Axios error:', error.message); + } else { + console.error('Unknown error:', error); + } +}; + +export const getProducts = async ( + params: GetProductsParams = {}, +): Promise => { + try { + const response = await instance.get('/products', { + params: { + page: params.page || 1, + pageSize: params.pageSize || 10, + orderBy: params.orderBy, + keyword: params.keyword, + }, + }); + return response.data; + } catch (error) { + handleAxiosError(error); + return undefined; + } +}; diff --git a/app/apis/loginUser.ts b/app/apis/loginUser.ts index 8725fcd0a..632657773 100644 --- a/app/apis/loginUser.ts +++ b/app/apis/loginUser.ts @@ -1,5 +1,6 @@ -import { AxiosError } from "axios"; -import { instance } from "./Axios"; +import { AxiosError } from 'axios'; + +import { instance } from './Axios'; type LoginData = { email: string; @@ -12,23 +13,23 @@ type LoginResponse = { }; const loginUser = async ( - data: LoginData + data: LoginData, ): Promise => { try { - const response = await instance.post("/auth/signIn", data); + const response = await instance.post('/auth/signIn', data); const { accessToken, refreshToken } = response.data; - if (typeof window !== "undefined") { - localStorage.setItem("accessToken", accessToken); - localStorage.setItem("refreshToken", refreshToken); + if (typeof window !== 'undefined') { + localStorage.setItem('accessToken', accessToken); + localStorage.setItem('refreshToken', refreshToken); } return response.data; } catch (error) { if (error instanceof AxiosError) { - console.error("요청 실패 (Axios error):", error.message); + console.error('요청 실패 (Axios error):', error.message); } else { - console.error("요청 실패 (Unknown error):", error); + console.error('요청 실패 (Unknown error):', error); } return undefined; } diff --git a/app/apis/postArticle.ts b/app/apis/postArticle.ts index 5c0a1285e..b269da8e2 100644 --- a/app/apis/postArticle.ts +++ b/app/apis/postArticle.ts @@ -1,4 +1,3 @@ -// postArticle.ts import { instance } from "./Axios"; export const uploadImage = async ( diff --git a/app/boards/[id]/page.tsx b/app/boards/[id]/page.tsx index 0eac85549..695820eda 100644 --- a/app/boards/[id]/page.tsx +++ b/app/boards/[id]/page.tsx @@ -1,12 +1,13 @@ -import BoardDetail from "@/components/BoardDetail/BoardDetail"; -import CommentInput from "@/components/BoardDetail/CommentInput"; -import CommentsList from "@/components/BoardDetail/CommentsList"; -import { getComments } from "@/app/apis/getComments"; -import { getArticleDetail, RootObject } from "@/app/apis/getArticleDetail"; -import styles from "@/app/boards/[id]/Page.module.css"; -import backIcon from "@/app/assets/images/ic_back.png"; -import Link from "next/link"; -import Image from "next/image"; +import Image from 'next/image'; +import Link from 'next/link'; + +import { getArticleDetail, RootObject } from '@/app/apis/getArticleDetail'; +import { getComments } from '@/app/apis/getComments'; +import backIcon from '@/app/assets/images/ic_back.png'; +import styles from '@/app/boards/[id]/Page.module.css'; +import BoardDetail from '@/components/BoardDetail/BoardDetail'; +import CommentInput from '@/components/BoardDetail/CommentInput'; +import CommentsList from '@/components/BoardDetail/CommentsList'; interface BoardDetailProps { params: { diff --git a/app/boards/page.tsx b/app/boards/page.tsx index f031544bf..6fce3d818 100644 --- a/app/boards/page.tsx +++ b/app/boards/page.tsx @@ -1,8 +1,9 @@ -import BestList from "@/components/Board/BestList"; -import styles from "@/app/boards/BoardPage.module.css"; -import SearchTitle from "@/components/Board/SearchTitle"; -import { List, RootObject, BASE_URL } from "@/app/apis/getArticle"; -import Link from "next/link"; +import Link from 'next/link'; + +import { BASE_URL, List, RootObject } from '@/app/apis/getArticle'; +import styles from '@/app/boards/BoardPage.module.css'; +import BestList from '@/components/Board/BestList'; +import SearchTitle from '@/components/Board/SearchTitle'; interface Props { searchParams?: { @@ -14,18 +15,18 @@ interface Props { } export default async function BoardPage({ searchParams }: Props) { - const page = parseInt(searchParams?.page || "1"); - const pageSize = parseInt(searchParams?.pageSize || "10"); - const orderBy = searchParams?.orderBy || "recent"; - const keyword = searchParams?.keyword || ""; + const page = parseInt(searchParams?.page || '1'); + const pageSize = parseInt(searchParams?.pageSize || '10'); + const orderBy = searchParams?.orderBy || 'recent'; + const keyword = searchParams?.keyword || ''; const [articlesRes, bestListRes] = await Promise.all([ fetch( `${BASE_URL}/articles?page=${page}&pageSize=${pageSize}&orderBy=${orderBy}&keyword=${keyword}`, - { cache: "no-store" } + { cache: 'no-store' }, ), fetch(`${BASE_URL}/articles?page=1&pageSize=3&orderBy=like`, { - cache: "no-store", + cache: 'no-store', }), ]); diff --git a/app/boards/post/page.tsx b/app/boards/post/page.tsx index 9fbc49923..b5733571b 100644 --- a/app/boards/post/page.tsx +++ b/app/boards/post/page.tsx @@ -1,9 +1,11 @@ -"use client"; -import styles from "./Page.module.css"; -import FileInput from "@/components/BoardPost/FileInput"; -import { useState } from "react"; -import { useRouter } from "next/navigation"; -import { BASE_URL } from "@/app/apis/getArticle"; +'use client'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; + +import { BASE_URL } from '@/app/apis/getArticle'; +import FileInput from '@/components/BoardPost/FileInput'; + +import styles from './Page.module.css'; type Values = { title: string; @@ -14,8 +16,8 @@ type Values = { export default function PostPage() { const router = useRouter(); const [values, setValues] = useState({ - title: "", - content: "", + title: '', + content: '', imgFile: null, }); @@ -28,10 +30,10 @@ export default function PostPage() { const handleSubmit = async () => { try { - const accessToken = localStorage.getItem("accessToken"); + const accessToken = localStorage.getItem('accessToken'); if (!accessToken) { - console.error("Access token not found"); + console.error('Access token not found'); return; } @@ -42,10 +44,10 @@ export default function PostPage() { if (imgFile) { const formData = new FormData(); - formData.append("image", imgFile); + formData.append('image', imgFile); const imageResponse = await fetch(`${BASE_URL}/images/upload`, { - method: "POST", + method: 'POST', headers: { Authorization: `Bearer ${accessToken}`, }, @@ -57,7 +59,7 @@ export default function PostPage() { imageUrl = imageData.url; } else { - console.error("Error uploading image:", imageResponse.statusText); + console.error('Error uploading image:', imageResponse.statusText); return; } } @@ -69,21 +71,21 @@ export default function PostPage() { }; const response = await fetch(`${BASE_URL}/articles`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', Authorization: `Bearer ${accessToken}`, }, body: JSON.stringify(requestBody), }); if (response.ok) { - router.push("/articles"); + router.push('/articles'); } else { - console.error("Error posting article:", response.statusText); + console.error('Error posting article:', response.statusText); } } catch (error) { - console.error("Error posting article:", error); + console.error('Error posting article:', error); } }; @@ -108,7 +110,7 @@ export default function PostPage() { className={styles.postTitleInput} placeholder="제목을 입력해주세요" value={values.title} - onChange={(e) => handleChange("title", e.target.value)} + onChange={(e) => handleChange('title', e.target.value)} />
@@ -117,7 +119,7 @@ export default function PostPage() { className={styles.postContentInput} placeholder="내용을 입력해주세요" value={values.content} - onChange={(e) => handleChange("content", e.target.value)} + onChange={(e) => handleChange('content', e.target.value)} />
diff --git a/app/hooks/useLike.tsx b/app/hooks/useLike.tsx index f94efd65e..b67f2253e 100644 --- a/app/hooks/useLike.tsx +++ b/app/hooks/useLike.tsx @@ -1,5 +1,6 @@ -import { useState } from "react"; -import { postLike, deleteLike } from "@/app/apis/postLike"; +import { useState } from 'react'; + +import { deleteLike, postLike } from '@/app/apis/postLike'; export default function useLike(articleId: number, initialLikeCount: number) { const [likeCount, setLikeCount] = useState(initialLikeCount); @@ -13,7 +14,7 @@ export default function useLike(articleId: number, initialLikeCount: number) { setLikeCount((prevCount) => prevCount - 1); setIsLiked(false); } catch (error) { - console.error("Failed to delete like:", error); + console.error('Failed to delete like:', error); } } else { // 좋아요 추가 diff --git a/app/hooks/useOutsideClick.ts b/app/hooks/useOutsideClick.ts index 256ba527b..ca967b50c 100644 --- a/app/hooks/useOutsideClick.ts +++ b/app/hooks/useOutsideClick.ts @@ -1,4 +1,4 @@ -import { useEffect, RefObject } from "react"; +import { RefObject, useEffect } from 'react'; const useOutsideClick = (ref: RefObject, callback: () => void) => { useEffect(() => { @@ -8,10 +8,10 @@ const useOutsideClick = (ref: RefObject, callback: () => void) => { } }; - document.addEventListener("mousedown", handleClick); + document.addEventListener('mousedown', handleClick); return () => { - document.removeEventListener("mousedown", handleClick); + document.removeEventListener('mousedown', handleClick); }; }, [ref, callback]); }; diff --git a/app/items/page.tsx b/app/items/page.tsx new file mode 100644 index 000000000..0f1345db6 --- /dev/null +++ b/app/items/page.tsx @@ -0,0 +1,23 @@ +import ProductContent from '@/components/items/ProductContent'; + +import { getProducts } from '../apis/getProducts'; +import styles from './pages.module.css'; + +async function ProductPage() { + const productsData = await getProducts({ page: 1, pageSize: 10 }); + + if (!productsData) { + return
데이터를 불러오는 데 실패했습니다.
; + } + + return ( +
+ +
+ ); +} + +export default ProductPage; diff --git a/app/items/pages.module.css b/app/items/pages.module.css new file mode 100644 index 000000000..89078b2e0 --- /dev/null +++ b/app/items/pages.module.css @@ -0,0 +1,9 @@ +.productContainer { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + flex-direction: column; + padding: 50px 140px; +} diff --git a/app/layout.tsx b/app/layout.tsx index 5b495d255..bfa0bd57b 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,16 +1,19 @@ -import type { Metadata } from "next"; -import { Inter } from "next/font/google"; -import "../styles/globals.css"; -import Header from "@/components/Header/Header"; +import '../styles/globals.css'; -const inter = Inter({ subsets: ["latin"] }); +import type { Metadata } from 'next'; +import { Inter } from 'next/font/google'; + +import Header from '@/components/Header/Header'; +import ReactQueryProvider from '@/components/QueryProvider'; + +const inter = Inter({ subsets: ['latin'] }); export const metadata: Metadata = { title: { - template: "%s", - default: "판다마켓", + template: '%s', + default: '판다마켓', }, - description: "Hello I am a description!", + description: 'Hello I am a description!', }; export default function RootLayout({ @@ -21,8 +24,10 @@ export default function RootLayout({ return ( -
- {children} + +
+ {children} + ); diff --git a/app/login/LoginForm.tsx b/app/login/LoginForm.tsx index b2594df06..1b45929b7 100644 --- a/app/login/LoginForm.tsx +++ b/app/login/LoginForm.tsx @@ -1,14 +1,15 @@ "use client"; +import { yupResolver } from "@hookform/resolvers/yup"; +import Image from "next/image"; +import { useRouter } from "next/navigation"; import React from "react"; -import styles from "./LoginForm.module.css"; +import { useForm } from "react-hook-form"; + import GoogleLogo from "../../app/assets/images/google.png"; import KakaoLogo from "../../app/assets/images/kakao.png"; -import { loginSchema } from "../utils/validation/Schema"; import loginUser from "../apis/loginUser"; -import { useForm } from "react-hook-form"; -import { yupResolver } from "@hookform/resolvers/yup"; -import { useRouter } from "next/navigation"; -import Image from "next/image"; +import { loginSchema } from "../utils/validation/Schema"; +import styles from "./LoginForm.module.css"; interface FormValues { email: string; diff --git a/app/login/page.tsx b/app/login/page.tsx index 67351f3d4..6d9abbd5f 100644 --- a/app/login/page.tsx +++ b/app/login/page.tsx @@ -1,10 +1,10 @@ "use client"; -import React from "react"; +import Image from "next/image"; import { useRouter } from "next/navigation"; -import LoginForm from "./LoginForm"; + import PandaLogo from "../assets/images/logo.png"; +import LoginForm from "./LoginForm"; import styles from "./LoginPage.module.css"; -import Image from "next/image"; const LoginPage = () => { const router = useRouter(); diff --git a/app/signup/page.tsx b/app/signup/page.tsx index 67b652efb..815627200 100644 --- a/app/signup/page.tsx +++ b/app/signup/page.tsx @@ -1,21 +1,22 @@ -"use client"; +'use client'; +import Image from 'next/image'; +import { useRouter } from 'next/navigation'; +import React from 'react'; -import React from "react"; -import { useRouter } from "next/navigation"; -import SignUpForm from "@/app/signup/signUpForm"; -import PandaLogo from "@/app/assets/images/logo.png"; -import styles from "./Page.module.css"; -import Image from "next/image"; +import PandaLogo from '@/app/assets/images/logo.png'; +import SignUpForm from '@/app/signup/signUpForm'; + +import styles from './Page.module.css'; const SignUpPage = () => { const router = useRouter(); const handleLogoClick = () => { - router.push("/"); + router.push('/'); }; const handleLoginClick = () => { - router.push("/login"); + router.push('/login'); }; return ( @@ -32,7 +33,7 @@ const SignUpPage = () => {
- 이미 회원이신가요?{" "} + 이미 회원이신가요?{' '} 로그인 diff --git a/app/signup/signUpForm.tsx b/app/signup/signUpForm.tsx index 83bb03735..aeaea4582 100644 --- a/app/signup/signUpForm.tsx +++ b/app/signup/signUpForm.tsx @@ -1,12 +1,14 @@ -import React from "react"; -import styles from "./SignupForm.module.css"; -import { signUpSchema } from "@/app/utils/validation/Schema"; -import { signUpUser } from "@/app/apis/SignUpUser"; -import { useForm } from "react-hook-form"; -import { yupResolver } from "@hookform/resolvers/yup"; -import GoogleLogo from "../../app/assets/images/google.png"; -import KakaoLogo from "../../app/assets/images/kakao.png"; -import Image from "next/image"; +import { yupResolver } from '@hookform/resolvers/yup'; +import Image from 'next/image'; +import React from 'react'; +import { useForm } from 'react-hook-form'; + +import { signUpUser } from '@/app/apis/SignUpUser'; +import { signUpSchema } from '@/app/utils/validation/Schema'; + +import GoogleLogo from '../../app/assets/images/google.png'; +import KakaoLogo from '../../app/assets/images/kakao.png'; +import styles from './SignupForm.module.css'; interface FormValues { email: string; @@ -23,17 +25,17 @@ const SignUpForm = () => { formState: { errors, isValid }, } = useForm({ resolver, - mode: "onChange", + mode: 'onChange', }); const handleSignUp = handleSubmit(async (data: FormValues) => { try { const response = await signUpUser(data); if (response) { - console.log("회원가입 성공"); + console.log('회원가입 성공'); } } catch (error) { - console.error("회원가입 실패:", error); + console.error('회원가입 실패:', error); } }); @@ -47,8 +49,8 @@ const SignUpForm = () => {
{errors.email?.message}
@@ -59,8 +61,8 @@ const SignUpForm = () => {
{errors.nickname?.message}
@@ -71,8 +73,8 @@ const SignUpForm = () => {
{errors.password?.message}
@@ -83,9 +85,9 @@ const SignUpForm = () => {
@@ -96,7 +98,7 @@ const SignUpForm = () => { type="submit" disabled={!isValid} className={`${styles.signUpButton} ${ - !isValid ? styles.disabled : "" + !isValid ? styles.disabled : '' }`} > 회원가입 diff --git a/app/utils/validation/Schema.ts b/app/utils/validation/Schema.ts index 82b9693ad..51f4aa34b 100644 --- a/app/utils/validation/Schema.ts +++ b/app/utils/validation/Schema.ts @@ -1,5 +1,6 @@ -import * as yup from "yup"; -import Messages from "./Message"; +import * as yup from 'yup'; + +import Messages from './Message'; export const loginSchema = yup.object().shape({ email: yup @@ -24,6 +25,6 @@ export const signUpSchema = yup.object().shape({ passwordConfirmation: yup .string() .required(Messages.CONFIRM_PASSWORD_REQUIRED) - .oneOf([yup.ref("password")], Messages.PASSWORDS_MUST_MATCH), + .oneOf([yup.ref('password')], Messages.PASSWORDS_MUST_MATCH), nickname: yup.string().required(Messages.NICKNAME_REQUIRED), }); diff --git a/components/Board/BestList.tsx b/components/Board/BestList.tsx index 43018d4cd..62e565010 100644 --- a/components/Board/BestList.tsx +++ b/components/Board/BestList.tsx @@ -1,10 +1,12 @@ -import BestListCss from "./BestList.module.css"; -import { List } from "@/app/apis/getArticle"; -import { formatDate } from "@/app/utils/formateDate"; -import Image from "next/image"; -import bestBadge from "@/app/assets/images/img_badgez.svg"; -import heartIcon from "@/app/assets/images/ic_heart.svg"; -import Link from "next/link"; +import Image from 'next/image'; +import Link from 'next/link'; + +import { List } from '@/app/apis/getArticle'; +import heartIcon from '@/app/assets/images/ic_heart.svg'; +import bestBadge from '@/app/assets/images/img_badgez.svg'; +import { formatDate } from '@/app/utils/formateDate'; + +import BestListCss from './BestList.module.css'; interface Props { bestList: List[]; diff --git a/components/Board/SearchTitle.tsx b/components/Board/SearchTitle.tsx index deec040a7..c5acb0bf8 100644 --- a/components/Board/SearchTitle.tsx +++ b/components/Board/SearchTitle.tsx @@ -1,13 +1,15 @@ -"use client"; -import styles from "./SearchTitle.module.css"; -import Image from "next/image"; -import { List } from "@/app/apis/getArticle"; -import { formatDate } from "@/app/utils/formateDate"; -import heartIcon from "@/app/assets/images/ic_heart.svg"; -import profileIcon from "@/app/assets/images/ic_profile.png"; -import searchIcon from "@/app/assets/images/ic_search.png"; -import { useRouter } from "next/navigation"; -import { useState, useEffect } from "react"; +'use client'; +import Image from 'next/image'; +import { useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; + +import { List } from '@/app/apis/getArticle'; +import heartIcon from '@/app/assets/images/ic_heart.svg'; +import profileIcon from '@/app/assets/images/ic_profile.png'; +import searchIcon from '@/app/assets/images/ic_search.png'; +import { formatDate } from '@/app/utils/formateDate'; + +import styles from './SearchTitle.module.css'; interface Props { articles: List[]; @@ -38,10 +40,10 @@ export default function SearchTitle({ useEffect(() => { const debounceTimer = setTimeout(() => { const params = new URLSearchParams(); - params.append("page", String(page)); - params.append("pageSize", String(pageSize)); - params.append("keyword", searchKeyword); - params.append("orderBy", sortBy); + params.append('page', String(page)); + params.append('pageSize', String(pageSize)); + params.append('keyword', searchKeyword); + params.append('orderBy', sortBy); const newUrl = `/boards?${params.toString()}`; router.push(newUrl); @@ -61,10 +63,10 @@ export default function SearchTitle({ setIsDropdownOpen(false); const params = new URLSearchParams(); - params.append("page", String(page)); - params.append("pageSize", String(pageSize)); - params.append("keyword", searchKeyword); - params.append("orderBy", newSortBy); + params.append('page', String(page)); + params.append('pageSize', String(pageSize)); + params.append('keyword', searchKeyword); + params.append('orderBy', newSortBy); const newUrl = `/boards?${params.toString()}`; router.push(newUrl); @@ -72,10 +74,10 @@ export default function SearchTitle({ const handleArticleClick = (articleId: number) => { const params = new URLSearchParams(); - params.append("page", String(page)); - params.append("pageSize", String(pageSize)); - params.append("keyword", searchKeyword); - params.append("orderBy", sortBy); + params.append('page', String(page)); + params.append('pageSize', String(pageSize)); + params.append('keyword', searchKeyword); + params.append('orderBy', sortBy); const newUrl = `/boards/${articleId}?${params.toString()}`; router.push(newUrl); @@ -88,15 +90,15 @@ export default function SearchTitle({ const pageNumbers = Array.from( { length: endPage - startPage + 1 }, - (_, index) => startPage + index + (_, index) => startPage + index, ); const handlePageChange = (newPage: number) => { const params = new URLSearchParams(); - params.append("page", String(newPage)); - params.append("pageSize", String(pageSize)); - params.append("keyword", searchKeyword); - params.append("orderBy", sortBy); + params.append('page', String(newPage)); + params.append('pageSize', String(pageSize)); + params.append('keyword', searchKeyword); + params.append('orderBy', sortBy); const newUrl = `/boards?${params.toString()}`; router.push(newUrl, { scroll: false }); @@ -117,13 +119,13 @@ export default function SearchTitle({ className={styles.sortDropdownToggle} onClick={() => setIsDropdownOpen(!isDropdownOpen)} > - {sortBy === "recent" ? "최신순" : "좋아요순"} + {sortBy === 'recent' ? '최신순' : '좋아요순'}
{isDropdownOpen && (
    -
  • handleSortChange("recent")}>최신순
  • -
  • handleSortChange("like")}>좋아요순
  • +
  • handleSortChange('recent')}>최신순
  • +
  • handleSortChange('like')}>좋아요순
)} @@ -181,18 +183,18 @@ export default function SearchTitle({
{pageNumbers.map((pageNumber) => (
diff --git a/components/BoardDetail/BoardDetail.tsx b/components/BoardDetail/BoardDetail.tsx index 0271c6374..f472dfb46 100644 --- a/components/BoardDetail/BoardDetail.tsx +++ b/components/BoardDetail/BoardDetail.tsx @@ -1,13 +1,15 @@ -"use client"; -import styles from "@/components/BoardDetail/BoardDetail.module.css"; -import { RootObject } from "@/app/apis/getArticleDetail"; -import { formatDate } from "@/app/utils/formateDate"; -import Image from "next/image"; -import profileImg from "@/app/assets/images/ic_profile.png"; -import LikeButton from "./LikeButton"; -import DropdownMenu from "@/components/DropDown"; -import { useState } from "react"; -import ImageModal from "@/components/ImageModal"; +'use client'; +import Image from 'next/image'; +import { useState } from 'react'; + +import { RootObject } from '@/app/apis/getArticleDetail'; +import profileImg from '@/app/assets/images/ic_profile.png'; +import { formatDate } from '@/app/utils/formateDate'; +import styles from '@/components/BoardDetail/BoardDetail.module.css'; +import DropdownMenu from '@/components/DropDown'; +import ImageModal from '@/components/ImageModal'; + +import LikeButton from './LikeButton'; type Props = { article: RootObject; @@ -61,7 +63,7 @@ export default function BoardDetail({ article }: Props) { ); diff --git a/components/BoardDetail/CommentInput.tsx b/components/BoardDetail/CommentInput.tsx index 8d939dc12..381dd9ff6 100644 --- a/components/BoardDetail/CommentInput.tsx +++ b/components/BoardDetail/CommentInput.tsx @@ -1,20 +1,21 @@ -"use client"; -import { useState, useEffect } from "react"; -import styles from "@/components/BoardDetail/CommentInput.module.css"; -import { useRouter } from "next/navigation"; -import { postComment } from "@/app/apis/postComments"; +'use client'; +import { useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; + +import { postComment } from '@/app/apis/postComments'; +import styles from '@/components/BoardDetail/CommentInput.module.css'; interface CommentInputProps { articleId: number; } export default function CommentInput({ articleId }: CommentInputProps) { - const [comment, setComment] = useState(""); - const [token, setToken] = useState(""); + const [comment, setComment] = useState(''); + const [token, setToken] = useState(''); const router = useRouter(); useEffect(() => { - const storedToken = localStorage.getItem("accessToken"); + const storedToken = localStorage.getItem('accessToken'); if (storedToken) { setToken(storedToken); } @@ -25,10 +26,10 @@ export default function CommentInput({ articleId }: CommentInputProps) { try { await postComment(articleId, comment, token); - setComment(""); + setComment(''); router.refresh(); } catch (error) { - console.error("댓글 작성 중 오류 발생:", error); + console.error('댓글 작성 중 오류 발생:', error); } }; diff --git a/components/BoardDetail/CommentsList.tsx b/components/BoardDetail/CommentsList.tsx index a8fd3e030..1ab6078a9 100644 --- a/components/BoardDetail/CommentsList.tsx +++ b/components/BoardDetail/CommentsList.tsx @@ -1,10 +1,11 @@ -import styles from "@/components/BoardDetail/CommentList.module.css"; -import emptyCommentImg from "@/app/assets/images/Img_reply_empty.png"; -import { formatTimes } from "@/app/utils/fotmatTime"; -import DropdownMenu from "@/components/DropDown"; -import ProfileImg from "@/app/assets/images/ic_profile.png"; -import Image from "next/image"; -import { List } from "@/app/apis/getComments"; +import Image from 'next/image'; + +import { List } from '@/app/apis/getComments'; +import ProfileImg from '@/app/assets/images/ic_profile.png'; +import emptyCommentImg from '@/app/assets/images/Img_reply_empty.png'; +import { formatTimes } from '@/app/utils/fotmatTime'; +import styles from '@/components/BoardDetail/CommentList.module.css'; +import DropdownMenu from '@/components/DropDown'; interface Props { articleId: number; comments: List[]; diff --git a/components/BoardDetail/LikeButton.tsx b/components/BoardDetail/LikeButton.tsx index 62802ecbd..0692290d6 100644 --- a/components/BoardDetail/LikeButton.tsx +++ b/components/BoardDetail/LikeButton.tsx @@ -1,10 +1,11 @@ // LikeButton.tsx -"use client"; -import Image from "next/image"; -import styles from "@/components/BoardDetail/BoardDetail.module.css"; -import heartImg from "@/app/assets/images/ic_heart.svg"; -import heartfill from "@/app/assets/images/fillheart.png"; -import useLike from "@/app/hooks/useLike"; +'use client'; +import Image from 'next/image'; + +import heartfill from '@/app/assets/images/fillheart.png'; +import heartImg from '@/app/assets/images/ic_heart.svg'; +import useLike from '@/app/hooks/useLike'; +import styles from '@/components/BoardDetail/BoardDetail.module.css'; type Props = { articleId: number; @@ -14,7 +15,7 @@ type Props = { export default function LikeButton({ articleId, initialLikeCount }: Props) { const { likeCount, isLiked, handleLikeClick } = useLike( articleId, - initialLikeCount + initialLikeCount, ); return ( diff --git a/components/BoardPost/FileInput.tsx b/components/BoardPost/FileInput.tsx index 15a074ae5..bc37d9bc5 100644 --- a/components/BoardPost/FileInput.tsx +++ b/components/BoardPost/FileInput.tsx @@ -1,7 +1,8 @@ -"use client"; -import React, { useState, useRef, useEffect } from "react"; -import styles from "./FileInput.module.css"; -import Image from "next/image"; +'use client'; +import Image from 'next/image'; +import React, { useEffect, useRef, useState } from 'react'; + +import styles from './FileInput.module.css'; interface FileInputProps { name: string; @@ -10,7 +11,7 @@ interface FileInputProps { } const FileInput: React.FC = ({ name, value, onChange }) => { - const [previewImg, setPreviewImg] = useState(""); + const [previewImg, setPreviewImg] = useState(''); const inputRef = useRef(null); const handleChange = (e: React.ChangeEvent) => { @@ -21,14 +22,14 @@ const FileInput: React.FC = ({ name, value, onChange }) => { const handleRemoveFile = () => { const inputNode = inputRef.current; if (!inputNode) return; - inputNode.value = ""; + inputNode.value = ''; onChange(name, null); - setPreviewImg(""); + setPreviewImg(''); }; useEffect(() => { if (!value) { - setPreviewImg(""); + setPreviewImg(''); return; } const nextPreview = URL.createObjectURL(value); @@ -47,7 +48,7 @@ const FileInput: React.FC = ({ name, value, onChange }) => { onChange={handleChange} id="file-input" ref={inputRef} - style={{ display: "none" }} + style={{ display: 'none' }} />