Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/common/apis/image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import axiosApi from "./AxiosApi.tsx";

export const uploadImage = async (blogInfo: any) => {
const formData = new FormData();
formData.append("file", blogInfo.blob());

return await axiosApi.post("/image", formData);
}
18 changes: 18 additions & 0 deletions src/common/apis/post.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import axiosApi from "./AxiosApi.tsx";
import {PostListRequest, PostRequest, PostUpdateRequest} from "../types/post.tsx";
import {postListRequestToParameter} from "../util/url.tsx";

export const createPost = async (postRequest: PostRequest) =>
await axiosApi.post("/post", postRequest);

export const updatePost = async (postUpdateRequest: PostUpdateRequest) =>
await axiosApi.patch(`/post`, postUpdateRequest);

export const deletePost = async (id: string) =>
await axiosApi.patch(`/post/delete/${id}`);

export const getPost = async (id: string) =>
await axiosApi.get(`/post/${id}`);

export const getPosts = async (postListRequest: PostListRequest) =>
await axiosApi.get(`/post${postListRequestToParameter(postListRequest)}`);
6 changes: 5 additions & 1 deletion src/common/router/postRouter.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import {Suspense} from "react";
import {Loading, Post} from "./page.tsx";
import {Loading, Post, Write} from "./page.tsx";

