Skip to content

Commit

Permalink
[#12] 친구 정보 저장 기능
Browse files Browse the repository at this point in the history
 - fire store에 저장하기 전, Cloudinary에 먼저 저장 + 이미지 변환
 - 이미지 변환 후, fire store에 저장
 - 저장하는 도중 로딩 스피너
 - 저장에 성공시 대화창 표시

 Resolves #12
  • Loading branch information
DanBi-Lee committed Feb 8, 2021
1 parent ecb6dfb commit a34a934
Show file tree
Hide file tree
Showing 10 changed files with 256 additions and 33 deletions.
7 changes: 6 additions & 1 deletion src/components/friend/Editor.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import EditorStyles from './Editor.module.css';

function Editor ({friendInfo, setFriendInfo}) {
function Editor ({friendInfo, setFriendInfo, setImgData}) {
const handlingEditor = event => {
const {id : key } = event.target;
const {value} = event.target;
Expand All @@ -15,6 +15,11 @@ function Editor ({friendInfo, setFriendInfo}) {
setFriendInfo( {...friendInfo, [key]: e.target.result});
}, false);
reader.readAsDataURL(event.target.files[0]);

const formData = new FormData();
formData.append("file", event.target.files[0]);
formData.append("upload_preset", "defrag-friend");
setImgData(()=>formData);
};

return (
Expand Down
24 changes: 4 additions & 20 deletions src/components/friend/FriendBox.jsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
import React, { useState } from 'react';
import React from 'react';
import Editor from './Editor';
import friendBoxStyles from './FriendBox.module.css';
import PreviewBox from './PreviewBox';

function FriendBox ({saveData}) {
const initFriendState = {
thumb: '',
name : '이름',
nickname : '닉네임',
category: '미분류',
tel : '전화번호',
email: '이메일',
stie : '블로그, 웹사이트',
instagram : '',
kakaoTalk : '',
twitter: '',
facebook: '',
memo: `메모`,
birthday: '1900-01-01'
}
const [friendInfo, setFriendInfo] = useState(initFriendState);
console.log(friendInfo);
function FriendBox ({saveData, friendInfo, setFriendInfo, setImgData}) {


return (
<section className={friendBoxStyles.friendBox}>
<div className={friendBoxStyles.innerWrap}>
<PreviewBox saveData={saveData} friendInfo={friendInfo} />
<Editor setFriendInfo={setFriendInfo} friendInfo={friendInfo} />
<Editor setFriendInfo={setFriendInfo} friendInfo={friendInfo} setImgData={setImgData} />
</div>
</section>
);
Expand Down
19 changes: 19 additions & 0 deletions src/components/loading/Loading.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import ModalBox from '../templates/ModalBox';
import loadingSpinner from '../../images/loadingSpinner.svg';
import LoadingStyles from './Loading.module.css';

function Loading () {
return (
<ModalBox>
<section>
<p className={LoadingStyles.message}>
저장중
</p>
<img className={LoadingStyles.loadingSpinner} src={loadingSpinner} alt="로딩 스피너"/>
</section>
</ModalBox>
);
}

export default Loading;
67 changes: 67 additions & 0 deletions src/components/loading/Loading.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
.message {
text-align: center;
margin-bottom: 20px;
font-size: 24px;
}

.btnBox {
display: flex;
}

.btn {
width: 48%;
display: inline-block;
font-size: 16px;
border: 1px solid;
padding: 20px;
border-radius: 8px;
box-sizing: border-box;
text-align: center;
word-break: keep-all;
}

.btn.point {
background: #222;
color: #fff;
}

.btn + .btn {
margin-left: 4%;
}

@keyframes loading {
0% {
transform: rotate(0deg);
}
12.5% {
transform: rotate(45deg);
}
25% {
transform: rotate(90deg);
}
37.5% {
transform: rotate(135deg);
}
50% {
transform: rotate(180deg);
}
62.5% {
transform: rotate(225deg);
}
75% {
transform: rotate(270deg);
}
87.5% {
transform: rotate(315deg);
}
100% {
transform: rotate(360deg);
}
}

.loadingSpinner {
display: block;
margin: 0px auto;
width: 50%;
animation: loading 2.5s step-end infinite;
}
24 changes: 24 additions & 0 deletions src/components/loading/LoadingSuccess.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import { Link } from 'react-router-dom';
import ModalBox from '../templates/ModalBox';
import LoadingStyles from './Loading.module.css';

function LoadingSuccess ({setLoading}) {
const onBack = () => {
setLoading(()=>'ready');
}

return (
<ModalBox>
<section>
<p className={LoadingStyles.message}>친구 저장 완료</p>
<div className={LoadingStyles.btnBox}>
<button className={LoadingStyles.btn} onClick={onBack}>더 많은 친구</button>
<Link className={`${LoadingStyles.btn} ${LoadingStyles.point}`} to="/list">친구 리스트</Link>
</div>
</section>
</ModalBox>
);
}

export default LoadingSuccess;
12 changes: 12 additions & 0 deletions src/components/templates/ModalBox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import ModalBoxStyles from './ModalBox.module.css';

function ModalBox ({children}) {
return (
<div className={ModalBoxStyles.background}>
{children}
</div>
);
}

export default ModalBox;
23 changes: 23 additions & 0 deletions src/components/templates/ModalBox.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.background {
position: fixed;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(15px);
z-index: 3000;
padding: 20px;
box-sizing: border-box;
overflow: auto;
}

.background > section {
background-color: #fff;
padding: 40px;
box-sizing: border-box;
border-radius: 8px;
}
28 changes: 28 additions & 0 deletions src/images/loadingSpinner.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 60 additions & 12 deletions src/pages/Friend.jsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,79 @@
import React from 'react';
import React, { useCallback, useState } from 'react';
import SubHeader from '../components/common/SubHeader';
import FriendBox from '../components/friend/FriendBox';
import Loading from '../components/loading/Loading';
import LoadingSuccess from '../components/loading/LoadingSuccess';
import SubMainBox from '../components/templates/SubMainBox';
import DataService from '../service/data_service';
import ImageService from '../service/image_service';

function Friend ({setLoginModal, user}) {
const dataService = new DataService();
const imageService = new ImageService();
const [imgData, setImgData] = useState({});
const [loading, setLoading] = useState('ready');

const saveData = () => {
if(!user){
alert('로그인 후 이용 가능');
return;
}
const initFriendState = {
thumb: '',
name : '이름',
nickname : '닉네임',
category: '미분류',
tel : '전화번호',
email: '이메일',
stie : '블로그, 웹사이트',
instagram : '',
kakaoTalk : '',
twitter: '',
facebook: '',
memo: `메모`,
birthday: '1900-01-01'
}
const [friendInfo, setFriendInfo] = useState(initFriendState);
console.log(friendInfo);

const friend = {
name: 'test'
};

dataService.addFriend(user, friend).then(console.log);
const uploadImg = () => {
return imageService.uploadImg(imgData).then((response)=> response.text()).then((data)=>JSON.parse(data).url);
}
const saveFriend = (friendInfo) => {
return dataService.addFriend(user, friendInfo);
};
const setImg = async (thumb) => {
return {...friendInfo, thumb : thumb || ''};
}

const uploadImgThenSaveFriend = async () => {
console.log('업로드시작')
setLoading(()=>'loading');
const thumb = await uploadImg();
const copy_info = await setImg(thumb);
await saveFriend(copy_info);
console.log('업로드 끝');
setLoading(()=>'success');
}

const handlingSaveBtn = () =>{
if(!user){
alert('로그인 후 이용 가능');
return;
}
uploadImgThenSaveFriend();
}

const loadingSpinner = useCallback(() => {
if(loading === 'loading'){
return <Loading>로딩중</Loading>
}else if(loading === 'success'){
return <LoadingSuccess setLoading={setLoading}>성공!</LoadingSuccess>
}
}, [loading]);

return (
<>
<SubHeader setLoginModal={setLoginModal} user={user} />
<SubMainBox>
<FriendBox saveData={saveData} />
<FriendBox saveData={handlingSaveBtn} friendInfo={friendInfo} setFriendInfo={setFriendInfo} setImgData={setImgData} />
</SubMainBox>
{loadingSpinner()}
</>
);
}
Expand Down
13 changes: 13 additions & 0 deletions src/service/image_service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const cloud_name = process.env.REACT_APP_CLOUD_NAME;
const url = `https://api.cloudinary.com/v1_1/${cloud_name}/image/upload`;

class ImageService {
uploadImg(formData) {
return fetch(url, {
method: "POST",
body: formData,
});
}
}

export default ImageService;

0 comments on commit a34a934

Please sign in to comment.