Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 6 additions & 18 deletions src/api/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ import Cookies from 'js-cookie'
import type { loginDataTypes } from '@/types/auth'
import { useMemberStore } from '@/stores/member'

export const postLogin = async (loginData: loginDataTypes, sessionId: string) => {
const memberStore = useMemberStore()
const response = await axiosInstance.post('/api/auths/login', loginData, {
headers: { sessionId: sessionId }
})
export const postLogin = async (loginData: loginDataTypes) => {
const response = await axiosInstance.post('/api/auths/login', loginData)
Cookies.set('accessToken', response.data.accessToken, {
path: '/',
sameSite: 'strict'
Expand All @@ -16,7 +13,6 @@ export const postLogin = async (loginData: loginDataTypes, sessionId: string) =>
path: '/',
sameSite: 'strict'
})
await memberStore.updateMemberInfoWithToken()
return response.data
}

Expand All @@ -26,16 +22,8 @@ export const patchPassword = async (password: string) => {
}

export const deleteLogout = async () => {
const refreshToken = Cookies.get('refreshToken')
const accessToken = Cookies.get('accessToken')

const response = await axiosInstance.delete('/api/auths/logout', {
headers: {
Authorization: `Bearer ${accessToken}`,
refreshToken: refreshToken
}
})
Cookies.remove('accessToken', { path: '/' })
Cookies.remove('refreshToken', { path: '/' })
return response
const memberStore = useMemberStore()
memberStore.$reset()
Cookies.remove('accessToken')
Cookies.remove('refreshToken')
}
8 changes: 6 additions & 2 deletions src/components/LineChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
:options="options" />
<NoContent
v-else
content="데이터가 없습니다" />
:content="`집계된 ${periodText[periodType]} 데이터가 없습니다`" />
</template>

<script setup lang="ts">
Expand All @@ -22,6 +22,7 @@ import {
Colors
} from 'chart.js'
import NoContent from './lists/NoContent.vue'
import type { PeriodType } from '@/types/manager'

ChartJS.register(
Title,
Expand All @@ -34,12 +35,15 @@ ChartJS.register(
Colors
)

const { labels, series, dataLabel } = defineProps<{
const { labels, series, dataLabel, periodType } = defineProps<{
labels: string[]
series: number[]
dataLabel: string
periodType: PeriodType
}>()

const periodText = { DAY: '일간', WEEK: '주간', MONTH: '월간' }

const teamData = {
labels,
datasets: [
Expand Down
14 changes: 12 additions & 2 deletions src/components/PieChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
:options="options" />
<NoContent
v-else
content="집계된 데이터가 없습니다" />
:content="
!content && periodType ? `집계된 ${periodText[periodType]} 데이터가 없습니다` : content
" />
</template>

<script setup lang="ts">
Expand All @@ -21,11 +23,19 @@ import {
type ActiveElement
} from 'chart.js'
import NoContent from './lists/NoContent.vue'
import type { PeriodType } from '@/types/manager'
ChartJS.register(Title, Tooltip, Legend, ArcElement, Colors)

const { labels, series } = defineProps<{ labels: string[]; series: number[] }>()
const { labels, series, periodType, content } = defineProps<{
labels: string[]
series: number[]
periodType?: PeriodType
content?: string
}>()
const emit = defineEmits(['onClick'])

const periodText = { DAY: '일간', WEEK: '주간', MONTH: '월간' }

const teamData = {
labels,
datasets: [
Expand Down
19 changes: 19 additions & 0 deletions src/components/common/ResultModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<ModalView
:type="type"
:is-open="isOpen"
@close="emit('close')">
<template #header>{{ message }}</template>
</ModalView>
</template>

<script setup lang="ts">
import ModalView from '../ModalView.vue'

const { type, isOpen, message } = defineProps<{
type: string
isOpen: boolean
message: string
}>()
const emit = defineEmits(['close'])
</script>
2 changes: 1 addition & 1 deletion src/components/icons/NotificationIcon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<div
v-if="newNotification"
class="absolute top-0 right-0 w-5 h-5 rounded-full bg-red-1 text-white font-bold text-xs flex justify-center items-center">
{{ newNotification }}
{{ newNotification < 100 ? newNotification : 99 }}
</div>
</div>
</template>
Expand Down
4 changes: 2 additions & 2 deletions src/components/lists/NoContent.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<template>
<div class="w-full h-full flex justify-center items-center">
<span class="text-lg text-disabled font-bold">{{ content }}</span>
<span class="text-lg text-disabled font-bold text-center">{{ content }}</span>
</div>
</template>

<script setup lang="ts">
const { content = '표시할 항목이 없어요' } = defineProps<{ content?: string }>()
const { content = '표시할 항목이 없습니다' } = defineProps<{ content?: string }>()
</script>
4 changes: 2 additions & 2 deletions src/components/login-logs/LoginLogsListCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import type { ListCardProps } from '@/types/common'
import ListCardTab from '../lists/ListCardTab.vue'
import type { LoginLogsListData } from '@/types/admin'
import { formatDate } from '@/utils/date'
import { formatFullDateTime } from '@/utils/date'

const logStatus = {
LOGIN: '로그인 시도',
Expand All @@ -31,7 +31,7 @@ const myRequestTabList: ListCardProps[] = [
isTextXs: true,
isTextBody: true
},
{ content: formatDate(info.requestAt), width: 180, isTextXs: true },
{ content: formatFullDateTime(info.requestAt), width: 180, isTextXs: true },
{ content: info.nickName, width: 80 },
{ content: info.clientIp, width: 120, isTextXs: true },
{ content: String(info.statusCode), width: 40, isTextXs: true, isStatusCode: true },
Expand Down
59 changes: 29 additions & 30 deletions src/components/member-management/MemberManagementListCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,11 @@
<template #header>회원을 삭제 하시겠습니까?</template>
<template #body>삭제된 회원은 복구할 수 없습니다</template>
</ModalView>
<ModalView
type="failType"
:is-open="isModalVisible.fail"
@close="closeModal">
<template #header>회원 삭제에 실패했습니다</template>
</ModalView>
<ModalView
type="successType"
:is-open="isModalVisible.success"
@close="closeModal">
<template #header>회원을 삭제했습니다</template>
</ModalView>

<ModalView
type="successType"
:is-open="isModalVisible.invite"
@close="closeModal">
<template #header>초대 메일을 발송하였습니다</template>
</ModalView>
<ResultModal
:type="resultModalType"
:is-open="isModalVisible.result"
:message="message"
@close="closeModal" />
</template>

<script setup lang="ts">
Expand All @@ -66,6 +52,7 @@ import { ref } from 'vue'
import { axiosInstance } from '@/utils/axios'
import { useQueryClient } from '@tanstack/vue-query'
import { formatDate } from '@/utils/date'
import ResultModal from '../common/ResultModal.vue'

const roleContent = (role: Role) => {
return role === 'ROLE_USER' ? '사용자' : role === 'ROLE_MANAGER' ? '담당자' : '관리자'
Expand All @@ -88,32 +75,44 @@ const queryClient = useQueryClient()

const isModalVisible = ref({
delete: false,
invite: false,
fail: false,
success: false
result: false
})
const resultModalType = ref('')
const message = ref('')
const toggleModal = (key: keyof typeof isModalVisible.value) => {
isModalVisible.value = Object.fromEntries(
Object.keys(isModalVisible.value).map(k => [k, k === key])
) as typeof isModalVisible.value
}
const closeModal = () => {
const prevSuccess = isModalVisible.value.success
isModalVisible.value = { delete: false, invite: false, fail: false, success: false }
const prevSuccess = isModalVisible.value.result
isModalVisible.value = { delete: false, result: false }
if (prevSuccess) queryClient.invalidateQueries({ queryKey: ['member'] })
}

const onMemberDelete = async (memberId: number) => {
try {
await axiosInstance.patch(`/api/managements/members/delete`, { memberId })
toggleModal('success')
await axiosInstance.delete(`/api/managements/members`, { data: { memberId } })
resultModalType.value = 'successType'
message.value = '회원을 삭제했습니다'
toggleModal('result')
} catch {
toggleModal('fail')
resultModalType.value = 'failType'
message.value = '회원 삭제에 실패했습니다'
toggleModal('result')
}
}

const onMemberInvite = (memberId: number) => {
console.log(memberId)
toggleModal('invite')
const onMemberInvite = async (memberId: number) => {
try {
await axiosInstance.post('/api/managements/members/invite', { memberId })
resultModalType.value = 'successType'
message.value = '초대 메일을 발송하였습니다'
toggleModal('result')
} catch {
resultModalType.value = 'failType'
message.value = '초대 메일 발송에 실패했습니다'
toggleModal('result')
}
}
</script>
7 changes: 5 additions & 2 deletions src/components/my-request/MyRequestListCard.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<template>
<div class="list-card">
<div
class="list-card"
@click="handleModal(info.taskId)">
<ListCardTab
v-for="tab in myRequestTabList"
@click="handleModal(info.taskId)"
:key="tab.content"
:content="tab.content"
:width="tab.width"
Expand All @@ -29,6 +30,8 @@ const { info } = defineProps<{ info: MyRequestListData }>()
const selectedID = ref<number | null>(null)

const handleModal = (id: number | null) => {
if (id) document.body.style.overflow = 'hidden'
else document.body.style.overflow = ''
selectedID.value = id
}

Expand Down
7 changes: 5 additions & 2 deletions src/components/my-task/MyTaskListCard.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<template>
<div class="list-card">
<div
class="list-card"
@click="handleModal(info.taskId)">
<ListCardTab
v-for="tab in myRequestTabList"
@click="handleModal(info.taskId)"
:key="tab.content"
:content="tab.content"
:width="tab.width"
Expand All @@ -29,6 +30,8 @@ const { info } = defineProps<{ info: MyTaskListData }>()
const selectedID = ref<number | null>(null)

const handleModal = (id: number | null) => {
if (id) document.body.style.overflow = 'hidden'
else document.body.style.overflow = ''
selectedID.value = id
}
const myRequestTabList: ListCardProps[] = [
Expand Down
7 changes: 5 additions & 2 deletions src/components/request-history/RequestHistoryListCard.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<template>
<div class="list-card">
<div
class="list-card"
@click="handleModal(info.taskId)">
<ListCardTab
v-for="tab in myRequestTabList"
@click="handleModal(info.taskId)"
:key="tab.content"
:content="tab.content"
:width="tab.width"
Expand All @@ -29,6 +30,8 @@ const { info } = defineProps<{ info: RequestHistoryListData }>()
const selectedID = ref<number | null>(null)

const handleModal = (id: number | null) => {
if (id) document.body.style.overflow = 'hidden'
else document.body.style.overflow = ''
selectedID.value = id
}
const myRequestTabList: ListCardProps[] = [
Expand Down
12 changes: 9 additions & 3 deletions src/components/request-task/CategoryDropDown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
카테고리를 선택해주세요
</p>
</div>
<div class="relative flex">
<div
ref="htmlRef"
class="relative flex">
<div
class="flex w-full h-11 items-center rounded p-4 bg-white border border-border-1 cursor-pointer text-black"
class="flex w-full h-11 items-center rounded p-4 border border-border-1 cursor-pointer text-black"
:class="isDisabled ? 'bg-background-1' : 'bg-white'"
@click="toggleDropdown">
<p :class="{ 'text-disabled': !modelValue?.name }">
{{ modelValue?.name ?? labelName + '를 선택해주세요' }}
Expand All @@ -26,7 +29,7 @@
</div>
<div
v-if="dropdownOpen"
class="absolute w-full h-40 overflow-y-auto top-[52px] flex flex-col gap-2 p-2 bg-white rounded z-10 shadow border-t border-t-border-2 text-black">
class="absolute w-full max-h-40 overflow-y-auto top-[52px] flex flex-col gap-2 p-2 bg-white rounded z-10 shadow border-t border-t-border-2 text-black">
<div
v-for="option in options"
:key="option.id"
Expand All @@ -44,6 +47,7 @@ import { dropdownIcon } from '@/constants/iconPath'
import type { Category, CategoryDropdownProps } from '@/types/common'
import { computed, ref } from 'vue'
import CommonIcons from '../common/CommonIcons.vue'
import { useOutsideClick } from '../hooks/useOutsideClick'

const { options, labelName, modelValue, isLabel, isDisabled, isInvalidate } =
defineProps<CategoryDropdownProps>()
Expand All @@ -62,4 +66,6 @@ const selectOption = (option: Category) => {
emit('update:modelValue', option)
dropdownOpen.value = false
}

const { htmlRef } = useOutsideClick(() => dropdownOpen.value && toggleDropdown())
</script>
Loading