Skip to content

Commit 7e37147

Browse files
committed
♻️ [refactor] 카테고리 추가 / 수정 validation 리팩토링
1 parent de1ccb4 commit 7e37147

File tree

9 files changed

+72
-56
lines changed

9 files changed

+72
-56
lines changed

src/api/common.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,56 @@
1+
import { useMemberStore } from '@/stores/member'
12
import { axiosInstance, formDataAxiosInstance } from '../utils/axios'
3+
import { createPinia, setActivePinia, storeToRefs } from 'pinia'
4+
5+
setActivePinia(createPinia())
6+
7+
const memberStore = useMemberStore()
8+
const { isLogined } = storeToRefs(memberStore)
29

310
export const patchEditInfo = async (formdata: FormData) => {
11+
if (!isLogined) return
412
const response = await formDataAxiosInstance.patch('/api/members/info', formdata)
513
return response.data
614
}
715

816
export const getNotification = async (pageNum: number, sizeNum: number) => {
17+
if (!isLogined) return
918
const response = await axiosInstance.get(`/api/notifications?page=${pageNum}&size=${sizeNum}`)
10-
1119
return response.data
1220
}
1321

1422
export const patchNotificationRead = async (notificationId: number) => {
23+
if (!isLogined) return
1524
const response = await axiosInstance.patch(`/api/notifications/${notificationId}`)
1625
return response.data
1726
}
1827

1928
export const getNotifiCount = async () => {
29+
if (!isLogined) return
2030
const response = await axiosInstance.get(`/api/notifications/count`)
2131
return response.data
2232
}
2333

2434
export const getMainCategory = async () => {
35+
if (!isLogined) return
2536
const response = await axiosInstance.get('/api/main-category')
2637
return response.data
2738
}
2839

2940
export const getSubCategory = async () => {
41+
if (!isLogined) return
3042
const response = await axiosInstance.get('/api/sub-category')
3143
return response.data
3244
}
3345

3446
export const getLabels = async () => {
47+
if (!isLogined) return
3548
const response = await axiosInstance.get('/api/labels')
3649
return response.data
3750
}
3851

3952
export const getCategory = async () => {
53+
if (!isLogined) return
4054
const response = await axiosInstance.get('/api/category')
4155
return response.data
4256
}

