Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b55717a276 | ||
|
|
236142deff | ||
|
|
395beaacfe | ||
|
|
94aeedcada | ||
|
|
b4ca72b6dc | ||
|
|
40f3e1d651 | ||
|
|
1c82e9238d | ||
|
|
51d6211822 | ||
|
|
45e40b8aa1 | ||
|
|
2a64d218d3 | ||
|
|
44b52a029e | ||
|
|
74b81d2665 |
+1
-1
@@ -412,7 +412,7 @@ const accountLabels = computed(() => [
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Story
|
<Story
|
||||||
title="Components/ConversationCard"
|
title="Components/Conversation/ConversationCard"
|
||||||
:layout="{ type: 'grid', width: '600px' }"
|
:layout="{ type: 'grid', width: '600px' }"
|
||||||
>
|
>
|
||||||
<Variant title="Conversation without meta">
|
<Variant title="Conversation without meta">
|
||||||
|
|||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
<script setup>
|
||||||
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
import ConversationSortMenu from './ConversationSortMenu.vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
activeStatus: {
|
||||||
|
type: String,
|
||||||
|
default: 'open',
|
||||||
|
},
|
||||||
|
activeOrdering: {
|
||||||
|
type: String,
|
||||||
|
default: 'last_activity_at_desc',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits([
|
||||||
|
'filter',
|
||||||
|
'update:activeStatus',
|
||||||
|
'update:activeOrdering',
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between gap-2 pt-4 pb-4 ltr:pl-6 rtl:pr-6 ltr:pr-5 rtl:pl-5"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="min-w-0 text-base font-semibold leading-5 truncate text-n-slate-12"
|
||||||
|
>
|
||||||
|
{{ title }}
|
||||||
|
</h4>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
icon="i-lucide-list-filter"
|
||||||
|
color="slate"
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
@click="emit('filter')"
|
||||||
|
/>
|
||||||
|
<ConversationSortMenu
|
||||||
|
:active-status="activeStatus"
|
||||||
|
:active-ordering="activeOrdering"
|
||||||
|
@update:active-status="emit('update:activeStatus', $event)"
|
||||||
|
@update:active-ordering="emit('update:activeOrdering', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
+123
@@ -0,0 +1,123 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, computed, toRef } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { vOnClickOutside } from '@vueuse/components';
|
||||||
|
|
||||||
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
import SelectMenu from 'dashboard/components-next/selectmenu/SelectMenu.vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
activeStatus: {
|
||||||
|
type: String,
|
||||||
|
default: 'open',
|
||||||
|
},
|
||||||
|
activeOrdering: {
|
||||||
|
type: String,
|
||||||
|
default: 'last_activity_at_desc',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:activeStatus', 'update:activeOrdering']);
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const CHAT_STATUS_FILTER_ITEMS = Object.freeze([
|
||||||
|
'open',
|
||||||
|
'resolved',
|
||||||
|
'pending',
|
||||||
|
'snoozed',
|
||||||
|
'all',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const SORT_ORDER_ITEMS = Object.freeze([
|
||||||
|
'last_activity_at_asc',
|
||||||
|
'last_activity_at_desc',
|
||||||
|
'created_at_desc',
|
||||||
|
'created_at_asc',
|
||||||
|
'priority_desc',
|
||||||
|
'priority_asc',
|
||||||
|
'waiting_since_asc',
|
||||||
|
'waiting_since_desc',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Converted to ref to avoid reactivity issues
|
||||||
|
const activeStatus = toRef(props, 'activeStatus');
|
||||||
|
const activeOrdering = toRef(props, 'activeOrdering');
|
||||||
|
|
||||||
|
const statusMenus = computed(() => {
|
||||||
|
return CHAT_STATUS_FILTER_ITEMS.map(item => ({
|
||||||
|
label: t(`CONVERSATION_LIST.CHAT_STATUS.OPTIONS.${item.toUpperCase()}`),
|
||||||
|
value: item,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
const orderingMenus = computed(() => {
|
||||||
|
return SORT_ORDER_ITEMS.map(item => ({
|
||||||
|
label: t(`CONVERSATION_LIST.CHAT_SORT_ORDER.OPTIONS.${item.toUpperCase()}`),
|
||||||
|
value: item,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
const activeStatusLabel = computed(() => {
|
||||||
|
return t(
|
||||||
|
`CONVERSATION_LIST.CHAT_STATUS.OPTIONS.${activeStatus.value.toUpperCase()}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const activeOrderingLabel = computed(() => {
|
||||||
|
return t(
|
||||||
|
`CONVERSATION_LIST.CHAT_SORT_ORDER.OPTIONS.${activeOrdering.value.toUpperCase()}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const isMenuOpen = ref(false);
|
||||||
|
|
||||||
|
const handleStatusChange = value => {
|
||||||
|
emit('update:activeStatus', value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOrderChange = value => {
|
||||||
|
emit('update:activeOrdering', value);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="relative">
|
||||||
|
<Button
|
||||||
|
icon="i-lucide-arrow-down-up"
|
||||||
|
color="slate"
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
:class="isMenuOpen ? 'bg-n-alpha-2' : ''"
|
||||||
|
@click="isMenuOpen = !isMenuOpen"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="isMenuOpen"
|
||||||
|
v-on-click-outside="() => (isMenuOpen = false)"
|
||||||
|
class="absolute top-full mt-1 ltr:right-0 rtl:left-0 flex flex-col gap-4 bg-n-alpha-3 backdrop-blur-[100px] border border-n-weak w-72 rounded-xl p-4"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between gap-2">
|
||||||
|
<span class="text-sm text-n-slate-12">
|
||||||
|
{{ t('CONVERSATION_LIST.CHAT_STATUS.LABEL') }}
|
||||||
|
</span>
|
||||||
|
<SelectMenu
|
||||||
|
:model-value="activeStatus"
|
||||||
|
:options="statusMenus"
|
||||||
|
:label="activeStatusLabel"
|
||||||
|
@update:model-value="handleStatusChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between gap-2">
|
||||||
|
<span class="text-sm text-n-slate-12">
|
||||||
|
{{ t('CONVERSATION_LIST.CHAT_SORT_ORDER.LABEL') }}
|
||||||
|
</span>
|
||||||
|
<SelectMenu
|
||||||
|
:model-value="activeOrdering"
|
||||||
|
:options="orderingMenus"
|
||||||
|
:label="activeOrderingLabel"
|
||||||
|
@update:model-value="handleOrderChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
<script setup>
|
||||||
|
import ConversationListHeader from '../ConversationListHeader.vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
// Story state
|
||||||
|
const activeStatus = ref('open');
|
||||||
|
const activeOrdering = ref('last_activity_at_desc');
|
||||||
|
|
||||||
|
const filter = () => {
|
||||||
|
console.log('filter');
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateActiveStatus = newStatus => {
|
||||||
|
activeStatus.value = newStatus;
|
||||||
|
console.log('updateActiveStatus', newStatus);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateActiveOrdering = newOrdering => {
|
||||||
|
activeOrdering.value = newOrdering;
|
||||||
|
console.log('updateActiveOrdering', newOrdering);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Story title="Components/Conversation/ConversationListHeader">
|
||||||
|
<Variant title="Default">
|
||||||
|
<div
|
||||||
|
class="flex justify-center items-start w-full h-[500px] bg-n-solid-1"
|
||||||
|
>
|
||||||
|
<ConversationListHeader
|
||||||
|
title="Conversations"
|
||||||
|
:active-status="activeStatus"
|
||||||
|
:active-ordering="activeOrdering"
|
||||||
|
class="max-w-[400px] w-full"
|
||||||
|
@filter="filter"
|
||||||
|
@update:active-status="updateActiveStatus"
|
||||||
|
@update:active-ordering="updateActiveOrdering"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Variant>
|
||||||
|
</Story>
|
||||||
|
</template>
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
|
import { vOnClickOutside } from '@vueuse/components';
|
||||||
|
|
||||||
import Button from 'dashboard/components-next/button/Button.vue';
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -35,7 +37,7 @@ const handleSelect = value => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-on-clickaway="() => (isOpen = false)"
|
v-on-click-outside="() => (isOpen = false)"
|
||||||
class="relative flex flex-col gap-1 w-fit"
|
class="relative flex flex-col gap-1 w-fit"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
@@ -44,7 +46,7 @@ const handleSelect = value => {
|
|||||||
trailing-icon
|
trailing-icon
|
||||||
color="slate"
|
color="slate"
|
||||||
variant="faded"
|
variant="faded"
|
||||||
class="!w-fit"
|
class="!w-fit max-w-40"
|
||||||
:class="{ 'dark:!bg-n-alpha-2 !bg-n-slate-9/20': isOpen }"
|
:class="{ 'dark:!bg-n-alpha-2 !bg-n-slate-9/20': isOpen }"
|
||||||
:label="labelValue"
|
:label="labelValue"
|
||||||
@click="toggleMenu"
|
@click="toggleMenu"
|
||||||
|
|||||||
@@ -135,5 +135,32 @@
|
|||||||
"SHOW_QUOTED_TEXT": "Show Quoted Text",
|
"SHOW_QUOTED_TEXT": "Show Quoted Text",
|
||||||
"MESSAGE_READ": "Read",
|
"MESSAGE_READ": "Read",
|
||||||
"SENDING": "Sending"
|
"SENDING": "Sending"
|
||||||
|
},
|
||||||
|
|
||||||
|
"CONVERSATION_LIST": {
|
||||||
|
"CHAT_STATUS": {
|
||||||
|
"LABEL": "Status",
|
||||||
|
"OPTIONS": {
|
||||||
|
"OPEN": "Open",
|
||||||
|
"RESOLVED": "Resolved",
|
||||||
|
"PENDING": "Pending",
|
||||||
|
"SNOOZED": "Snoozed",
|
||||||
|
"ALL": "All"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"CHAT_SORT_ORDER": {
|
||||||
|
"LABEL": "Order by",
|
||||||
|
"OPTIONS": {
|
||||||
|
"LAST_ACTIVITY_AT_ASC": "Last activity: Oldest first",
|
||||||
|
"LAST_ACTIVITY_AT_DESC": "Last activity: Newest first",
|
||||||
|
"CREATED_AT_DESC": "Created at: Newest first",
|
||||||
|
"CREATED_AT_ASC": "Created at: Oldest first",
|
||||||
|
"PRIORITY_DESC": "Priority: Highest first",
|
||||||
|
"PRIORITY_ASC": "Priority: Lowest first",
|
||||||
|
"WAITING_SINCE_ASC": "Pending Response: Longest first",
|
||||||
|
"WAITING_SINCE_DESC": "Pending Response: Shortest first"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user