Skip to content

Commit

Permalink
style: modal 기능 리팩토링 및 타입 추론 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
lavi27 committed Jan 19, 2024
1 parent f03cdc3 commit 41d4f29
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 76 deletions.
28 changes: 28 additions & 0 deletions composables/useModal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { Cast, MyExtract, ArrayElement } from '~/utils/types'

export default <T extends readonly string[]>(modalNames: T) => {
type ModalName = ArrayElement<T>

const modalsIsShow = useState<Record<ModalName, boolean>>('useModal', () => {
return Object.keys(modalNames).reduce((acc, name) => {
acc[name as ModalName] = false
return acc
}, {} as Record<ModalName, boolean>)
})

const modalShow = (name: ModalName) => {
modalsIsShow.value[name] = true
}

const modalClose = (name: ModalName) => {
modalsIsShow.value[name] = false
}

const modalShowAndClose = async (name: ModalName, waitMs: number) => {
modalsIsShow.value[name] = true
await wait(waitMs)
modalsIsShow.value[name] = false
}

return { modalsIsShow, modalShow, modalClose, modalShowAndClose }
}
14 changes: 7 additions & 7 deletions layouts/modal.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
<script setup lang="ts">
const emit = defineEmits(['close'])
const props = defineProps<{ isShow: boolean }>()
const modalsIsShow = useState<Record<string, boolean>>('useModal')
const { modalName } = defineProps<{ modalName: string }>()
const bgEl = ref()
const onClose = () => {
emit('close')
modalsIsShow.value[modalName] = false
}
onClickOutside(bgEl, onClose)
if (!modalsIsShow.value[modalName]) throw new Error(`모달의 name인 ${modalName} 이/가 잘못 입력되었습니다.`)
</script>

<style lang="scss">
@import url('~/assets/styles/layouts/modal.scss');
</style>

<template>
<div class="modal_bg" :class="{ show: props.isShow }"></div>
<div class="modal_bg" :class="{ show: modalsIsShow[modalName] }"></div>
<div class="modal_wrap">
<div ref="bgEl" class="modal" v-if="props.isShow">
<div ref="bgEl" class="modal" v-if="modalsIsShow[modalName]">
<slot />
</div>
</div>
Expand Down
45 changes: 17 additions & 28 deletions pages/dashboard/invite.vue
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
</button>
</NuxtLayout>

<NuxtLayout name="modal" :isShow="isShowModals.permission" @close="isShowModals.permission = false">
<NuxtLayout name="modal" :modalName="MODAL.permission">
<h2>
<!-- 한디리에서 봇을 추천해주세요 -->
{{ $t('invite.permissionModal.title') }}
Expand All @@ -129,14 +129,14 @@
<!-- 유료 플랜 -->
{{ $t('invite.permissionModal.btns.goUpgrade') }}
</a>
<a @click="isShowModals.permission = false">
<a @click="modalClose(MODAL.permission)">
<!-- 확인 -->
{{ $t('common.modal.btns.confirm') }}
</a>
</div>
</NuxtLayout>

<NuxtLayout name="modal" :isShow="isShowModals.premiere_only" @close="isShowModals.premiere_only = false">
<NuxtLayout name="modal" :modalName="MODAL.premiereOnly">
<h2>
<!-- 프리미어 플랜에서만 이용하실 수 있습니다. -->
{{ $t('invite.premiereOnlyModal.title') }}
Expand All @@ -148,14 +148,14 @@
<!-- 유료 플랜 -->
{{ $t('invite.premiereOnlyModal.btns.goUpgrade') }}
</a>
<a @click="isShowModals.premiere_only = false">
<a @click="modalClose(MODAL.premiereOnly)">
<!-- 확인 -->
{{ $t('common.modal.btns.confirm') }}
</a>
</div>
</NuxtLayout>

<NuxtLayout name="modal" :isShow="isShowModals.custom_domain" @close="isShowModals.custom_domain = false">
<NuxtLayout name="modal" :modalName="MODAL.customDomain">
<h2>
<!-- DNS 설정을 완료하셨나요? -->
{{ $t('invite.customDomainModal.title') }}
Expand All @@ -172,18 +172,18 @@
<!-- 설정방법 확인 -->
{{ $t('invite.customDomainModal.btns.goDocs') }}
</a>
<a @click="isShowModals.custom_domain = false">
<a @click="modalClose(MODAL.customDomain)">
<!-- 취소 -->
{{ $t('common.modal.btns.cancel') }}
</a>
<a @click="isShowModals.custom_domain = false">
<a @click="modalClose(MODAL.customDomain)">
<!-- 확인 -->
{{ $t('common.modal.btns.confirm') }}
</a>
</div>
</NuxtLayout>

<NuxtLayout name="modal" :isShow="isShowModals.success" @close="isShowModals.success = false">
<NuxtLayout name="modal" :modalName="MODAL.success">
<h2>
<!-- 성공적으로 저장했습니다! -->
{{ $t('common.modal.saved') }}
Expand All @@ -206,7 +206,7 @@
<div class="btns"></div>
</NuxtLayout>

