mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-27 11:41:09 -04:00
add mail sender in setting
This commit is contained in:
@ -3,80 +3,29 @@
|
||||
namespace Crater\Http\Controllers\V1\Admin\Settings;
|
||||
|
||||
use Crater\Http\Controllers\Controller;
|
||||
use Crater\Http\Requests\MailEnvironmentRequest;
|
||||
use Crater\Http\Requests\TestMailDriverRequest;
|
||||
use Crater\Mail\TestMail;
|
||||
use Crater\Models\Setting;
|
||||
use Crater\Space\EnvironmentManager;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Crater\Models\MailSender;
|
||||
use Illuminate\Http\Request;
|
||||
use Mail;
|
||||
|
||||
class MailConfigurationController extends Controller
|
||||
{
|
||||
/**
|
||||
* @var EnvironmentManager
|
||||
*/
|
||||
protected $environmentManager;
|
||||
|
||||
/**
|
||||
* @param EnvironmentManager $environmentManager
|
||||
*/
|
||||
public function __construct(EnvironmentManager $environmentManager)
|
||||
{
|
||||
$this->environmentManager = $environmentManager;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param MailEnvironmentRequest $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function saveMailEnvironment(MailEnvironmentRequest $request)
|
||||
public function TestMailDriver(TestMailDriverRequest $request)
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$setting = Setting::getSetting('profile_complete');
|
||||
$results = $this->environmentManager->saveMailVariables($request);
|
||||
MailSender::setMailConfiguration($request->mail_sender_id);
|
||||
|
||||
if ($setting !== 'COMPLETED') {
|
||||
Setting::setSetting('profile_complete', 4);
|
||||
}
|
||||
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
|
||||
|
||||
return response()->json($results);
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getMailEnvironment()
|
||||
public function getMailDrivers(Request $request)
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$MailData = [
|
||||
'mail_driver' => config('mail.driver'),
|
||||
'mail_host' => config('mail.host'),
|
||||
'mail_port' => config('mail.port'),
|
||||
'mail_username' => config('mail.username'),
|
||||
'mail_password' => config('mail.password'),
|
||||
'mail_encryption' => config('mail.encryption'),
|
||||
'from_name' => config('mail.from.name'),
|
||||
'from_mail' => config('mail.from.address'),
|
||||
'mail_mailgun_endpoint' => config('services.mailgun.endpoint'),
|
||||
'mail_mailgun_domain' => config('services.mailgun.domain'),
|
||||
'mail_mailgun_secret' => config('services.mailgun.secret'),
|
||||
'mail_ses_key' => config('services.ses.key'),
|
||||
'mail_ses_secret' => config('services.ses.secret'),
|
||||
];
|
||||
|
||||
|
||||
return response()->json($MailData);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getMailDrivers()
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$drivers = [
|
||||
'smtp',
|
||||
'mail',
|
||||
@ -87,21 +36,4 @@ class MailConfigurationController extends Controller
|
||||
|
||||
return response()->json($drivers);
|
||||
}
|
||||
|
||||
public function testEmailConfig(Request $request)
|
||||
{
|
||||
$this->authorize('manage email config');
|
||||
|
||||
$this->validate($request, [
|
||||
'to' => 'required|email',
|
||||
'subject' => 'required',
|
||||
'message' => 'required',
|
||||
]);
|
||||
|
||||
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ class MailSenderRequest extends FormRequest
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
39
app/Http/Requests/TestMailDriverRequest.php
Normal file
39
app/Http/Requests/TestMailDriverRequest.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class TestMailDriverRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'to' => [
|
||||
'required',
|
||||
'email'
|
||||
],
|
||||
'subject' => [
|
||||
'required'
|
||||
],
|
||||
'message' => [
|
||||
'required'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ namespace Crater\Models;
|
||||
use Crater\Http\Requests\MailSenderRequest;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Config;
|
||||
|
||||
class MailSender extends Model
|
||||
{
|
||||
@ -74,4 +75,25 @@ class MailSender extends Model
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function setMailConfiguration($id, $check = null)
|
||||
{
|
||||
$mailSender = MailSender::find($id);
|
||||
|
||||
$settings = $mailSender->settings;
|
||||
$settings['driver'] = $mailSender->driver;
|
||||
$settings['from'] = [
|
||||
'address' => $mailSender->from_address,
|
||||
'name' => $mailSender->from_name
|
||||
];
|
||||
|
||||
Config::set('mail', $settings);
|
||||
|
||||
if ($check) {
|
||||
return $mailSender;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
123
app/Policies/MailSenderPolicy.php
Normal file
123
app/Policies/MailSenderPolicy.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Crater\Policies;
|
||||
|
||||
use Crater\Models\MailSender;
|
||||
use Crater\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Silber\Bouncer\BouncerFacade;
|
||||
|
||||
class MailSenderPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function viewAny(User $user)
|
||||
{
|
||||
if (BouncerFacade::can('view-mail-sender', MailSender::class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @param \Crater\Models\MailSender $mailSender
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function view(User $user, MailSender $mailSender)
|
||||
{
|
||||
if (BouncerFacade::can('view-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function create(User $user)
|
||||
{
|
||||
if (BouncerFacade::can('create-mail-sender', MailSender::class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @param \Crater\Models\MailSender $mailSender
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function update(User $user, MailSender $mailSender)
|
||||
{
|
||||
if (BouncerFacade::can('edit-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @param \Crater\Models\MailSender $mailSender
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function delete(User $user, MailSender $mailSender)
|
||||
{
|
||||
if (BouncerFacade::can('delete-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @param \Crater\Models\MailSender $mailSender
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function restore(User $user, MailSender $mailSender)
|
||||
{
|
||||
if (BouncerFacade::can('delete-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
*
|
||||
* @param \Crater\Models\User $user
|
||||
* @param \Crater\Models\MailSender $mailSender
|
||||
* @return \Illuminate\Auth\Access\Response|bool
|
||||
*/
|
||||
public function forceDelete(User $user, MailSender $mailSender)
|
||||
{
|
||||
if (BouncerFacade::can('delete-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -39,6 +39,7 @@ class AuthServiceProvider extends ServiceProvider
|
||||
\Crater\Models\CustomField::class => \Crater\Policies\CustomFieldPolicy::class,
|
||||
\Crater\Models\User::class => \Crater\Policies\UserPolicy::class,
|
||||
\Crater\Models\Item::class => \Crater\Policies\ItemPolicy::class,
|
||||
\Crater\Models\MailSender::class => \Crater\Policies\MailSenderPolicy::class,
|
||||
\Silber\Bouncer\Database\Role::class => \Crater\Policies\RolePolicy::class,
|
||||
\Crater\Models\Unit::class => \Crater\Policies\UnitPolicy::class,
|
||||
\Crater\Models\RecurringInvoice::class => \Crater\Policies\RecurringInvoicePolicy::class,
|
||||
|
||||
@ -7,6 +7,7 @@ use Crater\Models\ExchangeRateProvider;
|
||||
use Crater\Models\Expense;
|
||||
use Crater\Models\Invoice;
|
||||
use Crater\Models\Item;
|
||||
use Crater\Models\MailSender;
|
||||
use Crater\Models\Note;
|
||||
use Crater\Models\Payment;
|
||||
use Crater\Models\RecurringInvoice;
|
||||
@ -225,6 +226,17 @@ return [
|
||||
'ability' => 'view-all-notes',
|
||||
'model' => Note::class
|
||||
],
|
||||
[
|
||||
'title' => 'settings.menu_title.mail_sender',
|
||||
'group' => '',
|
||||
'name' => 'Mail Sender',
|
||||
'link' => '/admin/settings/mail-sender',
|
||||
'icon' => 'MailIcon',
|
||||
'owner_only' => false,
|
||||
'ability' => 'view-mail-sender',
|
||||
'model' => MailSender::class
|
||||
],
|
||||
|
||||
[
|
||||
'title' => 'settings.menu_title.expense_category',
|
||||
'group' => '',
|
||||
@ -235,16 +247,6 @@ return [
|
||||
'ability' => 'view-expense',
|
||||
'model' => Expense::class
|
||||
],
|
||||
[
|
||||
'title' => 'settings.mail.mail_config',
|
||||
'group' => '',
|
||||
'name' => 'Mail Configuration',
|
||||
'link' => '/admin/settings/mail-configuration',
|
||||
'icon' => 'MailIcon',
|
||||
'owner_only' => true,
|
||||
'ability' => '',
|
||||
'model' => ''
|
||||
],
|
||||
[
|
||||
'title' => 'settings.menu_title.file_disk',
|
||||
'group' => '',
|
||||
@ -275,6 +277,7 @@ return [
|
||||
'ability' => '',
|
||||
'model' => ''
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@ -47,8 +47,6 @@ const ExpenseCategory = () =>
|
||||
import('@/scripts/admin/views/settings/ExpenseCategorySetting.vue')
|
||||
const ExchangeRateSetting = () =>
|
||||
import('@/scripts/admin/views/settings/ExchangeRateProviderSetting.vue')
|
||||
const MailConfig = () =>
|
||||
import('@/scripts/admin/views/settings/MailConfigSetting.vue')
|
||||
const FileDisk = () =>
|
||||
import('@/scripts/admin/views/settings/FileDiskSetting.vue')
|
||||
const Backup = () => import('@/scripts/admin/views/settings/BackupSetting.vue')
|
||||
@ -56,6 +54,8 @@ const UpdateApp = () =>
|
||||
import('@/scripts/admin/views/settings/UpdateAppSetting.vue')
|
||||
const RolesSettings = () =>
|
||||
import('@/scripts/admin/views/settings/RolesSettings.vue')
|
||||
const MailSender = () =>
|
||||
import('@/scripts/admin/views/settings/mail-sender/Index.vue')
|
||||
|
||||
// Items
|
||||
const ItemsIndex = () => import('@/scripts/admin/views/items/Index.vue')
|
||||
@ -302,13 +302,6 @@ export default [
|
||||
meta: { ability: abilities.VIEW_EXPENSE },
|
||||
component: ExpenseCategory,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'mail-configuration',
|
||||
name: 'mailconfig',
|
||||
meta: { isOwner: true },
|
||||
component: MailConfig,
|
||||
},
|
||||
{
|
||||
path: 'file-disk',
|
||||
name: 'file-disk',
|
||||
@ -327,6 +320,13 @@ export default [
|
||||
meta: { isOwner: true },
|
||||
component: UpdateApp,
|
||||
},
|
||||
{
|
||||
path: 'mail-sender',
|
||||
name: 'mailsender',
|
||||
meta: { ability: abilities.VIEW_MAIL_SENDER },
|
||||
component: MailSender,
|
||||
},
|
||||
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<BaseDropdown>
|
||||
<template #activator>
|
||||
<BaseButton v-if="route.name === 'mailsender.view'" variant="primary">
|
||||
<BaseIcon name="DotsHorizontalIcon" class="h-5 text-white" />
|
||||
</BaseButton>
|
||||
<BaseIcon v-else name="DotsHorizontalIcon" class="h-5 text-gray-500" />
|
||||
</template>
|
||||
|
||||
<!-- edit mail-sender -->
|
||||
<BaseDropdownItem @click="editMailSender(row.id)">
|
||||
<BaseIcon
|
||||
name="PencilIcon"
|
||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
||||
/>
|
||||
{{ $t('general.edit') }}
|
||||
</BaseDropdownItem>
|
||||
|
||||
<!-- delete mail-sender -->
|
||||
<BaseDropdownItem @click="removeMailSender(row.id)">
|
||||
<BaseIcon
|
||||
name="TrashIcon"
|
||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
||||
/>
|
||||
{{ $t('general.delete') }}
|
||||
</BaseDropdownItem>
|
||||
|
||||
<!-- send test mail-sender -->
|
||||
<BaseDropdownItem @click="openMailSenderTestModal(row.id)">
|
||||
<BaseIcon
|
||||
name="PaperAirplaneIcon"
|
||||
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
||||
/>
|
||||
{{ $t('general.send_test_mail') }}
|
||||
</BaseDropdownItem>
|
||||
</BaseDropdown>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { inject } from 'vue'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
|
||||
const props = defineProps({
|
||||
row: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
table: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
loadData: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
})
|
||||
|
||||
const pre_t = 'settings.mail_sender'
|
||||
const dialogStore = useDialogStore()
|
||||
const { t } = useI18n()
|
||||
const mailSenderStore = useMailSenderStore()
|
||||
const route = useRoute()
|
||||
const modalStore = useModalStore()
|
||||
|
||||
async function editMailSender(id) {
|
||||
await mailSenderStore.fetchMailSender(id)
|
||||
modalStore.openModal({
|
||||
title: t(`${pre_t}.edit_mail_sender`),
|
||||
componentName: 'MailSenderModal',
|
||||
size: 'md',
|
||||
refreshData: props.loadData && props.loadData,
|
||||
})
|
||||
}
|
||||
|
||||
function removeMailSender(id) {
|
||||
dialogStore
|
||||
.openDialog({
|
||||
title: t('general.are_you_sure'),
|
||||
message: t(`${pre_t}.confirm_delete`),
|
||||
yesLabel: t('general.ok'),
|
||||
noLabel: t('general.cancel'),
|
||||
variant: 'danger',
|
||||
hideNoButton: false,
|
||||
size: 'lg',
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (res) {
|
||||
let response = await mailSenderStore.deleteMailSender(id)
|
||||
if (response.data.success) {
|
||||
props.loadData && props.loadData()
|
||||
return true
|
||||
}
|
||||
props.loadData && props.loadData()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function openMailSenderTestModal(id) {
|
||||
modalStore.openModal({
|
||||
title: t(`general.send_test_mail`),
|
||||
componentName: 'MailSenderTestModal',
|
||||
size: 'md',
|
||||
id: id,
|
||||
refreshData: props.loadData && props.loadData,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,290 @@
|
||||
<template>
|
||||
<BaseModal
|
||||
:show="modalStore.active && modalStore.componentName === 'MailSenderModal'"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex justify-between w-full">
|
||||
{{ modalStore.title }}
|
||||
<BaseIcon
|
||||
name="XIcon"
|
||||
class="h-6 w-6 text-gray-500 cursor-pointer"
|
||||
@click="closeMailSenderModal"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<form action="" @submit.prevent="submitMailSenderData">
|
||||
<div class="p-4 sm:p-6 my-2">
|
||||
<!-- Name -->
|
||||
<BaseInputGrid>
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.name`)"
|
||||
:error="v$.name.$error && v$.name.$errors[0].$message"
|
||||
:help-text="$t(`${pre_t}.name_help`)"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model.trim="mailSenderStore.currentMailSender.name"
|
||||
:invalid="v$.name.$error"
|
||||
type="text"
|
||||
@input="v$.name.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- From Name -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.from_name`)"
|
||||
:error="v$.from_name.$error && v$.from_name.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model="mailSenderStore.currentMailSender.from_name"
|
||||
:invalid="v$.from_name.$error"
|
||||
type="text"
|
||||
@input="v$.from_name.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- From Address -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.from_address`)"
|
||||
:error="
|
||||
v$.from_address.$error && v$.from_address.$errors[0].$message
|
||||
"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model="mailSenderStore.currentMailSender.from_address"
|
||||
:invalid="v$.from_address.$error"
|
||||
type="text"
|
||||
@input="v$.from_address.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- CC -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.cc`)"
|
||||
:error="v$.cc.$error && v$.cc.$errors[0].$message"
|
||||
:help-text="$t(`${pre_t}.email_list`)"
|
||||
>
|
||||
<BaseInput
|
||||
v-model="mailSenderStore.currentMailSender.cc"
|
||||
:invalid="v$.cc.$error"
|
||||
type="text"
|
||||
@input="v$.cc.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- BCC -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.bcc`)"
|
||||
:error="v$.bcc.$error && v$.bcc.$errors[0].$message"
|
||||
:help-text="$t(`${pre_t}.email_list`)"
|
||||
>
|
||||
<BaseInput
|
||||
v-model="mailSenderStore.currentMailSender.bcc"
|
||||
:invalid="v$.bcc.$error"
|
||||
type="text"
|
||||
@input="v$.bcc.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Mail Driver -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.driver`)"
|
||||
:error="v$.driver.$error && v$.driver.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseMultiselect
|
||||
v-model="mailSenderStore.currentMailSender.driver"
|
||||
:options="mailSenderStore.mail_drivers"
|
||||
:can-deselect="false"
|
||||
:invalid="v$.driver.$error"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<component
|
||||
:is="loadMailDriver"
|
||||
:mail-sender-store="mailSenderStore"
|
||||
/>
|
||||
</BaseInputGrid>
|
||||
|
||||
<BaseDivider class="mt-4 mb-0" />
|
||||
|
||||
<!-- Is Default? -->
|
||||
<BaseSwitchSection
|
||||
v-model="mailSenderStore.currentMailSender.is_default"
|
||||
:title="$t(`${pre_t}.is_default`)"
|
||||
:description="$t(`${pre_t}.is_default_description`)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="z-0 flex justify-end p-4 border-t border-solid border--200 border-modal-bg"
|
||||
>
|
||||
<BaseButton
|
||||
class="mr-3 text-sm"
|
||||
variant="primary-outline"
|
||||
type="button"
|
||||
@click="closeMailSenderModal"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</BaseButton>
|
||||
<BaseButton
|
||||
:loading="isSaving"
|
||||
:disabled="isSaving"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
>
|
||||
<template #left="slotProps">
|
||||
<BaseIcon
|
||||
v-if="!isSaving"
|
||||
name="SaveIcon"
|
||||
:class="slotProps.class"
|
||||
/>
|
||||
</template>
|
||||
{{
|
||||
mailSenderStore.isEdit ? $t('general.update') : $t('general.save')
|
||||
}}
|
||||
</BaseButton>
|
||||
</div>
|
||||
</form>
|
||||
</BaseModal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { required, email, minLength, helpers } from '@vuelidate/validators'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||
import SmtpDriver from '@/scripts/admin/views/settings/mail-sender/SmtpDriver.vue'
|
||||
import MailgunDriver from '@/scripts/admin/views/settings/mail-sender/MailgunDriver.vue'
|
||||
import SesDriver from '@/scripts/admin/views/settings/mail-sender/SesDriver.vue'
|
||||
|
||||
const pre_t = 'settings.mail_sender'
|
||||
const modalStore = useModalStore()
|
||||
const mailSenderStore = useMailSenderStore()
|
||||
const { t } = useI18n()
|
||||
let isSaving = ref(false)
|
||||
const loadMailDriver = computed(() => {
|
||||
switch (mailSenderStore.currentMailSender.driver) {
|
||||
case 'smtp':
|
||||
return SmtpDriver
|
||||
break
|
||||
case 'mail':
|
||||
return false
|
||||
break
|
||||
case 'sendmail':
|
||||
return false
|
||||
break
|
||||
case 'mailgun':
|
||||
return MailgunDriver
|
||||
break
|
||||
case 'ses':
|
||||
return SesDriver
|
||||
break
|
||||
default:
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
// This is multiple email custom validation
|
||||
const multiEmail = (value) => {
|
||||
if (value == '' || value === null) return true
|
||||
const emailRegex =
|
||||
/^(?:[A-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]{2,}(?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i
|
||||
|
||||
const emailArr = value.split(',')
|
||||
let isValid = emailArr.every((v) => {
|
||||
return emailRegex.test(v)
|
||||
})
|
||||
return isValid
|
||||
}
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
name: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
minLength: helpers.withMessage(
|
||||
t('validation.name_min_length', { count: 3 }),
|
||||
minLength(3)
|
||||
),
|
||||
},
|
||||
from_name: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
from_address: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
email: helpers.withMessage(t('validation.email_incorrect'), email),
|
||||
},
|
||||
cc: {
|
||||
multiEmail: helpers.withMessage(
|
||||
t('validation.email_incorrect'),
|
||||
multiEmail
|
||||
),
|
||||
},
|
||||
bcc: {
|
||||
multiEmail: helpers.withMessage(
|
||||
t('validation.email_incorrect'),
|
||||
multiEmail
|
||||
),
|
||||
},
|
||||
driver: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const v$ = useVuelidate(
|
||||
rules,
|
||||
computed(() => mailSenderStore.currentMailSender)
|
||||
)
|
||||
|
||||
async function submitMailSenderData() {
|
||||
v$.value.$touch()
|
||||
if (v$.value.$invalid) {
|
||||
return true
|
||||
}
|
||||
try {
|
||||
const action = mailSenderStore.isEdit
|
||||
? mailSenderStore.updateMailSender
|
||||
: mailSenderStore.addMailSender
|
||||
isSaving.value = true
|
||||
|
||||
var mailDriverConfig = null
|
||||
switch (mailSenderStore.currentMailSender.driver) {
|
||||
case 'smtp':
|
||||
mailDriverConfig = mailSenderStore.smtpConfig
|
||||
break
|
||||
case 'mailgun':
|
||||
mailDriverConfig = mailSenderStore.mailgunConfig
|
||||
break
|
||||
case 'ses':
|
||||
mailDriverConfig = mailSenderStore.sesConfig
|
||||
break
|
||||
}
|
||||
mailSenderStore.currentMailSender.settings = mailDriverConfig
|
||||
|
||||
let res = await action(mailSenderStore.currentMailSender)
|
||||
isSaving.value = false
|
||||
modalStore.refreshData ? modalStore.refreshData(res.data.data) : ''
|
||||
closeMailSenderModal()
|
||||
} catch (err) {
|
||||
isSaving.value = false
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
function closeMailSenderModal() {
|
||||
modalStore.closeModal()
|
||||
setTimeout(() => {
|
||||
mailSenderStore.resetCurrentMailSender()
|
||||
v$.value.$reset()
|
||||
}, 300)
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await mailSenderStore.fetchMailDrivers()
|
||||
})
|
||||
</script>
|
||||
@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<BaseModal :show="modalActive" @open="setInitialData">
|
||||
<template #header>
|
||||
<div class="flex justify-between w-full">
|
||||
{{ modalStore.title }}
|
||||
<BaseIcon
|
||||
name="XIcon"
|
||||
class="w-6 h-6 text-gray-500 cursor-pointer"
|
||||
@click="closeTestModal"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<form action="" @submit.prevent="onTestMailSend">
|
||||
<div class="p-4 md:p-8">
|
||||
<BaseInputGrid layout="one-column">
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.title`)"
|
||||
variant="horizontal"
|
||||
:content-loading="isFetchingInitialData"
|
||||
:error="
|
||||
v$.mail_sender_id.$error && v$.mail_sender_id.$errors[0].$message
|
||||
"
|
||||
>
|
||||
<BaseMultiselect
|
||||
v-model="formData.mail_sender_id"
|
||||
:invalid="v$.mail_sender_id.$error"
|
||||
label="name"
|
||||
:options="mailSenderStore.mailSenders"
|
||||
value-prop="id"
|
||||
:can-deselect="false"
|
||||
:can-clear="false"
|
||||
:placeholder="$t(`${pre_t}.select_mail_sender`)"
|
||||
searchable
|
||||
track-by="name"
|
||||
:content-loading="isFetchingInitialData"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<BaseInputGroup
|
||||
:label="$t('general.to')"
|
||||
:error="v$.to.$error && v$.to.$errors[0].$message"
|
||||
variant="horizontal"
|
||||
required
|
||||
:content-loading="isFetchingInitialData"
|
||||
>
|
||||
<BaseInput
|
||||
v-model="formData.to"
|
||||
type="text"
|
||||
:invalid="v$.to.$error"
|
||||
:content-loading="isFetchingInitialData"
|
||||
@input="v$.to.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
<BaseInputGroup
|
||||
:label="$t('general.subject')"
|
||||
:error="v$.subject.$error && v$.subject.$errors[0].$message"
|
||||
variant="horizontal"
|
||||
required
|
||||
:content-loading="isFetchingInitialData"
|
||||
>
|
||||
<BaseInput
|
||||
v-model="formData.subject"
|
||||
type="text"
|
||||
:invalid="v$.subject.$error"
|
||||
:content-loading="isFetchingInitialData"
|
||||
@input="v$.subject.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
<BaseInputGroup
|
||||
:label="$t('general.message')"
|
||||
:error="v$.message.$error && v$.message.$errors[0].$message"
|
||||
variant="horizontal"
|
||||
required
|
||||
:content-loading="isFetchingInitialData"
|
||||
>
|
||||
<BaseTextarea
|
||||
v-model="formData.message"
|
||||
rows="4"
|
||||
cols="50"
|
||||
:invalid="v$.message.$error"
|
||||
:content-loading="isFetchingInitialData"
|
||||
@input="v$.message.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
</BaseInputGrid>
|
||||
</div>
|
||||
<div
|
||||
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
||||
>
|
||||
<BaseButton
|
||||
variant="primary-outline"
|
||||
type="button"
|
||||
class="mr-3"
|
||||
:content-loading="isFetchingInitialData"
|
||||
@click="closeTestModal()"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</BaseButton>
|
||||
|
||||
<BaseButton
|
||||
:loading="isSaving"
|
||||
variant="primary"
|
||||
type="submit"
|
||||
:content-loading="isFetchingInitialData"
|
||||
>
|
||||
<template #left="slotProps">
|
||||
<BaseIcon
|
||||
v-if="!isSaving"
|
||||
name="PaperAirplaneIcon"
|
||||
:class="slotProps.class"
|
||||
/>
|
||||
</template>
|
||||
{{ $t('general.send') }}
|
||||
</BaseButton>
|
||||
</div>
|
||||
</form>
|
||||
</BaseModal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { required, email, maxLength, helpers } from '@vuelidate/validators'
|
||||
import useVuelidate from '@vuelidate/core'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||
|
||||
const pre_t = 'settings.mail_sender'
|
||||
const modalStore = useModalStore()
|
||||
const mailSenderStore = useMailSenderStore()
|
||||
const { t } = useI18n()
|
||||
let isSaving = ref(false)
|
||||
let formData = reactive({
|
||||
mail_sender_id: '',
|
||||
to: '',
|
||||
subject: '',
|
||||
message: '',
|
||||
})
|
||||
const isFetchingInitialData = ref(false)
|
||||
|
||||
const modalActive = computed(() => {
|
||||
return modalStore.active && modalStore.componentName === 'MailSenderTestModal'
|
||||
})
|
||||
|
||||
function setInitialData() {
|
||||
isFetchingInitialData.value = true
|
||||
formData.mail_sender_id = modalStore.id
|
||||
setTimeout(() => {
|
||||
isFetchingInitialData.value = false
|
||||
}, 100)
|
||||
}
|
||||
|
||||
const rules = {
|
||||
mail_sender_id: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
to: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
email: helpers.withMessage(t('validation.email_incorrect'), email),
|
||||
},
|
||||
subject: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
maxLength: helpers.withMessage(
|
||||
t('validation.subject_maxlength'),
|
||||
maxLength(100)
|
||||
),
|
||||
},
|
||||
message: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
maxLength: helpers.withMessage(
|
||||
t('validation.message_maxlength'),
|
||||
maxLength(255)
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
const v$ = useVuelidate(rules, formData)
|
||||
|
||||
function resetFormData() {
|
||||
formData.mail_sender_id = ''
|
||||
formData.to = ''
|
||||
formData.subject = ''
|
||||
formData.message = ''
|
||||
|
||||
v$.value.$reset()
|
||||
}
|
||||
|
||||
async function onTestMailSend() {
|
||||
v$.value.$touch()
|
||||
if (v$.value.$invalid) {
|
||||
return true
|
||||
}
|
||||
|
||||
isSaving.value = true
|
||||
let response = await mailSenderStore.sendTestMail(formData)
|
||||
if (response.data) {
|
||||
closeTestModal()
|
||||
}
|
||||
}
|
||||
function closeTestModal() {
|
||||
modalStore.closeModal()
|
||||
setTimeout(() => {
|
||||
isSaving.value = false
|
||||
modalStore.resetModalData()
|
||||
resetFormData()
|
||||
}, 300)
|
||||
}
|
||||
</script>
|
||||
209
resources/scripts/admin/stores/mail-sender.js
Normal file
209
resources/scripts/admin/stores/mail-sender.js
Normal file
@ -0,0 +1,209 @@
|
||||
import axios from 'axios'
|
||||
import { defineStore } from 'pinia'
|
||||
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||
import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import mailSenderStub from '@/scripts/admin/stub/mail-sender.js'
|
||||
|
||||
export const useMailSenderStore = (useWindow = false) => {
|
||||
const pre_t = 'settings.mail_sender'
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
const { global } = window.i18n
|
||||
|
||||
return defineStoreFunc({
|
||||
id: 'mailSender',
|
||||
|
||||
state: () => ({
|
||||
mailSenders: [],
|
||||
mail_drivers: [], // list of mail drivers
|
||||
currentMailSender: { ...mailSenderStub.basicConfig },
|
||||
smtpConfig: { ...mailSenderStub.smtpConfig },
|
||||
mailgunConfig: { ...mailSenderStub.mailgunConfig },
|
||||
sesConfig: { ...mailSenderStub.sesConfig },
|
||||
mail_encryptions: ['none', 'tls', 'ssl', 'starttls'],
|
||||
}),
|
||||
|
||||
getters: {
|
||||
isEdit: (state) => (state.currentMailSender.id ? true : false),
|
||||
},
|
||||
|
||||
actions: {
|
||||
resetCurrentMailSender() {
|
||||
this.currentMailSender = { ...mailSenderStub.basicConfig }
|
||||
this.smtpConfig = { ...mailSenderStub.smtpConfig }
|
||||
this.mailgunConfig = { ...mailSenderStub.mailgunConfig }
|
||||
this.sesConfig = { ...mailSenderStub.sesConfig }
|
||||
},
|
||||
|
||||
fetchMailDrivers() {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.get('/api/v1/mail-drivers')
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
this.mail_drivers = response.data
|
||||
}
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
fetchMailSenderList(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.get(`/api/v1/mail-senders`, { params })
|
||||
.then((response) => {
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
fetchMailSenders(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.get(`/api/v1/mail-sender`, { params })
|
||||
.then((response) => {
|
||||
this.mailSenders = response.data.data
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
fetchMailSender(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.get(`/api/v1/mail-sender/${id}`)
|
||||
.then((response) => {
|
||||
this.currentMailSender = response.data.data
|
||||
if (response.data.data.settings) {
|
||||
var settings = response.data.data.settings
|
||||
switch (response.data.data.driver) {
|
||||
case 'smtp':
|
||||
this.smtpConfig = settings
|
||||
break
|
||||
case 'mailgun':
|
||||
this.mailgunConfig = settings
|
||||
break
|
||||
case 'ses':
|
||||
this.sesConfig = settings
|
||||
break
|
||||
}
|
||||
}
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
addMailSender(data) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post('/api/v1/mail-sender', data)
|
||||
.then((response) => {
|
||||
this.mailSenders.push(response.data.data)
|
||||
notificationStore.showNotification({
|
||||
type: 'success',
|
||||
message: global.t(`${pre_t}.created_message`),
|
||||
})
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
updateMailSender(data) {
|
||||
const notificationStore = useNotificationStore()
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.put(`/api/v1/mail-sender/${data.id}`, data)
|
||||
.then((response) => {
|
||||
if (response.data) {
|
||||
let pos = this.mailSenders.findIndex(
|
||||
(mailSender) => mailSender.id === response.data.data.id
|
||||
)
|
||||
this.mailSenders[pos] = data
|
||||
notificationStore.showNotification({
|
||||
type: 'success',
|
||||
message: global.t(`${pre_t}.updated_message`),
|
||||
})
|
||||
}
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
deleteMailSender(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.delete(`/api/v1/mail-sender/${id}`)
|
||||
.then((response) => {
|
||||
if (response.data.success) {
|
||||
let index = this.mailSenders.findIndex(
|
||||
(mailSender) => mailSender.id === id
|
||||
)
|
||||
this.mailSenders.splice(index, 1)
|
||||
const notificationStore = useNotificationStore()
|
||||
notificationStore.showNotification({
|
||||
type: 'success',
|
||||
message: global.t(`${pre_t}.deleted_message`),
|
||||
})
|
||||
}
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
sendTestMail(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post('/api/v1/mail-test', data)
|
||||
.then((response) => {
|
||||
const notificationStore = useNotificationStore()
|
||||
if (response.data.success) {
|
||||
notificationStore.showNotification({
|
||||
type: 'success',
|
||||
message: global.t('general.send_mail_successfully'),
|
||||
})
|
||||
} else {
|
||||
notificationStore.showNotification({
|
||||
type: 'error',
|
||||
message: global.t('validation.something_went_wrong'),
|
||||
})
|
||||
}
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
})()
|
||||
}
|
||||
@ -25,6 +25,7 @@ export const useUsersStore = (useWindow = false) => {
|
||||
password: null,
|
||||
phone: null,
|
||||
companies: [],
|
||||
sender_id: null,
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
@ -15,5 +15,6 @@ export default function () {
|
||||
customFields: [],
|
||||
fields: [],
|
||||
enable_portal: false,
|
||||
mail_sender_id: null,
|
||||
}
|
||||
}
|
||||
|
||||
31
resources/scripts/admin/stub/mail-sender.js
Normal file
31
resources/scripts/admin/stub/mail-sender.js
Normal file
@ -0,0 +1,31 @@
|
||||
export default {
|
||||
basicConfig: {
|
||||
name: '',
|
||||
from_name: '',
|
||||
from_address: '',
|
||||
cc: '',
|
||||
bcc: '',
|
||||
is_default: false,
|
||||
driver: 'smtp', // 'smtp', 'mail', 'sendmail', 'mailgun', 'ses'
|
||||
settings: '',
|
||||
},
|
||||
smtpConfig: {
|
||||
host: '',
|
||||
port: null,
|
||||
username: '',
|
||||
password: '',
|
||||
encryption: 'tls', // 'tls', 'ssl', 'starttls'
|
||||
},
|
||||
mailgunConfig: {
|
||||
domain: '',
|
||||
secret: '',
|
||||
endpoint: '',
|
||||
},
|
||||
sesConfig: {
|
||||
host: '',
|
||||
port: null,
|
||||
encryption: 'tls', // 'tls', 'ssl', 'starttls'
|
||||
ses_key: '',
|
||||
ses_secret: '',
|
||||
},
|
||||
}
|
||||
@ -256,6 +256,31 @@
|
||||
/> </template
|
||||
></BaseInput>
|
||||
</BaseInputGroup>
|
||||
<!-- && setPasswordMethod !== 'manual' -->
|
||||
<BaseInputGroup
|
||||
v-show="customerStore.currentCustomer.enable_portal"
|
||||
:label="$t('customers.select_sender')"
|
||||
class="pt-5"
|
||||
:error="
|
||||
v$.currentCustomer.mail_sender_id.$error &&
|
||||
v$.currentCustomer.mail_sender_id.$errors[0].$message
|
||||
"
|
||||
:content-loading="isFetchingInitialData"
|
||||
required
|
||||
>
|
||||
<BaseMultiselect
|
||||
v-model="customerStore.currentCustomer.mail_sender_id"
|
||||
label="name"
|
||||
value-prop="id"
|
||||
:options="mailSenderStore.mailSenders"
|
||||
:can-deselect="false"
|
||||
:can-clear="false"
|
||||
searchable
|
||||
track-by="name"
|
||||
:invalid="v$.currentCustomer.mail_sender_id.$error"
|
||||
@input="v$.currentCustomer.mail_sender_id.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
</BaseInputGrid>
|
||||
</div>
|
||||
|
||||
@ -601,11 +626,13 @@ import CustomerCustomFields from '@/scripts/admin/components/custom-fields/Creat
|
||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||
import CopyInputField from '@/scripts/admin/components/CopyInputField.vue'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||
|
||||
const customerStore = useCustomerStore()
|
||||
const customFieldStore = useCustomFieldStore()
|
||||
const globalStore = useGlobalStore()
|
||||
const companyStore = useCompanyStore()
|
||||
const mailSenderStore = useMailSenderStore()
|
||||
|
||||
const customFieldValidationScope = 'customFields'
|
||||
|
||||
@ -617,6 +644,7 @@ const route = useRoute()
|
||||
let isFetchingInitialData = ref(false)
|
||||
let isShowPassword = ref(false)
|
||||
let isShowConfirmPassword = ref(false)
|
||||
const mailSenders = ref(null)
|
||||
|
||||
let active = ref(false)
|
||||
const isSaving = ref(false)
|
||||
@ -679,6 +707,9 @@ const rules = computed(() => {
|
||||
website: {
|
||||
url: helpers.withMessage(t('validation.invalid_url'), url),
|
||||
},
|
||||
mail_sender_id: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
billing: {
|
||||
address_street_1: {
|
||||
maxLength: helpers.withMessage(
|
||||
@ -722,6 +753,20 @@ const v$ = useVuelidate(rules, customerStore, {
|
||||
$scope: customFieldValidationScope,
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
await mailSenderStore.fetchMailSenders()
|
||||
let mailSenderData = await mailSenderStore.fetchMailSenderList()
|
||||
if (mailSenderData.data) {
|
||||
mailSenders.value = mailSenderData.data.data
|
||||
let defaultMailSender = mailSenderData.data.data.find(
|
||||
(mailSender) => mailSender.is_default == true
|
||||
)
|
||||
customerStore.currentCustomer.mail_sender_id = defaultMailSender
|
||||
? defaultMailSender.id
|
||||
: null
|
||||
}
|
||||
})
|
||||
|
||||
customerStore.resetCurrentCustomer()
|
||||
|
||||
customerStore.fetchCustomerInitialSettings(isEdit.value)
|
||||
|
||||
136
resources/scripts/admin/views/settings/mail-sender/Index.vue
Normal file
136
resources/scripts/admin/views/settings/mail-sender/Index.vue
Normal file
@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<BaseSettingCard
|
||||
:title="$tc(`${pre_t}.title`, 2)"
|
||||
:description="$t(`${pre_t}.description`)"
|
||||
>
|
||||
<MailSenderModal />
|
||||
<MailSenderTestModal />
|
||||
|
||||
<template #action>
|
||||
<BaseButton
|
||||
type="submit"
|
||||
variant="primary-outline"
|
||||
@click="openMailSenderModal"
|
||||
>
|
||||
<template #left="slotProps">
|
||||
<BaseIcon :class="slotProps.class" name="PlusIcon" />
|
||||
</template>
|
||||
{{ $t(`${pre_t}.add_new_mail_sender`) }}
|
||||
</BaseButton>
|
||||
</template>
|
||||
|
||||
<BaseTable
|
||||
ref="table"
|
||||
class="mt-16"
|
||||
:data="fetchData"
|
||||
:columns="mailSenderColumns"
|
||||
>
|
||||
<template #cell-is_default="{ row }">
|
||||
<BaseBadge
|
||||
:bg-color="
|
||||
utils.getBadgeStatusColor(row.data.is_default ? 'YES' : 'NO')
|
||||
.bgColor
|
||||
"
|
||||
:color="
|
||||
utils.getBadgeStatusColor(row.data.is_default ? 'YES' : 'NO').color
|
||||
"
|
||||
>
|
||||
{{ row.data.is_default ? $t('general.yes') : $t('general.no') }}
|
||||
</BaseBadge>
|
||||
</template>
|
||||
|
||||
<template #cell-actions="{ row }">
|
||||
<MailSenderDropdown
|
||||
:row="row.data"
|
||||
:table="table"
|
||||
:load-data="refreshTable"
|
||||
/>
|
||||
</template>
|
||||
</BaseTable>
|
||||
</BaseSettingCard>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, inject } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import MailSenderModal from '@/scripts/admin/components/modal-components/MailSenderModal.vue'
|
||||
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||
import MailSenderDropdown from '@/scripts/admin/components/dropdowns/MailSenderIndexDropdown.vue'
|
||||
import MailSenderTestModal from '@/scripts/admin/components/modal-components/MailSenderTestModal.vue'
|
||||
|
||||
const pre_t = 'settings.mail_sender'
|
||||
const modalStore = useModalStore()
|
||||
const mailSenderStore = useMailSenderStore()
|
||||
const { t } = useI18n()
|
||||
const table = ref(null)
|
||||
const utils = inject('utils')
|
||||
|
||||
function openMailSenderModal() {
|
||||
modalStore.openModal({
|
||||
title: t(`${pre_t}.add_new_mail_sender`),
|
||||
componentName: 'MailSenderModal',
|
||||
size: 'md',
|
||||
refreshData: refreshTable,
|
||||
})
|
||||
}
|
||||
|
||||
const mailSenderColumns = computed(() => {
|
||||
return [
|
||||
{
|
||||
key: 'name',
|
||||
label: t(`${pre_t}.name`),
|
||||
thClass: 'extra',
|
||||
tdClass: 'font-medium text-gray-900',
|
||||
},
|
||||
{
|
||||
key: 'driver',
|
||||
label: t(`${pre_t}.driver`),
|
||||
thClass: 'extra',
|
||||
tdClass: 'font-medium text-gray-900',
|
||||
},
|
||||
{
|
||||
key: 'from_address',
|
||||
label: t(`${pre_t}.from_address`),
|
||||
thClass: 'extra',
|
||||
tdClass: 'font-medium text-gray-900',
|
||||
},
|
||||
{
|
||||
key: 'is_default',
|
||||
label: t(`${pre_t}.is_default`),
|
||||
thClass: 'extra',
|
||||
tdClass: 'font-medium text-gray-900',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: '',
|
||||
tdClass: 'text-right text-sm font-medium',
|
||||
sortable: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
async function fetchData({ page, filter, sort }) {
|
||||
let data = {
|
||||
orderByField: sort.fieldName || 'created_at',
|
||||
orderBy: sort.order || 'desc',
|
||||
page,
|
||||
}
|
||||
|
||||
let response = await mailSenderStore.fetchMailSenders(data)
|
||||
|
||||
return {
|
||||
data: response.data.data,
|
||||
pagination: {
|
||||
totalPages: response.data.meta.last_page,
|
||||
currentPage: page,
|
||||
totalCount: response.data.meta.total,
|
||||
limit: response.data.meta.per_page ? response.data.meta.per_page : 10,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshTable() {
|
||||
table.value && table.value.refresh()
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<!-- Domain -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.domain`)"
|
||||
:error="v$.domain.$error && v$.domain.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model.trim="mailSenderStore.mailgunConfig.domain"
|
||||
:invalid="v$.domain.$error"
|
||||
type="text"
|
||||
@input="v$.domain.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Mailgun Secret -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.secret`)"
|
||||
:error="v$.secret.$error && v$.secret.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model="mailSenderStore.mailgunConfig.secret"
|
||||
:type="getInputType"
|
||||
autocomplete="off"
|
||||
:invalid="v$.secret.$error"
|
||||
@input="v$.secret.$touch()"
|
||||
>
|
||||
<template #right>
|
||||
<BaseIcon
|
||||
v-if="isShowPassword"
|
||||
class="mr-1 text-gray-500 cursor-pointer"
|
||||
name="EyeOffIcon"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class="mr-1 text-gray-500 cursor-pointer"
|
||||
name="EyeIcon"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
</template>
|
||||
</BaseInput>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Mailgun Endpoint -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.endpoint`)"
|
||||
:error="v$.endpoint.$error && v$.endpoint.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model.trim="mailSenderStore.mailgunConfig.endpoint"
|
||||
type="text"
|
||||
:invalid="v$.endpoint.$error"
|
||||
@input="v$.endpoint.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from "vue"
|
||||
import { useI18n } from "vue-i18n"
|
||||
import { required, email, numeric, helpers } from "@vuelidate/validators"
|
||||
import { useVuelidate } from "@vuelidate/core"
|
||||
|
||||
const pre_t = "settings.mail_sender.mailgun_config"
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps({
|
||||
mailSenderStore: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
})
|
||||
|
||||
let isShowPassword = ref(false)
|
||||
const getInputType = computed(() => {
|
||||
if (isShowPassword.value) {
|
||||
return "text"
|
||||
}
|
||||
return "password"
|
||||
})
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
domain: {
|
||||
required: helpers.withMessage(t("validation.required"), required),
|
||||
},
|
||||
endpoint: {
|
||||
required: helpers.withMessage(t("validation.required"), required),
|
||||
},
|
||||
secret: {
|
||||
required: helpers.withMessage(t("validation.required"), required),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const v$ = useVuelidate(
|
||||
rules,
|
||||
computed(() => props.mailSenderStore.mailgunConfig)
|
||||
)
|
||||
</script>
|
||||
143
resources/scripts/admin/views/settings/mail-sender/SesDriver.vue
Normal file
143
resources/scripts/admin/views/settings/mail-sender/SesDriver.vue
Normal file
@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<!-- Host -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.host`)"
|
||||
:error="v$.host.$error && v$.host.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model.trim="mailSenderStore.sesConfig.host"
|
||||
:invalid="v$.host.$error"
|
||||
type="text"
|
||||
@input="v$.host.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Port -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.port`)"
|
||||
:error="v$.port.$error && v$.port.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model.trim="mailSenderStore.sesConfig.port"
|
||||
type="text"
|
||||
:invalid="v$.port.$error"
|
||||
@input="v$.port.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Encryption -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.encryption`)"
|
||||
:error="v$.encryption.$error && v$.encryption.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseMultiselect
|
||||
v-model.trim="mailSenderStore.sesConfig.encryption"
|
||||
:options="encryptions"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('general.select_option')"
|
||||
:invalid="v$.encryption.$error"
|
||||
@input="v$.encryption.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- SES Key -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.ses_key`)"
|
||||
:error="v$.ses_key.$error && v$.ses_key.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model.trim="mailSenderStore.sesConfig.ses_key"
|
||||
type="text"
|
||||
:invalid="v$.ses_key.$error"
|
||||
@input="v$.ses_key.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- SES Secret -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.ses_secret`)"
|
||||
:error="v$.ses_secret.$error && v$.ses_secret.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model="mailSenderStore.sesConfig.ses_secret"
|
||||
:type="getInputType"
|
||||
autocomplete="off"
|
||||
:invalid="v$.ses_secret.$error"
|
||||
@input="v$.ses_secret.$touch()"
|
||||
>
|
||||
<template #right>
|
||||
<BaseIcon
|
||||
v-if="isShowPassword"
|
||||
class="mr-1 text-gray-500 cursor-pointer"
|
||||
name="EyeOffIcon"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class="mr-1 text-gray-500 cursor-pointer"
|
||||
name="EyeIcon"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
</template>
|
||||
</BaseInput>
|
||||
</BaseInputGroup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, reactive } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { required, email, numeric, helpers } from '@vuelidate/validators'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
|
||||
const pre_t = 'settings.mail_sender.ses_config'
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps({
|
||||
mailSenderStore: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
})
|
||||
|
||||
let isShowPassword = ref(false)
|
||||
const getInputType = computed(() => {
|
||||
if (isShowPassword.value) {
|
||||
return 'text'
|
||||
}
|
||||
return 'password'
|
||||
})
|
||||
const encryptions = props.mailSenderStore.mail_encryptions
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
host: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
port: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
numeric,
|
||||
},
|
||||
encryption: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
ses_key: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
ses_secret: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const v$ = useVuelidate(
|
||||
rules,
|
||||
computed(() => props.mailSenderStore.sesConfig)
|
||||
)
|
||||
</script>
|
||||
@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<!-- Host -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.host`)"
|
||||
:error="v$.host.$error && v$.host.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model.trim="mailSenderStore.smtpConfig.host"
|
||||
:invalid="v$.host.$error"
|
||||
type="text"
|
||||
@input="v$.host.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Port -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.port`)"
|
||||
:error="v$.port.$error && v$.port.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseInput
|
||||
v-model.trim="mailSenderStore.smtpConfig.port"
|
||||
type="text"
|
||||
:invalid="v$.port.$error"
|
||||
@input="v$.port.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Username -->
|
||||
<BaseInputGroup :label="$t(`${pre_t}.username`)">
|
||||
<BaseInput v-model.trim="mailSenderStore.smtpConfig.username" type="text" />
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Password -->
|
||||
<BaseInputGroup :label="$t(`${pre_t}.password`)">
|
||||
<BaseInput
|
||||
v-model="mailSenderStore.smtpConfig.password"
|
||||
:type="getInputType"
|
||||
>
|
||||
<template #right>
|
||||
<BaseIcon
|
||||
v-if="isShowPassword"
|
||||
class="mr-1 text-gray-500 cursor-pointer"
|
||||
name="EyeOffIcon"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class="mr-1 text-gray-500 cursor-pointer"
|
||||
name="EyeIcon"
|
||||
@click="isShowPassword = !isShowPassword"
|
||||
/>
|
||||
</template>
|
||||
</BaseInput>
|
||||
</BaseInputGroup>
|
||||
|
||||
<!-- Encryption -->
|
||||
<BaseInputGroup
|
||||
:label="$t(`${pre_t}.encryption`)"
|
||||
:error="v$.encryption.$error && v$.encryption.$errors[0].$message"
|
||||
required
|
||||
>
|
||||
<BaseMultiselect
|
||||
v-model.trim="mailSenderStore.smtpConfig.encryption"
|
||||
:options="encryptions"
|
||||
:searchable="true"
|
||||
:show-labels="false"
|
||||
:placeholder="$t('general.select_option')"
|
||||
:invalid="v$.encryption.$error"
|
||||
@input="v$.encryption.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, reactive } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { required, numeric, helpers } from '@vuelidate/validators'
|
||||
import { useVuelidate } from '@vuelidate/core'
|
||||
|
||||
const pre_t = 'settings.mail_sender.smtp_config'
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps({
|
||||
mailSenderStore: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: Object,
|
||||
},
|
||||
})
|
||||
let isShowPassword = ref(false)
|
||||
const getInputType = computed(() => {
|
||||
if (isShowPassword.value) {
|
||||
return 'text'
|
||||
}
|
||||
return 'password'
|
||||
})
|
||||
const encryptions = props.mailSenderStore.mail_encryptions
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
host: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
port: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
numeric: helpers.withMessage(t('validation.numbers_only'), numeric),
|
||||
},
|
||||
encryption: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const v$ = useVuelidate(
|
||||
rules,
|
||||
computed(() => props.mailSenderStore.smtpConfig)
|
||||
)
|
||||
</script>
|
||||
@ -128,6 +128,29 @@
|
||||
</BaseInput>
|
||||
</BaseInputGroup>
|
||||
|
||||
<BaseInputGroup
|
||||
:label="$t('users.select_sender')"
|
||||
:error="
|
||||
v$.userData.mail_sender_id.$error &&
|
||||
v$.userData.mail_sender_id.$errors[0].$message
|
||||
"
|
||||
:content-loading="isFetchingInitialData"
|
||||
required
|
||||
>
|
||||
<BaseMultiselect
|
||||
v-model="userStore.userData.mail_sender_id"
|
||||
label="name"
|
||||
value-prop="id"
|
||||
:options="mailSenderStore.mailSenders"
|
||||
:can-deselect="false"
|
||||
:can-clear="false"
|
||||
searchable
|
||||
track-by="name"
|
||||
:invalid="v$.userData.mail_sender_id.$error"
|
||||
@input="v$.userData.mail_sender_id.$touch()"
|
||||
/>
|
||||
</BaseInputGroup>
|
||||
|
||||
<BaseInputGroup
|
||||
:content-loading="isFetchingInitialData"
|
||||
:label="$t('users.phone')"
|
||||
@ -162,7 +185,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, reactive } from 'vue'
|
||||
import { ref, computed, reactive, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||
import {
|
||||
@ -176,6 +199,7 @@ import useVuelidate from '@vuelidate/core'
|
||||
import { ValidateEach } from '@vuelidate/components'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useUsersStore } from '@/scripts/admin/stores/users'
|
||||
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||
|
||||
const userStore = useUsersStore()
|
||||
|
||||
@ -183,11 +207,13 @@ const { t } = useI18n()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const companyStore = useCompanyStore()
|
||||
const mailSenderStore = useMailSenderStore()
|
||||
|
||||
let isSaving = ref(false)
|
||||
let isFetchingInitialData = ref(false)
|
||||
let selectedCompanies = ref([])
|
||||
let companies = ref([])
|
||||
const mailSenders = ref(null)
|
||||
|
||||
const isEdit = computed(() => route.name === 'users.edit')
|
||||
|
||||
@ -222,6 +248,9 @@ const rules = computed(() => {
|
||||
companies: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
mail_sender_id: {
|
||||
required: helpers.withMessage(t('validation.required'), required),
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
@ -236,6 +265,20 @@ const v$ = useVuelidate(rules, userStore, {
|
||||
$scope: true,
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
await mailSenderStore.fetchMailSenders()
|
||||
let mailSenderData = await mailSenderStore.fetchMailSenderList()
|
||||
if (mailSenderData.data) {
|
||||
mailSenders.value = mailSenderData.data.data
|
||||
let defaultMailSender = mailSenderData.data.data.find(
|
||||
(mailSender) => mailSender.is_default == true
|
||||
)
|
||||
userStore.userData.mail_sender_id = defaultMailSender
|
||||
? defaultMailSender.id
|
||||
: null
|
||||
}
|
||||
})
|
||||
|
||||
loadInitialData()
|
||||
|
||||
userStore.resetUserData()
|
||||
|
||||
@ -100,7 +100,8 @@
|
||||
"pay_invoice": "Pay Invoice",
|
||||
"login_successfully": "Logged in successfully!",
|
||||
"logged_out_successfully": "Logged out successfully",
|
||||
"mark_as_default": "Mark as default"
|
||||
"mark_as_default": "Mark as default",
|
||||
"send_test_mail": "Send Test Mail"
|
||||
},
|
||||
"dashboard": {
|
||||
"select_year": "Select year",
|
||||
@ -233,7 +234,8 @@
|
||||
"updated_message": "Customer updated successfully",
|
||||
"address_updated_message": "Address Information Updated succesfully",
|
||||
"deleted_message": "Customer deleted successfully | Customers deleted successfully",
|
||||
"edit_currency_not_allowed": "Cannot change currency once transactions created."
|
||||
"edit_currency_not_allowed": "Cannot change currency once transactions created.",
|
||||
"select_sender": "Select Sender"
|
||||
},
|
||||
"items": {
|
||||
"title": "Items",
|
||||
@ -728,7 +730,8 @@
|
||||
"updated_message": "User updated successfully",
|
||||
"deleted_message": "User deleted successfully | Users deleted successfully",
|
||||
"select_company_role": "Select Role for {company}",
|
||||
"companies": "Companies"
|
||||
"companies": "Companies",
|
||||
"select_sender": "Select Sender"
|
||||
},
|
||||
"reports": {
|
||||
"title": "Report",
|
||||
@ -807,7 +810,8 @@
|
||||
"payment_modes": "Payment Modes",
|
||||
"notes": "Notes",
|
||||
"exchange_rate": "Exchange Rate",
|
||||
"address_information": "Address Information"
|
||||
"address_information": "Address Information",
|
||||
"mail_sender": "Mail Senders"
|
||||
},
|
||||
"address_information": {
|
||||
"section_description": " You can update Your Address information using form below."
|
||||
@ -1311,6 +1315,51 @@
|
||||
"state_placeholder": "Example: CA",
|
||||
"zip_placeholder": "Example: 90024",
|
||||
"invalid_address": "Please provide valid address details."
|
||||
},
|
||||
"mail_sender": {
|
||||
"title": "Mail Sender | Mail Senders",
|
||||
"description": "Configure & test your mail senders for the selected company.",
|
||||
"add_new_mail_sender": "New Mail Sender",
|
||||
"name": "Sender Name",
|
||||
"name_help": "Type a name to identify the sender for users.",
|
||||
"driver": "Mail Driver",
|
||||
"is_default": "Set as default",
|
||||
"is_default_description": "You can only set one sender as default at a given time.",
|
||||
"cc": "CC",
|
||||
"bcc": "BCC",
|
||||
"from_address": "From Mail Address",
|
||||
"from_name": "From Mail Name",
|
||||
"edit_mail_sender": "Edit Mail Sender",
|
||||
"delete_mail_sender": "Delete Mail Sender",
|
||||
"confirm_delete": "You will not be able to recover this Mail Sender",
|
||||
"created_message": "Mail Sender created successfully",
|
||||
"updated_message": "Mail Sender updated successfully",
|
||||
"deleted_message": "Mail Sender deleted successfully",
|
||||
"default_record_exists": "Default mail sender already exist",
|
||||
"email_list": "Supports a comma separated list of email addresses",
|
||||
"select_mail_sender": "Select Mail Sender",
|
||||
"manage_mail_sender": "Manage Mail Senders",
|
||||
"no_mail_sender_found": "No mail senders found!",
|
||||
"no_mail_sender_found_description": "You must configure at-least one mail sender for the selected company in order to continue.",
|
||||
"smtp_config": {
|
||||
"host": "Host",
|
||||
"port": "Port",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"encryption": "Encryption"
|
||||
},
|
||||
"mailgun_config": {
|
||||
"domain": "Domain",
|
||||
"secret": "Maingun Secret",
|
||||
"endpoint": "Mailgun Endpoint"
|
||||
},
|
||||
"ses_config": {
|
||||
"host": "Host",
|
||||
"port": "Port",
|
||||
"encryption": "Encryption",
|
||||
"ses_key": "SES Key",
|
||||
"ses_secret": "SES Secret"
|
||||
}
|
||||
}
|
||||
},
|
||||
"wizard": {
|
||||
@ -1523,4 +1572,4 @@
|
||||
"pdf_ship_to": "Ship to,",
|
||||
"pdf_received_from": "Received from:",
|
||||
"pdf_tax_label": "Tax"
|
||||
}
|
||||
}
|
||||
@ -403,15 +403,12 @@ Route::prefix('/v1')->group(function () {
|
||||
// Mails
|
||||
//----------------------------------
|
||||
|
||||
Route::get('/mail/drivers', [MailConfigurationController::class, 'getMailDrivers']);
|
||||
|
||||
Route::post('/mail/test', [MailConfigurationController::class, 'testEmailConfig']);
|
||||
// Route::get('/mail/config', [MailConfigurationController::class, 'getMailEnvironment']);
|
||||
|
||||
// Route::post('/mail/config', [MailConfigurationController::class, 'saveMailEnvironment']);
|
||||
|
||||
Route::apiResource('mail-sender', MailSenderController::class);
|
||||
|
||||
Route::get('/mail-drivers', [MailConfigurationController::class, 'getMailDrivers']);
|
||||
|
||||
Route::post('/mail-test', [MailConfigurationController::class, 'TestMailDriver']);
|
||||
|
||||
Route::get('mail-senders', GetAllMailSendersController::class);
|
||||
|
||||
Route::get('/company/mail/config', GetCompanyMailConfigurationController::class);
|
||||
|
||||
Reference in New Issue
Block a user