๋ฐฐํฌ URL | ํ ์คํธ ID | ํ ์คํธ PW |
---|---|---|
https://happy4.netlify.app/ |
[email protected] |
happypawpw |
- ํ๋ก์ ํธ ์๊ฐ
- ๊ฐ๋ฐ ํ๊ฒฝ
- ํ์ ํ๊ฒฝ
- ์ญํ ๋ถ๋ด
- ํ๋ก์ ํธ ๊ตฌํ
- ํต์ฌ ์ฝ๋
- ํธ๋ฌ๋ธ ์ํ
- ๐ฑ ๋ฐ๋ ค๋๋ฌผ์ ์ ๋ณด๋ฅผ ๊ณต์ ํ๋ ์ปค๋ฎค๋ํฐ๋ฅผ ๊ตฌ์ถํฉ๋๋ค.
- ๐๏ธย ์ํ๋ ๋ฌผํ์ ํ๋งคํ๊ฑฐ๋ ๊ตฌ๋งคํ๋ ์๋น์ค๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ๐งค ์ฌ์ฉ์๋ค ๋ผ๋ฆฌ ํ๋ก์ฐ ๊ธฐ๋ฅ์ ํตํด ์๋ก์ ์์์ ๊ณต์ ํ ์ ์์ต๋๋ค.
- ๐ผ๏ธย ๊ธ๊ณผ ์ฌ์ง์ ํจ๊ป ์ ๋ก๋ํ์ฌ ๋ฐ๋ ค ๋๋ฌผ๋ค์ ์ผ์์ ์๋ํ๊ณ ๊ณต์ ํ ์ ์์ต๋๋ค.
- ๐งก ๋ค๋ฅธ ์ฌ์ฉ์๋ค์ ๊ธ์ ์ข์์๋ฅผ ๋๋ฅด๊ณ ๋๊ธ์ ์์ฑํ ์ ์์ต๋๋ค.
- ๐บ๏ธ ์ง๋๊ธฐ๋ฅ์ ํตํด ๋ด์ฃผ๋ณ์ ๋ฐ๋ ค๋๋ฌผ ์นดํ, ๋ณ์, ํธํ ์ ์ฐพ์ ์ ์์ต๋๋ค.
- ํ๋ก์ ํธ ๊ธฐํ ๋ฐ ๊ฐ๋ฐ : 2023.06.01 ~ 2023.06.30
- ํ๋ก์ ํธ ๋
ธ์
:
ํดํผํฌ ๋ ธ์ ๋ฐ๋ก๊ฐ๊ธฐ
Front-End | Back-End | Co-work & etc |
---|---|---|
์ ๊ณต๋ API ์ฌ์ฉ
|
๐พ HappyPaw
โโ ๐ฆ public
โ โโ โญ favicon.ico
โ โโ ๐ index.html
โโ ๐ฆ src
โ โโ ๐ api
โ โโ ๐ assets
โ โ โโ ๐ icon
โ โ โโ ๐ splash
โ โโ ๐ components
โ โ โโ ๐ common
โ โ โ โโ ๐ Button
โ โ โ โโ ๐ Carousel
โ โ โ โโ ๐ Header
โ โ โ โโ ๐ Input
โ โ โ โโ ๐ MainLayout
โ โ โ โโ ๐ Modal
โ โ โ โโ ๐ TabMenu
โ โ โ โโ ๐ Wrapper
โ โ โโ ๐ Follow
โ โ โโ ๐ Post
โ โ โโ ๐ Product
โ โ โโ ๐ Profile
โ โ โโ ๐ Skeleton
โ โโ ๐ context
โ โโ ๐ hooks
โ โโ ๐ pages
โ โ โโ ๐ ChatPage
โ โ โโ ๐ ErrorPage
โ โ โโ ๐ FollowListPage
โ โ โโ ๐ HomePage
โ โ โโ ๐ JoinPage
โ โ โโ ๐ LoginPage
โ โ โโ ๐ MapPage
โ โ โโ ๐ PostPage
โ โ โโ ๐ ProductPage
โ โ โโ ๐ ProfilePage
โ โ โโ ๐ SearchPage
โ โ โโ ๐ SplashPage
โ โโ ๐ routes
โ โโ ๐ styles
| โโ ๐ App.js
| โโ ๐ index.js
- ํ์ ์ ์ข ๋ฅ ์คย ํ๋๋ง ์ ํํ๋ฉฐ,ย ์์ด ์๋ฌธ์๋ก ์์ํ๋ค.
- ์ฃผ์ ๋ ํ๊ธ๋ก ๊ฐ๋จ๋ช ๋ฃํ๊ฒ ์์ฑํ๋ค.
- ์ฃผ์ ์ ๋ง์ง๋ง ๋ฌธ์๋กย
.(๋ง์นจํ)
๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค. - ์ฃผ์ ๋ '-๋ค', '-์'๊ณผ ๊ฐ์ ์ด๋ฏธ๋ก ๋๋ด์ง ์๊ณ , ๊ณผ๊ฑฐํ์ ์ฌ์ฉํ์ง ์๋๋ค.
- ์ฌ๋ฐ๋ฅด์ง ์์ ์ )ย
feat: ์นด์นด์ค ๋ก๊ทธ์ธ ์ฐ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ค, ํน์ ์ถ๊ฐํจ (#3)
- ์ณ์ ์ )ย
feat: ์นด์นด์ค ๋ก๊ทธ์ธ ์ฐ๋ ๊ธฐ๋ฅ ์ถ๊ฐ (#3)
- ์ฌ๋ฐ๋ฅด์ง ์์ ์ )ย
- ์ฃผ์ ๋ ์์ค ์ฝ๋๋ฅผ ๋ณด์ง ์๊ณ ๋ ๋ณ๊ฒฝ ์ฌํญ์ด ๋ฌด์์ธ์ง ์ ์ ์๋๋ก ์์ฑํด์ผ ํ๋ค.
- ์ฌ๋ฐ๋ฅด์ง ์์ ์ )ย
design: CSS ์กฐ์ (#4)
- ์ณ์ ์ )ย
design: text box์ layout frame ์ฌ์ด์ left padding ์ถ๊ฐ (#4)
- ์ฌ๋ฐ๋ฅด์ง ์์ ์ )ย
- ์ปค๋ฐ ๋ฉ์์ง๋ ์ ์ผ์๊ฐ ๋ดค์ ๋ ๋ฌด์์ ํ๋์ง ํ์ ํ ์ ์๊ฒ ์์ธํ ์์ฑํ๋ค.
- ์ปค๋ฐ ๋ฉ์์ง๋ ์ด๋ป๊ฒ ๋ณด๋จย ๋ฌด์๊ณผ ์๋ฅผ ์ค๋ช ํ๋ค.
- ํ ์ปค๋ฐ์๋ ํ ๊ฐ์ง ๊ธฐ๋ฅ๋ง ๋ด๋๋ค.
- ์ ) ํ๋ฉด ๊ฐ๋ฐ์ ๊ฒฝ์ฐ : ์ปดํฌ๋ํธ ๋จ์๋ก ์ปค๋ฐ
- ์2 ) ๊ธฐ๋ฅ ๊ฐ๋ฐ์ ๊ฒฝ์ฐ : ๊ฐ ๊ธฐ๋ฅ ๋จ์๋ก ์ปค๋ฐ
- fix: ์ฌ๋ฐ๋ฅด์ง ์์ ๋์์ ๊ณ ์น ๊ฒฝ์ฐ
- feat: ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ๊ฒฝ์ฐ
- refactor: ๋ด๋ถ ๋ก์ง์ ๋ณ๊ฒฝํ์ง ์๊ณ ์ฝ๋๋ฅผ ๊ฐ์ ํ ๊ฒฝ์ฐ
- style: ์ฝ๋ ๊ฐ์ ๊ณผ ์๊ด์์ด ์ฌ์ํ๊ฒ ์ฝ๋๋ฅผ ์์ ํ ๊ฒฝ์ฐ
- design: ์ฌ์ฉ์ UI๋ฅผ ์ถ๊ฐ, ์์ ํ ๊ฒฝ์ฐ (๋งํฌ์
, ํผ๋ธ๋ฆฌ์ฑ ์์
)
- add: ํด๋, ํ์ผ ๋ฑ์ ์ถ๊ฐํ ๊ฒฝ์ฐ
- move: ํด๋, ํ์ผ, ์ฝ๋ ๋ฑ์ ์์น๋ฅผ ์ด๋ํ ๊ฒฝ์ฐ
- rename: ํด๋๋ช
, ํ์ผ๋ช
๋ฑ์ ์์ ํ ๊ฒฝ์ฐ
- remove: ํด๋, ํ์ผ, ์ฝ๋ ๋ฑ์ ์ญ์ ํ ๊ฒฝ์ฐ
- assets: ์์
์ ์ถ๊ฐ, ์์ ํ ๊ฒฝ์ฐ
- docs: ๋ฌธ์๋ฅผ ์ถ๊ฐ, ์์ ํ ๊ฒฝ์ฐ
- chore: ์์ ๋ชจ๋ ๊ฒฝ์ฐ์ ํฌํจ๋์ง ์๋ ๊ธฐํ ์์ ์ฌํญ
- ๊ณตํต ์ด์๋ง๋ค๊ณ , ๊ณต์ ํ๊ณ ์ถ์ ๋ฌธ์ ๊ฐ ์๋ ๊ฒฝ์ฐ ์ด์๋ก ์์ฑํ์ฌ ๊ณต์ ํ๊ณ ์์ ํ ์ด๋ ฅ ๋จ๊ธฐ๊ธฐ
const colors = {
primary: '#374259',
secondary: '#b1b5bb',
third: '#F2D8D8',
gray: '#dbdbdb',
bgGray: '#f2f2f2',
txtColor: '#767676',
warning: '#FD7A6E',
white: '#fff',
};
const theme = { colors };
export default theme;
์ ํ๋น | ๋ฐ์ง์ค | ์ด์์ฉ | ๊น๋ฏธ์ |
---|---|---|---|
ํ์ฅ | ํ์ | ํ์ | ํ์ |
hyeonbinnn | JiyunPark1301 | yongisadragon | goyomi |
์คํ๋์ | ๋ก๊ทธ์ธ | ํ์๊ฐ์ & ํ๋กํ ์ค์ |
---|---|---|
ํ | ๊ณ์ ๊ฒ์ | ํ๋ก์ฐ & ํ๋ก์ |
---|---|---|
๊ฒ์๊ธ ์ ๋ก๋ | ๊ฒ์๊ธ ์์ | ๊ฒ์๊ธ ์ญ์ |
---|---|---|
๋๊ธ ์์ฑ | ๋๊ธ ์ญ์ | ๋๊ธ ์ ๊ณ |
---|---|---|
์ํ ๋ฑ๋ก | ์ํ ์์ | ์ํ ์ญ์ |
---|---|---|
ํ๋กํ ์์ | 404 | ์ง๋ |
---|---|---|
useEffect(() => {
if (!['email', 'accountname'].includes(id)) return;
if (
(id === 'email' && !EMAIL_REGEX.test(formData.email)) ||
(id === 'accountname' && !ID_REGEX.test(formData.accountname)) ||
formData['accountname'] === userAccountname
// ํ๋กํ ์์ ํ์ด์ง์์ ํ์ฌ ๋ก๊ทธ์ธํ ์ ์ ์ accountname์ธ ๊ฒฝ์ฐ ์ด๋ฏธ ๊ฐ์
๋ ๊ณ์ ์ด๋ผ๋ ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ๋ณด์ฌ์ฃผ์ง ์๊ธฐ ์ํจ
) {
return;
}
const errorMsg = id === 'email' ? '์ด๋ฏธ ๊ฐ์
๋ ์ด๋ฉ์ผ ์ฃผ์ ์
๋๋ค.' : '์ด๋ฏธ ๊ฐ์
๋ ๊ณ์ ID ์
๋๋ค.';
const timer = setTimeout(() => {
checkDuplication(errorMsg);
}, 300);
return () => {
clearTimeout(timer);
};
}, [formData.email, formData.accountname]);
-
email
๊ณผaccountname
๋ง ์ค๋ณต ๊ฒ์ฌ๋ฅผ ์งํํ๊ธฐ ๋๋ฌธ์id
๊ฐ ๋ค๋ฅธ ๊ฐ์ด ๋๋ฉดreturn
์ ํฉ๋๋ค.
๊ทธ ๋ค์formData.email
,formData.accountname
์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์คํ์ด ๋ฉ๋๋ค. -
์กฐ๊ฑด๋ฌธ์ ํตํด ์ ๋ ฅ๋ ์ด๋ฉ์ผ๊ณผ ๊ณ์ ID์ ํ์์ด ์ฌ๋ฐ๋ฅธ์ง ํ์ธํ ๋ค,
formData.accountname
์ด ํ์ฌ ๋ก๊ทธ์ธํ ์ฌ์ฉ์์ ๊ณ์ ID์ ์ผ์นํ์ง ์๋์ง ํ์ธ ํ, ๋ง์ฝ ์กฐ๊ฑด์ ํด๋นํ์ง ์๋๋ค๋ฉด ํจ์๋ฅผ ์ข ๋ฃํฉ๋๋ค. -
๊ทธ ์ด์ธ์, ์ค๋ณต๋ ์ด๋ฉ์ผ ๋๋ ๊ณ์ ID ์๋ฌ ๋ฉ์์ง๋ฅผ ์ค์ ํ๊ณ , 300๋ฐ๋ฆฌ์ด ํ์
checkDuplication
ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
timer
๋ณ์์๋setTimeout
ํจ์๋ก ์์ฑ๋ ํ์ด๋จธ ID๊ฐ ์ ์ฅ๋๋ฉฐ,clearTimeout
์ ์ฌ์ฉํ์ฌ ํ์ด๋จธ ์ทจ์๊ฐ ๊ฐ๋ฅํฉ๋๋ค. -
useEffect
์ ๋ฐํ ํจ์๋ ํด๋น ์ดํํธ๊ฐ ์ ๋ฆฌ(clean-up)๋ ๋ ์คํํ๊ณ , ์ฌ๊ธฐ์ ํ์ด๋จธ๋ฅผ ์ทจ์ํ๊ธฐ ์ํดclearTimeout
์ ํธ์ถํฉ๋๋ค.
๋๋ฐ์ด์ฑ ๊ธฐ๋ฅ์ ์ ์ฉํจ์ผ๋ก์จ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ๋๋ง๋ค ์๋ฒ์์ฒญ์ ํ์ง ์๊ธฐ์ ํต์ ๋น์ฉ์ด ๋ฐ์ํ์ง ์์ต๋๋ค.
import { useState } from 'react';
import { uploadImages } from '../api/image';
const ALLOWED_EXTENSIONS = ['.jpg', '.gif', '.png', '.jpeg', '.bmp', '.tif', '.heic'];
const MAX_SIZE = 10 * 1024 * 1024;
const useImagesUpload = () => {
const [images, setImages] = useState([]);
const onUpload = async (files, length) => {
if (images.length + length > 3) return alert('์ด๋ฏธ์ง๋ ์ต๋ 3๊ฐ๊น์ง ์
๋ก๋ ํ ์ ์์ต๋๋ค.');
const formData = new FormData();
for (let i = 0; i < length; i++) {
const file = files[i];
const fileExtension = file.name.split('.').pop().toLowerCase();
if (ALLOWED_EXTENSIONS.includes(`.${fileExtension}`) && file.size <= MAX_SIZE) {
formData.append('image', file);
}
}
try {
const data = await uploadImages(formData);
const filenames = data.map((data) => data.filename);
setImages((prev) => [...prev, ...filenames]);
} catch (error) {
console.log(error.message);
}
};
const onDelete = (index) => {
setImages((prevImages) => {
const updatedImages = [...prevImages];
updatedImages.splice(index, 1);
return updatedImages;
});
alert('์ญ์ ๋์์ต๋๋ค.');
};
return { images, onUpload, onDelete };
};
export default useImagesUpload;
-
์ด๋ฏธ์ง ์ ๋ก๋๋ ํน์ฑ์ ํ์๊ฐ์ ์ ํ๋กํ ์ค์ , ํ๋กํ ์์ , ๊ฒ์๊ธ ์์ฑ, ์ํ ๋ฑ๋ก ๋ฑ ์ฌ๋ฌ ํ์ด์ง์์ ๋ฐ๋ณต์ ์ผ๋ก ์ฌ์ฉ๋ฉ๋๋ค. ๊ทธ๋์ ์ฌ๋ฌ ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ ํ ์ ์๋ ์ํ๋ฅผ ์ ์ธํ๊ณ , ์๋กญ๊ฒ ๋ค์ด์ค๋ ์ด๋ฏธ์ง๋ค๊ณผ ๊ธฐ์กด ์ด๋ฏธ์ง๋ฅผ ํฉ์น ๊ฐ์ด 3์ด ๋์ผ๋ฉด ๋ ์ด์ ์ ๋ก๋ ํ ์ ์๋๋ก ๊ตฌํํฉ๋๋ค.
-
FormData
๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ,files
๋ฐฐ์ด์ ์ํํ๋ฉด์ ํ์ฉ๋๋ ํ์ฅ์ ๋ชฉ๋ก๊ณผ ์ด๋ฏธ์ง ์ฌ์ด์ฆ๋ฅผ ๊ฒ์ฌํ ๋ค, ํต๊ณผํ๋ค๋ฉดformData
์image
๋ผ๋ ํค ๊ฐ์ผ๋ก ํ์ผ์ ์ถ๊ฐํ ์ ์์ต๋๋ค. -
๊ทธ ๋ค์
uploadImages
ํจ์๋ฅผ ํตํด ์๋ฒ์ ์ด๋ฏธ์ง๋ฅผ ์ ๋ก๋ํ๊ณ , ์๋ฒ ์๋ต์์ ํ์ผ๋ช ์ ์ถ์ถํ์ฌ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ๊ณ ,setImages
ํจ์๋ฅผ ์ฌ์ฉํด ์ด์ ์ํ๊ฐ์ธprev
๋ฐฐ์ด๊ณผ ์๋ก์ด ํ์ผ๋ช ๋ฐฐ์ด์ธfilenames
๋ฅผ ํฉ์ณ์ ์ํ๋ฅผ ๊ฐฑ์ ํฉ๋๋ค. -
์ด๋ ๊ฒ ํจ์ผ๋ก์จ, ์ด๋ฏธ์ง ์ ๋ก๋ ํ์ ์ํ๊ฐ์ ์ ๋ฐ์ดํธํ๊ณ
React
์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋ ์ ์๋๋ก ํฉ๋๋ค.
const BASE_URL = 'https://api.mandarin.weniv.co.kr';
export const request = async (url, options) => {
try {
const response = await fetch(`${BASE_URL}/${url}`, {
...options,
headers: {
'Content-Type': 'application/json',
...options.headers,
},
});
if (response.ok) {
const data = await response.json();
return data;
}
} catch (err) {
console.log(err);
}
};
export const imageRequest = async (url, options) => {
try {
const response = await fetch(`${BASE_URL}/${url}`, { ...options });
if (response.ok) {
const data = await response.json();
return data;
}
} catch (err) {
console.log(err);
}
};
- ๊ฐ์ฅ ๊ธฐ๋ณธ์ด ๋๋
request
ํจ์๋ฅผ ๋ง๋ค์ด ์ค๋๋ค. ๊ทธ ๋ค์, ๋ก๊ทธ์ธ์auth.js
, ๊ฒ์๊ธ์post.js
, ์ํ์product.js
๋ฑ ๊ธฐ๋ฅ๋ณ๋ก ํ์ผ์ ๋ง๋ญ๋๋ค.
import { request } from './request';
// ํ์๊ฐ์
export const join = async (state, formData, image) => {
return await request('user', {
method: 'POST',
body: JSON.stringify({ user: { ...state, ...formData, image } }),
});
};
// ๋ก๊ทธ์ธ
export const login = async (email, password) => {
return await request('user/login', {
method: 'POST',
body: JSON.stringify({ user: { email, password } }),
});
};
// ํ ํฐ ๊ฒ์ฆ
// ...
// ์ด๋ฏธ ์กด์ฌํ๋ ์ด๋ฉ์ผ(๋๋ ๊ณ์ )์ธ์ง ๊ฒ์ฌ
export const validateForm = async (id, formData) => {
return await request(`user/${id}valid`, {
method: 'POST',
body: JSON.stringify({ user: { [id]: formData[id] } }),
});
};
-
ํ์ผ ๋ด์์ ํ์ํ ์์ฒญ๋ค ์ฆ,
auth.js
๋ ํ์๊ฐ์ , ๋ก๊ทธ์ธ ๋ฑpost.js
๋ ๊ฒ์๊ธ ๋ถ๋ฌ์ค๊ธฐ, ์ ๋ก๋, ์์ , ์ญ์ , ์ ๊ณ ๋ฑ ๊ฐ๊ฐ์ ํจ์๋ก ๋ง๋ค์ด ์ค๋๋ค. -
๊ทธ๋ฆฌ๊ณ ๊ฐ๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํ ๋๋ ๋จผ์ import ํด์ฃผ๊ณ , api๋ฅผ ๊ฐ์ ธ์จ ํ ํ์ํ ์ธ์ ๊ฐ๋ค์ ๋๊ฒจ์ฃผ๋ฉด ๋ฉ๋๋ค.