Skip to content

Commit

Permalink
[#44] 파일 업로드 API 변경 및 파일 업로드 함수화
Browse files Browse the repository at this point in the history
  • Loading branch information
Taeyoung-Yang authored and YangTaeyoung committed Sep 29, 2023
1 parent 1c6a453 commit deac867
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 84 deletions.
29 changes: 11 additions & 18 deletions src/components/blog/PlogEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import {Editor} from "@toast-ui/react-editor";
import React, {LegacyRef, useState} from "react";
import Radio from '@mui/material/Radio';
import {plogAxios} from "../../modules/axios";
import {PreviewStyle} from "@toast-ui/editor/types/editor";
import Box from "@mui/material/Box";
import {VerticalSplit} from "@mui/icons-material";
import SquareIcon from '@mui/icons-material/Square';
import {plogAuthAxios} from "../../modules/axios";
import {ensureFile, uploadFile} from "../../modules/file";


interface PlogEditorProps {
Expand Down Expand Up @@ -51,22 +50,16 @@ export const PlogEditor = React.forwardRef((props: PlogEditorProps, ref: LegacyR
initialValue={props.initialValue ? props.initialValue : ""}
ref={ref}
hooks={{
addImageBlobHook: function (blob: File | Blob, callback: any) {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = () => {
const base64 = reader.result?.toString().split(',')[1];
plogAuthAxios.post('/upload-file', {
fileBase64: base64
}).then((res) => {
const data = res.data.data
callback(data.uploadedFileURL, "image");
}).catch(
(err) => {
callback("지원하지 않는 파일 형식입니다.", "error");
}
)
}
addImageBlobHook: function (fileOrBlob: File | Blob, callback: any) {
// 파일로 타입 확정
let file = ensureFile(fileOrBlob)

// 파일 업로드
uploadFile(file, (uploadedURL: string) => {
callback(uploadedURL, 'image')
}, (error: any) => {
callback("지원하지 않는 파일 형식 입니다.", 'error')
})
}
}
}
Expand Down
57 changes: 57 additions & 0 deletions src/modules/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {plogAuthAxios} from "./axios";
import axios from "axios";

export function uploadFile(file: File,
afterUploadCallback: (uploadedURL: string) => void,
uploadFailedCallback: (error: any) => void = (error) => {
console.error(error);
}) {
plogAuthAxios.post('/generate-presigned-url', {
contentType: file.type,
fileName: file.name
}).then((res) => {
const preSignedURL = res.data.preSignedURL;

// URL을 받은 후에 PUT 요청으로 파일을 업로드
axios.put(preSignedURL, file, {
headers: {
'Content-Type': file.type
}
}).then((res) => {
afterUploadCallback(preSignedURL.split('?')[0]);
}).catch((err) => {
uploadFailedCallback(err)
});
}).catch((err) => {
uploadFailedCallback(err)
});
}

function getExtensionFromMimeType(mimeType: string): string {
const mapping: { [key: string]: string } = {
'image/jpeg': 'jpg',
'image/png': 'png',
'image/gif': 'gif',
'image/webp': 'webp',
// ... 기타 MIME 타입에 대한 확장자 매핑 ...
};

return mapping[mimeType] || '';
}


export function ensureFile(fileOrBlob: File | Blob): File {
const extension = getExtensionFromMimeType(fileOrBlob.type);
const fileName = `image.${extension}`;

if (fileOrBlob instanceof File) {
// 이미 File 형태인 경우 이름은 그대로 유지하거나 필요한 경우 변경할 수 있습니다.
return fileOrBlob;
}

// Blob 형태인 경우 File로 변환
return new File([fileOrBlob], fileName, {
type: fileOrBlob.type,
lastModified: new Date().getTime()
});
}
113 changes: 76 additions & 37 deletions src/pages/mypage/MyPage.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import jwt_decode from "jwt-decode";
import {Editor, Viewer} from "@toast-ui/react-editor";
import {Editor} from "@toast-ui/react-editor";
import {useNavigate} from "react-router-dom";
import React, {ChangeEvent, useEffect, useState, useRef, RefObject} from 'react';
import {plogAuthAxios, plogAxios} from "../../modules/axios";
import React, {ChangeEvent, RefObject, useEffect, useRef, useState} from 'react';
import {plogAuthAxios} from "../../modules/axios";
import {PlogEditor} from "../../components/blog/PlogEditor";
import {LoginTokenPayload, MyPageInfo, UpdateUserRequest} from '../../types/UMSType';
import { UpdateBlogRequest} from "../../types/BlogType";
import {Avatar, Box, Button, Divider, TextField, Typography} from '@mui/material';
import {Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Snackbar} from '@mui/material';
import {UpdateBlogRequest} from "../../types/BlogType";
import {
Avatar,
Box,
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Divider,
Snackbar,
TextField,
Typography
} from '@mui/material';
import {uploadFile} from "../../modules/file";

export function MyPage() {
const navigate = useNavigate();
Expand Down Expand Up @@ -46,9 +59,9 @@ export function MyPage() {
.then(res => {
if (res.status === 204) {
setMyPageInfo(prevState => ({
...prevState,
profileImageURL: ""
}))
...prevState,
profileImageURL: ""
}))
}
})
.catch(err => console.log(err))
Expand All @@ -57,22 +70,18 @@ export function MyPage() {
const uploadProfileImage = (event: ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0] || null;
if (file) {
const reader = new FileReader();
reader.readAsDataURL(file)
reader.onload = () => {
const base64 = reader.result?.toString().split(',')[1];
plogAuthAxios.post('/upload-file', {fileBase64: base64})
.then((res) => {
setMyPageInfo(prevState => ({
...prevState,
profileImageURL: res.data.data.uploadedFileURL
}))
plogAuthAxios.put('/auth/edit-profile', {nickName: myPageInfo.nickname, profileImageURL: res.data.data.uploadedFileURL, userID: userID})
})
.catch((err) => {
console.log(err);
});
}
uploadFile(file, (uploadedURL: string) => {
setMyPageInfo(prevState => ({
...prevState,
profileImageURL: uploadedURL
}))

plogAuthAxios.put('/auth/edit-profile', {
nickName: myPageInfo.nickname,
profileImageURL: uploadedURL,
userID: userID
})
})
}
}

Expand Down Expand Up @@ -142,7 +151,7 @@ export function MyPage() {
<Box sx={{display: 'flex', flexDirection: 'column', alignItems: 'center'}}>
<Avatar sx={{width: 150, height: 150}} src={myPageInfo.profileImageURL}
alt={myPageInfo.nickname}/>
<Box sx={{display: 'flex', flexDirection: 'column', marginTop:'15px', marginBottom: '10px'}}>
<Box sx={{display: 'flex', flexDirection: 'column', marginTop: '15px', marginBottom: '10px'}}>
<Button
style={{width: 160, backgroundColor: '#6CAC23', fontSize: '16px'}}
size='small'
Expand Down Expand Up @@ -174,8 +183,22 @@ export function MyPage() {
variant="middle"
flexItem
/>
<Box sx={{display: 'flex',flexDirection: 'column', alignItems: 'flex-start', width: '100%', marginTop: '10px', marginBottom: '10px'}}>
<Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%', marginTop: '3px', marginBottom: '3px'}}>
<Box sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
width: '100%',
marginTop: '10px',
marginBottom: '10px'
}}>
<Box sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
width: '100%',
marginTop: '3px',
marginBottom: '3px'
}}>
{isNicknameEditMode ? (
<>
<TextField
Expand Down Expand Up @@ -209,7 +232,14 @@ export function MyPage() {
</>
)}
</Box>
<Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%', marginTop: '3px', marginBottom: '3px'}}
<Box sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
width: '100%',
marginTop: '3px',
marginBottom: '3px'
}}
>
{isShortIntroEditMode ? (
<>
Expand Down Expand Up @@ -298,20 +328,27 @@ export function MyPage() {
<DialogTitle><b>회원 탈퇴</b></DialogTitle>
<DialogContent>
<DialogContentText>
탈퇴 시 작성하신 포스트 및 댓글이 모두 삭제되며 복구되지 않습니다.<br />
탈퇴 시 작성하신 포스트 및 댓글이 모두 삭제되며 복구되지 않습니다.<br/>
정말로 탈퇴하시겠습니까?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button
<Button
sx={{color: '#000000', borderColor: '#6CAC23', borderWidth: '1px'}}
onClick={event => setWithdrawalDialogOpen(false)}
>
취소
</Button>
<Button
sx={{color: '#FFFFFF', backgroundColor: '#6CAC23', borderColor: '#6CAC23', borderWidth: '1px'}}
onClick={event => {handleUserWithdrawal()}}
<Button
sx={{
color: '#FFFFFF',
backgroundColor: '#6CAC23',
borderColor: '#6CAC23',
borderWidth: '1px'
}}
onClick={event => {
handleUserWithdrawal()
}}
>
탈퇴
</Button>
Expand All @@ -321,7 +358,7 @@ export function MyPage() {
</Box>
<Box sx={{display: 'flex', alignItems: 'center', padding: '16px'}}>
<Box sx={{width: '120px'}}>
<Typography
<Typography
sx={{fontSize: '18px'}}
>
<b>자기소개</b>
Expand All @@ -335,7 +372,7 @@ export function MyPage() {
<u>저장</u>
</Button>
<Snackbar
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
anchorOrigin={{vertical: 'bottom', horizontal: 'right'}}
autoHideDuration={800}
open={introSnackbarOpen}
onClose={event => setIntroSnackbarOpen(false)}
Expand All @@ -345,7 +382,9 @@ export function MyPage() {
</Box>
<Box className="intro-container">
<Box sx={{width: '766px'}}>
{myPageInfo.introMd && <PlogEditor height={"600px"} initialValue={myPageInfo.introMd ? myPageInfo.introMd : ""} ref={editorRef}/>}
{myPageInfo.introMd &&
<PlogEditor height={"600px"} initialValue={myPageInfo.introMd ? myPageInfo.introMd : ""}
ref={editorRef}/>}
</Box>
</Box>
</Box>
Expand Down
23 changes: 7 additions & 16 deletions src/pages/posting/PostingEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import Autocomplete from '@mui/material/Autocomplete';

import {EditPostingRequest, PostingResponse, PostingTag, PostingTagResponse} from "../../types/PostingType";
import {htmlStringWithRandomID} from "../../modules/html";
import {uploadFile} from "../../modules/file";

type Category = {
categoryID: number
Expand Down Expand Up @@ -290,22 +291,12 @@ export function PostingEdit() {
}

const handleFileAdded = (file: File) => {
const reader = new FileReader();

reader.onload = () => {
plogAuthAxios.post('/upload-file', {
fileBase64: reader.result?.toString().split(',')[1]
}).then((res) => {
setPostingResponse(prevState => ({
...prevState,
thumbnailImageUrl: res.data.data.uploadedFileURL
}));
}).catch((err) => {
console.log(err);
})
};

reader.readAsDataURL(file);
uploadFile(file, (uploadedURL: string) => {
setPostingResponse(prevState => ({
...prevState,
thumbnailImageUrl: uploadedURL
}))
})
};

function EditPostingRequestValidate(request: EditPostingRequest): boolean {
Expand Down
16 changes: 3 additions & 13 deletions src/pages/posting/PostingWrite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import FileDrop from "../../components/common/FileDrop";
import LoadingButton from '@mui/lab/LoadingButton';
import Autocomplete from '@mui/material/Autocomplete';
import {htmlStringWithRandomID} from "../../modules/html";
import {uploadFile} from "../../modules/file";

type CreatePostingRequest = {
title: string
Expand Down Expand Up @@ -81,21 +82,10 @@ export function PostingWrite() {
const editorRef = useRef<Editor>(null) as RefObject<Editor>;
const [isPosted, setIsPosted] = useState<boolean>(false);
const handleFileAdded = (file: File) => {
const reader = new FileReader();

reader.onload = () => {
plogAuthAxios.post('/upload-file', {
fileBase64: reader.result?.toString().split(',')[1]
}).then((res) => {
setThumbnailURL(res.data.data.uploadedFileURL);
}).catch((err) => {
console.log(err);
})
};

reader.readAsDataURL(file);
uploadFile(file, setThumbnailURL)
};


useEffect(() => {
plogAxios.get(`/blogs/${blogID}/categories`)
.then(
Expand Down

0 comments on commit deac867

Please sign in to comment.