Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8990017
feat: kakao/google login
yj-leee Feb 14, 2025
c0db1c0
fix: 서버응답 데이터 에러처리
yj-leee Feb 20, 2025
4fe587f
feat: 로그인 스타일링
yj-leee Feb 20, 2025
c8704b9
feat: 이미지 최적화
yj-leee Feb 21, 2025
5cd0b06
refactor: 로그인 이미지 네임 변경
yj-leee Feb 21, 2025
eb0e02f
feat: track login image with Git LFS
yj-leee Feb 21, 2025
0d75b38
feat: temp
yj-leee Feb 15, 2025
155b7e0
feat: temp
yj-leee Feb 16, 2025
b0715e1
feat: 전체 기능 1차
yj-leee Feb 19, 2025
384cdc7
feat: 임시저장 기능 서버에서 불러오기
yj-leee Feb 19, 2025
24f5e3e
refactor: 코드 정리 및 타입
yj-leee Feb 20, 2025
987d3b8
refactor: 목표기간
yj-leee Feb 20, 2025
e61dd44
fix: 타입 수정
yj-leee Feb 22, 2025
473b554
style: 스타일 적용
yj-leee Feb 22, 2025
0ad2427
style: 캘린더 스타일 적용
yj-leee Feb 22, 2025
2647bee
Merge branch 'dev' into feat/goal-create
yj-leee Feb 26, 2025
ef27b95
Merge branch 'dev' into feat/goal-create
yj-leee Feb 27, 2025
a5b2dd2
fix: 병합 오류 수정
yj-leee Feb 28, 2025
2ed9a8a
fix: 버튼 이동 url 수정
yj-leee Feb 28, 2025
f1905ed
fix: 리뷰 반영
yj-leee Feb 28, 2025
8c4f086
Merge branch 'dev' into feat/goal-create
yj-leee Feb 28, 2025
a3aa33e
Merge branch 'dev' into feat/goal-create
yj-leee Feb 28, 2025
7c6e7a0
fix: 불필요한 공백 제거
yj-leee Feb 28, 2025
a57e2ae
fix: 리뷰 반영
yj-leee Mar 1, 2025
45efa97
Merge branch 'dev' into feat/goal-create
yj-leee Mar 1, 2025
fe62243
fix: toast 적용
yj-leee Mar 1, 2025
5789770
Merge branch 'dev' into feat/goal-create
yj-leee Mar 2, 2025
97e0daf
fix: conflict 해결 및 store userId 추가
yj-leee Mar 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link href="/dist/styles.css" rel="stylesheet" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css"
/>

<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Check Locatiion</title>
</head>
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
"@radix-ui/react-slot": "^1.1.1",
"@tanstack/react-query": "^5.65.0",
"axios": "^1.7.9",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"es-toolkit": "^1.31.0",
"lucide-react": "^0.473.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
Expand Down
35 changes: 23 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion src/app/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { useMemo } from "react";

import KakaoCallback from "@/app/routes/auth/kakao-callback";
import LoginView from "@/app/routes/auth/login";
import CreateGoalView from "@/app/routes/goal/create-goal";
import {
default as AppRoot,
ErrorBoundary as RootErrorBoundary
} from "@/app/routes/index.tsx";
import PrivateRoute from "@/app/routes/PrivateRoute";
import GoogleCallback from "@/features/auth/routes/GoogleCallback";
import DatePickView from "@/features/goal/components/create-goal/date-pick";
import { QueryClient, useQueryClient } from "@tanstack/react-query";
import { createBrowserRouter, RouterProvider } from "react-router";

Expand Down Expand Up @@ -63,12 +65,20 @@ const createAppRouter = (queryClient: QueryClient) =>
import("./routes/profile/reward").then(convert(queryClient))
},
{
path: paths.goal.path,
path: paths.goal.root.path,
lazy: () => import("./routes/goal").then(convert(queryClient))
},
{
path: "*",
lazy: () => import("./routes/not-found").then(convert(queryClient))
},
{
path: paths.goal.create.path,
element: <CreateGoalView />
},
{
path: paths.goal.date.path,
element: <DatePickView />
}
]
},
Expand All @@ -83,6 +93,10 @@ const createAppRouter = (queryClient: QueryClient) =>
{
path: paths.auth.login.path,
element: <LoginView />
},
{
path: "*",
lazy: () => import("./routes/not-found").then(convert(queryClient))
}
]);

Expand Down
11 changes: 11 additions & 0 deletions src/app/routes/goal/create-goal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import CreateGoal from "@/features/goal/routes/CreateGoal";
import { useParams } from "react-router";

