Skip to content

Commit 265a348

Browse files
authored
Merge pull request #32 from DDD-Community/feat/goal
[API 테스트필요] '목표추가' 기능 추가
2 parents 0548def + cf9330c commit 265a348

File tree

18 files changed

+911
-33
lines changed

18 files changed

+911
-33
lines changed

public/Logomark.svg

Lines changed: 95 additions & 0 deletions
Loading

public/icon/arrow-right.svg

Lines changed: 3 additions & 0 deletions
Loading

src/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export default function RootLayout({
2929
}>) {
3030
return (
3131
<html lang="en">
32-
<body className={`${pretendard.variable} font-pretendard pretendard`}>
32+
<body className={`${pretendard.variable} font-pretendard pretendard bg-[#1C1C1E]`}>
3333
<MSWClientProvider>
3434
<ToastProvider>{children}</ToastProvider>
3535
</MSWClientProvider>

src/app/main/api.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Goal } from '@/shared/type/goal';
2+
import { apiClient } from '@/shared/lib/apiClient';
3+
import { CommonResponse } from '@/shared/type/response';
4+
import { GoalFormData } from '@/app/main/create-goal/page';
5+
6+
interface GoalListResponse extends CommonResponse<{ goals: Goal[] }> {}
7+
8+
interface CreateGoalRequest extends GoalFormData {}
9+
10+
export async function getGoalList() {
11+
const { data } = await apiClient.get<GoalListResponse>('/goals');
12+
return data.data.goals;
13+
}
14+
15+
export async function postCreateGoal(req: CreateGoalRequest) {
16+
return await apiClient.post<CreateGoalRequest>('/goal', req);
17+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import FlexBox from '@/shared/components/layout/FlexBox';
2+
import Button from '@/shared/components/navigation/Button';
3+
import { motion } from 'framer-motion';
4+
5+
interface ProgressBarProps {
6+
doneTask?: number;
7+
totalTask?: number;
8+
isLoading: boolean;
9+
percentage: number;
10+
onComplete: () => void;
11+
isComplete: boolean;
12+
isError?: boolean;
13+
}
14+
15+
export const ConfirmGoalBottomBar = ({
16+
isLoading,
17+
doneTask,
18+
totalTask,
19+
percentage,
20+
onComplete,
21+
isComplete,
22+
isError = false,
23+
}: ProgressBarProps) => {
24+
const isButtonEnabled = !isLoading && (isComplete || isError);
25+
26+
const getButtonText = () => {
27+
if (isLoading) return '로딩중';
28+
if (isError) return '다시 시도';
29+
return '목표 작성 완료';
30+
};
31+
32+
return (
33+
<div className="w-full flex items-center px-[40px] pt-[12px] pb-[16px] gap-[95px] border-t border-line-normal">
34+
<div className="flex flex-col gap-2 items-start w-full">
35+
<FlexBox className="w-full justify-between">
36+
<div className="body-1-medium text-primary-normal">
37+
<span className="title-3-bold text-accent-violet">{percentage}%</span>
38+
{/*<span className="ml-2 text-label-alternative">{`${Math.min(doneTask, totalTask)}/${totalTask}`}</span>*/}
39+
</div>
40+
</FlexBox>
41+
<FlexBox className="relative w-full rounded-full h-3 bg-fill-normal">
42+
<motion.div
43+
className={`absolute h-full top-0 left-0 rounded-full bg-accent-fg-violet`}
44+
initial={{ width: 0 }}
45+
animate={{ width: `${percentage}%` }}
46+
transition={{ duration: 0.4, ease: 'easeOut' }}
47+
/>
48+
</FlexBox>
49+
</div>
50+
<FlexBox className="min-w-[130px]">
51+
<Button
52+
size="ml"
53+
text={getButtonText()}
54+
onClick={onComplete}
55+
disabled={!isButtonEnabled}
56+
className={isButtonEnabled ? '' : 'opacity-50 cursor-not-allowed'}
57+
/>
58+
</FlexBox>
59+
</div>
60+
);
61+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { useRouter } from 'next/navigation';
2+
import { tokenController } from '@/shared/lib/token';
3+
import Button from '@/shared/components/navigation/Button';
4+
5+
export const LogoutButton = () => {
6+
const router = useRouter();
7+
8+
const handleLogout = () => {
9+
tokenController.clearTokens();
10+
router.push('/login');
11+
};
12+
13+
return <Button size={'ml'} text={'로그아웃'} onClick={handleLogout} />;
14+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use client';
2+
3+
import { useRouter } from 'next/navigation';
4+
import Image from 'next/image';
5+
6+
export const Sidebar = ({ children }: { children?: React.ReactNode }) => {
7+
const router = useRouter();
8+
return (
9+
<aside className="h-screen w-[88px] bg-fill-normal flex flex-col items-center py-8 shadow-lg">
10+
<button onClick={() => router.push('/main')}>
11+
<Image src="/Logomark.svg" alt="icon of growit" width={32} height={32} />
12+
</button>
13+
<div className="flex-1 w-full flex flex-col items-center">{children}</div>
14+
</aside>
15+
);
16+
};

0 commit comments

Comments
 (0)