const postRouter = () => {

return [
{
path: 'edit/:id',
element: <Suspense fallback={Loading}><Write/></Suspense>
},
{
path: ':id',
element: <Suspense fallback={Loading}><Post/></Suspense>
Expand Down
22 changes: 22 additions & 0 deletions src/common/types/post.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
import {PageResponse} from "./common.tsx";

export interface PostRequest {
title: string,
content: string,
tagNames: string[],
urls: string[],
}

export interface PostUpdateRequest {
id: string,
title: string,
content: string,
tagNames: string[],
urls: string[],
}

export interface PostListRequest {
sorts: string[],
page: number,
size: number,
isDescending: boolean,
}

export interface PostListResponse {
content: PostResponse[];
page: PageResponse;
Expand Down
18 changes: 11 additions & 7 deletions src/common/util/html.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
export const removeImgTags = (content: string) => {
const doc = new DOMParser().parseFromString(content, 'text/html');
const imgTags = doc.querySelectorAll('img');
imgTags.forEach((img) => img.remove());
return doc.body.innerHTML;
}

export const getImgSrc = (content: string) => {
const doc = new DOMParser().parseFromString(content, 'text/html');
const imgTag = doc.querySelector('img');
return imgTag ? imgTag.src : null;
}

export const getImgUrls = (content: string) => {
const doc = new DOMParser().parseFromString(content, 'text/html');
const images = doc.querySelectorAll('img');
return Array.from(images).map(img => img.src);
}

export const removeHtmlTags = (content: string) => {
const regex = /(<([^>]+)>)/gi;
return content.replace(regex, "");
}
71 changes: 71 additions & 0 deletions src/common/util/infiniteScroll.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {useEffect, useState, useMemo, useRef, MutableRefObject} from 'react';
import {PostResponse} from "../types/post.tsx";

export interface InfiniteScrollProps {
root?: Element | null;
rootMargin?: string;
target: MutableRefObject<HTMLDivElement | null>;
threshold?: number;
targetArray: Array<PostResponse>;
endPoint?: number;
}

const useInfiniteScroll = ({
root = null,
target,
threshold = 1,
rootMargin = '0px',
targetArray,
endPoint = 1
}: InfiniteScrollProps) => {

const [page, setPage] = useState<number>(0);
const currentChild = useRef<Element | null>(null);

// IntersectionObserver 생성자 등록 및 callback 함수 등록
const observer = useMemo(() => {
return new IntersectionObserver(
(entries, observer) => {
if (target?.current === null) {
return;
}
if (entries[0].isIntersecting) {
setPage((v) => v + 1);
// setPage 가 무한으로 올라가는 것을 방지하기 위한 연결 끊음
observer.disconnect();
}
},
{
root,
rootMargin,
threshold,
},
);
}, [target, root, rootMargin, threshold]);

useEffect(() => {
if (target?.current === null) {
return;
}

// 관측하는 Element 가 달라졌을 때, 다시 관측을 시작
const observeChild = target.current.children[target.current.children.length - endPoint];
if (observeChild && currentChild.current !== observeChild) {
currentChild.current = observeChild;
observer.observe(observeChild);
}

return () => {
if (target.current !== null && observer) {
observer.unobserve(target.current);
}
};
}, [page, targetArray, target, endPoint, observer]);

return {
page,
setPage
};
};

export default useInfiniteScroll;
5 changes: 5 additions & 0 deletions src/common/util/regex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ export const checkPassword = (password: string) => {
const regex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d\W_]{8,16}$/;

return !!(password !== "" && password.match(regex));
}

export const checkUUID = (id: string) => {
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
return uuidRegex.test(id);
}
19 changes: 19 additions & 0 deletions src/common/util/sort.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {TagResponse} from "../types/post.tsx";

export const sortByName = (names: string[]) => {
names.sort((a: string, b: string) => {
if (a < b) return -1;
else if (a > b) return 1;
return 0;
});
return names;
}

export const sortTagByName = (tags: TagResponse[]) => {
tags.sort((a: TagResponse, b: TagResponse) => {
if (a.name < b.name) return -1;
else if (a.name > b.name) return 1;
return 0;
});
return tags;
}
7 changes: 7 additions & 0 deletions src/common/util/url.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {PostListRequest} from "../types/post.tsx";

export const postListRequestToParameter = (postListRequest: PostListRequest)=> {
const sorts = postListRequest.sorts.map(sort => `sorts=${sort}`).join("&");

return `?${sorts}&page=${postListRequest.page}&size=${postListRequest.size}&isDescending=${postListRequest.isDescending}`;
}
6 changes: 3 additions & 3 deletions src/components/common/FillButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ export function FillButton({text, onClick, addStyle}: { text: string, onClick: (
);
}

export function FillLink({text, to}: { text: string, to: string }) {
export function FillLink({text, to, addStyle}: { text: string, to: string, addStyle?: string }) {
return (
<Link to={to} className={className}>
<Link to={to} className={(addStyle) ? addStyle + className : className}>
{text}
</Link>
);
}

export function LoadMoreButton({onClick, addStyle}: { onClick: () => void, addStyle?: string }) {
return (
<FillButton text={"더 불러오기"} onClick={onClick} addStyle={addStyle + " !bg-gray-400 hover:brightness-105"} />
<FillButton text={"더 불러오기"} onClick={onClick} addStyle={addStyle + " !bg-gray-400 hover:brightness-105"}/>
);
}
19 changes: 16 additions & 3 deletions src/components/common/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
import {Link, useNavigate} from "react-router-dom";
import {useSelector} from "react-redux";
import {useDispatch, useSelector} from "react-redux";
import {RootState} from "../../store.tsx";
import {faker} from "@faker-js/faker/locale/ko";
import {useEffect, useRef, useState} from "react";
import {TextLink} from "./TextButton.tsx";
import {MdOutlineSearch} from "react-icons/md";
import IconButton from "./IconButton.tsx";
import {logoutApi} from "../../common/apis/member.tsx";
import {logout} from "../../common/slices/loginSlice.tsx";
import {getProfile, logoutApi} from "../../common/apis/member.tsx";
import {login, logout} from "../../common/slices/loginSlice.tsx";

function Header() {


const dispatch = useDispatch();
const loginState = useSelector((state: RootState) => state.loginSlice);
const navigate = useNavigate();

const dashboardRef = useRef<HTMLDivElement | null>(null);
const [isOpen, setIsOpen] = useState(false);

useEffect(() => {
getProfile()
.then(res => {
dispatch(login({
...loginState,
email: res.data.email,
username: res.data.username,
}));
})
}, []);

const handleDropDown = () => {
setIsOpen(cur => !cur);
}
Expand Down
6 changes: 3 additions & 3 deletions src/components/common/OutlineButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Link} from "react-router-dom";

const className = "bg-transparent hover:bg-lime-300 text-lime-700 font-semibold hover:text-white py-2 px-4 border border-lime-500 hover:border-transparent rounded hover:cursor-pointer";
const className = " bg-transparent hover:bg-lime-300 text-lime-700 font-semibold hover:text-white py-2 px-4 border border-lime-500 hover:border-transparent rounded hover:cursor-pointer";

export function OutlineButton({text, onClick, addStyle}: { text: string, onClick?: () => void, addStyle?: string }) {
return (
Expand All @@ -10,9 +10,9 @@ export function OutlineButton({text, onClick, addStyle}: { text: string, onClick
);
}

export function OutlineLink({text, to}: { text: string, to: string }) {
export function OutlineLink({text, to, addStyle}: { text: string, to: string, addStyle?: string }) {
return (
<Link to={to} className={className}>
<Link to={to} className={(addStyle) ? addStyle + className : className}>
{text}
</Link>
);
Expand Down
6 changes: 3 additions & 3 deletions src/components/post/PostCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {PostResponse} from "../../common/types/post.tsx";
import {getImgSrc, removeImgTags} from "../../common/util/html.tsx";
import {getImgSrc, removeHtmlTags} from "../../common/util/html.tsx";
import DOMPurify from "dompurify";
import {MdImage} from "react-icons/md";
import {dateToKorean} from "../../common/util/date.tsx";
Expand All @@ -17,7 +17,7 @@ function PostCard(post: PostResponse) {
? <img className="w-full h-52 object-cover
transform transition-transform duration-300 ease-out hover:scale-105"
src={url} alt="post_image"/>
: <div className="flex justify-center items-center w-full h-52">
: <div className="bg-gray-100 flex justify-center items-center w-full h-52">
<MdImage className="size-16 text-gray-400"/>
</div>}
</Link>
Expand All @@ -37,7 +37,7 @@ function PostCard(post: PostResponse) {
</div>
</Link>
<div className="line-clamp-3 text-gray-500 font-normal">
{removeImgTags(safeContent)}
{removeHtmlTags(safeContent)}
</div>
</div>
</div>
Expand Down
53 changes: 0 additions & 53 deletions src/components/setting/CategoryMoveModal.tsx

This file was deleted.

Loading