Skip to content

Commit

Permalink
Merge pull request #88 from Nubblee/feature/previewPage-43
Browse files Browse the repository at this point in the history
[Feature] 미리보기 페이지 기능 구현
  • Loading branch information
Sonseongoh authored Oct 23, 2024
2 parents 3c454bc + 6f7c535 commit 5c4b036
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 33 deletions.
1 change: 1 addition & 0 deletions src/components/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function ShowToast(message: string, toastType = 'success') {
} else {
toast.error(`${message}`, {
autoClose: 2000,
theme: 'dark',
draggable: true,
})
}
Expand Down
15 changes: 15 additions & 0 deletions src/hooks/useWrite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,36 @@ export default function useWrite() {
const categories = useWriteStore((state) => state.category)
const boardId = useWriteStore((state) => state.boardId)
const thumbnail = useWriteStore((state) => state.thumbnailImg)
const description = useWriteStore((state) => state.description)
const setTitle = useWriteStore((state) => state.setTitle)
const setContent = useWriteStore((state) => state.setContent)
const setThumbnail = useWriteStore((state) => state.setThumbnail)
const setCategories = useWriteStore((state) => state.setCategory)
const setBoardId = useWriteStore((state) => state.setBoardId)
const setDescription = useWriteStore((state) => state.setDescription)

const reset = () => {
setTitle('')
setContent('')
setThumbnail('')
setDescription('')
setCategories([])
setBoardId(0)
}

return {
markdownContent,
markdownTitle,
categories,
thumbnail,
boardId,
description,
setTitle,
setContent,
setThumbnail,
setCategories,
setBoardId,
setDescription,
reset,
}
}
6 changes: 1 addition & 5 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,4 @@ import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'

createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
createRoot(document.getElementById('root')!).render(<App />)
2 changes: 2 additions & 0 deletions src/pages/PostDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { type FileContent, useCoteData } from '@/hooks/useCoteData'
import { formatDate } from '@/utils/formatDate'
import { useParams } from 'react-router-dom'
import { useEffect, useState } from 'react'
import Toast from '@components/Toast'

