직책관리
-
+
diff --git a/src/pages/admin/DutyManage/Tooltip/DutyProfileTooltip.tsx b/src/pages/admin/DutyManage/Tooltip/DutyProfileTooltip.tsx
index 0887743aa..de8b48605 100644
--- a/src/pages/admin/DutyManage/Tooltip/DutyProfileTooltip.tsx
+++ b/src/pages/admin/DutyManage/Tooltip/DutyProfileTooltip.tsx
@@ -3,6 +3,7 @@ import { Typography } from '@mui/material';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import { VscSearch } from 'react-icons/vsc';
+import { MEMBER_ROLE } from '@constants/member';
import muiTheme from '@constants/muiTheme';
import { roleDutyListInfo, roles } from '@mocks/DutyManageApi';
@@ -50,13 +51,8 @@ const DutyProfileTooltip = ({ jobName }: DutyProfileTooltipProps) => {
const [tooltipOpen, setTooltipOpen] = useState(false);
const [modalOpen, toggleModalOpen] = useReducer((prev) => !prev, false);
- let badgeImage;
- if (jobName.search('전산관리자') !== -1) {
- badgeImage = roles.find((role) => role.name === 'ROLE_전산관리자')?.img;
- } else {
- badgeImage = roles.find((role) => role.name === jobName)?.img;
- }
-
+ const badgeImage = roles.find((role) => role.name === jobName)?.img;
+ // NOTE jobName으로는 "ROLE_전산관리자" 내려오지만, roles에는 존재하지 않습니다! 세부적인 전산관리자(프론트, 백, 인프라)만 존재합니다
return (
{
setTooltipOpen={setTooltipOpen}
toggleModalOpen={toggleModalOpen}
/>
- {jobName !== 'ROLE_전산관리자' ? (
+ {jobName !== MEMBER_ROLE.전산관리자 && (
<>
{
badgeImage={badgeImage}
/>
>
- ) : null}
+ )}
);
};
diff --git a/src/pages/admin/LibraryManage/Modal/UploadBookModal.tsx b/src/pages/admin/LibraryManage/Modal/UploadBookModal.tsx
index da29a157d..4dbd95232 100644
--- a/src/pages/admin/LibraryManage/Modal/UploadBookModal.tsx
+++ b/src/pages/admin/LibraryManage/Modal/UploadBookModal.tsx
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { Typography, Tooltip } from '@mui/material';
import { ManageBookInfo } from '@api/dto';
import { useAddBookMutation, useEditBookInfoMutation, useEditBookThumbnailMutation } from '@api/libraryManageApi';
+import { COMMON } from '@constants/helperText';
import StandardInput from '@components/Input/StandardInput';
import ActionModal from '@components/Modal/ActionModal';
import ImageUploader from '@components/Uploader/ImageUploader';
@@ -40,19 +41,19 @@ const UploadBookModal = ({ open, onClose, bookDetail }: SelectorProps) => {
const authorTrim = author.trim();
if (titleTrim === '') {
- setTitleHelperText('도서명을 입력해주세요');
+ setTitleHelperText(COMMON.error.required);
setIsInvalidTitle(true);
}
if (authorTrim === '') {
- setAuthorHelperText('저자명을 입력해주세요');
+ setAuthorHelperText(COMMON.error.required);
setIsInvalidAuthor(true);
}
- if (titleTrim.length > 30) {
- setTitleHelperText('도서명은 200자 이내여야 합니다.');
+ if (titleTrim.length > 200) {
+ setTitleHelperText(COMMON.error.maxLength(200));
setIsInvalidTitle(true);
}
- if (authorTrim.length > 20) {
- setAuthorHelperText('저자명은 30자 이내여야 합니다.');
+ if (authorTrim.length > 30) {
+ setAuthorHelperText(COMMON.error.maxLength(30));
setIsInvalidAuthor(true);
}
diff --git a/src/pages/admin/LibraryManage/Selector/TotalBookNumberSelector.tsx b/src/pages/admin/LibraryManage/Selector/TotalBookNumberSelector.tsx
index ee49c0898..cad212787 100644
--- a/src/pages/admin/LibraryManage/Selector/TotalBookNumberSelector.tsx
+++ b/src/pages/admin/LibraryManage/Selector/TotalBookNumberSelector.tsx
@@ -8,18 +8,7 @@ interface TotalBookNumberProps {
}
const TotalBookNumberSelector = ({ value, setValue }: TotalBookNumberProps) => {
- const bookNumberList = [
- { id: 1, content: '1권' },
- { id: 2, content: '2권' },
- { id: 3, content: '3권' },
- { id: 4, content: '4권' },
- { id: 5, content: '5권' },
- { id: 6, content: '6권' },
- { id: 7, content: '7권' },
- { id: 8, content: '8권' },
- { id: 9, content: '9권' },
- { id: 10, content: '10권' },
- ];
+ const bookNumberList = Array.from({ length: 20 }, (_, index) => ({ id: index + 1, content: `${index + 1}권` }));
const handleTotalBookNumberChange = (event: SelectChangeEvent
) => {
setValue(Number(event.target.value as string));
diff --git a/src/pages/board/BoardView/Modal/SecretPostModal.tsx b/src/pages/board/BoardView/Modal/SecretPostModal.tsx
index febb863c0..320dd86e4 100644
--- a/src/pages/board/BoardView/Modal/SecretPostModal.tsx
+++ b/src/pages/board/BoardView/Modal/SecretPostModal.tsx
@@ -2,7 +2,7 @@ import React, { Dispatch, SetStateAction } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { Typography } from '@mui/material';
-import { REQUIRE_ERROR_MSG } from '@constants/errorMsg';
+import { BOARD_MSG, COMMON } from '@constants/helperText';
import { POST_PASSWORD_MAX_LENGTH } from '@pages/board/BoardWrite/Modal/SettingUploadModal';
import StandardInput from '@components/Input/StandardInput';
import ActionModal from '@components/Modal/ActionModal';
@@ -49,10 +49,10 @@ const SecretPostModal = ({ setPassword, setIsSecretPasswordSubmited, open, setOp
defaultValue=""
control={control}
rules={{
- required: `작성자가 아닐 시 ${REQUIRE_ERROR_MSG}`,
+ required: BOARD_MSG.error.requiredPassword,
maxLength: {
value: POST_PASSWORD_MAX_LENGTH,
- message: `비밀번호는 최대 ${POST_PASSWORD_MAX_LENGTH}글자 입력이 가능합니다.`,
+ message: COMMON.error.maxLength(POST_PASSWORD_MAX_LENGTH),
},
}}
render={({ field, fieldState: { error } }) => {
diff --git a/src/pages/board/BoardWrite/BoardWrite.tsx b/src/pages/board/BoardWrite/BoardWrite.tsx
index 5422ce7b7..c03a112db 100644
--- a/src/pages/board/BoardWrite/BoardWrite.tsx
+++ b/src/pages/board/BoardWrite/BoardWrite.tsx
@@ -13,7 +13,7 @@ import {
useEditPostThumbnailMutation,
useUploadPostMutation,
} from '@api/postApi';
-import { REQUIRE_ERROR_MSG } from '@constants/errorMsg';
+import { COMMON } from '@constants/helperText';
import memberState from '@recoil/member.recoil';
import { categoryNameToId } from '@utils/converter';
import OutlinedButton from '@components/Button/OutlinedButton';
@@ -74,7 +74,7 @@ const BoardWrite = () => {
if (!content || content.length < 0) {
setHasContent(false);
- setContentErrMsg(REQUIRE_ERROR_MSG);
+ setContentErrMsg(COMMON.error.required);
return;
}
setHasContent(true);
@@ -172,10 +172,10 @@ const BoardWrite = () => {
defaultValue={editMode ? editMode.post.title : ''}
control={control}
rules={{
- required: REQUIRE_ERROR_MSG,
+ required: COMMON.error.required,
maxLength: {
value: POST_TITLE_MAX_LENGTH,
- message: `제목은 최대 ${POST_TITLE_MAX_LENGTH}글자 입력이 가능합니다.`,
+ message: COMMON.error.maxLength(POST_TITLE_MAX_LENGTH),
},
}}
render={({ field, fieldState: { error } }) => {
diff --git a/src/pages/board/BoardWrite/Modal/SettingUploadModal.tsx b/src/pages/board/BoardWrite/Modal/SettingUploadModal.tsx
index a8507fb50..14a8d3618 100644
--- a/src/pages/board/BoardWrite/Modal/SettingUploadModal.tsx
+++ b/src/pages/board/BoardWrite/Modal/SettingUploadModal.tsx
@@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { Checkbox, FormControlLabel, FormGroup, Typography, useMediaQuery, useTheme } from '@mui/material';
import { UploadPostSettings, PostInfo } from '@api/dto';
-import { REQUIRE_ERROR_MSG } from '@constants/errorMsg';
+import { COMMON } from '@constants/helperText';
import StandardInput from '@components/Input/StandardInput';
import ActionModal from '@components/Modal/ActionModal';
import ImageUploader from '@components/Uploader/ImageUploader';
@@ -118,10 +118,10 @@ const SettingUploadModal = ({
defaultValue=""
control={control}
rules={{
- required: REQUIRE_ERROR_MSG,
+ required: COMMON.error.required,
maxLength: {
value: POST_PASSWORD_MAX_LENGTH,
- message: `비밀번호는 최대 ${POST_PASSWORD_MAX_LENGTH}글자 입력이 가능합니다.`,
+ message: COMMON.error.maxLength(POST_PASSWORD_MAX_LENGTH),
},
}}
render={({ field, fieldState: { error } }) => {
diff --git a/src/pages/home/Trendings.tsx b/src/pages/home/Trendings.tsx
index 795025165..88605b70d 100644
--- a/src/pages/home/Trendings.tsx
+++ b/src/pages/home/Trendings.tsx
@@ -12,8 +12,8 @@ const Card = ({ post }: { post: TrendingPostInfo }) => {
diff --git a/src/pages/login/Search/SearchPWFirstStep.tsx b/src/pages/login/Search/SearchPWFirstStep.tsx
index 4756b7177..d495db9d5 100644
--- a/src/pages/login/Search/SearchPWFirstStep.tsx
+++ b/src/pages/login/Search/SearchPWFirstStep.tsx
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { Divider, Typography, useMediaQuery, useTheme } from '@mui/material';
import { DateTime } from 'luxon';
import { useCheckAuthCodeMutation, useRequestAuthCodeMutation } from '@api/SearchAccountApi';
-import { REQUIRE_ERROR_MSG } from '@constants/errorMsg';
+import { COMMON, EMAIL_MSG } from '@constants/helperText';
import { validateEmail } from '@utils/validateEmail';
import OutlinedButton from '@components/Button/OutlinedButton';
import EmailAuthInput from '@components/Input/EmailAuthInput';
@@ -64,17 +64,17 @@ const SearchPWFirstStep = ({ setCurrentStep, form, setForm }: SearchPWFirstStepP
const handleEmailBlur = () => {
if (!validateEmail(form.email)) {
- setEmailErrorMsg('이메일 형식을 확인해주세요.');
+ setEmailErrorMsg(EMAIL_MSG.error.formatError);
}
};
const handleRequestVerificationCode = () => {
if (!form.id) {
- setIdErrorMsg(REQUIRE_ERROR_MSG);
+ setIdErrorMsg(COMMON.error.required);
return;
}
if (!form.email) {
- setEmailErrorMsg(REQUIRE_ERROR_MSG);
+ setEmailErrorMsg(COMMON.error.required);
return;
}
diff --git a/src/pages/login/Search/SearchPWSecondStep.tsx b/src/pages/login/Search/SearchPWSecondStep.tsx
index 151be0191..80b78ddf1 100644
--- a/src/pages/login/Search/SearchPWSecondStep.tsx
+++ b/src/pages/login/Search/SearchPWSecondStep.tsx
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Divider } from '@mui/material';
import { useChangePasswordMutation } from '@api/SearchAccountApi';
+import { CONFIRM_PASSWORD_MSG } from '@constants/helperText';
import OutlinedButton from '@components/Button/OutlinedButton';
import StandardInput from '@components/Input/StandardInput';
@@ -45,11 +46,11 @@ const SearchPWSecondStep = ({ setCurrentStep, firstForm }: SearchPWSecondStepPro
const handleBlur = (e: React.FocusEvent) => {
const { name, value } = e.currentTarget;
if (name === 'newPassword') {
- if (value && !passwordRegex.test(value)) setPasswordErrorMsg('8~20자 영문과 숫자를 사용하세요.');
+ if (value && !passwordRegex.test(value)) setPasswordErrorMsg(CONFIRM_PASSWORD_MSG.error.formatError);
}
if (name === 'confirmPassword') {
if (!(value.length > 0 && isSame)) {
- setConfirmPasswordErrorMsg('비밀번호가 일치하지 않습니다.');
+ setConfirmPasswordErrorMsg(CONFIRM_PASSWORD_MSG.error.mismatch);
}
}
};
@@ -112,7 +113,7 @@ const SearchPWSecondStep = ({ setCurrentStep, firstForm }: SearchPWSecondStepPro
onChange={handleChange}
onBlur={handleBlur}
error={Boolean(confirmPasswordErrorMsg)}
- helperText={confirmPasswordErrorMsg || (isSame && '비밀번호가 일치합니다.')}
+ helperText={confirmPasswordErrorMsg || (isSame && CONFIRM_PASSWORD_MSG.success.match)}
/>
diff --git a/src/pages/senimarAttend/Card/MemberCardContent.tsx b/src/pages/senimarAttend/Card/MemberCardContent.tsx
index c8ead08ea..0e3ed25c7 100644
--- a/src/pages/senimarAttend/Card/MemberCardContent.tsx
+++ b/src/pages/senimarAttend/Card/MemberCardContent.tsx
@@ -5,6 +5,7 @@ import { DateTime } from 'luxon';
import { useRecoilState } from 'recoil';
import { SeminarStatus } from '@api/dto';
import { useAttendSeminarMutation, useGetAvailableSeminarInfoQuery, useGetSeminarInfoQuery } from '@api/seminarApi';
+import { MEMBER_CARD } from '@constants/apiResponseMessage';
import FilledButton from '@components/Button/FilledButton';
import ConfirmModal from '@components/Modal/ConfirmModal';
import Countdown from '../Countdown/Countdown';
@@ -51,10 +52,10 @@ const MemberCardContent = ({ seminarId }: { seminarId: number }) => {
if (remainAttendCount <= 0) {
setExcessModalOpen(true);
- setIncorrectCodeMsg('남은 제출 횟수가 없습니다.');
+ setIncorrectCodeMsg(MEMBER_CARD.error.noSubmissionsLeft);
return;
}
- setIncorrectCodeMsg(`출석코드가 틀렸습니다. (남은 제출횟수 ${remainAttendCount}회)`);
+ setIncorrectCodeMsg(MEMBER_CARD.error.mismatchWithCount(remainAttendCount));
return;
}
const errorMessage = axiosError?.response?.data?.message;
diff --git a/src/pages/senimarAttend/SenimarAttend.tsx b/src/pages/senimarAttend/SenimarAttend.tsx
index 0b650e475..4ce8edaa2 100644
--- a/src/pages/senimarAttend/SenimarAttend.tsx
+++ b/src/pages/senimarAttend/SenimarAttend.tsx
@@ -8,6 +8,7 @@ import {
useGetRecentlyDoneSeminarInfoQuery,
useGetRecentlyUpcomingSeminarInfoQuery,
} from '@api/seminarApi';
+import { MEMBER_ROLE } from '@constants/member';
import useCheckAuth from '@hooks/useCheckAuth';
import memberState from '@recoil/member.recoil';
import starterState from '@recoil/seminarStarter.recoil';
@@ -30,7 +31,7 @@ const SeminarAttend = () => {
const { data: availableSeminarData } = useGetAvailableSeminarInfoQuery();
const { checkIncludeOneOfAuths } = useCheckAuth();
- const authorizedMember = checkIncludeOneOfAuths(['ROLE_회장', 'ROLE_부회장', 'ROLE_서기']);
+ const authorizedMember = checkIncludeOneOfAuths([MEMBER_ROLE.회장, MEMBER_ROLE.부회장, MEMBER_ROLE.서기]);
const startMember: number | undefined = useRecoilValue(starterState);
const member: MemberInfo | null = useRecoilValue(memberState);
diff --git a/tailwind.config.js b/tailwind.config.js
index a59598de0..85aa1a2ee 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,64 +1,63 @@
/** @type {import('tailwindcss').Config} */
+import { KEEPER_HEIGHT, KEEPER_COLOR, KEEPER_WIDTH } from './src/constants/keeperTheme';
-module.exports = {
- content: ['./src/**/*.{js,jsx,ts,tsx}'],
- theme: {
- extend: {
- colors: {
- mainBlack: '#131316',
- middleBlack: '#18181C',
- subBlack: '#26262C',
- pointBlue: '#4CEEF9',
- subGray: '#575E69',
- subRed: '#EF4444',
- subOrange: '#FFA500',
- },
- fontFamily: {
- base: 'IBM Plex Sans KR, system-ui, sans-serif',
- orbitron: '"Orbitron", sans-serif',
- },
- fontSize: {
- h1: '28px',
- h3: '20px',
- paragraph: '14px',
- small: '10px',
- },
- spacing: {
- header: '66px',
- sidebar: '240px',
- },
- maxWidth: {
- container: '1080px',
- },
- minWidth: {
- sidebar: '240px',
- },
- backgroundImage: {
- galaxy: "url('/public/img/background_galaxy.png')",
- },
- keyframes: {
- typing: {
- '0%': {
- width: '0%',
- visibility: 'hidden',
- },
- '100%': {
- width: '100%',
- },
+export const content = ['./src/**/*.{js,jsx,ts,tsx}'];
+export const theme = {
+ extend: {
+ colors: {
+ mainBlack: KEEPER_COLOR.mainBlack,
+ middleBlack: KEEPER_COLOR.middleBlack,
+ subBlack: KEEPER_COLOR.subBlack,
+ pointBlue: KEEPER_COLOR.pointBlue,
+ subGray: KEEPER_COLOR.subGray,
+ subRed: KEEPER_COLOR.subRed,
+ subOrange: KEEPER_COLOR.subOrange,
+ },
+ fontFamily: {
+ base: 'IBM Plex Sans KR, system-ui, sans-serif',
+ orbitron: '"Orbitron", sans-serif',
+ },
+ fontSize: {
+ h1: '28px',
+ h3: '20px',
+ paragraph: '14px',
+ small: '10px',
+ },
+ spacing: {
+ header: KEEPER_HEIGHT.header.sm,
+ sidebar: KEEPER_WIDTH.sidebar,
+ },
+ maxWidth: {
+ container: KEEPER_WIDTH.container,
+ },
+ minWidth: {
+ sidebar: KEEPER_WIDTH.sidebar,
+ },
+ backgroundImage: {
+ galaxy: "url('/public/img/background_galaxy.png')",
+ },
+ keyframes: {
+ typing: {
+ '0%': {
+ width: '0%',
+ visibility: 'hidden',
},
- blink: {
- '50%': {
- borderColor: 'transparent',
- },
- '100%': {
- borderColor: 'white',
- },
+ '100%': {
+ width: '100%',
},
},
- animation: {
- typing: 'typing 2s steps(25), blink',
+ blink: {
+ '50%': {
+ borderColor: 'transparent',
+ },
+ '100%': {
+ borderColor: 'white',
+ },
},
},
+ animation: {
+ typing: 'typing 2s steps(25), blink',
+ },
},
- plugins: [],
};
+export const plugins = [];