Shivam Mishra
2024-10-02 13:06:30 +05:30
committed by GitHub
parent e0bf2bd9d4
commit 42f6621afb
661 changed files with 15939 additions and 31194 deletions

View File

@@ -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');
}

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');
}

View File

@@ -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');
}

View File

@@ -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');
}

View File

@@ -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";

View File

@@ -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;

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>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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'),
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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"

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 {

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 }}

View File

@@ -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>

View File

@@ -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;

View File

@@ -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',
},
};

View File

@@ -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>

View File

@@ -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' }],
};

View File

@@ -56,7 +56,7 @@ export default {
methods: {
onclick(option) {
this.$emit('click', option);
this.$emit('select', option);
},
focusInput() {
this.$refs.searchbar.focus();

View File

@@ -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'),
};

View File

@@ -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'),
};

View File

@@ -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

View File

@@ -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'),
};

View File

@@ -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>

View File

@@ -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(),
}));

View File

@@ -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

View File

@@ -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';
/**

View File

@@ -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';

View File

@@ -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,

View File

@@ -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;
}
};

View File

@@ -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];