mirror of
https://github.com/lingble/chatwoot.git
synced 2025-12-14 01:37:12 +00:00
This PR fixes a few UI issues with the sidebar 1. `z-index` issues with sidebar dropdowns 2. Move the event listener to the root of the dropdown container, it allows more consistent behaviour of the trigger, earlier the click on the trigger when the dropdown was open would cause the container to re-render 3. Use `perserve-open` for the status switcher menu item in the profile menu. 4. Use `sessionStorage` instead of `localStorage` to preserve sidebar dropdown info. When opening the dashboard without directly going to a specific route, any previous known item would get expanded even if it's link was not active, this caused issues across tabs too, this fixes it. 5. Use `snakeCaseKeys` instead of `decamelize` we had two packages doing the same thing 6. Update `vueuse` the new version is vue3 only
123 lines
3.7 KiB
Vue
123 lines
3.7 KiB
Vue
<script setup>
|
|
import { computed, h } from 'vue';
|
|
import { useMapGetter, useStore } from 'dashboard/composables/store';
|
|
import wootConstants from 'dashboard/constants/globals';
|
|
import { useAlert } from 'dashboard/composables';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
import {
|
|
DropdownContainer,
|
|
DropdownBody,
|
|
DropdownSection,
|
|
DropdownItem,
|
|
} from 'next/dropdown-menu/base';
|
|
import Icon from 'next/icon/Icon.vue';
|
|
import Button from 'next/button/Button.vue';
|
|
|
|
const { t } = useI18n();
|
|
const store = useStore();
|
|
const currentUserAvailability = useMapGetter('getCurrentUserAvailability');
|
|
const currentAccountId = useMapGetter('getCurrentAccountId');
|
|
const currentUserAutoOffline = useMapGetter('getCurrentUserAutoOffline');
|
|
|
|
const { AVAILABILITY_STATUS_KEYS } = wootConstants;
|
|
const statusList = computed(() => {
|
|
return [
|
|
t('PROFILE_SETTINGS.FORM.AVAILABILITY.STATUS.ONLINE'),
|
|
t('PROFILE_SETTINGS.FORM.AVAILABILITY.STATUS.BUSY'),
|
|
t('PROFILE_SETTINGS.FORM.AVAILABILITY.STATUS.OFFLINE'),
|
|
];
|
|
});
|
|
|
|
const statusColors = ['bg-n-teal-9', 'bg-n-amber-9', 'bg-n-slate-9'];
|
|
|
|
const availabilityStatuses = computed(() => {
|
|
return statusList.value.map((statusLabel, index) => ({
|
|
label: statusLabel,
|
|
value: AVAILABILITY_STATUS_KEYS[index],
|
|
color: statusColors[index],
|
|
icon: h('span', { class: [statusColors[index], 'size-[12px] rounded'] }),
|
|
active: currentUserAvailability.value === AVAILABILITY_STATUS_KEYS[index],
|
|
}));
|
|
});
|
|
|
|
const activeStatus = computed(() => {
|
|
return availabilityStatuses.value.find(status => status.active);
|
|
});
|
|
|
|
function changeAvailabilityStatus(availability) {
|
|
try {
|
|
store.dispatch('updateAvailability', {
|
|
availability,
|
|
account_id: currentAccountId.value,
|
|
});
|
|
} catch (error) {
|
|
useAlert(t('PROFILE_SETTINGS.FORM.AVAILABILITY.SET_AVAILABILITY_ERROR'));
|
|
}
|
|
}
|
|
|
|
function updateAutoOffline(autoOffline) {
|
|
store.dispatch('updateAutoOffline', {
|
|
accountId: currentAccountId.value,
|
|
autoOffline,
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<DropdownSection>
|
|
<div class="grid gap-0">
|
|
<DropdownItem preserve-open>
|
|
<div class="flex-grow flex items-center gap-1">
|
|
{{ $t('SIDEBAR.SET_YOUR_AVAILABILITY') }}
|
|
</div>
|
|
<DropdownContainer>
|
|
<template #trigger="{ toggle }">
|
|
<Button
|
|
size="sm"
|
|
color="slate"
|
|
variant="faded"
|
|
class="min-w-[96px]"
|
|
icon="i-lucide-chevron-down"
|
|
trailing-icon
|
|
@click="toggle"
|
|
>
|
|
<div class="flex gap-1 items-center flex-grow text-sm">
|
|
<div class="p-1 flex-shrink-0">
|
|
<div class="size-2 rounded-sm" :class="activeStatus.color" />
|
|
</div>
|
|
<span>{{ activeStatus.label }}</span>
|
|
</div>
|
|
</Button>
|
|
</template>
|
|
<DropdownBody class="min-w-32 z-20">
|
|
<DropdownItem
|
|
v-for="status in availabilityStatuses"
|
|
:key="status.value"
|
|
:label="status.label"
|
|
:icon="status.icon"
|
|
class="cursor-pointer"
|
|
@click="changeAvailabilityStatus(status.value)"
|
|
/>
|
|
</DropdownBody>
|
|
</DropdownContainer>
|
|
</DropdownItem>
|
|
<DropdownItem>
|
|
<div class="flex-grow flex items-center gap-1">
|
|
{{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }}
|
|
<Icon
|
|
v-tooltip.top="$t('SIDEBAR.SET_AUTO_OFFLINE.INFO_SHORT')"
|
|
icon="i-lucide-info"
|
|
class="size-4 text-n-slate-10"
|
|
/>
|
|
</div>
|
|
<woot-switch
|
|
class="flex-shrink-0"
|
|
:model-value="currentUserAutoOffline"
|
|
@input="updateAutoOffline"
|
|
/>
|
|
</DropdownItem>
|
|
</div>
|
|
</DropdownSection>
|
|
</template>
|