Skip to content

Commit a2b50cc

Browse files
authored
Merge pull request #6 from Con-graduation/feat/practice
FEAT: 기타 연습 페이지&마이페이지&구글 소셜 연동
2 parents 75ad9f4 + 1caef3e commit a2b50cc

18 files changed

Lines changed: 883 additions & 138 deletions

File tree

.env

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
VITE_BASE_URL = http://13.209.75.228:8080
1+
# VITE_BASE_URL = http://13.209.75.228:8080
2+
VITE_BASE_URL = https://www.dailyguitar.site/
3+
4+
VITE_S3_BUCKET_URL = https://daily-guitar-s3.s3.ap-northeast-2.amazonaws.com
5+
6+
VITE_GOOGLE_CLIENT_ID = 175199577563-5sqn62s05094gvb1jldb3g9mq5vg32hm.apps.googleusercontent.com
7+
8+
VITE_GOOGLE_REDIRECT_URI=https://www.dailyguitar.site/oauth/google/callback

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- name: Set up Node.js
1717
uses: actions/setup-node@v4
1818
with:
19-
node-version: "v20.10.0"
19+
node-version: "20.19.0"
2020

2121
- name: Install dependencies
2222
run: npm install

index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>기타 앱</title>
8+
<script src="https://accounts.google.com/gsi/client" async defer></script>
89
</head>
910
<body>
1011
<div id="root"></div>
1112
<script type="module" src="/src/main.jsx"></script>
12-
</body>
13+
</body>
1314
</html>

src/api/auth.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,11 @@ export async function postVerifyEmail(email, verificationCode) {
4848
return response;
4949
}
5050

51+
// 구글 소셜 로그인
52+
export async function postGoogleLogin(credential) {
53+
const response = await client.post("/api/auth/google", {
54+
credential: credential,
55+
});
56+
return response;
57+
}
58+

src/api/client.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ client.interceptors.request.use(
1717

1818
if (accessToken) {
1919
config.headers.Authorization = `Bearer ${accessToken}`;
20-
console.log("✅ 토큰 포함:", config.headers.Authorization);
20+
// console.log("✅ 토큰 포함:", config.headers.Authorization);
2121
} else {
2222
console.log("❌ 액세스 토큰이 없음");
2323
}
2424

25-
console.log("📤 요청 URL:", `${config.baseURL}${config.url}`);
26-
console.log("📤 요청 헤더:", config.headers);
25+
// console.log("📤 요청 URL:", `${config.baseURL}${config.url}`);
26+
// console.log("📤 요청 헤더:", config.headers);
2727
return config;
2828
},
2929
(error) => {

src/api/mypage.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import client from "./client";
2+
import axios from "axios";
3+
4+
export const getMypage = async () => {
5+
const response = await client.get("/api/mypage");
6+
return response.data;
7+
};
8+
9+
export const getProfileDownloadUrl = async () => {
10+
const response = await client.get("/api/profile-image/download-url");
11+
// console.log('프로필 이미지 다운로드 URL:', response);
12+
return response.data;
13+
};
14+
15+
export const postProfileUploadUrl = async (file) => {
16+
const requestBody = {
17+
contentType: file.type || "image/png",
18+
filename: file.name
19+
};
20+
const response = await client.post("/api/profile-image/upload-url", requestBody);
21+
return response.data;
22+
}
23+
24+
/* S3 업로드 헬퍼 */
25+
export const uploadToS3 = async (url, file) => {
26+
return axios.put(url, file, {
27+
headers: { "Content-Type": file.type },
28+
});
29+
};
30+
31+
export const postConfirmProfile = async (objectKey) => {
32+
const requestBody = { objectKey };
33+
const response = await client.post("/api/profile-image/confirm", requestBody);
34+
return response.data;
35+
};

src/api/practice.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
import client from './client';
1+
import axios from 'axios';
22

3-
export const postPractice = async (formData) => {
4-
const response = await client.post('/api/practice', formData, {
3+
const SERVER_URL = import.meta.env.VITE_BASE_URL;
4+
5+
export const postPracticeComplete = async (id, audioFile) => {
6+
const formData = new FormData();
7+
formData.append('audioFile', audioFile);
8+
9+
const accessToken = localStorage.getItem('accessToken');
10+
11+
console.log('URL:', `${SERVER_URL}/api/routines/complete?routineId=${id}`);
12+
13+
const response = await axios.post(`${SERVER_URL}/api/routines/complete?routineId=${id}`, formData, {
514
headers: {
6-
'Content-Type': 'multipart/form-data',
15+
'Authorization': `Bearer ${accessToken}`,
716
},
17+
withCredentials: true,
818
});
919
return response.data;
1020
};

src/assets/hand.png

1.03 KB
Loading

src/components/header.jsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
11
import { useNavigate } from 'react-router-dom';
2-
import { useState } from 'react';
2+
import { useState, useEffect } from 'react';
33
import profile from '../assets/profile.svg';
44
import logoWidth from '../assets/logoWidth.png';
5+
import { getProfileDownloadUrl } from '../api/mypage';
6+
57

68
export default function Header() {
9+
const [profileImage, setProfileImage] = useState(null);
10+
11+
const fetchProfileImage = async () => {
12+
try {
13+
const response = await getProfileDownloadUrl();
14+
return response.downloadUrl;
15+
} catch (error) {
16+
console.error('프로필 이미지 로드 실패:', error);
17+
return null;
18+
}
19+
};
20+
useEffect(() => {
21+
const loadProfileImage = async () => {
22+
const imageUrl = await fetchProfileImage();
23+
setProfileImage(imageUrl);
24+
};
25+
loadProfileImage();
26+
}, []);
27+
728
const navigate = useNavigate();
829
return (
930
<div className="sticky top-0 z-50 backdrop-blur-md bg-blue-400/80 w-screen h-16 flex items-center justify-between px-4 shadow-md">
@@ -12,9 +33,15 @@ export default function Header() {
1233
onClick={() => navigate('/home')}
1334
/>
1435

15-
<img src={profile} alt="profile" className="w-8 h-8 cursor-pointer"
16-
onClick={() => navigate('/mypage')}
17-
/>
36+
{profileImage ? (
37+
<img src={profileImage} alt="profile" className="w-8 h-8 cursor-pointer rounded-full object-cover"
38+
onClick={() => navigate('/mypage')}
39+
/>
40+
) : (
41+
<img src={profile} alt="profile" className="w-8 h-8 cursor-pointer"
42+
onClick={() => navigate('/mypage')}
43+
/>
44+
)}
1845
</div>
1946
);
2047
}

src/components/routineBox.jsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,9 @@ export default function RoutineBox({title, description, lastDate, component}) {
1111
<p className="text-sm text-gray-600">{lastDate}</p>
1212
</div>
1313
<p className="text-md text-black font-semibold">구성 요소</p>
14-
<ul className="text-sm text-gray-600">
15-
{component && component.map((item, index) => (
16-
<li key={index} className="list-disc list-inside">
17-
{item}
18-
</li>
19-
))}
20-
</ul>
14+
<p className="text-sm text-gray-600">
15+
{component && component.join(', ')}
16+
</p>
2117
</div>
2218
);
2319
}

0 commit comments

Comments
 (0)