Skip to content
Merged
Show file tree
Hide file tree
Changes from 113 commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
fb27f84
Main page 일단 모킹은 가능하도록 했습니다. (#26)
Hys-Lee Jul 4, 2025
76e1413
Main page mock ui관련 수정 사항 반영 (#29)
Hys-Lee Jul 4, 2025
c905582
Main page mock msw 동작하도록 수정 (#30)
Hys-Lee Jul 4, 2025
f3ca3b6
Merge remote-tracking branch 'upstream/main-page-mock' into merge-mai…
devgony Jul 7, 2025
7737032
wip-1
devgony Jul 7, 2025
2665cb4
extract authStore
devgony Jul 8, 2025
e4f7e5a
feat: fix SSR hydration mismatch using Next.js dynamic imports
devgony Jul 8, 2025
3604be6
feat: implement groups page with reusable components
devgony Jul 8, 2025
517cfb8
feat: update group page text styles to match Figma design
devgony Jul 8, 2025
b2df1d0
Merge remote-tracking branch 'upstream/main' into login-global
devgony Jul 9, 2025
78e4679
remove unused
devgony Jul 9, 2025
e1d03d1
Merge branch 'groups' of https://github.com/devgony/10th-Motimo-FE in…
devgony Jul 9, 2025
8bd70cd
generate api
devgony Jul 9, 2025
7d87402
fix get access token
devgony Jul 9, 2025
c5afb9f
implement getJoinedGroups
devgony Jul 9, 2025
0801818
refactor: Update fetchTemplate to use auth store instead of localStorage
devgony Jul 10, 2025
5f1f7c0
generate api
devgony Jul 10, 2025
7d5b0b0
feat: Add API service wrapper with automatic Bearer token authentication
devgony Jul 10, 2025
29d251c
refactor: Implement dynamic API/SWR mapping with type safety
devgony Jul 10, 2025
b1fda88
refactor: Improve API service SWR integration and debugging
devgony Jul 10, 2025
62d9ef2
refactor: Replace legacy SWR hooks with centralized service.ts hooks
devgony Jul 10, 2025
4cb1fa1
refactor: Restructure API service architecture
devgony Jul 10, 2025
5cb3029
refactor: Extract useApiQuery into separate module
devgony Jul 10, 2025
2d9e42d
feat: Integrate environment variable for API baseUrl
devgony Jul 10, 2025
54131ae
add env
devgony Jul 10, 2025
5566c9c
fix: Use NEXT_PUBLIC_ prefix for client-side environment variables
devgony Jul 10, 2025
d079bb4
feat: Separate environment configurations for dev and local
devgony Jul 10, 2025
7d97fae
feat: Configure local API server for npm run local
devgony Jul 10, 2025
f73baf9
refactor: Complete environment file separation for dev and local
devgony Jul 10, 2025
67d99c8
refactor: Replace all templateFetch usage with SWR hooks and direct A…
devgony Jul 10, 2025
99a16ff
remove: delete legacy templateFetch files
devgony Jul 10, 2025
3dc2d45
chore: remove unused
devgony Jul 10, 2025
88e6b3e
Merge remote-tracking branch 'upstream/main' into login-global
devgony Jul 10, 2025
52c181b
remove .env.local from gitignore
devgony Jul 10, 2025
ddb84cf
tidy up
devgony Jul 10, 2025
3460e43
refactor: simplify auth store initialization
devgony Jul 10, 2025
2cf7d0f
feat: improve authentication handling and fix hydration issues
devgony Jul 10, 2025
62b6e30
Merge remote-tracking branch 'upstream/main' into groups
devgony Jul 10, 2025
64efc8c
Merge remote-tracking branch 'origin/login-global' into groups
devgony Jul 10, 2025
37408c6
refactor: update group page to use new API hooks and types
devgony Jul 10, 2025
dbf506f
refactor: implement generic-based GroupList with type guards
devgony Jul 10, 2025
b8ce792
feat: add goal ID routing and error handling for GroupList
devgony Jul 10, 2025
01cf882
feat: implement join random group page based on Figma design
devgony Jul 10, 2025
7b713e9
add text-center, remove mt-auto
devgony Jul 10, 2025
4753087
add justify-center
devgony Jul 10, 2025
bb5d28f
feat: add group detail page and improve group join flow
devgony Jul 11, 2025
127b910
fix: escape quotes in group detail page title
devgony Jul 11, 2025
1ca6937
fix: resolve type errors and template literal updates
devgony Jul 11, 2025
0106b67
fix: wrap useSearchParams in Suspense boundary to fix build error
devgony Jul 11, 2025
983ff1f
feat: Update environment configuration and build scripts
devgony Jul 11, 2025
60688e2
fix: Add Next.js router mocking to Storybook
devgony Jul 11, 2025
840e64d
feat: Complete Next.js router mocking solution for Storybook
devgony Jul 11, 2025
d57197c
feat: Add onboarding completion check and redirect
devgony Jul 11, 2025
d6dd94e
feat: Implement useOnboardingStore for centralized data management
devgony Jul 11, 2025
4f595a6
Add OAuth state and onboarding completion tracking to auth store
devgony Jul 13, 2025
45cfad7
Refactor auth store hydration to use useEffect hook
devgony Jul 13, 2025
543c0e1
Fix due date calculation logic for month-based periods
devgony Jul 13, 2025
a2e462e
Add error handling for goal creation API call in onboarding
devgony Jul 13, 2025
29603d4
Merge branch 'login-global' into groups
devgony Jul 13, 2025
8975299
Merge branch 'groups' of https://github.com/devgony/10th-Motimo-FE in…
devgony Jul 13, 2025
ffa5ec8
create random group
devgony Jul 13, 2025
b124042
revert useEffect
devgony Jul 13, 2025
165acff
Merge branch 'login-global' into groups
devgony Jul 13, 2025
ed18ba0
wip1
devgony Jul 13, 2025
cb485d5
update api
devgony Jul 14, 2025
f81bd20
feat: Update API hooks and fix TypeScript errors
devgony Jul 14, 2025
3f785ec
feat(group): integrate API data for group details and user profile
devgony Jul 14, 2025
b18b326
refactor(group): improve navigation functionality and clean up compon…
devgony Jul 14, 2025
7d402fe
Merge remote-tracking branch 'upstream/main' into groups
devgony Jul 14, 2025
438bc7c
remove unused
devgony Jul 14, 2025
f0d5414
refactor(GoalCard): simplify boolean conversion
devgony Jul 14, 2025
17c9647
feat(api): enhance error handling and add runtime validation in useAp…
devgony Jul 14, 2025
3748d8e
remove env.local
devgony Jul 21, 2025
ecb4320
generate api
devgony Jul 21, 2025
c7a62d6
sync healthApi
devgony Jul 21, 2025
2eb7cfc
feat: update API service and hooks to match latest generated API
devgony Jul 21, 2025
a7c9669
generate api
devgony Jul 22, 2025
faed449
fix: update notification hook to use page parameter instead of offset
devgony Jul 22, 2025
aa4eb19
feat: format lastActivityDate in GroupItem and fix navigation
devgony Jul 22, 2025
c91d198
Onboarding 중복 클릭 방지 가드 추가 (#43)
devgony Jul 21, 2025
947a2a2
Detail page 및 메인 페이지 ui일부 수정 (#40)
Hys-Lee Jul 22, 2025
a9b97ed
fix: resolve TypeScript build errors in group components
devgony Jul 22, 2025
a12f911
Merge remote-tracking branch 'upstream/main' into groups
devgony Jul 22, 2025
7941d49
improve: enhance error message construction in useApiQuery for better…
devgony Jul 22, 2025
b784ae8
feat: add new message notifications to group items
devgony Jul 22, 2025
63c034a
remove: delete .env.production file
devgony Jul 22, 2025
d2374c0
fix: simplify default goal title in join random group page
devgony Jul 22, 2025
46a515d
remove: replace all alert() calls with console statements
devgony Jul 22, 2025
9c89fb0
feat: add Loading component with Lottie animation
devgony Jul 22, 2025
dede1f5
fix: update Loading component with proper asset loading and styling
devgony Jul 22, 2025
9781d9f
refactor: use local import for Lottie animation instead of fetch
devgony Jul 22, 2025
491174e
feat: add navigation to member page from group detail
devgony Jul 22, 2025
8c166b0
feat: implement group member page with member list and leave group fu…
devgony Jul 22, 2025
fcbd9f8
feat: add date formatting utility and implement poke functionality
devgony Jul 22, 2025
6682d6f
feat: add toast notification for poke functionality
devgony Jul 22, 2025
2ed8912
feat: implement leave group functionality with confirmation and navig…
devgony Jul 22, 2025
32e988e
refactor: replace browser confirm with custom Modal for leave group c…
devgony Jul 22, 2025
4f408ec
feat: implement notification page with AppBar navigation and Figma de…
devgony Jul 22, 2025
c6d7ddd
refactor: improve BellIcon prop naming for better clarity
devgony Jul 22, 2025
11371a3
refactor: improve notification page ternary logic
devgony Jul 22, 2025
6b19088
feat: update NotificationIcon component with proper bell icon design
devgony Jul 22, 2025
fb11743
feat: implement infinite scroll for notification page
devgony Jul 22, 2025
b117ae7
feat: add mock data for testing infinite scroll in notifications
devgony Jul 22, 2025
43f618f
refactor: extract NotificationContent component and move mock data to…
devgony Jul 23, 2025
553545b
fix: resolve TypeScript errors in AppBar and notification components
devgony Jul 23, 2025
3703b06
fix: improve loading UI for join random group page
devgony Jul 23, 2025
aa50ab0
fix: add input validation and error handling to formatDate function
devgony Jul 23, 2025
a35b50b
refactor: improve type safety and simplify notification content parsing
devgony Jul 23, 2025
765b8e4
fix: improve timeout handling and error management in group member page
devgony Jul 23, 2025
75800b6
fix: resolve TypeScript error in useRef timeout declaration
devgony Jul 23, 2025
3d9d0df
fix: wrap useSearchParams in Suspense boundary for join-random page
devgony Jul 23, 2025
26a4bcf
feat: add Primary story to NotificationContent Storybook
devgony Jul 23, 2025
84ac867
fix: improve error handling for poke functionality
devgony Jul 23, 2025
0022dce
Merge remote-tracking branch 'upstream/main' into groups
devgony Jul 24, 2025
ade5b43
feat: extract GroupMemberList component and add 7-day poke button logic
devgony Jul 24, 2025
2870bbd
refactor: replace custom spinners with shared Loading component in on…
devgony Jul 24, 2025
3835c40
fix: prevent infinite loading when entering onboarding without login
devgony Jul 24, 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
File renamed without changes.
16 changes: 15 additions & 1 deletion .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ const config = {
],
framework: {
name: "@storybook/nextjs",
options: {},
options: {
nextConfigPath: "../next.config.ts",
},
},
staticDirs: [path.resolve(__dirname, "../public")],
typescript: {
Expand All @@ -55,6 +57,18 @@ const config = {
},
];

// Mock Next.js navigation module
if (!config.resolve) {
config.resolve = {};
}
if (!config.resolve.alias) {
config.resolve.alias = {};
}
config.resolve.alias["next/navigation"] = path.resolve(
__dirname,
"nextjs-mock.ts",
);

return config;
},
};
Expand Down
48 changes: 48 additions & 0 deletions .storybook/nextjs-mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Mock Next.js App Router navigation for Storybook
const mockRouter = {
push: (url: string) => {
console.log("Router.push called with:", url);
},
replace: (url: string) => {
console.log("Router.replace called with:", url);
},
back: () => {
console.log("Router.back called");
},
forward: () => {
console.log("Router.forward called");
},
refresh: () => {
console.log("Router.refresh called");
},
prefetch: (url: string) => {
console.log("Router.prefetch called with:", url);
},
};

// Export the functions that next/navigation provides
export const useRouter = () => mockRouter;

export const useSearchParams = () => new URLSearchParams();

export const usePathname = () => "/";

export const useParams = () => ({});

export const notFound = () => {
console.log("notFound called");
};

export const redirect = (url: string) => {
console.log("redirect called with:", url);
};

// For backward compatibility
export default {
useRouter,
useSearchParams,
usePathname,
useParams,
notFound,
redirect,
};
3 changes: 3 additions & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from "react";
import type { Preview } from "@storybook/react";
import "../app/globals.css";
import "./storybook-fonts.css";
Expand All @@ -9,6 +10,7 @@ import {
Controls,
Stories,
} from "@storybook/blocks";

const preview: Preview = {
tags: ["autodocs"],
decorators: [
Expand All @@ -31,6 +33,7 @@ const preview: Preview = {
date: /Date$/i,
},
},

docs: {
page: () => (
<>
Expand Down
50 changes: 41 additions & 9 deletions api/generated/motimo/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,16 +342,36 @@ export interface PointRs {
point?: number;
}

export interface CustomSliceNotificationItemRs {
export interface CustomPageNotificationItemRs {
content?: NotificationItemRs[];
hasNext?: boolean;
/** @format int64 */
totalCount?: number;
/** @format int32 */
offset?: number;
totalPage?: number;
/** @format int32 */
page?: number;
/** @format int32 */
size?: number;
}

export type NotificationItemRs = object;
export interface NotificationItemRs {
/**
* 알림 아이디입니다.
* @format uuid
*/
id?: string;
/** 알림 내용 전체입니다. */
content?: string;
/** 알림 타입입니다. */
type?: NotificationItemRsTypeEnum;
/**
* 알림과 연결되는 항목의 아이디입니다.
* @format uuid
*/
referenceId?: string;
/** 읽음 여부입니다. */
isRead?: boolean;
}

export interface GroupDetailRs {
/**
Expand Down Expand Up @@ -777,6 +797,15 @@ export enum TodoRsStatusEnum {
INCOMPLETE = "INCOMPLETE",
}

/** 알림 타입입니다. */
export enum NotificationItemRsTypeEnum {
REACTION = "REACTION",
POKE = "POKE",
TODO_DUE_DAY = "TODO_DUE_DAY",
GROUP_TODO_COMPLETED = "GROUP_TODO_COMPLETED",
GROUP_TODO_RESULT_COMPLETED = "GROUP_TODO_RESULT_COMPLETED",
}

export enum GroupMessageContentTypeEnum {
JOIN = "JOIN",
LEAVE = "LEAVE",
Expand Down Expand Up @@ -1998,18 +2027,21 @@ export class Api<SecurityDataType extends unknown> {
* @summary 알림 목록 API
* @request GET:/v1/notifications
* @secure
* @response `200` `CustomSliceNotificationItemRs` OK
* @response `200` `CustomPageNotificationItemRs` OK
*/
getNotificationList: (
query: {
/**
* @format int32
* @default 0
*/
page?: number;
/** @format int32 */
offset: number;
/** @format int32 */
limit: number;
size: number;
},
params: RequestParams = {},
) =>
this.http.request<CustomSliceNotificationItemRs, any>({
this.http.request<CustomPageNotificationItemRs, any>({
path: `/v1/notifications`,
method: "GET",
query: query,
Expand Down
116 changes: 92 additions & 24 deletions api/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { SWRConfiguration } from "swr";
import { useApiQuery } from "./useApiQuery";
import { GetGroupChatParamsDirectionEnum } from "./generated/motimo/Api";

export const useQuery = {
// Todo API
Expand Down Expand Up @@ -40,15 +41,35 @@ export const useQuery = {
goalsNotInGroup: (config?: SWRConfiguration) =>
useApiQuery("목표Api", "getGoalNotJoinGroup", [], undefined, config),

// // Sub Goal API
// subGoalTodos: (subGoalId: string | null, config?: SWRConfiguration) =>
// useApiQuery(
// "세부목표Api",
// "getIncompleteOrTodayTodos",
// subGoalId ? [subGoalId] : null,
// undefined,
// config,
// ),
// Sub Goal API
subGoalTodos: (
subGoalId: string | null,
offset: number = 0,
size: number = 10,
config?: SWRConfiguration,
) =>
useApiQuery(
"세부목표Api",
"getIncompleteOrTodayTodosWithSlice",
subGoalId ? [subGoalId, { offset, size }] : null,
undefined,
config,
),

// Sub Goal API - All todos (complete and incomplete)
allSubGoalTodos: (
subGoalId: string | null,
offset: number = 0,
size: number = 10,
config?: SWRConfiguration,
) =>
useApiQuery(
"세부목표Api",
"getTodosBySubGoalIdWithSlice",
subGoalId ? [subGoalId, { offset, size }] : null,
undefined,
config,
),

// User API
myProfile: (config?: SWRConfiguration) =>
Expand All @@ -64,19 +85,42 @@ export const useQuery = {
config,
),

// groupChat: (
// groupId: string | null,
// page: number,
// size: number,
// config?: SWRConfiguration,
// ) =>
// useApiQuery(
// "그룹Api",
// "getGroupChat",
// groupId ? [groupId, { page, size }] : null,
// undefined,
// config,
// ),
groupChat: (
groupId: string | null,
limit?: string,
cursor?: string,
direction?: GetGroupChatParamsDirectionEnum,
config?: SWRConfiguration,
) =>
useApiQuery(
"그룹Api",
"getGroupChat",
groupId ? [groupId, { limit, cursor, direction }] : null,
undefined,
config,
),

groupDetail: (groupId: string | null, config?: SWRConfiguration) =>
useApiQuery(
"그룹Api",
"getGroupDetail",
groupId ? [groupId] : null,
undefined,
config,
),

newGroupMessages: (
groupId: string | null,
latestCursor?: string,
config?: SWRConfiguration,
) =>
useApiQuery(
"그룹Api",
"getNewGroupMessages",
groupId ? [groupId, { latestCursor }] : null,
undefined,
config,
),

joinedGroups: (config?: SWRConfiguration) =>
useApiQuery("그룹Api", "getJoinedGroups", [], undefined, config),
Expand All @@ -87,6 +131,24 @@ export const useQuery = {

cheerPhrase: (config?: SWRConfiguration) =>
useApiQuery("응원Api", "getCheerPhrase", [], undefined, config),

// Completed Goals API
completedGoals: (config?: SWRConfiguration) =>
useApiQuery("목표Api", "getCompletedGoals", [], undefined, config),

// Health API
health: (config?: SWRConfiguration) =>
useApiQuery("healthController", "health", [], undefined, config),

// Notification API
notifications: (page: number = 0, size: number, config?: SWRConfiguration) =>
useApiQuery(
"알림Api",
"getNotificationList",
[{ page, size }],
undefined,
config,
),
};

// Legacy hooks for backward compatibility (이전 방식과 호환성 유지)
Expand All @@ -96,10 +158,16 @@ export const useGoals = useQuery.goals;
export const useGoalDetail = useQuery.goalDetail;
export const useGoalWithSubGoals = useQuery.goalWithSubGoals;
export const useGoalsNotInGroup = useQuery.goalsNotInGroup;
// export const useSubGoalTodos = useQuery.subGoalTodos;
export const useSubGoalTodos = useQuery.subGoalTodos;
export const useMyProfile = useQuery.myProfile;
export const useGroupMembers = useQuery.groupMembers;
// export const useGroupChat = useQuery.groupChat;
export const useGroupChat = useQuery.groupChat;
export const useGroupDetail = useQuery.groupDetail;
export const useNewGroupMessages = useQuery.newGroupMessages;
export const useJoinedGroups = useQuery.joinedGroups;
export const usePoints = useQuery.points;
export const useCheerPhrase = useQuery.cheerPhrase;
export const useNotifications = useQuery.notifications;
export const useCompletedGoals = useQuery.completedGoals;
export const useHealth = useQuery.health;
export const useAllSubGoalTodos = useQuery.allSubGoalTodos;
5 changes: 3 additions & 2 deletions api/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ export type ApiMethodParams<
> = ApiClient[T][M] extends (...args: infer P) => any ? P : never;

// 개별 API 그룹들을 직접 export하여 사용하기 편하게 함
export const userApi = api.사용자Api;
export const todoApi = api.투두Api;
export const goalApi = api.목표Api;
export const subGoalApi = api.세부목표Api;
export const groupApi = api.그룹Api;
// export const pokeApi = api.찌르기Api;
export const authApi = api.authController;
export const userApi = api.사용자Api;
export const pointApi = api.포인트Api;
export const notificationApi = api.알림Api;
export const cheerApi = api.응원Api;
export const healthApi = api.healthController;

export default api;
18 changes: 15 additions & 3 deletions api/useApiQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export function useApiQuery<
? null
: () => {
const apiGroupInstance = api[apiGroup] as any;

if (!apiGroupInstance) {
throw new Error(`API group ${String(apiGroup)} not found`);
}

const methodFunction = apiGroupInstance[method] as any;

if (typeof methodFunction !== "function") {
Expand All @@ -41,9 +46,16 @@ export function useApiQuery<
}

// params가 배열이면 spread, 아니면 그대로 전달
return Array.isArray(params) && params.length > 0
? methodFunction(...params)
: methodFunction();
try {
return Array.isArray(params) && params.length > 0
? methodFunction(...params)
: methodFunction();
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
throw new Error(
`Failed to call ${String(apiGroup)}.${String(method)}: ${errorMessage}`,
);
}
},
config,
);
Expand Down
Loading
Loading