Skip to content

Commit

Permalink
패키지 구조 변경 및 중복 로직 삭제 (#796)
Browse files Browse the repository at this point in the history
* refactor: 패키지 구조 변경

* feat: useForm hook 구현

* refactor: 중복 로직 리팩토링
  • Loading branch information
LJW25 authored and hgo641 committed Apr 23, 2024
1 parent c47b031 commit a665ee5
Showing 151 changed files with 499 additions and 638 deletions.
1 change: 0 additions & 1 deletion frontend-monorepo/packages/hanglog-admin/.prettierrc
Original file line number Diff line number Diff line change
@@ -17,7 +17,6 @@
"^@utils/(.*)$",
"^@api/(.*)$",
"^@mocks/(.*)$",
"^@stories/(.*)$",
"^@router/(.*)$",
"^@store/(.*)$",
"^[./]"
60 changes: 30 additions & 30 deletions frontend-monorepo/packages/hanglog-admin/README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
export default {
// other rules...
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json'],
tsconfigRootDir: __dirname,
},
};
```

- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
export default {
// other rules...
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json'],
tsconfigRootDir: __dirname,
},
};
```

- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import type { PasswordPatchData } from '@type/adminMember';

import { END_POINTS } from '@constants/api';

import { axiosInstance } from '../axiosInstance';
import { axiosInstance } from '../../common/api/axiosInstance';

export interface PatchPasswordParams extends PasswordPatchData {
adminMemberId: number;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Button, Flex, Modal, Theme } from 'hang-log-design-system';

import { useAddAdminMemberForm } from '@hooks/adminMember/useAddAdminMemberForm';
import { useAddAdminMemberForm } from '@/adminMember/hooks/useAddAdminMemberForm';

import CloseIcon from '@assets/svg/close-icon.svg?react';

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Button, Flex, Modal, Theme } from 'hang-log-design-system';

import { useUpdatePasswordForm } from '@hooks/adminMember/useUpdatePasswordForm';
import { useUpdatePasswordForm } from '@/adminMember/hooks/useUpdatePasswordForm';

import CloseIcon from '@assets/svg/close-icon.svg?react';