<NuxtLayout name="modal" :isShow="isShowModals.fail" @close="isShowModals.fail = false">
<NuxtLayout name="modal" :modalName="MODAL.failed">
<h2>
<!-- 저장 중 오류가 발생했습니다. -->
{{ $t('common.errorModal.title') }}
Expand All @@ -230,6 +230,9 @@ definePageMeta({
middleware: ['auth', 'guild-id'],
})
const modalNames = ['permission', 'premiereOnly', 'customDomain', 'success', 'failed'] as const
const MODAL = strArrToEnumObject<typeof modalNames>(modalNames)
const { modalShow, modalClose, modalShowAndClose } = useModal<typeof modalNames>(modalNames)
const API = useAPI()
const { loadingSuccess } = useLoadingState()
const i18n = useI18n()
Expand All @@ -241,16 +244,6 @@ const generateRandom = () => {
const hasPermission = useState('hasPermission', () => false)
const isEnterprise = useState('isEnterprise', () => false)
const isShowModals = useState('inviteModals', () => {
return {
permission: false,
premiere_only: false,
custom_domain: false,
success: false,
fail: false,
}
})
const setting = useState('inviteSetting', () => {
return {
inviteLink: {
Expand Down Expand Up @@ -287,20 +280,20 @@ const setting = useState('inviteSetting', () => {
const clickInviteLink = () => {
if (hasPermission.value) return
isShowModals.value.permission = true
modalShow(MODAL.permission)
}
const clickCustomDomain = () => {
if (isEnterprise.value) return
isShowModals.value.premiere_only = true
modalShow(MODAL.premiereOnly)
}
const checkVote = () => {
// this.connState = 0
// location.reload()
}
const reconfirmSaveSettings = async () => {
if (setting.value.inviteLink.enabled && setting.value.inviteLink.settings.inviteURL.value != '') {
isShowModals.value.custom_domain = true
modalShow(MODAL.customDomain)
} else {
saveSettings()
}
Expand All @@ -316,13 +309,9 @@ const saveSettings = async () => {
// ssl: this.switch_.domain ? this.switch_.domain_ssl : null,
// },
// })
// $modal.show('success')settingp
// await wait(3000)
// $modal.hide('success')
// modalShowAndClose(MODAL.success, 3000)
// } catch (e) {
// $modal.show('fail')
// await wait(3000)
// $modal.hide('fail')
// modalShowAndClose(MODAL.failed, 3000)
// }
}
Expand Down
36 changes: 13 additions & 23 deletions pages/dashboard/members.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
</ul>
</NuxtLayout>

<NuxtLayout name="modal" :isShow="isShowModals.reconfirmBlackList" @close="isShowModals.reconfirmBlackList = false">
<NuxtLayout name="modal" :modalName="MODAL.reconfirmBlackList">
<h2 v-if="tempBlockUserId">
<!-- {{ processBlackList.nickName }}님을 블랙리스트에 등록하시겠어요? -->
{{ $t('members.modal1.title').replace('{Place}', memberMap[tempBlockUserId].nickName) }}
Expand All @@ -70,11 +70,7 @@
</div>
</NuxtLayout>

<NuxtLayout
name="modal"
:isShow="isShowModals.reconfirmRemoveBlackList"
@close="isShowModals.reconfirmRemoveBlackList = false"
>
<NuxtLayout name="modal" :modalName="MODAL.reconfirmRemoveBlackList">
<h2 v-if="tempBlockUserId">
<!-- {{ processBlackList.nickName }}님을 블랙리스트에서 삭제하시겠어요? -->
{{ $t('members.modal2.title').replace('{Place}', memberMap[tempBlockUserId].nickName) }}
Expand All @@ -96,7 +92,7 @@
</div>
</NuxtLayout>

<NuxtLayout name="modal" :isShow="isShowModals.fail" @close="isShowModals.fail = false">
<NuxtLayout name="modal" :modalName="MODAL.failed">
<h2>
<!-- 저장 중 오류가 발생했습니다. -->
{{ $t('common.errorModal.title') }}
Expand Down Expand Up @@ -126,32 +122,29 @@ definePageMeta({
middleware: ['auth', 'guild-id'],
})
const modalNames = ['reconfirmBlackList', 'reconfirmRemoveBlackList', 'failed'] as const
const MODAL = strArrToEnumObject<typeof modalNames>(modalNames)
const { modalShow, modalClose, modalShowAndClose } = useModal<typeof modalNames>(modalNames)
const API = useAPI()
const { loadingSuccess } = useLoadingState()
const memberList = useState<string[]>()
const tempBlockUserId = useState<string | null>()
const isShowModals = useState('membersModals', () => {
return {
reconfirmBlackList: false,
reconfirmRemoveBlackList: false,
fail: false,
}
})
const memberMap = useState<Record<string, APIMemberBase>>('memberMap', () => {
return {}
})
const reconfirmAddBlackList = (id: string) => {
tempBlockUserId.value = id
isShowModals.value.reconfirmBlackList = true
modalShow(MODAL.reconfirmBlackList)
}
const reconfirmRemoveBlackList = (id: string) => {
tempBlockUserId.value = id
isShowModals.value.reconfirmRemoveBlackList = true
modalShow(MODAL.reconfirmRemoveBlackList)
}
const setBlackList = async () => {
Expand All @@ -160,19 +153,16 @@ const setBlackList = async () => {
tempBlockUserId.value = null
isShowModals.value.reconfirmBlackList = false
isShowModals.value.reconfirmRemoveBlackList = false
modalClose(MODAL.reconfirmBlackList)
modalClose(MODAL.reconfirmRemoveBlackList)
try {
await API.post.members(targetId)
const member = memberMap.value[targetId]
member.isBlackList = !member.isBlackList
} catch (e) {
isShowModals.value.fail = true
await wait(3000)
isShowModals.value.fail = false
await modalShowAndClose(MODAL.failed, 3000)
await wait(1000)
// location.reload()
Expand Down
29 changes: 11 additions & 18 deletions pages/dashboard/verify.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
</button>
</NuxtLayout>

<NuxtLayout name="modal" :isShow="isShowModals.success" @close="isShowModals.success = false">
<NuxtLayout name="modal" :modalName="MODAL.success">
<h2>
{{ $t('common.modal.saved') }}
<!-- 성공적으로 저장했습니다! -->
Expand All @@ -56,12 +56,12 @@
<span v-if="setting.cmdVerify.enabled">
<!-- 새로운 유저가 <code>/verify</code> 명령어로 인증할 수 있습니다. -->
<!-- FIXME - [intlify] Not found 'verify.modal.applied' key in 'ko' locale messages. -->
<!-- {{ $t('verify.modal.applied') }} -->
{{ $t('verify.modal.applied') }}
</span>
<span v-else>
<!-- 새로운 유저는 더 이상 <code>/verify</code> 명령어로 인증할 수 없습니다. -->
<!-- FIXME - [intlify] Not found 'verify.modal.deleted' key in 'ko' locale messages. -->
<!-- {{ $t('verify.modal.deleted') }} -->
{{ $t('verify.modal.deleted') }}
</span>

<br />
Expand All @@ -72,7 +72,7 @@
<div class="btns"></div>
</NuxtLayout>

<NuxtLayout name="modal" :isShow="isShowModals.fail" @close="isShowModals.fail = false">
<NuxtLayout name="modal" :modalName="MODAL.failed">
<h2>
<!-- 저장 중 오류가 발생했습니다. -->
{{ $t('common.errorModal.title') }}
Expand All @@ -96,16 +96,12 @@ definePageMeta({
middleware: ['auth', 'guild-id'],
})
const modalNames = ['success', 'failed'] as const
const MODAL = strArrToEnumObject<typeof modalNames>(modalNames)
const { modalShow, modalClose, modalShowAndClose } = useModal<typeof modalNames>(modalNames)
const API = useAPI()
const { loadingSuccess } = useLoadingState()
const isShowModals = useState('verifyModals', () => {
return {
success: false,
fail: false,
}
})
const setting = useState('verifySetting', () => {
return {
cmdVerify: {
Expand Down Expand Up @@ -136,13 +132,14 @@ const setting = useState('verifySetting', () => {
const doinputInputMenu = (value: string) => {
const Tlqkf = setting.value.cmdVerify.settings.verifyRole
Tlqkf.inputValue = value
Tlqkf.inputValue = value
Tlqkf.menuIndex = []
}
const setInputMenuIndex = (index: string) => {
const Tlqkf = setting.value.cmdVerify.settings.verifyRole
Tlqkf.index = index
Tlqkf.inputValue = Tlqkf.dataMap[index].name
Tlqkf.selectedData = Tlqkf.dataMap[index].data
Expand All @@ -154,13 +151,9 @@ const saveSettings = async () => {
// status: this.switch_.confirm,
// role: this.input.role,
// })
// $modal.show('success')
// await wait(3000)
// $modal.hide('success')
// modalShowAndClose(MODAL.success, 3000)
// } catch (e) {
// $modal.show('fail')
// await wait(3000)
// $modal.hide('fail')
// modalShowAndClose(MODAL.failed, 3000)
// }
}
Expand Down
18 changes: 18 additions & 0 deletions utils/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export type Cast<X, Y> = X extends Y ? X : Y

export type MyExtract<T, U> = T extends U ? T : never

export type ArrayElement<A> = A extends readonly (infer T)[] ? T : never

type ArrToEnum<T> = T extends readonly (infer Key)[]
? { [K in Cast<Key, string>]: Cast<K, string> }
: Record<string, string>

export const strArrToEnumObject = <T extends readonly string[]>(value: T): ArrToEnum<T> => {
const tmpObj = value.reduce((prev, value) => {
prev[value] = value
return {}
}, {} as Record<string, string>)

return tmpObj as ArrToEnum<T>
}

0 comments on commit 41d4f29

Please sign in to comment.