Skip to content

Commit 74c89a9

Browse files
authored
✨feat: 프로필 이미지 선택 구현 및 Axios 모듈화 완료feat: 프로필 이미지 선택 구현 및 Axios 모듈화 완료
✨feat: 프로필 이미지 선택 구현 및 Axios 모듈화 완료feat: 프로필 이미지 선택 구현 및 Axios 모듈화 완료
2 parents 35cfe87 + c76d4e6 commit 74c89a9

8 files changed

Lines changed: 161 additions & 6 deletions

File tree

eslint.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ const config = [
4646
'import/no-anonymous-default-export': [
4747
'error',
4848
{
49-
allowArrowFunction: false,
49+
allowArrowFunction: true,
5050
allowAnonymousFunction: false,
5151
allowAnonymousClass: false,
5252
},
5353
],
5454

55-
'func-style': ['warn', 'declaration', { allowArrowFunctions: false }],
55+
'func-style': ['warn', 'declaration', { allowArrowFunctions: true }],
5656
},
5757
settings: {
5858
react: {

src/App.jsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import './assets/styles/base.scss';
22
import { Route, Routes } from 'react-router-dom';
33
import Header from './components/layout/Header/Header';
4-
import Test from './pages/List-page/Test';
54
import Home from './pages/Home/home';
65

76
export default function App() {
@@ -10,7 +9,6 @@ export default function App() {
109
<Header />
1110
<Routes>
1211
<Route path="/" element={<Home />} />
13-
<Route path="/" element={<Test />} />
1412
</Routes>
1513
</>
1614
);

src/api/api.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import axios from 'axios';
2+
3+
const api = axios.create({
4+
baseURL: import.meta.env.VITE_API_BASE_URL,
5+
headers: { 'Content-Type': 'application/json' },
6+
timeout: 5000,
7+
});
8+
9+
api.interceptors.response.use(
10+
(res) => res,
11+
(error) => {
12+
const status = error.response?.status;
13+
if (status === 404) {
14+
alert('요청한 자원을 찾을 수 없습니다.');
15+
} else if (status === 500) {
16+
alert('서버에 문제가 발생했습니다.');
17+
} else {
18+
alert('문제가 발생했습니다.');
19+
}
20+
return Promise.reject(error);
21+
},
22+
);
23+
24+
export default api;

src/api/fetchProfileImages.js.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import api from './api';
2+
3+
export default async function fetchProfileImages() {
4+
const res = await api.get('/profile-images/');
5+
return res.data.imageUrls;
6+
}

src/components/common/Button.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import styles from './Button.module.scss';
22

3-
export default function Button({ text, type = 'primary', onClick, disabled }) {
3+
export default function Button({
4+
children,
5+
type = 'primary',
6+
onClick,
7+
disabled,
8+
}) {
49
return (
510
<button
611
onClick={onClick}
712
disabled={disabled}
813
className={`${styles.button} ${styles[`button--${type}`]}`}
914
>
10-
{text}
15+
{children}
1116
</button>
1217
);
1318
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { useEffect, useState } from 'react';
2+
import fetchProfileImages from '../../api/fetchProfileImages.js';
3+
import DEFAULT_PROFILE_IMAGE from '../../constants/image.js';
4+
import styles from './UserProFileSelector.module.scss';
5+
6+
export default function UserProfileSelector({ onSelect }) {
7+
const [profileImages, setProfileImages] = useState([]);
8+
const [selectedImage, setSelectedImage] = useState(DEFAULT_PROFILE_IMAGE);
9+
10+
useEffect(() => {
11+
const loadImages = async () => {
12+
try {
13+
const images = await fetchProfileImages();
14+
setProfileImages(images);
15+
} catch (_) {
16+
setProfileImages([]);
17+
}
18+
};
19+
loadImages();
20+
}, []);
21+
22+
const handleSelect = (url) => {
23+
setSelectedImage(url);
24+
onSelect?.(url);
25+
};
26+
27+
return (
28+
<div className={styles['profile-select']}>
29+
<h2 className={styles['profile-select__title']}>프로필 이미지</h2>
30+
<div className={styles['profile-select__content']}>
31+
<img
32+
src={selectedImage}
33+
alt="선택된 프로필"
34+
className={styles['profile-select__selected-image']}
35+
/>
36+
<div className={styles['profile-select__right']}>
37+
<p className={styles['profile-select__description']}>
38+
프로필 이미지를 선택해주세요!
39+
</p>
40+
<div className={styles['profile-select__image-list']}>
41+
{profileImages.map((url, idx) => (
42+
<img
43+
key={idx}
44+
src={url}
45+
alt={`profile-${idx}`}
46+
className={`${styles['profile-select__image']} ${
47+
selectedImage === url
48+
? styles['profile-select__image--selected']
49+
: ''
50+
}`}
51+
onClick={() => handleSelect(url)}
52+
/>
53+
))}
54+
</div>
55+
</div>
56+
</div>
57+
</div>
58+
);
59+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
@use '../../assets/styles/variables.scss' as *;
2+
3+
.profile-select {
4+
display: flex;
5+
flex-direction: column;
6+
width: 71.7rem;
7+
height: 14.2rem;
8+
gap: 12px;
9+
10+
&__title {
11+
width: 12.9rem;
12+
height: 3.6rem;
13+
margin: 0;
14+
@include font-24-bold;
15+
color: $gray-900;
16+
white-space: nowrap;
17+
}
18+
19+
&__selected-image {
20+
width: 8rem;
21+
height: 8rem;
22+
border-radius: 100px;
23+
}
24+
25+
&__content {
26+
display: flex;
27+
align-items: center;
28+
height: 9.4rem;
29+
gap: 32px;
30+
}
31+
32+
&__right {
33+
display: flex;
34+
flex-direction: column;
35+
width: 60.5rem;
36+
gap: 12px;
37+
}
38+
39+
&__description {
40+
width: 19rem;
41+
height: 2.6rem;
42+
@include font-16-regular;
43+
color: $gray-500;
44+
45+
white-space: nowrap;
46+
}
47+
&__image-list {
48+
display: flex;
49+
height: 5.6rem;
50+
gap: 4px;
51+
}
52+
53+
&__image {
54+
width: 5.6rem;
55+
height: 5.6rem;
56+
border: 1px solid $gray-200;
57+
border-radius: 100px;
58+
}
59+
}

src/constants/image.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const DEFAULT_PROFILE_IMAGE =
2+
'https://learn-codeit-kr-static.s3.ap-northeast-2.amazonaws.com/sprint-proj-image/default_avatar.png';
3+
4+
export default DEFAULT_PROFILE_IMAGE;

0 commit comments

Comments
 (0)