@@ -24,7 +24,7 @@ interface PasswordUpdateModalProps {
const PasswordUpdateModal = (
{ adminMemberId, isOpen = true, onClose }: PasswordUpdateModalProps
) => {
const { adminMemberInformation, errors, disableError, updateInputValue, handleSubmit } =
const { passwordFormData, errors, disableError, updateInputValue, handleSubmit } =
useUpdatePasswordForm({ adminMemberId: adminMemberId, onSuccess: onClose });

return (
@@ -47,19 +47,19 @@ const PasswordUpdateModal = (
<form css={formStyling} onSubmit={handleSubmit} noValidate>
<Flex styles={{ direction: 'column', gap: Theme.spacer.spacing3, align: 'stretch' }}>
<CurrentPasswordInput
value={adminMemberInformation.currentPassword}
value={passwordFormData.currentPassword}
isError={errors.isCurrentPasswordError}
updateInputValue={updateInputValue}
disableError={() => disableError('isCurrentPasswordError')}
/>
<PasswordInput
value={adminMemberInformation.newPassword}
isError={errors.isPasswordError}
value={passwordFormData.newPassword}
isError={errors.isNewPasswordError}
updateInputValue={updateInputValue}
disableError={() => disableError('isPasswordError')}
/>
<ConfirmPasswordInput
value={adminMemberInformation.confirmPassword}
value={passwordFormData.confirmPassword}
isError={errors.isConfirmPasswordError}
updateInputValue={updateInputValue}
disableError={() => disableError('isConfirmPasswordError')}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type { AdminMemberFormData } from '@type/adminMember';

import { useForm } from '@hooks/useForm';

import { isEmptyString, isValidPassword } from '@utils/validator';

import { useAddAdminMemberMutation } from './useAddAdminMemberMutation';

interface useAddAdminMemberFormParams {
onSuccess?: () => void;
onError?: () => void;
}

export const useAddAdminMemberForm = ({ onSuccess, onError }: useAddAdminMemberFormParams) => {
const addAdminMemberMutation = useAddAdminMemberMutation();

const initialValues: AdminMemberFormData = {
username: '',
adminType: 'ADMIN',
password: '',
confirmPassword: '',
};

const validate = (values: AdminMemberFormData) => {
return {
username: isEmptyString(values.username.trim()),
password: !isValidPassword(values.password.trim()),
confirmPassword: values.password !== values.confirmPassword,
};
};

const submitAction = (
values: AdminMemberFormData,
onSuccess?: () => void,
onError?: () => void
) => {
addAdminMemberMutation.mutate(values, { onSuccess, onError });
};

const { formValues, errors, updateInputValue, disableError, handleSubmit } = useForm(
initialValues,
validate,
submitAction,
{ onSuccess, onError }
);

const adjustedErrors = {
isUsernameError: errors.username,
isPasswordError: errors.password,
isConfirmPasswordError: errors.confirmPassword,
};

return {
adminMemberInformation: formValues,
errors: adjustedErrors,
disableError,
updateInputValue,
handleSubmit,
};
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';

import { postAdminMember } from '@api/adminMember/postAdminMember';
import { postAdminMember } from '@/adminMember/api/postAdminMember';

import type { ErrorResponseData } from '@api/interceptors';

import { useToast } from '../common/useToast';
import { useToast } from '../../common/hooks/useToast';

export const useAddAdminMemberMutation = () => {
const queryClient = useQueryClient();
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useSuspenseQuery } from '@tanstack/react-query';
import type { AxiosError } from 'axios';

import type { AdminMemberData } from '@type/adminMember';
import { getAdminMember } from '@/adminMember/api/getAdminMember';

import { getAdminMember } from '@api/adminMember/getAdminMember';
import type { AdminMemberData } from '@type/adminMember';

export const useAdminMemberQuery = () => {
const { data: adminMemberData } = useSuspenseQuery<AdminMemberData[], AxiosError>({
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { useMutation } from '@tanstack/react-query';

import { patchAdminMemberPassword } from '@api/adminMember/patchAdminMember';
import { patchAdminMemberPassword } from '@/adminMember/api/patchAdminMember';

import type { ErrorResponseData } from '@api/interceptors';

import { useToast } from '../common/useToast';
import { useToast } from '../../common/hooks/useToast';

export const useUpdateAdminMemberPasswordMutation = () => {
const { createToast } = useToast();
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { PasswordPatchData } from '@type/adminMember';

import { useForm } from '@hooks/useForm';

import { isEmptyString, isValidPassword } from '@utils/validator';

import { useUpdateAdminMemberPasswordMutation } from './useUpdateAdminMemberPasswordMutation';

interface useUpdatePasswordFormParams {
adminMemberId: number;
onSuccess?: () => void;
onError?: () => void;
}

export interface PasswordFormData extends PasswordPatchData {
confirmPassword: string;
}

export const useUpdatePasswordForm = (
{ adminMemberId, onSuccess, onError }: useUpdatePasswordFormParams
) => {
const updatePasswordMutation = useUpdateAdminMemberPasswordMutation();

const initialValues: PasswordFormData = {
currentPassword: '',
newPassword: '',
confirmPassword: '',
};

const validate = (values: PasswordFormData) => {
return {
currentPassword: isEmptyString(values.currentPassword.trim()),
newPassword: !isValidPassword(values.newPassword.trim()),
confirmPassword: values.newPassword !== values.confirmPassword,
};
};

const submitAction = (values: PasswordFormData, onSuccess?: () => void, onError?: () => void) => {
updatePasswordMutation.mutate(
{
adminMemberId,
currentPassword: values.currentPassword,
newPassword: values.newPassword,
},
{ onSuccess, onError }
);
};

const { formValues, errors, updateInputValue, disableError, handleSubmit } = useForm(
initialValues,
validate,
submitAction,
{ onSuccess, onError }
);

const adjustedErrors = {
isCurrentPasswordError: errors.currentPassword,
isNewPasswordError: errors.newPassword,
isConfirmPasswordError: errors.confirmPassword,
};

return {
passwordFormData: formValues,
errors: adjustedErrors,
disableError,
updateInputValue,
handleSubmit,
};
};
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Button, Flex, Heading, useOverlay } from 'hang-log-design-system';
import { Suspense, useCallback, useEffect, useState } from 'react';

import AdminMemberAddModal from '@components/adminMember/AdminMemberAddModal/AdminMemberAddModal';
import AdminMemberTable from '@components/adminMember/AdminMemberTable/AdminMemberTable';
import AdminMemberTableSkeleton from '@components/adminMember/AdminMemberTable/AdminMemberTableSkeleton';
import AdminMemberAddModal from '@/adminMember/components/AdminMemberAddModal/AdminMemberAddModal';
import AdminMemberTable from '@/adminMember/components/AdminMemberTable/AdminMemberTable';
import AdminMemberTableSkeleton from '@/adminMember/components/AdminMemberTable/AdminMemberTableSkeleton';
import { useAdminMemberQuery } from '@/adminMember/hooks/useAdminMemberQuery';

import PageNavigation from '@components/common/PageNavigation/PageNavigation';
import SidebarNavigation from '@components/common/SidebarNavigation/SidebarNavigation';

import { useAdminMemberQuery } from '@hooks/api/useAdminMemberQuery';
import { usePageIndex } from '@hooks/common/usePageIndex';
import { usePageIndex } from '@hooks/usePageIndex';

import { TABLE_ROW_LENGTH } from '@constants/ui';

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Button, Flex, Modal, Theme } from 'hang-log-design-system';

import { CategoryData } from '@type/category';
import { useAddCategoryForm } from '@/category/hooks/useAddCategoryForm';

import { useAddCategoryForm } from '@hooks/category/useAddCategoryForm';
import { CategoryData } from '@type/category';

import CloseIcon from '@assets/svg/close-icon.svg?react';

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { CategoryData } from '@type/category';

import { useForm } from '@hooks/useForm';

import { isEmptyString, isEnglish, isInvalidCategoryId, isKorean } from '@utils/validator';

import { useAddCategoryMutation } from './useAddCategoryMutation';
import { useUpdateCategoryMutation } from './useUpdateCategoryMutation';

interface useAddCategoryFormParams {
originalCategoryId?: number;
initialData?: CategoryData;
onSuccess?: () => void;
onError?: () => void;
}

export const useAddCategoryForm = (
{ originalCategoryId, initialData, onSuccess, onError }: useAddCategoryFormParams
) => {
const addCategoryMutation = useAddCategoryMutation();
const updateCategoryMutation = useUpdateCategoryMutation();

const initialValues: CategoryData = initialData ?? {
id: 0,
engName: '',
korName: '',
};

const validate = (values: CategoryData) => {
return {
id: isInvalidCategoryId(values.id),
engName: isEmptyString(values.engName.trim()) || !isEnglish(values.engName),
korName: isEmptyString(values.korName.trim()) || !isKorean(values.korName),
};
};

const submitAction = (values: CategoryData, onSuccess?: () => void, onError?: () => void) => {
if (originalCategoryId !== undefined) {
updateCategoryMutation.mutate({ ...values, id: originalCategoryId }, { onSuccess, onError });
} else {
addCategoryMutation.mutate(values, { onSuccess, onError });
}
};

const { formValues, errors, updateInputValue, disableError, handleSubmit } = useForm(
initialValues,
validate,
submitAction,
{ onSuccess, onError }
);

const adjustedErrors = {
isIdError: errors.id,
isEngNameError: errors.engName,
isKorNameError: errors.korName,
};

return {
categoryInformation: formValues,
errors: adjustedErrors,
disableError,
updateInputValue,
handleSubmit,
};
};
Loading

0 comments on commit a665ee5

Please sign in to comment.