-
+
+
-
-
+
+
+
+
+
+
+
+
@@ -58,6 +66,7 @@ import ProfileModal from './ProfileModal.vue'
import { getNotifiCount } from '@/api/common'
import { useRoute, useRouter } from 'vue-router'
import { PERMITTED_URL } from '@/constants/common'
+import { useOutsideClick } from '../hooks/useOutsideClick'
const memberStore = useMemberStore()
const { isLogined, info } = storeToRefs(memberStore)
@@ -77,10 +86,6 @@ onMounted(async () => {
if (!PERMITTED_URL.ROLE_MANAGER.includes(originUrl)) router.push('/my-task')
} else if (info.value.role === 'ROLE_ADMIN') {
if (!PERMITTED_URL.ROLE_ADMIN.includes(originUrl)) router.push('/member-management')
- } else {
- if (!PERMITTED_URL.UNKNOWN.includes(originUrl)) {
- router.push('/login')
- }
}
})
@@ -91,17 +96,17 @@ const isNotifiVisible = ref(false)
const isProfileVisible = ref(false)
const fetchNotificationCount = async () => {
- if (isLogined.value) {
- try {
- const data = await getNotifiCount()
- countNotifi.value = data.count
- } catch (error) {
- console.error('알림 개수 불러오기 실패:', error)
- }
+ if (!isLogined.value) return
+ try {
+ const data = await getNotifiCount()
+ countNotifi.value = data.count
+ } catch (error) {
+ console.error('알림 개수 불러오기 실패:', error)
}
}
-const toggleNotifi = () => {
+const toggleNotifi = async () => {
+ await fetchNotificationCount()
isNotifiVisible.value = !isNotifiVisible.value
}
const toggleProfile = () => {
@@ -110,6 +115,7 @@ const toggleProfile = () => {
const onCloseSide = () => {
isSideOpen.value = false
+ document.body.style.overflow = ''
}
watch(isLogined, newValue => {
@@ -121,10 +127,18 @@ watch(isLogined, newValue => {
watch(
() => info.value,
async newInfo => {
- if (newInfo.name && isLogined) {
+ if (newInfo.name) {
await fetchNotificationCount()
}
},
{ deep: true }
)
+
+const { htmlRef: notifiRef } = useOutsideClick(() => isNotifiVisible.value && toggleNotifi())
+const { htmlRef: profileRef } = useOutsideClick(() => isProfileVisible.value && toggleProfile())
+
+const onOpenSide = () => {
+ document.body.style.overflow = 'hidden'
+ isSideOpen.value = !isSideOpen.value
+}
diff --git a/src/constants/iconPath.ts b/src/constants/iconPath.ts
index 4a79d92b..161d2042 100644
--- a/src/constants/iconPath.ts
+++ b/src/constants/iconPath.ts
@@ -77,10 +77,10 @@ export const deleteIcon = {
}
export const smallCheckIcon = {
- path: 'M7.35497 0.605052C7.30849 0.558188 7.25319 0.520991 7.19226 0.495607C7.13133 0.470222 7.06598 0.457153 6.99997 0.457153C6.93397 0.457153 6.86862 0.470222 6.80769 0.495607C6.74676 0.520991 6.69146 0.558188 6.64498 0.605052L2.91998 4.33505L1.35497 2.76505C1.30671 2.71843 1.24974 2.68178 1.18732 2.65717C1.12489 2.63257 1.05823 2.62051 0.991136 2.62167C0.924046 2.62283 0.857841 2.63719 0.796302 2.66394C0.734763 2.69069 0.679094 2.72929 0.632475 2.77755C0.585856 2.82581 0.549199 2.88278 0.524597 2.94521C0.499995 3.00764 0.487929 3.0743 0.48909 3.14139C0.490251 3.20848 0.504615 3.27469 0.531362 3.33623C0.558108 3.39776 0.596714 3.45343 0.644975 3.50005L2.56498 5.42005C2.61146 5.46692 2.66676 5.50411 2.72769 5.5295C2.78862 5.55488 2.85397 5.56795 2.91998 5.56795C2.98598 5.56795 3.05133 5.55488 3.11226 5.5295C3.17319 5.50411 3.22849 5.46692 3.27498 5.42005L7.35497 1.34005C7.40573 1.29323 7.44623 1.23641 7.47393 1.17316C7.50164 1.10991 7.51594 1.0416 7.51594 0.972552C7.51594 0.903502 7.50164 0.835199 7.47393 0.771949C7.44623 0.708699 7.40573 0.651874 7.35497 0.605052Z',
- width: 8,
- height: 6,
- fill: '#A1A1AA'
+ path: 'M12.4733 4.80657C12.4114 4.74409 12.3376 4.69449 12.2564 4.66065C12.1752 4.6268 12.088 4.60938 12 4.60938C11.912 4.60938 11.8249 4.6268 11.7436 4.66065C11.6624 4.69449 11.5886 4.74409 11.5267 4.80657L6.56001 9.77991L4.47334 7.68657C4.40899 7.62441 4.33303 7.57554 4.2498 7.54274C4.16656 7.50993 4.07768 7.49385 3.98822 7.49539C3.89877 7.49694 3.8105 7.51609 3.72844 7.55176C3.64639 7.58742 3.57217 7.63889 3.51001 7.70324C3.44785 7.76759 3.39897 7.84355 3.36617 7.92679C3.33337 8.01002 3.31728 8.0989 3.31883 8.18836C3.32038 8.27781 3.33953 8.36609 3.37519 8.44814C3.41085 8.53019 3.46233 8.60441 3.52667 8.66657L6.08667 11.2266C6.14865 11.2891 6.22238 11.3387 6.30362 11.3725C6.38486 11.4063 6.472 11.4238 6.56001 11.4238C6.64802 11.4238 6.73515 11.4063 6.81639 11.3725C6.89763 11.3387 6.97137 11.2891 7.03334 11.2266L12.4733 5.78657C12.541 5.72415 12.595 5.64838 12.632 5.56404C12.6689 5.47971 12.688 5.38864 12.688 5.29657C12.688 5.20451 12.6689 5.11344 12.632 5.0291C12.595 4.94477 12.541 4.869 12.4733 4.80657Z',
+ width: 16,
+ height: 16,
+ fill: '#7879EB'
}
export const plusIcon = {
diff --git a/src/stores/member.ts b/src/stores/member.ts
index 3c164ea2..4a64b046 100644
--- a/src/stores/member.ts
+++ b/src/stores/member.ts
@@ -3,15 +3,16 @@ import { axiosInstance } from '@/utils/axios'
import { ref } from 'vue'
import type { User } from '@/types/auth'
import Cookies from 'js-cookie'
+import { useRouter } from 'vue-router'
export const useMemberStore = defineStore('memberInfo', () => {
- const info = ref
({
+ const INITIAL_INFO: User = {
+ profileImageUrl: '',
name: '',
nickname: '',
- profileImageUrl: '',
- role: '',
- memberStatus: '',
email: '',
+ isReviewer: false,
+ role: '',
departmentName: '',
departmentRole: '',
notificationSettingInfo: {
@@ -19,46 +20,44 @@ export const useMemberStore = defineStore('memberInfo', () => {
email: false,
kakaoWork: false
}
- })
+ }
+ const info = ref(INITIAL_INFO)
const refreshToken = ref(Cookies.get('refreshToken') || '')
const isLogined = ref(!!refreshToken.value)
+ const router = useRouter()
async function updateMemberInfoWithToken() {
- const response = await axiosInstance.get('/api/members/info')
- updateMemberInfo(response.data)
- isLogined.value = true
- }
-
- function updateMemberInfo(responseData: User) {
- info.value = {
- name: responseData.name || '',
- nickname: responseData.nickname || '',
- email: responseData.email || '',
- profileImageUrl: responseData.profileImageUrl || '',
- role: responseData.role || '',
- memberStatus: responseData.memberStatus || '',
- departmentName: responseData.departmentName || '',
- departmentRole: responseData.departmentRole || '',
- notificationSettingInfo: {
- agit: responseData.notificationSettingInfo.agit,
- email: responseData.notificationSettingInfo.email,
- kakaoWork: responseData.notificationSettingInfo.kakaoWork
- }
+ if (!Cookies.get('accessToken')) {
+ router.push('/login')
+ return
+ }
+ try {
+ const { data }: { data: User } = await axiosInstance.get('/api/members/info')
+ info.value = data
+ isLogined.value = true
+ return data.role
+ } catch {
+ router.push('/login')
}
}
function logout() {
+ $reset()
isLogined.value = false
Cookies.remove('accessToken')
Cookies.remove('refreshToken')
}
+ function $reset() {
+ info.value = INITIAL_INFO
+ }
+
return {
info,
isLogined,
- updateMemberInfo,
updateMemberInfoWithToken,
- logout
+ logout,
+ $reset
}
})
diff --git a/src/types/auth.ts b/src/types/auth.ts
index 43a1407d..97648f14 100644
--- a/src/types/auth.ts
+++ b/src/types/auth.ts
@@ -1,10 +1,12 @@
+import type { Role } from './common'
+
export interface User {
+ profileImageUrl: string
name: string
nickname: string
email: string
- profileImageUrl: string
- role: string
- memberStatus: string
+ isReviewer: boolean
+ role: Role | ''
departmentName: string
departmentRole: string
notificationSettingInfo: {
diff --git a/src/types/common.ts b/src/types/common.ts
index 4c18d85a..f83de8c4 100644
--- a/src/types/common.ts
+++ b/src/types/common.ts
@@ -111,6 +111,23 @@ export interface TaskStatusListTypes {
content: string
}
+export type NotificationType =
+ | 'COMMENT'
+ | 'TASK_REQUESTED'
+ | 'STATUS_SWITCHED'
+ | 'PROCESSOR_ASSIGNED'
+ | 'PROCESSOR_CHANGED'
+
+export interface NotificationContent {
+ notificationId: number
+ taskId: number
+ notificationType: NotificationType
+ receiverId: number
+ taskTitle: string
+ message: string
+ isRead: boolean
+ createdAt: string
+}
export interface TaskDetailHistoryProps {
historyData: TaskHistory[]
taskId: number
diff --git a/src/utils/axios.ts b/src/utils/axios.ts
index 9c12f4c6..de4651c4 100644
--- a/src/utils/axios.ts
+++ b/src/utils/axios.ts
@@ -26,7 +26,7 @@ const getNewAccessToken = async () => {
console.error('토큰 발행 실패', e)
Cookies.remove('accessToken')
Cookies.remove('refreshToken')
- window.location.reload()
+ window.location.href = '/login'
}
}
const setInterceptors = (instance: AxiosInstance) => {
diff --git a/src/utils/date.ts b/src/utils/date.ts
index 7b7f2378..269f5ef1 100644
--- a/src/utils/date.ts
+++ b/src/utils/date.ts
@@ -62,3 +62,20 @@ export const formatTodayOrNot = (dateStr: string, timeStr: string) => {
return `${inputDate.getMonth() + 1}월 ${inputDate.getDate()}일`
}
}
+
+export const formatFullDateTime = (dateString: string) => {
+ const date = new Date(dateString)
+
+ const year = date.getFullYear()
+ const month = String(date.getMonth() + 1).padStart(2, '0')
+ const day = String(date.getDate()).padStart(2, '0')
+
+ let hours = date.getHours()
+ const minutes = String(date.getMinutes()).padStart(2, '0')
+ const seconds = String(date.getSeconds()).padStart(2, '0')
+
+ const period = hours < 12 ? '오전' : '오후'
+ hours = hours % 12 || 12
+
+ return `${year}.${month}.${day} ${period} ${hours}:${minutes}:${seconds}`
+}
diff --git a/src/utils/getNotification.ts b/src/utils/getNotification.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue
index a5617ef9..e332f5ff 100644
--- a/src/views/LoginView.vue
+++ b/src/views/LoginView.vue
@@ -46,12 +46,14 @@
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { postLogin } from '@/api/auth'
+import { useMemberStore } from '@/stores/member'
import TitleContainer from '@/components/common/TitleContainer.vue'
const router = useRouter()
const nickname = ref('')
const password = ref('')
+const memberStore = useMemberStore()
const handleLogin = async () => {
try {
@@ -59,10 +61,11 @@ const handleLogin = async () => {
nickname: nickname.value,
password: password.value
}
- const sessionId = '000'
- const res = await postLogin(loginData, sessionId)
- if (res) {
- switch (res.memberInfo.role) {
+ const res = await postLogin(loginData)
+ const role = await memberStore.updateMemberInfoWithToken()
+
+ if (res && role) {
+ switch (role) {
case 'ROLE_ADMIN':
router.push('/member-management')
break