chatwoot-develop/app/javascript/dashboard/routes/dashboard/captain/units/UnitModal.vue

317 lines
10 KiB
Vue

<script>
/* eslint-disable @intlify/vue-i18n/no-raw-text, vue/no-bare-strings-in-template */
import { useVuelidate } from '@vuelidate/core';
import { required } from '@vuelidate/validators';
import { useAlert } from 'dashboard/composables';
import WootModal from 'dashboard/components/Modal.vue';
import WootInput from 'dashboard/components-next/input/Input.vue';
import WootButton from 'dashboard/components-next/button/Button.vue';
export default {
components: {
WootModal,
WootInput,
WootButton,
},
props: {
show: {
type: Boolean,
default: false,
},
unit: {
type: Object,
default: null,
},
},
emits: ['close', 'save'],
setup() {
return {
v$: useVuelidate(),
alert: useAlert(),
};
},
data() {
return {
name: '',
captain_brand_id: '',
inter_client_id: '',
inter_client_secret: '',
inter_pix_key: '',
inter_cert_path: '',
inter_key_path: '',
inter_account_number: '',
webhook_url: '',
inbox_id: '',
brands: [],
inboxes: [],
isLoadingBrands: false,
};
},
validations() {
return {
name: { required },
captain_brand_id: { required },
};
},
watch: {
show(val) {
if (val) {
this.fetchBrands();
this.fetchInboxes();
if (this.unit) {
this.name = this.unit.name;
this.captain_brand_id = this.unit.captain_brand_id;
this.inter_client_id = this.unit.inter_client_id;
this.inter_client_secret = this.unit.inter_client_secret;
this.inter_pix_key = this.unit.inter_pix_key;
this.inter_cert_path = this.unit.inter_cert_path;
this.inter_key_path = this.unit.inter_key_path;
this.inter_account_number = this.unit.inter_account_number;
this.webhook_url = this.unit.webhook_url;
this.inbox_id = this.unit.inbox_id;
} else {
this.resetForm();
}
}
},
},
methods: {
resetForm() {
this.name = '';
this.captain_brand_id = '';
this.inter_client_id = '';
this.inter_client_secret = '';
this.inter_pix_key = '';
this.inter_cert_path = '';
this.inter_key_path = '';
this.inter_account_number = '';
this.webhook_url = '';
this.inbox_id = '';
this.v$.$reset();
},
async fetchInboxes() {
try {
const { data } = await window.axios.get(
`/api/v1/accounts/${this.$route.params.accountId}/inboxes`
);
this.inboxes = data.payload;
} catch (error) {
// Silent error or alert
}
},
async fetchBrands() {
this.isLoadingBrands = true;
try {
const { data } = await window.axios.get(
`/api/v1/accounts/${this.$route.params.accountId}/captain/brands`
);
this.brands = data;
} catch (error) {
this.alert(this.$t('CAPTAIN.UNITS.ERROR_FETCHING'));
} finally {
this.isLoadingBrands = false;
}
},
async save() {
this.v$.$touch();
if (this.v$.$invalid) return;
const payload = {
name: this.name,
captain_brand_id: this.captain_brand_id,
inter_client_id: this.inter_client_id,
inter_client_secret: this.inter_client_secret,
inter_pix_key: this.inter_pix_key,
inter_cert_path: this.inter_cert_path,
inter_key_path: this.inter_key_path,
inter_account_number: this.inter_account_number,
webhook_url: this.webhook_url,
inbox_id: this.inbox_id,
};
try {
let response;
if (this.unit) {
response = await window.axios.put(
`/api/v1/accounts/${this.$route.params.accountId}/captain/units/${this.unit.id}`,
{ unit: payload }
);
} else {
response = await window.axios.post(
`/api/v1/accounts/${this.$route.params.accountId}/captain/units`,
{ unit: payload }
);
}
this.$emit('save', response.data);
this.$emit('close');
this.alert(this.$t('CAPTAIN.UNITS.SAVE_SUCCESS'));
} catch (error) {
this.alert(this.$t('CAPTAIN.UNITS.SAVE_ERROR'));
}
},
},
};
</script>
<template>
<!-- eslint-disable @intlify/vue-i18n/no-raw-text, vue/no-bare-strings-in-template -->
<WootModal :show="show" :on-close="() => $emit('close')">
<div
class="flex flex-col w-[600px] bg-white dark:bg-slate-900 rounded-lg shadow-xl overflow-hidden"
>
<!-- Header -->
<div
class="px-6 py-4 border-b border-slate-200 dark:border-slate-800 flex justify-between items-center"
>
<h2 class="text-lg font-semibold text-slate-800 dark:text-slate-100">
{{
unit
? $t('CAPTAIN.UNITS.EDIT_TITLE')
: $t('CAPTAIN.UNITS.ADD_TITLE')
}}
</h2>
</div>
<!-- Scrollable Body -->
<div class="flex-1 overflow-y-auto p-6 max-h-[65vh] flex flex-col gap-5">
<WootInput
v-model="name"
:label="$t('CAPTAIN.UNITS.FORM.NAME_LABEL')"
:placeholder="$t('CAPTAIN.UNITS.FORM.NAME_PLACEHOLDER')"
:error="v$.name.$error ? $t('CAPTAIN.UNITS.FORM.NAME_ERROR') : ''"
/>
<div>
<label
class="block mb-1.5 text-sm font-medium text-slate-700 dark:text-slate-200"
>
{{ $t('CAPTAIN.UNITS.FORM.BRAND_LABEL') }}
</label>
<div class="relative">
<select
v-model="captain_brand_id"
class="w-full h-10 px-3 py-2 border rounded-md border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 text-slate-800 dark:text-slate-100 focus:outline-none focus:ring-1 focus:ring-blue-500 appearance-none"
>
<option value="" disabled>
{{ $t('CAPTAIN.UNITS.FORM.BRAND_PLACEHOLDER') }}
</option>
<option v-for="brand in brands" :key="brand.id" :value="brand.id">
{{ brand.name }}
</option>
</select>
<!-- Chevron Icon for Select -->
<div
class="absolute inset-y-0 right-0 flex items-center px-2 pointer-events-none text-slate-500"
>
<i class="i-lucide-chevron-down text-base" />
</div>
</div>
<span
v-if="v$.captain_brand_id.$error"
class="mt-1 text-xs text-red-500"
>
{{ $t('forms.invalid') }}
</span>
</div>
<div>
<label
class="block mb-1.5 text-sm font-medium text-slate-700 dark:text-slate-200"
>
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
Caixa de Entrada (WhatsApp de Notificação)
</label>
<div class="relative">
<select
v-model="inbox_id"
class="w-full h-10 px-3 py-2 border rounded-md border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 text-slate-800 dark:text-slate-100 focus:outline-none focus:ring-1 focus:ring-blue-500 appearance-none"
>
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
<option value="">Selecione um Inbox (Opcional)</option>
<option
v-for="inbox in inboxes"
:key="inbox.id"
:value="inbox.id"
>
<!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
{{ inbox.name }} ({{ inbox.channel_type }})
</option>
</select>
<div
class="absolute inset-y-0 right-0 flex items-center px-2 pointer-events-none text-slate-500"
>
<i class="i-lucide-chevron-down text-base" />
</div>
</div>
</div>
<div class="my-1 h-px bg-slate-100 dark:bg-slate-800" />
<h4
class="text-sm font-semibold text-slate-800 dark:text-slate-100 uppercase tracking-wide"
>
{{ $t('CAPTAIN.UNITS.FORM.PIX_CONFIG_TITLE') }}
</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<WootInput
v-model="inter_client_id"
:label="$t('CAPTAIN.UNITS.FORM.CLIENT_ID')"
placeholder="Client ID"
/>
<WootInput
v-model="inter_client_secret"
:label="$t('CAPTAIN.UNITS.FORM.CLIENT_SECRET')"
placeholder="Client Secret"
/>
<WootInput
v-model="inter_pix_key"
:label="$t('CAPTAIN.UNITS.FORM.PIX_KEY')"
placeholder="Chave Pix"
class="md:col-span-2"
/>
<WootInput
v-model="inter_cert_path"
:label="$t('CAPTAIN.UNITS.FORM.CERT_PATH')"
placeholder="/app/certs/..."
/>
<WootInput
v-model="inter_key_path"
:label="$t('CAPTAIN.UNITS.FORM.KEY_PATH')"
placeholder="/app/certs/..."
/>
<WootInput
v-model="inter_account_number"
:label="$t('CAPTAIN.UNITS.FORM.ACCOUNT_NUMBER')"
placeholder="Opcional"
class="md:col-span-2"
/>
</div>
<div class="my-1 h-px bg-slate-100 dark:bg-slate-800" />
<h4
class="text-sm font-semibold text-slate-800 dark:text-slate-100 uppercase tracking-wide"
>
{{ $t('CAPTAIN.UNITS.FORM.WEBHOOK_TITLE') }}
</h4>
<WootInput
v-model="webhook_url"
:label="$t('CAPTAIN.UNITS.FORM.WEBHOOK_URL')"
placeholder="https://webhook.n8n.cloud/webhook/..."
/>
</div>
<!-- Footer -->
<div
class="px-6 py-4 bg-slate-50 dark:bg-slate-800/50 border-t border-slate-100 dark:border-slate-800 flex justify-end gap-2"
>
<WootButton variant="ghost" @click="$emit('close')">
{{ $t('CAPTAIN.FORM.CANCEL') }}
</WootButton>
<WootButton :disabled="isLoadingBrands" @click="save">
{{ unit ? $t('CAPTAIN.FORM.EDIT') : $t('CAPTAIN.FORM.CREATE') }}
</WootButton>
</div>
</div>
</WootModal>
</template>