Shivam Mishra
2024-10-02 00:36:30 -07:00
committed by GitHub
co-authored by Pranav Sivin Varghese
parent e0bf2bd9d4
commit 42f6621afb
661 changed files with 15939 additions and 31194 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@
font-style: normal;
font-weight: 100;
font-display: swap;
src: url('~shared/assets/fonts/InterDisplay/InterDisplay-Thin.woff2') format('woff2');
src: url('shared/assets/fonts/InterDisplay/InterDisplay-Thin.woff2') format('woff2');
}
@font-face {
@@ -11,7 +11,7 @@
font-style: normal;
font-weight: 200;
font-display: swap;
src: url('~shared/assets/fonts/InterDisplay/InterDisplay-ExtraLight.woff2') format('woff2');
src: url('shared/assets/fonts/InterDisplay/InterDisplay-ExtraLight.woff2') format('woff2');
}
@font-face {
@@ -19,7 +19,7 @@
font-style: normal;
font-weight: 300;
font-display: swap;
src: url('~shared/assets/fonts/InterDisplay/InterDisplay-Light.woff2') format('woff2');
src: url('shared/assets/fonts/InterDisplay/InterDisplay-Light.woff2') format('woff2');
}
@font-face {
@@ -27,7 +27,7 @@
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('~shared/assets/fonts/InterDisplay/InterDisplay-Regular.woff2') format('woff2');
src: url('shared/assets/fonts/InterDisplay/InterDisplay-Regular.woff2') format('woff2');
}
@font-face {
@@ -35,7 +35,7 @@
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('~shared/assets/fonts/InterDisplay/InterDisplay-Medium.woff2') format('woff2');
src: url('shared/assets/fonts/InterDisplay/InterDisplay-Medium.woff2') format('woff2');
}
@font-face {
@@ -43,7 +43,7 @@
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('~shared/assets/fonts/InterDisplay/InterDisplay-SemiBold.woff2') format('woff2');
src: url('shared/assets/fonts/InterDisplay/InterDisplay-SemiBold.woff2') format('woff2');
}
@font-face {
@@ -51,7 +51,7 @@
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('~shared/assets/fonts/InterDisplay/InterDisplay-Bold.woff2') format('woff2');
src: url('shared/assets/fonts/InterDisplay/InterDisplay-Bold.woff2') format('woff2');
}
@font-face {
@@ -59,7 +59,7 @@
font-style: normal;
font-weight: 800;
font-display: swap;
src: url('~shared/assets/fonts/InterDisplay/InterDisplay-ExtraBold.woff2') format('woff2');
src: url('shared/assets/fonts/InterDisplay/InterDisplay-ExtraBold.woff2') format('woff2');
}
@font-face {
@@ -67,5 +67,5 @@
font-style: normal;
font-weight: 900;
font-display: swap;
src: url('~shared/assets/fonts/InterDisplay/InterDisplay-Black.woff2') format('woff2');
src: url('shared/assets/fonts/InterDisplay/InterDisplay-Black.woff2') format('woff2');
}
+7 -14
View File
@@ -3,8 +3,7 @@
font-style: normal;
font-weight: 100;
font-display: swap;
src: url('~shared/assets/fonts/Inter-Thin.woff2') format('woff2'),
url('~shared/assets/fonts/Inter-Thin.woff') format('woff');
src: url('shared/assets/fonts/Inter/Inter-Thin.woff2') format('woff2');
}
@font-face {
@@ -12,8 +11,7 @@
font-style: normal;
font-weight: 300;
font-display: swap;
src: url('~shared/assets/fonts/Inter-Light.woff2') format('woff2'),
url('~shared/assets/fonts/Inter-Light.woff') format('woff');
src: url('shared/assets/fonts/Inter/Inter-Light.woff2') format('woff2');
}
@font-face {
@@ -21,8 +19,7 @@
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('~shared/assets/fonts/Inter-Regular.woff2') format('woff2'),
url('~shared/assets/fonts/Inter-Regular.woff') format('woff');
src: url('shared/assets/fonts/Inter/Inter-Regular.woff2') format('woff2');
}
@font-face {
@@ -30,8 +27,7 @@
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('~shared/assets/fonts/Inter-Italic.woff2') format('woff2'),
url('~shared/assets/fonts/Inter-Italic.woff') format('woff');
src: url('shared/assets/fonts/Inter/Inter-Italic.woff2') format('woff2');
}
@font-face {
@@ -39,8 +35,7 @@
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('~shared/assets/fonts/Inter-Medium.woff2') format('woff2'),
url('~shared/assets/fonts/Inter-Medium.woff') format('woff');
src: url('shared/assets/fonts/Inter/Inter-Medium.woff2') format('woff2');
}
@font-face {
@@ -48,8 +43,7 @@
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('~shared/assets/fonts/Inter-SemiBold.woff2') format('woff2'),
url('~shared/assets/fonts/Inter-SemiBold.woff') format('woff');
src: url('shared/assets/fonts/Inter/Inter-SemiBold.woff2') format('woff2');
}
@font-face {
@@ -57,6 +51,5 @@
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('~shared/assets/fonts/Inter-Bold.woff2') format('woff2'),
url('~shared/assets/fonts/Inter-Bold.woff') format('woff');
src: url('shared/assets/fonts/Inter/Inter-Bold.woff2') format('woff2');
}
@@ -1,63 +0,0 @@
@font-face {
font-family: 'PlusJakarta';
font-style: normal;
font-weight: 200;
font-display: swap;
src: url('~shared/assets/fonts/PlusJakartaSans/PlusJakartaSans-ExtraLight.woff2') format('woff2');
}
@font-face {
font-family: 'PlusJakarta';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url('~shared/assets/fonts/PlusJakartaSans/PlusJakartaSans-Light.woff2') format('woff2');
}
@font-face {
font-family: 'PlusJakarta';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('~shared/assets/fonts/PlusJakartaSans/PlusJakartaSans-Regular.woff2') format('woff2');
}
@font-face {
font-family: 'PlusJakarta';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url('~shared/assets/fonts/PlusJakartaSans/PlusJakartaSans-Italic.woff2') format('woff2');
}
@font-face {
font-family: 'PlusJakarta';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('~shared/assets/fonts/PlusJakartaSans/PlusJakartaSans-Medium.woff2') format('woff2');
}
@font-face {
font-family: 'PlusJakarta';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('~shared/assets/fonts/PlusJakartaSans/PlusJakartaSans-SemiBold.woff2') format('woff2');
}
@font-face {
font-family: 'PlusJakarta';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('~shared/assets/fonts/PlusJakartaSans/PlusJakartaSans-Bold.woff2') format('woff2');
}
@font-face {
font-family: 'PlusJakarta';
font-style: normal;
font-weight: 800;
font-display: swap;
src: url('~shared/assets/fonts/PlusJakartaSans/PlusJakartaSans-ExtraBold.woff2') format('woff2');
}
@@ -3,8 +3,7 @@
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('~shared/assets/fonts/Inter-Regular.woff2') format('woff2'),
url('~shared/assets/fonts/Inter-Regular.woff') format('woff');
src: url('shared/assets/fonts/Inter/Inter-Regular.woff2') format('woff2');
}
@font-face {
@@ -12,6 +11,5 @@
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('~shared/assets/fonts/Inter-Medium.woff2') format('woff2'),
url('~shared/assets/fonts/Inter-Medium.woff') format('woff');
src: url('shared/assets/fonts/Inter/Inter-Medium.woff2') format('woff2');
}
@@ -1,24 +0,0 @@
@import "~ionicons/scss/ionicons-variables";
@font-face {
font-display: swap;
font-family: $ionicons-font-family;
font-style: normal;
font-weight: normal;
src: url("#{$ionicons-font-path}/ionicons.woff?v=#{$ionicons-version}") format("woff");
}
.ion {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
display: inline-block;
font-family: $ionicons-font-family;
font-style: normal;
font-variant: normal;
font-weight: normal;
line-height: 1;
text-rendering: auto;
text-transform: none;
}
@import "~ionicons/scss/ionicons-icons";
@@ -69,7 +69,7 @@ export default {
</template>
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
@import 'widget/assets/scss/variables.scss';
.branding--image {
margin-right: $space-smaller;
+1 -11
View File
@@ -48,21 +48,11 @@ export default {
return styles;
},
},
methods: {
onClick(e) {
this.$emit('click', e);
},
},
};
</script>
<template>
<button
:class="buttonClassName"
:style="buttonStyles"
:disabled="disabled"
@click="onClick"
>
<button :class="buttonClassName" :style="buttonStyles" :disabled="disabled">
<slot />
</button>
</template>
@@ -56,8 +56,7 @@ export default {
</template>
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
@import '~dashboard/assets/scss/mixins.scss';
@import 'widget/assets/scss/variables.scss';
.action-button {
align-items: center;
@@ -56,8 +56,8 @@ export default {
</template>
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
@import '~dashboard/assets/scss/mixins.scss';
@import 'widget/assets/scss/variables.scss';
@import 'dashboard/assets/scss/mixins.scss';
.card-message {
max-width: 220px;
@@ -167,7 +167,7 @@ export default {
</template>
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
@import 'widget/assets/scss/variables.scss';
.form {
padding: $space-normal;
@@ -20,7 +20,7 @@ export default {
},
methods: {
onClick() {
this.$emit('click', this.action);
this.$emit('optionSelect', this.action);
},
},
};
@@ -39,7 +39,7 @@ export default {
</template>
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
@import 'widget/assets/scss/variables.scss';
.option {
border-radius: $space-jumbo;
@@ -35,7 +35,7 @@ export default {
return this.selected === option.id;
},
onClick(selectedOption) {
this.$emit('click', selectedOption);
this.$emit('optionSelect', selectedOption);
},
},
};
@@ -60,7 +60,7 @@ export default {
:key="option.id"
:action="option"
:is-selected="isSelected(option)"
@click="onClick"
@option-select="onClick"
/>
</ul>
</div>
@@ -68,7 +68,8 @@ export default {
</template>
<style lang="scss">
@import '~dashboard/assets/scss/variables.scss';
@import 'dashboard/assets/scss/variables.scss';
.has-selected {
.option-button:not(.is-selected) {
color: $color-light-gray;
@@ -78,7 +79,7 @@ export default {
</style>
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
@import 'widget/assets/scss/variables.scss';
.options-message {
max-width: 17rem;
@@ -1,19 +0,0 @@
import { action } from '@storybook/addon-actions';
import CustomerSatisfaction from './CustomerSatisfaction';
export default {
title: 'Components/CustomerSatisfaction',
component: CustomerSatisfaction,
argTypes: {},
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { CustomerSatisfaction },
template: '<customer-satisfaction />',
});
export const Item = Template.bind({});
Item.args = {
onClick: action('Selected'),
};
@@ -156,8 +156,8 @@ export default {
</template>
<style lang="scss" scoped>
@import '~widget/assets/scss/variables.scss';
@import '~widget/assets/scss/mixins.scss';
@import 'widget/assets/scss/variables.scss';
@import 'widget/assets/scss/mixins.scss';
.customer-satisfaction {
@include light-shadow;
@@ -204,6 +204,7 @@ export default {
}
}
}
.feedback-form {
display: flex;
@@ -35,7 +35,7 @@ export default {
</template>
<style lang="scss" scoped>
@import '~widget/assets/scss/variables';
@import 'widget/assets/scss/variables';
.date--separator {
font-size: $font-size-default;
@@ -13,7 +13,7 @@ export default {
type: String,
default: '',
},
value: {
modelValue: {
type: String,
default: '',
},
@@ -82,7 +82,7 @@ export default {
},
mounted() {
this.$nextTick(() => {
if (this.value) {
if (this.modelValue) {
this.resizeTextarea();
this.setCursor();
} else {
@@ -93,7 +93,7 @@ export default {
methods: {
resizeTextarea() {
this.$el.style.height = 'auto';
if (!this.value) {
if (!this.modelValue) {
this.$el.style.height = `${this.minHeight}rem`;
} else {
this.$el.style.height = `${this.$el.scrollHeight}px`;
@@ -104,9 +104,10 @@ export default {
// is supposed to be added, else we remove it.
toggleSignatureInEditor(signatureEnabled) {
const valueWithSignature = signatureEnabled
? appendSignature(this.value, this.cleanedSignature)
: removeSignature(this.value, this.cleanedSignature);
? appendSignature(this.modelValue, this.cleanedSignature)
: removeSignature(this.modelValue, this.cleanedSignature);
this.$emit('update:modelValue', valueWithSignature);
this.$emit('input', valueWithSignature);
this.$nextTick(() => {
@@ -116,7 +117,7 @@ export default {
},
setCursor() {
const bodyWithoutSignature = removeSignature(
this.value,
this.modelValue,
this.cleanedSignature
);
@@ -130,6 +131,7 @@ export default {
}
},
onInput(event) {
this.$emit('update:modelValue', event.target.value);
this.$emit('input', event.target.value);
this.resizeTextarea();
},
@@ -155,7 +157,7 @@ export default {
ref="textarea"
:placeholder="placeholder"
:rows="rows"
:value="value"
:value="modelValue"
@input="onInput"
@focus="onFocus"
@keyup="onKeyup"
+1 -1
View File
@@ -35,7 +35,7 @@ export default {
</template>
<style scoped lang="scss">
@import '~widget/assets/scss/variables';
@import 'widget/assets/scss/variables.scss';
@mixin color-spinner() {
@keyframes spinner {
+10 -6
View File
@@ -9,7 +9,7 @@ export default {
type: String,
default: '',
},
value: {
modelValue: {
type: [String, Number],
required: true,
},
@@ -18,9 +18,14 @@ export default {
default: '',
},
},
methods: {
onChange(event) {
this.$emit('input', event.target.value);
computed: {
computedModel: {
get() {
return this.modelValue;
},
set(value) {
this.$emit('update:modelValue', value);
},
},
},
};
@@ -39,6 +44,7 @@ export default {
{{ label }}
</div>
<textarea
v-model="computedModel"
class="w-full px-3 py-2 leading-tight border rounded outline-none resize-none text-slate-700"
:class="{
'border-black-200 hover:border-black-300 focus:border-black-300':
@@ -46,8 +52,6 @@ export default {
'border-red-200 hover:border-red-300 focus:border-red-300': error,
}"
:placeholder="placeholder"
:value="value"
@change="onChange"
/>
<div v-if="error" class="mt-2 text-xs font-medium text-red-400">
{{ error }}
@@ -0,0 +1,77 @@
<script setup>
import { computed } from 'vue';
import { Bar } from 'vue-chartjs';
import {
Chart as ChartJS,
Title,
Tooltip,
BarElement,
CategoryScale,
LinearScale,
} from 'chart.js';
const props = defineProps({
collection: {
type: Object,
default: () => ({}),
},
chartOptions: {
type: Object,
default: () => ({}),
},
});
ChartJS.register(Title, Tooltip, BarElement, CategoryScale, LinearScale);
const fontFamily =
'Inter,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
const defaultChartOptions = {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false,
labels: {
fontFamily,
},
},
animation: {
duration: 0,
},
datasets: {
bar: {
barPercentage: 1.0,
},
},
scales: {
x: {
ticks: {
fontFamily: fontFamily,
},
grid: {
drawOnChartArea: false,
},
},
y: {
type: 'linear',
position: 'left',
ticks: {
fontFamily: fontFamily,
beginAtZero: true,
stepSize: 1,
},
grid: {
drawOnChartArea: false,
},
},
},
};
const options = computed(() => {
return { ...defaultChartOptions, ...props.chartOptions };
});
</script>
<template>
<Bar :data="collection" :options="options" />
</template>
@@ -184,6 +184,7 @@ export default {
<style scoped>
@tailwind components;
@layer components {
.box-shadow-blue {
box-shadow:
@@ -200,7 +201,7 @@ export default {
</style>
<style lang="scss">
@import '~dashboard/assets/scss/mixins';
@import 'dashboard/assets/scss/mixins';
.emoji-dialog {
&::before {
@@ -210,6 +211,7 @@ export default {
$color-bg-dark: #26292b;
@include arrow(bottom, $color-bg-dark, $space-slab);
}
@media (prefers-color-scheme: light) {
$color-bg: #ebf0f5;
@include arrow(bottom, $color-bg, $space-slab);
@@ -245,6 +247,7 @@ export default {
.emoji-icon {
@apply text-slate-200 dark:text-slate-200 mb-2;
}
.empty-message--text {
@apply text-slate-200 dark:text-slate-200 text-sm font-medium;
}
@@ -271,6 +274,7 @@ export default {
li .active {
@apply bg-white dark:bg-slate-900;
}
.emoji--item {
@apply items-center flex text-sm;
@@ -1,65 +0,0 @@
import { action } from '@storybook/addon-actions';
import Dropdown from './MultiselectDropdown';
export default {
title: 'Components/Dropdown/Multiselect Dropdown',
component: Dropdown,
argTypes: {
options: {
control: {
type: 'object',
},
},
selectedItem: {
control: {
type: 'object',
},
},
multiselectorTitle: {
control: {
type: 'text',
},
},
multiselectorPlaceholder: {
control: {
type: 'text',
},
},
noSearchResult: {
control: {
type: 'text',
},
},
inputPlaceholder: {
control: {
type: 'text',
},
},
},
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { Dropdown },
template: '<dropdown v-bind="$props" @click="onClick"></dropdown>',
});
export const MultiselectDropdown = Template.bind({});
MultiselectDropdown.args = {
onClick: action('Opened'),
options: [
{
id: 1,
availability_status: 'online',
name: 'James Philip',
thumbnail: 'https://randomuser.me/api/portraits/men/4.jpg',
},
],
selectedItem: {
id: 1,
availability_status: 'online',
name: 'James Philip',
thumbnail: 'https://randomuser.me/api/portraits/men/4.jpg',
},
};
@@ -1,142 +1,130 @@
<script>
<script setup>
import { computed, defineEmits } from 'vue';
import { OnClickOutside } from '@vueuse/components';
import { useToggle } from '@vueuse/core';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import MultiselectDropdownItems from 'shared/components/ui/MultiselectDropdownItems.vue';
export default {
components: {
Thumbnail,
MultiselectDropdownItems,
},
props: {
options: {
type: Array,
default: () => [],
},
selectedItem: {
type: Object,
default: () => ({}),
},
hasThumbnail: {
type: Boolean,
default: true,
},
multiselectorTitle: {
type: String,
default: '',
},
multiselectorPlaceholder: {
type: String,
default: 'None',
},
noSearchResult: {
type: String,
default: 'No results found',
},
inputPlaceholder: {
type: String,
default: 'Search',
},
},
data() {
return {
showSearchDropdown: false,
};
},
computed: {
hasValue() {
if (this.selectedItem && this.selectedItem.id) {
return true;
}
return false;
},
},
methods: {
toggleDropdown() {
this.showSearchDropdown = !this.showSearchDropdown;
},
onCloseDropdown() {
this.showSearchDropdown = false;
},
onClickSelectItem(value) {
this.$emit('click', value);
this.onCloseDropdown();
},
const props = defineProps({
options: {
type: Array,
default: () => [],
},
selectedItem: {
type: Object,
default: () => ({}),
},
hasThumbnail: {
type: Boolean,
default: true,
},
multiselectorTitle: {
type: String,
default: '',
},
multiselectorPlaceholder: {
type: String,
default: 'None',
},
noSearchResult: {
type: String,
default: 'No results found',
},
inputPlaceholder: {
type: String,
default: 'Search',
},
});
const emit = defineEmits(['select']);
const [showSearchDropdown, toggleDropdown] = useToggle(false);
const onCloseDropdown = () => toggleDropdown(false);
const onClickSelectItem = value => {
emit('select', value);
onCloseDropdown();
};
const hasValue = computed(() => {
if (props.selectedItem && props.selectedItem.id) {
return true;
}
return false;
});
</script>
<template>
<div
v-on-clickaway="onCloseDropdown"
class="relative w-full mb-2"
@keyup.esc="onCloseDropdown"
>
<woot-button
variant="hollow"
color-scheme="secondary"
class="w-full border border-solid border-slate-100 dark:border-slate-700 px-2 hover:border-slate-75 dark:hover:border-slate-600"
@click="toggleDropdown"
>
<div class="flex gap-1">
<Thumbnail
v-if="hasValue && hasThumbnail"
:src="selectedItem.thumbnail"
size="24px"
:status="selectedItem.availability_status"
:username="selectedItem.name"
/>
<div class="flex justify-between w-full min-w-0 items-center">
<h4
v-if="!hasValue"
class="text-ellipsis text-sm text-slate-800 dark:text-slate-100"
>
{{ multiselectorPlaceholder }}
</h4>
<h4
v-else
class="items-center leading-tight overflow-hidden whitespace-nowrap text-ellipsis text-sm text-slate-800 dark:text-slate-100"
:title="selectedItem.name"
>
{{ selectedItem.name }}
</h4>
<i
v-if="showSearchDropdown"
class="icon ion-chevron-up text-slate-600 mr-1"
<OnClickOutside @trigger="onCloseDropdown">
<div class="relative w-full mb-2" @keyup.esc="onCloseDropdown">
<woot-button
variant="hollow"
color-scheme="secondary"
class="w-full border border-solid border-slate-100 dark:border-slate-700 px-2 hover:border-slate-75 dark:hover:border-slate-600"
@click="
() => toggleDropdown() // ensure that the event is not passed to the button
"
>
<div class="flex gap-1">
<Thumbnail
v-if="hasValue && hasThumbnail"
:src="selectedItem.thumbnail"
size="24px"
:status="selectedItem.availability_status"
:username="selectedItem.name"
/>
<i v-else class="icon ion-chevron-down text-slate-600 mr-1" />
<div class="flex justify-between w-full min-w-0 items-center">
<h4
v-if="!hasValue"
class="text-ellipsis text-sm text-slate-800 dark:text-slate-100"
>
{{ multiselectorPlaceholder }}
</h4>
<h4
v-else
class="items-center leading-tight overflow-hidden whitespace-nowrap text-ellipsis text-sm text-slate-800 dark:text-slate-100"
:title="selectedItem.name"
>
{{ selectedItem.name }}
</h4>
<i
v-if="showSearchDropdown"
class="icon i-lucide-chevron-up text-slate-600 mr-1"
/>
<i v-else class="icon i-lucide-chevron-down text-slate-600 mr-1" />
</div>
</div>
</div>
</woot-button>
<div
:class="{ 'dropdown-pane--open': showSearchDropdown }"
class="dropdown-pane"
>
<div class="flex justify-between items-center mb-1">
<h4
class="text-sm text-slate-800 dark:text-slate-100 m-0 overflow-hidden whitespace-nowrap text-ellipsis"
>
{{ multiselectorTitle }}
</h4>
<woot-button
icon="dismiss"
size="tiny"
color-scheme="secondary"
variant="clear"
@click="onCloseDropdown"
</woot-button>
<div
:class="{ 'dropdown-pane--open': showSearchDropdown }"
class="dropdown-pane"
>
<div class="flex justify-between items-center mb-1">
<h4
class="text-sm text-slate-800 dark:text-slate-100 m-0 overflow-hidden whitespace-nowrap text-ellipsis"
>
{{ multiselectorTitle }}
</h4>
<woot-button
icon="dismiss"
size="tiny"
color-scheme="secondary"
variant="clear"
@click="onCloseDropdown"
/>
</div>
<MultiselectDropdownItems
v-if="showSearchDropdown"
:options="options"
:selected-items="[selectedItem]"
:has-thumbnail="hasThumbnail"
:input-placeholder="inputPlaceholder"
:no-search-result="noSearchResult"
@select="onClickSelectItem"
/>
</div>
<MultiselectDropdownItems
v-if="showSearchDropdown"
:options="options"
:selected-items="[selectedItem]"
:has-thumbnail="hasThumbnail"
:input-placeholder="inputPlaceholder"
:no-search-result="noSearchResult"
@click="onClickSelectItem"
/>
</div>
</div>
</OnClickOutside>
</template>
<style lang="scss" scoped>
@@ -1,67 +0,0 @@
import { action } from '@storybook/addon-actions';
import DropdownItems from './MultiselectDropdownItems';
export default {
title: 'Components/Dropdown/Multiselect Dropdown Items',
component: DropdownItems,
argTypes: {
options: {
control: {
type: 'object',
},
},
selectedItems: {
control: {
type: 'object',
},
},
inputPlaceholder: {
control: {
type: 'text',
},
},
noSearchResult: {
control: {
type: 'text',
},
},
},
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { DropdownItems },
template:
'<dropdown-items v-bind="$props" @click="onClick"></dropdown-items>',
});
export const MultiselectDropdownItems = Template.bind({});
MultiselectDropdownItems.args = {
onClick: action('Added'),
options: [
{
id: '0',
name: 'None',
thumbnail: '',
},
{
id: '1',
name: 'James Philip',
availability_status: 'online',
role: 'administrator',
thumbnail: 'https://randomuser.me/api/portraits/men/4.jpg',
},
{
id: '2',
name: 'Support Team',
thumbnail: '',
},
{
id: '3',
name: 'Agent',
thumbnail: '',
},
],
selectedItems: [{ id: '1' }],
};
@@ -56,7 +56,7 @@ export default {
methods: {
onclick(option) {
this.$emit('click', option);
this.$emit('select', option);
},
focusInput() {
this.$refs.searchbar.focus();
@@ -1,19 +0,0 @@
import { action } from '@storybook/addon-actions';
import AddLabel from './AddLabel';
export default {
title: 'Components/Label/Add Button',
component: AddLabel,
argTypes: {},
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { AddLabel },
template: '<add-label v-bind="$props" @add="onClick"></add-label>',
});
export const AddButton = Template.bind({});
AddButton.args = {
onClick: action('opened'),
};
@@ -1,58 +0,0 @@
import { action } from '@storybook/addon-actions';
import LabelDropdown from './LabelDropdown';
export default {
title: 'Components/Label/Dropdown',
component: LabelDropdown,
argTypes: {
conversationId: {
control: {
type: 'text',
},
},
accountLabels: {
defaultValue: [
{
color: '#555',
description: '',
id: 1,
title: 'sales',
},
{
color: '#c242f5',
description: '',
id: 1,
title: 'business',
},
{
color: '#4287f5',
description: '',
id: 1,
title: 'testing',
},
],
control: {
type: 'object',
},
},
selectedLabels: {
defaultValue: 'sales, testing',
control: {
type: 'object',
},
},
},
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { LabelDropdown },
template:
'<label-dropdown v-bind="$props" @add="onAdd" @remove="onRemove"></label-dropdown>',
});
export const Dropdown = Template.bind({});
Dropdown.args = {
onAdd: action('added'),
onRemove: action('removed'),
};
@@ -142,7 +142,7 @@ export default {
:title="label.title"
:color="label.color"
:selected="selectedLabels.includes(label.title)"
@click="onAddRemove(label)"
@select-label="onAddRemove(label)"
/>
</woot-dropdown-menu>
<div
@@ -1,39 +0,0 @@
import { action } from '@storybook/addon-actions';
import LabelDropdownItem from './LabelDropdownItem';
export default {
title: 'Components/Label/Item',
component: LabelDropdownItem,
argTypes: {
title: {
defaultValue: 'sales',
control: {
type: 'text',
},
},
color: {
defaultValue: '#555',
control: {
type: 'text',
},
},
selected: {
defaultValue: true,
control: {
type: 'boolean',
},
},
},
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { LabelDropdownItem },
template:
'<label-dropdown-item v-bind="$props" @click="onClick"></label-dropdown-item>',
});
export const Item = Template.bind({});
Item.args = {
onClick: action('Selected'),
};
@@ -17,7 +17,7 @@ export default {
methods: {
onClick() {
this.$emit('click', this.title);
this.$emit('selectLabel', this.title);
},
},
};
@@ -37,7 +37,7 @@ export default {
<span class="label-text" :title="title">{{ title }}</span>
</div>
<div>
<i v-if="selected" class="icon ion-checkmark-round" />
<i v-if="selected" class="i-lucide-circle-check" />
</div>
</div>
</woot-button>
@@ -1,10 +1,10 @@
import { describe, it, expect, vi } from 'vitest';
import { useCampaign } from '../useCampaign';
import { useRoute } from 'dashboard/composables/route';
import { useRoute } from 'vue-router';
import { CAMPAIGN_TYPES } from '../../constants/campaign';
// Mock the useRoute composable
vi.mock('dashboard/composables/route', () => ({
vi.mock('vue-router', () => ({
useRoute: vi.fn(),
}));
@@ -1,11 +1,11 @@
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { useFilter } from '../useFilter';
import { useStore } from 'dashboard/composables/store';
import { useI18n } from 'dashboard/composables/useI18n';
import { useI18n } from 'vue-i18n';
// Mock the dependencies
vi.mock('dashboard/composables/store');
vi.mock('dashboard/composables/useI18n');
vi.mock('vue-i18n');
describe('useFilter', () => {
// Setup mocks
@@ -1,5 +1,5 @@
import { computed } from 'vue';
import { useRoute } from 'dashboard/composables/route';
import { useRoute } from 'vue-router';
import { CAMPAIGN_TYPES } from '../constants/campaign';
/**
@@ -1,6 +1,6 @@
import wootConstants from 'dashboard/constants/globals';
import { useStore } from 'dashboard/composables/store';
import { useI18n } from 'dashboard/composables/useI18n';
import { useI18n } from 'vue-i18n';
import { filterAttributeGroups as conversationFilterAttributeGroups } from 'dashboard/components/widgets/conversation/advancedFilterItems';
import { filterAttributeGroups as contactFilterAttributeGroups } from 'dashboard/routes/dashboard/contacts/contactFilterItems';
import * as OPERATORS from 'dashboard/components/widgets/FilterInput/FilterOperatorTypes.js';
@@ -1,6 +1,6 @@
import mila from 'markdown-it-link-attributes';
import mentionPlugin from './markdownIt/link';
import MarkdownIt from 'markdown-it';
const setImageHeight = inlineToken => {
const imgSrc = inlineToken.attrGet('src');
if (!imgSrc) return;
@@ -30,7 +30,7 @@ const imgResizeManager = md => {
});
};
const md = require('markdown-it')({
const md = MarkdownIt({
html: false,
xhtmlOut: true,
breaks: true,
@@ -1,5 +1,3 @@
import Vue from 'vue';
export const set = (state, data) => {
state.records = data;
};
@@ -20,7 +18,7 @@ export const setSingleRecord = (state, data) => {
export const update = (state, data) => {
state.records.forEach((element, index) => {
if (element.id === data.id) {
Vue.set(state.records, index, data);
state.records[index] = data;
}
});
};
@@ -29,7 +27,7 @@ export const update = (state, data) => {
export const updateAttributes = (state, data) => {
state.records.forEach((element, index) => {
if (element.id === data.id) {
Vue.set(state.records, index, { ...state.records[index], ...data });
state.records[index] = { ...state.records[index], ...data };
}
});
};
@@ -37,11 +35,7 @@ export const updateAttributes = (state, data) => {
export const updatePresence = (state, data) => {
state.records.forEach((element, index) => {
const availabilityStatus = data[element.id];
Vue.set(
state.records[index],
'availability_status',
availabilityStatus || 'offline'
);
state.records[index].availability_status = availabilityStatus || 'offline';
});
};
@@ -51,7 +45,7 @@ export const updateSingleRecordPresence = (
) => {
const [selectedRecord] = records.filter(record => record.id === Number(id));
if (selectedRecord) {
Vue.set(selectedRecord, 'availability_status', availabilityStatus);
selectedRecord.availability_status = availabilityStatus;
}
};
@@ -14,7 +14,7 @@ export default {
this.addEventHandler(keydownHandler);
}
},
beforeDestroy() {
unmounted() {
if (this.$el && this.$el.dataset?.keydownHandlerIndex) {
const handlerToRemove =
taggedHandlers[this.$el.dataset.keydownHandlerIndex];