feat: Complete API binding

This commit is contained in:
Muhsin Keloth
2024-04-17 14:07:55 +05:30
parent 4de6de2e56
commit 25ad9eee61
4 changed files with 758 additions and 76 deletions
@@ -1,48 +1,146 @@
<template>
<div class="flex flex-col w-full gap-4">
<h4 class="text-lg font-medium text-slate-900 dark:text-slate-25">
Change password
</h4>
<div class="flex flex-row items-center justify-between gap-4">
<div class="flex-grow h-0.5 bg-slate-50 dark:bg-slate-700" />
</div>
<form-input
name="current_password"
class="flex-1"
:class="{ error: false }"
label="Current password"
placeholder="Please enter your current password"
:has-error="false"
error-message="Please enter your current password"
/>
<form-input
name="new_password"
class="flex-1"
:class="{ error: false }"
label="New password"
placeholder="Please enter your new password"
:has-error="false"
error-message="Please enter your new password"
/>
<form @submit.prevent="changePassword()">
<div class="flex flex-col w-full gap-4">
<h4 class="text-lg font-medium text-slate-900 dark:text-slate-25">
Change password
</h4>
<woot-input
v-model="currentPassword"
type="password"
:class="{ error: $v.currentPassword.$error }"
:label="$t('PROFILE_SETTINGS.FORM.CURRENT_PASSWORD.LABEL')"
:placeholder="$t('PROFILE_SETTINGS.FORM.CURRENT_PASSWORD.PLACEHOLDER')"
:error="
$v.currentPassword.$error
? $t('PROFILE_SETTINGS.FORM.CURRENT_PASSWORD.ERROR')
: ''
"
@blur="$v.currentPassword.$touch"
/>
<form-input
name="confirm_password"
class="flex-1"
:class="{ error: false }"
label="Confirm password"
placeholder="Please confirm your new password"
:has-error="false"
error-message="Please confirm your new password"
/>
<woot-button
color-scheme="primary"
class="rounded-xl w-fit"
@click="$emit('click')"
>
Update password
</woot-button>
</div>
<woot-input
v-model="password"
type="password"
:class="{ error: $v.password.$error }"
:label="$t('PROFILE_SETTINGS.FORM.PASSWORD.LABEL')"
:placeholder="$t('PROFILE_SETTINGS.FORM.PASSWORD.PLACEHOLDER')"
:error="
$v.password.$error ? $t('PROFILE_SETTINGS.FORM.PASSWORD.ERROR') : ''
"
@blur="$v.password.$touch"
/>
<woot-input
v-model="passwordConfirmation"
type="password"
:class="{ error: $v.passwordConfirmation.$error }"
:label="$t('PROFILE_SETTINGS.FORM.PASSWORD_CONFIRMATION.LABEL')"
:placeholder="
$t('PROFILE_SETTINGS.FORM.PASSWORD_CONFIRMATION.PLACEHOLDER')
"
:error="
$v.passwordConfirmation.$error
? $t('PROFILE_SETTINGS.FORM.PASSWORD_CONFIRMATION.ERROR')
: ''
"
@blur="$v.passwordConfirmation.$touch"
/>
<woot-button
class="w-fit"
:is-loading="isPasswordChanging"
type="submit"
:disabled="
!currentPassword ||
!passwordConfirmation ||
!$v.passwordConfirmation.isEqPassword
"
>
{{ $t('PROFILE_SETTINGS.FORM.PASSWORD_SECTION.BTN_TEXT') }}
</woot-button>
</div>
</form>
</template>
<script setup>
import FormInput from 'v3/components/Form/Input.vue';
<script>
import { required, minLength } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import { parseAPIErrorResponse } from 'dashboard/store/utils/api';
export default {
mixins: [alertMixin],
data() {
return {
currentPassword: '',
password: '',
passwordConfirmation: '',
isPasswordChanging: false,
errorMessage: '',
};
},
validations: {
currentPassword: {
required,
},
password: {
minLength: minLength(6),
},
passwordConfirmation: {
minLength: minLength(6),
isEqPassword(value) {
if (value !== this.password) {
return false;
}
return true;
},
},
},
computed: {
...mapGetters({
currentUser: 'getCurrentUser',
currentUserId: 'getCurrentUserID',
}),
},
methods: {
async changePassword() {
this.$v.$touch();
if (this.$v.$invalid) {
this.showAlert(this.$t('PROFILE_SETTINGS.FORM.ERROR'));
return;
}
try {
await this.$store.dispatch('updateProfile', {
password: this.password,
password_confirmation: this.passwordConfirmation,
current_password: this.currentPassword,
});
this.errorMessage = this.$t('PROFILE_SETTINGS.PASSWORD_UPDATE_SUCCESS');
} catch (error) {
this.errorMessage =
parseAPIErrorResponse(error) ||
this.$t('RESET_PASSWORD.API.ERROR_MESSAGE');
} finally {
this.isPasswordChanging = false;
this.showAlert(this.errorMessage);
}
},
},
};
</script>
<style lang="scss">
@import '~dashboard/assets/scss/mixins.scss';
.profile--settings--row {
@include border-normal-bottom;
padding: var(--space-normal);
.small-3 {
padding: var(--space-normal) var(--space-medium) var(--space-normal) 0;
}
.small-9 {
padding: var(--space-normal);
}
}
</style>
@@ -9,15 +9,14 @@
class="flex justify-between items-center px-2 w-full h-10 rounded-t-[5px]"
>
<div class="flex items-center p-1 text-sm font-medium">{{ heading }}</div>
<!-- <fluent-icon
v-if="active"
icon="checkmark-circle"
type="solid"
size="24"
class="text-woot-500 dark:text-woot-500"
/> -->
<div>
<input type="radio" name="hotkey" value="enter" :checked="active" />
<!-- Show radio button, if the card is active, set radio button checked -->
<input
:checked="active"
type="radio"
name="hotkey"
@change="$emit('update', 'enter')"
/>
</div>
</div>
<div
@@ -35,6 +34,10 @@
<script>
export default {
props: {
active: {
type: Boolean,
default: false,
},
heading: {
type: String,
default: '',
@@ -43,14 +46,6 @@ export default {
type: String,
default: '',
},
active: {
type: Boolean,
default: false,
},
buttonText: {
type: String,
default: 'Active',
},
src: {
type: String,
default: '',
@@ -86,36 +86,35 @@
:heading="keyOption.heading"
:content="keyOption.content"
:src="keyOption.src"
:active="keyOption.key === 'enter'"
:active="isEditorHotKeyEnabled(uiSettings, keyOption.key)"
@click="toggleEditorMessageKey(keyOption.key)"
/>
</button>
</div>
</template>
</personal-wrapper>
<change-password />
<change-password v-if="!globalConfig.disableUserProfileUpdate" />
<personal-wrapper
header="Audio notifications"
description="Enable audio notifications in dashboard for new messages and conversations."
:show-action-button="false"
>
<template #settingsItem>
<audio-notifications />
</template>
</personal-wrapper>
<personal-wrapper
header="Notification preferences"
:show-action-button="false"
>
<template #settingsItem>
<notification-preferences />
<notification-settings />
</template>
</personal-wrapper>
<personal-wrapper
header="Access Token"
description="This token can be used if you are building an API based integration."
:description="
useInstallationName(
$t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.NOTE'),
globalConfig.installationName
)
"
:show-action-button="false"
>
<template #settingsItem>
<!-- TODO: Use masked text -->
<access-token />
</template>
</personal-wrapper>
@@ -129,8 +128,6 @@ import MessageSignature from './MessageSignature.vue';
import PersonalWrapper from './PersonalWrapper.vue';
import HotKeyCard from './HotKeyCard.vue';
import ChangePassword from './ChangePassword.vue';
import NotificationPreferences from './NotificationPreferences.vue';
import AudioNotifications from './AudioNotifications.vue';
import AccessToken from './AccessToken.vue';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import uiSettingsMixin, {
@@ -141,6 +138,7 @@ import { required, minLength, email } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import { clearCookiesOnLogout } from '../../../../store/utils/api';
import { hasValidAvatarUrl } from 'dashboard/helper/URLHelper';
import NotificationSettings from './NotificationSettings.vue';
export default {
components: {
@@ -149,8 +147,7 @@ export default {
PersonalWrapper,
HotKeyCard,
ChangePassword,
NotificationPreferences,
AudioNotifications,
NotificationSettings,
AccessToken,
},
mixins: [alertMixin, globalConfigMixin, uiSettingsMixin],
@@ -0,0 +1,592 @@
<template>
<div id="profile-settings-notifications" class="flex flex-col gap-4">
<form-select
v-model="notificationTone"
name="timezone"
spacing="compact"
label="Alert tone"
placeholder="Ding"
class="max-w-xl"
@input="handleAudioToneChange"
>
<option
v-for="file in notificationAlertTones"
:key="file.label"
:value="file.value"
>
{{ file.label }}
</option>
</form-select>
<div>
<label
class="flex justify-between pb-1 text-sm font-medium leading-6 text-slate-900 dark:text-white"
>
Alert events for conversations
</label>
<div
class="flex flex-row justify-between h-10 max-w-xl p-2 border border-solid rounded-md border-slate-75 dark:border-slate-600"
>
<div
class="flex flex-row items-center justify-center gap-1 border-r border-slate-75 grow"
>
<input
id="audio_enable_alert_none"
v-model="enableAudioAlerts"
class="notification--checkbox"
type="radio"
value="none"
@input="handleAudioInput"
/>
<label>None</label>
</div>
<div
class="flex flex-row items-center justify-center gap-1 border-r border-slate-75 grow"
>
<input
id="audio_enable_alert_mine"
v-model="enableAudioAlerts"
class="notification--checkbox"
type="radio"
value="mine"
@input="handleAudioInput"
/>
<label>Assigned</label>
</div>
<div class="flex flex-row items-center justify-center gap-1 grow">
<input
id="audio_enable_alert_all"
v-model="enableAudioAlerts"
class="notification--checkbox"
type="radio"
value="all"
@input="handleAudioInput"
/>
<label>All</label>
</div>
</div>
</div>
<div>
<label
class="flex justify-between pb-1 text-sm font-medium leading-6 text-slate-900 dark:text-white"
>
Alert conditions
</label>
<div class="flex flex-row items-center justify-start gap-2">
<input
id="audio_alert_when_tab_is_inactive"
v-model="playAudioWhenTabIsInactive"
type="checkbox"
value="tab_is_inactive"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handleAudioAlertConditions"
/>
<label>
Send audio alerts only if the browser window is not active
</label>
</div>
<div class="flex flex-row items-center justify-start gap-2">
<input
v-model="alertIfUnreadConversationExist"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
type="checkbox"
value="conversations_are_read"
@input="handleAudioAlertConditions"
/>
<label>
Send alerts every 30s until all the assigned conversations are read
</label>
</div>
</div>
<div>
<h4 class="text-lg font-medium text-slate-900 dark:text-slate-25">
Notification preferences
</h4>
<!-- Draw a line -->
<div class="flex flex-row items-center justify-between gap-4">
<div class="flex-grow h-0.5 bg-slate-50 dark:bg-slate-700" />
</div>
<div
class="grid content-center h-12 grid-cols-12 gap-4 py-0 rounded-t-xl"
>
<table-header-cell :span="6" label="Notification type" />
<table-header-cell :span="3" label="Email" />
<table-header-cell :span="3" label="Push notification">
<div class="flex flex-row items-center justify-center gap-1">
<span
class="text-xs font-medium uppercase text-slate-700 dark:text-slate-100 rtl:text-right"
>
Push notification
</span>
<woot-switch
:value="!hasEnabledPushPermissions"
@input="onRequestPermissions()"
/>
</div>
</table-header-cell>
</div>
<div
class="grid content-center h-12 grid-cols-12 gap-4 py-0 rounded-t-xl"
>
<div
class="flex items-center gap-2 col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
<span class="text-slate-700 dark:text-slate-200">
A new conversation is created
</span>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedEmailFlags"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
type="checkbox"
value="email_conversation_creation"
@input="handleEmailInput"
/>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
type="checkbox"
name="email"
:checked="false"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
/>
</div>
</div>
<div
class="grid content-center h-12 grid-cols-12 gap-4 py-0 rounded-t-xl"
>
<div
class="flex items-center gap-2 col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
<span class="text-slate-700 dark:text-slate-200">
Conversation is assigned to you
</span>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedEmailFlags"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
type="checkbox"
value="email_conversation_assignment"
@input="handleEmailInput"
/>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedPushFlags"
type="checkbox"
value="push_conversation_creation"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handlePushInput"
/>
</div>
</div>
<div
class="grid content-center h-12 grid-cols-12 gap-4 py-0 rounded-t-xl"
>
<div
class="flex items-center gap-2 col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
<span class="text-slate-700 dark:text-slate-200">
You are mentioned in a conversation
</span>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedEmailFlags"
type="checkbox"
value="email_conversation_mention"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handleEmailInput"
/>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedPushFlags"
type="checkbox"
value="push_conversation_mention"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handlePushInput"
/>
</div>
</div>
<div
class="grid content-center h-12 grid-cols-12 gap-4 py-0 rounded-t-xl"
>
<div
class="flex items-center gap-2 col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
<span class="text-slate-700 dark:text-slate-200">
New message is created in an assigned conversation
</span>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedEmailFlags"
type="checkbox"
value="email_conversation_message"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handleEmailInput"
/>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedPushFlags"
type="checkbox"
value="push_assigned_conversation_new_message"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handlePushInput"
/>
</div>
</div>
<div
class="grid content-center h-12 grid-cols-12 gap-4 py-0 rounded-t-xl"
>
<div
class="flex items-center gap-2 col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
<span class="text-slate-700 dark:text-slate-200">
New message is created in an participating conversation
</span>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedEmailFlags"
type="checkbox"
value="email_participating_conversation_new_message"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handleEmailInput"
/>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedPushFlags"
type="checkbox"
value="push_participating_conversation_new_message"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handlePushInput"
/>
</div>
</div>
<div
v-if="isSLAEnabled"
class="grid content-center h-12 grid-cols-12 gap-4 py-0 rounded-t-xl"
>
<div
class="flex items-center gap-2 col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
<span class="text-slate-700 dark:text-slate-200">
Conversation misses first response SLA
</span>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedEmailFlags"
type="checkbox"
value="email_sla_missed_first_response"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
/>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedPushFlags"
type="checkbox"
value="push_sla_missed_first_response"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handlePushInput"
/>
</div>
</div>
<div
v-if="isSLAEnabled"
class="grid content-center h-12 grid-cols-12 gap-4 py-0 rounded-t-xl"
>
<div
class="flex items-center gap-2 col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
<span class="text-slate-700 dark:text-slate-200">
Conversation misses next response SLA
</span>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedEmailFlags"
type="checkbox"
value="email_sla_missed_next_response"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
/>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedPushFlags"
type="checkbox"
value="push_sla_missed_next_response"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handlePushInput"
/>
</div>
</div>
<div
v-if="isSLAEnabled"
class="grid content-center h-12 grid-cols-12 gap-4 py-0 rounded-t-xl"
>
<div
class="flex items-center gap-2 col-span-6 px-0 py-2 text-sm tracking-[0.5] text-slate-700 dark:text-slate-100 rtl:text-right"
>
<span class="text-slate-700 dark:text-slate-200">
Conversation misses resolution SLA
</span>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedEmailFlags"
type="checkbox"
value="email_sla_missed_resolution"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
/>
</div>
<div
class="flex items-center gap-2 col-span-3 py-2 px-0 text-sm tracking-[0.5] text-slate-700 dark:text-slate-50 text-left rtl:text-right"
>
<input
v-model="selectedPushFlags"
type="checkbox"
value="push_sla_missed_resolution"
class="m-0 border-[1.5px] shadow border-slate-200 dark:border-slate-600 appearance-none rounded-[4px] w-4 h-4 dark:bg-slate-800 focus:ring-1 focus:ring-slate-100 dark:focus:ring-slate-700 checked:bg-woot-600 dark:checked:bg-woot-600 after:content-[''] after:text-white checked:after:content-['✓'] after:flex after:items-center after:justify-center checked:border-t checked:border-woot-700 dark:checked:border-woot-300 checked:border-b-0 checked:border-r-0 checked:border-l-0 after:text-center after:text-xs after:font-bold after:relative after:-top-[1.5px]"
@input="handlePushInput"
/>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import configMixin from 'shared/mixins/configMixin';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import FormSelect from 'v3/components/Form/Select.vue';
import TableHeaderCell from 'dashboard/components/widgets/TableHeaderCell.vue';
import {
hasPushPermissions,
requestPushPermissions,
verifyServiceWorkerExistence,
} from '../../../../helper/pushHelper';
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
export default {
components: {
FormSelect,
TableHeaderCell,
},
mixins: [alertMixin, configMixin, uiSettingsMixin],
data() {
return {
selectedEmailFlags: [],
selectedPushFlags: [],
enableAudioAlerts: false,
hasEnabledPushPermissions: false,
playAudioWhenTabIsInactive: false,
alertIfUnreadConversationExist: false,
notificationTone: 'ding',
notificationAlertTones: [
{
value: 'ding',
label: 'Ding',
},
{
value: 'bell',
label: 'Bell',
},
],
};
},
computed: {
...mapGetters({
accountId: 'getCurrentAccountId',
emailFlags: 'userNotificationSettings/getSelectedEmailFlags',
pushFlags: 'userNotificationSettings/getSelectedPushFlags',
uiSettings: 'getUISettings',
isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
}),
hasPushAPISupport() {
return !!('Notification' in window);
},
isSLAEnabled() {
return this.isFeatureEnabledonAccount(this.accountId, FEATURE_FLAGS.SLA);
},
},
watch: {
emailFlags(value) {
this.selectedEmailFlags = value;
},
pushFlags(value) {
this.selectedPushFlags = value;
},
uiSettings(value) {
this.notificationUISettings(value);
},
},
mounted() {
if (hasPushPermissions()) {
this.getPushSubscription();
}
this.notificationUISettings(this.uiSettings);
this.$store.dispatch('userNotificationSettings/get');
},
methods: {
notificationUISettings(uiSettings) {
const {
enable_audio_alerts: enableAudio = false,
always_play_audio_alert: alwaysPlayAudioAlert,
alert_if_unread_assigned_conversation_exist:
alertIfUnreadConversationExist,
notification_tone: notificationTone,
} = uiSettings;
this.enableAudioAlerts = enableAudio;
this.playAudioWhenTabIsInactive = !alwaysPlayAudioAlert;
this.alertIfUnreadConversationExist = alertIfUnreadConversationExist;
this.notificationTone = notificationTone || 'ding';
},
onRegistrationSuccess() {
this.hasEnabledPushPermissions = true;
},
onRequestPermissions() {
requestPushPermissions({
onSuccess: this.onRegistrationSuccess,
});
},
getPushSubscription() {
verifyServiceWorkerExistence(registration =>
registration.pushManager
.getSubscription()
.then(subscription => {
if (!subscription) {
this.hasEnabledPushPermissions = false;
} else {
this.hasEnabledPushPermissions = true;
}
})
// eslint-disable-next-line no-console
.catch(error => console.log(error))
);
},
async updateNotificationSettings() {
try {
this.$store.dispatch('userNotificationSettings/update', {
selectedEmailFlags: this.selectedEmailFlags,
selectedPushFlags: this.selectedPushFlags,
});
this.showAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS'));
} catch (error) {
this.showAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_ERROR'));
}
},
handleEmailInput(e) {
this.selectedEmailFlags = this.toggleInput(
this.selectedEmailFlags,
e.target.value
);
this.updateNotificationSettings();
},
handlePushInput(e) {
this.selectedPushFlags = this.toggleInput(
this.selectedPushFlags,
e.target.value
);
this.updateNotificationSettings();
},
handleAudioInput(e) {
this.enableAudioAlerts = e.target.value;
this.updateUISettings({
enable_audio_alerts: this.enableAudioAlerts,
});
this.showAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS'));
},
handleAudioAlertConditions(e) {
let condition = e.target.value;
if (condition === 'tab_is_inactive') {
this.updateUISettings({
always_play_audio_alert: !e.target.checked,
});
} else if (condition === 'conversations_are_read') {
this.updateUISettings({
alert_if_unread_assigned_conversation_exist: e.target.checked,
});
}
this.showAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS'));
},
handleAudioToneChange(value) {
this.updateUISettings({ notification_tone: value });
this.showAlert(this.$t('PROFILE_SETTINGS.FORM.API.UPDATE_SUCCESS'));
},
toggleInput(selected, current) {
if (selected.includes(current)) {
const newSelectedFlags = selected.filter(flag => flag !== current);
return newSelectedFlags;
}
return [...selected, current];
},
},
};
</script>
<style lang="scss" scoped>
@import '~dashboard/assets/scss/variables.scss';
.notification--checkbox {
font-size: $font-size-large;
}
.push-notification--button {
margin-bottom: var(--space-one);
}
.notification-label {
display: flex;
font-weight: var(--font-weight-bold);
margin-bottom: var(--space-small);
}
.tone-selector {
height: var(--space-large);
padding-bottom: var(--space-micro);
padding-top: var(--space-micro);
width: var(--space-mega);
}
</style>