diff --git a/frontend-monorepo/.pnp.cjs b/frontend-monorepo/.pnp.cjs index 985028362..48dacb1cd 100755 --- a/frontend-monorepo/.pnp.cjs +++ b/frontend-monorepo/.pnp.cjs @@ -9848,6 +9848,29 @@ const RAW_RUNTIME_STATE = ],\ "linkType": "SOFT"\ }],\ + ["virtual:6264e4ace59854ecf9b472698c80728bdcc2d10f14544f599ba5efc7fcd6964ec6168fe59fac412c2d471e85c1215f26fcc7078067d892fabf03abcb468d4c65#npm:4.3.0", {\ + "packageLocation": "./.yarn/__virtual__/@trivago-prettier-plugin-sort-imports-virtual-41b758e5dd/0/cache/@trivago-prettier-plugin-sort-imports-npm-4.3.0-622c28680b-42270fb9c8.zip/node_modules/@trivago/prettier-plugin-sort-imports/",\ + "packageDependencies": [\ + ["@trivago/prettier-plugin-sort-imports", "virtual:6264e4ace59854ecf9b472698c80728bdcc2d10f14544f599ba5efc7fcd6964ec6168fe59fac412c2d471e85c1215f26fcc7078067d892fabf03abcb468d4c65#npm:4.3.0"],\ + ["@babel/generator", "npm:7.17.7"],\ + ["@babel/parser", "npm:7.23.9"],\ + ["@babel/traverse", "npm:7.23.2"],\ + ["@babel/types", "npm:7.17.0"],\ + ["@types/prettier", null],\ + ["@types/vue__compiler-sfc", null],\ + ["@vue/compiler-sfc", null],\ + ["javascript-natural-sort", "npm:0.7.1"],\ + ["lodash", "npm:4.17.21"],\ + ["prettier", "npm:3.2.4"]\ + ],\ + "packagePeers": [\ + "@types/prettier",\ + "@types/vue__compiler-sfc",\ + "@vue/compiler-sfc",\ + "prettier"\ + ],\ + "linkType": "HARD"\ + }],\ ["virtual:bfca90541deadef7ca04341b77694a3566f3f74bd9fba48871c271fa573dfe36954ed36daf70be7a147b2df8f86d5f876593eb78f1d8ef71040405a3ef477ede#npm:4.3.0", {\ "packageLocation": "./.yarn/__virtual__/@trivago-prettier-plugin-sort-imports-virtual-f48f9a9d6a/0/cache/@trivago-prettier-plugin-sort-imports-npm-4.3.0-622c28680b-42270fb9c8.zip/node_modules/@trivago/prettier-plugin-sort-imports/",\ "packageDependencies": [\ @@ -18338,6 +18361,7 @@ const RAW_RUNTIME_STATE = ["@storybook/react-vite", "virtual:6264e4ace59854ecf9b472698c80728bdcc2d10f14544f599ba5efc7fcd6964ec6168fe59fac412c2d471e85c1215f26fcc7078067d892fabf03abcb468d4c65#npm:7.6.10"],\ ["@storybook/test", "npm:7.6.10"],\ ["@tanstack/react-query", "virtual:6264e4ace59854ecf9b472698c80728bdcc2d10f14544f599ba5efc7fcd6964ec6168fe59fac412c2d471e85c1215f26fcc7078067d892fabf03abcb468d4c65#npm:5.17.19"],\ + ["@trivago/prettier-plugin-sort-imports", "virtual:6264e4ace59854ecf9b472698c80728bdcc2d10f14544f599ba5efc7fcd6964ec6168fe59fac412c2d471e85c1215f26fcc7078067d892fabf03abcb468d4c65#npm:4.3.0"],\ ["@types/babel__core", "npm:7.20.5"],\ ["@types/babel__preset-env", "npm:7.9.6"],\ ["@types/react", "npm:18.2.48"],\ diff --git a/frontend-monorepo/packages/hanglog-admin/.eslintrc.json b/frontend-monorepo/packages/hanglog-admin/.eslintrc.json index 7b558d471..90f2e4322 100644 --- a/frontend-monorepo/packages/hanglog-admin/.eslintrc.json +++ b/frontend-monorepo/packages/hanglog-admin/.eslintrc.json @@ -1,6 +1,6 @@ { "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], + "plugins": ["@typescript-eslint", "import"], "extends": [ "eslint:recommended", "airbnb", diff --git a/frontend-monorepo/packages/hanglog-admin/.prettierrc b/frontend-monorepo/packages/hanglog-admin/.prettierrc index 4531a5b82..987d9650f 100644 --- a/frontend-monorepo/packages/hanglog-admin/.prettierrc +++ b/frontend-monorepo/packages/hanglog-admin/.prettierrc @@ -4,13 +4,22 @@ "tabWidth": 2, "printWidth": 100, "semi": true, + "plugins": ["@trivago/prettier-plugin-sort-imports"], "importOrder": [ - "^@utils/(.*)$", - "^@api/(.*)$", + "^@/(.*)$", + "^@components/(.*)$", + "^@type/(.*)$", "^@hooks/(.*)$", "^@pages/(.*)$", - "^@components/(.*)$", "^@styles/(.*)$", + "^@constants/(.*)$", + "^@assets/(.*)$", + "^@utils/(.*)$", + "^@api/(.*)$", + "^@mocks/(.*)$", + "^@stories/(.*)$", + "^@router/(.*)$", + "^@store/(.*)$", "^[./]" ], "importOrderSeparation": true, diff --git a/frontend-monorepo/packages/hanglog-admin/package.json b/frontend-monorepo/packages/hanglog-admin/package.json index 739be8bc4..5ca4fdd2f 100644 --- a/frontend-monorepo/packages/hanglog-admin/package.json +++ b/frontend-monorepo/packages/hanglog-admin/package.json @@ -39,6 +39,7 @@ "@storybook/react": "^7.6.10", "@storybook/react-vite": "^7.6.10", "@storybook/test": "^7.6.10", + "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/babel__core": "^7", "@types/babel__preset-env": "^7", "@types/react": "^18.2.43", diff --git a/frontend-monorepo/packages/hanglog-admin/src/App.tsx b/frontend-monorepo/packages/hanglog-admin/src/App.tsx index 911ce62f6..b2ca4f63f 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/App.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/App.tsx @@ -1,8 +1,8 @@ import { Outlet } from 'react-router-dom'; -import Header from '@components/layout/Header/Header'; -import Footer from '@components/layout/Footer/Footer'; import ToastContainer from '@components/common/ToastContainer/ToastContainer'; +import Footer from '@components/layout/Footer/Footer'; +import Header from '@components/layout/Header/Header'; const App = () => { return ( diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/adminMember/getAdminMember.ts b/frontend-monorepo/packages/hanglog-admin/src/api/adminMember/getAdminMember.ts new file mode 100644 index 000000000..8b0639a24 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/api/adminMember/getAdminMember.ts @@ -0,0 +1,10 @@ +import type { AdminMemberData } from '@type/adminMember'; + +import { END_POINTS } from '@constants/api'; + +import { axiosInstance } from '@api/axiosInstance'; + +export const getAdminMember = async () => { + const { data } = await axiosInstance.get(END_POINTS.MEMBER); + return data; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/adminMember/patchAdminMember.ts b/frontend-monorepo/packages/hanglog-admin/src/api/adminMember/patchAdminMember.ts new file mode 100644 index 000000000..3d8f8a555 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/api/adminMember/patchAdminMember.ts @@ -0,0 +1,18 @@ +import type { PasswordPatchData } from '@type/adminMember'; + +import { END_POINTS } from '@constants/api'; + +import { axiosInstance } from '../axiosInstance'; + +export interface PatchPasswordParams extends PasswordPatchData { + adminMemberId: number; +} + +export const patchAdminMemberPassword = ( + { adminMemberId, ...passwordInformation }: PatchPasswordParams +) => { + return axiosInstance.patch( + END_POINTS.CHANGE_MEMBER_PASSWORD(adminMemberId), + passwordInformation + ); +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/adminMember/postAdminMember.ts b/frontend-monorepo/packages/hanglog-admin/src/api/adminMember/postAdminMember.ts new file mode 100644 index 000000000..a055b6930 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/api/adminMember/postAdminMember.ts @@ -0,0 +1,13 @@ +import type { AdminMemberPostData } from '@type/adminMember'; + +import { END_POINTS } from '@constants/api'; + +import { axiosInstance } from '@api/axiosInstance'; + +export const postAdminMember = async (adminMemberFormData: AdminMemberPostData) => { + const response = await axiosInstance.post(END_POINTS.MEMBER, adminMemberFormData); + + const adminMemberId = response.headers.location.replace(`${END_POINTS.MEMBER}/`, ''); + + return adminMemberId; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/axiosInstance.ts b/frontend-monorepo/packages/hanglog-admin/src/api/axiosInstance.ts index b33dc59ce..1aace1e44 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/api/axiosInstance.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/api/axiosInstance.ts @@ -1,9 +1,9 @@ import axios from 'axios'; -import { handleAPIError } from '@api/interceptors'; - import { AXIOS_BASE_URL, NETWORK } from '@constants/api'; +import { handleAPIError } from '@api/interceptors'; + export const axiosInstance = axios.create({ baseURL: AXIOS_BASE_URL, timeout: NETWORK.TIMEOUT, diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/category/getCategory.ts b/frontend-monorepo/packages/hanglog-admin/src/api/category/getCategory.ts new file mode 100644 index 000000000..eb4c5e399 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/api/category/getCategory.ts @@ -0,0 +1,10 @@ +import type { CategoryData } from '@type/category'; + +import { END_POINTS } from '@constants/api'; + +import { axiosInstance } from '@api/axiosInstance'; + +export const getCategory = async () => { + const { data } = await axiosInstance.get(END_POINTS.CATEGORY); + return data; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/category/postCategory.ts b/frontend-monorepo/packages/hanglog-admin/src/api/category/postCategory.ts new file mode 100644 index 000000000..d494154ba --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/api/category/postCategory.ts @@ -0,0 +1,13 @@ +import type { CategoryData } from '@type/category'; + +import { END_POINTS } from '@constants/api'; + +import { axiosInstance } from '@api/axiosInstance'; + +export const postCategory = async (categoryData: CategoryData) => { + const response = await axiosInstance.post(END_POINTS.CATEGORY, categoryData); + + const categoryId = response.headers.location.replace(`${END_POINTS.CATEGORY}/`, ''); + + return categoryId; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/category/putCategeory.ts b/frontend-monorepo/packages/hanglog-admin/src/api/category/putCategeory.ts new file mode 100644 index 000000000..c55ed96c2 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/api/category/putCategeory.ts @@ -0,0 +1,11 @@ +import type { CategoryData } from '@type/category'; + +import { END_POINTS } from '@constants/api'; + +import { axiosInstance } from '@api/axiosInstance'; + +export const putCategory = (category: CategoryData) => { + return axiosInstance.put(END_POINTS.CHANGE_CATEGORY(category.id), { + ...category, + }); +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/city/getCity.ts b/frontend-monorepo/packages/hanglog-admin/src/api/city/getCity.ts index 681052290..923b06141 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/api/city/getCity.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/api/city/getCity.ts @@ -1,9 +1,9 @@ -import { axiosInstance } from '@api/axiosInstance'; - import type { CityData } from '@type/city'; import { END_POINTS } from '@constants/api'; +import { axiosInstance } from '@api/axiosInstance'; + export const getCity = async () => { const { data } = await axiosInstance.get(END_POINTS.CITY); return data; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/city/postCity.ts b/frontend-monorepo/packages/hanglog-admin/src/api/city/postCity.ts index f426dd3d4..d227b2b59 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/api/city/postCity.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/api/city/postCity.ts @@ -1,13 +1,13 @@ -import { axiosInstance } from '@api/axiosInstance'; - import type { CityFormData } from '@type/city'; import { END_POINTS } from '@constants/api'; +import { axiosInstance } from '@api/axiosInstance'; + export const postCity = async (cityFormData: CityFormData) => { const response = await axiosInstance.post(END_POINTS.CITY, cityFormData); - const tripId = response.headers.location.replace(`${END_POINTS.CITY}/`, ''); + const cityId = response.headers.location.replace(`${END_POINTS.CITY}/`, ''); - return tripId; + return cityId; }; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/city/putCity.ts b/frontend-monorepo/packages/hanglog-admin/src/api/city/putCity.ts index 57f20cf07..cc5534f95 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/api/city/putCity.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/api/city/putCity.ts @@ -1,9 +1,9 @@ -import { axiosInstance } from '@api/axiosInstance'; - import type { CityFormData } from '@type/city'; import { END_POINTS } from '@constants/api'; +import { axiosInstance } from '@api/axiosInstance'; + export interface PutCityParams extends CityFormData { cityId: number; } diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/currency/getCurrency.ts b/frontend-monorepo/packages/hanglog-admin/src/api/currency/getCurrency.ts new file mode 100644 index 000000000..8ef7d4aa8 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/api/currency/getCurrency.ts @@ -0,0 +1,10 @@ +import type { CurrencyListData } from '@type/currency'; + +import { END_POINTS } from '@constants/api'; + +import { axiosInstance } from '@api/axiosInstance'; + +export const getCurrency = async (page: number, size: number) => { + const { data } = await axiosInstance.get(END_POINTS.CURRENCY_PAGE(page, size)); + return data; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/currency/postCurrency.ts b/frontend-monorepo/packages/hanglog-admin/src/api/currency/postCurrency.ts new file mode 100644 index 000000000..facf19e19 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/api/currency/postCurrency.ts @@ -0,0 +1,13 @@ +import type { CurrencyFormData } from '@type/currency'; + +import { END_POINTS } from '@constants/api'; + +import { axiosInstance } from '@api/axiosInstance'; + +export const postCurrency = async (currencyFormData: CurrencyFormData) => { + const response = await axiosInstance.post(END_POINTS.CURRENCY, currencyFormData); + + const currencyId = response.headers.location.replace(`${END_POINTS.CURRENCY}/`, ''); + + return currencyId; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/currency/putCurrency.ts b/frontend-monorepo/packages/hanglog-admin/src/api/currency/putCurrency.ts new file mode 100644 index 000000000..120de320b --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/api/currency/putCurrency.ts @@ -0,0 +1,15 @@ +import type { CurrencyFormData } from '@type/currency'; + +import { END_POINTS } from '@constants/api'; + +import { axiosInstance } from '@api/axiosInstance'; + +export interface PutCurrencyParams extends CurrencyFormData { + currencyId: number; +} + +export const putCurrency = ({ currencyId, ...currencyInformation }: PutCurrencyParams) => { + return axiosInstance.put(END_POINTS.CHANGE_CURRENCY(currencyId), { + ...currencyInformation, + }); +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/api/interceptors.ts b/frontend-monorepo/packages/hanglog-admin/src/api/interceptors.ts index 84e9d573f..5ca802778 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/api/interceptors.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/api/interceptors.ts @@ -1,8 +1,9 @@ import type { AxiosError } from 'axios'; -import { HTTPError } from '@api/HTTPError'; import { HTTP_STATUS_CODE } from '@constants/api'; +import { HTTPError } from '@api/HTTPError'; + export interface ErrorResponseData { statusCode?: number; message?: string; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/AdminMemberAddModal.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/AdminMemberAddModal.style.ts new file mode 100644 index 000000000..7491c545f --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/AdminMemberAddModal.style.ts @@ -0,0 +1,42 @@ +import { css } from '@emotion/react'; +import { Theme } from 'hang-log-design-system'; + +export const wrapperStyling = css({ + width: '400px', + minHeight: '528px', + + '@media screen and (max-width: 600px)': { + width: `calc(100vw - ${Theme.spacer.spacing4})`, + height: `80%`, + }, +}); + +export const formStyling = css({ + display: 'flex', + flexDirection: 'column', + gap: Theme.spacer.spacing4, + width: '80%', +}); + +export const buttonStyling = css({ + width: '100%', +}); + +export const closeButtonStyling = css({ + position: 'absolute', + right: Theme.spacer.spacing4, + top: Theme.spacer.spacing4, + alignSelf: 'flex-end', + + marginBottom: Theme.spacer.spacing1, + + border: 'none', + backgroundColor: 'transparent', + + cursor: 'pointer', +}); + +export const closeIconStyling = css({ + width: '16px', + height: '16px', +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/AdminMemberAddModal.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/AdminMemberAddModal.tsx new file mode 100644 index 000000000..443f3caa5 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/AdminMemberAddModal.tsx @@ -0,0 +1,79 @@ +import { Button, Flex, Modal, Theme } from 'hang-log-design-system'; + +import { useAddAdminMemberForm } from '@hooks/adminMember/useAddAdminMemberForm'; + +import CloseIcon from '@assets/svg/close-icon.svg?react'; + +import { + buttonStyling, + closeButtonStyling, + closeIconStyling, + formStyling, + wrapperStyling, +} from './AdminMemberAddModal.style'; +import AdminTypeSelect from './AdminTypeSelect/AdminTypeSelect'; +import ConfirmPasswordInput from './PasswordInput/ConfirmPasswordInput'; +import PasswordInput from './PasswordInput/PasswordInput'; +import UsernameInput from './UsernameInput/UsernameInput'; + +interface AdminMemberAddModalProps { + isOpen?: boolean; + onClose: () => void; +} + +const AdminMemberAddModal = ({ isOpen = true, onClose }: AdminMemberAddModalProps) => { + const { adminMemberInformation, errors, disableError, updateInputValue, handleSubmit } = + useAddAdminMemberForm({ onSuccess: onClose }); + + return ( + <> + + +
+ + disableError('isUsernameError')} + /> + + disableError('isPasswordError')} + /> + disableError('isConfirmPasswordError')} + /> + + +
+
+ + ); +}; + +export default AdminMemberAddModal; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/AdminTypeSelect/AdminTypeSelect.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/AdminTypeSelect/AdminTypeSelect.tsx new file mode 100644 index 000000000..fc6aef6d9 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/AdminTypeSelect/AdminTypeSelect.tsx @@ -0,0 +1,40 @@ +import { Select } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import { AdminMemberFormData, SelectableAdminType } from '@type/adminMember'; + +interface AdminTypeSelectProps { + value: string; + updateInputValue: ( + key: K, + value: AdminMemberFormData[K] + ) => void; +} + +const AdminTypeSelect = ({ value, updateInputValue }: AdminTypeSelectProps) => { + const handleAdminTypeChange = (event: ChangeEvent) => { + const newAdminTypeValue = event.target.value; + updateInputValue('adminType', newAdminTypeValue); + }; + + return ( + + ); +}; + +export default memo(AdminTypeSelect); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/PasswordInput/ConfirmPasswordInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/PasswordInput/ConfirmPasswordInput.tsx new file mode 100644 index 000000000..b89ce2947 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/PasswordInput/ConfirmPasswordInput.tsx @@ -0,0 +1,45 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { AdminMemberFormData } from '@type/adminMember'; + +import { ADMIN_MEMBER_MAX_LENGTH } from '@constants/ui'; + +interface ConfirmPasswordInputProps { + value: string; + isError: boolean; + updateInputValue: ( + key: K, + value: AdminMemberFormData[K] + ) => void; + disableError: () => void; +} + +const ConfirmPasswordInput = ( + { isError, value, updateInputValue, disableError }: ConfirmPasswordInputProps +) => { + const handleConfirmPasswordChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue('confirmPassword', event.target.value); + }; + + return ( + + ); +}; + +export default memo(ConfirmPasswordInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/PasswordInput/PasswordInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/PasswordInput/PasswordInput.tsx new file mode 100644 index 000000000..58f79145b --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/PasswordInput/PasswordInput.tsx @@ -0,0 +1,43 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { AdminMemberFormData } from '@type/adminMember'; + +import { ADMIN_MEMBER_MAX_LENGTH } from '@constants/ui'; + +interface PasswordInputProps { + value: string; + isError: boolean; + updateInputValue: ( + key: K, + value: AdminMemberFormData[K] + ) => void; + disableError: () => void; +} + +const PasswordInput = ({ isError, value, updateInputValue, disableError }: PasswordInputProps) => { + const handlePasswordChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue('password', event.target.value); + }; + + return ( + + ); +}; + +export default memo(PasswordInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/UsernameInput/UsernameInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/UsernameInput/UsernameInput.tsx new file mode 100644 index 000000000..0f5af3c35 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberAddModal/UsernameInput/UsernameInput.tsx @@ -0,0 +1,42 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { AdminMemberFormData } from '@type/adminMember'; + +import { ADMIN_MEMBER_MAX_LENGTH } from '@constants/ui'; + +interface UsernameInputProps { + value: string; + isError: boolean; + updateInputValue: ( + key: K, + value: AdminMemberFormData[K] + ) => void; + disableError: () => void; +} + +const UsernameInput = ({ isError, value, updateInputValue, disableError }: UsernameInputProps) => { + const handleUsernameChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue('username', event.target.value); + }; + + return ( + + ); +}; + +export default memo(UsernameInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberTable/AdminMemberTable.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberTable/AdminMemberTable.style.ts new file mode 100644 index 000000000..81c5efb03 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberTable/AdminMemberTable.style.ts @@ -0,0 +1,11 @@ +import { css } from '@emotion/react'; + +export const tableStyling = css({ + 'th:first-of-type, th:last-of-type': { + width: '20%', + }, + + 'th:not(:first-of-type):not(:last-of-type)': { + width: '30%', + }, +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberTable/AdminMemberTable.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberTable/AdminMemberTable.tsx new file mode 100644 index 000000000..e524f6866 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberTable/AdminMemberTable.tsx @@ -0,0 +1,37 @@ +import type { AdminMemberData } from '@type/adminMember'; + +import PasswordEditButton from '../PasswordEditButton/PasswordEditButton'; +import { tableStyling } from './AdminMemberTable.style'; + +interface AdminmemberTableProps { + adminMembers: AdminMemberData[]; +} + +const AdminMemberTable = ({ adminMembers }: AdminmemberTableProps) => { + return ( + + + + + + + + + + + {adminMembers.map((adminMember) => ( + + + + + + + ))} + +
ID계정명관리자 등급비밀번호 수정
{adminMember.id}{adminMember.username}{adminMember.adminType} + +
+ ); +}; + +export default AdminMemberTable; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberTable/AdminMemberTableSkeleton.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberTable/AdminMemberTableSkeleton.tsx new file mode 100644 index 000000000..f8b0e458b --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/AdminMemberTable/AdminMemberTableSkeleton.tsx @@ -0,0 +1,35 @@ +import { Skeleton } from 'hang-log-design-system'; + +import { tableStyling } from './AdminMemberTable.style'; + +interface AdminMemberTableSkeletonProps { + length: number; +} + +const AdminMemberTableSkeleton = ({ length }: AdminMemberTableSkeletonProps) => { + return ( + + + + + + + + + + + {Array.from({ length }, (_, index) => { + return ( + + + + ); + })} + +
ID계정명관리자 등급비밀번호 수정
+ +
+ ); +}; + +export default AdminMemberTableSkeleton; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/city/CityEditMenu/CityEditMenu.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordEditButton/PasswordEditButton.style.ts similarity index 99% rename from frontend-monorepo/packages/hanglog-admin/src/components/city/CityEditMenu/CityEditMenu.style.ts rename to frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordEditButton/PasswordEditButton.style.ts index 9550b80d5..fa768354e 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/components/city/CityEditMenu/CityEditMenu.style.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordEditButton/PasswordEditButton.style.ts @@ -1,5 +1,4 @@ import { css } from '@emotion/react'; - import { Theme } from 'hang-log-design-system'; export const buttonStyling = css({ diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordEditButton/PasswordEditButton.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordEditButton/PasswordEditButton.tsx new file mode 100644 index 000000000..ff0a78345 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordEditButton/PasswordEditButton.tsx @@ -0,0 +1,30 @@ +import { useOverlay } from 'hang-log-design-system'; + +import EditIcon from '@assets/svg/edit-icon.svg?react'; + +import PasswordUpdateModal from '../PasswordUpdateModal/PasswordUpdateModal'; +import { buttonStyling, editIconStyling } from './PasswordEditButton.style'; + +interface PasswordEditButtonProps { + id: number; +} + +const PasswordEditButton = ({ id }: PasswordEditButtonProps) => { + const { isOpen: isEditModalOpen, open: openEditModal, close: closeEditModal } = useOverlay(); + + return ( + <> + + {isEditModalOpen && } + + ); +}; + +export default PasswordEditButton; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordInput/ConfirmPasswordInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordInput/ConfirmPasswordInput.tsx new file mode 100644 index 000000000..25adde850 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordInput/ConfirmPasswordInput.tsx @@ -0,0 +1,42 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { PasswordFormData } from '@type/adminMember'; + +import { ADMIN_MEMBER_MAX_LENGTH } from '@constants/ui'; + +interface ConfirmPasswordInputProps { + value: string; + isError: boolean; + updateInputValue: (key: K, value: PasswordFormData[K]) => void; + disableError: () => void; +} + +const ConfirmPasswordInput = ( + { isError, value, updateInputValue, disableError }: ConfirmPasswordInputProps +) => { + const handleConfirmPasswordChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue('confirmPassword', event.target.value); + }; + + return ( + + ); +}; + +export default memo(ConfirmPasswordInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordInput/CurrentPasswordInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordInput/CurrentPasswordInput.tsx new file mode 100644 index 000000000..f6947a779 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordInput/CurrentPasswordInput.tsx @@ -0,0 +1,42 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { PasswordFormData } from '@type/adminMember'; + +import { ADMIN_MEMBER_MAX_LENGTH } from '@constants/ui'; + +interface CurrentPasswordInputProps { + value: string; + isError: boolean; + updateInputValue: (key: K, value: PasswordFormData[K]) => void; + disableError: () => void; +} + +const CurrentPasswordInput = ( + { isError, value, updateInputValue, disableError }: CurrentPasswordInputProps +) => { + const handleCurrentPasswordChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue('currentPassword', event.target.value); + }; + + return ( + + ); +}; + +export default memo(CurrentPasswordInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordInput/PasswordInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordInput/PasswordInput.tsx new file mode 100644 index 000000000..a2dd6e51f --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordInput/PasswordInput.tsx @@ -0,0 +1,40 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { PasswordFormData } from '@type/adminMember'; + +import { ADMIN_MEMBER_MAX_LENGTH } from '@constants/ui'; + +interface PasswordInputProps { + value: string; + isError: boolean; + updateInputValue: (key: K, value: PasswordFormData[K]) => void; + disableError: () => void; +} + +const PasswordInput = ({ isError, value, updateInputValue, disableError }: PasswordInputProps) => { + const handlePasswordChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue('newPassword', event.target.value); + }; + + return ( + + ); +}; + +export default memo(PasswordInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordUpdateModal.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordUpdateModal.style.ts new file mode 100644 index 000000000..bbb3d1057 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordUpdateModal.style.ts @@ -0,0 +1,42 @@ +import { css } from '@emotion/react'; +import { Theme } from 'hang-log-design-system'; + +export const wrapperStyling = css({ + width: '400px', + minHeight: '428px', + + '@media screen and (max-width: 600px)': { + width: `calc(100vw - ${Theme.spacer.spacing4})`, + height: `80%`, + }, +}); + +export const formStyling = css({ + display: 'flex', + flexDirection: 'column', + gap: Theme.spacer.spacing4, + width: '80%', +}); + +export const buttonStyling = css({ + width: '100%', +}); + +export const closeButtonStyling = css({ + position: 'absolute', + right: Theme.spacer.spacing4, + top: Theme.spacer.spacing4, + alignSelf: 'flex-end', + + marginBottom: Theme.spacer.spacing1, + + border: 'none', + backgroundColor: 'transparent', + + cursor: 'pointer', +}); + +export const closeIconStyling = css({ + width: '16px', + height: '16px', +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordUpdateModal.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordUpdateModal.tsx new file mode 100644 index 000000000..912fa9299 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/adminMember/PasswordUpdateModal/PasswordUpdateModal.tsx @@ -0,0 +1,77 @@ +import { Button, Flex, Modal, Theme } from 'hang-log-design-system'; + +import { useUpdatePasswordForm } from '@hooks/adminMember/useUpdatePasswordForm'; + +import CloseIcon from '@assets/svg/close-icon.svg?react'; + +import ConfirmPasswordInput from './PasswordInput/ConfirmPasswordInput'; +import CurrentPasswordInput from './PasswordInput/CurrentPasswordInput'; +import PasswordInput from './PasswordInput/PasswordInput'; +import { + buttonStyling, + closeButtonStyling, + closeIconStyling, + formStyling, + wrapperStyling, +} from './PasswordUpdateModal.style'; + +interface PasswordUpdateModalProps { + adminMemberId: number; + isOpen?: boolean; + onClose: () => void; +} + +const PasswordUpdateModal = ( + { adminMemberId, isOpen = true, onClose }: PasswordUpdateModalProps +) => { + const { adminMemberInformation, errors, disableError, updateInputValue, handleSubmit } = + useUpdatePasswordForm({ adminMemberId: adminMemberId, onSuccess: onClose }); + + return ( + <> + + +
+ + disableError('isCurrentPasswordError')} + /> + disableError('isPasswordError')} + /> + disableError('isConfirmPasswordError')} + /> + + +
+
+ + ); +}; + +export default PasswordUpdateModal; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/CategoryAddModal.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/CategoryAddModal.style.ts new file mode 100644 index 000000000..bb9e9e8e2 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/CategoryAddModal.style.ts @@ -0,0 +1,42 @@ +import { css } from '@emotion/react'; +import { Theme } from 'hang-log-design-system'; + +export const wrapperStyling = css({ + width: '400px', + minHeight: '420px', + + '@media screen and (max-width: 600px)': { + width: `calc(100vw - ${Theme.spacer.spacing4})`, + height: `50%`, + }, +}); + +export const formStyling = css({ + display: 'flex', + flexDirection: 'column', + gap: Theme.spacer.spacing4, + width: '80%', +}); + +export const buttonStyling = css({ + width: '100%', +}); + +export const closeButtonStyling = css({ + position: 'absolute', + right: Theme.spacer.spacing4, + top: Theme.spacer.spacing4, + alignSelf: 'flex-end', + + marginBottom: Theme.spacer.spacing1, + + border: 'none', + backgroundColor: 'transparent', + + cursor: 'pointer', +}); + +export const closeIconStyling = css({ + width: '16px', + height: '16px', +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/CategoryAddModal.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/CategoryAddModal.tsx new file mode 100644 index 000000000..078d5ae41 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/CategoryAddModal.tsx @@ -0,0 +1,84 @@ +import { Button, Flex, Modal, Theme } from 'hang-log-design-system'; + +import { CategoryData } from '@type/category'; + +import { useAddCategoryForm } from '@hooks/category/useAddCategoryForm'; + +import CloseIcon from '@assets/svg/close-icon.svg?react'; + +import { + buttonStyling, + closeButtonStyling, + closeIconStyling, + formStyling, + wrapperStyling, +} from './CategoryAddModal.style'; +import EngNameInput from './EngNameInput/EngNameInput'; +import IdInput from './IdInput/IdInput'; +import KorNameInput from './KorNameInput/KorNameInput'; + +interface CategoryAddModalProps { + originalCategoryId?: number; + initialData?: CategoryData; + isOpen?: boolean; + onClose: () => void; +} + +const CategoryAddModal = ( + { originalCategoryId, initialData, isOpen = true, onClose }: CategoryAddModalProps +) => { + const { categoryInformation, errors, disableError, updateInputValue, handleSubmit } = + useAddCategoryForm({ + originalCategoryId, + initialData, + onSuccess: onClose, + }); + + return ( + <> + + +
+ + disableError('isIdError')} + /> + disableError('isEngNameError')} + /> + disableError('isKorNameError')} + /> + + +
+
+ + ); +}; + +export default CategoryAddModal; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/EngNameInput/EngNameInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/EngNameInput/EngNameInput.tsx new file mode 100644 index 000000000..8c3acd7b8 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/EngNameInput/EngNameInput.tsx @@ -0,0 +1,39 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { CategoryData } from '@type/category'; + +import { CATEGORY_NAME_MAX } from '@constants/ui'; + +interface EngNameInputProps { + value: string; + isError: boolean; + updateInputValue: (key: K, value: CategoryData[K]) => void; + disableError: () => void; +} + +const EngNameInput = ({ isError, value, updateInputValue, disableError }: EngNameInputProps) => { + const handleEngNameChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue('engName', event.target.value); + }; + + return ( + + ); +}; + +export default memo(EngNameInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/IdInput/IdInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/IdInput/IdInput.tsx new file mode 100644 index 000000000..293e7b655 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/IdInput/IdInput.tsx @@ -0,0 +1,41 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { CategoryData } from '@type/category'; + +import { CATEGORY_ID_MAX, CATEGORY_ID_MIN } from '@constants/ui'; + +interface IdInputProps { + value: number; + isError: boolean; + updateInputValue: (key: K, value: CategoryData[K]) => void; + disableError: () => void; +} + +const IdInput = ({ isError, value, updateInputValue, disableError }: IdInputProps) => { + const handleIdChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue('id', Number(event.target.value)); + }; + + return ( + + ); +}; + +export default memo(IdInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/KorNameInput/KorNameInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/KorNameInput/KorNameInput.tsx new file mode 100644 index 000000000..3cfcb6bcb --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryAddModal/KorNameInput/KorNameInput.tsx @@ -0,0 +1,39 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { CategoryData } from '@type/category'; + +import { CATEGORY_NAME_MAX } from '@constants/ui'; + +interface KorNameInputProps { + value: string; + isError: boolean; + updateInputValue: (key: K, value: CategoryData[K]) => void; + disableError: () => void; +} + +const KorNameInput = ({ isError, value, updateInputValue, disableError }: KorNameInputProps) => { + const handleKorNameChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue('korName', event.target.value); + }; + + return ( + + ); +}; + +export default memo(KorNameInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryEditButton/CategoryEditButton.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryEditButton/CategoryEditButton.style.ts new file mode 100644 index 000000000..fa768354e --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryEditButton/CategoryEditButton.style.ts @@ -0,0 +1,28 @@ +import { css } from '@emotion/react'; +import { Theme } from 'hang-log-design-system'; + +export const buttonStyling = css({ + width: '20px', + height: '20px', + border: 'none', + outline: 0, + + backgroundColor: 'transparent', + + cursor: 'pointer', + + '& svg': { + width: '20px', + height: '20px', + }, +}); + +export const editIconStyling = css({ + '& path': { + fill: Theme.color.gray600, + }, + + '&:hover path': { + fill: Theme.color.gray800, + }, +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryEditButton/CategoryEditButton.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryEditButton/CategoryEditButton.tsx new file mode 100644 index 000000000..dea2ab042 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryEditButton/CategoryEditButton.tsx @@ -0,0 +1,34 @@ +import { useOverlay } from 'hang-log-design-system'; + +import type { CategoryData } from '@type/category'; + +import EditIcon from '@assets/svg/edit-icon.svg?react'; + +import CategoryAddModal from '../CategoryAddModal/CategoryAddModal'; +import { buttonStyling, editIconStyling } from './CategoryEditButton.style'; + +const CategoryEditButton = ({ ...information }: CategoryData) => { + const { isOpen: isEditModalOpen, open: openEditModal, close: closeEditModal } = useOverlay(); + + return ( + <> + + {isEditModalOpen && ( + + )} + + ); +}; + +export default CategoryEditButton; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryTable/CategoryTable.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryTable/CategoryTable.style.ts new file mode 100644 index 000000000..332a3a402 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryTable/CategoryTable.style.ts @@ -0,0 +1,11 @@ +import { css } from '@emotion/react'; + +export const tableStyling = css({ + 'th:first-of-type, th:last-of-type': { + width: '15%', + }, + + 'th:not(:first-of-type):not(:last-of-type)': { + width: '35%', + }, +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryTable/CategoryTable.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryTable/CategoryTable.tsx new file mode 100644 index 000000000..fff4861dd --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryTable/CategoryTable.tsx @@ -0,0 +1,37 @@ +import type { CategoryData } from '@type/category'; + +import CategoryEditButton from '../CategoryEditButton/CategoryEditButton'; +import { tableStyling } from './CategoryTable.style'; + +interface CategoryTableProps { + categories: CategoryData[]; +} + +const CategoryTable = ({ categories }: CategoryTableProps) => { + return ( + + + + + + + + + + + {categories.map((category) => ( + + + + + + + ))} + +
ID영문명국문명
{category.id}{category.engName}{category.korName} + +
+ ); +}; + +export default CategoryTable; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryTable/CategoryTableSkeleton.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryTable/CategoryTableSkeleton.tsx new file mode 100644 index 000000000..75759261f --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/category/CategoryTable/CategoryTableSkeleton.tsx @@ -0,0 +1,35 @@ +import { Skeleton } from 'hang-log-design-system'; + +import { tableStyling } from './CategoryTable.style'; + +interface CategoryTableSkeletonProps { + length: number; +} + +const CategoryTableSkeleton = ({ length }: CategoryTableSkeletonProps) => { + return ( + + + + + + + + + + + {Array.from({ length }, (_, index) => { + return ( + + + + ); + })} + +
ID영문명국문명
+ +
+ ); +}; + +export default CategoryTableSkeleton; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/city/CityAddModal/CityAddModal.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/city/CityAddModal/CityAddModal.style.ts index be1ad5696..7491c545f 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/components/city/CityAddModal/CityAddModal.style.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/components/city/CityAddModal/CityAddModal.style.ts @@ -1,5 +1,4 @@ import { css } from '@emotion/react'; - import { Theme } from 'hang-log-design-system'; export const wrapperStyling = css({ diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/city/CityAddModal/CityAddModal.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/city/CityAddModal/CityAddModal.tsx index 74ba6a9b6..16dcf39bd 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/components/city/CityAddModal/CityAddModal.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/components/city/CityAddModal/CityAddModal.tsx @@ -1,23 +1,22 @@ import { Button, Flex, Modal, Theme } from 'hang-log-design-system'; -import { UseAddCityForm } from '@/hooks/city/useAddCityForm'; +import type { CityFormData } from '@type/city'; -import type { CityFormData } from '@/types/city'; +import { useAddCityForm } from '@hooks/city/useAddCityForm'; import CloseIcon from '@assets/svg/close-icon.svg?react'; -import NameInput from './NameInput/NameInput'; -import CountryInput from './CountryInput/CountryInput'; -import LatitudeInput from './LatitudeInput/LatitudeInput'; -import LongitudeInput from './LongitudeInput/LongitudeInput'; - import { - wrapperStyling, - formStyling, buttonStyling, closeButtonStyling, closeIconStyling, + formStyling, + wrapperStyling, } from './CityAddModal.style'; +import CountryInput from './CountryInput/CountryInput'; +import LatitudeInput from './LatitudeInput/LatitudeInput'; +import LongitudeInput from './LongitudeInput/LongitudeInput'; +import NameInput from './NameInput/NameInput'; interface CityAddModalProps { cityId?: number; @@ -27,19 +26,7 @@ interface CityAddModalProps { } const CityAddModal = ({ cityId, initialData, isOpen = true, onClose }: CityAddModalProps) => { - const { - cityInformation, - isNameError, - isCountryError, - isLatitudeError, - isLongitudeError, - disableNameError, - disableCountryError, - disableLatitudeError, - disableLongitudeError, - updateInputValue, - handleSubmit, - } = UseAddCityForm({ + const { cityInformation, errors, disableError, updateInputValue, handleSubmit } = useAddCityForm({ cityId, initialData, onSuccess: onClose, @@ -66,27 +53,27 @@ const CityAddModal = ({ cityId, initialData, isOpen = true, onClose }: CityAddMo disableError('isNameError')} /> disableError('isCountryError')} /> disableError('isLatitudeError')} /> disableError('isLongitudeError')} /> +
+ + + + {leftCurrency.map((key) => { + return ( + disableCurrencyError(key)} + /> + ); + })} + + + {rightCurrency.map((key) => { + return ( + disableCurrencyError(key)} + /> + ); + })} + + + +
+ + + ); +}; + +export default CurrencyAddModal; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyAddModal/CurrencyInput/CurrencyInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyAddModal/CurrencyInput/CurrencyInput.tsx new file mode 100644 index 000000000..165d3cee3 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyAddModal/CurrencyInput/CurrencyInput.tsx @@ -0,0 +1,49 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { CurrencyFormData } from '@type/currency'; + +import { CURRENCY_MAX, CURRENCY_MIN } from '@constants/ui'; + +interface CurrencyInputProps { + currencyType: string; + value: number; + isError: boolean; + updateInputValue: ( + key: string, + value: CurrencyFormData[K] + ) => void; + disableError: () => void; +} + +const CurrencyInput = ( + { currencyType, isError, value, updateInputValue, disableError }: CurrencyInputProps +) => { + const handleCurrencyChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue(currencyType, Number(event.target.value)); + }; + + return ( + + ); +}; + +export default memo(CurrencyInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyAddModal/DataInput/DateInput.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyAddModal/DataInput/DateInput.tsx new file mode 100644 index 000000000..4c71d8ae5 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyAddModal/DataInput/DateInput.tsx @@ -0,0 +1,39 @@ +import { Input } from 'hang-log-design-system'; +import type { ChangeEvent } from 'react'; +import { memo } from 'react'; + +import type { CurrencyFormData } from '@type/currency'; + +import { CURRENCY_DATE_MAX_LENGTH } from '@constants/ui'; + +interface DateInputProps { + value: string; + isError: boolean; + updateInputValue: (key: K, value: CurrencyFormData[K]) => void; + disableError: () => void; +} + +const DateInput = ({ isError, value, updateInputValue, disableError }: DateInputProps) => { + const handleDateChange = (event: ChangeEvent) => { + disableError(); + + updateInputValue('date', event.target.value); + }; + + return ( + + ); +}; + +export default memo(DateInput); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyEditButton/CurrencyEditButton.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyEditButton/CurrencyEditButton.style.ts new file mode 100644 index 000000000..fa768354e --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyEditButton/CurrencyEditButton.style.ts @@ -0,0 +1,28 @@ +import { css } from '@emotion/react'; +import { Theme } from 'hang-log-design-system'; + +export const buttonStyling = css({ + width: '20px', + height: '20px', + border: 'none', + outline: 0, + + backgroundColor: 'transparent', + + cursor: 'pointer', + + '& svg': { + width: '20px', + height: '20px', + }, +}); + +export const editIconStyling = css({ + '& path': { + fill: Theme.color.gray600, + }, + + '&:hover path': { + fill: Theme.color.gray800, + }, +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyEditButton/CurrencyEditButton.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyEditButton/CurrencyEditButton.tsx new file mode 100644 index 000000000..9878605ec --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyEditButton/CurrencyEditButton.tsx @@ -0,0 +1,34 @@ +import { useOverlay } from 'hang-log-design-system'; + +import type { CurrencyData } from '@type/currency'; + +import EditIcon from '@assets/svg/edit-icon.svg?react'; + +import CurrencyAddModal from '../CurrencyAddModal/CurrencyAddModal'; +import { buttonStyling, editIconStyling } from './CurrencyEditButton.style'; + +const CurrencyEditButton = ({ ...information }: CurrencyData) => { + const { isOpen: isEditModalOpen, open: openEditModal, close: closeEditModal } = useOverlay(); + + return ( + <> + + {isEditModalOpen && ( + + )} + + ); +}; + +export default CurrencyEditButton; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyTable/CurrencyTable.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyTable/CurrencyTable.style.ts new file mode 100644 index 000000000..6efc31821 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyTable/CurrencyTable.style.ts @@ -0,0 +1,15 @@ +import { css } from '@emotion/react'; + +export const tableStyling = css({ + 'th:first-of-type, th:last-of-type': { + width: '5%', + }, + + 'th:second-of-type': { + width: '10%', + }, + + 'th:not(:first-of-type):not(:last-of-type):not(:second-of-type)': { + width: '8%', + }, +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyTable/CurrencyTable.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyTable/CurrencyTable.tsx new file mode 100644 index 000000000..023d3b9df --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyTable/CurrencyTable.tsx @@ -0,0 +1,53 @@ +import type { CurrencyData } from '@type/currency'; + +import CurrencyEditButton from '../CurrencyEditButton/CurrencyEditButton'; +import { tableStyling } from './CurrencyTable.style'; + +interface CurrencyTableProps { + currencies: CurrencyData[]; +} + +const CurrencyTable = ({ currencies }: CurrencyTableProps) => { + return ( + + + + + + + + + + + + + + + + + + + {currencies.map((currency) => ( + + + + + + + + + + + + + + + ))} + +
ID날짜USDEURGBPJPY(100)CNYCHFSGDTHBHKD
{currency.id}{currency.date}{currency.usd}{currency.eur}{currency.gbp}{currency.jpy}{currency.cny}{currency.chf}{currency.sgd}{currency.thb}{currency.hkd} + +
+ ); +}; + +export default CurrencyTable; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyTable/CurrencyTableSkeleton.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyTable/CurrencyTableSkeleton.tsx new file mode 100644 index 000000000..88fe87984 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/components/currency/CurrencyTable/CurrencyTableSkeleton.tsx @@ -0,0 +1,43 @@ +import { Skeleton } from 'hang-log-design-system'; + +import { tableStyling } from './CurrencyTable.style'; + +interface CurrencyTableSkeletonProps { + length: number; +} + +const CurrencyTableSkeleton = ({ length }: CurrencyTableSkeletonProps) => { + return ( + + + + + + + + + + + + + + + + + + + {Array.from({ length }, (_, index) => { + return ( + + + + ); + })} + +
ID날짜USDEURGBPJPY(100)CNYCHFSGDTHBHKD
+ +
+ ); +}; + +export default CurrencyTableSkeleton; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/layout/Footer/Footer.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/layout/Footer/Footer.style.ts index 7dbcae118..917a20ef3 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/components/layout/Footer/Footer.style.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/components/layout/Footer/Footer.style.ts @@ -1,5 +1,4 @@ import { css } from '@emotion/react'; - import { Theme } from 'hang-log-design-system'; export const containerStyling = css({ diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/Header.style.ts b/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/Header.style.ts index f943f4822..4d43dcfc0 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/Header.style.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/Header.style.ts @@ -1,5 +1,4 @@ import { css } from '@emotion/react'; - import { Theme } from 'hang-log-design-system'; export const headerStyling = css({ diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/Header.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/Header.tsx index e6ddd5888..e779013a0 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/Header.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/Header.tsx @@ -1,20 +1,10 @@ /* eslint-disable jsx-a11y/tabindex-no-positive */ -import { Suspense } from 'react'; +import { Flex, Theme } from 'hang-log-design-system'; import { useLocation, useNavigate } from 'react-router-dom'; -import { useRecoilValue } from 'recoil'; - -import { Flex, Text, Theme } from 'hang-log-design-system'; - -import { - getItemStyling, - getTapNavigateButtonStyling, - headerStyling, -} from '@components/layout/Header/Header.style'; +import { getItemStyling, headerStyling } from '@components/layout/Header/Header.style'; import LoggedOutOption from '@components/layout/Header/LoggedOutMenu/LoggedOutMenu'; -import { isLoggedInState } from '@store/auth'; - import { PATH } from '@constants/path'; import LogoHorizontal from '@assets/svg/logo-horizontal.svg?react'; diff --git a/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/LoggedOutMenu/LoggedOutMenu.tsx b/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/LoggedOutMenu/LoggedOutMenu.tsx index e2867b0b4..d9314c5d3 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/LoggedOutMenu/LoggedOutMenu.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/components/layout/Header/LoggedOutMenu/LoggedOutMenu.tsx @@ -1,7 +1,6 @@ +import { Button } from 'hang-log-design-system'; import { useNavigate } from 'react-router-dom'; -import { Button} from 'hang-log-design-system'; - import { PATH } from '@constants/path'; const LoggedOutMenu = () => { diff --git a/frontend-monorepo/packages/hanglog-admin/src/constants/api.ts b/frontend-monorepo/packages/hanglog-admin/src/constants/api.ts index dad292108..9a428a5b3 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/constants/api.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/constants/api.ts @@ -18,8 +18,8 @@ export const END_POINTS = { CHANGE_CITY: (cityId: number) => `/admin/cities/${cityId}`, CATEGORY: '/admin/categories', CHANGE_CATEGORY: (categoryId: number) => `/admin/categories/${categoryId}`, - CURRENCY: '/admin/currency', - CURRENCIES: (page: number, size: number) => `/admin/currencies/trips?page=${page}&size=${size}`, + CURRENCY: '/admin/currencies', + CURRENCY_PAGE: (page: number, size: number) => `/admin/currencies?page=${page}&size=${size}`, CHANGE_CURRENCY: (currencyId: number) => `/admin/currencies/${currencyId}`, } as const; diff --git a/frontend-monorepo/packages/hanglog-admin/src/constants/currency.ts b/frontend-monorepo/packages/hanglog-admin/src/constants/currency.ts new file mode 100644 index 000000000..6be43305b --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/constants/currency.ts @@ -0,0 +1,13 @@ +import { CurrencyFormData } from '@type/currency'; + +export const currencyKeys: (keyof CurrencyFormData)[] = [ + 'usd', + 'eur', + 'gbp', + 'jpy', + 'cny', + 'chf', + 'sgd', + 'thb', + 'hkd', +]; diff --git a/frontend-monorepo/packages/hanglog-admin/src/constants/regex.ts b/frontend-monorepo/packages/hanglog-admin/src/constants/regex.ts index 7c7681f16..ff982ad72 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/constants/regex.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/constants/regex.ts @@ -2,4 +2,7 @@ export const REGEX = { ONLY_LETTER: /^[A-Za-z가-힣ㄱ-ㅎ]+$/g, ALPHABET_AND_KOREAN_CHARACTERS: /^[a-zA-Zㄱ-ㅎㅏ-ㅣ가-힣]+$/, HTTP_TO_HTTPS: /^http(?!s)/, + ALPHABET: /^[A-Za-z]+$/, + KOREAN_CHARACTERS: /^[가-힣]+$/, + DATE: /^\d{4}-\d{2}-\d{2}$/, }; diff --git a/frontend-monorepo/packages/hanglog-admin/src/constants/ui.ts b/frontend-monorepo/packages/hanglog-admin/src/constants/ui.ts index e3e2dbf06..a575bf52d 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/constants/ui.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/constants/ui.ts @@ -15,3 +15,19 @@ export const CITY_LATITUDE_MAX = 90; export const CITY_LONGITUDE_MIN = -180; export const CITY_LONGITUDE_MAX = 180; + +export const CATEGORY_ID_MIN = 100; + +export const CATEGORY_ID_MAX = 999; + +export const CATEGORY_NAME_MAX = 50; + +export const CURRENCY_DATE_MAX_LENGTH = 10; + +export const CURRENCY_MIN = 0; + +export const CURRENCY_MAX = 10000000; + +export const ADMIN_MEMBER_MAX_LENGTH = 20; + +export const ADMIN_MEMBER_MIN_PASSWORD_LENGTH = 4; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/adminMember/useAddAdminMemberForm.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/adminMember/useAddAdminMemberForm.ts new file mode 100644 index 000000000..d580845b5 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/adminMember/useAddAdminMemberForm.ts @@ -0,0 +1,84 @@ +import type { FormEvent } from 'react'; +import { useCallback, useState } from 'react'; + +import type { AdminMemberFormData } from '@type/adminMember'; + +import { isEmptyString, isValidPassword } from '@utils/validator'; + +import { useAddAdminMemberMutation } from '../api/useAddAdminMemberMutation'; + +interface useAddAdminMemberFormParams { + onSuccess?: () => void; + onError?: () => void; +} + +export const useAddAdminMemberForm = ({ onSuccess, onError }: useAddAdminMemberFormParams) => { + const addAdminMemberMutaion = useAddAdminMemberMutation(); + + const [adminMemberInformation, setAdminMemberInformation] = useState({ + username: '', + adminType: 'ADMIN', + password: '', + confirmPassword: '', + }); + + const [errors, setErrors] = useState({ + isUsernameError: false, + isPasswordError: false, + isConfirmPasswordError: false, + }); + + const updateInputValue = useCallback( + (key: K, value: AdminMemberFormData[K]) => { + setAdminMemberInformation((prevAdminMemberInformation) => { + const data = { + ...prevAdminMemberInformation, + [key]: value, + }; + + return data; + }); + }, + [] + ); + + const disableError = useCallback((errorKey: keyof typeof errors) => { + setErrors((prev) => ({ ...prev, [errorKey]: false })); + }, []); + + const validateForm = () => { + const { username, password, confirmPassword } = adminMemberInformation; + const newErrors = { + isUsernameError: isEmptyString(username.trim()), + isPasswordError: !isValidPassword(password.trim()), + isConfirmPasswordError: password !== confirmPassword, + }; + + setErrors(newErrors); + + return Object.values(newErrors).some((isError) => isError); + }; + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + + if (validateForm()) { + return; + } + + addAdminMemberMutaion.mutate( + { + ...adminMemberInformation, + }, + { onSuccess, onError } + ); + }; + + return { + adminMemberInformation, + errors, + disableError, + updateInputValue, + handleSubmit, + }; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/adminMember/useUpdatePasswordForm.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/adminMember/useUpdatePasswordForm.ts new file mode 100644 index 000000000..93dfa16a1 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/adminMember/useUpdatePasswordForm.ts @@ -0,0 +1,93 @@ +import type { FormEvent } from 'react'; +import { useCallback, useState } from 'react'; + +import { PasswordPatchData } from '@type/adminMember'; + +import { isEmptyString, isValidPassword } from '@utils/validator'; + +import { useUpdateAdminMemberPasswordMutation } from '../api/useUpdateAdminMemberPasswordMutation'; + +interface useUpdatePasswordFormParams { + adminMemberId: number; + onSuccess?: () => void; + onError?: () => void; +} + +export interface PassowrdFormData extends PasswordPatchData { + confirmPassword: string; +} + +export const useUpdatePasswordForm = ( + { adminMemberId, onSuccess, onError }: useUpdatePasswordFormParams +) => { + const updatePasswordMutaion = useUpdateAdminMemberPasswordMutation(); + + const [adminMemberInformation, setAdminMemberInformation] = useState({ + currentPassword: '', + newPassword: '', + confirmPassword: '', + }); + + const [errors, setErrors] = useState({ + isCurrentPasswordError: false, + isPasswordError: false, + isConfirmPasswordError: false, + }); + + const updateInputValue = useCallback( + (key: K, value: PassowrdFormData[K]) => { + setAdminMemberInformation((prevAdminMemberInformation) => { + const data = { + ...prevAdminMemberInformation, + [key]: value, + }; + + return data; + }); + }, + [] + ); + + const disableError = useCallback((errorKey: keyof typeof errors) => { + setErrors((prev) => ({ ...prev, [errorKey]: false })); + }, []); + + const validateForm = () => { + const { currentPassword, newPassword, confirmPassword } = adminMemberInformation; + const newErrors = { + isCurrentPasswordError: isEmptyString(currentPassword.trim()), + isPasswordError: !isValidPassword(newPassword.trim()), + isConfirmPasswordError: newPassword !== confirmPassword, + }; + + setErrors(newErrors); + + return Object.values(newErrors).some((isError) => isError); + }; + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + + if (validateForm()) { + return; + } + + updatePasswordMutaion.mutate( + { + adminMemberId, + ...adminMemberInformation, + }, + { onSuccess, onError } + ); + }; + + return { + adminMemberInformation, + errors, + disableError, + updateInputValue, + handleSubmit, + }; +}; + +export default useUpdatePasswordForm; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddAdminMemberMutation.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddAdminMemberMutation.ts new file mode 100644 index 000000000..6a17a0910 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddAdminMemberMutation.ts @@ -0,0 +1,24 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { postAdminMember } from '@api/adminMember/postAdminMember'; +import type { ErrorResponseData } from '@api/interceptors'; + +import { useToast } from '../common/useToast'; + +export const useAddAdminMemberMutation = () => { + const queryClient = useQueryClient(); + const { createToast } = useToast(); + + const addAdminMemberMutation = useMutation({ + mutationFn: postAdminMember, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['adminMember'] }); + createToast('관리자 멤버를 성공적으로 추가했습니다.', 'success'); + }, + onError: (error: ErrorResponseData) => { + createToast('관리자 멤버 추가에 실패했습니다. 잠시 후 다시 시도해 주세요.'); + }, + }); + + return addAdminMemberMutation; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddCategoryMutation.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddCategoryMutation.ts new file mode 100644 index 000000000..37a7afa92 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddCategoryMutation.ts @@ -0,0 +1,24 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { postCategory } from '@api/category/postCategory'; +import type { ErrorResponseData } from '@api/interceptors'; + +import { useToast } from '../common/useToast'; + +export const useAddCategoryMutation = () => { + const queryClient = useQueryClient(); + const { createToast } = useToast(); + + const addCategoryMutation = useMutation({ + mutationFn: postCategory, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['category'] }); + createToast('카테고리를 성공적으로 추가했습니다.', 'success'); + }, + onError: (error: ErrorResponseData) => { + createToast('카테고리 추가에 실패했습니다. 잠시 후 다시 시도해 주세요.'); + }, + }); + + return addCategoryMutation; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddCityMutation.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddCityMutation.ts index 1f7785bbe..3c97b13f1 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddCityMutation.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddCityMutation.ts @@ -1,9 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { useToast } from '../common/useToast'; - +import { postCity } from '@api/city/postCity'; import type { ErrorResponseData } from '@api/interceptors'; -import { postCity } from '@/api/city/postCity'; + +import { useToast } from '../common/useToast'; export const useAddCityMutation = () => { const queryClient = useQueryClient(); diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddCurrencyMutation.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddCurrencyMutation.ts new file mode 100644 index 000000000..6bce8305b --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAddCurrencyMutation.ts @@ -0,0 +1,24 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { postCurrency } from '@api/currency/postCurrency'; +import type { ErrorResponseData } from '@api/interceptors'; + +import { useToast } from '../common/useToast'; + +export const useAddCurrencyMutation = () => { + const queryClient = useQueryClient(); + const { createToast } = useToast(); + + const addCurrencyMutation = useMutation({ + mutationFn: postCurrency, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['currency'] }); + createToast('환율 정보를 성공적으로 추가했습니다.', 'success'); + }, + onError: (error: ErrorResponseData) => { + createToast('환율 정보 추가에 실패했습니다. 잠시 후 다시 시도해 주세요.'); + }, + }); + + return addCurrencyMutation; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAdminMemberQuery.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAdminMemberQuery.ts new file mode 100644 index 000000000..3f9b91f31 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useAdminMemberQuery.ts @@ -0,0 +1,17 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; +import type { AxiosError } from 'axios'; + +import type { AdminMemberData } from '@type/adminMember'; + +import { getAdminMember } from '@api/adminMember/getAdminMember'; + +export const useAdminMemberQuery = () => { + const { data: adminMemberData } = useSuspenseQuery({ + queryKey: ['adminMember'], + queryFn: getAdminMember, + gcTime: 24 * 60 * 60 * 60 * 1000, + staleTime: Infinity, + }); + + return { adminMemberData }; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useCategoryQuery.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useCategoryQuery.ts new file mode 100644 index 000000000..cb1d3cdf2 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useCategoryQuery.ts @@ -0,0 +1,17 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; +import type { AxiosError } from 'axios'; + +import type { CategoryData } from '@type/category'; + +import { getCategory } from '@api/category/getCategory'; + +export const useCategoryQuery = () => { + const { data: categoryData } = useSuspenseQuery({ + queryKey: ['category'], + queryFn: getCategory, + gcTime: 24 * 60 * 60 * 60 * 1000, + staleTime: Infinity, + }); + + return { categoryData }; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useCityQuery.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useCityQuery.ts index ce11f037b..35155ec02 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useCityQuery.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useCityQuery.ts @@ -1,11 +1,10 @@ import { useSuspenseQuery } from '@tanstack/react-query'; - import type { AxiosError } from 'axios'; -import { getCity } from '@api/city/getCity'; - import type { CityData } from '@type/city'; +import { getCity } from '@api/city/getCity'; + export const useCityQuery = () => { const { data: cityData } = useSuspenseQuery({ queryKey: ['city'], diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useCurrencyQuery.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useCurrencyQuery.ts new file mode 100644 index 000000000..cbe095976 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useCurrencyQuery.ts @@ -0,0 +1,15 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; +import type { AxiosError } from 'axios'; + +import type { CurrencyListData } from '@type/currency'; + +import { getCurrency } from '@api/currency/getCurrency'; + +export const useCurrencyQuery = (page: number, size: number) => { + const { data: currencyListData } = useSuspenseQuery({ + queryKey: ['currency', page, size], + queryFn: () => getCurrency(page, size), + }); + + return { currencyListData }; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateAdminMemberPasswordMutation.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateAdminMemberPasswordMutation.ts new file mode 100644 index 000000000..84053ded3 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateAdminMemberPasswordMutation.ts @@ -0,0 +1,22 @@ +import { useMutation } from '@tanstack/react-query'; + +import { patchAdminMemberPassword } from '@api/adminMember/patchAdminMember'; +import type { ErrorResponseData } from '@api/interceptors'; + +import { useToast } from '../common/useToast'; + +export const useUpdateAdminMemberPasswordMutation = () => { + const { createToast } = useToast(); + + const updateAdminMemberPasswordMutation = useMutation({ + mutationFn: patchAdminMemberPassword, + onSuccess: () => { + createToast('비밀번호를 성공적으로 수정했습니다.', 'success'); + }, + onError: (error: ErrorResponseData) => { + createToast('비밀번호 수정에 실패했습니다. 잠시 후 다시 시도해 주세요.'); + }, + }); + + return updateAdminMemberPasswordMutation; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateCategoryMutation.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateCategoryMutation.ts new file mode 100644 index 000000000..a39082291 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateCategoryMutation.ts @@ -0,0 +1,24 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { putCategory } from '@api/category/putCategeory'; +import type { ErrorResponseData } from '@api/interceptors'; + +import { useToast } from '../common/useToast'; + +export const useUpdateCategoryMutation = () => { + const queryClient = useQueryClient(); + const { createToast } = useToast(); + + const updateCategoryMutation = useMutation({ + mutationFn: putCategory, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['category'] }); + createToast('카테고리를 성공적으로 수정했습니다.', 'success'); + }, + onError: (error: ErrorResponseData) => { + createToast('카테고리 수정에 실패했습니다. 잠시 후 다시 시도해 주세요.'); + }, + }); + + return updateCategoryMutation; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateCityMutation.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateCityMutation.ts index 3140c1751..81b50827f 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateCityMutation.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateCityMutation.ts @@ -1,9 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { useToast } from '../common/useToast'; - +import { putCity } from '@api/city/putCity'; import type { ErrorResponseData } from '@api/interceptors'; -import { putCity } from '@/api/city/putCity'; + +import { useToast } from '../common/useToast'; export const useUpdateCityMutation = () => { const queryClient = useQueryClient(); diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateCurrencyMutation.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateCurrencyMutation.ts new file mode 100644 index 000000000..592b2020d --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/api/useUpdateCurrencyMutation.ts @@ -0,0 +1,24 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +import { putCurrency } from '@api/currency/putCurrency'; +import type { ErrorResponseData } from '@api/interceptors'; + +import { useToast } from '../common/useToast'; + +export const useUpdateCurrencyMutation = () => { + const queryClient = useQueryClient(); + const { createToast } = useToast(); + + const updateCurrencyMutation = useMutation({ + mutationFn: putCurrency, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['currency'] }); + createToast('환율 정보를 성공적으로 수정했습니다.', 'success'); + }, + onError: (error: ErrorResponseData) => { + createToast('환율 정보 수정에 실패했습니다. 잠시 후 다시 시도해 주세요.'); + }, + }); + + return updateCurrencyMutation; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/category/useAddCategoryForm.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/category/useAddCategoryForm.ts new file mode 100644 index 000000000..70cc07e9c --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/category/useAddCategoryForm.ts @@ -0,0 +1,100 @@ +import type { FormEvent } from 'react'; +import { useCallback, useState } from 'react'; + +import type { CategoryData } from '@type/category'; + +import { isEmptyString, isEnglish, isInvalidCategoryId, isKorean } from '@utils/validator'; + +import { useAddCategoryMutation } from '../api/useAddCategoryMutation'; +import { useUpdateCategoryMutation } from '../api/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 [categoryInformation, setCategoryInformation] = useState( + initialData ?? { + id: 0, + engName: '', + korName: '', + } + ); + + const [errors, setErrors] = useState({ + isIdError: false, + isEngNameError: false, + isKorNameError: false, + }); + + const updateInputValue = useCallback( + (key: K, value: CategoryData[K]) => { + setCategoryInformation((prevCategoryInformation) => { + const data = { + ...prevCategoryInformation, + [key]: value, + }; + + return data; + }); + }, + [] + ); + + const disableError = useCallback((errorKey: keyof typeof errors) => { + setErrors((prev) => ({ ...prev, [errorKey]: false })); + }, []); + + const validateForm = () => { + const { id, engName, korName } = categoryInformation; + const newErrors = { + isIdError: isInvalidCategoryId(id), + isEngNameError: isEmptyString(engName.trim()) || !isEnglish(engName), + isKorNameError: isEmptyString(korName.trim()) || !isKorean(korName), + }; + + setErrors(newErrors); + + return Object.values(newErrors).some((isError) => isError); + }; + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + + if (validateForm()) { + return; + } + + if (!originalCategoryId) { + addCategoryMutation.mutate( + { + ...categoryInformation, + }, + { onSuccess, onError } + ); + return; + } + + updateCategoryMutation.mutate( + { + ...categoryInformation, + }, + { onSuccess, onError } + ); + }; + + return { + categoryInformation, + errors, + disableError, + updateInputValue, + handleSubmit, + }; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/city/useAddCityForm.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/city/useAddCityForm.ts index 0002e879f..2b255459a 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/hooks/city/useAddCityForm.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/city/useAddCityForm.ts @@ -1,26 +1,23 @@ import type { FormEvent } from 'react'; import { useCallback, useState } from 'react'; -import { useAddCityMutation } from '../api/useAddCityMutation'; -import { useUpdateCityMutation } from '../api/useUpdateCityMutation'; +import type { CityFormData } from '@type/city'; -import { isEmptyString, isInvalidLatitude, isInvalidLongitude } from '@/utils/validator'; +import { isEmptyString, isInvalidLatitude, isInvalidLongitude } from '@utils/validator'; -import type { CityFormData } from '@/types/city'; +import { useAddCityMutation } from '../api/useAddCityMutation'; +import { useUpdateCityMutation } from '../api/useUpdateCityMutation'; -interface UseAddCityFormParams { +interface useAddCityFormParams { cityId?: number; initialData?: CityFormData; onSuccess?: () => void; onError?: () => void; } -export const UseAddCityForm = ({ - cityId, - initialData, - onSuccess, - onError, -}: UseAddCityFormParams) => { +export const useAddCityForm = ( + { cityId, initialData, onSuccess, onError }: useAddCityFormParams +) => { const addCityMutation = useAddCityMutation(); const updateCityMutation = useUpdateCityMutation(); @@ -33,10 +30,12 @@ export const UseAddCityForm = ({ } ); - const [isNameError, setIsNameError] = useState(false); - const [isCountryError, setIsCountryError] = useState(false); - const [isLatitudeError, setIsLatitudeError] = useState(false); - const [isLongitudeError, setIsLongitudeError] = useState(false); + const [errors, setErrors] = useState({ + isNameError: false, + isCountryError: false, + isLatitudeError: false, + isLongitudeError: false, + }); const updateInputValue = useCallback( (key: K, value: CityFormData[K]) => { @@ -52,39 +51,28 @@ export const UseAddCityForm = ({ [] ); - const disableNameError = useCallback(() => { - setIsNameError(false); + const disableError = useCallback((errorKey: keyof typeof errors) => { + setErrors((prev) => ({ ...prev, [errorKey]: false })); }, []); - const disableCountryError = useCallback(() => { - setIsCountryError(false); - }, []); + const validateForm = () => { + const { name, country, latitude, longitude } = cityInformation; + const newErrors = { + isNameError: isEmptyString(name.trim()), + isCountryError: isEmptyString(country.trim()), + isLatitudeError: isInvalidLatitude(latitude), + isLongitudeError: isInvalidLongitude(longitude), + }; - const disableLatitudeError = useCallback(() => { - setIsLatitudeError(false); - }, []); + setErrors(newErrors); - const disableLongitudeError = useCallback(() => { - setIsLongitudeError(false); - }, []); + return Object.values(newErrors).some((isError) => isError); + }; const handleSubmit = (event: FormEvent) => { event.preventDefault(); - if (isEmptyString(cityInformation.name.trim())) { - setIsNameError(true); - return; - } - if (isEmptyString(cityInformation.country.trim())) { - setIsCountryError(true); - return; - } - if (isInvalidLatitude(cityInformation.latitude)) { - setIsLatitudeError(true); - return; - } - if (isInvalidLongitude(cityInformation.longitude)) { - setIsLongitudeError(true); + if (validateForm()) { return; } @@ -110,14 +98,8 @@ export const UseAddCityForm = ({ return { cityInformation, - isNameError, - isCountryError, - isLatitudeError, - isLongitudeError, - disableNameError, - disableCountryError, - disableLatitudeError, - disableLongitudeError, + errors, + disableError, updateInputValue, handleSubmit, }; diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/common/useMediaQuery.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/common/useMediaQuery.ts index 935486491..8ae3df819 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/hooks/common/useMediaQuery.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/common/useMediaQuery.ts @@ -2,9 +2,9 @@ import { useCallback, useEffect, useRef } from 'react'; import { useSetRecoilState } from 'recoil'; -import { mediaQueryMobileState, viewportHeightState, viewportWidthState } from '@store/mediaQuery'; +import { MOBILE_MEDIA_QUERY_SIZE } from '@constants/ui'; -import { MOBILE_MEDIA_QUERY_SIZE } from '@/constants/ui'; +import { mediaQueryMobileState, viewportHeightState, viewportWidthState } from '@store/mediaQuery'; export const useMediaQuery = () => { const setViewportWidth = useSetRecoilState(viewportWidthState); diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/common/useToast.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/common/useToast.ts index 5f0ef0d37..c415bd6f2 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/hooks/common/useToast.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/common/useToast.ts @@ -1,12 +1,11 @@ import { useCallback } from 'react'; - import { useSetRecoilState } from 'recoil'; -import { toastListState } from '@store/toast'; +import type { ToastType } from '@type/toast'; -import { generateUniqueId } from '@/utils/uniqueId'; +import { generateUniqueId } from '@utils/uniqueId'; -import type { ToastType } from '@type/toast'; +import { toastListState } from '@store/toast'; export const useToast = () => { const setToastList = useSetRecoilState(toastListState); diff --git a/frontend-monorepo/packages/hanglog-admin/src/hooks/currency/useAddCurrencyForm.ts b/frontend-monorepo/packages/hanglog-admin/src/hooks/currency/useAddCurrencyForm.ts new file mode 100644 index 000000000..0a98e79e3 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/hooks/currency/useAddCurrencyForm.ts @@ -0,0 +1,128 @@ +import type { FormEvent } from 'react'; +import { useCallback, useState } from 'react'; + +import type { CurrencyFormData } from '@type/currency'; + +import { currencyKeys } from '@constants/currency'; + +import { isInvalidCurrency, isValidCurrencyDate } from '@utils/validator'; + +import { useAddCurrencyMutation } from '../api/useAddCurrencyMutation'; +import { useUpdateCurrencyMutation } from '../api/useUpdateCurrencyMutation'; + +interface useAddCurrencyFormPrams { + currencyId?: number; + initialData?: CurrencyFormData; + onSuccess?: () => void; + onError?: () => void; +} + +export const useAddCurrencyForm = ( + { currencyId, initialData, onSuccess, onError }: useAddCurrencyFormPrams +) => { + const addCurrencyMutation = useAddCurrencyMutation(); + const updateCurrencyMutation = useUpdateCurrencyMutation(); + + const [currencyInformation, setCurrencyInformation] = useState( + initialData ?? { + date: '', + usd: 0, + eur: 0, + gbp: 0, + jpy: 0, + cny: 0, + chf: 0, + sgd: 0, + thb: 0, + hkd: 0, + } + ); + + const [isDateError, setIsDateError] = useState(false); + + const updateInputValue = useCallback( + (key: string, value: CurrencyFormData[K]) => { + setCurrencyInformation((prevCurrencyInformation) => { + const data = { + ...prevCurrencyInformation, + [key]: value, + }; + + return data; + }); + }, + [] + ); + + const disableDateError = useCallback(() => { + setIsDateError(false); + }, []); + + const [currencyErrors, setCurrencyErrors] = useState>( + currencyKeys.reduce((acc, key) => { + acc[key] = false; + return acc; + }, {} as Record) + ); + const disableCurrencyError = useCallback((currencyKey: string) => { + setCurrencyErrors((prevErrors) => ({ + ...prevErrors, + [currencyKey]: false, + })); + }, []); + + const checkAndSetCurrencyValidity = useCallback(() => { + const newCurrencyErrors = { ...currencyErrors }; + + currencyKeys.forEach((key) => { + newCurrencyErrors[key] = isInvalidCurrency(Number(currencyInformation[key])); + }); + + setCurrencyErrors(newCurrencyErrors); + + return Object.values(newCurrencyErrors).some((isError) => isError); + }, [currencyInformation, currencyErrors]); + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + + if (!isValidCurrencyDate(currencyInformation.date)) { + setIsDateError(true); + return; + } + + const isAnyCurrencyInvalid = checkAndSetCurrencyValidity(); + if (isAnyCurrencyInvalid) { + return; + } + + if (!currencyId) { + addCurrencyMutation.mutate( + { + ...currencyInformation, + }, + { onSuccess, onError } + ); + + return; + } + + updateCurrencyMutation.mutate( + { + currencyId, + ...currencyInformation, + }, + { onSuccess, onError } + ); + }; + + return { + currencyInformation, + isDateError, + currencyErrors, + disableDateError, + disableCurrencyError, + updateInputValue, + handleSubmit, + }; +}; diff --git a/frontend-monorepo/packages/hanglog-admin/src/index.tsx b/frontend-monorepo/packages/hanglog-admin/src/index.tsx index dc7db165a..aa2e0fb77 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/index.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/index.tsx @@ -1,5 +1,4 @@ import { Global } from '@emotion/react'; -import AppRouter from '@router/AppRouter'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { HangLogProvider } from 'hang-log-design-system'; import { StrictMode } from 'react'; @@ -8,6 +7,8 @@ import { RecoilRoot } from 'recoil'; import { GlobalStyle } from '@styles/index'; +import AppRouter from '@router/AppRouter'; + async function enableMocking() { if (process.env.NODE_ENV !== 'development') { return; diff --git a/frontend-monorepo/packages/hanglog-admin/src/mocks/browser.ts b/frontend-monorepo/packages/hanglog-admin/src/mocks/browser.ts index a85ed8318..40ac1cc75 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/mocks/browser.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/mocks/browser.ts @@ -1,4 +1,5 @@ -import { handlers } from '@mocks/handlers'; import { setupWorker } from 'msw/browser'; +import { handlers } from '@mocks/handlers'; + export const worker = setupWorker(...handlers); diff --git a/frontend-monorepo/packages/hanglog-admin/src/mocks/data/adminMember.ts b/frontend-monorepo/packages/hanglog-admin/src/mocks/data/adminMember.ts new file mode 100644 index 000000000..f67313eb4 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/mocks/data/adminMember.ts @@ -0,0 +1,19 @@ +import type { AdminMemberData } from '@type/adminMember'; + +export const adminMembers: AdminMemberData[] = [ + { + id: 1, + username: 'HangLog', + adminType: 'MASTER', + }, + { + id: 2, + username: 'io25', + adminType: 'ADMIN', + }, + { + id: 3, + username: 'raon', + adminType: 'ADMIN', + }, +]; diff --git a/frontend-monorepo/packages/hanglog-admin/src/mocks/data/category.ts b/frontend-monorepo/packages/hanglog-admin/src/mocks/data/category.ts index e69de29bb..004c70bc1 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/mocks/data/category.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/mocks/data/category.ts @@ -0,0 +1,39 @@ +import type { CategoryData } from '@type/category'; + +export const categories: CategoryData[] = [ + { + id: 100, + engName: 'food', + korName: '음식', + }, + { + id: 200, + engName: 'culture', + korName: '문화', + }, + { + id: 264, + engName: 'university', + korName: '대학교', + }, + { + id: 300, + engName: 'shopping', + korName: '쇼핑', + }, + { + id: 400, + engName: 'accommodation', + korName: '숙박', + }, + { + id: 500, + engName: 'transportation', + korName: '교통', + }, + { + id: 600, + engName: 'etc', + korName: '기타', + }, +]; diff --git a/frontend-monorepo/packages/hanglog-admin/src/mocks/data/currency.ts b/frontend-monorepo/packages/hanglog-admin/src/mocks/data/currency.ts new file mode 100644 index 000000000..1dfed25d0 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/mocks/data/currency.ts @@ -0,0 +1,1260 @@ +import type { CurrencyData } from '@type/currency'; + +export const currencyListData = (page: number, size: number) => { + const lastPageIndex = Math.ceil(currencies.length / size) - 1; + const listData = currencies.slice(page * size, (page + 1) * size); + + return { + lastPageIndex: lastPageIndex, + currencies: listData, + }; +}; + +export const currencies: CurrencyData[] = [ + { + id: 1, + date: '2023-05-15', + chf: 1484.25, + cny: 191.86, + eur: 1447.09, + gbp: 1660.07, + hkd: 170.05, + jpy: 982.21, + krw: 1, + sgd: 996.26, + thb: 39.32, + usd: 1333.6, + }, + { + id: 2, + date: '2023-05-16', + chf: 1493.83, + cny: 192.01, + eur: 1454.79, + gbp: 1675.59, + hkd: 170.67, + jpy: 983.57, + krw: 1, + sgd: 1001.12, + thb: 39.6, + usd: 1337.8, + }, + { + id: 3, + date: '2023-05-17', + chf: 1490.16, + cny: 191.72, + eur: 1451.16, + gbp: 1667.46, + hkd: 170.44, + jpy: 979.29, + krw: 1, + sgd: 996.61, + thb: 39.18, + usd: 1336.0, + }, + { + id: 4, + date: '2023-05-18', + chf: 1490.62, + cny: 191.29, + eur: 1451.64, + gbp: 1672.58, + hkd: 171.03, + jpy: 973.44, + krw: 1, + sgd: 997.84, + thb: 39.1, + usd: 1339.4, + }, + { + id: 5, + date: '2023-05-19', + chf: 1472.92, + cny: 189.72, + eur: 1436.12, + gbp: 1654.35, + hkd: 170.27, + jpy: 962.0, + krw: 1, + sgd: 988.83, + thb: 38.71, + usd: 1332.7, + }, + { + id: 6, + date: '2023-05-22', + chf: 1481.83, + cny: 188.66, + eur: 1440.69, + gbp: 1658.48, + hkd: 170.28, + jpy: 967.34, + krw: 1, + sgd: 990.07, + thb: 38.79, + usd: 1331.2, + }, + { + id: 7, + date: '2023-05-23', + chf: 1468.93, + cny: 187.69, + eur: 1426.01, + gbp: 1640.37, + hkd: 168.5, + jpy: 951.9, + krw: 1, + sgd: 979.69, + thb: 38.28, + usd: 1319.1, + }, + { + id: 8, + date: '2023-05-24', + chf: 1455.09, + cny: 185.76, + eur: 1412.77, + gbp: 1628.76, + hkd: 167.33, + jpy: 946.59, + krw: 1, + sgd: 973.72, + thb: 37.93, + usd: 1311.4, + }, + { + id: 9, + date: '2023-05-25', + chf: 1456.69, + cny: 186.32, + eur: 1416.97, + gbp: 1629.48, + hkd: 168.27, + jpy: 946.31, + krw: 1, + sgd: 976.61, + thb: 38.05, + usd: 1317.5, + }, + { + id: 10, + date: '2023-05-26', + chf: 1461.67, + cny: 186.93, + eur: 1419.48, + gbp: 1630.96, + hkd: 168.91, + jpy: 945.72, + krw: 1, + sgd: 977.0, + thb: 38.09, + usd: 1323.4, + }, + { + id: 11, + date: '2023-05-30', + chf: 1465.72, + cny: 187.25, + eur: 1419.45, + gbp: 1637.91, + hkd: 169.33, + jpy: 943.72, + krw: 1, + sgd: 979.21, + thb: 38.2, + usd: 1325.6, + }, + { + id: 12, + date: '2023-05-31', + chf: 1458.98, + cny: 186.31, + eur: 1418.99, + gbp: 1640.72, + hkd: 168.77, + jpy: 945.98, + krw: 1, + sgd: 978.94, + thb: 38.12, + usd: 1322.2, + }, + { + id: 13, + date: '2023-06-01', + chf: 1451.99, + cny: 185.92, + eur: 1413.39, + gbp: 1644.93, + hkd: 168.78, + jpy: 950.01, + krw: 1, + sgd: 977.91, + thb: 38.1, + usd: 1321.6, + }, + { + id: 14, + date: '2023-06-02', + chf: 1458.53, + cny: 185.58, + eur: 1421.54, + gbp: 1654.51, + hkd: 168.65, + jpy: 951.75, + krw: 1, + sgd: 980.4, + thb: 38.21, + usd: 1320.7, + }, + { + id: 15, + date: '2023-06-05', + chf: 1439.35, + cny: 184.32, + eur: 1400.55, + gbp: 1627.56, + hkd: 167.0, + jpy: 934.02, + krw: 1, + sgd: 969.01, + thb: 37.59, + usd: 1308.8, + }, + { + id: 16, + date: '2023-06-07', + chf: 1441.49, + cny: 183.99, + eur: 1398.97, + gbp: 1625.43, + hkd: 166.81, + jpy: 937.28, + krw: 1, + sgd: 970.37, + thb: 37.61, + usd: 1308.3, + }, + { + id: 17, + date: '2023-06-08', + chf: 1429.28, + cny: 182.46, + eur: 1391.21, + gbp: 1617.43, + hkd: 165.86, + jpy: 928.63, + krw: 1, + sgd: 964.23, + thb: 37.32, + usd: 1300.5, + }, + { + id: 18, + date: '2023-06-09', + chf: 1453.08, + cny: 182.72, + eur: 1408.5, + gbp: 1640.72, + hkd: 166.67, + jpy: 940.69, + krw: 1, + sgd: 972.92, + thb: 37.73, + usd: 1306.1, + }, + { + id: 19, + date: '2023-06-12', + chf: 1432.81, + cny: 181.78, + eur: 1391.5, + gbp: 1628.47, + hkd: 165.19, + jpy: 928.81, + krw: 1, + sgd: 963.75, + thb: 37.42, + usd: 1294.9, + }, + { + id: 20, + date: '2023-06-13', + chf: 1421.06, + cny: 180.59, + eur: 1389.55, + gbp: 1615.75, + hkd: 164.78, + jpy: 925.75, + krw: 1, + sgd: 961.03, + thb: 37.26, + usd: 1291.1, + }, + { + id: 21, + date: '2023-06-14', + chf: 1411.45, + cny: 178.19, + eur: 1378.55, + gbp: 1610.8, + hkd: 163.08, + jpy: 911.49, + krw: 1, + sgd: 951.76, + thb: 36.85, + usd: 1277.5, + }, + { + id: 22, + date: '2023-06-15', + chf: 1416.25, + cny: 177.98, + eur: 1382.18, + gbp: 1615.67, + hkd: 162.94, + jpy: 911.0, + krw: 1, + sgd: 951.21, + thb: 36.76, + usd: 1275.9, + }, + { + id: 23, + date: '2023-06-16', + chf: 1436.22, + cny: 178.67, + eur: 1401.84, + gbp: 1637.25, + hkd: 163.66, + jpy: 913.48, + krw: 1, + sgd: 958.05, + thb: 37.0, + usd: 1280.1, + }, + { + id: 24, + date: '2023-06-19', + chf: 1423.86, + cny: 178.66, + eur: 1393.53, + gbp: 1634.03, + hkd: 162.84, + jpy: 897.49, + krw: 1, + sgd: 952.26, + thb: 36.72, + usd: 1273.5, + }, + { + id: 25, + date: '2023-06-20', + chf: 1429.75, + cny: 179.46, + eur: 1398.84, + gbp: 1639.36, + hkd: 163.85, + jpy: 902.31, + krw: 1, + sgd: 955.28, + thb: 36.84, + usd: 1280.7, + }, + { + id: 26, + date: '2023-06-21', + chf: 1428.48, + cny: 178.29, + eur: 1400.35, + gbp: 1636.6, + hkd: 163.85, + jpy: 907.46, + krw: 1, + sgd: 954.62, + thb: 36.8, + usd: 1282.2, + }, + { + id: 27, + date: '2023-06-22', + chf: 1447.38, + cny: 179.54, + eur: 1419.68, + gbp: 1649.5, + hkd: 164.98, + jpy: 911.5, + krw: 1, + sgd: 963.84, + thb: 37.14, + usd: 1291.5, + }, + { + id: 28, + date: '2023-06-23', + chf: 1443.07, + cny: 179.71, + eur: 1414.79, + gbp: 1646.15, + hkd: 164.92, + jpy: 902.67, + krw: 1, + sgd: 960.29, + thb: 36.74, + usd: 1291.4, + }, + { + id: 29, + date: '2023-06-26', + chf: 1453.19, + cny: 180.57, + eur: 1419.85, + gbp: 1656.59, + hkd: 166.3, + jpy: 907.01, + krw: 1, + sgd: 963.13, + thb: 36.96, + usd: 1302.2, + }, + { + id: 30, + date: '2023-06-27', + chf: 1455.87, + cny: 180.66, + eur: 1422.45, + gbp: 1657.59, + hkd: 166.51, + jpy: 909.11, + krw: 1, + sgd: 963.32, + thb: 37.02, + usd: 1303.8, + }, + { + id: 31, + date: '2023-06-28', + chf: 1458.1, + cny: 180.45, + eur: 1427.94, + gbp: 1661.13, + hkd: 166.35, + jpy: 905.34, + krw: 1, + sgd: 965.72, + thb: 36.95, + usd: 1303.1, + }, + { + id: 32, + date: '2023-06-29', + chf: 1454.64, + cny: 180.28, + eur: 1423.84, + gbp: 1648.64, + hkd: 166.52, + jpy: 903.35, + krw: 1, + sgd: 964.22, + thb: 36.65, + usd: 1304.3, + }, + { + id: 33, + date: '2023-06-30', + chf: 1459.72, + cny: 181.05, + eur: 1426.55, + gbp: 1655.51, + hkd: 167.48, + jpy: 906.97, + krw: 1, + sgd: 967.96, + thb: 36.84, + usd: 1312.8, + }, + { + id: 34, + date: '2023-07-03', + chf: 1474.03, + cny: 181.77, + eur: 1439.47, + gbp: 1675.37, + hkd: 168.36, + jpy: 913.87, + krw: 1, + sgd: 975.56, + thb: 37.39, + usd: 1319.4, + }, + { + id: 35, + date: '2023-07-04', + chf: 1461.48, + cny: 180.88, + eur: 1429.8, + gbp: 1662.46, + hkd: 167.22, + jpy: 905.57, + krw: 1, + sgd: 969.65, + thb: 37.39, + usd: 1310.0, + }, + { + id: 36, + date: '2023-07-05', + chf: 1451.01, + cny: 179.53, + eur: 1416.38, + gbp: 1654.85, + hkd: 166.22, + jpy: 900.92, + krw: 1, + sgd: 964.62, + thb: 37.32, + usd: 1301.7, + }, + { + id: 37, + date: '2023-07-06', + chf: 1447.42, + cny: 179.87, + eur: 1411.89, + gbp: 1652.47, + hkd: 166.31, + jpy: 900.05, + krw: 1, + sgd: 961.03, + thb: 37.19, + usd: 1300.8, + }, + { + id: 38, + date: '2023-07-07', + chf: 1456.6, + cny: 179.44, + eur: 1420.36, + gbp: 1661.69, + hkd: 166.68, + jpy: 905.51, + krw: 1, + sgd: 963.74, + thb: 37.08, + usd: 1303.8, + }, + { + id: 39, + date: '2023-07-10', + chf: 1470.12, + cny: 180.29, + eur: 1433.39, + gbp: 1677.85, + hkd: 167.02, + jpy: 919.11, + krw: 1, + sgd: 970.74, + thb: 37.18, + usd: 1307.3, + }, + { + id: 40, + date: '2023-07-11', + chf: 1472.55, + cny: 180.16, + eur: 1434.44, + gbp: 1677.21, + hkd: 166.56, + jpy: 922.82, + krw: 1, + sgd: 969.84, + thb: 37.17, + usd: 1303.8, + }, + { + id: 41, + date: '2023-07-12', + chf: 1473.43, + cny: 179.26, + eur: 1426.12, + gbp: 1675.41, + hkd: 165.45, + jpy: 923.25, + krw: 1, + sgd: 965.95, + thb: 37.23, + usd: 1295.0, + }, + { + id: 42, + date: '2023-07-13', + chf: 1489.25, + cny: 179.43, + eur: 1437.97, + gbp: 1677.72, + hkd: 165.02, + jpy: 932.92, + krw: 1, + sgd: 970.9, + thb: 37.25, + usd: 1291.4, + }, + { + id: 43, + date: '2023-07-14', + chf: 1485.77, + cny: 177.82, + eur: 1432.66, + gbp: 1676.16, + hkd: 163.16, + jpy: 925.22, + krw: 1, + sgd: 965.25, + thb: 36.94, + usd: 1276.2, + }, + { + id: 44, + date: '2023-07-17', + chf: 1468.28, + cny: 177.15, + eur: 1420.92, + gbp: 1656.68, + hkd: 161.97, + jpy: 911.99, + krw: 1, + sgd: 957.6, + thb: 36.48, + usd: 1265.8, + }, + { + id: 45, + date: '2023-07-18', + chf: 1471.61, + cny: 176.69, + eur: 1423.1, + gbp: 1655.43, + hkd: 162.03, + jpy: 912.87, + krw: 1, + sgd: 957.9, + thb: 36.6, + usd: 1266.1, + }, + { + id: 46, + date: '2023-07-19', + chf: 1471.17, + cny: 175.66, + eur: 1416.97, + gbp: 1644.75, + hkd: 161.47, + jpy: 908.31, + krw: 1, + sgd: 953.88, + thb: 37.04, + usd: 1261.6, + }, + { + id: 47, + date: '2023-07-20', + chf: 1474.4, + cny: 175.55, + eur: 1417.63, + gbp: 1636.79, + hkd: 162.06, + jpy: 906.03, + krw: 1, + sgd: 955.13, + thb: 37.18, + usd: 1265.4, + }, + { + id: 48, + date: '2023-07-21', + chf: 1460.99, + cny: 175.97, + eur: 1409.66, + gbp: 1629.4, + hkd: 162.0, + jpy: 904.37, + krw: 1, + sgd: 953.95, + thb: 37.01, + usd: 1265.8, + }, + { + id: 49, + date: '2023-07-24', + chf: 1480.02, + cny: 178.55, + eur: 1426.4, + gbp: 1647.5, + hkd: 163.95, + jpy: 904.61, + krw: 1, + sgd: 963.18, + thb: 37.22, + usd: 1281.7, + }, + { + id: 50, + date: '2023-07-25', + chf: 1475.8, + cny: 178.3, + eur: 1420.14, + gbp: 1645.45, + hkd: 164.31, + jpy: 907.12, + krw: 1, + sgd: 963.78, + thb: 37.17, + usd: 1283.8, + }, + { + id: 51, + date: '2023-07-26', + chf: 1481.43, + cny: 178.87, + eur: 1415.37, + gbp: 1651.4, + hkd: 163.95, + jpy: 908.78, + krw: 1, + sgd: 964.56, + thb: 37.21, + usd: 1280.7, + }, + { + id: 52, + date: '2023-07-27', + chf: 1484.96, + cny: 178.64, + eur: 1417.38, + gbp: 1653.49, + hkd: 163.91, + jpy: 910.59, + krw: 1, + sgd: 964.66, + thb: 37.37, + usd: 1278.7, + }, + { + id: 53, + date: '2023-07-28', + chf: 1465.11, + cny: 178.33, + eur: 1397.94, + gbp: 1629.32, + hkd: 163.19, + jpy: 914.4, + krw: 1, + sgd: 956.69, + thb: 36.97, + usd: 1273.4, + }, + { + id: 54, + date: '2023-07-31', + chf: 1471.52, + cny: 178.49, + eur: 1411.33, + gbp: 1645.38, + hkd: 164.18, + jpy: 908.28, + krw: 1, + sgd: 961.18, + thb: 37.37, + usd: 1280.0, + }, + { + id: 55, + date: '2023-08-01', + chf: 1461.37, + cny: 178.29, + eur: 1401.12, + gbp: 1635.18, + hkd: 163.34, + jpy: 895.18, + krw: 1, + sgd: 957.92, + thb: 37.18, + usd: 1273.8, + }, + { + id: 56, + date: '2023-08-02', + chf: 1466.42, + cny: 178.63, + eur: 1409.67, + gbp: 1637.82, + hkd: 164.31, + jpy: 896.0, + krw: 1, + sgd: 959.29, + thb: 37.31, + usd: 1280.7, + }, + { + id: 57, + date: '2023-08-03', + chf: 1474.01, + cny: 179.95, + eur: 1415.06, + gbp: 1644.18, + hkd: 165.74, + jpy: 902.78, + krw: 1, + sgd: 963.99, + thb: 37.51, + usd: 1293.0, + }, + { + id: 58, + date: '2023-08-04', + chf: 1485.79, + cny: 180.47, + eur: 1422.45, + gbp: 1651.1, + hkd: 166.35, + jpy: 911.02, + krw: 1, + sgd: 968.57, + thb: 37.59, + usd: 1298.8, + }, + { + id: 59, + date: '2023-08-07', + chf: 1491.71, + cny: 181.53, + eur: 1434.68, + gbp: 1662.47, + hkd: 166.93, + jpy: 919.05, + krw: 1, + sgd: 973.24, + thb: 37.58, + usd: 1303.9, + }, + { + id: 60, + date: '2023-08-08', + chf: 1494.24, + cny: 181.16, + eur: 1434.97, + gbp: 1666.77, + hkd: 167.04, + jpy: 915.58, + krw: 1, + sgd: 972.52, + thb: 37.42, + usd: 1304.1, + }, + { + id: 61, + date: '2023-08-09', + chf: 1498.49, + cny: 181.9, + eur: 1437.95, + gbp: 1672.71, + hkd: 167.98, + jpy: 916.08, + krw: 1, + sgd: 973.88, + thb: 37.48, + usd: 1312.6, + }, + { + id: 62, + date: '2023-08-10', + chf: 1503.11, + cny: 182.64, + eur: 1446.97, + gbp: 1676.68, + hkd: 168.56, + jpy: 917.49, + krw: 1, + sgd: 979.27, + thb: 37.59, + usd: 1318.3, + }, + { + id: 63, + date: '2023-08-11', + chf: 1502.4, + cny: 182.32, + eur: 1446.72, + gbp: 1669.22, + hkd: 168.46, + jpy: 909.77, + krw: 1, + sgd: 976.25, + thb: 37.5, + usd: 1317.3, + }, + { + id: 64, + date: '2023-08-14', + chf: 1506.39, + cny: 182.59, + eur: 1445.68, + gbp: 1676.48, + hkd: 168.98, + jpy: 911.7, + krw: 1, + sgd: 976.42, + thb: 37.64, + usd: 1321.1, + }, + { + id: 65, + date: '2023-08-16', + chf: 1514.99, + cny: 183.28, + eur: 1451.52, + gbp: 1690.75, + hkd: 170.16, + jpy: 914.26, + krw: 1, + sgd: 980.01, + thb: 37.61, + usd: 1331.3, + }, + { + id: 66, + date: '2023-08-17', + chf: 1520.8, + cny: 182.83, + eur: 1455.87, + gbp: 1703.79, + hkd: 170.89, + jpy: 914.8, + krw: 1, + sgd: 984.23, + thb: 37.72, + usd: 1338.3, + }, + { + id: 67, + date: '2023-08-18', + chf: 1527.41, + cny: 182.8, + eur: 1458.79, + gbp: 1709.94, + hkd: 171.34, + jpy: 920.76, + krw: 1, + sgd: 987.67, + thb: 37.77, + usd: 1341.6, + }, + { + id: 68, + date: '2023-08-21', + chf: 1514.9, + cny: 183.27, + eur: 1453.54, + gbp: 1702.68, + hkd: 170.68, + jpy: 919.75, + krw: 1, + sgd: 984.93, + thb: 37.78, + usd: 1336.9, + }, + { + id: 69, + date: '2023-08-22', + chf: 1527.03, + cny: 183.13, + eur: 1461.83, + gbp: 1711.75, + hkd: 171.13, + jpy: 917.48, + krw: 1, + sgd: 988.18, + thb: 38.11, + usd: 1341.5, + }, + { + id: 70, + date: '2023-08-23', + chf: 1520.9, + cny: 183.37, + eur: 1452.02, + gbp: 1704.23, + hkd: 170.8, + jpy: 918.05, + krw: 1, + sgd: 986.04, + thb: 38.2, + usd: 1338.7, + }, + { + id: 71, + date: '2023-08-24', + chf: 1524.35, + cny: 183.29, + eur: 1453.6, + gbp: 1701.74, + hkd: 170.65, + jpy: 924.38, + krw: 1, + sgd: 989.32, + thb: 38.28, + usd: 1338.0, + }, + { + id: 72, + date: '2023-08-25', + chf: 1495.37, + cny: 181.54, + eur: 1429.52, + gbp: 1666.78, + hkd: 168.85, + jpy: 906.88, + krw: 1, + sgd: 975.83, + thb: 37.8, + usd: 1324.0, + }, + { + id: 73, + date: '2023-08-28', + chf: 1498.81, + cny: 182.1, + eur: 1431.93, + gbp: 1668.86, + hkd: 169.13, + jpy: 905.0, + krw: 1, + sgd: 978.25, + thb: 37.77, + usd: 1326.6, + }, + { + id: 74, + date: '2023-08-29', + chf: 1497.23, + cny: 181.65, + eur: 1431.8, + gbp: 1667.67, + hkd: 168.56, + jpy: 903.13, + krw: 1, + sgd: 975.76, + thb: 37.53, + usd: 1322.5, + }, + { + id: 75, + date: '2023-08-30', + chf: 1505.52, + cny: 181.34, + eur: 1438.86, + gbp: 1672.26, + hkd: 168.48, + jpy: 906.69, + krw: 1, + sgd: 979.73, + thb: 37.74, + usd: 1322.0, + }, + { + id: 76, + date: '2023-08-31', + chf: 1505.01, + cny: 181.09, + eur: 1444.36, + gbp: 1681.15, + hkd: 168.41, + jpy: 905.07, + krw: 1, + sgd: 978.96, + thb: 37.73, + usd: 1321.4, + }, + { + id: 77, + date: '2023-09-01', + chf: 1496.83, + cny: 181.35, + eur: 1433.77, + gbp: 1675.68, + hkd: 168.6, + jpy: 908.64, + krw: 1, + sgd: 978.5, + thb: 37.76, + usd: 1322.3, + }, + { + id: 78, + date: '2023-09-04', + chf: 1489.53, + cny: 181.77, + eur: 1421.64, + gbp: 1660.74, + hkd: 168.14, + jpy: 902.94, + krw: 1, + sgd: 974.05, + thb: 37.57, + usd: 1319.2, + }, + { + id: 79, + date: '2023-09-05', + chf: 1491.49, + cny: 181.37, + eur: 1424.25, + gbp: 1666.08, + hkd: 168.39, + jpy: 900.45, + krw: 1, + sgd: 973.65, + thb: 37.45, + usd: 1319.3, + }, + { + id: 80, + date: '2023-09-06', + chf: 1488.98, + cny: 181.65, + eur: 1420.44, + gbp: 1664.65, + hkd: 168.89, + jpy: 897.86, + krw: 1, + sgd: 973.0, + thb: 37.35, + usd: 1324.3, + }, + { + id: 81, + date: '2023-09-07', + chf: 1494.95, + cny: 182.04, + eur: 1429.08, + gbp: 1665.55, + hkd: 169.92, + jpy: 902.63, + krw: 1, + sgd: 977.09, + thb: 37.49, + usd: 1332.6, + }, + { + id: 82, + date: '2023-09-08', + chf: 1495.04, + cny: 182.02, + eur: 1427.6, + gbp: 1664.3, + hkd: 170.26, + jpy: 906.2, + krw: 1, + sgd: 977.19, + thb: 37.47, + usd: 1334.7, + }, + { + id: 83, + date: '2023-09-11', + chf: 1494.01, + cny: 181.35, + eur: 1427.94, + gbp: 1663.68, + hkd: 170.06, + jpy: 905.75, + krw: 1, + sgd: 976.6, + thb: 37.47, + usd: 1333.4, + }, + { + id: 84, + date: '2023-09-12', + chf: 1495.4, + cny: 181.82, + eur: 1432.46, + gbp: 1667.17, + hkd: 170.11, + jpy: 909.08, + krw: 1, + sgd: 979.38, + thb: 37.55, + usd: 1332.4, + }, + { + id: 85, + date: '2023-09-13', + chf: 1487.49, + cny: 181.46, + eur: 1426.35, + gbp: 1656.76, + hkd: 169.42, + jpy: 901.59, + krw: 1, + sgd: 974.61, + thb: 37.24, + usd: 1326.1, + }, + { + id: 86, + date: '2023-09-14', + chf: 1486.07, + cny: 181.9, + eur: 1425.06, + gbp: 1658.42, + hkd: 169.67, + jpy: 901.18, + krw: 1, + sgd: 975.57, + thb: 37.14, + usd: 1327.8, + }, + { + id: 87, + date: '2023-09-15', + chf: 1480.02, + cny: 182.26, + eur: 1410.84, + gbp: 1645.29, + hkd: 169.4, + jpy: 899.08, + krw: 1, + sgd: 972.46, + thb: 37.05, + usd: 1326.1, + }, + { + id: 88, + date: '2023-09-18', + chf: 1479.38, + cny: 182.58, + eur: 1415.75, + gbp: 1645.16, + hkd: 169.62, + jpy: 897.91, + krw: 1, + sgd: 973.78, + thb: 37.15, + usd: 1327.6, + }, + { + date: '2023-09-19', + id: 89, + chf: 1477.77, + cny: 182.06, + eur: 1417.76, + gbp: 1642.25, + hkd: 169.6, + jpy: 898.34, + krw: 1, + sgd: 972.53, + thb: 37.17, + usd: 1326.0, + }, +]; diff --git a/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/adminMember.ts b/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/adminMember.ts new file mode 100644 index 000000000..c2fdac7e7 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/adminMember.ts @@ -0,0 +1,25 @@ +import { HttpResponse, http } from 'msw'; + +import { END_POINTS, HTTP_STATUS_CODE } from '@constants/api'; + +import { adminMembers } from '../data/adminMember'; + +export const adminMemberHandlers = [ + http.get(END_POINTS.MEMBER, () => { + return HttpResponse.json(adminMembers); + }), + http.post(END_POINTS.MEMBER, async ({ request }) => { + const newAdminMemberId = 999; + + return new HttpResponse(null, { + status: HTTP_STATUS_CODE.CREATED, + headers: { + Location: `${END_POINTS.MEMBER}/${newAdminMemberId}`, + }, + }); + }), + http.patch(`${END_POINTS.MEMBER}/:id/password`, async ({ params, request }) => { + const { id } = params; + return new HttpResponse(null, { status: HTTP_STATUS_CODE.NO_CONTENT }); + }), +]; diff --git a/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/category.ts b/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/category.ts new file mode 100644 index 000000000..875b9b1c7 --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/category.ts @@ -0,0 +1,25 @@ +import { HttpResponse, http } from 'msw'; + +import { END_POINTS, HTTP_STATUS_CODE } from '@constants/api'; + +import { categories } from '../data/category'; + +export const categoryHandlers = [ + http.get(END_POINTS.CATEGORY, () => { + return HttpResponse.json(categories); + }), + http.post(END_POINTS.CATEGORY, async ({ request }) => { + const newCategoryId = 999; + + return new HttpResponse(null, { + status: HTTP_STATUS_CODE.CREATED, + headers: { + Location: `${END_POINTS.CATEGORY}/${newCategoryId}`, + }, + }); + }), + http.put(`${END_POINTS.CATEGORY}/:id`, async ({ params, request }) => { + const { id } = params; + return new HttpResponse(null, { status: HTTP_STATUS_CODE.NO_CONTENT }); + }), +]; diff --git a/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/city.ts b/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/city.ts index 0689cc722..3587f04c1 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/city.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/city.ts @@ -1,4 +1,4 @@ -import { http, HttpResponse } from 'msw'; +import { HttpResponse, http } from 'msw'; import { END_POINTS, HTTP_STATUS_CODE } from '@constants/api'; diff --git a/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/currency.ts b/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/currency.ts new file mode 100644 index 000000000..1090be52b --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/currency.ts @@ -0,0 +1,29 @@ +import { HttpResponse, http } from 'msw'; + +import { END_POINTS, HTTP_STATUS_CODE } from '@constants/api'; + +import { currencyListData } from '../data/currency'; + +export const currencyHandlers = [ + http.get(`${END_POINTS.CURRENCY}`, ({ request }) => { + const url = new URL(request.url); + const page = Number(url.searchParams.getAll('page')); + const size = Number(url.searchParams.getAll('size')); + + return HttpResponse.json(currencyListData(page, size)); + }), + http.post(END_POINTS.CURRENCY, async ({ request }) => { + const newCurrencyId = 999; + + return new HttpResponse(null, { + status: HTTP_STATUS_CODE.CREATED, + headers: { + Location: `${END_POINTS.CURRENCY}/${newCurrencyId}`, + }, + }); + }), + http.put(`${END_POINTS.CURRENCY}/:id`, async ({ params, request }) => { + const { id } = params; + return new HttpResponse(null, { status: HTTP_STATUS_CODE.NO_CONTENT }); + }), +]; diff --git a/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/index.ts b/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/index.ts index 676a0e9e8..2227f904b 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/index.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/mocks/handlers/index.ts @@ -1,3 +1,12 @@ import { cityHandlers } from '@mocks/handlers/city'; -export const handlers = [...cityHandlers]; +import { adminMemberHandlers } from './adminMember'; +import { categoryHandlers } from './category'; +import { currencyHandlers } from './currency'; + +export const handlers = [ + ...cityHandlers, + ...categoryHandlers, + ...currencyHandlers, + ...adminMemberHandlers, +]; diff --git a/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMainPage/AdminMainPage.style.ts b/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMainPage/AdminMainPage.style.ts index 99fd6c5bb..3f7b5a004 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMainPage/AdminMainPage.style.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMainPage/AdminMainPage.style.ts @@ -1,5 +1,4 @@ import { css } from '@emotion/react'; - import { Theme } from 'hang-log-design-system'; export interface subTitleStylingProps { diff --git a/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMainPage/AdminMainPage.tsx b/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMainPage/AdminMainPage.tsx index 8378c5b8e..fd74f4937 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMainPage/AdminMainPage.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMainPage/AdminMainPage.tsx @@ -1,6 +1,6 @@ import { Flex, Heading } from 'hang-log-design-system'; -import SidebarNavigation from '@/components/common/SidebarNavigation/SidebarNavigation'; +import SidebarNavigation from '@components/common/SidebarNavigation/SidebarNavigation'; import { subTitleStyling } from './AdminMainPage.style'; diff --git a/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMemberPage/AdminMemberPage.style.ts b/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMemberPage/AdminMemberPage.style.ts new file mode 100644 index 000000000..994998a7c --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMemberPage/AdminMemberPage.style.ts @@ -0,0 +1,36 @@ +import { css } from '@emotion/react'; +import { Theme } from 'hang-log-design-system'; + +export const containerStyling = css({ + width: '80vw', + padding: `${Theme.spacer.spacing6} ${Theme.spacer.spacing6} ${Theme.spacer.spacing0} ${Theme.spacer.spacing6}`, +}); + +export const titleStyling = css({ + alignSelf: 'flex-start', +}); + +export const addButtonStyling = css({ + margin: Theme.spacer.spacing3, + alignSelf: 'flex-end', +}); + +export const tableStyling = css({ + width: '70vw', + height: '60vh', +}); + +export const pagenationSkeletonStyling = css({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + + padding: `${Theme.spacer.spacing6} 0px ${Theme.spacer.spacing6} 0px`, + + width: '100%', + height: Theme.spacer.spacing6, + + '& > div': { + width: '300px', + }, +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMemberPage/AdminMemberPage.tsx b/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMemberPage/AdminMemberPage.tsx index db407de2e..932592dd2 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMemberPage/AdminMemberPage.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/pages/AdminMemberPage/AdminMemberPage.tsx @@ -1,13 +1,71 @@ -import { Flex, Heading } from 'hang-log-design-system'; +import { Button, Flex, Heading, useOverlay } from 'hang-log-design-system'; +import { Suspense, useCallback, useEffect, useState } from 'react'; -import SidebarNavigation from '@/components/common/SidebarNavigation/SidebarNavigation'; +import AdminMemberAddModal from '@components/adminMember/AdminMemberAddModal/AdminMemberAddModal'; +import AdminMemberTable from '@components/adminMember/AdminMemberTable/AdminMemberTable'; +import AdminMemberTableSkeleton from '@components/adminMember/AdminMemberTable/AdminMemberTableSkeleton'; +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 { TABLE_ROW_LENGTH } from '@constants/ui'; + +import { + addButtonStyling, + containerStyling, + tableStyling, + titleStyling, +} from './AdminMemberPage.style'; const AdminMemberPage = () => { + const { isOpen: isAddModalOpen, open: openAddModal, close: closeAddModal } = useOverlay(); + + const [page, setPage] = useState(1); + + const { adminMemberData } = useAdminMemberQuery(); + + const lastPageIndex = Math.ceil(adminMemberData.length / TABLE_ROW_LENGTH); + const currentPageData = adminMemberData.slice( + (page - 1) * TABLE_ROW_LENGTH, + page * TABLE_ROW_LENGTH + ); + + const { pageIndexDatas, changeNavigationDatas } = usePageIndex(lastPageIndex, page); + + const handleSetPage = useCallback((page: number) => { + setPage(page); + }, []); + + useEffect(() => { + changeNavigationDatas(); + }, [changeNavigationDatas, page]); + return ( <> - 행록 관리자 멤버 관리 페이지입니다. + + + 관리자 멤버 관리 + + +
+ }> + + +
+ +
+ {isAddModalOpen && }
); diff --git a/frontend-monorepo/packages/hanglog-admin/src/pages/CategoryPage/CategoryPage.style.ts b/frontend-monorepo/packages/hanglog-admin/src/pages/CategoryPage/CategoryPage.style.ts new file mode 100644 index 000000000..994998a7c --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/pages/CategoryPage/CategoryPage.style.ts @@ -0,0 +1,36 @@ +import { css } from '@emotion/react'; +import { Theme } from 'hang-log-design-system'; + +export const containerStyling = css({ + width: '80vw', + padding: `${Theme.spacer.spacing6} ${Theme.spacer.spacing6} ${Theme.spacer.spacing0} ${Theme.spacer.spacing6}`, +}); + +export const titleStyling = css({ + alignSelf: 'flex-start', +}); + +export const addButtonStyling = css({ + margin: Theme.spacer.spacing3, + alignSelf: 'flex-end', +}); + +export const tableStyling = css({ + width: '70vw', + height: '60vh', +}); + +export const pagenationSkeletonStyling = css({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + + padding: `${Theme.spacer.spacing6} 0px ${Theme.spacer.spacing6} 0px`, + + width: '100%', + height: Theme.spacer.spacing6, + + '& > div': { + width: '300px', + }, +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/pages/CategoryPage/CategoryPage.tsx b/frontend-monorepo/packages/hanglog-admin/src/pages/CategoryPage/CategoryPage.tsx index fbc13315f..f038e7809 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/pages/CategoryPage/CategoryPage.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/pages/CategoryPage/CategoryPage.tsx @@ -1,13 +1,71 @@ -import { Flex, Heading } from 'hang-log-design-system'; +import { Button, Flex, Heading, useOverlay } from 'hang-log-design-system'; +import { Suspense, useCallback, useEffect, useState } from 'react'; -import SidebarNavigation from '@/components/common/SidebarNavigation/SidebarNavigation'; +import CategoryAddModal from '@components/category/CategoryAddModal/CategoryAddModal'; +import CategoryTable from '@components/category/CategoryTable/CategoryTable'; +import CategoryTableSkeleton from '@components/category/CategoryTable/CategoryTableSkeleton'; +import PageNavigation from '@components/common/PageNavigation/PageNavigation'; +import SidebarNavigation from '@components/common/SidebarNavigation/SidebarNavigation'; + +import { useCategoryQuery } from '@hooks/api/useCategoryQuery'; +import { usePageIndex } from '@hooks/common/usePageIndex'; + +import { TABLE_ROW_LENGTH } from '@constants/ui'; + +import { + addButtonStyling, + containerStyling, + tableStyling, + titleStyling, +} from './CategoryPage.style'; const CategoryPage = () => { + const { isOpen: isAddModalOpen, open: openAddModal, close: closeAddModal } = useOverlay(); + + const [page, setPage] = useState(1); + + const { categoryData } = useCategoryQuery(); + + const lastPageIndex = Math.ceil(categoryData.length / TABLE_ROW_LENGTH); + const currentPageData = categoryData.slice( + (page - 1) * TABLE_ROW_LENGTH, + page * TABLE_ROW_LENGTH + ); + + const { pageIndexDatas, changeNavigationDatas } = usePageIndex(lastPageIndex, page); + + const handleSetPage = useCallback((page: number) => { + setPage(page); + }, []); + + useEffect(() => { + changeNavigationDatas(); + }, [changeNavigationDatas, page]); + return ( <> - 행록 카테고리 관리 페이지 입니다. + + + 카테고리 관리 + + +
+ }> + + +
+ +
+ {isAddModalOpen && }
); diff --git a/frontend-monorepo/packages/hanglog-admin/src/pages/CityPage/CityPage.style.ts b/frontend-monorepo/packages/hanglog-admin/src/pages/CityPage/CityPage.style.ts index bf4eb8a29..994998a7c 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/pages/CityPage/CityPage.style.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/pages/CityPage/CityPage.style.ts @@ -1,30 +1,36 @@ import { css } from '@emotion/react'; - import { Theme } from 'hang-log-design-system'; -export const containerStyling = () => { - return css({ - width: '80vw', - padding: `${Theme.spacer.spacing6} ${Theme.spacer.spacing6} ${Theme.spacer.spacing0} ${Theme.spacer.spacing6}`, - }); -}; - -export const titleStyling = () => { - return css({ - alignSelf: 'flex-start', - }); -}; - -export const addButtonStyling = () => { - return css({ - margin: Theme.spacer.spacing3, - alignSelf: 'flex-end', - }); -}; - -export const tableStyling = () => { - return css({ - width: '70vw', - height: '60vh', - }); -}; +export const containerStyling = css({ + width: '80vw', + padding: `${Theme.spacer.spacing6} ${Theme.spacer.spacing6} ${Theme.spacer.spacing0} ${Theme.spacer.spacing6}`, +}); + +export const titleStyling = css({ + alignSelf: 'flex-start', +}); + +export const addButtonStyling = css({ + margin: Theme.spacer.spacing3, + alignSelf: 'flex-end', +}); + +export const tableStyling = css({ + width: '70vw', + height: '60vh', +}); + +export const pagenationSkeletonStyling = css({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + + padding: `${Theme.spacer.spacing6} 0px ${Theme.spacer.spacing6} 0px`, + + width: '100%', + height: Theme.spacer.spacing6, + + '& > div': { + width: '300px', + }, +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/pages/CityPage/CityPage.tsx b/frontend-monorepo/packages/hanglog-admin/src/pages/CityPage/CityPage.tsx index 1c99dfd18..1b1df8155 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/pages/CityPage/CityPage.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/pages/CityPage/CityPage.tsx @@ -1,18 +1,18 @@ -import { useCallback, useEffect, useState } from 'react'; - import { Button, Flex, Heading, useOverlay } from 'hang-log-design-system'; +import { Suspense, useCallback, useEffect, useState } from 'react'; -import SidebarNavigation from '@/components/common/SidebarNavigation/SidebarNavigation'; -import PageNavigation from '@/components/common/PageNavigation/PageNavigation'; -import CityTable from '@/components/city/CityTable/CityTable'; -import CityAddModal from '@/components/city/CityAddModal/CityAddModal'; +import CityAddModal from '@components/city/CityAddModal/CityAddModal'; +import CityTable from '@components/city/CityTable/CityTable'; +import CityTableSkeleton from '@components/city/CityTable/CityTableSkeleton'; +import PageNavigation from '@components/common/PageNavigation/PageNavigation'; +import SidebarNavigation from '@components/common/SidebarNavigation/SidebarNavigation'; -import { useCityQuery } from '@/hooks/api/useCityQuery'; -import { usePageIndex } from '@/hooks/common/usePageIndex'; +import { useCityQuery } from '@hooks/api/useCityQuery'; +import { usePageIndex } from '@hooks/common/usePageIndex'; -import { TABLE_ROW_LENGTH } from '@/constants/ui'; +import { TABLE_ROW_LENGTH } from '@constants/ui'; -import { containerStyling, titleStyling, addButtonStyling, tableStyling } from './CityPage.style'; +import { addButtonStyling, containerStyling, tableStyling, titleStyling } from './CityPage.style'; const CityPage = () => { const { isOpen: isAddModalOpen, open: openAddModal, close: closeAddModal } = useOverlay(); @@ -46,7 +46,9 @@ const CityPage = () => { 추가하기
- + }> + +
{ - return
; -}; - -export default CityPageSkeleton; diff --git a/frontend-monorepo/packages/hanglog-admin/src/pages/CurrencyPage/CurrencyPage.style.ts b/frontend-monorepo/packages/hanglog-admin/src/pages/CurrencyPage/CurrencyPage.style.ts new file mode 100644 index 000000000..994998a7c --- /dev/null +++ b/frontend-monorepo/packages/hanglog-admin/src/pages/CurrencyPage/CurrencyPage.style.ts @@ -0,0 +1,36 @@ +import { css } from '@emotion/react'; +import { Theme } from 'hang-log-design-system'; + +export const containerStyling = css({ + width: '80vw', + padding: `${Theme.spacer.spacing6} ${Theme.spacer.spacing6} ${Theme.spacer.spacing0} ${Theme.spacer.spacing6}`, +}); + +export const titleStyling = css({ + alignSelf: 'flex-start', +}); + +export const addButtonStyling = css({ + margin: Theme.spacer.spacing3, + alignSelf: 'flex-end', +}); + +export const tableStyling = css({ + width: '70vw', + height: '60vh', +}); + +export const pagenationSkeletonStyling = css({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + + padding: `${Theme.spacer.spacing6} 0px ${Theme.spacer.spacing6} 0px`, + + width: '100%', + height: Theme.spacer.spacing6, + + '& > div': { + width: '300px', + }, +}); diff --git a/frontend-monorepo/packages/hanglog-admin/src/pages/CurrencyPage/CurrencyPage.tsx b/frontend-monorepo/packages/hanglog-admin/src/pages/CurrencyPage/CurrencyPage.tsx index 53f65e398..944c13e5d 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/pages/CurrencyPage/CurrencyPage.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/pages/CurrencyPage/CurrencyPage.tsx @@ -1,13 +1,68 @@ -import { Flex, Heading } from 'hang-log-design-system'; +import { Button, Flex, Heading, useOverlay } from 'hang-log-design-system'; +import { Suspense, useCallback, useEffect, useState } from 'react'; -import SidebarNavigation from '@/components/common/SidebarNavigation/SidebarNavigation'; +import PageNavigation from '@components/common/PageNavigation/PageNavigation'; +import SidebarNavigation from '@components/common/SidebarNavigation/SidebarNavigation'; +import CurrencyAddModal from '@components/currency/CurrencyAddModal/CurrencyAddModal'; +import CurrencyTable from '@components/currency/CurrencyTable/CurrencyTable'; +import CurrencyTableSkeleton from '@components/currency/CurrencyTable/CurrencyTableSkeleton'; + +import { useCurrencyQuery } from '@hooks/api/useCurrencyQuery'; +import { usePageIndex } from '@hooks/common/usePageIndex'; + +import { TABLE_ROW_LENGTH } from '@constants/ui'; + +import { + addButtonStyling, + containerStyling, + tableStyling, + titleStyling, +} from './CurrencyPage.style'; const CurrencyPage = () => { + const { isOpen: isAddModalOpen, open: openAddModal, close: closeAddModal } = useOverlay(); + + const [page, setPage] = useState(1); + + const { currencyListData } = useCurrencyQuery(page, TABLE_ROW_LENGTH); + + const { pageIndexDatas, changeNavigationDatas } = usePageIndex( + currencyListData.lastPageIndex, + page + ); + + const handleSetPage = useCallback((page: number) => { + setPage(page); + }, []); + + useEffect(() => { + changeNavigationDatas(); + }, [changeNavigationDatas, page]); + return ( <> - 행록 환율 관리 페이지 입니다. + + + 환율 관리 + + +
+ }> + + +
+ + {isAddModalOpen && } +
); diff --git a/frontend-monorepo/packages/hanglog-admin/src/router/AppRouter.tsx b/frontend-monorepo/packages/hanglog-admin/src/router/AppRouter.tsx index 37b456843..c0de082ba 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/router/AppRouter.tsx +++ b/frontend-monorepo/packages/hanglog-admin/src/router/AppRouter.tsx @@ -1,17 +1,16 @@ -import App from '@/App'; +import { Suspense } from 'react'; +import { RouterProvider, createBrowserRouter } from 'react-router-dom'; -import NotFoundPage from '@/pages/NotFoundPage/NotFoundPage'; -import AdminMainPage from '@/pages/AdminMainPage/AdminMainPage'; -import AdminMemberPage from '@/pages/AdminMemberPage/AdminMemberPage'; -import CityPage from '@/pages/CityPage/CityPage'; -import CategoryPage from '@/pages/CategoryPage/CategoryPage'; -import CurrencyPage from '@/pages/CurrencyPage/CurrencyPage'; +import App from '@/App'; -import CityPageSkeleton from '@/pages/CityPage/CityPageSkeleton'; +import AdminMainPage from '@pages/AdminMainPage/AdminMainPage'; +import AdminMemberPage from '@pages/AdminMemberPage/AdminMemberPage'; +import CategoryPage from '@pages/CategoryPage/CategoryPage'; +import CityPage from '@pages/CityPage/CityPage'; +import CurrencyPage from '@pages/CurrencyPage/CurrencyPage'; +import NotFoundPage from '@pages/NotFoundPage/NotFoundPage'; import { PATH } from '@constants/path'; -import { Suspense } from 'react'; -import { RouterProvider, createBrowserRouter } from 'react-router-dom'; const router = createBrowserRouter([ { @@ -42,7 +41,7 @@ const router = createBrowserRouter([ { path: PATH.CITY, element: ( - }> + ), diff --git a/frontend-monorepo/packages/hanglog-admin/src/styles/index.ts b/frontend-monorepo/packages/hanglog-admin/src/styles/index.ts index 4d149a0b4..280c4d698 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/styles/index.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/styles/index.ts @@ -1,5 +1,4 @@ import { css } from '@emotion/react'; - import { Theme } from 'hang-log-design-system'; export const GlobalStyle = css({ @@ -24,7 +23,7 @@ export const GlobalStyle = css({ backgroundColor: Theme.color.gray200, }, - 'th:first-of-type, td:first-of-type': { + 'th:first-of-type, th:last-of-type, td:first-of-type, td:last-of-type': { textAlign: 'center', }, }); diff --git a/frontend-monorepo/packages/hanglog-admin/src/types/adminMember.ts b/frontend-monorepo/packages/hanglog-admin/src/types/adminMember.ts index f3a0ee664..befcc513f 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/types/adminMember.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/types/adminMember.ts @@ -3,3 +3,26 @@ export interface AdminMemberData { username: string; adminType: string; } + +export interface AdminMemberPostData { + username: string; + adminType: string; + password: string; +} + +export interface AdminMemberFormData extends AdminMemberPostData { + confirmPassword: string; +} + +export type AdminTypeData = 'MASTER' | 'ADMIN'; + +export const SelectableAdminType = ['ADMIN']; + +export interface PasswordPatchData { + currentPassword: string; + newPassword: string; +} + +export interface PasswordFormData extends PasswordPatchData { + confirmPassword: string; +} diff --git a/frontend-monorepo/packages/hanglog-admin/src/types/currency.ts b/frontend-monorepo/packages/hanglog-admin/src/types/currency.ts index e39672f99..19ed886e9 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/types/currency.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/types/currency.ts @@ -17,3 +17,16 @@ export interface CurrencyListData { lastPageIndex: number; currencies: CurrencyData[]; } + +export interface CurrencyFormData { + date: string; + usd: number; + eur: number; + gbp: number; + jpy: number; + cny: number; + chf: number; + sgd: number; + thb: number; + hkd: number; +} diff --git a/frontend-monorepo/packages/hanglog-admin/src/utils/validator.ts b/frontend-monorepo/packages/hanglog-admin/src/utils/validator.ts index d000257fb..dbc76a424 100644 --- a/frontend-monorepo/packages/hanglog-admin/src/utils/validator.ts +++ b/frontend-monorepo/packages/hanglog-admin/src/utils/validator.ts @@ -1,11 +1,55 @@ +import { REGEX } from '@constants/regex'; +import { + ADMIN_MEMBER_MIN_PASSWORD_LENGTH, + CATEGORY_ID_MAX, + CATEGORY_ID_MIN, + CITY_LATITUDE_MAX, + CITY_LATITUDE_MIN, + CITY_LONGITUDE_MAX, + CITY_LONGITUDE_MIN, + CURRENCY_MAX, + CURRENCY_MIN, +} from '@constants/ui'; + export const isEmptyString = (input: string) => { return /^$/.test(input); }; export const isInvalidLatitude = (input: number) => { - return input > 90 || input < -90; + return input > CITY_LATITUDE_MAX || input < CITY_LATITUDE_MIN; }; export const isInvalidLongitude = (input: number) => { - return input > 180 || input < -180; + return input > CITY_LONGITUDE_MAX || input < CITY_LONGITUDE_MIN; +}; + +export const isInvalidCategoryId = (input: number) => { + return input > CATEGORY_ID_MAX || input < CATEGORY_ID_MIN; +}; + +export const isEnglish = (input: string) => { + return REGEX.ALPHABET.test(input); +}; + +export const isKorean = (input: string) => { + return REGEX.KOREAN_CHARACTERS.test(input); +}; + +export const isValidCurrencyDate = (input: string) => { + if (!REGEX.DATE.test(input)) return false; + + const [year, month, day] = input.split('-').map(Number); + const dateObj = new Date(year, month - 1, day); + + return ( + dateObj.getFullYear() === year && dateObj.getMonth() === month - 1 && dateObj.getDate() === day + ); +}; + +export const isInvalidCurrency = (input: number) => { + return input < CURRENCY_MIN || input > CURRENCY_MAX; +}; + +export const isValidPassword = (input: string) => { + return input.length >= ADMIN_MEMBER_MIN_PASSWORD_LENGTH; }; diff --git a/frontend-monorepo/yarn.lock b/frontend-monorepo/yarn.lock index 818dba8f4..226c4accb 100644 --- a/frontend-monorepo/yarn.lock +++ b/frontend-monorepo/yarn.lock @@ -5007,7 +5007,7 @@ __metadata: languageName: node linkType: hard -"@trivago/prettier-plugin-sort-imports@npm:^4.1.1": +"@trivago/prettier-plugin-sort-imports@npm:^4.1.1, @trivago/prettier-plugin-sort-imports@npm:^4.3.0": version: 4.3.0 resolution: "@trivago/prettier-plugin-sort-imports@npm:4.3.0" dependencies: @@ -11355,6 +11355,7 @@ __metadata: "@storybook/react-vite": "npm:^7.6.10" "@storybook/test": "npm:^7.6.10" "@tanstack/react-query": "npm:^5.17.19" + "@trivago/prettier-plugin-sort-imports": "npm:^4.3.0" "@types/babel__core": "npm:^7" "@types/babel__preset-env": "npm:^7" "@types/react": "npm:^18.2.43"