Skip to content

Commit

Permalink
๐Ÿ’„ Add Portfolio API and fix Bug
Browse files Browse the repository at this point in the history
#233 ํฌํŠธํด๋ฆฌ์˜ค api ์—ฐ๊ฒฐ ๋ฐ ์˜ค๋ฅ˜ ์ˆ˜์ •
  • Loading branch information
chaeyoungwon authored and sxxcxng committed Sep 22, 2024
1 parent c85d7d1 commit e321594
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 107 deletions.
186 changes: 94 additions & 92 deletions gongjakso/src/pages/Portfolio/UsePortfolio.jsx
Original file line number Diff line number Diff line change
@@ -1,102 +1,115 @@
import * as S from './Portfolio.Styled';
import { useRef, useState, useEffect } from 'react';
import { getMyInfo } from '../../service/profile_service';
import { postExistPortfolio } from '../../service/portfolio_service';
import { useNavigate } from 'react-router-dom';
import {
getExistPortfolio,
postExistPortfolio,
editExistPortfolio,
} from '../../service/portfolio_service';
import { useNavigate, useParams } from 'react-router-dom';

const UsePortfolio = () => {
const [data, setProfileData] = useState();
const navigate = useNavigate();
const { id } = useParams(); // ํฌํŠธํด๋ฆฌ์˜ค ID ๊ฐ€์ ธ์˜ค๊ธฐ
const fileInput = useRef(null);
const [snsLinks, setSnsLinks] = useState([{ id: 1, link: '' }]);
const [isEdit, setIsEdit] = useState(false);
const [snsLink, setSnsLink] = useState(''); // ๋‹จ์ผ ๋…ธ์…˜ ๋งํฌ
const [error, setError] = useState(''); // State for error messages
const [files, setFiles] = useState([]); // ์—ฌ๋Ÿฌ ํŒŒ์ผ์„ ์ €์žฅํ•˜๋Š” ๋ฐฐ์—ด
const [file, setFile] = useState(null); // ๋‹จ์ผ ํŒŒ์ผ
const [existingFile, setExistingFile] = useState(null); // ๊ธฐ์กด ํŒŒ์ผ URI ์ƒํƒœ

useEffect(() => {
// ๊ธฐ์กด ํฌํŠธํด๋ฆฌ์˜ค ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ snsLink์™€ file ์ƒํƒœ๋ฅผ ์„ค์ •
const fetchPortfolio = async () => {
try {
const response = await getExistPortfolio(id); // ํฌํŠธํด๋ฆฌ์˜ค ์ƒ์„ธ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
const portfolioData = response?.data.data;

// ๊ธฐ์กด ๋…ธ์…˜ ๋งํฌ ๋ฐ ํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ์ƒํƒœ์— ์„ค์ •
if (portfolioData) {
setSnsLink(portfolioData.notionUri || ''); // ๋…ธ์…˜ ๋งํฌ ์„ค์ •
console.log(portfolioData);
if (portfolioData.fileUri) {
const fileName = portfolioData.fileUri.split('/').pop();
setExistingFile({
name: fileName,
uri: portfolioData.fileUri,
}); // ํŒŒ์ผ ์ด๋ฆ„๊ณผ URI ์„ค์ •
}
}
} catch (error) {}
};

fetchPortfolio();
getMyInfo().then(response => {
setProfileData(response?.data);
});
}, [id]);

const handleButtonClick = () => {
fileInput.current.click();
};

const addSNSLink = () => {
setSnsLinks([...snsLinks, { id: new Date(), link: '' }]);
};
const handleChange = e => {
const selectedFiles = Array.from(e.target.files); // ์„ ํƒ๋œ ํŒŒ์ผ๋“ค์„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜
const selectedFile = e.target.files[0]; // ์ฒซ ๋ฒˆ์งธ ํŒŒ์ผ๋งŒ ์„ ํƒ
const maxSize = 10 * 1024 * 1024; // 10MB ์ œํ•œ

let totalSize = 0;
selectedFiles.forEach(file => {
totalSize += file.size;
});

if (totalSize > maxSize) {
if (selectedFile.size > maxSize) {
setError(
'์ „์ฒด ํŒŒ์ผ ํฌ๊ธฐ๊ฐ€ 10MB๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ์„ ๋‹ค์‹œ ์„ ํƒํ•ด ์ฃผ์„ธ์š”.',
'ํŒŒ์ผ ํฌ๊ธฐ๊ฐ€ 10MB๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŒŒ์ผ์„ ์„ ํƒํ•ด ์ฃผ์„ธ์š”.',
);
} else {
setError('');

// ๊ธฐ์กด ํŒŒ์ผ๊ณผ ์ƒˆ๋กœ ์„ ํƒํ•œ ํŒŒ์ผ๋“ค์„ ํ•ฉ์ณ์„œ ์—…๋ฐ์ดํŠธ
const updatedFiles = [...files, ...selectedFiles];

// ์ค‘๋ณต ํŒŒ์ผ ์ œ๊ฑฐ (ํŒŒ์ผ ์ด๋ฆ„ ๊ธฐ์ค€)
const uniqueFiles = updatedFiles.filter(
(file, index, self) =>
index === self.findIndex(f => f.name === file.name),
);

setFiles(uniqueFiles); // ์ค‘๋ณต ์ œ๊ฑฐ ํ›„ ํŒŒ์ผ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
setFile(selectedFile); // ์„ ํƒ๋œ ํŒŒ์ผ ์„ค์ •
setExistingFile(null); // ์ƒˆ ํŒŒ์ผ์„ ์„ ํƒํ•œ ๊ฒฝ์šฐ ๊ธฐ์กด ํŒŒ์ผ ์ดˆ๊ธฐํ™”
}
};

// ํŒŒ์ผ ์‚ญ์ œ
const handleFileDelete = index => {
const updatedFiles = files.filter((_, i) => i !== index); // ์„ ํƒ๋œ ํŒŒ์ผ ์‚ญ์ œ
setFiles(updatedFiles); // ํŒŒ์ผ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
};

// ๋…ธ์…˜ ๋งํฌ ์‚ญ์ œ
const handleSNSDelete = id => {
setSnsLinks(snsLinks.filter(link => link.id !== id)); // ๋งํฌ ์‚ญ์ œ
const handleFileDelete = () => {
setFile(null); // ํŒŒ์ผ ์ƒํƒœ ์ดˆ๊ธฐํ™”
setExistingFile(null); // ๊ธฐ์กด ํŒŒ์ผ๋„ ์ดˆ๊ธฐํ™”
};

const handleSubmit = async () => {
const formData = new FormData();

// ํŒŒ์ผ ๋ฐฐ์—ด์„ ์ˆœํšŒํ•˜์—ฌ ๊ฐ ํŒŒ์ผ์„ 'file' ํ•„๋“œ๋กœ ์ถ”๊ฐ€ (๋‹จ์ผ ํŒŒ์ผ์”ฉ ์ถ”๊ฐ€)
files.forEach(file => {
// ํŒŒ์ผ์ด ์ƒˆ๋กœ ์„ ํƒ๋˜์—ˆ์œผ๋ฉด FormData์— ์ถ”๊ฐ€
if (file) {
formData.append('file', file);
console.log('ํŒŒ์ผ ์ถ”๊ฐ€๋จ:', file);
});
console.log('์ƒˆ ํŒŒ์ผ ์ถ”๊ฐ€๋จ:', file);
} else if (existingFile) {
// ์ƒˆ ํŒŒ์ผ์ด ์—†๊ณ  ๊ธฐ์กด ํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ์„œ๋ฒ„์— ๊ธฐ์กด ํŒŒ์ผ์„ ์œ ์ง€ํ•˜๊ฒŒ ์•Œ๋ฆผ
formData.append('existingFileUri', existingFile.uri);
console.log('๊ธฐ์กด ํŒŒ์ผ ์œ ์ง€๋จ:', existingFile.name);
}

// notionUri ๋ฐฐ์—ด์„ JSON ๋ฌธ์ž์—ด๋กœ FormData์— ์ถ”๊ฐ€
if (snsLinks.length > 0) {
const notionUris = snsLinks.map(link => link.link).filter(Boolean); // ๋นˆ ๋งํฌ ํ•„ํ„ฐ๋ง
if (notionUris.length > 0) {
formData.append('notionUri', JSON.stringify(notionUris)); // ๋…ธ์…˜ ๋งํฌ ๋ฐฐ์—ด์„ JSON์œผ๋กœ ์ถ”๊ฐ€
}
// ๋…ธ์…˜ ๋งํฌ๊ฐ€ ๋นˆ ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ฉด ์ถ”๊ฐ€
if (snsLink && snsLink.trim() !== '') {
formData.append('notionUri', snsLink); // ๋…ธ์…˜ ๋งํฌ๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์ถ”๊ฐ€
}

if (files.length === 0 && snsLinks.every(link => !link.link)) {
// ํŒŒ์ผ์ด๋‚˜ ๋…ธ์…˜ ๋งํฌ๊ฐ€ ์—†์œผ๋ฉด ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ (๊ธฐ์กด ํŒŒ์ผ๋„ ํฌํ•จ)
if (!file && !existingFile && !snsLink) {
setError('ํŒŒ์ผ ๋˜๋Š” ๋…ธ์…˜ ๋งํฌ ์ค‘ ํ•˜๋‚˜๋Š” ํ•„์ˆ˜๋กœ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.');
return;
}
for (let pair of formData.entries()) {
console.log(pair[0], pair[1]);
}

try {
await postExistPortfolio(formData);
// ์ƒˆ ํฌํŠธํด๋ฆฌ์˜ค๋ฅผ ์˜ฌ๋ฆฌ๋Š” ๊ฒฝ์šฐ: file์ด ์žˆ์œผ๋ฉด ๋ฌด์กฐ๊ฑด ์ƒˆ ํฌํŠธํด๋ฆฌ์˜ค๋ผ๊ณ  ๊ฐ€์ •
if (!id) {
// ID๊ฐ€ ์—†์„ ๊ฒฝ์šฐ์—๋งŒ ํฌ์ŠคํŠธ API ํ˜ธ์ถœ
await postExistPortfolio(formData);
} else {
// ๊ธฐ์กด ํฌํŠธํด๋ฆฌ์˜ค ์ˆ˜์ •ํ•˜๋Š” ๊ฒฝ์šฐ ํŽธ์ง‘ API ํ˜ธ์ถœ
await editExistPortfolio(id, formData);
}
navigate('/profile');
} catch (err) {
setError('ํฌํŠธํด๋ฆฌ์˜ค ์—…๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.');
}
};

useEffect(() => {
getMyInfo().then(response => {
setProfileData(response?.data);
});
}, []);

return (
<div>
<S.TopBox>
Expand All @@ -108,7 +121,9 @@ const UsePortfolio = () => {
</S.PortfolioInfo>
</S.TopBox>
<S.GlobalBox>
<S.SubTitle>ํฌํŠธํด๋ฆฌ์˜ค ํŒŒ์ผ ์—…๋กœ๋“œํ•˜๊ธฐ</S.SubTitle>
<S.SubTitle>
ํฌํŠธํด๋ฆฌ์˜ค ํŒŒ์ผ {isEdit ? '์ˆ˜์ •' : '์—…๋กœ๋“œ'}ํ•˜๊ธฐ
</S.SubTitle>
<S.UploadInfo>
PDF ํ˜•์‹์œผ๋กœ ์—…๋กœ๋“œ ํ•ด์ฃผ์„ธ์š”.
<br />
Expand All @@ -123,65 +138,52 @@ const UsePortfolio = () => {
<input
type="file"
ref={fileInput}
multiple
onChange={handleChange}
style={{ display: 'none' }}
/>
</S.FileUploadBox>

{/* ํŒŒ์ผ ๋ฆฌ์ŠคํŠธ ํ‘œ์‹œ */}
{files.length > 0 && (
{/* ํŒŒ์ผ์ด ์„ ํƒ๋˜์—ˆ๊ฑฐ๋‚˜ ๊ธฐ์กด ํŒŒ์ผ์ด ์žˆ์„ ๋•Œ๋งŒ ํŒŒ์ผ ์ •๋ณด ํ‘œ์‹œ */}
{(file || existingFile) && (
<S.FileInfo>
<S.FileList>
{files.map((file, index) => (
<S.FileItem key={index}>
<S.FileName>{file.name}</S.FileName>
<S.FileItem>
<S.FileName>
{file ? file.name : existingFile?.name}
</S.FileName>
{file && file.size && (
<S.FileSize>
{(file.size / (1024 * 1024)).toFixed(2)}{' '}
MB
</S.FileSize>
<S.DeleteBtn
onClick={() => handleFileDelete(index)}
/>
</S.FileItem>
))}
)}
<S.DeleteBtn onClick={handleFileDelete} />
</S.FileItem>
</S.FileList>
</S.FileInfo>
)}

{error && <S.ErrorMessage>{error}</S.ErrorMessage>}

<S.TitleSection>
<S.SubTitle>๋…ธ์…˜ ํฌํŠธํด๋ฆฌ์˜ค ๊ณต์œ ํ•˜๊ธฐ</S.SubTitle>
<S.PlusBtn onClick={addSNSLink} />
<S.SubTitle>๋…ธ์…˜ ํฌํŠธํด๋ฆฌ์˜ค ๋งํฌ ์ž…๋ ฅํ•˜๊ธฐ</S.SubTitle>
</S.TitleSection>
<S.UploadInfo>
๋…ธ์…˜ ๊ณต์œ ์—์„œ โ€˜์›น์— ๊ฒŒ์‹œโ€™ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”! ๊ฒŒ์‹œ๊ฐ€
ํ—ˆ์šฉ๋˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ๋งํฌ ํ™•์ธ์ด ๋ถˆ๊ฐ€๋Šฅํ•ด์š”.
</S.UploadInfo>

{/* ๋…ธ์…˜ ๋งํฌ ๋ฆฌ์ŠคํŠธ */}
{snsLinks.map((section, index) => (
<S.BoxDetail key={section.id}>
<S.LinkContainer>
<S.LinkIcon />
<S.SNSInput
placeholder="๋งํฌ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
value={section.link}
onChange={e => {
const updatedLinks = [...snsLinks];
updatedLinks[index].link = e.target.value;
setSnsLinks(updatedLinks);
}}
/>
{snsLinks.length > 1 && (
<S.DeleteBtn
onClick={() => handleSNSDelete(section.id)}
/>
)}
</S.LinkContainer>
</S.BoxDetail>
))}
{/* ๋‹จ์ผ ๋…ธ์…˜ ๋งํฌ ์ž…๋ ฅ ํ•„๋“œ */}
<S.BoxDetail>
<S.LinkContainer>
<S.LinkIcon />
<S.SNSInput
placeholder="๋…ธ์…˜ ๋งํฌ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
value={snsLink} // ๋””ํดํŠธ ๊ฐ’์œผ๋กœ ์ƒํƒœ์—์„œ ๊ฐ€์ ธ์˜จ snsLink ์‚ฌ์šฉ
onChange={e => setSnsLink(e.target.value)}
/>
</S.LinkContainer>
</S.BoxDetail>

<S.BtnContainer>
<S.BackBtn onClick={() => navigate(-1)}>๋Œ์•„๊ฐ€๊ธฐ</S.BackBtn>
Expand Down
Loading

0 comments on commit e321594

Please sign in to comment.