Client - add dropdown to select timezone in user preferences

This commit is contained in:
Sam
2021-11-10 12:03:32 +01:00
parent 9d304a2f1e
commit 7ba4e66e8e
28 changed files with 536 additions and 45 deletions

View File

@ -0,0 +1,132 @@
<template>
<div id="tz-dropdown">
<input
class="tz-dropdown-input"
id="timezone"
name="timezone"
:value="timezone"
:disabled="disabled"
required
@keydown.esc="onUpdateTimezone(input)"
@keydown.enter="onEnter"
@input="openDropdown"
/>
<ul class="tz-dropdown-list" v-if="isOpen" ref="tzList">
<li
v-for="(tz, index) in timeZones.filter((t) => matchTimezone(t))"
:key="tz"
class="tz-dropdown-item"
:class="{ focus: index === focusItemIndex }"
@click="onUpdateTimezone(tz)"
@mouseover="onMouseOver(index)"
:autofocus="index === focusItemIndex"
>
{{ tz }}
</li>
</ul>
</div>
</template>
<script lang="ts">
import { Ref, defineComponent, ref, watch } from 'vue'
import { timeZones } from '@/utils/timezone'
export default defineComponent({
name: 'TimezoneDropdown',
props: {
disabled: {
type: Boolean,
default: false,
},
input: {
type: String,
required: true,
},
},
emits: ['updateTimezone'],
setup(props, { emit }) {
const timezone: Ref<string> = ref(props.input)
const isOpen: Ref<boolean> = ref(false)
const tzList: Ref<HTMLInputElement | null> = ref(null)
const focusItemIndex: Ref<number> = ref(0)
function matchTimezone(t: string): RegExpMatchArray | null {
return t.toLowerCase().match(timezone.value.toLowerCase())
}
function onMouseOver(index: number) {
focusItemIndex.value = index
}
function onUpdateTimezone(value: string) {
timezone.value = value
isOpen.value = false
emit('updateTimezone', value)
}
function onEnter(event: Event & { target: HTMLInputElement }) {
event.preventDefault()
if (tzList.value?.firstElementChild?.innerHTML) {
onUpdateTimezone(tzList.value?.firstElementChild?.innerHTML)
}
}
function openDropdown(event: Event & { target: HTMLInputElement }) {
event.preventDefault()
isOpen.value = true
timezone.value = event.target.value.trim()
}
watch(
() => props.input,
(value) => {
timezone.value = value
}
)
return {
focusItemIndex,
isOpen,
timezone,
timeZones,
tzList,
matchTimezone,
onEnter,
onMouseOver,
onUpdateTimezone,
openDropdown,
}
},
})
</script>
<style lang="scss" scoped>
@import '~@/scss/base.scss';
#tz-dropdown {
display: flex;
flex-direction: column;
position: relative;
.tz-dropdown-list {
background-color: var(--input-bg-color);
border-radius: $border-radius;
border: solid 1px var(--input-border-color);
padding: $default-padding * 0.5 0;
position: absolute;
overflow-y: auto;
top: 20px;
left: 0;
right: 0;
max-height: 200px;
width: inherit;
}
.tz-dropdown-item {
cursor: pointer;
font-size: 0.9em;
font-weight: normal;
padding: $default-padding * 0.5;
&.focus {
background-color: var(--dropdown-hover-color);
}
}
}
</style>

View File

@ -15,12 +15,12 @@
</option>
</select>
</label>
<label class="form-items" for="timezone">
<label class="form-items">
{{ $t('user.PROFILE.TIMEZONE') }}
<input
id="timezone"
v-model="userForm.timezone"
<TimezoneDropdown
:input="userForm.timezone"
:disabled="loading"
@updateTimezone="updateTZ"
/>
</label>
<label class="form-items">
@ -61,6 +61,7 @@
onMounted,
} from 'vue'
import TimezoneDropdown from '@/components/User/ProfileEdition/TimezoneDropdown.vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { IUserProfile, IUserPreferencesPayload } from '@/types/user'
import { useStore } from '@/use/useStore'
@ -68,6 +69,9 @@
export default defineComponent({
name: 'UserPreferencesEdition',
components: {
TimezoneDropdown,
},
props: {
user: {
type: Object as PropType<IUserProfile>,
@ -115,6 +119,9 @@
userForm
)
}
function updateTZ(value: string) {
userForm.timezone = value
}
return {
availableLanguages,
@ -123,6 +130,7 @@
userForm,
weekStart,
updateProfile,
updateTZ,
}
},
})