src/components/request-approve/RequestApprove.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ import CategoryDropDown from '../request-task/CategoryDropDown.vue'
7171
import DueDateInput from './DueDateInput.vue'
7272
import LabelDropdown from './LabelDropdown.vue'
7373
import ManagerDropdown from './ManagerDropdown.vue'
74+
import { useErrorStore } from '@/stores/error'
75+
import { redirectToLogin } from '@/utils/redirectToLogin'
7476
7577
const isModalVisible = ref(false)
7678
const category1 = ref<Category | null>(null)
@@ -109,6 +111,11 @@ onBeforeRouteLeave((to, from, next) => {
109111
})
110112
111113
onMounted(async () => {
114+
const { setError } = useErrorStore()
115+
if (!requestId) {
116+
setError('존재하지 않는 요청입니다', '', () => redirectToLogin('/requested'))
117+
return
118+
}
112119
mainCategoryArr.value = await getMainCategory()
113120
subCategoryArr.value = await getSubCategory()
114121
const data = await getTaskDetailUser(requestId)

src/components/request-task/RequestTask.vue

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
:options="mainCategoryArr"
66
:label-name="'1차 카테고리'"
77
:placeholderText="'1차 카테고리를 선택해주세요'"
8-
:is-invalidate="isInvalidate"
8+
:is-invalidate="isInvalidate === 'category1' ? 'category' : ''"
99
:isDisabled="false" />
1010
<CategoryDropDown
1111
v-model="category2"
1212
:options="afterSubCategoryArr"
1313
:label-name="'2차 카테고리'"
1414
:placeholderText="'2차 카테고리를 선택해주세요'"
15-
:is-invalidate="isInvalidate"
15+
:is-invalidate="isInvalidate === 'category2' ? 'category' : ''"
1616
:isDisabled="!category1" />
1717
<RequestTaskInput
1818
v-model="title"
@@ -107,8 +107,11 @@ const handleCancel = () => {
107107
const handleSubmit = async () => {
108108
if (isSubmitting.value || isModalVisible.value) return
109109
110-
if (!category1.value || !category2.value) {
111-
isInvalidate.value = 'category'
110+
if (!category1.value) {
111+
isInvalidate.value = 'category1'
112+
return
113+
} else if (!category2.value) {
114+
isInvalidate.value = 'category2'
112115
return
113116
} else if (!title.value) {
114117
isInvalidate.value = 'input'

src/components/request-task/RequestTaskDropdown.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<div class="flex text-xs text-red-1 gap-x-1 mb-2">
44
<p class="text-body font-bold">{{ labelName }}</p>
55
<p v-if="!isLabel">*</p>
6+
<p v-if="!isInvalidate">카테고리를 선택해주세요</p>
67
</div>
78
<div
89
ref="htmlRef"
@@ -40,7 +41,7 @@ import { ref } from 'vue'
4041
import CommonIcons from '../common/CommonIcons.vue'
4142
import { useOutsideClick } from '@/hooks/useOutsideClick'
4243
43-
const { placeholderText, options, labelName, modelValue, isLabel, disabled } =
44+
const { placeholderText, options, labelName, modelValue, isLabel, disabled, isInvalidate } =
4445
defineProps<RequestTaskDropdownProps>()
4546
const emit = defineEmits(['update:modelValue'])
4647
const dropdownOpen = ref(false)

src/components/request-task/RequestTaskInput.vue

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
<p v-if="isInvalidateState === 'input'">{{ labelName }}을 입력해주세요</p>
77
<p v-if="isInvalidateState === 'duplicate'">회원아이디가 중복되었습니다</p>
88
<p v-if="isInvalidateState === 'title'">제목은 30자 이내로 적어주세요</p>
9+
<p v-if="isInvalidateState === 'noCode'">작업코드를 입력해주세요</p>
10+
<p v-if="isInvalidateState === 'code'">사용할 수 없는 작업코드입니다</p>
11+
<p v-if="isInvalidateState === 'categoryName'">카테고리명을 입력해주세요</p>
912
</div>
1013
<input
1114
class="w-full h-11 border border-border-1 px-4 focus:outline-none rounded"
@@ -15,11 +18,6 @@
1518
:placeholder="placeholderText"
1619
:class="{ 'text-gray-500': isEdit }"
1720
:maxlength="labelName === '제목' ? 30 : undefined" />
18-
<p
19-
v-if="isInvalidateState === 'code'"
20-
class="text-red-1 text-xs absolute top-[calc(100%+4px)]">
21-
사용할 수 없는 작업코드입니다.
22-
</p>
2321
</div>
2422
</template>
2523

src/components/task-management/CategoryAdd.vue

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,24 @@
1414
<template #header>{{ route.params.id ? '수정을' : '추가를' }} 취소 하시겠습니까?</template>
1515
<template #body>작성하신 내용은 사라집니다</template>
1616
</ModalView>
17-
<ModalView
18-
:is-open="isModalVisible.fail"
19-
type="failType"
20-
@close="handleFailModal">
21-
<template #header>{{ errorMessage }}</template>
22-
</ModalView>
2317
<RequestTaskDropdown
2418
v-model="mainCategory"
2519
:options="categoryOptions.map(el => el.name)"
2620
label-name="1차 카테고리"
2721
placeholder-text="1차 카테고리를 선택해주세요"
2822
v-if="categoryStep == '2'"
29-
:disabled="route.params.id !== undefined" />
23+
:disabled="route.params.id !== undefined"
24+
:is-invalidate="hasMainCategory" />
3025
<RequestTaskInput
3126
v-model="categoryForm.name"
3227
placeholder-text="카테고리명을 입력해주세요"
33-
:label-name="`${categoryStep}차 카테고리명`" />
28+
:label-name="`${categoryStep}차 카테고리명`"
29+
:is-invalidate="errorMessage.categoryName" />
3430
<RequestTaskInput
3531
v-model="categoryForm.code"
3632
placeholder-text="카테고리의 작업코드를 입력해주세요"
3733
label-name="작업코드 (대문자 영어 2글자까지)"
38-
:is-invalidate="isCodeInvalidate" />
34+
:is-invalidate="errorMessage.categoryCode === 'noCode' ? 'noCode' : isCodeInvalidate" />
3935

4036
<div
4137
v-if="categoryStep === '2'"
@@ -68,7 +64,6 @@ import { axiosInstance } from '@/utils/axios'
6864
import { getMainCategory } from '@/api/common'
6965
import type { Category, CategoryForm } from '@/types/common'
7066
import ModalView from '../common/ModalView.vue'
71-
import axios from 'axios'
7267
7368
const router = useRouter()
7469
const route = useRoute()
@@ -78,7 +73,8 @@ const { categoryStep } = defineProps<{
7873
}>()
7974
8075
const isModalVisible = ref({ add: false, cancel: false, fail: false })
81-
const errorMessage = ref('')
76+
const errorMessage = ref({ categoryName: '', categoryCode: '' })
77+
const hasMainCategory = ref(true)
8278
8379
const categoryForm = ref<CategoryForm>(CATEGORY_FORM)
8480
@@ -89,10 +85,6 @@ const handleAddModal = () => {
8985
const handleCancelModal = () => {
9086
isModalVisible.value.cancel = !isModalVisible.value.cancel
9187
}
92-
const handleFailModal = (message: string = '카테고리 정보를 확인해주세요') => {
93-
errorMessage.value = message
94-
isModalVisible.value.fail = !isModalVisible.value.fail
95-
}
9688
9789
const handleCancel = () => {
9890
handleCancelModal()
@@ -103,36 +95,32 @@ const handleGoBack = () => {
10395
}
10496
10597
const handleSubmit = async () => {
106-
if (
107-
isCodeInvalidate.value ||
108-
categoryForm.value.name.length === 0 ||
109-
categoryForm.value.code.length === 0 ||
110-
(categoryStep === '2' && categoryForm.value.mainCategoryId === undefined)
111-
) {
112-
handleFailModal()
98+
hasMainCategory.value = true
99+
errorMessage.value = { categoryCode: '', categoryName: '' }
100+
if (!categoryForm.value.mainCategoryId) {
101+
hasMainCategory.value = false
102+
return
103+
} else if (isCodeInvalidate.value) {
104+
errorMessage.value.categoryCode = 'code'
105+
return
106+
} else if (categoryForm.value.name.length === 0) {
107+
errorMessage.value.categoryName = 'categoryName'
108+
return
109+
} else if (categoryForm.value.code.length === 0) {
110+
errorMessage.value.categoryCode = 'noCode'
113111
return
114112
}
115113
116-
try {
117-
const categoryId = route.params.id
118-
if (categoryId) {
119-
const patchUrl = `/api/managements/categories/${categoryId}`
120-
await axiosInstance.patch(patchUrl, categoryForm.value)
121-
} else {
122-
const postUrl =
123-
categoryStep === '1' ? '/api/managements/main-category' : '/api/managements/sub-category'
124-
await axiosInstance.post(postUrl, categoryForm.value)
125-
}
126-
isModalVisible.value.add = true
127-
} catch (error) {
128-
if (axios.isAxiosError(error)) {
129-
if (error.response?.data === 'TASK_013') {
130-
handleFailModal('중복된 카테고리명\n혹은 고유코드입니다')
131-
} else {
132-
handleFailModal()
133-
}
134-
}
114+
const categoryId = route.params.id
115+
if (categoryId) {
116+
const patchUrl = `/api/managements/categories/${categoryId}`
117+
await axiosInstance.patch(patchUrl, categoryForm.value)
118+
} else {
119+
const postUrl =
120+
categoryStep === '1' ? '/api/managements/main-category' : '/api/managements/sub-category'
121+
await axiosInstance.post(postUrl, categoryForm.value)
135122
}
123+
isModalVisible.value.add = true
136124
}
137125
138126
const isCodeInvalidate = computed(() => {
@@ -163,7 +151,8 @@ onMounted(async () => {
163151
const mainCategoryId = ref(Number(route.query.mainCategoryId))
164152
categoryForm.value.mainCategoryId = mainCategoryId.value
165153
mainCategory.value =
166-
categoryOptions.value.find(el => el.mainCategoryId === mainCategoryId.value)?.name || ''
154+
categoryOptions.value.find(el => el.mainCategoryId === mainCategoryId.value)?.name ||
155+
'1차 카테고리를 선택해주세요'
167156
}
168157
if (id) {
169158
const { data: initialValue } = await axiosInstance.get(`/api/sub-categories/${id}`)

src/types/user.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface RequestTaskDropdownProps {
2121
modelValue: string
2222
isLabel?: boolean
2323
disabled?: boolean
24+
isInvalidate?: boolean
2425
}
2526

2627
export interface RequestTaskInputProps {

src/utils/axios.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const setInterceptors = (instance: AxiosInstance) => {
4343
instance.interceptors.response.use(
4444
response => response,
4545
async error => {
46+
console.log(error)
4647
const { setError } = useErrorStore()
4748
if (axios.isCancel(error)) {
4849
setError('요청이 취소되었습니다:', error.message)
@@ -77,7 +78,9 @@ const setInterceptors = (instance: AxiosInstance) => {
7778
break
7879
}
7980
case 400:
80-
if (error.response.data === 'MEMBER_013') {
81+
if (error.response.data === 'TASK_013') {
82+
setError('중복된 카테고리명\n혹은 고유코드입니다')
83+
} else if (error.response.data === 'MEMBER_013') {
8184
return Promise.reject(new Error('MEMBER_REVIEWER'))
8285
} else if (error.response.data === 'MEMBER_012') {
8386
return Promise.reject(new Error('MEMBER_DUPLICATED'))

src/utils/redirectToLogin.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useErrorStore } from '@/stores/error'
22

3-
export const redirectToLogin = () => {
3+
export const redirectToLogin = (url?: string) => {
44
const { clearError } = useErrorStore()
55
clearError()
6-
window.location.href = '/login'
6+
window.location.href = url || '/login'
77
}

0 commit comments

Comments
 (0)