const CreateGoalView = () => {
const { goalId } = useParams<{ goalId?: string }>();
const parsedGoalId: number | undefined = goalId ? Number(goalId) : undefined;

return <CreateGoal goalId={parsedGoalId} />;
};

export default CreateGoalView;
4 changes: 4 additions & 0 deletions src/asset/goal/check-gray.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/asset/goal/check-green.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/components/ui/header/index.const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export const NOT_VISIBLE_HEADER_PAGES = [

export const HEADER_TITLE_MAP = new Map([
[paths.map.certification.getHref(), "목표인증"],
[paths.goal.getHref(), "목표"],
[paths.goal.root.getHref(), "목표"],
[paths.goal.create.getHref(), "목표추가"],
[paths.profile.reward.getHref(), "리워드 신청"]
]);

Expand Down
11 changes: 8 additions & 3 deletions src/config/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@ export const paths = {
},

goal: {
path: "/goal",
getHref: () => "/goal",

root: {
path: "/goal",
getHref: () => "/goal"
},
create: {
path: "/goal/create",
getHref: () => "/goal/create"
},
date: {
path: "/goal/date",
getHref: () => "/goal/date"
}
},

Expand Down
6 changes: 3 additions & 3 deletions src/features/auth/routes/GoogleCallback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ const GoogleCallback = (): JSX.Element | null => {
async (code: string): Promise<void> => {
try {
const response = await postGoogleLogin({ data: { code } });
if (!response.ok) {
if (response.status < 200 || response.status >= 300) {
throw new Error("구글 인증에 실패했습니다.");
}

const { accessToken, refreshToken } = response.data;
const { accessToken, refreshToken, userId } = response.data;

setTokens(accessToken, refreshToken);
setTokens(accessToken, refreshToken, userId);

navigate(paths.home.path);
} catch (error) {
Expand Down
4 changes: 2 additions & 2 deletions src/features/auth/routes/KakaoCallback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ const KakaoCallback = (): JSX.Element | null => {
throw new Error("카카오 인증에 실패했습니다.");
}

const { accessToken, refreshToken } = response.data;
const { accessToken, refreshToken, userId } = response.data;

setTokens(accessToken, refreshToken);
setTokens(accessToken, refreshToken, userId);

navigate(paths.home.path);
} catch (error) {
Expand Down
25 changes: 24 additions & 1 deletion src/features/goal/api/goal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { BASE_PATH } from "@/features/goal/api/path";
import { GoalData } from "@/features/goal/types/goal-create";

import type { R } from "@/types/common.ts";
import { GET } from "@/lib/axios";
import { GET, POST } from "@/lib/axios";
import type { CompleteGoal, ProgressGoal } from "../types";
import { GOALS_CHECK, GOALS_COMPLETE } from "./path";

Expand All @@ -10,3 +13,23 @@ export function getGoalsCheck(): R<ProgressGoal[]> {
export function getGoalsComplete(): R<CompleteGoal[]> {
return GET({ url: GOALS_COMPLETE });
}

export function postCreateGoal({ data }: { data: GoalData }) {
return POST({
url: `${BASE_PATH}`,
data
});
}

export function postCreateTempSaveGoal({ data }: { data: GoalData }) {
return POST({
url: `${BASE_PATH}`,
data
});
}

export function getTempGoal(pathParam: { goalId: number }) {
return GET({
url: `${BASE_PATH}/check/${pathParam.goalId}`
});
}
34 changes: 34 additions & 0 deletions src/features/goal/components/create-goal/BalanceInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
interface BalanceInfoProps {
balancePoint: number;
}

const BalanceInfo: React.FC<BalanceInfoProps> = ({ balancePoint }) => (
<div className="relative mt-[20px] flex h-[51px] w-[335px] flex-col gap-[19px]">
<div className="flex h-[18px] w-full items-center justify-between text-[16px] font-normal leading-[18px] tracking-[-2.5%] text-gray-900">
<span>차감 포인트:</span>
<span className="flex items-center gap-1">
<span className="h-[18px] w-[31px] text-[16px] font-bold leading-[18px] tracking-[-2.5%] text-gray-900">
200
</span>
<span className="ml-[2px] h-[18px] w-[10px] text-[16px] leading-[18px] tracking-[-2.5%] text-gray-900">
p
</span>
</span>
</div>
<div className="ml-auto mt-0 flex items-center text-gray-400">
<span className="text-[12px] font-normal leading-[14px] tracking-[-2.5%]">
보유 포인트
</span>
<div className="flex items-end gap-1">
<span className="w-[30px] text-right text-[12px] font-semibold leading-[14px] tracking-[-2.5%]">
{balancePoint}
</span>
<span className="w-[6px] text-right text-[10px] font-normal leading-[12px] tracking-[-2.5%]">
p
</span>
</div>
</div>
</div>
);

export default BalanceInfo;
71 changes: 71 additions & 0 deletions src/features/goal/components/create-goal/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { format } from "date-fns";

interface DatePickerProps {
startDate: Date | null;
endDate: Date | null;
onDateClick: (mode: "start" | "end") => void;
}

const DatePicker: React.FC<DatePickerProps> = ({
startDate,
endDate,
onDateClick
}) => (
<div className="h-[86px] w-[335px]">
<label className="block text-[14px] font-medium leading-[16px] tracking-[-2.5%] text-[#1A1A1A]">
목표 기간
</label>
<div className="mt-1 flex items-center justify-between">
<button
className={`h-[44px] w-[150px] rounded-[8px] p-[10px] text-[14px] ${
startDate ? "text-black" : "text-gray-400"
} flex items-center gap-2 bg-gray-50`}
onClick={() => onDateClick("start")}
>
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="mr-1 text-gray-400"
>
<path
d="M13 0C13.2449 3.23106e-05 13.4813 0.0899562 13.6644 0.252715C13.8474 0.415475 13.9643 0.639749 13.993 0.883L14 1V2H16C16.5046 1.99984 16.9906 2.19041 17.3605 2.5335C17.7305 2.87659 17.9572 3.34684 17.995 3.85L18 4V16C18.0002 16.5046 17.8096 16.9906 17.4665 17.3605C17.1234 17.7305 16.6532 17.9572 16.15 17.995L16 18H2C1.49542 18.0002 1.00943 17.8096 0.639452 17.4665C0.269471 17.1234 0.0428434 16.6532 0.00500021 16.15L1.00268e-07 16V4C-0.000159579 3.49542 0.190406 3.00943 0.533497 2.63945C0.876588 2.26947 1.34684 2.04284 1.85 2.005L2 2H4V1C4.00028 0.74512 4.09788 0.499968 4.27285 0.314632C4.44782 0.129296 4.68695 0.017765 4.94139 0.00282788C5.19584 -0.0121092 5.44638 0.0706746 5.64183 0.234265C5.83729 0.397855 5.9629 0.629904 5.993 0.883L6 1V2H12V1C12 0.734784 12.1054 0.48043 12.2929 0.292893C12.4804 0.105357 12.7348 0 13 0ZM16 9H2V16H16V9ZM16 4H2V7H16V4Z"
fill="#9E9E9E"
/>
</svg>

{startDate ? format(startDate, "yyyy-MM-dd") : "시작 날짜"}
</button>
<span className="rounded px-2 py-1 text-gray-500">~</span>
<button
className={`h-[44px] w-[150px] rounded-[8px] p-[10px] text-[14px] ${
endDate ? "text-black" : "text-gray-400"
} flex items-center gap-2 bg-gray-50`}
onClick={() => onDateClick("end")}
>
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="mr-1 text-gray-400"
>
<path
d="M13 0C13.2449 3.23106e-05 13.4813 0.0899562 13.6644 0.252715C13.8474 0.415475 13.9643 0.639749 13.993 0.883L14 1V2H16C16.5046 1.99984 16.9906 2.19041 17.3605 2.5335C17.7305 2.87659 17.9572 3.34684 17.995 3.85L18 4V16C18.0002 16.5046 17.8096 16.9906 17.4665 17.3605C17.1234 17.7305 16.6532 17.9572 16.15 17.995L16 18H2C1.49542 18.0002 1.00943 17.8096 0.639452 17.4665C0.269471 17.1234 0.0428434 16.6532 0.00500021 16.15L1.00268e-07 16V4C-0.000159579 3.49542 0.190406 3.00943 0.533497 2.63945C0.876588 2.26947 1.34684 2.04284 1.85 2.005L2 2H4V1C4.00028 0.74512 4.09788 0.499968 4.27285 0.314632C4.44782 0.129296 4.68695 0.017765 4.94139 0.00282788C5.19584 -0.0121092 5.44638 0.0706746 5.64183 0.234265C5.83729 0.397855 5.9629 0.629904 5.993 0.883L6 1V2H12V1C12 0.734784 12.1054 0.48043 12.2929 0.292893C12.4804 0.105357 12.7348 0 13 0ZM16 9H2V16H16V9ZM16 4H2V7H16V4Z"
fill="#9E9E9E"
/>
</svg>

{endDate ? format(endDate, "yyyy-MM-dd") : "목표 날짜"}
</button>
</div>
<p className="mt-1 text-[12px] font-medium leading-[14px] tracking-[-2.5%] text-gray-400">
최소 7일, 최대 3개월까지 설정할 수 있어요.
</p>
</div>
);

export default DatePicker;
Loading