Skip to content

Commit 4d05982

Browse files
authored
Merge pull request #78 from TaskFlow-CLAP/CLAP-223
CLAP-223 TopBar 알림, 프로필 모달 UI 구현
2 parents c9cc465 + 8fbbe1c commit 4d05982

File tree

6 files changed

+231
-6
lines changed

6 files changed

+231
-6
lines changed

src/App.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import TopBar from './components/TopBar.vue'
2+
import TopBar from './components/top-bar/TopBar.vue'
33
import TheView from './layout/TheView.vue'
44
</script>
55

src/components/request-task/RequestTask.vue

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
v-model="category1"
55
:options="mainCategoryArr"
66
:label-name="'1차 카테고리'"
7-
:isInvalidate="isInvalidate"
7+
:placeholderText="'1차 카테고리를 선택해주세요'"
88
:isDisabled="false" />
99
<CategoryDropDown
1010
v-model="category2"
1111
:options="afterSubCategoryArr"
1212
:label-name="'2차 카테고리'"
13-
:is-invalidate="isInvalidate"
13+
:placeholderText="'2차 카테고리를 선택해주세요'"
1414
:isDisabled="!category1" />
1515
<RequestTaskInput
1616
v-model="title"
@@ -42,7 +42,6 @@ import type { Category, SubCategory } from '@/types/common'
4242
import { onMounted, ref, watch } from 'vue'
4343
import { useRouter } from 'vue-router'
4444
import FormButtonContainer from '../common/FormButtonContainer.vue'
45-
import ModalView from '../ModalView.vue'
4645
import CategoryDropDown from './CategoryDropDown.vue'
4746
import RequestTaskFileInput from './RequestTaskFileInput.vue'
4847
import RequestTaskInput from './RequestTaskInput.vue'
@@ -112,7 +111,6 @@ const handleSubmit = async () => {
112111
}
113112
try {
114113
const res = await postTaskRequest(formData)
115-
isModalVisible.value = true
116114
console.error('요청 성공:', res)
117115
} catch (error) {
118116
console.error('요청 실패:', error)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<template>
2+
<div
3+
v-if="isOpen"
4+
class="fixed inset-0 flex z-50 justify-center"
5+
@click.self="closeModal">
6+
<div
7+
class="flex relative w-[1200px] h-[72px] bg-opacity-15"
8+
@click.self="closeModal">
9+
<div
10+
class="absolute right-6 top-[72px] h-60 w-80 bg-white rounded-lg shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
11+
<div class="flex relative px-4 pt-3 pb-2 border-b border-border-2">
12+
<p class="text-body font-bold text-xs">알림</p>
13+
<div class="absolute right-4">
14+
<div class="flex items-center">
15+
<button class="flex items-center">
16+
<CommonIcons
17+
:name="smallCheckIcon"
18+
class="w-2.5 h-1.5 mr-1 fill-primary1" />
19+
<p class="font-bold text-primary1 text-xs">모두 읽음</p>
20+
</button>
21+
<CommonIcons
22+
:name="closeIcon"
23+
class="ml-2 cursor-pointer"
24+
@click="closeModal" />
25+
</div>
26+
</div>
27+
</div>
28+
<div class="max-h-[186px] flex flex-col h-full overflow-y-auto">
29+
<div class="overflow-y-scroll flex"></div>
30+
<button :class="['flex flex-col border-b py-3 px-4', { 'bg-primary2': isCheck }]">
31+
<p class="text-xs text-body font-bold">{{ title }}</p>
32+
<div class="flex text-xs pt-2">
33+
<span class="text-black">
34+
<span class="text-primary1 font-bold">"{{ taskTitle }}"</span>
35+
&nbsp;요청이&nbsp;
36+
<span class="text-primary1 font-bold">{{ message }}</span>
37+
&nbsp;상태로 변경 되었습니다
38+
</span>
39+
</div>
40+
</button>
41+
<button :class="['flex flex-col border-b py-3 px-4', { 'bg-primary2': !isCheck }]">
42+
<p class="text-xs text-body font-bold">{{ title }}</p>
43+
<div class="flex text-xs pt-2">
44+
<span class="text-black">
45+
<span class="text-primary1 font-bold">"{{ taskTitle }}"</span>
46+
&nbsp;요청이&nbsp;
47+
<span class="text-primary1 font-bold">{{ message }}</span>
48+
&nbsp;상태로 변경 되었습니다
49+
</span>
50+
</div>
51+
</button>
52+
</div>
53+
</div>
54+
</div>
55+
</div>
56+
</template>
57+
58+
<script setup lang="ts">
59+
import { ref } from 'vue'
60+
import CommonIcons from '../common/CommonIcons.vue'
61+
import { smallCheckIcon, closeIcon } from '@/constants/iconPath'
62+
const props = defineProps<{
63+
isOpen: boolean
64+
}>()
65+
66+
const title = ref('작업 상태 변경 알림')
67+
const taskTitle = ref('VM 생성 요청')
68+
const message = ref('진행 중')
69+
const isCheck = ref(true)
70+
71+
const emit = defineEmits<{
72+
(e: 'close'): void
73+
}>()
74+
75+
const closeModal = () => {
76+
emit('close')
77+
}
78+
</script>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<template>
2+
<div
3+
v-if="isOpen"
4+
class="fixed inset-0 flex z-50 justify-center"
5+
@click.self="closeModal">
6+
<div
7+
class="flex relative w-[1200px] h-[72px] bg-opacity-15"
8+
@click.self="closeModal">
9+
<div
10+
class="absolute w-60 bg-white right-6 top-[72px] rounded-lg shadow-[0_3px_10px_rgb(0,0,0,0.2)]">
11+
<div
12+
class="flex items-center justify-center relative px-6 py-8 border-b bg-primary2 border-border-2">
13+
<div class="flex flex-col items-center justify-center">
14+
<div class="w-24 h-24 bg-background-1 rounded-full mb-6"></div>
15+
<div>
16+
<div class="flex flex-col justify-center items-center w-[172px]">
17+
<p class="text-xs text-body font-bold">{{ name }}</p>
18+
<p class="text-black">{{ nickname }}</p>
19+
</div>
20+
</div>
21+
</div>
22+
</div>
23+
<button
24+
@click="handleEdit"
25+
type="button"
26+
class="flex w-full py-4 px-6 text-sm text-black font-bold border-b border-border-2">
27+
내 정보 수정
28+
</button>
29+
<button
30+
@click="handleLogout"
31+
type="button"
32+
class="flex w-full py-4 px-6 text-sm text-red-1 font-bold">
33+
로그아웃
34+
</button>
35+
</div>
36+
</div>
37+
</div>
38+
</template>
39+
40+
<script setup lang="ts">
41+
import { ref } from 'vue'
42+
import { useRouter } from 'vue-router'
43+
44+
const router = useRouter()
45+
46+
const props = defineProps<{
47+
isOpen: boolean
48+
}>()
49+
50+
const name = ref('벡지연')
51+
const nickname = ref('Chloe.yeon')
52+
53+
const emit = defineEmits<{
54+
(e: 'close'): void
55+
}>()
56+
57+
const closeModal = () => {
58+
emit('close')
59+
}
60+
const handleEdit = () => {
61+
router.push('/edit-information')
62+
emit('close')
63+
}
64+
const handleLogout = () => {
65+
// 로그아웃 API 추가 필요
66+
}
67+
</script>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
<script setup lang="ts">
6969
import { useRoute } from 'vue-router'
7070
import { computed } from 'vue'
71-
import CommonIcons from './common/CommonIcons.vue'
71+
import CommonIcons from '../common/CommonIcons.vue'
7272
import { hamburgerIcon } from '@/constants/iconPath'
7373
import { SIDE_USER_MENU, SIDE_MANAGER_MENU, SIDE_ADMIN_MENU } from '@/constants/menu'
7474
import { useMemberStore } from '@/stores/member'

src/components/top-bar/TopBar.vue

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<template>
2+
<NotificationModal
3+
:isOpen="isNotifiVisible"
4+
@close="toggleNotifi" />
5+
<ProfileModal
6+
:isOpen="isProfileVisible"
7+
@close="toggleProfile" />
8+
<div class="fixed w-full bg-white text-black py-2 border-b border-border-1">
9+
<div
10+
class="max-w-[1200px] min-w-[1024px] mx-auto px-6 flex w-full justify-between items-center">
11+
<div class="flex justify-center items-center gap-6 h-full">
12+
<button
13+
type="button"
14+
v-show="isLogined"
15+
@click="isSideOpen = true">
16+
<CommonIcons :name="hamburgerIcon" />
17+
</button>
18+
<img src="/MainLogo.svg" />
19+
</div>
20+
<div
21+
v-show="isLogined"
22+
class="flex items-center gap-6">
23+
<button
24+
type="button"
25+
@click="toggleNotifi">
26+
<NotificationIcon :new-notification="12" />
27+
</button>
28+
<button
29+
type="button"
30+
@click="toggleProfile">
31+
<img
32+
v-if="info?.imageUrl"
33+
class="rounded-[50%] w-10 h-10"
34+
:src="info.imageUrl"
35+
alt="프로필 이미지" />
36+
<div
37+
v-else
38+
class="rounded-[50%] bg-zinc-100 p-5" />
39+
</button>
40+
</div>
41+
</div>
42+
</div>
43+
<SideBar
44+
v-if="isSideOpen"
45+
@close="onCloseSide" />
46+
</template>
47+
48+
<script setup lang="ts">
49+
import { ref, onMounted } from 'vue'
50+
import CommonIcons from '../common/CommonIcons.vue'
51+
import SideBar from './SideBar.vue'
52+
import { hamburgerIcon } from '../../constants/iconPath'
53+
import NotificationIcon from '../icons/NotificationIcon.vue'
54+
import { storeToRefs } from 'pinia'
55+
import { useMemberStore } from '@/stores/member'
56+
import NotificationModal from './NotificationModal.vue'
57+
import ProfileModal from './ProfileModal.vue'
58+
59+
const memberStore = useMemberStore()
60+
const { info } = storeToRefs(memberStore)
61+
62+
onMounted(async () => {
63+
await memberStore.updateMemberInfoWithToken()
64+
})
65+
66+
const isSideOpen = ref(false)
67+
const isLogined = ref(true)
68+
69+
const isNotifiVisible = ref(false)
70+
const isProfileVisible = ref(false)
71+
72+
const toggleNotifi = () => {
73+
isNotifiVisible.value = !isNotifiVisible.value
74+
}
75+
const toggleProfile = () => {
76+
isProfileVisible.value = !isProfileVisible.value
77+
}
78+
79+
const onCloseSide = () => {
80+
isSideOpen.value = false
81+
}
82+
</script>

0 commit comments

Comments
 (0)