diff --git a/src/App.tsx b/src/App.tsx index 06da3e8..9691eaf 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,10 +1,10 @@ -import {RouterProvider} from 'react-router-dom' +import { RouterProvider } from 'react-router-dom' import root from './common/router/root' function App() { return ( - + ) } diff --git a/src/common/apis/AxiosApi.tsx b/src/common/apis/AxiosApi.tsx index e1334f5..33245ab 100644 --- a/src/common/apis/AxiosApi.tsx +++ b/src/common/apis/AxiosApi.tsx @@ -1,6 +1,6 @@ import axios from "axios"; import store from "../../store.tsx"; -import {login} from "../slices/loginSlice.tsx"; +import { login } from "../slices/loginSlice.tsx"; const axiosApi = axios.create({ baseURL: `${import.meta.env.VITE_SERVER_URL}/api`, @@ -27,7 +27,7 @@ axiosApi.interceptors.response.use( originalRequest._retry = true; try { - const refreshResponse = await axiosApi.get('/member/refresh', {withCredentials: true}); + const refreshResponse = await axiosApi.get('/member/refresh', { withCredentials: true }); if (refreshResponse.data.status === 200) { store.dispatch(login({ diff --git a/src/common/apis/blog.tsx b/src/common/apis/blog.tsx index 6cc051d..a096818 100644 --- a/src/common/apis/blog.tsx +++ b/src/common/apis/blog.tsx @@ -1,6 +1,6 @@ -import {FolderDeleteRequest, FolderRequest, PostListMemberRequest} from "../types/blog.tsx"; +import { FolderDeleteRequest, FolderRequest, PostListMemberRequest } from "../types/blog.tsx"; import axiosApi from "./AxiosApi.tsx"; -import {postListMemberRequestToParameter} from "../util/url.tsx"; +import { postListMemberRequestToParameter } from "../util/url.tsx"; export const getMemberPosts = (postListMemberRequest: PostListMemberRequest) => axiosApi.get(`/post/member${postListMemberRequestToParameter(postListMemberRequest)}`); @@ -15,4 +15,4 @@ export const saveAndUpdateFolder = (folderRequestList: FolderRequest[]) => axiosApi.put("/folders", folderRequestList); export const deleteFolder = (folderDeleteRequestList: FolderDeleteRequest[]) => - axiosApi.delete("/folders", {data: folderDeleteRequestList}); \ No newline at end of file + axiosApi.delete("/folders", { data: folderDeleteRequestList }); \ No newline at end of file diff --git a/src/common/apis/comment.tsx b/src/common/apis/comment.tsx index 99c4394..49e1dd2 100644 --- a/src/common/apis/comment.tsx +++ b/src/common/apis/comment.tsx @@ -1,6 +1,6 @@ import axiosApi from "./AxiosApi.tsx"; -import {CommentListRequest, CommentRequest, CommentUpdateRequest} from "../types/comment.tsx"; -import {commentListRequestToParameter} from "../util/url.tsx"; +import { CommentListRequest, CommentRequest, CommentUpdateRequest } from "../types/comment.tsx"; +import { commentListRequestToParameter } from "../util/url.tsx"; export const getComments = async (commentListRequest: CommentListRequest) => await axiosApi.get(`/comment${commentListRequestToParameter(commentListRequest)}`); diff --git a/src/common/apis/member.tsx b/src/common/apis/member.tsx index 9277926..bfae393 100644 --- a/src/common/apis/member.tsx +++ b/src/common/apis/member.tsx @@ -1,6 +1,6 @@ import axiosApi from "./AxiosApi.tsx"; -import {MemberProfileSearchRequest} from "../types/member.tsx"; -import {memberProfileSearchRequestToParameter} from "../util/url.tsx"; +import { MemberProfileSearchRequest } from "../types/member.tsx"; +import { memberProfileSearchRequestToParameter } from "../util/url.tsx"; export const sendMail = async (email: string) => await axiosApi.post("/verify", { @@ -24,12 +24,12 @@ export const loginApi = async (email: string, password: string) => await axiosApi.post("/member/login", { email: email, password: password - }, {withCredentials: true}); + }, { withCredentials: true }); export const logoutApi = async (email: string) => await axiosApi.post("/member/logout", { email: email - }, {withCredentials: true}); + }, { withCredentials: true }); export const handleKakaoLogin = () => location.href = `${import.meta.env.VITE_SERVER_URL}/oauth2/authorization/kakao`; diff --git a/src/common/apis/post.tsx b/src/common/apis/post.tsx index 83bc9c7..74e2444 100644 --- a/src/common/apis/post.tsx +++ b/src/common/apis/post.tsx @@ -5,7 +5,7 @@ import { PostListTagRequest, PostRequest, PostSearchRequest, - PostUpdateRequest + PostUpdateRequest, } from "../types/post.tsx"; import { postListRequestToParameter, @@ -35,4 +35,12 @@ export const getMemberTagPosts = async (postListTagRequest: PostListTagRequest) await axiosApi.get(`/post/member/tag${postListTagRequestToParameter(postListTagRequest)}`); export const searchPost = async (postSearchRequest: PostSearchRequest) => - await axiosApi.get(`/post/search${postListSearchRequestToParameter(postSearchRequest)}`); \ No newline at end of file + await axiosApi.get(`/post/search${postListSearchRequestToParameter(postSearchRequest)}`); + +export const incrementPostViewCount = async (id: string) => + await axiosApi.post(`/post/view/increment`, { + postId: id + }); + +export const getPostViewCount = async (id: string) => + await axiosApi.get(`/post/view/${id}`); \ No newline at end of file diff --git a/src/common/router/blogRouter.tsx b/src/common/router/blogRouter.tsx index dd6f259..3b8b354 100644 --- a/src/common/router/blogRouter.tsx +++ b/src/common/router/blogRouter.tsx @@ -1,16 +1,16 @@ -import {Suspense} from "react"; -import {Blog, BlogTag, Loading} from "./page.tsx"; +import { Suspense } from "react"; +import { Blog, BlogTag, Loading } from "./page.tsx"; const blogRouter = () => { return [ { path: ':username', - element: + element: }, { path: ':username/tag', - element: + element: }, ]; } diff --git a/src/common/router/page.tsx b/src/common/router/page.tsx index 6b29228..888942a 100644 --- a/src/common/router/page.tsx +++ b/src/common/router/page.tsx @@ -1,16 +1,16 @@ -import {lazy} from "react"; +import { lazy } from "react"; export const Loading =
; diff --git a/src/common/router/postRouter.tsx b/src/common/router/postRouter.tsx index f27b41a..a6df455 100644 --- a/src/common/router/postRouter.tsx +++ b/src/common/router/postRouter.tsx @@ -1,16 +1,16 @@ -import {Suspense} from "react"; -import {Loading, Post, Write} from "./page.tsx"; +import { Suspense } from "react"; +import { Loading, Post, Write } from "./page.tsx"; const postRouter = () => { return [ { path: 'edit/:id', - element: + element: }, { path: ':id', - element: + element: }, ]; } diff --git a/src/common/router/root.tsx b/src/common/router/root.tsx index 498baa8..c9105c7 100644 --- a/src/common/router/root.tsx +++ b/src/common/router/root.tsx @@ -1,6 +1,6 @@ -import {createBrowserRouter} from "react-router-dom"; -import {Suspense} from "react"; -import {Loading, Login, Main, Search, Setting, Write} from "./page.tsx"; +import { createBrowserRouter } from "react-router-dom"; +import { Suspense } from "react"; +import { Loading, Login, Main, Search, Setting, Write } from "./page.tsx"; import postRouter from "./postRouter.tsx"; import blogRouter from "./blogRouter.tsx"; import signupRouter from "./signupRouter.tsx"; @@ -8,23 +8,23 @@ import signupRouter from "./signupRouter.tsx"; const root = createBrowserRouter([ { path: '', - element:
+ element:
}, { path: '/login', - element: + element: }, { path: '/setting/:section', - element: + element: }, { path: '/search', - element: + element: }, { path: '/write', - element: + element: }, { path: '/signup', diff --git a/src/common/router/signupRouter.tsx b/src/common/router/signupRouter.tsx index f8c46b6..8a29da7 100644 --- a/src/common/router/signupRouter.tsx +++ b/src/common/router/signupRouter.tsx @@ -1,24 +1,24 @@ -import {Code, Email, Loading, Platform, Signup} from "./page.tsx"; -import {Suspense} from "react"; +import { Code, Email, Loading, Platform, Signup } from "./page.tsx"; +import { Suspense } from "react"; const signupRouter = () => { return [ { path: 'platform', - element: + element: }, { path: 'email', - element: + element: }, { path: 'code', - element: + element: }, { path: '', - element: + element: }, ]; } diff --git a/src/common/slices/loginSlice.tsx b/src/common/slices/loginSlice.tsx index 6a81f8c..585eab9 100644 --- a/src/common/slices/loginSlice.tsx +++ b/src/common/slices/loginSlice.tsx @@ -1,4 +1,4 @@ -import {createSlice} from "@reduxjs/toolkit"; +import { createSlice } from "@reduxjs/toolkit"; const initialState = { isLogin: false, @@ -51,6 +51,6 @@ const loginSlice = createSlice({ } }); -export const {login, logout, setUsername, setProfile, setReloadedFalse} = loginSlice.actions; +export const { login, logout, setUsername, setProfile, setReloadedFalse } = loginSlice.actions; export default loginSlice.reducer; \ No newline at end of file diff --git a/src/common/types/comment.tsx b/src/common/types/comment.tsx index 50b3732..6489f80 100644 --- a/src/common/types/comment.tsx +++ b/src/common/types/comment.tsx @@ -1,4 +1,4 @@ -import {PageResponse} from "./common.tsx"; +import { PageResponse } from "./common.tsx"; export interface CommentType { id: string, diff --git a/src/common/types/post.tsx b/src/common/types/post.tsx index 3398dc3..36c87a2 100644 --- a/src/common/types/post.tsx +++ b/src/common/types/post.tsx @@ -1,4 +1,4 @@ -import {PageResponse} from "./common.tsx"; +import { PageResponse } from "./common.tsx"; export interface PostRequest { title: string, @@ -52,6 +52,7 @@ export interface PostResponse { username: string; folder?: PostFolderResponse; tags: TagResponse[]; + viewCount: number; createdAt: Date; } diff --git a/src/common/util/infiniteScroll.tsx b/src/common/util/infiniteScroll.tsx index d47e1ce..4dc4ea9 100644 --- a/src/common/util/infiniteScroll.tsx +++ b/src/common/util/infiniteScroll.tsx @@ -1,5 +1,5 @@ -import {useEffect, useState, useMemo, useRef, MutableRefObject} from 'react'; -import {PostResponse} from "../types/post.tsx"; +import { useEffect, useState, useMemo, useRef, MutableRefObject } from 'react'; +import { PostResponse } from "../types/post.tsx"; export interface InfiniteScrollProps { root?: Element | null; @@ -11,13 +11,13 @@ export interface InfiniteScrollProps { } const useInfiniteScroll = ({ - root = null, - target, - threshold = 1, - rootMargin = '0px', - targetArray, - endPoint = 1 - }: InfiniteScrollProps) => { + root = null, + target, + threshold = 1, + rootMargin = '0px', + targetArray, + endPoint = 1 +}: InfiniteScrollProps) => { const [page, setPage] = useState(0); const currentChild = useRef(null); diff --git a/src/common/util/sort.tsx b/src/common/util/sort.tsx index d3253f0..658de8d 100644 --- a/src/common/util/sort.tsx +++ b/src/common/util/sort.tsx @@ -1,4 +1,4 @@ -import {TagResponse} from "../types/post.tsx"; +import { TagResponse } from "../types/post.tsx"; export const sortByName = (names: string[]) => { names.sort((a: string, b: string) => { diff --git a/src/common/util/url.tsx b/src/common/util/url.tsx index 0078556..778614c 100644 --- a/src/common/util/url.tsx +++ b/src/common/util/url.tsx @@ -1,7 +1,7 @@ -import {PostListRequest, PostListTagRequest, PostSearchRequest} from "../types/post.tsx"; -import {CommentListRequest} from "../types/comment.tsx"; -import {PostListMemberRequest} from "../types/blog.tsx"; -import {MemberProfileSearchRequest} from "../types/member.tsx"; +import { PostListRequest, PostListTagRequest, PostSearchRequest } from "../types/post.tsx"; +import { CommentListRequest } from "../types/comment.tsx"; +import { PostListMemberRequest } from "../types/blog.tsx"; +import { MemberProfileSearchRequest } from "../types/member.tsx"; export const postListRequestToParameter = (postListRequest: PostListRequest) => { const sorts = postListRequest.sorts.map(sort => `sorts=${sort}`).join("&"); diff --git a/src/components/blog/BlogSearchBar.tsx b/src/components/blog/BlogSearchBar.tsx index ffadb33..e5ff335 100644 --- a/src/components/blog/BlogSearchBar.tsx +++ b/src/components/blog/BlogSearchBar.tsx @@ -1,4 +1,4 @@ -function BlogSearchBar({value, setValue}: { +function BlogSearchBar({ value, setValue }: { value: string, setValue: (value: string) => void, }) { diff --git a/src/components/blog/BlogSideBar.tsx b/src/components/blog/BlogSideBar.tsx index e847b7f..daf1de0 100644 --- a/src/components/blog/BlogSideBar.tsx +++ b/src/components/blog/BlogSideBar.tsx @@ -1,13 +1,13 @@ -import {FolderType} from "../../common/types/blog.tsx"; -import {useSelector} from "react-redux"; -import {RootState} from "../../store.tsx"; -import {OutlineLink} from "../common/OutlineButton.tsx"; +import { FolderType } from "../../common/types/blog.tsx"; +import { useSelector } from "react-redux"; +import { RootState } from "../../store.tsx"; +import { OutlineLink } from "../common/OutlineButton.tsx"; import BlogTagCard from "./BlogTagCard.tsx"; -import {getFolderTitle} from "../../common/util/string.tsx"; +import { getFolderTitle } from "../../common/util/string.tsx"; import ProfileImageCircle from "../common/ProfileImageCircle.tsx"; -import {TagResponse} from "../../common/types/post.tsx"; +import { TagResponse } from "../../common/types/post.tsx"; -function BlogSideBar({folders, tags, username, profileUrl, selectedFolder, setSelectedFolder, bgColor, side}: { +function BlogSideBar({ folders, tags, username, profileUrl, selectedFolder, setSelectedFolder, bgColor, side }: { folders: FolderType[], tags: TagResponse[], username: string | undefined, @@ -23,15 +23,15 @@ function BlogSideBar({folders, tags, username, profileUrl, selectedFolder, setSe return (
- +
{username}
{username === loginState.username && (
- + + addStyle={"!border-neutral-500 !text-neutral-500 hover:bg-neutral-500 hover:!text-white"} />
)}
@@ -40,7 +40,7 @@ function BlogSideBar({folders, tags, username, profileUrl, selectedFolder, setSe + setSelectedFolder={setSelectedFolder} />
태그
@@ -49,7 +49,7 @@ function BlogSideBar({folders, tags, username, profileUrl, selectedFolder, setSe + username={username || ""} /> ))} {tags.length === 0 &&
@@ -61,7 +61,7 @@ function BlogSideBar({folders, tags, username, profileUrl, selectedFolder, setSe ); } -function BlogFolderList({depth = 0, folders, selectedFolder, setSelectedFolder}: { +function BlogFolderList({ depth = 0, folders, selectedFolder, setSelectedFolder }: { depth?: number, folders: FolderType[], selectedFolder: FolderType | null, @@ -84,7 +84,7 @@ function BlogFolderList({depth = 0, folders, selectedFolder, setSelectedFolder}:
{folders.length > 1 && folders.map(folder =>
- {depth === 0 &&
} + {depth === 0 &&
} - {folder.subFolders.length > 0 && depth === 0 &&
} + {folder.subFolders.length > 0 && depth === 0 &&
} + setSelectedFolder={setSelectedFolder} />
)} {depth === 0 && folders.length <= 1 &&
diff --git a/src/components/blog/BlogTagCard.tsx b/src/components/blog/BlogTagCard.tsx index 99f187e..5a499f5 100644 --- a/src/components/blog/BlogTagCard.tsx +++ b/src/components/blog/BlogTagCard.tsx @@ -1,8 +1,8 @@ -import {TagResponse} from "../../common/types/post.tsx"; -import {TextButton} from "../common/TextButton.tsx"; -import {useNavigate} from "react-router-dom"; +import { TagResponse } from "../../common/types/post.tsx"; +import { TextButton } from "../common/TextButton.tsx"; +import { useNavigate } from "react-router-dom"; -function BlogTagCard({tag, username}: { +function BlogTagCard({ tag, username }: { tag: TagResponse, username: string, }) { @@ -12,8 +12,8 @@ function BlogTagCard({tag, username}: { return ( navigate(`/blog/${username}/tag`, {state: {tagId: tag.id}})} - addStyle={"!px-1 !py-0 hover:text-lime-700"}/> + onClick={() => navigate(`/blog/${username}/tag`, { state: { tagId: tag.id } })} + addStyle={"!px-1 !py-0 hover:text-lime-700"} /> ); } diff --git a/src/components/common/FillButton.tsx b/src/components/common/FillButton.tsx index 603ee07..94ffd1a 100644 --- a/src/components/common/FillButton.tsx +++ b/src/components/common/FillButton.tsx @@ -1,8 +1,8 @@ -import {Link} from "react-router-dom"; +import { Link } from "react-router-dom"; const className = " bg-lime-500 hover:brightness-105 text-white text-sm font-semibold py-2 px-4 rounded hover:cursor-pointer"; -export function FillButton({text, onClick, addStyle, disabled}: { +export function FillButton({ text, onClick, addStyle, disabled }: { text: string, onClick: () => void, addStyle?: string, @@ -18,7 +18,7 @@ export function FillButton({text, onClick, addStyle, disabled}: { ); } -export function FillLink({text, to, addStyle}: { text: string, to: string, addStyle?: string }) { +export function FillLink({ text, to, addStyle }: { text: string, to: string, addStyle?: string }) { return ( {text} @@ -26,7 +26,7 @@ export function FillLink({text, to, addStyle}: { text: string, to: string, addSt ); } -export function LoadMoreButton({onClick, addStyle, disabled}: { +export function LoadMoreButton({ onClick, addStyle, disabled }: { onClick: () => void, addStyle?: string, disabled?: boolean @@ -36,6 +36,6 @@ export function LoadMoreButton({onClick, addStyle, disabled}: { text={"더 불러오기"} onClick={onClick} addStyle={`${addStyle} "!bg-gray-400 hover:brightness-105"`} - disabled={disabled}/> + disabled={disabled} /> ); } \ No newline at end of file diff --git a/src/components/common/Footer.tsx b/src/components/common/Footer.tsx index 1d3b6a8..b56b7bb 100644 --- a/src/components/common/Footer.tsx +++ b/src/components/common/Footer.tsx @@ -1,12 +1,12 @@ -import {FaGithub} from "react-icons/fa"; -import {Link} from "react-router-dom"; +import { FaGithub } from "react-icons/fa"; +import { Link } from "react-router-dom"; function Footer() { return (
- + className="text-gray-400"> +
); diff --git a/src/components/common/Header.tsx b/src/components/common/Header.tsx index 2ee0acd..0ca984c 100644 --- a/src/components/common/Header.tsx +++ b/src/components/common/Header.tsx @@ -1,12 +1,12 @@ -import {Link, useNavigate} from "react-router-dom"; -import {useDispatch, useSelector} from "react-redux"; -import {RootState} from "../../store.tsx"; -import {useEffect, useRef, useState} from "react"; -import {TextLink} from "./TextButton.tsx"; -import {MdOutlineSearch} from "react-icons/md"; +import { Link, useNavigate } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "../../store.tsx"; +import { useEffect, useRef, useState } from "react"; +import { TextLink } from "./TextButton.tsx"; +import { MdOutlineSearch } from "react-icons/md"; import IconButton from "./IconButton.tsx"; -import {getProfile, logoutApi} from "../../common/apis/member.tsx"; -import {logout, setProfile, setReloadedFalse} from "../../common/slices/loginSlice.tsx"; +import { getProfile, logoutApi } from "../../common/apis/member.tsx"; +import { logout, setProfile, setReloadedFalse } from "../../common/slices/loginSlice.tsx"; import ProfileImageCircle from "./ProfileImageCircle.tsx"; function Header() { @@ -76,7 +76,7 @@ function Header() {
logo + className="size-8 mb-1" />
DIGLOG
@@ -84,13 +84,13 @@ function Header() {
} - onClick={() => navigate("/search?word=&option=ALL&sort=createdAt&isDescending=true&tab=post")}/> + className="size-5" />} + onClick={() => navigate("/search?word=&option=ALL&sort=createdAt&isDescending=true&tab=post")} /> {loginState.isLogin ?
- +
@@ -99,15 +99,15 @@ function Header() {
+ className="w-full block px-4 py-2 text-gray-700 hover:bg-gray-100"> 게시글 작성 + className="w-full block px-4 py-2 text-gray-700 hover:bg-gray-100"> 내 블로그 + className="w-full block px-4 py-2 text-gray-700 hover:bg-gray-100"> 설정
@@ -122,8 +122,8 @@ function Header() {
:
- -
}
diff --git a/src/components/common/IconButton.tsx b/src/components/common/IconButton.tsx index 0995c47..ac246df 100644 --- a/src/components/common/IconButton.tsx +++ b/src/components/common/IconButton.tsx @@ -1,6 +1,6 @@ -import {ReactNode} from 'react'; +import { ReactNode } from 'react'; -function IconButton({icon, onClick, addStyle}: { icon: ReactNode; onClick: () => void, addStyle?: string }) { +function IconButton({ icon, onClick, addStyle }: { icon: ReactNode; onClick: () => void, addStyle?: string }) { return (
{pageList.map(currentPage => )}
); diff --git a/src/components/common/ProfileImageCircle.tsx b/src/components/common/ProfileImageCircle.tsx index 08c3fae..1584820 100644 --- a/src/components/common/ProfileImageCircle.tsx +++ b/src/components/common/ProfileImageCircle.tsx @@ -1,6 +1,6 @@ -import {MdOutlinePerson} from "react-icons/md"; +import { MdOutlinePerson } from "react-icons/md"; -function ProfileImageCircle({profileUrl, size, onClick, addStyle}: { +function ProfileImageCircle({ profileUrl, size, onClick, addStyle }: { profileUrl: string | null, size?: string, onClick?: () => void, @@ -22,12 +22,12 @@ function ProfileImageCircle({profileUrl, size, onClick, addStyle}: { if (profileUrl) { return user_image; + onClick={onClick} + src={profileUrl} alt="user_image" />; } return ; + onClick={onClick} />; } export default ProfileImageCircle; \ No newline at end of file diff --git a/src/components/common/TextButton.tsx b/src/components/common/TextButton.tsx index ac444fb..2f0fb88 100644 --- a/src/components/common/TextButton.tsx +++ b/src/components/common/TextButton.tsx @@ -1,8 +1,8 @@ -import {Link} from "react-router-dom"; +import { Link } from "react-router-dom"; const className = " flex justify-center items-center bg-transparent text-sm py-2 px-4 hover:cursor-pointer"; -export function TextButton({text, onClick, addStyle}: { text: string, onClick?: () => void, addStyle?: string }) { +export function TextButton({ text, onClick, addStyle }: { text: string, onClick?: () => void, addStyle?: string }) { return (
}
); diff --git a/src/components/folder/FolderSelectBox.tsx b/src/components/folder/FolderSelectBox.tsx index cdad268..a7b72c7 100644 --- a/src/components/folder/FolderSelectBox.tsx +++ b/src/components/folder/FolderSelectBox.tsx @@ -1,9 +1,9 @@ -import {FolderType} from "../../common/types/blog.tsx"; -import {MdOutlineArrowDropDown} from "react-icons/md"; -import {useEffect, useRef, useState} from "react"; -import {getFolderTitle} from "../../common/util/string.tsx"; +import { FolderType } from "../../common/types/blog.tsx"; +import { MdOutlineArrowDropDown } from "react-icons/md"; +import { useEffect, useRef, useState } from "react"; +import { getFolderTitle } from "../../common/util/string.tsx"; -function FolderSelectBox({folders, depth = 0, selectedFolder, targetFolder, setTargetFolder, center}: { +function FolderSelectBox({ folders, depth = 0, selectedFolder, targetFolder, setTargetFolder, center }: { folders: FolderType[], depth?: number, selectedFolder?: FolderType | null, @@ -32,12 +32,12 @@ function FolderSelectBox({folders, depth = 0, selectedFolder, targetFolder, setT return (
+ className={`w-full relative flex ${center ? "justify-center" : "justify-start"} text-gray-700 items-center my-2 text-sm font-normal`}>
@@ -48,14 +48,14 @@ function FolderSelectBox({folders, depth = 0, selectedFolder, targetFolder, setT depth={depth} selectedFolder={selectedFolder} setTargetFolder={setTargetFolder} - setFolderOpen={setFolderOpen}/> + setFolderOpen={setFolderOpen} /> )}
); } -function FolderSelectCard({folder, depth, selectedFolder, setTargetFolder, setFolderOpen}: { +function FolderSelectCard({ folder, depth, selectedFolder, setTargetFolder, setFolderOpen }: { folder: FolderType, depth: number, selectedFolder?: FolderType | null, @@ -72,7 +72,7 @@ function FolderSelectCard({folder, depth, selectedFolder, setTargetFolder, setFo setFolderOpen(false); }}>
-
+
{getFolderTitle(folder.title, depth)} {folder.id !== "empty" &&

({folder.postCount})

}
@@ -85,7 +85,7 @@ function FolderSelectCard({folder, depth, selectedFolder, setTargetFolder, setFo selectedFolder={selectedFolder} depth={depth + 1} setTargetFolder={setTargetFolder} - setFolderOpen={setFolderOpen}/>))} + setFolderOpen={setFolderOpen} />))}
) : <>; } diff --git a/src/components/member/LoginButton.tsx b/src/components/member/LoginButton.tsx index 640398f..80691bc 100644 --- a/src/components/member/LoginButton.tsx +++ b/src/components/member/LoginButton.tsx @@ -1,6 +1,6 @@ -import {ReactNode} from "react"; +import { ReactNode } from "react"; -function LoginButton({text, onClick, bgColor, disable, icon}: { +function LoginButton({ text, onClick, bgColor, disable, icon }: { text: string, onClick: () => void, bgColor: string, @@ -9,7 +9,7 @@ function LoginButton({text, onClick, bgColor, disable, icon}: { }) { return ( diff --git a/src/components/member/LoginTextField.tsx b/src/components/member/LoginTextField.tsx index f3dc216..99596c8 100644 --- a/src/components/member/LoginTextField.tsx +++ b/src/components/member/LoginTextField.tsx @@ -1,7 +1,7 @@ import * as React from "react"; -import {Ref} from "react"; +import { Ref } from "react"; -function LoginTextField({label, type, placeholder, value, setValue, customRef, error, isError, onKeyDown}: { +function LoginTextField({ label, type, placeholder, value, setValue, customRef, error, isError, onKeyDown }: { label?: string, type: string, placeholder: string, @@ -18,17 +18,17 @@ function LoginTextField({label, type, placeholder, value, setValue, customRef, e {label} setValue(event.target.value))} - onKeyDown={onKeyDown} - ref={customRef} - autoComplete={"on"}/> + placeholder={placeholder} required + className="bg-gray-50 border border-gray-300 text-gray-900 text-md rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" + value={value} + onChange={(event => setValue(event.target.value))} + onKeyDown={onKeyDown} + ref={customRef} + autoComplete={"on"} /> {(error) && ( isError ?

{error}

- :
+ :
)}
); diff --git a/src/components/post/CommentCard.tsx b/src/components/post/CommentCard.tsx index c52bf8c..9e01c6c 100644 --- a/src/components/post/CommentCard.tsx +++ b/src/components/post/CommentCard.tsx @@ -1,16 +1,16 @@ -import {relativeDateToKorean} from "../../common/util/date.tsx"; -import {MdOutlineAddComment, MdOutlineComment, MdOutlinePerson} from "react-icons/md"; -import {ChangeEvent, useState} from "react"; +import { relativeDateToKorean } from "../../common/util/date.tsx"; +import { MdOutlineAddComment, MdOutlineComment, MdOutlinePerson } from "react-icons/md"; +import { ChangeEvent, useState } from "react"; import CommentTextField from "./CommentTextField.tsx"; -import {CommentType} from "../../common/types/comment.tsx"; -import {LoadMoreButton} from "../common/FillButton.tsx"; -import {useSelector} from "react-redux"; -import {RootState} from "../../store.tsx"; -import {TextButton} from "../common/TextButton.tsx"; -import {deleteComment} from "../../common/apis/comment.tsx"; -import {useNavigate} from "react-router-dom"; +import { CommentType } from "../../common/types/comment.tsx"; +import { LoadMoreButton } from "../common/FillButton.tsx"; +import { useSelector } from "react-redux"; +import { RootState } from "../../store.tsx"; +import { TextButton } from "../common/TextButton.tsx"; +import { deleteComment } from "../../common/apis/comment.tsx"; +import { useNavigate } from "react-router-dom"; -function CommentCard({comment, handleLoadMoreSubComment, handleCommentSubmit, pageSize, depth = 0}: { +function CommentCard({ comment, handleLoadMoreSubComment, handleCommentSubmit, pageSize, depth = 0 }: { comment: CommentType, handleLoadMoreSubComment: (page: number, parentId: string) => void, handleCommentSubmit: (commentId: string | null, content: string, taggedUsername: string | null, originalComment: CommentType | null) => void, @@ -64,14 +64,14 @@ function CommentCard({comment, handleLoadMoreSubComment, handleCommentSubmit, pa return (
- {depth !== 0 &&
} + {depth !== 0 &&
}
{comment.member.profileUrl ? user_image - : } + src={comment.member.profileUrl} alt="user_image" /> + : }

{comment.member.username}

@@ -83,8 +83,8 @@ function CommentCard({comment, handleLoadMoreSubComment, handleCommentSubmit, pa {!showEditTextField && comment.taggedUsername && - @{comment.taggedUsername} - } + @{comment.taggedUsername} + } {showEditTextField ? + handleShowTextField={handleShowEdit} /> :
{comment.content}
}
@@ -103,22 +103,22 @@ function CommentCard({comment, handleLoadMoreSubComment, handleCommentSubmit, pa handleLoadMoreSubComment(page, comment.id); setPage(page + 1); }}> - + 답글 ({comment.replyCount}) } -
+
{loginState.isLogin && !showEditTextField &&
{comment.member.username === loginState.username &&
- - + +
}
@@ -133,7 +133,7 @@ function CommentCard({comment, handleLoadMoreSubComment, handleCommentSubmit, pa handleSubmit={handleCommentSubmit} commentId={comment.id} taggedUsername={taggedUsername} - handleShowTextField={handleShowTextField}/>} + handleShowTextField={handleShowTextField} />}
{comment.subComments &&
@@ -145,7 +145,7 @@ function CommentCard({comment, handleLoadMoreSubComment, handleCommentSubmit, pa handleLoadMoreSubComment={handleLoadMoreSubComment} handleCommentSubmit={handleCommentSubmit} pageSize={pageSize} - depth={depth + 1}/> + depth={depth + 1} /> : null)} {page !== 0 && (page) * 10 < comment.replyCount && { handleLoadMoreSubComment(page, comment.id); setPage(page + 1); - }}/>} + }} />}
}
diff --git a/src/components/post/CommentTextField.tsx b/src/components/post/CommentTextField.tsx index d270af0..ab77352 100644 --- a/src/components/post/CommentTextField.tsx +++ b/src/components/post/CommentTextField.tsx @@ -1,7 +1,7 @@ -import {ChangeEventHandler, useState} from 'react'; -import {FillButton} from "../common/FillButton.tsx"; -import {TextButton} from "../common/TextButton.tsx"; -import {CommentType} from "../../common/types/comment.tsx"; +import { ChangeEventHandler, useState } from 'react'; +import { FillButton } from "../common/FillButton.tsx"; +import { TextButton } from "../common/TextButton.tsx"; +import { CommentType } from "../../common/types/comment.tsx"; interface CommentTextFieldProps { value: string, @@ -15,7 +15,7 @@ interface CommentTextFieldProps { function CommentTextField(props: CommentTextFieldProps) { - const {value, onChange, commentId, taggedUsername, originalComment, handleSubmit, handleShowTextField} = props; + const { value, onChange, commentId, taggedUsername, originalComment, handleSubmit, handleShowTextField } = props; const [username, setUsername] = useState(taggedUsername || null); @@ -26,21 +26,21 @@ function CommentTextField(props: CommentTextFieldProps) { onChange={onChange} className="p-2 border border-gray-400" rows={5} - minLength={5}/> + minLength={5} />
{username && setUsername(null)} - addStyle="w-fit !bg-gray-400 text-xs"/>} -
+ onClick={() => setUsername(null)} + addStyle="w-fit !bg-gray-400 text-xs" />} +
{(commentId || originalComment) && { if (handleShowTextField) { handleShowTextField(); } - }}/>} + }} />} handleSubmit(commentId || null, value, username || null, originalComment || null)}/> + onClick={() => handleSubmit(commentId || null, value, username || null, originalComment || null)} />
diff --git a/src/components/post/PostCard.tsx b/src/components/post/PostCard.tsx index ac117fa..ebdc049 100644 --- a/src/components/post/PostCard.tsx +++ b/src/components/post/PostCard.tsx @@ -1,11 +1,11 @@ -import {PostResponse} from "../../common/types/post.tsx"; -import {getImgSrc, removeHtmlTags} from "../../common/util/html.tsx"; +import { PostResponse } from "../../common/types/post.tsx"; +import { getImgSrc, removeHtmlTags } from "../../common/util/html.tsx"; import DOMPurify from "dompurify"; -import {MdImage} from "react-icons/md"; -import {relativeDateToKorean} from "../../common/util/date.tsx"; -import {Link} from "react-router-dom"; +import { MdImage } from "react-icons/md"; +import { relativeDateToKorean } from "../../common/util/date.tsx"; +import { Link } from "react-router-dom"; -function PostCard({post}: { post: PostResponse }) { +function PostCard({ post }: { post: PostResponse }) { const safeContent = DOMPurify.sanitize(post.content); const url = getImgSrc(safeContent); @@ -16,16 +16,16 @@ function PostCard({post}: { post: PostResponse }) { {(url) ? post_image + src={url} alt="post_image" /> :
- +
}
+ className="font-semibold text-lime-700 hover:text-lime-400"> {post.username}
diff --git a/src/components/post/TagCard.tsx b/src/components/post/TagCard.tsx index f0c2c60..af46502 100644 --- a/src/components/post/TagCard.tsx +++ b/src/components/post/TagCard.tsx @@ -1,6 +1,6 @@ -import {TagResponse} from "../../common/types/post.tsx"; +import { TagResponse } from "../../common/types/post.tsx"; -function TagCard({tag, onClick}: { tag: TagResponse, onClick: () => void }) { +function TagCard({ tag, onClick }: { tag: TagResponse, onClick: () => void }) { return ( ); } diff --git a/src/components/setting/SettingSideBar.tsx b/src/components/setting/SettingSideBar.tsx index 11f685a..6af3d88 100644 --- a/src/components/setting/SettingSideBar.tsx +++ b/src/components/setting/SettingSideBar.tsx @@ -3,15 +3,15 @@ interface TabType { title: string; } -function SettingSideBar({setSelectedSection, side}: { +function SettingSideBar({ setSelectedSection, side }: { setSelectedSection: (section: string) => void, side: boolean, }) { const tabList: TabType[] = [ - {section: "profile", title: "프로필"}, - {section: "folder", title: "폴더"}, - {section: "post", title: "게시글"}, + { section: "profile", title: "프로필" }, + { section: "folder", title: "폴더" }, + { section: "post", title: "게시글" }, ]; const handleSelectedTab = (tabSection: string) => { diff --git a/src/index.css b/src/index.css index 40f7146..08045e2 100644 --- a/src/index.css +++ b/src/index.css @@ -1,111 +1,111 @@ @import "tailwindcss"; @layer base { - h1 { - font-size: 2em; - font-weight: bold; - margin-top: 0.67em; - margin-bottom: 0.67em; - } - h2 { - font-size: 1.5em; - font-weight: bold; - margin-top: 0.83em; - margin-bottom: 0.83em; - } - h3 { - font-size: 1.17em; - font-weight: bold; - margin-top: 1em; - margin-bottom: 1em; - } - h4 { - font-size: 1em; - font-weight: bold; - margin-top: 1.33em; - margin-bottom: 1.33em; - } - blockquote { - margin: 0 32px; - padding-left: 1rem; - border-left: 2px solid #e5e7eb; - } - ul { - list-style: disc; - margin-left: 1.5em; - padding-left: 1.5em; - } - ol { - list-style: decimal; - margin-left: 1.5em; - padding-left: 1.5em; - } + h1 { + font-size: 2em; + font-weight: bold; + margin-top: 0.67em; + margin-bottom: 0.67em; + } + h2 { + font-size: 1.5em; + font-weight: bold; + margin-top: 0.83em; + margin-bottom: 0.83em; + } + h3 { + font-size: 1.17em; + font-weight: bold; + margin-top: 1em; + margin-bottom: 1em; + } + h4 { + font-size: 1em; + font-weight: bold; + margin-top: 1.33em; + margin-bottom: 1.33em; + } + blockquote { + margin: 0 32px; + padding-left: 1rem; + border-left: 2px solid #e5e7eb; + } + ul { + list-style: disc; + margin-left: 1.5em; + padding-left: 1.5em; + } + ol { + list-style: decimal; + margin-left: 1.5em; + padding-left: 1.5em; + } } @theme { - --font-*: initial; - --default-font-family: 'SCDream'; - --font-jalnan: 'Jalnan2'; + --font-*: initial; + --default-font-family: "SCDream"; + --font-jalnan: "Jalnan2"; } @font-face { - font-family: 'Jalnan2'; - src: url('./common/assets/fonts/Jalnan2.otf'); - font-weight: 400; - font-style: normal; + font-family: "Jalnan2"; + src: url("./common/assets/fonts/Jalnan2.otf"); + font-weight: 400; + font-style: normal; } @font-face { - font-family: 'SCDream'; - src: url('./common/assets/fonts/s-core/SCDream1.otf'); - font-weight: 100; - font-style: normal; + font-family: "SCDream"; + src: url("./common/assets/fonts/s-core/SCDream1.otf"); + font-weight: 100; + font-style: normal; } @font-face { - font-family: 'SCDream'; - src: url('./common/assets/fonts/s-core/SCDream2.otf'); - font-weight: 200; - font-style: normal; + font-family: "SCDream"; + src: url("./common/assets/fonts/s-core/SCDream2.otf"); + font-weight: 200; + font-style: normal; } @font-face { - font-family: 'SCDream'; - src: url('./common/assets/fonts/s-core/SCDream3.otf'); - font-weight: 300; - font-style: normal; + font-family: "SCDream"; + src: url("./common/assets/fonts/s-core/SCDream3.otf"); + font-weight: 300; + font-style: normal; } @font-face { - font-family: 'SCDream'; - src: url('./common/assets/fonts/s-core/SCDream4.otf'); - font-weight: 400; - font-style: normal; + font-family: "SCDream"; + src: url("./common/assets/fonts/s-core/SCDream4.otf"); + font-weight: 400; + font-style: normal; } @font-face { - font-family: 'SCDream'; - src: url('./common/assets/fonts/s-core/SCDream5.otf'); - font-weight: 500; - font-style: normal; + font-family: "SCDream"; + src: url("./common/assets/fonts/s-core/SCDream5.otf"); + font-weight: 500; + font-style: normal; } @font-face { - font-family: 'SCDream'; - src: url('./common/assets/fonts/s-core/SCDream6.otf'); - font-weight: 600; - font-style: normal; + font-family: "SCDream"; + src: url("./common/assets/fonts/s-core/SCDream6.otf"); + font-weight: 600; + font-style: normal; } @font-face { - font-family: 'SCDream'; - src: url('./common/assets/fonts/s-core/SCDream7.otf'); - font-weight: 700; - font-style: normal; + font-family: "SCDream"; + src: url("./common/assets/fonts/s-core/SCDream7.otf"); + font-weight: 700; + font-style: normal; } @font-face { - font-family: 'SCDream'; - src: url('./common/assets/fonts/s-core/SCDream8.otf'); - font-weight: 800; - font-style: normal; + font-family: "SCDream"; + src: url("./common/assets/fonts/s-core/SCDream8.otf"); + font-weight: 800; + font-style: normal; } @font-face { - font-family: 'SCDream'; - src: url('./common/assets/fonts/s-core/SCDream9.otf'); - font-weight: 900; - font-style: normal; -} \ No newline at end of file + font-family: "SCDream"; + src: url("./common/assets/fonts/s-core/SCDream9.otf"); + font-weight: 900; + font-style: normal; +} diff --git a/src/layout/BasicLayout.tsx b/src/layout/BasicLayout.tsx index 1803c7b..e622965 100644 --- a/src/layout/BasicLayout.tsx +++ b/src/layout/BasicLayout.tsx @@ -1,16 +1,16 @@ -import {ReactNode} from "react"; +import { ReactNode } from "react"; import Header from "../components/common/Header.tsx"; import Footer from "../components/common/Footer.tsx"; -function BasicLayout({children, center}: { children: ReactNode, center?: boolean }) { +function BasicLayout({ children, center }: { children: ReactNode, center?: boolean }) { return (
-
+
{children}
-
+
); } diff --git a/src/layout/LoadingLayout.tsx b/src/layout/LoadingLayout.tsx index a716d8c..8a4b5b1 100644 --- a/src/layout/LoadingLayout.tsx +++ b/src/layout/LoadingLayout.tsx @@ -1,4 +1,4 @@ -function LoadingLayout({loading}: { loading: boolean }) { +function LoadingLayout({ loading }: { loading: boolean }) { return ( loading && @@ -6,14 +6,14 @@ function LoadingLayout({loading}: { loading: boolean }) { className="fixed inset-0 flex items-center justify-center bg-gray-300 opacity-50 z-1000 dark:bg-gray-100 dark:bg-opacity-50">
Loading...
diff --git a/src/layout/ModalLayout.tsx b/src/layout/ModalLayout.tsx index 3efe563..5a55413 100644 --- a/src/layout/ModalLayout.tsx +++ b/src/layout/ModalLayout.tsx @@ -1,13 +1,13 @@ -import {ReactNode, Ref} from "react"; +import { ReactNode, Ref } from "react"; -function ModalLayout({children, customRef, addStyle}: { +function ModalLayout({ children, customRef, addStyle }: { children: ReactNode, customRef?: Ref, addStyle?: string, }) { return (
-
+
{children}
diff --git a/src/main.tsx b/src/main.tsx index 9b9b905..4b2e26b 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,11 +1,11 @@ -import {createRoot} from 'react-dom/client' +import { createRoot } from 'react-dom/client' import './index.css' import App from './App.tsx' -import {Provider} from "react-redux"; +import { Provider } from "react-redux"; import store from "./store.tsx"; createRoot(document.getElementById('root')!).render( - + , ) diff --git a/src/pages/MainPage.tsx b/src/pages/MainPage.tsx index ae3ba64..bdcbefc 100644 --- a/src/pages/MainPage.tsx +++ b/src/pages/MainPage.tsx @@ -1,15 +1,15 @@ import BasicLayout from "../layout/BasicLayout.tsx"; import PostCard from "../components/post/PostCard.tsx"; -import {useEffect, useRef, useState} from "react"; -import {getPosts} from "../common/apis/post.tsx"; -import {PostResponse} from "../common/types/post.tsx"; +import { useEffect, useRef, useState } from "react"; +import { getPosts } from "../common/apis/post.tsx"; +import { PostResponse } from "../common/types/post.tsx"; import useInfiniteScroll from "../common/util/infiniteScroll.tsx"; function MainPage() { const pageRef = useRef(null); const [posts, setPosts] = useState([]); - const {page} = useInfiniteScroll({ + const { page } = useInfiniteScroll({ target: pageRef, targetArray: posts, threshold: 0.5, @@ -37,11 +37,11 @@ function MainPage() { 최근 게시글
+ className="w-full grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-8"> {posts.map((post) => ( + post={post} /> ))}
diff --git a/src/pages/blog/BlogPage.tsx b/src/pages/blog/BlogPage.tsx index c7910aa..ee3acae 100644 --- a/src/pages/blog/BlogPage.tsx +++ b/src/pages/blog/BlogPage.tsx @@ -1,22 +1,22 @@ import BasicLayout from "../../layout/BasicLayout.tsx"; -import {useParams, useSearchParams} from "react-router-dom"; +import { useParams, useSearchParams } from "react-router-dom"; import PostCard from "../../components/post/PostCard.tsx"; -import {useEffect, useRef, useState} from "react"; -import {MdMenu, MdOutlineExitToApp} from "react-icons/md"; +import { useEffect, useRef, useState } from "react"; +import { MdMenu, MdOutlineExitToApp } from "react-icons/md"; import PaginationButton from "../../components/common/PaginationButton.tsx"; -import {FolderType, toFolderTypeList} from "../../common/types/blog.tsx"; +import { FolderType, toFolderTypeList } from "../../common/types/blog.tsx"; import BlogSideBar from "../../components/blog/BlogSideBar.tsx"; import IconButton from "../../components/common/IconButton.tsx"; -import {PageResponse} from "../../common/types/common.tsx"; -import {getMemberFolders, getMemberPosts, getMemberTags} from "../../common/apis/blog.tsx"; -import {PostResponse, TagResponse} from "../../common/types/post.tsx"; -import {MemberProfileResponse} from "../../common/types/member.tsx"; -import {getProfileByUsername} from "../../common/apis/member.tsx"; -import {TextLink} from "../../components/common/TextButton.tsx"; +import { PageResponse } from "../../common/types/common.tsx"; +import { getMemberFolders, getMemberPosts, getMemberTags } from "../../common/apis/blog.tsx"; +import { PostResponse, TagResponse } from "../../common/types/post.tsx"; +import { MemberProfileResponse } from "../../common/types/member.tsx"; +import { getProfileByUsername } from "../../common/apis/member.tsx"; +import { TextLink } from "../../components/common/TextButton.tsx"; function BlogPage() { - const {username} = useParams(); + const { username } = useParams(); const [folderParam, setFolderParam] = useSearchParams(); const [page, setPage] = useState(0); @@ -27,7 +27,7 @@ function BlogPage() { totalPages: 0 }); const [posts, setPosts] = useState([]); - const [member, setMember] = useState({username: username || "", profileUrl: null}); + const [member, setMember] = useState({ username: username || "", profileUrl: null }); const [folders, setFolders] = useState([]); const [tags, setTags] = useState([]); @@ -46,13 +46,13 @@ function BlogPage() { }; const handlePage = (page: number) => { - setFolderParam({...folderParam, "page": page.toString()}); + setFolderParam({ ...folderParam, "page": page.toString() }); setPage(page); } const handleSelectedFolder = (folder: FolderType) => { setSelectedFolder(folder); - setFolderParam({"folder": folder.id, "page": page.toString()}); + setFolderParam({ "folder": folder.id, "page": page.toString() }); setPage(0); } @@ -178,12 +178,12 @@ function BlogPage() { className={`${(isOpen) ? "opacity-50 backdrop-blur-sm z-10 overflow-y-hidden" : "z-10"} w-full flex flex-col`}>
+ to={`/blog/${username}`} + addStyle="!text-xl !font-jalnan" /> } + icon={} onClick={handleMenuOpen} - addStyle="lg:hidden"/> + addStyle="lg:hidden" />
( + post={post} /> ))} {posts.length === 0 &&
작성된 게시글이 없습니다.
} + pageInfo={pageInfo} setPage={handlePage} />
+ setSelectedFolder={handleSelectedFolder} />
+ side={true} />
); diff --git a/src/pages/blog/BlogTagPage.tsx b/src/pages/blog/BlogTagPage.tsx index e49610c..e4c0bf5 100644 --- a/src/pages/blog/BlogTagPage.tsx +++ b/src/pages/blog/BlogTagPage.tsx @@ -1,21 +1,21 @@ import BasicLayout from "../../layout/BasicLayout.tsx"; -import {useLocation, useNavigate, useParams} from "react-router-dom"; -import {useEffect, useState} from "react"; -import {PostResponse, TagResponse} from "../../common/types/post.tsx"; -import {PageResponse} from "../../common/types/common.tsx"; -import {getMemberTags} from "../../common/apis/blog.tsx"; +import { useLocation, useNavigate, useParams } from "react-router-dom"; +import { useEffect, useState } from "react"; +import { PostResponse, TagResponse } from "../../common/types/post.tsx"; +import { PageResponse } from "../../common/types/common.tsx"; +import { getMemberTags } from "../../common/apis/blog.tsx"; import TagCard from "../../components/post/TagCard.tsx"; import PostCard from "../../components/post/PostCard.tsx"; -import {getMemberTagPosts} from "../../common/apis/post.tsx"; +import { getMemberTagPosts } from "../../common/apis/post.tsx"; import PaginationButton from "../../components/common/PaginationButton.tsx"; -import {TextLink} from "../../components/common/TextButton.tsx"; +import { TextLink } from "../../components/common/TextButton.tsx"; function BlogTagPage() { - const {username} = useParams(); + const { username } = useParams(); const navigate = useNavigate(); - const {state} = useLocation(); - const {tagId} = state; + const { state } = useLocation(); + const { tagId } = state; const [tags, setTags] = useState([]); @@ -77,22 +77,23 @@ function BlogTagPage() {
+ to={`/blog/${username}`} + addStyle="flex justify-start !text-xl !font-jalnan" />
{tags.map(tag => handleSelectedTag(tag)}/>)} + onClick={() => handleSelectedTag(tag)} />)}

{selectedTag && "{selectedTag.name}"} {pageInfo.totalElements}개의 게시글

- {posts.map(post => )} + {posts.map(post => )}
- +
); diff --git a/src/pages/member/CodePage.tsx b/src/pages/member/CodePage.tsx index f64804a..afc910b 100644 --- a/src/pages/member/CodePage.tsx +++ b/src/pages/member/CodePage.tsx @@ -1,14 +1,14 @@ -import React, {useEffect, useRef, useState} from "react"; +import React, { useEffect, useRef, useState } from "react"; import BasicLayout from "../../layout/BasicLayout.tsx"; -import {useLocation, useNavigate} from "react-router-dom"; -import {formatTimer} from "../../common/util/date.tsx"; +import { useLocation, useNavigate } from "react-router-dom"; +import { formatTimer } from "../../common/util/date.tsx"; import LoadingLayout from "../../layout/LoadingLayout.tsx"; -import {checkCode} from "../../common/apis/member.tsx"; +import { checkCode } from "../../common/apis/member.tsx"; function CodePage() { - const {state} = useLocation(); - const {email} = state; + const { state } = useLocation(); + const { email } = state; const navigate = useNavigate(); const [loading, setLoading] = useState(false); @@ -69,7 +69,7 @@ function CodePage() { checkCode(email, code) .then(() => { - navigate("/signup", {state: {email: email, code: code}}); + navigate("/signup", { state: { email: email, code: code } }); }) .catch((error) => { alert(error.response.data.message); @@ -90,7 +90,7 @@ function CodePage() {

인증코드 6자리를 입력해주세요.

- {Array.from({length: 6}).map((_, index) => ( + {Array.from({ length: 6 }).map((_, index) => ( { @@ -114,7 +114,7 @@ function CodePage() { 유효시간 : {formatTimer(timer)}
- + ) ; diff --git a/src/pages/member/EmailPage.tsx b/src/pages/member/EmailPage.tsx index 1398c4d..a1a23d9 100644 --- a/src/pages/member/EmailPage.tsx +++ b/src/pages/member/EmailPage.tsx @@ -1,11 +1,11 @@ import BasicLayout from "../../layout/BasicLayout.tsx"; import LoginTextField from "../../components/member/LoginTextField.tsx"; -import {useEffect, useRef, useState} from "react"; +import { useEffect, useRef, useState } from "react"; import LoginButton from "../../components/member/LoginButton.tsx"; -import {useNavigate} from "react-router-dom"; +import { useNavigate } from "react-router-dom"; import * as React from "react"; -import {checkEmail} from "../../common/util/regex.tsx"; -import {sendMail} from "../../common/apis/member.tsx"; +import { checkEmail } from "../../common/util/regex.tsx"; +import { sendMail } from "../../common/apis/member.tsx"; import LoadingLayout from "../../layout/LoadingLayout.tsx"; function EmailPage() { @@ -34,7 +34,7 @@ function EmailPage() { sendMail(email) .then(() => { - navigate("/signup/code", {state: {email: email}}); + navigate("/signup/code", { state: { email: email } }); }) .catch((error) => alert(error.response.data.message)) .finally(() => setLoading(false)); @@ -55,10 +55,10 @@ function EmailPage() { value={email} setValue={(value) => setEmail(value)} customRef={emailRef} - onKeyDown={handleEmailEnter}/> - + onKeyDown={handleEmailEnter} /> +
- + ); } diff --git a/src/pages/member/LoginPage.tsx b/src/pages/member/LoginPage.tsx index af093d8..99200a0 100644 --- a/src/pages/member/LoginPage.tsx +++ b/src/pages/member/LoginPage.tsx @@ -1,15 +1,15 @@ import BasicLayout from "../../layout/BasicLayout.tsx"; -import {useNavigate} from "react-router-dom"; -import {useEffect, useRef, useState} from "react"; -import {useDispatch, useSelector} from "react-redux"; -import {getProfile, handleKakaoLogin, loginApi} from "../../common/apis/member.tsx"; -import {login, setProfile} from "../../common/slices/loginSlice.tsx"; +import { useNavigate } from "react-router-dom"; +import { useEffect, useRef, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { getProfile, handleKakaoLogin, loginApi } from "../../common/apis/member.tsx"; +import { login, setProfile } from "../../common/slices/loginSlice.tsx"; import LoginButton from "../../components/member/LoginButton.tsx"; import LoginTextField from "../../components/member/LoginTextField.tsx"; -import {checkEmail} from "../../common/util/regex.tsx"; +import { checkEmail } from "../../common/util/regex.tsx"; import * as React from "react"; -import {TextLink} from "../../components/common/TextButton.tsx"; -import {RootState} from "../../store.tsx"; +import { TextLink } from "../../components/common/TextButton.tsx"; +import { RootState } from "../../store.tsx"; function LoginPage() { @@ -21,7 +21,7 @@ function LoginPage() { const emailRef = useRef(null); const passwordRef = useRef(null); - const [loginInfo, setLoginInfo] = useState({email: "", password: ""}); + const [loginInfo, setLoginInfo] = useState({ email: "", password: "" }); const handleLogin = () => { loginApi(loginInfo.email, loginInfo.password) @@ -78,7 +78,7 @@ function LoginPage() { className="w-full max-w-[calc(420px)] flex flex-col justify-center items-center gap-y-4">
logo + className="size-16 mb-1" />
DIGLOG
@@ -89,23 +89,23 @@ function LoginPage() { type={"email"} placeholder={"이메일을 입력해주세요."} value={loginInfo.email} - setValue={(value) => setLoginInfo({...loginInfo, email: value})} + setValue={(value) => setLoginInfo({ ...loginInfo, email: value })} customRef={emailRef} - onKeyDown={handleEmailEnter}/> + onKeyDown={handleEmailEnter} /> setLoginInfo({...loginInfo, password: value})} + setValue={(value) => setLoginInfo({ ...loginInfo, password: value })} customRef={passwordRef} - onKeyDown={handlePasswordEnter}/> + onKeyDown={handlePasswordEnter} />
- + }/> - + icon={{"Kakao} /> +
diff --git a/src/pages/member/PlatformPage.tsx b/src/pages/member/PlatformPage.tsx index 77a588b..6fee2f6 100644 --- a/src/pages/member/PlatformPage.tsx +++ b/src/pages/member/PlatformPage.tsx @@ -1,7 +1,7 @@ import BasicLayout from "../../layout/BasicLayout.tsx"; import LoginButton from "../../components/member/LoginButton.tsx"; -import {handleKakaoLogin} from "../../common/apis/member.tsx"; -import {TextLink} from "../../components/common/TextButton.tsx"; +import { handleKakaoLogin } from "../../common/apis/member.tsx"; +import { TextLink } from "../../components/common/TextButton.tsx"; function PlatformPage() { @@ -9,8 +9,8 @@ function PlatformPage() {
}/> - + icon={{"Kakao} /> +
); diff --git a/src/pages/member/SignupPage.tsx b/src/pages/member/SignupPage.tsx index 4cb1883..96cf9d8 100644 --- a/src/pages/member/SignupPage.tsx +++ b/src/pages/member/SignupPage.tsx @@ -1,21 +1,21 @@ import BasicLayout from "../../layout/BasicLayout.tsx"; -import {useLocation, useNavigate} from "react-router-dom"; -import {useEffect, useRef, useState} from "react"; +import { useLocation, useNavigate } from "react-router-dom"; +import { useEffect, useRef, useState } from "react"; import LoginTextField from "../../components/member/LoginTextField.tsx"; -import {checkPassword} from "../../common/util/regex.tsx"; +import { checkPassword } from "../../common/util/regex.tsx"; import LoadingLayout from "../../layout/LoadingLayout.tsx"; import * as React from "react"; import LoginButton from "../../components/member/LoginButton.tsx"; -import {signup} from "../../common/apis/member.tsx"; +import { signup } from "../../common/apis/member.tsx"; function SignupPage() { const navigate = useNavigate(); - const {state} = useLocation(); - const {email, code} = state; + const { state } = useLocation(); + const { email, code } = state; const [loading, setLoading] = useState(false); - const [passwordInfo, setPasswordInfo] = useState({password: "", confirmPassword: ""}); + const [passwordInfo, setPasswordInfo] = useState({ password: "", confirmPassword: "" }); const passwordRef = useRef(null); const confirmPasswordRef = useRef(null); @@ -41,7 +41,7 @@ function SignupPage() { alert("비밀번호가 영문, 숫자 포함 8-16자리가 되도록 입력해주세요."); return; } - + if (passwordInfo.password !== passwordInfo.confirmPassword) { alert("비밀번호 확인이 일치하지 않습니다."); return; @@ -77,21 +77,21 @@ function SignupPage() { type={"password"} placeholder={"영문, 숫자 포함 8-16자"} value={passwordInfo.password} - setValue={(value) => setPasswordInfo({...passwordInfo, password: value})} + setValue={(value) => setPasswordInfo({ ...passwordInfo, password: value })} customRef={passwordRef} - onKeyDown={handlePasswordEnter}/> + onKeyDown={handlePasswordEnter} /> setPasswordInfo({...passwordInfo, confirmPassword: value})} + setValue={(value) => setPasswordInfo({ ...passwordInfo, confirmPassword: value })} customRef={confirmPasswordRef} - onKeyDown={handleConfirmPasswordEnter}/> + onKeyDown={handleConfirmPasswordEnter} /> - +
- + ); } diff --git a/src/pages/post/PostPage.tsx b/src/pages/post/PostPage.tsx index 0be43ab..736c00e 100644 --- a/src/pages/post/PostPage.tsx +++ b/src/pages/post/PostPage.tsx @@ -1,25 +1,26 @@ -import {Link, useNavigate, useParams} from "react-router-dom"; +import { Link, useNavigate, useParams } from "react-router-dom"; import BasicLayout from "../../layout/BasicLayout.tsx"; import DOMPurify from "dompurify"; -import {fullDateToKorean} from "../../common/util/date.tsx"; +import { fullDateToKorean } from "../../common/util/date.tsx"; import TagCard from "../../components/post/TagCard.tsx"; -import {getPost} from "../../common/apis/post.tsx"; -import {ChangeEvent, useEffect, useState} from "react"; -import {PostResponse} from "../../common/types/post.tsx"; -import {checkUUID} from "../../common/util/regex.tsx"; -import {sortTagByName} from "../../common/util/sort.tsx"; +import { getPost, getPostViewCount, incrementPostViewCount } from "../../common/apis/post.tsx"; +import { ChangeEvent, useEffect, useState } from "react"; +import { PostResponse } from "../../common/types/post.tsx"; +import { checkUUID } from "../../common/util/regex.tsx"; +import { sortTagByName } from "../../common/util/sort.tsx"; import CommentCard from "../../components/post/CommentCard.tsx"; import CommentTextField from "../../components/post/CommentTextField.tsx"; -import {FillLink, LoadMoreButton} from "../../components/common/FillButton.tsx"; -import {getComments, saveComment, updateComment} from "../../common/apis/comment.tsx"; -import {CommentResponse, CommentType} from "../../common/types/comment.tsx"; -import {useSelector} from "react-redux"; -import {RootState} from "../../store.tsx"; -import {PageResponse} from "../../common/types/common.tsx"; +import { FillLink, LoadMoreButton } from "../../components/common/FillButton.tsx"; +import { getComments, saveComment, updateComment } from "../../common/apis/comment.tsx"; +import { CommentResponse, CommentType } from "../../common/types/comment.tsx"; +import { useSelector } from "react-redux"; +import { RootState } from "../../store.tsx"; +import { PageResponse } from "../../common/types/common.tsx"; +import { FaEye } from "react-icons/fa6"; function PostPage() { - const {id} = useParams(); + const { id } = useParams(); const navigate = useNavigate(); const loginState = useSelector((state: RootState) => state.loginSlice); @@ -29,11 +30,12 @@ function PostPage() { content: "", username: "", tags: [], + viewCount: 0, createdAt: new Date(), }); const [commentInput, setCommentInput] = useState(""); const [comments, setComments] = useState([]); - const [pageInfo, setPageInfo] = useState({number: 0, size: 10, totalPages: 0, totalElements: 0}); + const [pageInfo, setPageInfo] = useState({ number: 0, size: 10, totalPages: 0, totalElements: 0 }); const [trigger, setTrigger] = useState(false); const handleCommentInput = (e: ChangeEvent) => { @@ -99,7 +101,7 @@ function PostPage() { } const handleLoadMoreComment = () => { - setPageInfo({...pageInfo, number: pageInfo.number + 1}); + setPageInfo({ ...pageInfo, number: pageInfo.number + 1 }); setTrigger(prev => !prev); } const handleLoadMoreSubComment = (page: number, parentId: string) => { @@ -131,15 +133,29 @@ function PostPage() { return; } + incrementPostViewCount(id); + + getPostViewCount(id) + .then((res) => { + setPost(prev => ({ ...prev, viewCount: res.data.viewCount })); + }); + getPost(id) .then((res) => { - setPost({ - ...res.data, + setPost(prev => ({ + ...prev, + id: res.data.id, + title: res.data.title, + content: res.data.content, + username: res.data.username, + folder: res.data.folder, tags: sortTagByName(res.data.tags), - }); + createdAt: new Date(res.data.createdAt), + })) setTrigger(prev => !prev); }) .catch((error) => alert(error.response.data.message)); + }, []); useEffect(() => { @@ -186,13 +202,13 @@ function PostPage() {
{` > `}
{post.folder.title} + className="text-xs">{post.folder.title}
}
+ className="text-md font-semibold text-lime-700 hover:text-lime-400"> {post.username}
@@ -206,11 +222,14 @@ function PostPage() { {post.tags.map(tag => { navigate(`/search?keyword=${tag.name}&option=TAG&sort=createdAt&isDescending=true&tab=post`) - }}/>)} + }} />)} +
+
+ {post.viewCount}
+ dangerouslySetInnerHTML={{ __html: safeContent }} />
@@ -218,13 +237,13 @@ function PostPage() { ? + handleSubmit={handleCommentSubmit} /> :