Restructure omni services and add Chatwoot research snapshot

This commit is contained in:
Ruslan Bakiev
2026-02-21 11:11:27 +07:00
parent edea7a0034
commit b73babbbf6
7732 changed files with 978203 additions and 32 deletions

View File

@@ -0,0 +1,65 @@
<script setup>
import { ref } from 'vue';
import { useStore } from 'dashboard/composables/store';
import { useAlert } from 'dashboard/composables';
import { useI18n } from 'vue-i18n';
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
import ConnectInboxForm from './ConnectInboxForm.vue';
defineProps({
assistantId: {
type: Number,
required: true,
},
});
const emit = defineEmits(['close']);
const { t } = useI18n();
const store = useStore();
const dialogRef = ref(null);
const connectForm = ref(null);
const i18nKey = 'CAPTAIN.INBOXES.CREATE';
const handleSubmit = async payload => {
try {
await store.dispatch('captainInboxes/create', payload);
useAlert(t(`${i18nKey}.SUCCESS_MESSAGE`));
dialogRef.value.close();
} catch (error) {
const errorMessage = error?.message || t(`${i18nKey}.ERROR_MESSAGE`);
useAlert(errorMessage);
}
};
const handleClose = () => {
emit('close');
};
const handleCancel = () => {
dialogRef.value.close();
};
defineExpose({ dialogRef });
</script>
<template>
<Dialog
ref="dialogRef"
type="create"
:title="$t(`${i18nKey}.TITLE`)"
:description="$t('CAPTAIN.INBOXES.FORM_DESCRIPTION')"
:show-cancel-button="false"
:show-confirm-button="false"
@close="handleClose"
>
<ConnectInboxForm
ref="connectForm"
:assistant-id="assistantId"
@submit="handleSubmit"
@cancel="handleCancel"
/>
<template #footer />
</Dialog>
</template>

View File

@@ -0,0 +1,115 @@
<script setup>
import { reactive, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useVuelidate } from '@vuelidate/core';
import { required } from '@vuelidate/validators';
import { useMapGetter } from 'dashboard/composables/store';
import Button from 'dashboard/components-next/button/Button.vue';
import ComboBox from 'dashboard/components-next/combobox/ComboBox.vue';
const props = defineProps({
assistantId: {
type: Number,
required: true,
},
});
const emit = defineEmits(['submit', 'cancel']);
const { t } = useI18n();
const formState = {
uiFlags: useMapGetter('captainInboxes/getUIFlags'),
inboxes: useMapGetter('inboxes/getInboxes'),
captainInboxes: useMapGetter('captainInboxes/getRecords'),
};
const initialState = {
inboxId: null,
};
const state = reactive({ ...initialState });
const validationRules = {
inboxId: { required },
};
const inboxList = computed(() => {
const captainInboxIds = formState.captainInboxes.value.map(inbox => inbox.id);
return formState.inboxes.value
.filter(inbox => !captainInboxIds.includes(inbox.id))
.map(inbox => ({
value: inbox.id,
label: inbox.name,
}));
});
const v$ = useVuelidate(validationRules, state);
const isLoading = computed(() => formState.uiFlags.value.creatingItem);
const getErrorMessage = (field, errorKey) => {
return v$.value[field].$error
? t(`CAPTAIN.INBOXES.FORM.${errorKey}.ERROR`)
: '';
};
const formErrors = computed(() => ({
inboxId: getErrorMessage('inboxId', 'INBOX'),
}));
const handleCancel = () => emit('cancel');
const prepareInboxPayload = () => ({
inboxId: state.inboxId,
assistantId: props.assistantId,
});
const handleSubmit = async () => {
const isFormValid = await v$.value.$validate();
if (!isFormValid) {
return;
}
emit('submit', prepareInboxPayload());
};
</script>
<template>
<form class="flex flex-col gap-4" @submit.prevent="handleSubmit">
<div class="flex flex-col gap-1">
<label for="inbox" class="mb-0.5 text-sm font-medium text-n-slate-12">
{{ t('CAPTAIN.INBOXES.FORM.INBOX.LABEL') }}
</label>
<ComboBox
id="inbox"
v-model="state.inboxId"
:options="inboxList"
:has-error="!!formErrors.inboxId"
:placeholder="t('CAPTAIN.INBOXES.FORM.INBOX.PLACEHOLDER')"
class="[&>div>button]:bg-n-alpha-black2 [&>div>button:not(.focused)]:dark:outline-n-weak [&>div>button:not(.focused)]:hover:!outline-n-slate-6"
:message="formErrors.inboxId"
/>
</div>
<div class="flex items-center justify-between w-full gap-3">
<Button
type="button"
variant="faded"
color="slate"
:label="t('CAPTAIN.FORM.CANCEL')"
class="w-full bg-n-alpha-2 text-n-blue-11 hover:bg-n-alpha-3"
@click="handleCancel"
/>
<Button
type="submit"
:label="t('CAPTAIN.FORM.CREATE')"
class="w-full"
:is-loading="isLoading"
:disabled="isLoading"
/>
</div>
</form>
</template>