diff --git a/apps/snutt-webclient/src/App.tsx b/apps/snutt-webclient/src/App.tsx
index 3b77434e..235ba549 100644
--- a/apps/snutt-webclient/src/App.tsx
+++ b/apps/snutt-webclient/src/App.tsx
@@ -25,11 +25,11 @@ import { implFeedbackSnuttApiRepository } from '@/infrastructures/implFeedbackSn
import { getNotificationRepository } from '@/infrastructures/implNotificationSnuttApiRepository';
import { implSearchSnuttApiRepository } from '@/infrastructures/implSearchSnuttApiRepository';
import { implSemesterSnuttApiRepository } from '@/infrastructures/implSemesterSnuttApiRepository';
+import { implUserSnuttApiRepository } from '@/infrastructures/implUserSnuttApiRepository';
import { ErrorPage } from '@/pages/error';
import { Main } from '@/pages/main';
import { MyPage } from '@/pages/mypage';
import { getTimetableRepository } from '@/repositories/timetableRepository';
-import { getUserRepository } from '@/repositories/userRepository';
import { getAuthService } from '@/usecases/authService';
import { getColorService } from '@/usecases/colorService';
import { getErrorService } from '@/usecases/errorService';
@@ -166,17 +166,11 @@ const GlobalStyles = createGlobalStyle`
`;
const getUnauthorizedServices = (ENV: { API_BASE_URL: string; API_KEY: string }) => {
- const httpClient = createFetchClient({
- baseURL: ENV.API_BASE_URL,
- headers: { 'x-access-apikey': ENV.API_KEY },
- });
-
const snuttApi = getSnuttApi(ENV);
const authRepository = implAuthSnuttApiRepository({ snuttApi });
const feedbackRepository = implFeedbackSnuttApiRepository({ snuttApi });
- const userRepository = getUserRepository({ httpClient });
- const authService = getAuthService({ authRepository, userRepository });
+ const authService = getAuthService({ authRepository });
const feedbackService = getFeedbackService({ feedbackRepository });
return { authService, feedbackService };
@@ -198,7 +192,7 @@ const getAuthorizedServices = (
const snuttApi = getSnuttApi(ENV);
- const userRepository = getUserRepository({ httpClient });
+ const userRepository = implUserSnuttApiRepository({ snuttApi });
const authRepository = implAuthSnuttApiRepository({ snuttApi });
const timetableRepository = getTimetableRepository({ httpClient });
const semesterRepository = implSemesterSnuttApiRepository({ snuttApi });
@@ -206,7 +200,7 @@ const getAuthorizedServices = (
const notificationRepository = getNotificationRepository({ snuttApi });
const colorRepository = implColorSnuttApiRepository({ snuttApi });
- const userService = getUserService({ repositories: [userRepository] });
+ const userService = getUserService({ userRepository });
const colorService = getColorService({ colorRepository });
const notificationService = getNotificationService({ notificationRepository });
const searchService = getSearchService({ searchRepository });
@@ -215,7 +209,7 @@ const getAuthorizedServices = (
const timeMaskService = getTimeMaskService();
const hourMinuteService = getHourMinuteService();
const hourMinutePickerService = getHourMinutePickerService({ services: [hourMinuteService] });
- const authService = getAuthService({ authRepository, userRepository });
+ const authService = getAuthService({ authRepository });
const semesterService = getSemesterService({ semesterRepository });
return {
diff --git a/apps/snutt-webclient/src/components/layout/layout-profile/index.tsx b/apps/snutt-webclient/src/components/layout/layout-profile/index.tsx
index 62b657e7..2a3e9b83 100644
--- a/apps/snutt-webclient/src/components/layout/layout-profile/index.tsx
+++ b/apps/snutt-webclient/src/components/layout/layout-profile/index.tsx
@@ -3,13 +3,13 @@ import { Link } from 'react-router-dom';
import styled from 'styled-components';
import { serviceContext } from '@/contexts/ServiceContext';
+import { useTokenAuthContext } from '@/contexts/TokenAuthContext';
import { useGuardContext } from '@/hooks/useGuardContext';
-import { queryKey } from '@/utils/query-key-factory';
export const LayoutProfile = () => {
const { data: myInfo } = useMyInfo();
- const isTempUser = !myInfo?.local_id && !myInfo?.fb_name;
+ const isTempUser = myInfo && myInfo.type === 'success' && !myInfo.data.localId && !myInfo.data.facebookName;
const isLoginButton = isTempUser;
return isLoginButton ? (
@@ -18,17 +18,18 @@ export const LayoutProfile = () => {
) : (
- {myInfo?.local_id ?? myInfo?.fb_name}님
+ {myInfo?.type === 'success' && `${myInfo.data.localId ?? myInfo.data.facebookName}님`}
);
};
const useMyInfo = () => {
const { userService } = useGuardContext(serviceContext);
+ const { token } = useTokenAuthContext();
return useQuery({
- queryKey: queryKey('user/info'),
- queryFn: () => userService.getUserInfo(),
+ queryKey: ['UserService', 'getUserInfo', { token }] as const,
+ queryFn: ({ queryKey }) => userService.getUserInfo(queryKey[2]),
});
};
diff --git a/apps/snutt-webclient/src/entities/user.ts b/apps/snutt-webclient/src/entities/user.ts
index 76427123..4d82b323 100644
--- a/apps/snutt-webclient/src/entities/user.ts
+++ b/apps/snutt-webclient/src/entities/user.ts
@@ -1,8 +1,8 @@
export interface User {
- email?: string;
- fb_name: string | null;
+ email: string | null;
+ facebookName: string | null;
isAdmin: boolean;
- local_id: string | null;
+ localId: string | null;
notificationCheckedAt: string;
regDate: string;
}
diff --git a/apps/snutt-webclient/src/infrastructures/implAuthSnuttApiRepository.ts b/apps/snutt-webclient/src/infrastructures/implAuthSnuttApiRepository.ts
index abcf65e3..68dc07f8 100644
--- a/apps/snutt-webclient/src/infrastructures/implAuthSnuttApiRepository.ts
+++ b/apps/snutt-webclient/src/infrastructures/implAuthSnuttApiRepository.ts
@@ -14,7 +14,12 @@ export const implAuthSnuttApiRepository = ({
else return { type: 'error', errcode: data.errcode };
},
signInWithFacebook: async (body) => {
- const { status, data } = await snuttApi['POST /auth/login_fb']({ body });
+ const { status, data } = await snuttApi['POST /auth/login_fb']({
+ body: {
+ fb_id: body.facebookId,
+ fb_token: body.facebookToken,
+ },
+ });
if (status === 200) return { type: 'success', data };
else return { type: 'error', errcode: data.errcode };
},
@@ -29,24 +34,45 @@ export const implAuthSnuttApiRepository = ({
else return { type: 'error', errcode: data.errcode };
},
passwordResetCheckEmail: async (body) => {
- const { status, data } = await snuttApi['POST /v1/auth/password/reset/email/check']({ body });
+ const { status, data } = await snuttApi['POST /v1/auth/password/reset/email/check']({
+ body: { user_id: body.userId },
+ });
if (status === 200) return { type: 'success', data };
else return { type: 'error', errcode: data.errcode };
},
sendPasswordResetVerificationEmail: async (body) => {
- const { status, data } = await snuttApi['POST /v1/auth/password/reset/email/send']({ body });
+ const { status, data } = await snuttApi['POST /v1/auth/password/reset/email/send']({
+ body: { user_email: body.userEmail },
+ });
if (status === 200) return { type: 'success', data };
else throw data;
},
verifyPasswordResetCode: async (body) => {
- const { status, data } = await snuttApi['POST /v1/auth/password/reset/verification/code']({ body });
+ const { status, data } = await snuttApi['POST /v1/auth/password/reset/verification/code']({
+ body: { user_id: body.userId, code: body.code },
+ });
if (status === 200) return { type: 'success' };
else return { type: 'error', errcode: data.errcode };
},
resetPassword: async (body) => {
- const { status, data } = await snuttApi['POST /v1/auth/password/reset']({ body });
+ const { status, data } = await snuttApi['POST /v1/auth/password/reset']({
+ body: { user_id: body.userId, password: body.password },
+ });
if (status === 200) return { type: 'success', data };
else throw data;
},
+ deleteUser: async ({ token }) => {
+ const { status, data } = await snuttApi['DELETE /v1/user/account']({ token });
+ if (status === 200) return { type: 'success' };
+ return { type: 'error', errcode: data.errcode };
+ },
+ changePassword: async ({ oldPassword, newPassword, token }) => {
+ const { status, data } = await snuttApi['PUT /v1/user/password']({
+ token,
+ body: { old_password: oldPassword, new_password: newPassword },
+ });
+ if (status === 200) return { type: 'success', data };
+ return { type: 'error', errcode: data.errcode };
+ },
};
};
diff --git a/apps/snutt-webclient/src/infrastructures/implUserSnuttApiRepository.ts b/apps/snutt-webclient/src/infrastructures/implUserSnuttApiRepository.ts
new file mode 100644
index 00000000..d1d48c91
--- /dev/null
+++ b/apps/snutt-webclient/src/infrastructures/implUserSnuttApiRepository.ts
@@ -0,0 +1,46 @@
+import { type SnuttApi } from '@sf/snutt-api';
+
+import { type getUserService } from '@/usecases/userService';
+
+export const implUserSnuttApiRepository = ({
+ snuttApi,
+}: {
+ snuttApi: SnuttApi;
+}): Parameters[0]['userRepository'] => {
+ return {
+ getUserInfo: async ({ token }) => {
+ const { status, data } = await snuttApi['GET /v1/user/info']({ token });
+ if (status === 200)
+ return {
+ type: 'success',
+ data: {
+ email: data.email ?? null,
+ facebookName: data.fb_name ?? null,
+ isAdmin: data.isAdmin,
+ localId: data.local_id ?? null,
+ notificationCheckedAt: data.notificationCheckedAt,
+ regDate: data.regDate,
+ },
+ };
+ return { type: 'error', errcode: data.errcode };
+ },
+ addIdPassword: async ({ id, password, token }) => {
+ const { status, data } = await snuttApi['POST /v1/user/password']({ body: { id, password }, token });
+ if (status === 200) return { type: 'success', data };
+ return { type: 'error', errcode: data.errcode };
+ },
+ attachFacebookAccount: async ({ facebookId, facebookToken, token }) => {
+ const { status, data } = await snuttApi['POST /v1/user/facebook']({
+ body: { fb_id: facebookId, fb_token: facebookToken },
+ token,
+ });
+ if (status === 200) return { type: 'success', data };
+ return { type: 'error', errcode: data.errcode };
+ },
+ detachFacebookAccount: async ({ token }) => {
+ const { status, data } = await snuttApi['DELETE /v1/user/facebook']({ token });
+ if (status === 200) return { type: 'success', data };
+ return { type: 'error', errcode: data.errcode };
+ },
+ };
+};
diff --git a/apps/snutt-webclient/src/mocks/handlers/index.ts b/apps/snutt-webclient/src/mocks/handlers/index.ts
index eeeb2f1a..dae76d42 100644
--- a/apps/snutt-webclient/src/mocks/handlers/index.ts
+++ b/apps/snutt-webclient/src/mocks/handlers/index.ts
@@ -22,7 +22,6 @@ import {
} from '@/mocks/fixtures/timetable';
import { mockUsers } from '@/mocks/fixtures/user';
import type { TimetableRepository } from '@/repositories/timetableRepository';
-import type { UserRepository } from '@/repositories/userRepository';
import { withValidateAccess } from '../utils/access';
@@ -78,7 +77,7 @@ export const handlers = [
),
),
- http.get | CoreServerError>>(
+ http.get(
`*/v1/user/info`,
withValidateAccess(({ token }) => {
const user = mockUsers.find((u) => u.auth.token === token);
diff --git a/apps/snutt-webclient/src/pages/landing/landing-login/index.tsx b/apps/snutt-webclient/src/pages/landing/landing-login/index.tsx
index 7daf73b5..2c295e39 100644
--- a/apps/snutt-webclient/src/pages/landing/landing-login/index.tsx
+++ b/apps/snutt-webclient/src/pages/landing/landing-login/index.tsx
@@ -34,7 +34,11 @@ export const LandingLogin = ({ className, authService, onSignUp }: Props) => {
const handleFacebookSignIn = async (userInfo: ReactFacebookLoginInfo) => {
setErrorMessage('');
- const res = await authService.signIn({ type: 'FACEBOOK', fb_id: userInfo.id, fb_token: userInfo.accessToken });
+ const res = await authService.signIn({
+ type: 'FACEBOOK',
+ facebookId: userInfo.id,
+ facebookToken: userInfo.accessToken,
+ });
if (res.type === 'success') saveToken(res.data.token, keepSignIn);
else setErrorMessage(res.message);
diff --git a/apps/snutt-webclient/src/pages/landing/landing-login/reset-password-dialog/index.tsx b/apps/snutt-webclient/src/pages/landing/landing-login/reset-password-dialog/index.tsx
index ee1c4082..9c675577 100644
--- a/apps/snutt-webclient/src/pages/landing/landing-login/reset-password-dialog/index.tsx
+++ b/apps/snutt-webclient/src/pages/landing/landing-login/reset-password-dialog/index.tsx
@@ -69,7 +69,7 @@ export const LoginResetPasswordDialog = ({ open, onClose, authService }: Props)
size="small"
onClick={() =>
checkEmailMutation.mutate(
- { user_id: id },
+ { userId: id },
{ onSuccess: ({ type }) => type === 'success' && setStep(Step.EMAIL_CONFIRM) },
)
}
@@ -94,7 +94,7 @@ export const LoginResetPasswordDialog = ({ open, onClose, authService }: Props)
onClick={() => {
if (checkEmailMutation.data?.type !== 'success') return;
sendCodeEmailMutation.mutate(
- { user_email: checkEmailMutation.data.data.email },
+ { userEmail: checkEmailMutation.data.data.email },
{ onSuccess: () => setStep(Step.CODE_INPUT) },
);
}}
@@ -122,7 +122,7 @@ export const LoginResetPasswordDialog = ({ open, onClose, authService }: Props)
size="small"
onClick={() =>
verifyCodeMutation.mutate(
- { user_id: id, code },
+ { userId: id, code },
{ onSuccess: ({ type }) => type === 'success' && setStep(Step.RESET_PASSWORD) },
)
}
@@ -148,7 +148,7 @@ export const LoginResetPasswordDialog = ({ open, onClose, authService }: Props)
size="small"
disabled={!password}
onClick={() =>
- resetPasswordMutation.mutate({ user_id: id, password }, { onSuccess: () => setStep(Step.DONE) })
+ resetPasswordMutation.mutate({ userId: id, password }, { onSuccess: () => setStep(Step.DONE) })
}
>
완료
@@ -174,23 +174,23 @@ export const LoginResetPasswordDialog = ({ open, onClose, authService }: Props)
};
const useCheckEmail = (authService: AuthService) => {
- return useMutation({ mutationFn: (body: { user_id: string }) => authService.passwordResetCheckEmail(body) });
+ return useMutation({ mutationFn: (body: { userId: string }) => authService.passwordResetCheckEmail(body) });
};
const useSendCodeEmail = (authService: AuthService) => {
return useMutation({
- mutationFn: (body: { user_email: string }) => authService.sendPasswordResetVerificationEmail(body),
+ mutationFn: (body: { userEmail: string }) => authService.sendPasswordResetVerificationEmail(body),
});
};
const useVerifyCode = (authService: AuthService) => {
return useMutation({
- mutationFn: (body: { user_id: string; code: string }) => authService.verifyPasswordResetCode(body),
+ mutationFn: (body: { userId: string; code: string }) => authService.verifyPasswordResetCode(body),
});
};
const useResetPassword = (authService: AuthService) => {
- return useMutation({ mutationFn: (body: { user_id: string; password: string }) => authService.resetPassword(body) });
+ return useMutation({ mutationFn: (body: { userId: string; password: string }) => authService.resetPassword(body) });
};
const Content = styled(Dialog.Content)`
diff --git a/apps/snutt-webclient/src/pages/mypage/index.tsx b/apps/snutt-webclient/src/pages/mypage/index.tsx
index 4c7d9aab..a5575a20 100644
--- a/apps/snutt-webclient/src/pages/mypage/index.tsx
+++ b/apps/snutt-webclient/src/pages/mypage/index.tsx
@@ -9,10 +9,9 @@ import { Button } from '@/components/button';
import { Layout } from '@/components/layout';
import { envContext } from '@/contexts/EnvContext';
import { serviceContext } from '@/contexts/ServiceContext';
+import { useTokenAuthContext } from '@/contexts/TokenAuthContext';
import { useTokenManageContext } from '@/contexts/TokenManageContext';
-import { type CoreServerError, getErrorMessage } from '@/entities/error';
import { useGuardContext } from '@/hooks/useGuardContext';
-import { queryKey } from '@/utils/query-key-factory';
import { MypageChangePassword } from './mypage-change-password';
import { MypageCloseAccountDialog } from './mypage-close-account-dialog';
@@ -30,7 +29,7 @@ export const MyPage = () => {
const { mutate: attach } = useAttachFacebook();
const { mutate: detach } = useDetachFacebook();
- const isFbOnlyUser = myInfo && userService.isFbOnlyUser(myInfo);
+ const isFbOnlyUser = myInfo?.type === 'success' ? userService.isFbOnlyUser(myInfo.data) : undefined;
const logout = () => {
clearToken();
@@ -70,10 +69,10 @@ export const MyPage = () => {
)}
- {myInfo?.local_id && (
+ {myInfo?.type === 'success' && myInfo.data.localId && (
페이스북
- {myInfo?.fb_name ? (
+ {myInfo.data.facebookName ? (
@@ -114,35 +113,41 @@ export const MyPage = () => {
const useMyInfo = () => {
const { userService } = useGuardContext(serviceContext);
+ const { token } = useTokenAuthContext();
return useQuery({
- queryKey: queryKey('user/info'),
- queryFn: () => userService.getUserInfo(),
+ queryKey: ['UserService', 'getUserInfo', { token }] as const,
+ queryFn: ({ queryKey }) => userService.getUserInfo(queryKey[2]),
});
};
const useAttachFacebook = () => {
const { saveToken } = useTokenManageContext();
const { userService } = useGuardContext(serviceContext);
+ const { token } = useTokenAuthContext();
return useMutation({
mutationFn: (userInfo: ReactFacebookLoginInfo) => {
- return userService.attachFacebookAccount({ fb_id: userInfo.id, fb_token: userInfo.accessToken });
+ return userService.attachFacebookAccount({ facebookId: userInfo.id, facebookToken: userInfo.accessToken, token });
+ },
+ onSuccess: (data) => {
+ if (data.type === 'success') saveToken(data.data.token, false);
+ else alert(data.message);
},
- onSuccess: ({ token }) => saveToken(token, false),
- onError: (error) => alert(getErrorMessage(error as unknown as CoreServerError)),
});
};
const useDetachFacebook = () => {
const { saveToken } = useTokenManageContext();
-
+ const { token } = useTokenAuthContext();
const { userService } = useGuardContext(serviceContext);
return useMutation({
- mutationFn: () => userService.detachFacebookAccount(),
- onSuccess: ({ token }) => saveToken(token, false),
- onError: (error) => alert(getErrorMessage(error as unknown as CoreServerError)),
+ mutationFn: () => userService.detachFacebookAccount({ token }),
+ onSuccess: (data) => {
+ if (data.type === 'success') saveToken(token, false);
+ else alert(data.message);
+ },
});
};
diff --git a/apps/snutt-webclient/src/pages/mypage/mypage-change-password/index.tsx b/apps/snutt-webclient/src/pages/mypage/mypage-change-password/index.tsx
index 7008084d..4f843240 100644
--- a/apps/snutt-webclient/src/pages/mypage/mypage-change-password/index.tsx
+++ b/apps/snutt-webclient/src/pages/mypage/mypage-change-password/index.tsx
@@ -5,11 +5,10 @@ import styled from 'styled-components';
import { Button } from '@/components/button';
import { ErrorDialog } from '@/components/error-dialog';
import { serviceContext } from '@/contexts/ServiceContext';
+import { useTokenAuthContext } from '@/contexts/TokenAuthContext';
import { useTokenManageContext } from '@/contexts/TokenManageContext';
-import { getErrorMessage } from '@/entities/error';
import { useErrorDialog } from '@/hooks/useErrorDialog';
import { useGuardContext } from '@/hooks/useGuardContext';
-import { get } from '@/utils/object/get';
export const MypageChangePassword = () => {
const [currentPassword, setCurrentPassword] = useState('');
@@ -34,16 +33,19 @@ export const MypageChangePassword = () => {
}
mutate(
- { old_password: currentPassword, new_password: newPassword },
+ { oldPassword: currentPassword, newPassword },
{
- onSuccess: ({ token }) => {
- alert('비밀번호가 변경되었습니다.');
- setCurrentPassword('');
- setNewPassword('');
- setNewPasswordConfirm('');
- saveToken(token, false);
+ onSuccess: (data) => {
+ if (data.type === 'success') {
+ alert('비밀번호가 변경되었습니다.');
+ setCurrentPassword('');
+ setNewPassword('');
+ setNewPasswordConfirm('');
+ saveToken(data.data.token, false);
+ } else {
+ open(data.message);
+ }
},
- onError: (err) => open(getErrorMessage({ errcode: get(err, ['errcode']) as number })),
},
);
};
@@ -82,8 +84,9 @@ export const MypageChangePassword = () => {
const useChangePassword = () => {
const { authService } = useGuardContext(serviceContext);
+ const { token } = useTokenAuthContext();
return useMutation({
- mutationFn: (body: { old_password: string; new_password: string }) => authService.changePassword(body),
+ mutationFn: (body: { oldPassword: string; newPassword: string }) => authService.changePassword({ ...body, token }),
});
};
diff --git a/apps/snutt-webclient/src/pages/mypage/mypage-close-account-dialog/index.tsx b/apps/snutt-webclient/src/pages/mypage/mypage-close-account-dialog/index.tsx
index 076a90a7..e8865382 100644
--- a/apps/snutt-webclient/src/pages/mypage/mypage-close-account-dialog/index.tsx
+++ b/apps/snutt-webclient/src/pages/mypage/mypage-close-account-dialog/index.tsx
@@ -6,6 +6,7 @@ import styled from 'styled-components';
import { Button } from '@/components/button';
import { Dialog } from '@/components/dialog';
import { serviceContext } from '@/contexts/ServiceContext';
+import { useTokenAuthContext } from '@/contexts/TokenAuthContext';
import { useTokenManageContext } from '@/contexts/TokenManageContext';
import { useGuardContext } from '@/hooks/useGuardContext';
@@ -63,8 +64,10 @@ export const MypageCloseAccountDialog = ({ onClose, isOpen }: Props) => {
const useCloseAccount = () => {
const { authService } = useGuardContext(serviceContext);
+ const { token } = useTokenAuthContext();
+
return useMutation({
- mutationFn: () => authService.closeAccount(),
+ mutationFn: () => authService.closeAccount({ token }),
});
};
diff --git a/apps/snutt-webclient/src/pages/mypage/mypage-register-id/index.tsx b/apps/snutt-webclient/src/pages/mypage/mypage-register-id/index.tsx
index e65a1800..44aaaeb3 100644
--- a/apps/snutt-webclient/src/pages/mypage/mypage-register-id/index.tsx
+++ b/apps/snutt-webclient/src/pages/mypage/mypage-register-id/index.tsx
@@ -5,6 +5,7 @@ import styled from 'styled-components';
import { Button } from '@/components/button';
import { ErrorDialog } from '@/components/error-dialog';
import { serviceContext } from '@/contexts/ServiceContext';
+import { useTokenAuthContext } from '@/contexts/TokenAuthContext';
import { useTokenManageContext } from '@/contexts/TokenManageContext';
import { getErrorMessage } from '@/entities/error';
import { useErrorDialog } from '@/hooks/useErrorDialog';
@@ -71,10 +72,12 @@ const useAddIdPassword = () => {
const { saveToken } = useTokenManageContext();
const queryClient = useQueryClient();
const { userService } = useGuardContext(serviceContext);
+ const { token } = useTokenAuthContext();
return useMutation({
- mutationFn: (body: { id: string; password: string }) => userService.addIdPassword(body),
- onSuccess: ({ token }) => {
+ mutationFn: (body: { id: string; password: string }) => userService.addIdPassword({ ...body, token }),
+ onSuccess: (data) => {
+ if (data.type === 'error') return;
saveToken(token, false);
return queryClient.invalidateQueries();
},
diff --git a/apps/snutt-webclient/src/repositories/userRepository.ts b/apps/snutt-webclient/src/repositories/userRepository.ts
deleted file mode 100644
index acc3ec1b..00000000
--- a/apps/snutt-webclient/src/repositories/userRepository.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import type { HttpClient } from '@/clients/HttpClient';
-import type { User } from '@/entities/user';
-
-export interface UserRepository {
- getUserInfo(): Promise;
- deleteUser(): Promise<{ message: 'ok' }>;
- changePassword(body: { old_password: string; new_password: string }): Promise<{ token: string }>;
- attachFacebookAccount(body: { fb_id: string; fb_token: string }): Promise<{ token: string }>;
- detachFacebookAccount(): Promise<{ token: string }>;
- addIdPassword(body: { id: string; password: string }): Promise<{ token: string }>;
-}
-
-export const getUserRepository = ({ httpClient }: { httpClient: HttpClient }): UserRepository => {
- return {
- getUserInfo: async () => (await httpClient.get('/v1/user/info')).data,
- deleteUser: async () => (await httpClient.delete<{ message: 'ok' }>('/v1/user/account')).data,
- changePassword: async (body) => (await httpClient.put<{ token: string }>('/v1/user/password', body)).data,
- addIdPassword: async (body) => (await httpClient.post<{ token: string }>('/v1/user/password', body)).data,
- attachFacebookAccount: async (body) => (await httpClient.post<{ token: string }>('/v1/user/facebook', body)).data,
- detachFacebookAccount: async () => (await httpClient.delete<{ token: string }>('/v1/user/facebook')).data,
- };
-};
diff --git a/apps/snutt-webclient/src/usecases/authService.ts b/apps/snutt-webclient/src/usecases/authService.ts
index a547e1fb..9fdb1eca 100644
--- a/apps/snutt-webclient/src/usecases/authService.ts
+++ b/apps/snutt-webclient/src/usecases/authService.ts
@@ -1,47 +1,58 @@
import { getErrorMessage } from '@/entities/error';
import { type RepositoryResponse, type UsecaseResponse } from '@/entities/response';
-import { type UserRepository } from '@/repositories/userRepository';
export interface AuthService {
isValidPassword(password: string): boolean;
- changePassword(body: { old_password: string; new_password: string }): Promise<{ token: string }>;
+ changePassword(body: { oldPassword: string; newPassword: string; token: string }): UsecaseResponse<{ token: string }>;
signIn(
- params: { type: 'LOCAL'; id: string; password: string } | { type: 'FACEBOOK'; fb_id: string; fb_token: string },
+ params:
+ | { type: 'LOCAL'; id: string; password: string }
+ | { type: 'FACEBOOK'; facebookId: string; facebookToken: string },
): UsecaseResponse<{ token: string }>;
signUp(body: { id: string; password: string }): UsecaseResponse<{ token: string }>;
- closeAccount(): Promise<{ message: 'ok' }>;
+ closeAccount(_: { token: string }): UsecaseResponse;
findIdByEmail(body: { email: string }): UsecaseResponse;
- passwordResetCheckEmail(body: { user_id: string }): UsecaseResponse<{ email: string }>;
- sendPasswordResetVerificationEmail(body: { user_email: string }): Promise<{ message: 'ok' }>;
- verifyPasswordResetCode(body: { user_id: string; code: string }): UsecaseResponse;
- resetPassword(body: { user_id: string; password: string }): Promise<{ message: 'ok' }>;
+ passwordResetCheckEmail(body: { userId: string }): UsecaseResponse<{ email: string }>;
+ sendPasswordResetVerificationEmail(body: { userEmail: string }): Promise<{ message: 'ok' }>;
+ verifyPasswordResetCode(body: { userId: string; code: string }): UsecaseResponse;
+ resetPassword(body: { userId: string; password: string }): Promise<{ message: 'ok' }>;
}
-type Deps = {
+export const getAuthService = ({
+ authRepository,
+}: {
authRepository: {
signInWithIdPassword(args: { id: string; password: string }): RepositoryResponse<{ token: string }>;
- signInWithFacebook(args: { fb_id: string; fb_token: string }): RepositoryResponse<{ token: string }>;
+ signInWithFacebook(args: { facebookId: string; facebookToken: string }): RepositoryResponse<{ token: string }>;
signUpWithIdPassword(body: { id: string; password: string }): RepositoryResponse<{ token: string }>;
findId(body: { email: string }): RepositoryResponse;
- passwordResetCheckEmail(body: { user_id: string }): RepositoryResponse<{ email: string }>;
- sendPasswordResetVerificationEmail(body: { user_email: string }): RepositoryResponse<{ message: 'ok' }>;
- verifyPasswordResetCode(body: { user_id: string; code: string }): RepositoryResponse;
- resetPassword(body: { user_id: string; password: string }): RepositoryResponse<{ message: 'ok' }>;
+ passwordResetCheckEmail(body: { userId: string }): RepositoryResponse<{ email: string }>;
+ sendPasswordResetVerificationEmail(body: { userEmail: string }): RepositoryResponse<{ message: 'ok' }>;
+ verifyPasswordResetCode(body: { userId: string; code: string }): RepositoryResponse;
+ resetPassword(body: { userId: string; password: string }): RepositoryResponse<{ message: 'ok' }>;
+ deleteUser(_: { token: string }): RepositoryResponse;
+ changePassword(body: {
+ oldPassword: string;
+ newPassword: string;
+ token: string;
+ }): RepositoryResponse<{ token: string }>;
};
- userRepository: UserRepository;
-};
-export const getAuthService = ({ authRepository, userRepository }: Deps): AuthService => {
+}): AuthService => {
return {
isValidPassword: (password) =>
password.split('').some((item) => /[0-9]+/.test(item)) &&
password.split('').some((item) => /[a-zA-Z]+/.test(item)) &&
password.length >= 6 &&
password.length <= 20,
- changePassword: async (body) => userRepository.changePassword(body),
+ changePassword: async (body) => {
+ const data = await authRepository.changePassword(body);
+ if (data.type === 'success') return { type: 'success', data: data.data };
+ else return { type: 'error', message: getErrorMessage(data) };
+ },
signIn: async (params) => {
const data = await (params.type === 'LOCAL'
? authRepository.signInWithIdPassword({ id: params.id, password: params.password })
- : authRepository.signInWithFacebook({ fb_id: params.fb_id, fb_token: params.fb_token }));
+ : authRepository.signInWithFacebook({ facebookId: params.facebookId, facebookToken: params.facebookToken }));
if (data.type === 'success') return { type: 'success', data: data.data };
else return { type: 'error', message: getErrorMessage(data) };
@@ -51,7 +62,11 @@ export const getAuthService = ({ authRepository, userRepository }: Deps): AuthSe
if (data.type === 'success') return { type: 'success', data: data.data };
else return { type: 'error', message: getErrorMessage(data) };
},
- closeAccount: () => userRepository.deleteUser(),
+ closeAccount: async ({ token }) => {
+ const data = await authRepository.deleteUser({ token });
+ if (data.type === 'success') return { type: 'success' };
+ else return { type: 'error', message: getErrorMessage(data) };
+ },
findIdByEmail: async (body) => {
const data = await authRepository.findId(body);
if (data.type === 'success') return { type: 'success' };
diff --git a/apps/snutt-webclient/src/usecases/userService.ts b/apps/snutt-webclient/src/usecases/userService.ts
index 6cecd012..18c51510 100644
--- a/apps/snutt-webclient/src/usecases/userService.ts
+++ b/apps/snutt-webclient/src/usecases/userService.ts
@@ -1,21 +1,54 @@
+import { getErrorMessage } from '@/entities/error';
+import { type RepositoryResponse, type UsecaseResponse } from '@/entities/response';
import { type User } from '@/entities/user';
-import { type UserRepository } from '@/repositories/userRepository';
export interface UserService {
- getUserInfo(): Promise;
- addIdPassword(body: { id: string; password: string }): Promise<{ token: string }>;
- attachFacebookAccount(body: { fb_id: string; fb_token: string }): Promise<{ token: string }>;
- detachFacebookAccount(): Promise<{ token: string }>;
+ getUserInfo(_: { token: string }): UsecaseResponse;
+ addIdPassword(body: { id: string; password: string; token: string }): UsecaseResponse<{ token: string }>;
+ attachFacebookAccount(body: {
+ facebookId: string;
+ facebookToken: string;
+ token: string;
+ }): UsecaseResponse<{ token: string }>;
+ detachFacebookAccount(_: { token: string }): UsecaseResponse<{ token: string }>;
isFbOnlyUser(user: User): boolean;
}
-type Deps = { repositories: [UserRepository] };
-export const getUserService = ({ repositories: [userRepository] }: Deps): UserService => {
+export const getUserService = ({
+ userRepository,
+}: {
+ userRepository: {
+ getUserInfo(_: { token: string }): RepositoryResponse;
+ attachFacebookAccount(body: {
+ facebookId: string;
+ facebookToken: string;
+ token: string;
+ }): RepositoryResponse<{ token: string }>;
+ detachFacebookAccount(_: { token: string }): RepositoryResponse<{ token: string }>;
+ addIdPassword(body: { id: string; password: string; token: string }): RepositoryResponse<{ token: string }>;
+ };
+}): UserService => {
return {
- getUserInfo: () => userRepository.getUserInfo(),
- addIdPassword: (body) => userRepository.addIdPassword(body),
- attachFacebookAccount: (body: { fb_id: string; fb_token: string }) => userRepository.attachFacebookAccount(body),
- detachFacebookAccount: () => userRepository.detachFacebookAccount(),
- isFbOnlyUser: (user) => !!user.fb_name && !user.local_id,
+ getUserInfo: async ({ token }) => {
+ const data = await userRepository.getUserInfo({ token });
+ if (data.type === 'success') return { type: 'success', data: data.data };
+ else return { type: 'error', message: getErrorMessage(data) };
+ },
+ addIdPassword: async (body) => {
+ const data = await userRepository.addIdPassword(body);
+ if (data.type === 'success') return { type: 'success', data: data.data };
+ else return { type: 'error', message: getErrorMessage(data) };
+ },
+ attachFacebookAccount: async (body) => {
+ const data = await userRepository.attachFacebookAccount(body);
+ if (data.type === 'success') return { type: 'success', data: data.data };
+ else return { type: 'error', message: getErrorMessage(data) };
+ },
+ detachFacebookAccount: async ({ token }) => {
+ const data = await userRepository.detachFacebookAccount({ token });
+ if (data.type === 'success') return { type: 'success', data: data.data };
+ else return { type: 'error', message: getErrorMessage(data) };
+ },
+ isFbOnlyUser: (user) => !!user.facebookName && !user.localId,
};
};
diff --git a/packages/snutt-api/src/apis/snutt-timetable/index.ts b/packages/snutt-api/src/apis/snutt-timetable/index.ts
index 35c99a24..cfe9f25e 100644
--- a/packages/snutt-api/src/apis/snutt-timetable/index.ts
+++ b/packages/snutt-api/src/apis/snutt-timetable/index.ts
@@ -1,6 +1,14 @@
import { Api, GetApiSpecsParameter } from '..';
import { SuccessResponse, ErrorResponse } from '../../response';
-import { LocalLoginRequest, LoginResponse, NotificationResponse, SearchQueryLegacy, LectureDto } from './schemas';
+import {
+ LocalLoginRequest,
+ LoginResponse,
+ NotificationResponse,
+ SearchQueryLegacy,
+ LectureDto,
+ UserLegacyDto,
+ OkResponse,
+} from './schemas';
export const getSnuttTimetableApis = ({ callWithToken, callWithoutToken }: GetApiSpecsParameter) =>
({
@@ -11,11 +19,23 @@ export const getSnuttTimetableApis = ({ callWithToken, callWithoutToken }: GetAp
body,
}),
'POST /v1/auth/register_local': ({ body }: { body: { id: string; password: string } }) =>
- callWithoutToken | ErrorResponse<403, 1229>>({
+ callWithoutToken | ErrorResponse<403, 1229>>({
method: 'post',
path: `/v1/auth/register_local`,
body,
}),
+ 'DELETE /v1/user/account': ({ token }: { token: string }) =>
+ callWithToken>({
+ method: 'delete',
+ path: `/v1/user/account`,
+ token,
+ }),
+ 'GET /v1/user/info': ({ token }: { token: string }) =>
+ callWithToken>({
+ method: 'get',
+ path: `/v1/user/info`,
+ token,
+ }),
'GET /v1/notification': ({ token }: { token: string }) =>
callWithToken>({
method: 'get',
diff --git a/packages/snutt-api/src/apis/snutt/index.ts b/packages/snutt-api/src/apis/snutt/index.ts
index 9dde7e2e..3709ec2c 100644
--- a/packages/snutt-api/src/apis/snutt/index.ts
+++ b/packages/snutt-api/src/apis/snutt/index.ts
@@ -79,4 +79,37 @@ export const getSnuttApis = ({ callWithToken, callWithoutToken }: GetApiSpecsPar
path: `/v1/tags/${params.year}/${params.semester}`,
token,
}),
+ 'PUT /v1/user/password': ({
+ body,
+ token,
+ }: {
+ body: { old_password: string; new_password: string };
+ token: string;
+ }) =>
+ callWithToken>({
+ method: 'put',
+ path: `/v1/user/password`,
+ body,
+ token,
+ }),
+ 'POST /v1/user/password': ({ body, token }: { body: { id: string; password: string }; token: string }) =>
+ callWithToken>({
+ method: 'post',
+ path: `/v1/user/password`,
+ body,
+ token,
+ }),
+ 'POST /v1/user/facebook': ({ body, token }: { body: { fb_id: string; fb_token: string }; token: string }) =>
+ callWithToken>({
+ method: 'post',
+ path: `/v1/user/facebook`,
+ body,
+ token,
+ }),
+ 'DELETE /v1/user/facebook': ({ token }: { token: string }) =>
+ callWithToken>({
+ method: 'delete',
+ path: `/v1/user/facebook`,
+ token,
+ }),
}) satisfies Record;