const PostDetail = () => {
const { title, author } = useParams()
Expand All @@ -25,6 +26,7 @@ const PostDetail = () => {

return (
<Container>
<Toast />
<FloatingMenu />
{coteData.map((data) => (
<Wrapper key={`${data.title}-${data.author}`}>
Expand Down
150 changes: 124 additions & 26 deletions src/pages/PreviewPage.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,102 @@
import React from 'react'
import React, { useRef } from 'react'
import styled from '@emotion/styled'
import { ImagePlus } from 'lucide-react'
import colors from '@/constants/color'
import { fontSize, fontWeight } from '@/constants/font'
import Button from '@components/Button'
import { useWriteStore } from '@/stores/writeStore'
import useGoBack from '@/hooks/useGoBack'
import useWrite from '@/hooks/useWrite'
import useFileUpload from '@/hooks/useFileUpload'
import { useNavigate } from 'react-router-dom'
import { useAuthStore } from '@/stores/authStore'
import axios from 'axios'
import { ShowToast } from '@components/Toast'

const PreviewPage = () => {
const title = useWriteStore((state) => state.title)
const content = useWriteStore((state) => state.content)
const thumbnail = useWriteStore((state) => state.thumbnailImg)
const {
markdownTitle,
markdownContent,
thumbnail,
boardId,
description,
setThumbnail,
setDescription,
reset,
} = useWrite()
const { userId } = useAuthStore()
const { uploadFile } = useFileUpload()
const fileRef = useRef<HTMLInputElement>(null)
const navigate = useNavigate()
const { sessionId } = useAuthStore()

const handleBack = useGoBack()

const handleThumnaileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0]
if (file) {
const res = await uploadFile(file)
setThumbnail(`![](${res.baseUrl + res.fileName})`)
}
}

const handleThumnailReupload = () => {
if (fileRef.current) {
fileRef.current.click()
}
}

const handleThumnailDelete = () => {
setThumbnail('')
}

const onChangeTextarea = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setDescription(e.target.value)
}

const handleSubmit = async () => {
try {
await axios.post(
'http://nubble-backend-eb-1-env.eba-f5sb82hp.ap-northeast-2.elasticbeanstalk.com/posts',
{
title: markdownTitle,
content: markdownContent,
boardId,
status: 'PUBLISHED',
thumbnailUrl: thumbnail,
description,
},
{
headers: {
'Content-Type': 'application/json',
'SESSION-ID': sessionId,
},
},
)
navigate(
`/postDetail/${boardId === 0 ? '코딩테스트' : '스터디'}/@${userId}/${encodeURIComponent(markdownTitle)}`,
)
ShowToast('게시물이 성공적으로 등록되었습니다.', 'success')
reset()
} catch (error) {
console.log('미리보기페이지 등록 에러 .................', error)
}
}

return (
<Container>
<Title>게시물 미리보기</Title>
<PreviewContainer>
<ThumnailContainer>
<div className="image-span">
<span>재업로드</span>
<span>제거</span>
<span onClick={handleThumnailReupload}>재업로드</span>
<input
type="file"
accept="image/*"
ref={fileRef}
style={{ display: 'none' }}
onChange={handleThumnaileChange}
/>
<span onClick={handleThumnailDelete}>제거</span>
</div>
<div
className="thumnail-upload"
Expand All @@ -30,30 +106,44 @@ const PreviewPage = () => {
backgroundPosition: 'center',
}}
>
{!thumbnail ? (
<ImagePlus size={200} strokeWidth={1} color={colors.deleteGray} />
) : (
<form>
<label htmlFor="thumbnailImg" className="img-label">
썸네일 업로드
</label>
<input type="file" accept="image/*" id="thumbnailImg" className="img-input" />
</form>
{!thumbnail && (
<>
<ImagePlus size={200} strokeWidth={1} color={colors.deleteGray} />
<form>
<label htmlFor="thumbnailImg" className="img-label">
썸네일 업로드
</label>
<input
type="file"
accept="image/*"
id="thumbnailImg"
className="img-input"
onChange={handleThumnaileChange}
/>
</form>
</>
)}
</div>
</ThumnailContainer>
<Line />
<PostPreviewContainer>
<div className="post-title">{title}</div>
<textarea defaultValue={content} className="post-content" />
<span className="count">{content.length}/150</span>
<div className="post-title">{markdownTitle}</div>
<textarea
placeholder="게시글 요약을 써주세요."
value={description}
onChange={onChangeTextarea}
className="post-content"
/>
<span className="count">{description.length}/150</span>
</PostPreviewContainer>
</PreviewContainer>
<ButtonContainer>
<Button variant="secondary" radius={50} onClick={handleBack}>
취소
</Button>
<Button radius={50}>등록하기</Button>
<Button radius={50} onClick={handleSubmit}>
등록하기
</Button>
</ButtonContainer>
</Container>
)
Expand Down Expand Up @@ -82,6 +172,7 @@ const PreviewContainer = styled.div`
`

const ThumnailContainer = styled.div`
position: relative;
.thumnail-upload {
width: 456px;
height: 260px;
Expand All @@ -93,9 +184,10 @@ const ThumnailContainer = styled.div`
}
.image-span {
text-align: right;
position: absolute;
top: -30px;
left: 350px;
color: ${colors.commentGray};
margin-bottom: 10px;
span {
margin-left: 10px;
Expand Down Expand Up @@ -135,12 +227,14 @@ const Line = styled.div`
`

const PostPreviewContainer = styled.div`
margin-top: 10px;
position: relative;
.post-title {
position: absolute;
top: -50px;
font-size: ${fontSize.xxxl};
font-weight: ${fontWeight.bold};
color: #d9d9d9;
margin-bottom: 18px;
}
.post-content {
Expand All @@ -154,16 +248,20 @@ const PostPreviewContainer = styled.div`
}
.count {
position: absolute;
right: 0;
bottom: -30px;
display: block;
margin-top: 10px;
text-align: right;
color: ${colors.commentGray};
}
`

const ButtonContainer = styled.div`
width: 970px;
display: inline;
display: flex;
justify-content: end;
text-align: right;
gap: 10px;
`
export default PreviewPage
4 changes: 3 additions & 1 deletion src/pages/WritePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const WritePage = () => {
setThumbnail,
setCategories,
setBoardId,
setDescription,
} = useWrite()
const { sessionId } = useAuthStore()

Expand Down Expand Up @@ -143,8 +144,9 @@ const WritePage = () => {

const handleSubmit = () => {
setTitle(markdownTitle)
setContent(markdownContent.slice(0, 150))
setContent(markdownContent)
setThumbnail(markdownContent)
setDescription(markdownContent)
navigate('/preview')
}

Expand Down
2 changes: 1 addition & 1 deletion src/routes/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const router = createBrowserRouter([
path: '/login',
element: <Login />, // 로그인 페이지 (헤더 없음)
},
{ path: '/postDetail/:author/:title', element: <PostDetail /> },
{ path: '/postDetail/:category/:author/:title', element: <PostDetail /> },
{
path: '/saves',
element: <Saves />,
Expand Down
4 changes: 4 additions & 0 deletions src/stores/writeStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ interface writeState {
title: string
thumbnailImg: string
content: string
description: string
category: categoryProps[]
boardId: number
setTitle: (newTitle: string) => void
setThumbnail: (newContent: string) => void
setContent: (newContent: string) => void
setDescription: (newDescription: string) => void
setCategory: (newCategory: categoryProps[]) => void
setBoardId: (newBoard: number) => void
}
Expand All @@ -18,6 +20,7 @@ export const useWriteStore = create<writeState>((set) => ({
title: '',
thumbnailImg: '',
content: '',
description: '',
category: [],
boardId: 0,
setTitle: (newTitle) => set({ title: newTitle }),
Expand All @@ -32,6 +35,7 @@ export const useWriteStore = create<writeState>((set) => ({
return state
})
},
setDescription: (newDescription) => set({ description: newDescription.slice(0, 150) }),
setCategory: (newCategory) =>
set((state) => {
return { ...state, category: newCategory }
Expand Down

0 comments on commit 5c4b036

Please sign in to comment.