diff --git a/src/components/Goalpage/GoormScreen.tsx b/src/components/Goalpage/GoormScreen.tsx index d850c4a7..ceed7dde 100644 --- a/src/components/Goalpage/GoormScreen.tsx +++ b/src/components/Goalpage/GoormScreen.tsx @@ -13,7 +13,6 @@ interface Cloud { hidden: boolean; } - export default function GoormScreen() { const [stage, setStage] = useState(0); @@ -22,25 +21,25 @@ export default function GoormScreen() { cloudType: stage === 1 ? ColorCloud : BlueCloud, colStart: 1, rowStart: 1, - hidden: stage === 0 + hidden: stage === 0, }, { cloudType: stage === 2 ? ColorCloud : BlueCloud, colStart: 2, rowStart: 2, - hidden: stage < 2 + hidden: stage < 2, }, { cloudType: stage === 3 ? ColorCloud : BlueCloud, colStart: 3, rowStart: 1, - hidden: stage < 3 + hidden: stage < 3, }, { - cloudType: stage === 4 ? ColorCloud : BlueCloud, + cloudType: stage === 4 ? ColorCloud : BlueCloud, colStart: 4, rowStart: 2, - hidden: stage < 4 + hidden: stage < 4, }, ]; @@ -57,9 +56,9 @@ export default function GoormScreen() { return (
{/* 단계 조절 버튼 */} @@ -93,4 +92,4 @@ export default function GoormScreen() {
); -} \ No newline at end of file +} diff --git a/src/components/Goalpage/GoormScreen/CloudComponent.tsx b/src/components/Goalpage/GoormScreen/CloudComponent.tsx index 0933bc9b..f03334f8 100644 --- a/src/components/Goalpage/GoormScreen/CloudComponent.tsx +++ b/src/components/Goalpage/GoormScreen/CloudComponent.tsx @@ -9,31 +9,36 @@ interface CloudComponentProps { hidden: boolean; } -export default function CloudComponent({ cloudType, colStart, rowStart, hidden }: CloudComponentProps) { +export default function CloudComponent({ + cloudType, + colStart, + rowStart, + hidden, +}: CloudComponentProps) { return ( -
- 구름 - 받침
); diff --git a/src/components/Goalpage/MemberList.tsx b/src/components/Goalpage/MemberList.tsx index 45046531..705e0d22 100644 --- a/src/components/Goalpage/MemberList.tsx +++ b/src/components/Goalpage/MemberList.tsx @@ -1,21 +1,21 @@ -import MemberCard from "./MemberList/MemberCard"; +import MemberCard from './MemberList/MemberCard'; export default function MemberList() { return ( <> -
- 질수없조 - 팀원들의 -
-
- 목표 인증을 확인해볼래요? -
+
+ 질수없조 + 팀원들의 +
+
+ 목표 인증을 확인해볼래요? +
-
- - - -
+
+ + + +
); -} \ No newline at end of file +} diff --git a/src/components/Goalpage/MemberList/MemberCard.tsx b/src/components/Goalpage/MemberList/MemberCard.tsx index 48e54e3a..4a2618fa 100644 --- a/src/components/Goalpage/MemberList/MemberCard.tsx +++ b/src/components/Goalpage/MemberList/MemberCard.tsx @@ -1,13 +1,15 @@ interface MemberCardProps { - name: string; + name: string; } -export default function MemberCard({name}: MemberCardProps) { - return ( -
-
-
{name}
- -
- ); -} \ No newline at end of file +export default function MemberCard({ name }: MemberCardProps) { + return ( +
+
+
{name}
+ +
+ ); +} diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 8a08e14c..7717bc32 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -1,11 +1,25 @@ -import { useState, useEffect, useRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; + import HamburgerMenu from './HamburgerMenu'; import NavLink from './NavLink'; import cn from '../../lib/cn'; +import { useNavigate } from 'react-router-dom'; export default function Header() { const [isMenuOpen, setIsMenuOpen] = useState(false); const menuRef = useRef(null); + const navigate = useNavigate(); + const [isLoggedIn, setIsLoggedIn] = useState(false); // 로그인 여부 상태 관리 + + useEffect(() => { + // localStorage에서 accessToken을 확인하여 로그인 여부 설정 + const token = localStorage.getItem('accessToken'); + if (token) { + setIsLoggedIn(true); + } else { + setIsLoggedIn(false); + } + }, []); const toggleMenu = () => { setIsMenuOpen((prev) => !prev); @@ -56,7 +70,11 @@ export default function Header() { - + {isLoggedIn ? ( + + ) : ( + + )} {/* 오버레이 */} @@ -99,7 +117,11 @@ export default function Header() { - + {isLoggedIn ? ( + + ) : ( + + )} diff --git a/src/components/Mainpage/AdditionalIntroSection.tsx b/src/components/Mainpage/AdditionalIntroSection.tsx index fe8556a0..8e7fbc2c 100644 --- a/src/components/Mainpage/AdditionalIntroSection.tsx +++ b/src/components/Mainpage/AdditionalIntroSection.tsx @@ -10,8 +10,7 @@ import Trophy from '../../assets/MainPage/Icons/Trophy.svg'; export default function AdditionalIntroSection() { const items = [ { - text: - '팀과 함께하는\n 목표 및 루틴 설정', + text: '팀과 함께하는\n 목표 및 루틴 설정', image: Flag, }, { @@ -40,9 +39,10 @@ export default function AdditionalIntroSection() { ]; return ( -
{/* 첫 번째 박스 그룹 */} @@ -53,11 +53,7 @@ export default function AdditionalIntroSection() {
{items.map((item, index) => ( - + ))}
@@ -70,14 +66,10 @@ export default function AdditionalIntroSection() {
{additionalItems.map((item, index) => ( - + ))}
); -} \ No newline at end of file +} diff --git a/src/components/Mainpage/ImageIntroSection.tsx b/src/components/Mainpage/ImageIntroSection.tsx index 3d63dcc9..d098beba 100644 --- a/src/components/Mainpage/ImageIntroSection.tsx +++ b/src/components/Mainpage/ImageIntroSection.tsx @@ -4,31 +4,33 @@ export default function ImageIntroSection() { return (
- GoormdariFriends

- 구름다리와
+ 구름다리와
함께 이뤄나가요!

- 구름다리는 친구들과 함께 매일 루틴을 달성하며
+ 구름다리는 친구들과 함께 매일 루틴을 달성하며{' '} +
목표를 향해 나아가는 서비스입니다

{/* 데스크탑에서 보이는 p태그 */}

- 친구들과의 루틴 인증을 통해 꾸준함을 유지하고 목표에 가까워질 수 있도록 도와드립니다
+ 친구들과의 루틴 인증을 통해 꾸준함을 유지하고 목표에 + 가까워질 수 있도록 도와드립니다
구름다리와 함께 생산적이고 의미있는 하루를 만들어보세요!

{/* 모바일에서 보이는 p태그 */} -

+

팀과의 루틴 인증을 통해 꾸준하게 목표를 이뤄보세요!

diff --git a/src/components/Mainpage/Item.tsx b/src/components/Mainpage/Item.tsx index e10bd469..b4f269e4 100644 --- a/src/components/Mainpage/Item.tsx +++ b/src/components/Mainpage/Item.tsx @@ -16,15 +16,16 @@ const Item: React.FC = ({ text, image }) => { return (
{/* 텍스트를 상단에 고정 */} -
{formattedText} @@ -35,9 +36,10 @@ const Item: React.FC = ({ text, image }) => { src={image} alt={text} className={cn( - "absolute bottom-2 md:bottom-5 right-2 md:right-5", - "object-contain rounded-b-lg", - "h-[50px] w-[50px] md:h-[120px] md:w-[120px]")} + 'absolute bottom-2 md:bottom-5 right-2 md:right-5', + 'object-contain rounded-b-lg', + 'h-[50px] w-[50px] md:h-[120px] md:w-[120px]' + )} />
); diff --git a/src/components/NeedLoginComponents.tsx b/src/components/NeedLoginComponents.tsx index 34382fba..a65a0f60 100644 --- a/src/components/NeedLoginComponents.tsx +++ b/src/components/NeedLoginComponents.tsx @@ -4,19 +4,21 @@ import cn from '../lib/cn.ts'; export default function NeedLoginComponents() { return (
- Not Good + Not Good

로그인 후

-

이용할 수 있는 기능이에요

+

+ 이용할 수 있는 기능이에요 +

-
); -} \ No newline at end of file +} diff --git a/src/custom.d.ts b/src/custom.d.ts index 869107fc..4255ce63 100644 --- a/src/custom.d.ts +++ b/src/custom.d.ts @@ -1,6 +1,6 @@ declare module 'cal-heatmap'; declare module 'cal-heatmap/plugins/Tooltip'; declare module '*.svg' { - const content: string; - export default content; + const content: string; + export default content; } diff --git a/src/lib/api/user/index.ts b/src/lib/api/user/index.ts index 22b0660e..38f413fb 100644 --- a/src/lib/api/user/index.ts +++ b/src/lib/api/user/index.ts @@ -1,7 +1,49 @@ -const BASE_URL = import.meta.env.VITE_API_BASE_URL; +import { fetchData } from '../util'; // 적절한 fetchData 파일 경로로 변경하세요 export namespace __User { - export async function login(username: string, password: string) {} + const BASE_URL = import.meta.env.VITE_API_BASE_URL; - export async function register(username: string, password: string) {} + // 로그인 함수 + export async function login(username: string, password: string) { + const url = `${BASE_URL}/auth/login`; + + const body = { + username, + password, + }; + + const response = await fetchData({ + url, + method: 'POST', + body, + }); + + // 로그인 성공 시 accessToken을 localStorage에 저장 + const { accessToken } = response; + if (accessToken) { + localStorage.setItem('accessToken', accessToken); // tokenType 없이 accessToken만 저장 + } + + return response; // 필요한 경우 호출하는 쪽에서 추가 처리 + } + + export async function register( + nickname: string, + username: string, + password: string + ) { + const url = `${BASE_URL}/auth/signup`; + + const body = { + nickname, + username, + password, + }; + + return fetchData({ + url, + method: 'POST', + body, + }); + } } diff --git a/src/lib/api/util.ts b/src/lib/api/util.ts index 16dbe9ab..b8179307 100644 --- a/src/lib/api/util.ts +++ b/src/lib/api/util.ts @@ -5,6 +5,7 @@ export async function fetchData(args: { method: 'POST' | 'PUT' | 'GET' | 'DELETE'; body?: any; isFormData?: boolean; + tokenOn?: boolean; // tokenOn 플래그 추가 }): Promise { let headers: Record = {}; @@ -12,6 +13,14 @@ export async function fetchData(args: { headers['Content-Type'] = 'application/json'; } + // tokenOn이 true일 경우, localStorage에서 accessToken을 가져와 헤더에 추가 + if (args.tokenOn) { + const token = localStorage.getItem('accessToken'); + if (token) { + headers['Authorization'] = token; + } + } + try { let response = await axios({ url: args.url, diff --git a/src/pages/goal.tsx b/src/pages/goal.tsx index 9fdf7aa3..f96a2529 100644 --- a/src/pages/goal.tsx +++ b/src/pages/goal.tsx @@ -6,7 +6,7 @@ import MemberList from '../components/Goalpage/MemberList.tsx'; export default function Goal() { const [isLogin, setIsLogin] = useState(false); - + useEffect(() => { if (localStorage.getItem('accesstoken')) { setIsLogin(true); @@ -20,14 +20,17 @@ export default function Goal() { 'pb-[50px] gap-[50px] min-h-screen' )} > - {/* 로그인 확인 컴포넌트 */} - { !isLogin ? : - <> -
- - -
- } + {/* 로그인 확인 컴포넌트 */} + {!isLogin ? ( + + ) : ( + <> +
+ + +
+ + )}
); -} \ No newline at end of file +} diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 6c1ec8f3..16c63aef 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -1,9 +1,27 @@ +import { API } from '../lib/api'; import cn from '../lib/cn.ts'; import { useNavigate } from 'react-router-dom'; +import { useState } from 'react'; export default function Login() { const navigate = useNavigate(); + // 입력 필드 상태 관리 + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + + const handleLogin = async () => { + try { + // 로그인 요청 + await API.User.login(username, password); + alert('로그인 성공!'); + navigate('/'); // 로그인 성공 시 메인 페이지로 이동 + } catch (error) { + console.error('로그인 실패:', error); + alert('로그인에 실패했습니다.'); + } + }; + return (
setUsername(e.target.value)} /> setPassword(e.target.value)} />
@@ -47,6 +69,7 @@ export default function Login() { 'w-[500px] h-[70px] bg-[#5A82F1] text-white font-bold rounded', 'hover:bg-[#4A72D1] focus:outline-none focus:ring-2 focus:ring-[#5A82F1]' )} + onClick={handleLogin} // 로그인 버튼 클릭 시 실행 > 로그인 diff --git a/src/pages/mypage.tsx b/src/pages/mypage.tsx index ea150ca0..20d713dd 100644 --- a/src/pages/mypage.tsx +++ b/src/pages/mypage.tsx @@ -6,7 +6,7 @@ import cn from '../lib/cn.ts'; export default function MyPage() { const [isLogin, setIsLogin] = useState(false); - + useEffect(() => { if (localStorage.getItem('accesstoken')) { setIsLogin(true); @@ -21,11 +21,14 @@ export default function MyPage() { )} > {/* 로그인 확인 컴포넌트 */} - { !isLogin ? : - <> - - - } + {!isLogin ? ( + + ) : ( + <> + + + + )} ); } diff --git a/src/pages/register.tsx b/src/pages/register.tsx index c3114290..7787a69b 100644 --- a/src/pages/register.tsx +++ b/src/pages/register.tsx @@ -1,9 +1,35 @@ +import React, { useState } from 'react'; + +import { API } from '../lib/api/index.ts'; import cn from '../lib/cn.ts'; import { useNavigate } from 'react-router-dom'; export default function Register() { const navigate = useNavigate(); + // 입력 필드 상태 관리 + const [nickname, setNickname] = useState(''); + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + + const handleRegister = async () => { + if (password !== confirmPassword) { + alert('비밀번호가 일치하지 않습니다.'); + return; + } + + try { + // 회원가입 요청 + await API.User.register(nickname, username, password); + alert('회원가입 성공!'); + navigate('/login'); // 회원가입 후 로그인 페이지로 이동 + } catch (error) { + console.error('회원가입 실패:', error); + alert('회원가입에 실패했습니다.'); + } + }; + return (
setNickname(e.target.value)} /> setUsername(e.target.value)} /> setPassword(e.target.value)} /> setConfirmPassword(e.target.value)} />
@@ -63,6 +97,7 @@ export default function Register() { 'w-1/2 h-[70px] bg-[#5A82F1] text-white font-bold rounded', 'hover:bg-[#4A72D1] focus:outline-none focus:ring-2 focus:ring-[#5A82F1]' )} + onClick={handleRegister} > 확인