Compare commits

..
Author SHA1 Message Date
Sivin VargheseandGitHub 54308a4145 Merge branch 'develop' into fix/editor-heading-error 2024-01-29 20:23:00 +05:30
Shivam MishraandGitHub 2eeec22868 fix: Cookies.set does not stringify JSON (#8807)
* fix: cookie setting

* chore: remove debug statement

* chore: add specs to test stringify
2024-01-29 18:14:49 +05:30
Muhsin KelothandGitHub ef50edb9e2 feat: Standardise the external channel user id and user name (#8802)
* feat: Standardize the external channel id and user name

* chore: add specs

* chore: add name space `social`
2024-01-29 16:57:10 +05:30
Shivam MishraandGitHub 3ed80fa867 feat: expiry for cache keys [CW-3038] (#8793)
* feat: set cache keys for 3 days only

* feat: invalidate should set the latest timestamp

* refactor: cache_keys concern

* remove invalidate_cache method
* refactor reset to set to new value instead of delete
* ensure only one event is dispatched

* feat: set expiry to 24 hours

* chore: make expiry 48 hours

* feat: include destroy event

* feat: set expiry to 72 days

* fix: typo

* test: cache update after `touch`

* test: update cache keys

* refactor: remove after_touch, it's already handled in commit
2024-01-29 15:27:26 +05:30
Nithin David ThomasandGitHub 88f44c21f2 Merge branch 'develop' into fix/editor-heading-error 2024-01-29 01:23:51 -08:00
Sivin VargheseandGitHub cf664ca2a0 feat: Inbox item card component (#8801) 2024-01-29 14:52:55 +05:30
Muhsin KelothandGitHub 485c561b18 feat: Add attributes location and country_code to Contact model (#8803)
feat: Add attributes location and country_code to Contact model
2024-01-29 14:10:14 +05:30
Pranav Raj SandGitHub 766698cb3a chore: Upgrade @june-so/analytics-next, js-cookie to the latest version (#8799)
This is a small change, upgrading 2 packages to the latest version. getJSON is removed from the latest version, I've added a patch for the same across the codebase.

fixes: https://linear.app/chatwoot/issue/CW-3035/upgrade-dependencies
2024-01-29 11:41:42 +04:00
Nithin David Thomas feb8ec7879 Upgrades package ith latest fixes 2024-01-29 10:33:23 +05:30
Shivam MishraandGitHub 082793290a feat: allow multiple files for FB and Insta [CW-3019] (#8783)
* feat: allow multiple messages

* fix: typo

* feat: send content and attachments both

* refactor: message sequence

* test: multiple attachments for instagram

* test: multiple attachments on facebook
2024-01-28 13:20:54 +05:30
Nithin David Thomas b5e81ccd3b Updates yarn lock 2024-01-26 10:45:16 +05:30
Nithin David ThomasandGitHub b31040901e Merge branch 'develop' into fix/editor-heading-error 2024-01-25 20:02:16 -08:00
Sivin VargheseandGitHub 1f610c7fc5 Merge branch 'develop' into fix/editor-heading-error 2024-01-24 11:09:20 +05:30
Nithin David Thomas 188a8a67c0 chore: Updates prosemirror package to latest version 2024-01-23 08:37:06 +05:30
219 changed files with 15082 additions and 1950 deletions
+1 -1
View File
@@ -74,7 +74,7 @@ jobs:
name: yarn
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
# Store yarn cache
# Store yarn / webpacker cache
- save_cache:
key: chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }}
paths:
+4 -4
View File
@@ -3,10 +3,10 @@ sed -i -e '/REDIS_URL/ s/=.*/=redis:\/\/localhost:6379/' .env
sed -i -e '/POSTGRES_HOST/ s/=.*/=localhost/' .env
sed -i -e '/SMTP_ADDRESS/ s/=.*/=localhost/' .env
sed -i -e "/FRONTEND_URL/ s/=.*/=https:\/\/$CODESPACE_NAME-3000.githubpreview.dev/" .env
sed -i -e "/DEV_SERVER_PUBLIC/ s/=.*/=https:\/\/$CODESPACE_NAME-3035.githubpreview.dev/" .env
# uncomment the dev server env variable
sed -i -e '/DEV_SERVER_PUBLIC/s/^# //' .env
# fix the error with dev server
sed -i -e "/WEBPACKER_DEV_SERVER_PUBLIC/ s/=.*/=https:\/\/$CODESPACE_NAME-3035.githubpreview.dev/" .env
# uncomment the webpacker env variable
sed -i -e '/WEBPACKER_DEV_SERVER_PUBLIC/s/^# //' .env
# fix the error with webpacker
echo 'export NODE_OPTIONS=--openssl-legacy-provider' >> ~/.zshrc
# codespaces make the ports public
+1 -1
View File
@@ -223,7 +223,7 @@ ANDROID_SHA256_CERT_FINGERPRINT=AC:73:8E:DE:EB:56:EA:CC:10:87:02:A7:65:37:7B:38:
# if you want to use letter_opener for local emails
# LETTER_OPENER=true
# meant to be used in github codespaces
# DEV_SERVER_PUBLIC=
# WEBPACKER_DEV_SERVER_PUBLIC=
# If you want to use official mobile app,
# the notifications would be relayed via a Chatwoot server
+10 -2
View File
@@ -7,10 +7,11 @@ module.exports = {
'plugin:cypress/recommended',
],
parserOptions: {
ecmaVersion: 2022,
parser: '@babel/eslint-parser',
ecmaVersion: 2020,
sourceType: 'module',
},
plugins: ['html', 'prettier'],
plugins: ['html', 'prettier', 'babel'],
rules: {
'prettier/prettier': ['error'],
camelcase: 'off',
@@ -55,6 +56,13 @@ module.exports = {
'import/extensions': ['off'],
'no-console': 'error',
},
settings: {
'import/resolver': {
webpack: {
config: 'config/webpack/resolve.js',
},
},
},
env: {
browser: true,
jest: true,
+1 -9
View File
@@ -75,12 +75,4 @@ yalc.lock
yarn-debug.log*
.yarn-integrity
/storybook-static
# Vite Ruby
/public/vite*
node_modules
# Vite uses dotenv and suggests to ignore local-only env files. See
# https://vitejs.dev/guide/env-and-mode.html#env-files
*.local
/storybook-static
+3 -1
View File
@@ -2,6 +2,7 @@ import { addDecorator } from '@storybook/vue';
import Vue from 'vue';
import Vuex from 'vuex';
import VueI18n from 'vue-i18n';
import Vuelidate from 'vuelidate';
import Multiselect from 'vue-multiselect';
import VueDOMPurifyHTML from 'vue-dompurify-html';
import FluentIcon from 'shared/components/FluentIcon/DashboardIcon';
@@ -13,6 +14,7 @@ import { domPurifyConfig } from 'shared/helpers/HTMLSanitizer';
import '../app/javascript/dashboard/assets/scss/storybook.scss';
Vue.use(VueI18n);
Vue.use(Vuelidate);
Vue.use(WootUiKit);
Vue.use(Vuex);
Vue.use(VueDOMPurifyHTML, domPurifyConfig);
@@ -30,7 +32,7 @@ addDecorator(() => ({
template: '<story/>',
i18n: i18nConfig,
store,
beforeCreate: function () {
beforeCreate: function() {
this.$root._i18n = this.$i18n;
},
}));
+1 -1
View File
@@ -64,7 +64,7 @@ gem 'activerecord-import'
gem 'dotenv-rails'
gem 'foreman'
gem 'puma'
gem 'vite_rails'
gem 'webpacker'
# metrics on heroku
gem 'barnes'
+8 -10
View File
@@ -216,7 +216,6 @@ GEM
railties (>= 3.2)
down (5.4.0)
addressable (~> 2.8)
dry-cli (1.0.0)
ecma-re-validator (0.4.0)
regexp_parser (~> 2.2)
elastic-apm (4.6.2)
@@ -571,7 +570,7 @@ GEM
rack (>= 1.2.0)
rack-protection (3.1.0)
rack (~> 2.2, >= 2.2.4)
rack-proxy (0.7.7)
rack-proxy (0.7.6)
rack
rack-test (2.1.0)
rack (>= 1.3)
@@ -709,6 +708,7 @@ GEM
activerecord (>= 4)
activesupport (>= 4)
selectize-rails (0.12.6)
semantic_range (3.0.0)
sentry-rails (5.14.0)
railties (>= 5.0)
sentry-ruby (~> 5.14.0)
@@ -795,13 +795,6 @@ GEM
activemodel (>= 3.2)
mail (~> 2.5)
version_gem (1.1.2)
vite_rails (3.0.17)
railties (>= 5.1, < 8)
vite_ruby (~> 3.0, >= 3.2.2)
vite_ruby (3.5.0)
dry-cli (>= 0.7, < 2)
rack-proxy (~> 0.6, >= 0.6.1)
zeitwerk (~> 2.2)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.1)
@@ -817,6 +810,11 @@ GEM
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webpacker (5.4.4)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
webrick (1.8.1)
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
@@ -959,10 +957,10 @@ DEPENDENCIES
tzinfo-data
uglifier
valid_email2
vite_rails
web-console (>= 4.2.1)
web-push
webmock
webpacker
wisper (= 2.0.0)
working_hours
+1 -1
View File
@@ -1,4 +1,4 @@
backend: bin/rails s -p 3000
frontend: export NODE_OPTIONS=--openssl-legacy-provider && bin/webpack-dev-server
# https://github.com/mperham/sidekiq/issues/3090#issuecomment-389748695
worker: dotenv bundle exec sidekiq -C config/sidekiq.yml
frontend: bin/vite dev
+1 -1
View File
@@ -1,3 +1,3 @@
backend: RAILS_ENV=test bin/rails s -p 5050
frontend: bin/vite
frontend: export NODE_OPTIONS=--openssl-legacy-provider && bin/webpack-dev-server
worker: RAILS_ENV=test dotenv bundle exec sidekiq -C config/sidekiq.yml
@@ -86,5 +86,8 @@ $swift-ease-out-duration: .4s !default;
$swift-ease-out-timing-function: cubic-bezier(.25, .8, .25, 1) !default;
$swift-ease-out: all $swift-ease-out-duration $swift-ease-out-timing-function !default;
// Ionicons
$ionicons-font-path: '~ionicons/fonts';
// Transitions
$transition-ease-in: all 0.250s ease-in;
+3 -2
View File
@@ -29,11 +29,12 @@ export default {
return fetchPromise;
},
hasAuthCookie() {
return !!Cookies.getJSON('cw_d_session_info');
return !!Cookies.get('cw_d_session_info');
},
getAuthData() {
if (this.hasAuthCookie()) {
return Cookies.getJSON('cw_d_session_info');
const savedAuthInfo = Cookies.get('cw_d_session_info');
return JSON.parse(savedAuthInfo || '{}');
}
return false;
},
@@ -1,4 +1,4 @@
@import 'vue2-datepicker/scss/index';
@import '~vue2-datepicker/scss/index';
.date-picker {
&.no-margin {
@@ -1,4 +1,4 @@
@import 'dashboard/assets/scss/variables';
@import '~dashboard/assets/scss/variables';
.formulate-input {
.formulate-input-errors {
@@ -0,0 +1,623 @@
// Foundation for Sites Settings
// -----------------------------
//
// Table of Contents:
//
// 1. Global
// 2. Breakpoints
// 3. The Grid
// 4. Base Typography
// 5. Typography Helpers
// 6. Abide
// 7. Accordion
// 8. Accordion Menu
// 9. Badge
// 10. Breadcrumbs
// 11. Button
// 12. Button Group
// 13. Callout
// 14. Card
// 15. Close Button
// 16. Drilldown
// 17. Dropdown
// 18. Dropdown Menu
// 19. Forms
// 20. Label
// 21. Media Object
// 22. Menu
// 23. Meter
// 24. Off-canvas
// 25. Orbit
// 26. Pagination
// 27. Progress Bar
// 28. Responsive Embed
// 29. Reveal
// 30. Slider
// 31. Switch
// 32. Table
// 33. Tabs
// 34. Thumbnail
// 35. Title Bar
// 36. Tooltip
// 37. Top Bar
@import '~foundation-sites/scss/util/util';
// 1. Global
// ---------
// Disable contrast warnings in Foundation.
$contrast-warnings: false;
$global-font-size: 16px;
$global-width: 100%;
$global-lineheight: 1.5;
$foundation-palette: (primary: $color-woot,
secondary: #5d7592,
success: #44ce4b,
warning: #ffc532,
alert: #ff382d);
$light-gray: #c0ccda;
$medium-gray: #8492a6;
$dark-gray: $color-gray;
$black: #000;
$white: #fff;
$body-background: $white;
$body-font-color: $color-body;
$body-font-family: 'PlusJakarta',
-apple-system,
system-ui,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
"Helvetica Neue",
Tahoma,
Arial,
sans-serif;
$body-antialiased: true;
$global-margin: $space-small;
$global-padding: $space-small;
$global-weight-normal: normal;
$global-weight-bold: bold;
$global-radius: 0;
$global-text-direction: ltr;
$global-flexbox: false;
$print-transparent-backgrounds: true;
@include add-foundation-colors;
// 2. Breakpoints
// --------------
$breakpoints: (small: 0,
medium: 640px,
large: 1024px,
xlarge: 1200px,
xxlarge: 1400px,
xxxlarge: 1600px,
);
$print-breakpoint: large;
$breakpoint-classes: (small medium large);
// 3. The Grid
// -----------
$grid-row-width: $global-width;
$grid-column-count: 12;
$grid-column-gutter: (small: $zero,
medium: $zero);
$grid-column-align-edge: true;
$block-grid-max: 8;
// 4. Base Typography
// ------------------
$header-font-family: $body-font-family;
$header-font-weight: $font-weight-medium;
$header-font-style: normal;
$font-family-monospace: $body-font-family;
$header-color: $color-heading;
$header-lineheight: 1.4;
$header-margin-bottom: 0.3125rem;
$header-styles: (small: ("h1": ("font-size": 24),
"h2": ("font-size": 20),
"h3": ("font-size": 19),
"h4": ("font-size": 18),
"h5": ("font-size": 17),
"h6": ("font-size": 16)),
medium: ("h1": ("font-size": 48),
"h2": ("font-size": 40),
"h3": ("font-size": 31),
"h4": ("font-size": 25),
"h5": ("font-size": 20),
"h6": ("font-size": 16)));
$header-text-rendering: optimizeLegibility;
$small-font-size: 80%;
$header-small-font-color: $medium-gray;
$paragraph-lineheight: 1.65;
$paragraph-margin-bottom: var(--space-small);
$paragraph-text-rendering: optimizeLegibility;
$code-color: $black;
$code-font-family: $font-family-monospace;
$code-font-weight: $global-weight-normal;
$code-background: $light-gray;
$code-border: 1px solid $medium-gray;
$code-padding: rem-calc(2 5 1);
$anchor-color: $primary-color;
$anchor-color-hover: scale-color($anchor-color, $lightness: -14%);
$anchor-text-decoration: none;
$anchor-text-decoration-hover: none;
$hr-width: $global-width;
$hr-border: 1px solid $medium-gray;
$hr-margin: rem-calc(20) auto;
$list-lineheight: $paragraph-lineheight;
$list-margin-bottom: $paragraph-margin-bottom;
$list-style-type: disc;
$list-style-position: outside;
$list-side-margin: 0.78125rem;
$list-nested-side-margin: 0.78125rem;
$defnlist-margin-bottom: 0.6875rem;
$defnlist-term-weight: $global-weight-bold;
$defnlist-term-margin-bottom: 0.1875rem;
$blockquote-color: $dark-gray;
$blockquote-padding: rem-calc(9 20 0 19);
$blockquote-border: 1px solid $medium-gray;
$cite-font-size: rem-calc(13);
$cite-color: $dark-gray;
$cite-pseudo-content: '\2014 \0020';
$keystroke-font: $font-family-monospace;
$keystroke-color: $black;
$keystroke-background: $light-gray;
$keystroke-padding: rem-calc(2 4 0);
$keystroke-radius: $global-radius;
$abbr-underline: 1px dotted $black;
// 5. Typography Helpers
// ---------------------
$lead-font-size: $global-font-size * 1.25;
$lead-lineheight: 1.6;
$subheader-lineheight: 1.4;
$subheader-color: $dark-gray;
$subheader-font-weight: $global-weight-normal;
$subheader-margin-top: 0.125rem;
$subheader-margin-bottom: 0.3125rem;
$stat-font-size: 1.5625rem;
// 6. Abide
// --------
$abide-inputs: true;
$abide-labels: true;
$input-background-invalid: get-color(alert);
$form-label-color-invalid: get-color(alert);
$input-error-color: get-color(alert);
$input-error-font-size: rem-calc(12);
$input-error-font-weight: $global-weight-bold;
// 7. Accordion
// ------------
$accordion-background: $white;
$accordion-plusminus: true;
$accordion-title-font-size: rem-calc(12);
$accordion-item-color: $primary-color;
$accordion-item-background-hover: $light-gray;
$accordion-item-padding: 0.78125rem 0.625rem;
$accordion-content-background: $white;
$accordion-content-border: 1px solid $light-gray;
$accordion-content-color: $body-font-color;
$accordion-content-padding: 0.625rem;
// 8. Accordion Menu
// -----------------
$accordionmenu-arrows: true;
$accordionmenu-arrow-color: $primary-color;
$accordionmenu-arrow-size: 6px;
// 9. Badge
// --------
$badge-background: $primary-color;
$badge-color: $white;
$badge-color-alt: $black;
$badge-palette: $foundation-palette;
$badge-padding: var(--space-smaller);
$badge-minwidth: 2.1em;
$badge-font-size: var(--font-size-nano);
// 10. Breadcrumbs
// ---------------
$breadcrumbs-margin: 0 0 $global-margin 0;
$breadcrumbs-item-font-size: rem-calc(11);
$breadcrumbs-item-color: $primary-color;
$breadcrumbs-item-color-current: $black;
$breadcrumbs-item-color-disabled: $medium-gray;
$breadcrumbs-item-margin: 0.46875rem;
$breadcrumbs-item-uppercase: true;
$breadcrumbs-item-slash: true;
// 11. Button
// ----------
$button-padding: var(--space-smaller) 1em;
$button-margin: 0 0 $global-margin 0;
$button-fill: solid;
$button-background: $primary-color;
$button-background-hover: scale-color($button-background, $lightness: -15%);
$button-color: $white;
$button-color-alt: $white;
$button-radius: var(--border-radius-normal);
$button-sizes: (tiny: var(--font-size-micro),
small: var(--font-size-mini),
default: var(--font-size-small),
large: var(--font-size-medium));
$button-palette: $foundation-palette;
$button-opacity-disabled: 0.4;
$button-background-hover-lightness: -20%;
$button-hollow-hover-lightness: -50%;
$button-transition: background-color 0.25s ease-out,
color 0.25s ease-out;
// 12. Button Group
// ----------------
$buttongroup-margin: 0;
$buttongroup-spacing: 0;
$buttongroup-child-selector: '.button';
$buttongroup-expand-max: 6;
$buttongroup-radius-on-each: false;
// 13. Callout
// -----------
$callout-background: $white;
$callout-background-fade: 85%;
$callout-border: 1px solid rgba($black, 0.25);
$callout-margin: 0 0 0.625rem 0;
$callout-padding: 0.625rem;
$callout-font-color: $body-font-color;
$callout-font-color-alt: $body-background;
$callout-radius: $global-radius;
$callout-link-tint: 30%;
// 14. Card
// --------
$card-background: $white;
$card-font-color: $body-font-color;
$card-divider-background: $light-gray;
$card-border: 1px solid var(--color-border);
$card-shadow: var(--shadow-small);
$card-border-radius: var(--border-radius-normal);
$card-padding: var(--space-small);
$card-margin: $global-margin;
// 15. Close Button
// ----------------
$closebutton-position: right top;
$closebutton-offset-horizontal: (small: 0.66rem,
medium: 1rem);
$closebutton-offset-vertical: (small: 0.33em,
medium: 0.5rem);
$closebutton-size: (small: 1.5em,
medium: 2em);
$closebutton-lineheight: 1;
$closebutton-color: $dark-gray;
$closebutton-color-hover: $black;
// 16. Drilldown
// -------------
$drilldown-transition: transform 0.15s linear;
$drilldown-arrows: true;
$drilldown-arrow-color: $primary-color;
$drilldown-arrow-size: 6px;
$drilldown-background: $white;
// 17. Dropdown
// ------------
$dropdown-padding: 0.625rem;
$dropdown-background: $body-background;
$dropdown-border: 1px solid $medium-gray;
$dropdown-font-size: 0.625rem;
$dropdown-width: 300px;
$dropdown-radius: $global-radius;
$dropdown-sizes: (tiny: 100px,
small: 200px,
large: 400px);
// 18. Dropdown Menu
// -----------------
$dropdownmenu-arrows: true;
$dropdownmenu-arrow-color: $anchor-color;
$dropdownmenu-arrow-size: 6px;
$dropdownmenu-min-width: 200px;
$dropdownmenu-background: $white;
$dropdownmenu-border: 1px solid $medium-gray;
// 19. Forms
// ---------
$fieldset-border: 1px solid $light-gray;
$fieldset-padding: $space-two;
$fieldset-margin: $space-one $zero;
$legend-padding: rem-calc(0 3);
$form-spacing: $space-normal;
$helptext-color: $color-body;
$helptext-font-size: $font-size-small;
$helptext-font-style: italic;
$input-prefix-color: $color-body;
$input-prefix-background: var(--b-100);
$input-prefix-border: 1px solid $color-border;
$input-prefix-padding: 0.625rem;
$form-label-color: $color-body;
$form-label-font-size: rem-calc(14);
$form-label-font-weight: $font-weight-medium;
$form-label-line-height: 1.8;
$select-background: $white;
$select-triangle-color: $dark-gray;
$select-radius: var(--border-radius-normal);
$input-color: $color-body;
$input-placeholder-color: $light-gray;
$input-font-family: inherit;
$input-font-size: $font-size-default;
$input-font-weight: $global-weight-normal;
$input-background: $white;
$input-background-focus: $white;
$input-background-disabled: $light-gray;
$input-border: 1px solid var(--s-200);
$input-border-focus: 1px solid lighten($primary-color, 15%);
$input-shadow: 0;
$input-shadow-focus: 0;
$input-cursor-disabled: not-allowed;
$input-transition: border-color 0.25s ease-in-out;
$input-number-spinners: true;
$input-radius: var(--border-radius-normal);
$form-button-radius: var(--border-radius-normal);
// 20. Label
// ---------
$label-background: $white;
$label-color: $black;
$label-color-alt: $black;
$label-palette: $foundation-palette;
$label-font-size: $font-size-mini;
$label-padding: $space-smaller $space-small;
$label-radius: var(--border-radius-small);
// 21. Media Object
// ----------------
$mediaobject-margin-bottom: $global-margin;
$mediaobject-section-padding: $global-padding;
$mediaobject-image-width-stacked: 100%;
// 22. Menu
// --------
$menu-margin: 0;
$menu-margin-nested: $space-medium;
$menu-item-padding: $space-slab;
$menu-item-color-active: $white;
$menu-item-background-active: $color-background;
$menu-icon-spacing: 0.15625rem;
$menu-item-background-hover: $light-gray;
$menu-border: $light-gray;
// 23. Meter
// ---------
$meter-height: 0.625rem;
$meter-radius: $global-radius;
$meter-background: $medium-gray;
$meter-fill-good: $success-color;
$meter-fill-medium: $warning-color;
$meter-fill-bad: $alert-color;
// 24. Off-canvas
// --------------
$offcanvas-sizes: (small: 14.375,
medium: 14.375,
);
$offcanvas-vertical-sizes: (small: 14.375,
medium: 14.375,
);
$offcanvas-background: $light-gray;
$offcanvas-shadow: 0 0 10px rgba($black, 0.7);
$offcanvas-push-zindex: 1;
$offcanvas-overlap-zindex: 10;
$offcanvas-reveal-zindex: 1;
$offcanvas-transition-length: 0.5s;
$offcanvas-transition-timing: ease;
$offcanvas-fixed-reveal: true;
$offcanvas-exit-background: rgba($white, 0.25);
$maincontent-class: 'off-canvas-content';
// 25. Orbit
// ---------
$orbit-bullet-background: $medium-gray;
$orbit-bullet-background-active: $dark-gray;
$orbit-bullet-diameter: 0.75rem;
$orbit-bullet-margin: 0.0625rem;
$orbit-bullet-margin-top: 0.5rem;
$orbit-bullet-margin-bottom: 0.5rem;
$orbit-caption-background: rgba($black, 0.5);
$orbit-caption-padding: 0.625rem;
$orbit-control-background-hover: rgba($black, 0.5);
$orbit-control-padding: 0.625rem;
$orbit-control-zindex: 10;
// 26. Pagination
// --------------
$pagination-font-size: rem-calc(14);
$pagination-margin-bottom: $global-margin;
$pagination-item-color: $black;
$pagination-item-padding: rem-calc(3 10);
$pagination-item-spacing: rem-calc(1);
$pagination-radius: $global-radius;
$pagination-item-background-hover: $light-gray;
$pagination-item-background-current: $primary-color;
$pagination-item-color-current: $white;
$pagination-item-color-disabled: $medium-gray;
$pagination-ellipsis-color: $black;
$pagination-mobile-items: false;
$pagination-mobile-current-item: false;
$pagination-arrows: true;
// 27. Progress Bar
// ----------------
$progress-height: 0.625rem;
$progress-background: $medium-gray;
$progress-margin-bottom: $global-margin;
$progress-meter-background: $primary-color;
$progress-radius: $global-radius;
// 28. Responsive Embed
// --------------------
$responsive-embed-margin-bottom: rem-calc(16);
$responsive-embed-ratios: (default: 4 by 3,
widescreen: 16 by 9);
// 29. Reveal
// ----------
$reveal-background: $white;
$reveal-width: 600px;
$reveal-max-width: $global-width;
$reveal-padding: $global-padding;
$reveal-border: 1px solid $medium-gray;
$reveal-radius: $global-radius;
$reveal-zindex: 1005;
$reveal-overlay-background: rgba($black, 0.45);
// 30. Slider
// ----------
$slider-width-vertical: 0.3125rem;
$slider-transition: all 0.2s ease-in-out;
$slider-height: 0.3125rem;
$slider-background: $light-gray;
$slider-fill-background: $medium-gray;
$slider-handle-height: 0.875rem;
$slider-handle-width: 0.875rem;
$slider-handle-background: $primary-color;
$slider-opacity-disabled: 0.25;
$slider-radius: $global-radius;
// 31. Switch
// ----------
$switch-background: $light-gray;
$switch-background-active: $primary-color;
$switch-height: $space-two;
$switch-height-tiny: $space-slab;
$switch-height-small: $space-normal;
$switch-height-large: $space-large;
$switch-radius: $space-large;
$switch-margin: $global-margin;
$switch-paddle-background: $white;
$switch-paddle-offset: $space-micro;
$switch-paddle-radius: $space-large;
$switch-paddle-transition: all 0.15s ease-out;
// 32. Table
// ---------
$table-background: transparent;
$table-color-scale: 5%;
$table-border: 1px solid transparent;
$table-padding: rem-calc(8 10 10);
$table-hover-scale: 2%;
$table-row-hover: darken($table-background, $table-hover-scale);
$table-row-stripe-hover: darken($table-background,
$table-color-scale + $table-hover-scale);
$table-is-striped: false;
$table-striped-background: smart-scale($table-background, $table-color-scale);
$table-stripe: even;
$table-head-background: smart-scale($table-background, $table-color-scale / 2);
$table-head-row-hover: darken($table-head-background, $table-hover-scale);
$table-foot-background: smart-scale($table-background, $table-color-scale);
$table-foot-row-hover: darken($table-foot-background, $table-hover-scale);
$table-head-font-color: $body-font-color;
$table-foot-font-color: $body-font-color;
$show-header-for-stacked: false;
// 33. Tabs
// --------
$tab-margin: 0;
$tab-background: transparent;
$tab-background-active: transparent;
$tab-item-font-size: $font-size-small;
$tab-item-background-hover: transparent;
$tab-item-padding: $space-one $zero;
$tab-color: $primary-color;
$tab-active-color: $primary-color;
$tab-expand-max: 6;
$tab-content-background: transparent;
$tab-content-border: transparent;
$tab-content-color: foreground($tab-background, $primary-color);
$tab-content-padding: 0.625rem;
// 34. Thumbnail
// -------------
$thumbnail-border: solid 4px $white;
$thumbnail-margin-bottom: $global-margin;
$thumbnail-shadow: 0 0 0 1px rgba($black, 0.2);
$thumbnail-shadow-hover: 0 0 6px 1px rgba($primary-color, 0.5);
$thumbnail-transition: box-shadow 200ms ease-out;
$thumbnail-radius: $global-radius;
// 35. Title Bar
// -------------
$titlebar-background: $black;
$titlebar-color: $white;
$titlebar-padding: 0.3125rem;
$titlebar-text-font-weight: bold;
$titlebar-icon-color: $white;
$titlebar-icon-color-hover: $medium-gray;
$titlebar-icon-spacing: 0.15625rem;
// 36. Tooltip
// -----------
$has-tip-font-weight: $global-weight-bold;
$has-tip-border-bottom: dotted 1px $dark-gray;
$tooltip-background-color: $black;
$tooltip-color: $white;
$tooltip-padding: 0.46875rem;
$tooltip-font-size: $font-size-mini;
$tooltip-pip-width: 0.46875rem;
$tooltip-pip-height: $tooltip-pip-width * 0.866;
$tooltip-radius: $global-radius;
// 37. Top Bar
// -----------
$topbar-padding: 0.3125;
$topbar-background: $light-gray;
$topbar-submenu-background: $topbar-background;
$topbar-title-spacing: 0.3125 0.625rem 0.3125 0;
$topbar-input-width: 200px;
$topbar-unstack-breakpoint: medium;
// Internal variable that contains the flex justifying options
$-zf-flex-justify: -zf-flex-justify($global-text-direction);
$menu-items-padding: $space-one;
$xy-grid: false;
@@ -2,6 +2,11 @@
@apply bg-slate-25 dark:bg-slate-800;
}
.flex-center {
@include flex-align(center, middle);
display: flex;
}
.bottom-space-fix {
margin-bottom: auto;
}
@@ -1,5 +1,5 @@
@import 'dashboard/assets/scss/variables';
@import 'widget/assets/scss/mixins';
@import '~dashboard/assets/scss/variables';
@import '~widget/assets/scss/mixins';
$spinner-before-border-color: rgba(255, 255, 255, 0.7);
@@ -89,6 +89,9 @@ $swift-ease-out-duration: .4s !default;
$swift-ease-out-function: cubic-bezier(0.37, 0, 0.63, 1) !default;
$swift-ease-out: all $swift-ease-out-duration $swift-ease-out-function !default;
// Ionicons
$ionicons-font-path: '~ionicons/fonts';
// Transitions
$transition-ease-in: all 0.250s ease-in;
@@ -15,13 +15,36 @@
@import 'variables';
@import 'mixins';
@import 'foundation-settings';
@import 'helper-classes';
@import 'formulate';
@import 'date-picker';
@import 'foundation-sites/scss/foundation';
@include foundation-everything($flex: true);
@include foundation-prototype-text-utilities;
@include foundation-prototype-text-transformation;
@include foundation-prototype-text-decoration;
@include foundation-prototype-font-styling;
@include foundation-prototype-list-style-type;
@include foundation-prototype-rounded;
@include foundation-prototype-bordered;
@include foundation-prototype-shadow;
@include foundation-prototype-separator;
@include foundation-prototype-overflow;
@include foundation-prototype-display;
@include foundation-prototype-position;
@include foundation-prototype-border-box;
@include foundation-prototype-border-none;
@include foundation-prototype-sizing;
@include foundation-prototype-spacing;
@import 'typography';
@import 'layout';
@import 'animations';
@import 'foundation-custom';
@import 'rtl';
@import 'widgets/buttons';
@@ -29,11 +52,15 @@
@import 'widgets/conversation-card';
@import 'widgets/conversation-view';
@import 'widgets/forms';
@import 'widgets/login';
@import 'widgets/modal';
@import 'widgets/reply-box';
@import 'widgets/report';
@import 'widgets/search-box';
@import 'widgets/sidemenu';
@import 'widgets/snackbar';
@import 'widgets/states';
@import 'widgets/status-bar';
@import 'widgets/tabs';
@import 'widgets/woot-tables';
@@ -42,6 +69,7 @@
@import 'plugins/multiselect';
@import 'plugins/dropdown';
@import '~shared/assets/stylesheets/ionicons';
@import 'utility-helpers';
.tooltip {
@@ -10,14 +10,21 @@
@import 'variables';
@import 'vue-multiselect/dist/vue-multiselect.min.css';
@import '~shared/assets/stylesheets/ionicons';
@import 'mixins';
@import 'foundation-settings';
@import 'helper-classes';
@import 'foundation-sites/scss/foundation';
@include foundation-prototype-spacing;
@include foundation-everything($flex: true);
@import 'typography';
@import 'layout';
@import 'animations';
@import 'foundation-custom';
@import 'widgets/buttons';
@import 'widgets/forms';
@@ -0,0 +1,66 @@
.auth-wrap {
width: 100%;
}
// Outside login wrapper
.login {
@include full-height;
overflow-y: auto;
padding-top: $space-larger * 1.2;
.login__hero {
margin-bottom: $space-larger;
.hero__logo {
width: 180px;
}
.hero__title {
font-weight: $font-weight-light;
margin-top: $space-larger;
}
.hero__sub {
color: $medium-gray;
font-size: $font-size-medium;
}
}
// Login box
.login-box {
@include background-white;
@include border-normal;
@include elegant-card;
border-radius: $space-smaller;
padding: $space-large;
label {
color: $color-gray;
font-size: $font-size-default;
input {
font-size: $font-size-default;
height: $space-larger;
padding: $space-slab;
}
.error {
font-size: $font-size-small;
}
}
.button {
height: $space-larger;
}
}
.sigin__footer {
font-size: $font-size-default;
padding: $space-medium;
> a {
font-weight: $font-weight-bold;
}
}
}
@@ -1,5 +1,7 @@
.modal-mask {
@apply flex items-center justify-center bg-modal-backdrop-light dark:bg-modal-backdrop-dark z-[9990] h-full left-0 fixed top-0 w-full;
// @include flex;
// @include flex-align(center, middle);
@apply flex items-center justify-center bg-modal-backdrop-light dark:bg-modal-backdrop-dark z-[9990] h-full left-0 fixed top-0 w-full;
}
.page-top-bar {
@@ -43,6 +45,8 @@
}
.modal-footer {
// @include flex;
// @include flex-align($x: flex-end, $y: middle);
@apply flex justify-end items-center py-2 px-0 gap-2;
&.justify-content-end {
@@ -8,7 +8,7 @@
.reply-box__top {
.icon {
color: var(--slate-500);
color: $medium-gray;
cursor: pointer;
font-size: $font-size-medium;
margin-right: $space-small;
@@ -34,7 +34,7 @@
resize: none;
}
>textarea {
> textarea {
@include ghost-input();
background: transparent;
margin: 0;
@@ -52,7 +52,7 @@
.reply-box__top {
@apply bg-yellow-100 dark:bg-yellow-800;
>input {
> input {
@apply bg-yellow-100 dark:bg-yellow-800;
}
}
@@ -1,10 +1,45 @@
.side-menu {
i {
margin-right: var(--space-smaller);
min-width: var(--space-two);
}
}
.sidebar {
z-index: 1024 - 1;
//logo
.logo {
img {
max-height: 108px;
padding: $woot-logo-padding;
}
}
.nested {
a {
font-size: var(--font-size-small);
margin-bottom: var(--space-micro);
margin-top: var(--space-micro);
.inbox-icon {
display: inline-block;
margin-right: var(--space-micro);
min-width: var(--space-normal);
text-align: center;
}
}
}
}
// bottom-nav
.bottom-nav {
@include flex;
@include space-between-column;
@include border-normal-top;
flex-direction: column;
padding: var(--space-one) var(--space-normal) var(--space-one) var(--space-one);
padding: var(--space-one) var(--space-normal) var(--space-one)
var(--space-one);
position: relative;
&:hover {
@@ -13,7 +13,7 @@
<div class="flex items-center justify-between w-full">
<span
class="attribute-name"
:class="{ error: v$.editedValue.$error }"
:class="{ error: $v.editedValue.$error }"
>
{{ label }}
</span>
@@ -39,8 +39,8 @@
:type="inputType"
class="input-group-field"
autofocus="true"
:class="{ error: v$.editedValue.$error }"
@blur="v$.editedValue.$touch"
:class="{ error: $v.editedValue.$error }"
@blur="$v.editedValue.$touch"
@keyup.enter="onUpdate"
/>
<div class="input-group-button">
@@ -122,13 +122,12 @@
<script>
import { format, parseISO } from 'date-fns';
import { required, url } from '@vuelidate/validators';
import { required, url } from 'vuelidate/lib/validators';
import { BUS_EVENTS } from 'shared/constants/busEvents';
import MultiselectDropdown from 'shared/components/ui/MultiselectDropdown.vue';
import { isValidURL } from '../helper/URLHelper';
import customAttributeMixin from '../mixins/customAttributeMixin';
const DATE_FORMAT = 'yyyy-MM-dd';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -150,9 +149,6 @@ export default {
attributeKey: { type: String, required: true },
contactId: { type: Number, default: null },
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
isEditing: false,
@@ -210,13 +206,13 @@ export default {
return this.isAttributeTypeLink ? 'url' : this.attributeType;
},
shouldShowErrorMessage() {
return this.v$.editedValue.$error;
return this.$v.editedValue.$error;
},
errorMessage() {
if (this.v$.editedValue.url) {
if (this.$v.editedValue.url) {
return this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.INVALID_URL');
}
if (!this.v$.editedValue.regexValidation) {
if (!this.$v.editedValue.regexValidation) {
return this.regexCue
? this.regexCue
: this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.INVALID_INPUT');
@@ -284,8 +280,8 @@ export default {
this.attributeType === 'date'
? parseISO(this.editedValue)
: this.editedValue;
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
this.isEditing = false;
@@ -306,14 +302,11 @@ export default {
.checkbox-wrap {
@apply flex items-center;
}
.checkbox {
@apply my-0 mr-2 ml-0;
}
.attribute-name {
@apply w-full text-slate-800 dark:text-slate-100;
&.error {
@apply text-red-400 dark:text-red-500;
}
@@ -330,7 +323,6 @@ export default {
.value {
@apply bg-slate-50 dark:bg-slate-700 mb-0;
}
.edit-button {
@apply block;
}
@@ -340,12 +332,10 @@ export default {
::v-deep {
.selector-wrap {
@apply m-0 top-1;
.selector-name {
@apply ml-0;
}
}
.name {
@apply ml-0;
}
+15 -15
View File
@@ -1,29 +1,29 @@
/* eslint no-plusplus: 0 */
import AvatarUploader from './widgets/forms/AvatarUploader.vue';
import Bar from './widgets/chart/BarChart';
import Button from './ui/WootButton.vue';
import Code from './Code.vue';
import ColorPicker from './widgets/ColorPicker.vue';
import Button from './ui/WootButton';
import Code from './Code';
import ColorPicker from './widgets/ColorPicker';
import ConfirmDeleteModal from './widgets/modal/ConfirmDeleteModal.vue';
import ConfirmModal from './widgets/modal/ConfirmationModal.vue';
import ContextMenu from './ui/ContextMenu.vue';
import DeleteModal from './widgets/modal/DeleteModal.vue';
import DropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
import DropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
import FeatureToggle from './widgets/FeatureToggle.vue';
import DropdownItem from 'shared/components/ui/dropdown/DropdownItem';
import DropdownMenu from 'shared/components/ui/dropdown/DropdownMenu';
import FeatureToggle from './widgets/FeatureToggle';
import HorizontalBar from './widgets/chart/HorizontalBarChart';
import Input from './widgets/forms/Input.vue';
import PhoneInput from './widgets/forms/PhoneInput.vue';
import Label from './ui/Label.vue';
import LoadingState from './widgets/LoadingState.vue';
import Modal from './Modal.vue';
import ModalHeader from './ModalHeader.vue';
import ReportStatsCard from './widgets/ReportStatsCard.vue';
import SidemenuIcon from './SidemenuIcon.vue';
import Spinner from 'shared/components/Spinner.vue';
import SubmitButton from './buttons/FormSubmitButton.vue';
import Label from './ui/Label';
import LoadingState from './widgets/LoadingState';
import Modal from './Modal';
import ModalHeader from './ModalHeader';
import ReportStatsCard from './widgets/ReportStatsCard';
import SidemenuIcon from './SidemenuIcon';
import Spinner from 'shared/components/Spinner';
import SubmitButton from './buttons/FormSubmitButton';
import Tabs from './ui/Tabs/Tabs';
import TabsItem from './ui/Tabs/TabsItem.vue';
import TabsItem from './ui/Tabs/TabsItem';
import Thumbnail from './widgets/Thumbnail.vue';
const WootUIKit = {
@@ -19,13 +19,13 @@
<form class="flex flex-col w-full" @submit.prevent="addAccount">
<div class="w-full">
<label :class="{ error: v$.accountName.$error }">
<label :class="{ error: $v.accountName.$error }">
{{ $t('CREATE_ACCOUNT.FORM.NAME.LABEL') }}
<input
v-model.trim="accountName"
type="text"
:placeholder="$t('CREATE_ACCOUNT.FORM.NAME.PLACEHOLDER')"
@input="v$.accountName.$touch"
@input="$v.accountName.$touch"
/>
</label>
</div>
@@ -33,8 +33,8 @@
<div class="w-full">
<woot-submit-button
:disabled="
v$.accountName.$invalid ||
v$.accountName.$invalid ||
$v.accountName.$invalid ||
$v.accountName.$invalid ||
uiFlags.isCreating
"
:button-text="$t('CREATE_ACCOUNT.FORM.SUBMIT')"
@@ -49,10 +49,9 @@
</template>
<script>
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [alertMixin],
@@ -66,9 +65,6 @@ export default {
default: true,
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
accountName: '',
@@ -1,6 +1,4 @@
import { defineComponent } from 'vue';
export default defineComponent({
export default {
name: 'WootTabs',
props: {
index: {
@@ -75,25 +73,19 @@ export default defineComponent({
});
const leftButton = this.createScrollButton(createElement, 'left');
const rightButton = this.createScrollButton(createElement, 'right');
return createElement(
'div',
{
class: {
return (
<div
class={{
'tabs--container--with-border': this.border,
'tabs--container': true,
},
},
[
leftButton,
createElement(
'ul',
{
class: { tabs: true, 'tabs--with-scroll': this.hasScroll },
},
Tabs
),
rightButton,
]
}}
>
{leftButton}
<ul class={{ tabs: true, 'tabs--with-scroll': this.hasScroll }}>
{Tabs}
</ul>
{rightButton}
</div>
);
},
});
};
@@ -12,11 +12,11 @@
<woot-input
v-model="value"
type="text"
:class="{ error: v$.value.$error }"
:class="{ error: $v.value.$error }"
:placeholder="
$t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.KEY_PLACEHOLDER')
"
@blur="v$.value.$touch"
@blur="$v.value.$touch"
/>
</div>
<div class="flex flex-row justify-between gap-2 py-2 px-0 w-full">
@@ -27,7 +27,7 @@
<woot-button variant="clear" @click.prevent="onDismiss">
{{ $t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.BUTTONS.DISMISS') }}
</woot-button>
<woot-button :is-disabled="v$.value.$invalid">
<woot-button :is-disabled="$v.value.$invalid">
{{ $t('INTEGRATION_SETTINGS.OPEN_AI.CTA_MODAL.BUTTONS.FINISH') }}
</woot-button>
</div>
@@ -37,19 +37,15 @@
</template>
<script>
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import aiMixin from 'dashboard/mixins/aiMixin';
import alertMixin from 'shared/mixins/alertMixin';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [aiMixin, alertMixin, uiSettingsMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
value: '',
@@ -53,8 +53,8 @@ export default {
</script>
<style scoped lang="scss">
@import 'dashboard/assets/scss/variables';
@import 'dashboard/assets/scss/mixins';
@import '~dashboard/assets/scss/variables';
@import '~dashboard/assets/scss/mixins';
.colorpicker {
position: relative;
@@ -705,11 +705,10 @@ export default {
</script>
<style lang="scss">
@import '@chatwoot/prosemirror-schema/src/styles/base.scss';
@import '~@chatwoot/prosemirror-schema/src/styles/base.scss';
.ProseMirror-menubar-wrapper {
@apply flex flex-col;
.ProseMirror-menubar {
min-height: var(--space-two) !important;
@apply -ml-2.5 pb-0 bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-100;
@@ -718,7 +717,6 @@ export default {
@apply bg-slate-75 dark:bg-slate-800;
}
}
> .ProseMirror {
@apply p-0 break-words text-slate-800 dark:text-slate-100;
@@ -41,7 +41,7 @@
:show-query-operator="i !== appliedFilters.length - 1"
:show-user-input="showUserInput(appliedFilters[i].filter_operator)"
:grouped-filters="true"
:v="v$.appliedFilters.$each[i]"
:v="$v.appliedFilters.$each[i]"
@resetFilter="resetFilter(i, appliedFilters[i])"
@removeFilter="removeFilter(i)"
/>
@@ -80,7 +80,7 @@
<script>
import alertMixin from 'shared/mixins/alertMixin';
import { required, requiredIf } from '@vuelidate/validators';
import { required, requiredIf } from 'vuelidate/lib/validators';
import FilterInputBox from '../FilterInput/Index.vue';
import languages from './advancedFilterItems/languages';
import countries from 'shared/constants/countries.js';
@@ -89,7 +89,6 @@ import { filterAttributeGroups } from './advancedFilterItems';
import filterMixin from 'shared/mixins/filterMixin';
import * as OPERATORS from 'dashboard/components/widgets/FilterInput/FilterOperatorTypes.js';
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -118,9 +117,6 @@ export default {
default: false,
},
},
setup() {
return { v$: useVuelidate() };
},
validations: {
appliedFilters: {
required,
@@ -351,8 +347,8 @@ export default {
}
},
submitFilterQuery() {
this.v$.$touch();
if (this.v$.$invalid) return;
this.$v.$touch();
if (this.$v.$invalid) return;
this.$store.dispatch(
'setConversationFilters',
JSON.parse(JSON.stringify(this.appliedFilters))
@@ -45,14 +45,14 @@
}}</label>
</div>
<div v-if="sentToOtherEmailAddress" class="w-[50%] mt-1">
<label :class="{ error: v$.email.$error }">
<label :class="{ error: $v.email.$error }">
<input
v-model.trim="email"
type="text"
:placeholder="$t('EMAIL_TRANSCRIPT.FORM.EMAIL.PLACEHOLDER')"
@input="v$.email.$touch"
@input="$v.email.$touch"
/>
<span v-if="v$.email.$error" class="message">
<span v-if="$v.email.$error" class="message">
{{ $t('EMAIL_TRANSCRIPT.FORM.EMAIL.ERROR') }}
</span>
</label>
@@ -73,10 +73,8 @@
</template>
<script>
import { required, minLength, email } from '@vuelidate/validators';
import { required, minLength, email } from 'vuelidate/lib/validators';
import alertMixin from 'shared/mixins/alertMixin';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [alertMixin],
props: {
@@ -89,9 +87,6 @@ export default {
default: () => ({}),
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
email: '',
@@ -113,7 +108,7 @@ export default {
isFormValid() {
if (this.selectedType) {
if (this.sentToOtherEmailAddress) {
return !!this.email && !this.v$.email.$error;
return !!this.email && !this.$v.email.$error;
}
return true;
}
@@ -164,7 +164,7 @@ import ReplyTopPanel from 'dashboard/components/widgets/WootWriter/ReplyTopPanel
import ReplyEmailHead from './ReplyEmailHead.vue';
import ReplyBottomPanel from 'dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue';
import ArticleSearchPopover from 'dashboard/routes/dashboard/helpcenter/components/ArticleSearch/SearchPopover.vue';
import MessageSignatureMissingAlert from './MessageSignatureMissingAlert.vue';
import MessageSignatureMissingAlert from './MessageSignatureMissingAlert';
import Banner from 'dashboard/components/ui/Banner.vue';
import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
@@ -198,7 +198,7 @@ import {
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
import { LocalStorage } from 'shared/helpers/localStorage';
const EmojiInput = () => import('shared/components/emoji/EmojiInput.vue');
const EmojiInput = () => import('shared/components/emoji/EmojiInput');
export default {
components: {
@@ -1208,7 +1208,6 @@ export default {
@apply bg-yellow-50 dark:bg-yellow-200;
}
}
.send-button {
@apply mb-0;
}
@@ -1229,7 +1228,6 @@ export default {
.emoji-dialog--rtl {
@apply left-[unset] -right-80;
&::before {
transform: rotate(90deg);
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.08));
@@ -1,15 +1,15 @@
<template>
<div>
<div v-if="toEmails">
<div class="input-group small" :class="{ error: v$.toEmailsVal.$error }">
<div class="input-group small" :class="{ error: $v.toEmailsVal.$error }">
<label class="input-group-label">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.TO') }}
</label>
<div class="input-group-field">
<woot-input
v-model.trim="v$.toEmailsVal.$model"
v-model.trim="$v.toEmailsVal.$model"
type="text"
:class="{ error: v$.toEmailsVal.$error }"
:class="{ error: $v.toEmailsVal.$error }"
:placeholder="$t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.PLACEHOLDER')"
@blur="onBlur"
/>
@@ -17,15 +17,15 @@
</div>
</div>
<div class="input-group-wrap">
<div class="input-group small" :class="{ error: v$.ccEmailsVal.$error }">
<div class="input-group small" :class="{ error: $v.ccEmailsVal.$error }">
<label class="input-group-label">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.LABEL') }}
</label>
<div class="input-group-field">
<woot-input
v-model.trim="v$.ccEmailsVal.$model"
v-model.trim="$v.ccEmailsVal.$model"
type="text"
:class="{ error: v$.ccEmailsVal.$error }"
:class="{ error: $v.ccEmailsVal.$error }"
:placeholder="$t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.PLACEHOLDER')"
@blur="onBlur"
/>
@@ -39,20 +39,20 @@
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.ADD_BCC') }}
</woot-button>
</div>
<span v-if="v$.ccEmailsVal.$error" class="message">
<span v-if="$v.ccEmailsVal.$error" class="message">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.ERROR') }}
</span>
</div>
<div v-if="showBcc" class="input-group-wrap">
<div class="input-group small" :class="{ error: v$.bccEmailsVal.$error }">
<div class="input-group small" :class="{ error: $v.bccEmailsVal.$error }">
<label class="input-group-label">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.BCC.LABEL') }}
</label>
<div class="input-group-field">
<woot-input
v-model.trim="v$.bccEmailsVal.$model"
v-model.trim="$v.bccEmailsVal.$model"
type="text"
:class="{ error: v$.bccEmailsVal.$error }"
:class="{ error: $v.bccEmailsVal.$error }"
:placeholder="
$t('CONVERSATION.REPLYBOX.EMAIL_HEAD.BCC.PLACEHOLDER')
"
@@ -60,7 +60,7 @@
/>
</div>
</div>
<span v-if="v$.bccEmailsVal.$error" class="message">
<span v-if="$v.bccEmailsVal.$error" class="message">
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.BCC.ERROR') }}
</span>
</div>
@@ -137,7 +137,7 @@ export default {
this.showBcc = true;
},
onBlur() {
this.v$.$touch();
this.$v.$touch();
this.$emit('update:bccEmails', this.bccEmailsVal);
this.$emit('update:ccEmails', this.ccEmailsVal);
this.$emit('update:toEmails', this.toEmailsVal);
@@ -149,14 +149,12 @@ export default {
.input-group-wrap .message {
@apply text-sm text-red-500 dark:text-red-500;
}
.input-group {
@apply border-b border-solid border-slate-75 dark:border-slate-700 my-1;
.input-group-label {
@apply border-transparent bg-transparent text-xs font-semibold pl-0;
}
.input-group-field::v-deep input {
@apply mb-0 border-transparent;
}
@@ -164,7 +162,6 @@ export default {
.input-group.error {
@apply border-b-red-500 dark:border-b-red-500;
.input-group-label {
@apply text-red-500 dark:text-red-500;
}
@@ -45,9 +45,7 @@ const allKeysRequired = value => {
const keys = Object.keys(value);
return keys.every(key => value[key]);
};
import { useVuelidate } from '@vuelidate/core';
import { requiredIf } from '@vuelidate/validators';
import { requiredIf } from 'vuelidate/lib/validators';
export default {
props: {
template: {
@@ -55,9 +53,6 @@ export default {
default: () => {},
},
},
setup() {
return { v$: useVuelidate() };
},
validations: {
processedParams: {
requiredIfKeysPresent: requiredIf('variables'),
@@ -154,11 +149,9 @@ footer {
@apply ml-2.5;
}
}
.error {
@apply bg-red-100 dark:bg-red-100 rounded-md text-red-800 dark:text-red-800 p-2.5 text-center;
}
.template-input {
@apply bg-slate-25 dark:bg-slate-900 text-slate-700 dark:text-slate-100;
}
@@ -46,7 +46,7 @@ export default {
</script>
<style lang="scss" scoped>
@import 'dashboard/assets/scss/variables';
@import '~dashboard/assets/scss/variables';
.file {
display: flex;
@@ -1,4 +1,4 @@
import { email as emailValidator } from '@vuelidate/validators';
import emailValidator from 'vuelidate/lib/validators/email';
export const validEmailsByComma = value => {
if (!value.length) return true;
@@ -6,12 +6,12 @@
<woot-input
v-model="value"
type="text"
:class="{ error: v$.value.$error }"
:class="{ error: $v.value.$error }"
:placeholder="confirmPlaceHolderText"
@blur="v$.value.$touch"
@blur="$v.value.$touch"
/>
<div class="button-wrapper">
<woot-button color-scheme="alert" :is-disabled="v$.value.$invalid">
<woot-button color-scheme="alert" :is-disabled="$v.value.$invalid">
{{ confirmText }}
</woot-button>
<woot-button class="clear" @click.prevent="closeModal">
@@ -23,14 +23,14 @@
</template>
<script>
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import Modal from '../../Modal.vue';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
Modal,
},
props: {
show: {
type: Boolean,
@@ -61,9 +61,6 @@ export default {
default: '',
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
value: '',
@@ -150,8 +150,8 @@ export default {
}
},
submitAutomation() {
this.v$.$touch();
if (this.v$.$invalid) return;
this.$v.$touch();
if (this.$v.$invalid) return;
const automation = generateAutomationPayload(this.automation);
this.$emit('saveAutomation', automation, this.mode);
},
@@ -1,10 +1,6 @@
import { required, requiredIf } from '@vuelidate/validators';
import { useVuelidate } from '@vuelidate/core';
import { required, requiredIf } from 'vuelidate/lib/validators';
export default {
setup() {
return { v$: useVuelidate() };
},
validations: {
automation: {
name: {
@@ -8,12 +8,12 @@
<form class="w-full" @submit.prevent="addCustomAttribute">
<woot-input
v-model.trim="attributeName"
:class="{ error: v$.attributeName.$error }"
:class="{ error: $v.attributeName.$error }"
class="w-full"
:error="attributeNameError"
:label="$t('CUSTOM_ATTRIBUTES.FORM.NAME.LABEL')"
:placeholder="$t('CUSTOM_ATTRIBUTES.FORM.NAME.PLACEHOLDER')"
@input="v$.attributeName.$touch"
@input="$v.attributeName.$touch"
/>
<woot-input
v-model.trim="attributeValue"
@@ -23,7 +23,7 @@
/>
<div class="flex justify-end items-center py-2 px-0 gap-2">
<woot-button
:is-disabled="v$.attributeName.$invalid || isCreating"
:is-disabled="$v.attributeName.$invalid || isCreating"
:is-loading="isCreating"
>
{{ $t('CUSTOM_ATTRIBUTES.FORM.CREATE') }}
@@ -39,8 +39,7 @@
<script>
import Modal from 'dashboard/components/Modal.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { required, minLength } from '@vuelidate/validators';
import { useVuelidate } from '@vuelidate/core';
import { required, minLength } from 'vuelidate/lib/validators';
export default {
components: {
@@ -57,9 +56,6 @@ export default {
default: false,
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
attributeValue: '',
@@ -74,7 +70,7 @@ export default {
},
computed: {
attributeNameError() {
if (this.v$.attributeName.$error) {
if (this.$v.attributeName.$error) {
return this.$t('CUSTOM_ATTRIBUTES.FORM.NAME.ERROR');
}
return '';
@@ -4,7 +4,7 @@
<div>
<div
class="mt-1 multiselect-wrap--medium"
:class="{ error: v$.parentContact.$error }"
:class="{ error: $v.parentContact.$error }"
>
<label class="multiselect__label">
{{ $t('MERGE_CONTACTS.PARENT.TITLE') }}
@@ -52,7 +52,7 @@
{{ $t('AGENT_MGMT.SEARCH.NO_RESULTS') }}
</span>
</multiselect>
<span v-if="v$.parentContact.$error" class="message">
<span v-if="$v.parentContact.$error" class="message">
{{ $t('MERGE_CONTACTS.FORM.CHILD_CONTACT.ERROR') }}
</span>
</div>
@@ -115,8 +115,7 @@
<script>
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { useVuelidate } from '@vuelidate/core';
import { required } from 'vuelidate/lib/validators';
import MergeContactSummary from 'dashboard/modules/contact/components/MergeContactSummary.vue';
import ContactDropdownItem from './ContactDropdownItem.vue';
@@ -142,10 +141,6 @@ export default {
default: () => [],
},
},
setup() {
return { v$: useVuelidate() };
},
validations: {
primaryContact: {
required,
@@ -170,8 +165,8 @@ export default {
this.$emit('search', query);
},
onSubmit() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
this.$emit('submit', this.parentContact.id);
@@ -45,8 +45,7 @@ export default {
</script>
<style scoped lang="scss">
@import 'dashboard/assets/scss/variables.scss';
@import '~dashboard/assets/scss/variables.scss';
.footer-wrap {
width: 100%;
display: flex;
@@ -41,7 +41,7 @@
:dropdown-values="getDropdownValues(appliedFilters[i].attribute_key)"
:show-query-operator="i !== appliedFilters.length - 1"
:show-user-input="showUserInput(appliedFilters[i].filter_operator)"
:v="v$.appliedFilters.$each[i]"
:v="$v.appliedFilters.$each[i]"
@resetFilter="resetFilter(i, appliedFilters[i])"
@removeFilter="removeFilter(i)"
/>
@@ -90,7 +90,7 @@
<script>
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import FilterInputBox from '../../../../components/widgets/FilterInput/Index.vue';
import countries from 'shared/constants/countries.js';
import { mapGetters } from 'vuex';
@@ -98,8 +98,6 @@ import { filterAttributeGroups } from '../contactFilterItems';
import filterMixin from 'shared/mixins/filterMixin';
import * as OPERATORS from 'dashboard/components/widgets/FilterInput/FilterOperatorTypes.js';
import { CONTACTS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
FilterInputBox,
@@ -127,9 +125,6 @@ export default {
default: '',
},
},
setup() {
return { v$: useVuelidate() };
},
validations: {
appliedFilters: {
required,
@@ -319,8 +314,8 @@ export default {
}
},
submitFilterQuery() {
this.v$.$touch();
if (this.v$.$invalid) return;
this.$v.$touch();
if (this.$v.$invalid) return;
this.$store.dispatch(
'contacts/setContactFilters',
JSON.parse(JSON.stringify(this.appliedFilters))
@@ -27,7 +27,7 @@
</section>
</template>
<script lang="jsx">
<script>
import { mixin as clickaway } from 'vue-clickaway';
import { VeTable } from 'vue-easytable';
import { getCountryFlag } from 'dashboard/helper/flag';
@@ -18,38 +18,38 @@
</div>
<div>
<div class="w-full">
<label :class="{ error: v$.name.$error }">
<label :class="{ error: $v.name.$error }">
{{ $t('CONTACT_FORM.FORM.NAME.LABEL') }}
<input
v-model.trim="name"
type="text"
:placeholder="$t('CONTACT_FORM.FORM.NAME.PLACEHOLDER')"
@input="v$.name.$touch"
@input="$v.name.$touch"
/>
</label>
<label :class="{ error: v$.email.$error }">
<label :class="{ error: $v.email.$error }">
{{ $t('CONTACT_FORM.FORM.EMAIL_ADDRESS.LABEL') }}
<input
v-model.trim="email"
type="text"
:placeholder="$t('CONTACT_FORM.FORM.EMAIL_ADDRESS.PLACEHOLDER')"
@input="v$.email.$touch"
@input="$v.email.$touch"
/>
<span v-if="v$.email.$error" class="message">
<span v-if="$v.email.$error" class="message">
{{ $t('CONTACT_FORM.FORM.EMAIL_ADDRESS.ERROR') }}
</span>
</label>
</div>
</div>
<div class="w-full">
<label :class="{ error: v$.description.$error }">
<label :class="{ error: $v.description.$error }">
{{ $t('CONTACT_FORM.FORM.BIO.LABEL') }}
<textarea
v-model.trim="description"
type="text"
:placeholder="$t('CONTACT_FORM.FORM.BIO.PLACEHOLDER')"
@input="v$.description.$touch"
@input="$v.description.$touch"
/>
</label>
</div>
@@ -67,7 +67,7 @@
:error="isPhoneNumberNotValid"
:placeholder="$t('CONTACT_FORM.FORM.PHONE_NUMBER.PLACEHOLDER')"
@input="onPhoneNumberInputChange"
@blur="v$.phoneNumber.$touch"
@blur="$v.phoneNumber.$touch"
@setCode="setPhoneCode"
/>
<span v-if="isPhoneNumberNotValid" class="message">
@@ -151,11 +151,10 @@ import {
DuplicateContactException,
ExceptionWithMessage,
} from 'shared/helpers/CustomErrors';
import { required, email } from '@vuelidate/validators';
import { required, email } from 'vuelidate/lib/validators';
import countries from 'shared/constants/countries.js';
import { isPhoneNumberValid } from 'shared/helpers/Validators';
import parsePhoneNumber from 'libphonenumber-js';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [alertMixin],
@@ -173,9 +172,6 @@ export default {
default: () => {},
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
countries: countries,
@@ -368,8 +364,8 @@ export default {
}
},
async handleSubmit() {
this.v$.$touch();
if (this.v$.$invalid || this.isPhoneNumberNotValid) {
this.$v.$touch();
if (this.$v.$invalid || this.isPhoneNumberNotValid) {
return;
}
try {
@@ -13,7 +13,7 @@
</label>
<div
class="multiselect-wrap--small"
:class="{ 'has-multi-select-error': v$.targetInbox.$error }"
:class="{ 'has-multi-select-error': $v.targetInbox.$error }"
>
<multiselect
v-model="targetInbox"
@@ -47,8 +47,8 @@
</template>
</multiselect>
</div>
<label :class="{ error: v$.targetInbox.$error }">
<span v-if="v$.targetInbox.$error" class="message">
<label :class="{ error: $v.targetInbox.$error }">
<span v-if="$v.targetInbox.$error" class="message">
{{ $t('NEW_CONVERSATION.FORM.INBOX.ERROR') }}
</span>
</label>
@@ -76,15 +76,15 @@
</div>
<div v-if="isAnEmailInbox" class="w-full">
<div class="w-full">
<label :class="{ error: v$.subject.$error }">
<label :class="{ error: $v.subject.$error }">
{{ $t('NEW_CONVERSATION.FORM.SUBJECT.LABEL') }}
<input
v-model="subject"
type="text"
:placeholder="$t('NEW_CONVERSATION.FORM.SUBJECT.PLACEHOLDER')"
@input="v$.subject.$touch"
@input="$v.subject.$touch"
/>
<span v-if="v$.subject.$error" class="message">
<span v-if="$v.subject.$error" class="message">
{{ $t('NEW_CONVERSATION.FORM.SUBJECT.ERROR') }}
</span>
</label>
@@ -112,13 +112,13 @@
<woot-message-editor
v-model="message"
class="message-editor"
:class="{ editor_warning: v$.message.$error }"
:class="{ editor_warning: $v.message.$error }"
:enable-variables="true"
:signature="signatureToApply"
:allow-signature="true"
:placeholder="$t('NEW_CONVERSATION.FORM.MESSAGE.PLACEHOLDER')"
@toggle-canned-menu="toggleCannedMenu"
@blur="v$.message.$touch"
@blur="$v.message.$touch"
>
<template #footer>
<message-signature-missing-alert
@@ -138,7 +138,7 @@
</div>
</template>
</woot-message-editor>
<span v-if="v$.message.$error" class="editor-warning__message">
<span v-if="$v.message.$error" class="editor-warning__message">
{{ $t('NEW_CONVERSATION.FORM.MESSAGE.ERROR') }}
</span>
</div>
@@ -149,16 +149,16 @@
@on-select-template="toggleWaTemplate"
@on-send="onSendWhatsAppReply"
/>
<label v-else :class="{ error: v$.message.$error }">
<label v-else :class="{ error: $v.message.$error }">
{{ $t('NEW_CONVERSATION.FORM.MESSAGE.LABEL') }}
<textarea
v-model="message"
class="min-h-[5rem]"
type="text"
:placeholder="$t('NEW_CONVERSATION.FORM.MESSAGE.PLACEHOLDER')"
@input="v$.message.$touch"
@input="$v.message.$touch"
/>
<span v-if="v$.message.$error" class="message">
<span v-if="$v.message.$error" class="message">
{{ $t('NEW_CONVERSATION.FORM.MESSAGE.ERROR') }}
</span>
</label>
@@ -240,17 +240,17 @@ import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import ReplyEmailHead from 'dashboard/components/widgets/conversation/ReplyEmailHead.vue';
import CannedResponse from 'dashboard/components/widgets/conversation/CannedResponse.vue';
import MessageSignatureMissingAlert from 'dashboard/components/widgets/conversation/MessageSignatureMissingAlert.vue';
import MessageSignatureMissingAlert from 'dashboard/components/widgets/conversation/MessageSignatureMissingAlert';
import InboxDropdownItem from 'dashboard/components/widgets/InboxDropdownItem.vue';
import WhatsappTemplates from './WhatsappTemplates.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { INBOX_TYPES } from 'shared/mixins/inboxMixin';
import { ExceptionWithMessage } from 'shared/helpers/CustomErrors';
import { getInboxSource } from 'dashboard/helper/inbox';
import { required, requiredIf } from '@vuelidate/validators';
import { required, requiredIf } from 'vuelidate/lib/validators';
import inboxMixin from 'shared/mixins/inboxMixin';
import FileUpload from 'vue-upload-component';
import AttachmentPreview from 'dashboard/components/widgets/AttachmentsPreview.vue';
import AttachmentPreview from 'dashboard/components/widgets/AttachmentsPreview';
import { ALLOWED_FILE_TYPES } from 'shared/constants/messages';
import fileUploadMixin from 'dashboard/mixins/fileUploadMixin';
import {
@@ -258,7 +258,6 @@ import {
removeSignature,
} from 'dashboard/helper/editorHelper';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -287,9 +286,6 @@ export default {
default: '',
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
name: '',
@@ -498,8 +494,8 @@ export default {
},
onFormSubmit() {
const isFromWhatsApp = false;
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
this.createConversation({
@@ -575,7 +571,6 @@ export default {
.file-uploads {
@apply text-start;
}
.multiselect-wrap--small.has-multi-select-error {
::v-deep {
.multiselect__tags {
@@ -588,11 +583,9 @@ export default {
.mention--box {
@apply left-0 m-auto right-0 top-auto h-fit;
}
.multiselect .multiselect__content .multiselect__option span {
@apply inline-flex w-6 text-slate-600 dark:text-slate-400;
}
.multiselect .multiselect__content .multiselect__option {
@apply py-0.5 px-1;
}
@@ -1,6 +1,6 @@
/* eslint arrow-body-style: 0 */
import { frontendURL } from '../../../helper/URLHelper';
const ConversationView = () => import('./ConversationView.vue');
const ConversationView = () => import('./ConversationView');
export default {
routes: [
@@ -8,11 +8,11 @@
:label="$t('FILTER.CUSTOM_VIEWS.ADD.LABEL')"
type="text"
:error="
v$.name.$error ? $t('FILTER.CUSTOM_VIEWS.ADD.ERROR_MESSAGE') : ''
$v.name.$error ? $t('FILTER.CUSTOM_VIEWS.ADD.ERROR_MESSAGE') : ''
"
:class="{ error: v$.name.$error }"
:class="{ error: $v.name.$error }"
:placeholder="$t('FILTER.CUSTOM_VIEWS.ADD.PLACEHOLDER')"
@blur="v$.name.$touch"
@blur="$v.name.$touch"
/>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
@@ -29,10 +29,9 @@
</template>
<script>
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import alertMixin from 'shared/mixins/alertMixin';
import { CONTACTS_EVENTS } from '../../../helper/AnalyticsHelper/events';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [alertMixin],
@@ -50,9 +49,7 @@ export default {
default: () => {},
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
show: true,
@@ -62,7 +59,7 @@ export default {
computed: {
isButtonDisabled() {
return this.v$.name.$invalid;
return this.$v.name.$invalid;
},
},
@@ -78,8 +75,8 @@ export default {
this.$emit('close');
},
async saveCustomViews() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
try {
@@ -7,7 +7,7 @@
/>
<form class="w-full" @submit.prevent="onCreate">
<div class="w-full">
<label :class="{ error: v$.selectedLocale.$error }">
<label :class="{ error: $v.selectedLocale.$error }">
{{ $t('HELP_CENTER.PORTAL.ADD_LOCALE.LOCALE.LABEL') }}
<select v-model="selectedLocale">
<option
@@ -18,7 +18,7 @@
{{ locale.name }}-{{ locale.code }}
</option>
</select>
<span v-if="v$.selectedLocale.$error" class="message">
<span v-if="$v.selectedLocale.$error" class="message">
{{ $t('HELP_CENTER.PORTAL.ADD_LOCALE.LOCALE.ERROR') }}
</span>
</label>
@@ -41,11 +41,9 @@
<script>
import Modal from 'dashboard/components/Modal.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import allLocales from 'shared/constants/locales.js';
import { PORTALS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
Modal,
@@ -61,9 +59,6 @@ export default {
default: () => ({}),
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
selectedLocale: '',
@@ -99,8 +94,8 @@ export default {
},
methods: {
async onCreate() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
const updatedLocales = this.addedLocales;
@@ -142,7 +137,6 @@ export default {
input {
margin-bottom: 0;
}
.message {
margin-top: 0;
}
@@ -59,7 +59,7 @@
</template>
<script>
import { mapGetters } from 'vuex';
import UpgradePage from './UpgradePage.vue';
import UpgradePage from './UpgradePage';
import { frontendURL } from '../../../../helper/URLHelper';
import Sidebar from 'dashboard/components/layout/Sidebar.vue';
import { BUS_EVENTS } from 'shared/constants/busEvents';
@@ -42,35 +42,35 @@
<div class="mb-4">
<woot-input
v-model.trim="name"
:class="{ error: v$.name.$error }"
:class="{ error: $v.name.$error }"
:error="nameError"
:label="$t('HELP_CENTER.PORTAL.ADD.NAME.LABEL')"
:placeholder="$t('HELP_CENTER.PORTAL.ADD.NAME.PLACEHOLDER')"
:help-text="$t('HELP_CENTER.PORTAL.ADD.NAME.HELP_TEXT')"
@blur="v$.name.$touch"
@blur="$v.name.$touch"
@input="onNameChange"
/>
</div>
<div class="mb-4">
<woot-input
v-model.trim="slug"
:class="{ error: v$.slug.$error }"
:class="{ error: $v.slug.$error }"
:error="slugError"
:label="$t('HELP_CENTER.PORTAL.ADD.SLUG.LABEL')"
:placeholder="$t('HELP_CENTER.PORTAL.ADD.SLUG.PLACEHOLDER')"
:help-text="domainHelpText"
@blur="v$.slug.$touch"
@blur="$v.slug.$touch"
/>
</div>
<div class="mb-4">
<woot-input
v-model.trim="domain"
:class="{ error: v$.domain.$error }"
:class="{ error: $v.domain.$error }"
:label="$t('HELP_CENTER.PORTAL.ADD.DOMAIN.LABEL')"
:placeholder="$t('HELP_CENTER.PORTAL.ADD.DOMAIN.PLACEHOLDER')"
:help-text="domainExampleHelpText"
:error="domainError"
@blur="v$.domain.$touch"
@blur="$v.domain.$touch"
/>
</div>
</div>
@@ -78,7 +78,7 @@
<div class="flex-end">
<woot-button
:is-loading="isSubmitting"
:is-disabled="v$.$invalid"
:is-disabled="$v.$invalid"
@click="onSubmitClick"
>
{{ submitButtonText }}
@@ -88,9 +88,8 @@
</template>
<script>
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import { isDomain } from 'shared/helpers/Validators';
import { useVuelidate } from '@vuelidate/core';
import alertMixin from 'shared/mixins/alertMixin';
import { convertToCategorySlug } from 'dashboard/helper/commons.js';
@@ -119,9 +118,6 @@ export default {
default: '',
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
name: '',
@@ -148,19 +144,19 @@ export default {
},
computed: {
nameError() {
if (this.v$.name.$error) {
if (this.$v.name.$error) {
return this.$t('HELP_CENTER.CATEGORY.ADD.NAME.ERROR');
}
return '';
},
slugError() {
if (this.v$.slug.$error) {
if (this.$v.slug.$error) {
return this.$t('HELP_CENTER.CATEGORY.ADD.SLUG.ERROR');
}
return '';
},
domainError() {
if (this.v$.domain.$error) {
if (this.$v.domain.$error) {
return this.$t('HELP_CENTER.PORTAL.ADD.DOMAIN.ERROR');
}
return '';
@@ -196,8 +192,8 @@ export default {
this.slug = convertToCategorySlug(this.name);
},
onSubmitClick() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
@@ -255,7 +251,6 @@ export default {
input {
@apply mb-1;
}
.help-text {
@apply mb-0;
}
@@ -47,12 +47,12 @@
"
:help-text="homepageExampleHelpText"
:error="
v$.homePageLink.$error
$v.homePageLink.$error
? $t('HELP_CENTER.PORTAL.ADD.HOME_PAGE_LINK.ERROR')
: ''
"
:class="{ error: v$.homePageLink.$error }"
@blur="v$.homePageLink.$touch"
:class="{ error: $v.homePageLink.$error }"
@blur="$v.homePageLink.$touch"
/>
</div>
</div>
@@ -60,7 +60,7 @@
<div class="flex-end">
<woot-button
:is-loading="isSubmitting"
:is-disabled="v$.$invalid"
:is-disabled="$v.$invalid"
@click="onSubmitClick"
>
{{
@@ -74,9 +74,8 @@
</template>
<script>
import { url } from '@vuelidate/validators';
import { url } from 'vuelidate/lib/validators';
import { getRandomColor } from 'dashboard/helper/labelColor';
import { useVuelidate } from '@vuelidate/core';
import alertMixin from 'shared/mixins/alertMixin';
import wootConstants from 'dashboard/constants/globals';
@@ -84,6 +83,7 @@ import wootConstants from 'dashboard/constants/globals';
const { EXAMPLE_URL } = wootConstants;
export default {
components: {},
mixins: [alertMixin],
props: {
portal: {
@@ -95,9 +95,6 @@ export default {
default: false,
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
color: '#000',
@@ -135,8 +132,8 @@ export default {
}
},
onSubmitClick() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
const portal = {
@@ -161,11 +158,9 @@ export default {
input {
@apply mb-1;
}
.help-text {
@apply mb-0;
}
.colorpicker--selected {
@apply mb-0;
}
@@ -1,32 +1,30 @@
import HelpCenterLayout from './components/HelpCenterLayout.vue';
import HelpCenterLayout from './components/HelpCenterLayout';
import { getPortalRoute } from './helpers/routeHelper';
const ListAllPortals = () => import('./pages/portals/ListAllPortals.vue');
const NewPortal = () => import('./pages/portals/NewPortal.vue');
const ListAllPortals = () => import('./pages/portals/ListAllPortals');
const NewPortal = () => import('./pages/portals/NewPortal');
const EditPortal = () => import('./pages/portals/EditPortal.vue');
const EditPortalBasic = () => import('./pages/portals/EditPortalBasic.vue');
const EditPortal = () => import('./pages/portals/EditPortal');
const EditPortalBasic = () => import('./pages/portals/EditPortalBasic');
const EditPortalCustomization = () =>
import('./pages/portals/EditPortalCustomization.vue');
import('./pages/portals/EditPortalCustomization');
const EditPortalLocales = () => import('./pages/portals/EditPortalLocales.vue');
const ShowPortal = () => import('./pages/portals/ShowPortal.vue');
const PortalDetails = () => import('./pages/portals/PortalDetails.vue');
const PortalCustomization = () =>
import('./pages/portals/PortalCustomization.vue');
const ShowPortal = () => import('./pages/portals/ShowPortal');
const PortalDetails = () => import('./pages/portals/PortalDetails');
const PortalCustomization = () => import('./pages/portals/PortalCustomization');
const PortalSettingsFinish = () =>
import('./pages/portals/PortalSettingsFinish.vue');
import('./pages/portals/PortalSettingsFinish');
const ListAllCategories = () =>
import('./pages/categories/ListAllCategories.vue');
const NewCategory = () => import('./pages/categories/NewCategory.vue');
const EditCategory = () => import('./pages/categories/EditCategory.vue');
const ListAllCategories = () => import('./pages/categories/ListAllCategories');
const NewCategory = () => import('./pages/categories/NewCategory');
const EditCategory = () => import('./pages/categories/EditCategory');
const ListCategoryArticles = () =>
import('./pages/articles/ListCategoryArticles.vue');
const ListAllArticles = () => import('./pages/articles/ListAllArticles.vue');
import('./pages/articles/ListCategoryArticles');
const ListAllArticles = () => import('./pages/articles/ListAllArticles');
const DefaultPortalArticles = () =>
import('./pages/articles/DefaultPortalArticles.vue');
const NewArticle = () => import('./pages/articles/NewArticle.vue');
const EditArticle = () => import('./pages/articles/EditArticle.vue');
import('./pages/articles/DefaultPortalArticles');
const NewArticle = () => import('./pages/articles/NewArticle');
const EditArticle = () => import('./pages/articles/EditArticle');
const portalRoutes = [
{
@@ -25,20 +25,20 @@
:label="$t('HELP_CENTER.CATEGORY.ADD.NAME.LABEL')"
:placeholder="$t('HELP_CENTER.CATEGORY.ADD.NAME.PLACEHOLDER')"
:help-text="$t('HELP_CENTER.CATEGORY.ADD.NAME.HELP_TEXT')"
:has-error="v$.name.$error"
:has-error="$v.name.$error"
:error-message="$t('HELP_CENTER.CATEGORY.ADD.NAME.ERROR')"
@name-change="onNameChange"
@icon-change="onClickInsertEmoji"
/>
<woot-input
v-model.trim="slug"
:class="{ error: v$.slug.$error }"
:class="{ error: $v.slug.$error }"
class="w-full"
:error="slugError"
:label="$t('HELP_CENTER.CATEGORY.ADD.SLUG.LABEL')"
:placeholder="$t('HELP_CENTER.CATEGORY.ADD.SLUG.PLACEHOLDER')"
:help-text="$t('HELP_CENTER.CATEGORY.ADD.SLUG.HELP_TEXT')"
@input="v$.slug.$touch"
@input="$v.slug.$touch"
/>
<label>
{{ $t('HELP_CENTER.CATEGORY.ADD.DESCRIPTION.LABEL') }}
@@ -68,11 +68,10 @@
<script>
import alertMixin from 'shared/mixins/alertMixin';
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import { convertToCategorySlug } from 'dashboard/helper/commons.js';
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
import CategoryNameIconInput from './NameEmojiInput.vue';
import { useVuelidate } from '@vuelidate/core';
export default {
components: { CategoryNameIconInput },
@@ -95,9 +94,6 @@ export default {
default: '',
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
name: '',
@@ -122,7 +118,7 @@ export default {
: this.portalSlug;
},
slugError() {
if (this.v$.slug.$error) {
if (this.$v.slug.$error) {
return this.$t('HELP_CENTER.CATEGORY.ADD.SLUG.ERROR');
}
return '';
@@ -152,8 +148,8 @@ export default {
description,
locale,
};
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
try {
@@ -25,7 +25,7 @@
:label="$t('HELP_CENTER.CATEGORY.EDIT.NAME.LABEL')"
:placeholder="$t('HELP_CENTER.CATEGORY.EDIT.NAME.PLACEHOLDER')"
:help-text="$t('HELP_CENTER.CATEGORY.EDIT.NAME.HELP_TEXT')"
:has-error="v$.name.$error"
:has-error="$v.name.$error"
:error-message="$t('HELP_CENTER.CATEGORY.ADD.NAME.ERROR')"
:existing-name="category.name"
:saved-icon="category.icon"
@@ -34,13 +34,13 @@
/>
<woot-input
v-model.trim="slug"
:class="{ error: v$.slug.$error }"
:class="{ error: $v.slug.$error }"
class="w-full"
:error="slugError"
:label="$t('HELP_CENTER.CATEGORY.EDIT.SLUG.LABEL')"
:placeholder="$t('HELP_CENTER.CATEGORY.EDIT.SLUG.PLACEHOLDER')"
:help-text="$t('HELP_CENTER.CATEGORY.EDIT.SLUG.HELP_TEXT')"
@input="v$.slug.$touch"
@input="$v.slug.$touch"
/>
<label>
{{ $t('HELP_CENTER.CATEGORY.EDIT.DESCRIPTION.LABEL') }}
@@ -70,11 +70,10 @@
<script>
import alertMixin from 'shared/mixins/alertMixin';
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import { convertToCategorySlug } from 'dashboard/helper/commons.js';
import { PORTALS_EVENTS } from '../../../../../helper/AnalyticsHelper/events';
import CategoryNameIconInput from './NameEmojiInput.vue';
import { useVuelidate } from '@vuelidate/core';
export default {
components: { CategoryNameIconInput },
@@ -101,9 +100,6 @@ export default {
default: '',
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
id: this.category.id,
@@ -124,7 +120,7 @@ export default {
},
computed: {
slugError() {
if (this.v$.slug.$error) {
if (this.$v.slug.$error) {
return this.$t('HELP_CENTER.CATEGORY.ADD.SLUG.ERROR');
}
return '';
@@ -163,8 +159,8 @@ export default {
slug,
description,
};
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
try {
@@ -194,7 +190,6 @@ export default {
.article-info {
width: 100%;
margin: 0 0 var(--space-normal);
.value {
color: var(--s-600);
}
@@ -38,7 +38,7 @@
<script>
import { mixin as clickaway } from 'vue-clickaway';
const EmojiInput = () => import('shared/components/emoji/EmojiInput.vue');
const EmojiInput = () => import('shared/components/emoji/EmojiInput');
export default {
components: { EmojiInput },
@@ -0,0 +1,70 @@
<script setup>
// import { defineProps } from 'vue';
import PriorityIcon from './components/PriorityIcon.vue';
import StatusIcon from './components/StatusIcon.vue';
import InboxNameAndId from './components/InboxNameAndId.vue';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
// const props = defineProps({
// notificationItem: {
// type: Object,
// default: () => {},
// },
// });
const assigneeMeta = {
thumbnail: '',
name: 'Michael Johnson',
};
const { thumbnail, name } = assigneeMeta || {};
const status = 'open';
const priority = 'high';
const inboxTypeMessage = 'Mentioned by Michael';
const inboxMessage = 'What is the best way to get started?';
const inbox = {
inbox_id: 16787,
inbox_name: 'Chatwoot Support',
};
</script>
<template>
<div
class="flex max-w-[360px] flex-col pl-5 pr-3 gap-2.5 py-3 w-full bg-white dark:bg-slate-900 border-b border-slate-200 dark:border-slate-500 hover:bg-slate-25 dark:hover:bg-slate-800 cursor-pointer"
>
<div class="flex relative items-center justify-between w-full">
<div
class="absolute -left-3.5 flex w-2 h-2 rounded bg-woot-500 dark:bg-woot-500"
/>
<InboxNameAndId :inbox="inbox" />
<div class="flex gap-2">
<PriorityIcon :priority="priority" />
<StatusIcon :status="status" />
</div>
</div>
<div class="flex flex-row justify-between items-center w-full">
<div class="flex gap-1.5 items-center max-w-[80%]">
<Thumbnail
v-if="assigneeMeta"
:src="thumbnail"
:username="name"
size="20px"
/>
<div class="flex min-w-0">
<span
class="font-medium text-slate-800 dark:text-slate-100 text-xs overflow-hidden text-ellipsis whitespace-nowrap"
>
{{ inboxTypeMessage }}<span v-if="inboxTypeMessage">:</span>
<span class="font-normal">{{ inboxMessage }}</span>
</span>
</div>
</div>
<span
class="font-medium text-slate-600 dark:text-slate-300 text-xs whitespace-nowrap"
>
10h ago
</span>
</div>
</div>
</template>
@@ -0,0 +1,34 @@
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
inbox: {
type: Object,
default: () => {},
},
});
const { inbox } = props;
const { inbox_id: inboxId, inbox_name: inboxName } = inbox;
</script>
<template>
<div
class="inline-flex items-center rounded-[4px] border border-slate-100 dark:border-slate-600 divide-x divide-slate-100 dark:divide-slate-600 bg-none"
>
<div class="flex items-center gap-0.5 py-0.5 px-1.5">
<fluent-icon
class="text-slate-600 dark:text-slate-300"
icon="globe-desktop"
size="14"
/>
<span class="font-medium text-slate-600 dark:text-slate-300 text-xs">
{{ inboxName }}
</span>
</div>
<div class="flex items-center py-0.5 px-1.5">
<span class="font-medium text-slate-600 dark:text-slate-300 text-xs">
{{ inboxId }}
</span>
</div>
</div>
</template>
@@ -0,0 +1,75 @@
<script setup>
import { CONVERSATION_PRIORITY } from 'shared/constants/messages';
import { defineProps } from 'vue';
const props = defineProps({
priority: {
type: String,
default: '',
},
});
</script>
<template>
<div class="inline-flex items-center justify-center rounded-md">
<!-- High Priority -->
<svg
v-if="props.priority === CONVERSATION_PRIORITY.HIGH"
class="h-4 w-4"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect x="4" y="12" width="4" height="8" rx="1" fill="#FFC291" />
<rect x="10" y="8" width="4" height="12" rx="1" fill="#FFC291" />
<rect x="16" y="4" width="4" height="16" rx="1" fill="#FFC291" />
</svg>
<!-- Low Priority -->
<svg
v-if="props.priority === CONVERSATION_PRIORITY.LOW"
class="h-4 w-4"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect x="4" y="12" width="4" height="8" rx="1" fill="#FFC291" />
<rect x="10" y="8" width="4" height="12" rx="1" fill="#DDDDDD" />
<rect x="16" y="4" width="4" height="16" rx="1" fill="#DDDDDD" />
</svg>
<!-- Medium Priority -->
<svg
v-if="props.priority === CONVERSATION_PRIORITY.MEDIUM"
class="h-4 w-4"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect x="4" y="12" width="4" height="8" rx="1" fill="#FFC291" />
<rect x="10" y="8" width="4" height="12" rx="1" fill="#FFC291" />
<rect x="16" y="4" width="4" height="16" rx="1" fill="#DDDDDD" />
</svg>
<!-- Urgent Priority -->
<svg
v-if="props.priority === CONVERSATION_PRIORITY.URGENT"
class="h-4 w-4"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect x="4" y="12" width="4" height="8" rx="1" fill="#E5484D" />
<rect x="10" y="8" width="4" height="12" rx="1" fill="#E5484D" />
<rect x="16" y="4" width="4" height="16" rx="1" fill="#E5484D" />
</svg>
</div>
</template>
@@ -0,0 +1,80 @@
<script setup>
import { CONVERSATION_STATUS } from 'shared/constants/messages';
import { defineProps } from 'vue';
const props = defineProps({
status: {
type: String,
default: '',
},
});
</script>
<template>
<div class="inline-flex items-center justify-center rounded-md">
<!-- Pending -->
<svg
v-if="props.status === CONVERSATION_STATUS.PENDING"
class="h-3.5 w-3.5"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.1 0.0449978V1.8558C4.5486 2.2986 1.8 5.328 1.8 9C1.8 12.9762 5.0238 16.2 9 16.2C10.6641 16.2 12.195 15.6357 13.4154 14.688L14.6961 15.9687C13.1445 17.2377 11.16 18 9 18C4.0293 18 0 13.9707 0 9C0 4.3335 3.5523 0.495898 8.1 0.0449978ZM17.955 9.9C17.775 11.7099 17.0604 13.3623 15.9687 14.6952L14.688 13.4154C15.462 12.4191 15.9804 11.2149 16.1442 9.9H17.9559H17.955ZM9.9018 0.0449978C14.1534 0.467098 17.5338 3.8484 17.9568 8.1H16.1451C15.7392 4.8438 13.158 2.2626 9.9018 1.8558V0.0440979V0.0449978Z"
class="fill-[#B9BBC6]"
/>
</svg>
<!-- Open -->
<svg
v-if="props.status === CONVERSATION_STATUS.OPEN"
class="h-3.5 w-3.5"
width="19"
height="19"
viewBox="0 0 19 19"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.375 18.875C4.19733 18.875 0 14.6776 0 9.5C0 4.32233 4.19733 0.125 9.375 0.125C14.5526 0.125 18.75 4.32233 18.75 9.5C18.75 14.6776 14.5526 18.875 9.375 18.875ZM9.375 17C13.5172 17 16.875 13.6422 16.875 9.5C16.875 5.35786 13.5172 2 9.375 2C5.23286 2 1.875 5.35786 1.875 9.5C1.875 13.6422 5.23286 17 9.375 17Z"
class="fill-[#ED8A5C]"
/>
</svg>
<!-- Snoozed -->
<svg
v-if="props.status === CONVERSATION_STATUS.SNOOZED"
class="h-3.5 w-3.5"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9 18C4.0293 18 0 13.9707 0 9C0 4.0293 4.0293 0 9 0C13.9707 0 18 4.0293 18 9C18 13.9707 13.9707 18 9 18ZM2.9961 12.9825C3.58766 13.8676 4.36812 14.6105 5.28129 15.1577C6.19446 15.7049 7.21761 16.0428 8.27707 16.147C9.33652 16.2513 10.4059 16.1193 11.4082 15.7606C12.4105 15.4019 13.3208 14.8254 14.0736 14.0726C14.8263 13.3198 15.4027 12.4094 15.7613 11.4071C16.12 10.4047 16.2518 9.33532 16.1475 8.27588C16.0431 7.21644 15.7052 6.19332 15.1579 5.2802C14.6106 4.36707 13.8676 3.58668 12.9825 2.9952C13.3706 4.3796 13.383 5.84237 13.0186 7.23318C12.6542 8.62399 11.926 9.89269 10.9089 10.9089C9.89277 11.9258 8.62423 12.6539 7.23359 13.0183C5.84296 13.3828 4.38037 13.3704 2.9961 12.9825Z"
class="fill-[#0B68CB]"
/>
</svg>
<!-- Resolved -->
<svg
v-if="props.status === CONVERSATION_STATUS.RESOLVED"
class="h-3.5 w-3.5"
fill="none"
xmlns="http://www.w3.org/2000/svg"
viewBox="3 3 17.92 17.92"
>
<path
d="M11.96 20.92C7.01152 20.92 3 16.9084 3 11.96C3 7.01152 7.01152 3 11.96 3C16.9084 3 20.92 7.01152 20.92 11.96C20.92 16.9084 16.9084 20.92 11.96 20.92ZM11.96 19.128C15.9188 19.128 19.128 15.9188 19.128 11.96C19.128 8.00122 15.9188 4.792 11.96 4.792C8.00122 4.792 4.792 8.00122 4.792 11.96C4.792 15.9188 8.00122 19.128 11.96 19.128Z"
class="fill-[#5BB98C]"
/>
<path
d="M11.9599 17.9333C15.2589 17.9333 17.9332 15.2589 17.9332 11.96C17.9332 8.66098 15.2589 5.98663 11.9599 5.98663C8.66092 5.98663 5.98657 8.66098 5.98657 11.96C5.98657 15.2589 8.66092 17.9333 11.9599 17.9333Z"
class="fill-[#5BB98C]"
/>
</svg>
</div>
</template>
@@ -130,7 +130,7 @@ export default {
</script>
<style lang="scss" scoped>
@import 'dashboard/assets/scss/mixins';
@import '~dashboard/assets/scss/mixins';
.notification--title {
@apply text-sm m-0 text-slate-800 dark:text-slate-100;
@@ -13,19 +13,19 @@
<p>{{ $t('GENERAL_SETTINGS.FORM.GENERAL_SECTION.NOTE') }}</p>
</div>
<div class="p-4 flex-grow-0 flex-shrink-0 flex-[50%]">
<label :class="{ error: v$.name.$error }">
<label :class="{ error: $v.name.$error }">
{{ $t('GENERAL_SETTINGS.FORM.NAME.LABEL') }}
<input
v-model="name"
type="text"
:placeholder="$t('GENERAL_SETTINGS.FORM.NAME.PLACEHOLDER')"
@blur="v$.name.$touch"
@blur="$v.name.$touch"
/>
<span v-if="v$.name.$error" class="message">
<span v-if="$v.name.$error" class="message">
{{ $t('GENERAL_SETTINGS.FORM.NAME.ERROR') }}
</span>
</label>
<label :class="{ error: v$.locale.$error }">
<label :class="{ error: $v.locale.$error }">
{{ $t('GENERAL_SETTINGS.FORM.LANGUAGE.LABEL') }}
<select v-model="locale">
<option
@@ -36,7 +36,7 @@
{{ lang.name }}
</option>
</select>
<span v-if="v$.locale.$error" class="message">
<span v-if="$v.locale.$error" class="message">
{{ $t('GENERAL_SETTINGS.FORM.LANGUAGE.ERROR') }}
</span>
</label>
@@ -68,7 +68,7 @@
</label>
<label
v-if="showAutoResolutionConfig"
:class="{ error: v$.autoResolveDuration.$error }"
:class="{ error: $v.autoResolveDuration.$error }"
>
{{ $t('GENERAL_SETTINGS.FORM.AUTO_RESOLVE_DURATION.LABEL') }}
<input
@@ -77,9 +77,9 @@
:placeholder="
$t('GENERAL_SETTINGS.FORM.AUTO_RESOLVE_DURATION.PLACEHOLDER')
"
@blur="v$.autoResolveDuration.$touch"
@blur="$v.autoResolveDuration.$touch"
/>
<span v-if="v$.autoResolveDuration.$error" class="message">
<span v-if="$v.autoResolveDuration.$error" class="message">
{{ $t('GENERAL_SETTINGS.FORM.AUTO_RESOLVE_DURATION.ERROR') }}
</span>
</label>
@@ -129,7 +129,7 @@
</template>
<script>
import { required, minValue, maxValue } from '@vuelidate/validators';
import { required, minValue, maxValue } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import configMixin from 'shared/mixins/configMixin';
@@ -138,13 +138,9 @@ import { FEATURE_FLAGS } from '../../../../featureFlags';
import semver from 'semver';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { getLanguageDirection } from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [accountMixin, alertMixin, configMixin, uiSettingsMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
id: '',
@@ -255,8 +251,8 @@ export default {
},
async updateAccount() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
this.showAlert(this.$t('GENERAL_SETTINGS.FORM.ERROR'));
return;
}
@@ -5,7 +5,7 @@
<div class="h-[calc(100vh-56px)] relative">
<csml-monaco-editor v-model="bot.csmlContent" class="w-full h-full" />
<div
v-if="v$.bot.csmlContent.$error"
v-if="$v.bot.csmlContent.$error"
class="bg-red-100 dark:bg-red-200 text-white dark:text-white absolute bottom-0 w-full p-2.5 flex items-center text-xs justify-center flex-shrink-0"
>
<span>{{ $t('AGENT_BOTS.CSML_BOT_EDITOR.BOT_CONFIG.ERROR') }}</span>
@@ -18,14 +18,14 @@
@submit.prevent="onSubmit"
>
<div>
<label :class="{ error: v$.bot.name.$error }">
<label :class="{ error: $v.bot.name.$error }">
{{ $t('AGENT_BOTS.CSML_BOT_EDITOR.NAME.LABEL') }}
<input
v-model="bot.name"
type="text"
:placeholder="$t('AGENT_BOTS.CSML_BOT_EDITOR.NAME.PLACEHOLDER')"
/>
<span v-if="v$.bot.name.$error" class="message">
<span v-if="$v.bot.name.$error" class="message">
{{ $t('AGENT_BOTS.CSML_BOT_EDITOR.NAME.ERROR') }}
</span>
</label>
@@ -50,9 +50,8 @@
</template>
<script>
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import CsmlMonacoEditor from './CSMLMonacoEditor.vue';
import { useVuelidate } from '@vuelidate/core';
export default {
components: { CsmlMonacoEditor },
@@ -62,9 +61,6 @@ export default {
default: () => {},
},
},
setup() {
return { v$: useVuelidate() };
},
validations: {
bot: {
name: { required },
@@ -82,8 +78,8 @@ export default {
},
methods: {
onSubmit() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
this.$emit('submit', {
@@ -11,37 +11,37 @@
@submit.prevent="addAgent()"
>
<div class="w-full">
<label :class="{ error: v$.agentName.$error }">
<label :class="{ error: $v.agentName.$error }">
{{ $t('AGENT_MGMT.ADD.FORM.NAME.LABEL') }}
<input
v-model.trim="agentName"
type="text"
:placeholder="$t('AGENT_MGMT.ADD.FORM.NAME.PLACEHOLDER')"
@input="v$.agentName.$touch"
@input="$v.agentName.$touch"
/>
</label>
</div>
<div class="w-full">
<label :class="{ error: v$.agentType.$error }">
<label :class="{ error: $v.agentType.$error }">
{{ $t('AGENT_MGMT.ADD.FORM.AGENT_TYPE.LABEL') }}
<select v-model="agentType">
<option v-for="role in roles" :key="role.name" :value="role.name">
{{ role.label }}
</option>
</select>
<span v-if="v$.agentType.$error" class="message">
<span v-if="$v.agentType.$error" class="message">
{{ $t('AGENT_MGMT.ADD.FORM.AGENT_TYPE.ERROR') }}
</span>
</label>
</div>
<div class="w-full">
<label :class="{ error: v$.agentEmail.$error }">
<label :class="{ error: $v.agentEmail.$error }">
{{ $t('AGENT_MGMT.ADD.FORM.EMAIL.LABEL') }}
<input
v-model.trim="agentEmail"
type="text"
:placeholder="$t('AGENT_MGMT.ADD.FORM.EMAIL.PLACEHOLDER')"
@input="v$.agentEmail.$touch"
@input="$v.agentEmail.$touch"
/>
</label>
</div>
@@ -49,8 +49,8 @@
<div class="w-full">
<woot-submit-button
:disabled="
v$.agentEmail.$invalid ||
v$.agentName.$invalid ||
$v.agentEmail.$invalid ||
$v.agentName.$invalid ||
uiFlags.isCreating
"
:button-text="$t('AGENT_MGMT.ADD.FORM.SUBMIT')"
@@ -67,9 +67,8 @@
</template>
<script>
import { required, minLength, email } from '@vuelidate/validators';
import { required, minLength, email } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import { useVuelidate } from '@vuelidate/core';
export default {
props: {
@@ -78,9 +77,6 @@ export default {
default: () => {},
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
agentName: '',
@@ -4,33 +4,33 @@
<woot-modal-header :header-title="pageTitle" />
<form class="w-full" @submit.prevent="editAgent()">
<div class="w-full">
<label :class="{ error: v$.agentName.$error }">
<label :class="{ error: $v.agentName.$error }">
{{ $t('AGENT_MGMT.EDIT.FORM.NAME.LABEL') }}
<input
v-model.trim="agentName"
type="text"
:placeholder="$t('AGENT_MGMT.EDIT.FORM.NAME.PLACEHOLDER')"
@input="v$.agentName.$touch"
@input="$v.agentName.$touch"
/>
</label>
</div>
<div class="w-full">
<label :class="{ error: v$.agentType.$error }">
<label :class="{ error: $v.agentType.$error }">
{{ $t('AGENT_MGMT.EDIT.FORM.AGENT_TYPE.LABEL') }}
<select v-model="agentType">
<option v-for="role in roles" :key="role.name" :value="role.name">
{{ role.label }}
</option>
</select>
<span v-if="v$.agentType.$error" class="message">
<span v-if="$v.agentType.$error" class="message">
{{ $t('AGENT_MGMT.EDIT.FORM.AGENT_TYPE.ERROR') }}
</span>
</label>
</div>
<div class="w-full">
<label :class="{ error: v$.agentAvailability.$error }">
<label :class="{ error: $v.agentAvailability.$error }">
{{ $t('PROFILE_SETTINGS.FORM.AVAILABILITY.LABEL') }}
<select v-model="agentAvailability">
<option
@@ -41,7 +41,7 @@
{{ role.label }}
</option>
</select>
<span v-if="v$.agentAvailability.$error" class="message">
<span v-if="$v.agentAvailability.$error" class="message">
{{ $t('AGENT_MGMT.EDIT.FORM.AGENT_AVAILABILITY.ERROR') }}
</span>
</label>
@@ -50,8 +50,8 @@
<div class="w-[50%]">
<woot-submit-button
:disabled="
v$.agentType.$invalid ||
v$.agentName.$invalid ||
$v.agentType.$invalid ||
$v.agentName.$invalid ||
uiFlags.isUpdating
"
:button-text="$t('AGENT_MGMT.EDIT.FORM.SUBMIT')"
@@ -77,13 +77,12 @@
</template>
<script>
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import WootSubmitButton from '../../../../components/buttons/FormSubmitButton.vue';
import Modal from '../../../../components/Modal.vue';
import Auth from '../../../../api/auth';
import wootConstants from 'dashboard/constants/globals';
import { useVuelidate } from '@vuelidate/core';
const { AVAILABILITY_STATUS_KEYS } = wootConstants;
@@ -118,9 +117,6 @@ export default {
required: true,
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
roles: [
@@ -5,14 +5,14 @@
<form class="flex w-full" @submit.prevent="addAttributes">
<div class="w-full">
<label :class="{ error: v$.attributeModel.$error }">
<label :class="{ error: $v.attributeModel.$error }">
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.MODEL.LABEL') }}
<select v-model="attributeModel">
<option v-for="model in models" :key="model.id" :value="model.id">
{{ model.option }}
</option>
</select>
<span v-if="v$.attributeModel.$error" class="message">
<span v-if="$v.attributeModel.$error" class="message">
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.MODEL.ERROR') }}
</span>
</label>
@@ -20,46 +20,46 @@
v-model="displayName"
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.NAME.LABEL')"
type="text"
:class="{ error: v$.displayName.$error }"
:class="{ error: $v.displayName.$error }"
:error="
v$.displayName.$error
$v.displayName.$error
? $t('ATTRIBUTES_MGMT.ADD.FORM.NAME.ERROR')
: ''
"
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.NAME.PLACEHOLDER')"
@input="onDisplayNameChange"
@blur="v$.displayName.$touch"
@blur="$v.displayName.$touch"
/>
<woot-input
v-model="attributeKey"
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.LABEL')"
type="text"
:class="{ error: v$.attributeKey.$error }"
:error="v$.attributeKey.$error ? keyErrorMessage : ''"
:class="{ error: $v.attributeKey.$error }"
:error="$v.attributeKey.$error ? keyErrorMessage : ''"
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.PLACEHOLDER')"
@blur="v$.attributeKey.$touch"
@blur="$v.attributeKey.$touch"
/>
<label :class="{ error: v$.description.$error }">
<label :class="{ error: $v.description.$error }">
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.DESC.LABEL') }}
<textarea
v-model="description"
rows="3"
type="text"
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.DESC.PLACEHOLDER')"
@blur="v$.description.$touch"
@blur="$v.description.$touch"
/>
<span v-if="v$.description.$error" class="message">
<span v-if="$v.description.$error" class="message">
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.DESC.ERROR') }}
</span>
</label>
<label :class="{ error: v$.attributeType.$error }">
<label :class="{ error: $v.attributeType.$error }">
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.LABEL') }}
<select v-model="attributeType">
<option v-for="type in types" :key="type.id" :value="type.id">
{{ type.option }}
</option>
</select>
<span v-if="v$.attributeType.$error" class="message">
<span v-if="$v.attributeType.$error" class="message">
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.ERROR') }}
</span>
</label>
@@ -126,12 +126,11 @@
</template>
<script>
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import { convertToAttributeSlug } from 'dashboard/helper/commons.js';
import { ATTRIBUTE_MODELS, ATTRIBUTE_TYPES } from './constants';
import alertMixin from 'shared/mixins/alertMixin';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [alertMixin],
@@ -141,9 +140,6 @@ export default {
default: () => {},
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
@@ -179,14 +175,14 @@ export default {
},
isButtonDisabled() {
return (
this.v$.displayName.$invalid ||
this.v$.description.$invalid ||
this.$v.displayName.$invalid ||
this.$v.description.$invalid ||
this.uiFlags.isCreating ||
this.isTagInputInvalid
);
},
keyErrorMessage() {
if (!this.v$.attributeKey.isKey) {
if (!this.$v.attributeKey.isKey) {
return this.$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.IN_VALID');
}
return this.$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.ERROR');
@@ -242,8 +238,8 @@ export default {
this.regexEnabled = !this.regexEnabled;
},
async addAttributes() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
if (!this.regexEnabled) {
@@ -281,16 +277,13 @@ export default {
padding: 0 var(--space-small) var(--space-small) 0;
font-family: monospace;
}
.multiselect--wrap {
margin-bottom: var(--space-normal);
.error-message {
color: var(--r-400);
font-size: var(--font-size-small);
font-weight: var(--font-weight-normal);
}
.invalid {
::v-deep {
.multiselect__tags {
@@ -299,16 +292,13 @@ export default {
}
}
}
::v-deep {
.multiselect {
margin-bottom: 0;
}
.multiselect__content-wrapper {
display: none;
}
.multiselect--active .multiselect__tags {
border-radius: var(--border-radius-normal);
}
@@ -7,46 +7,46 @@
v-model.trim="displayName"
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.NAME.LABEL')"
type="text"
:class="{ error: v$.displayName.$error }"
:class="{ error: $v.displayName.$error }"
:error="
v$.displayName.$error
$v.displayName.$error
? $t('ATTRIBUTES_MGMT.ADD.FORM.NAME.ERROR')
: ''
"
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.NAME.PLACEHOLDER')"
@blur="v$.displayName.$touch"
@blur="$v.displayName.$touch"
/>
<woot-input
v-model.trim="attributeKey"
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.LABEL')"
type="text"
:class="{ error: v$.attributeKey.$error }"
:error="v$.attributeKey.$error ? keyErrorMessage : ''"
:class="{ error: $v.attributeKey.$error }"
:error="$v.attributeKey.$error ? keyErrorMessage : ''"
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.PLACEHOLDER')"
readonly
@blur="v$.attributeKey.$touch"
@blur="$v.attributeKey.$touch"
/>
<label :class="{ error: v$.description.$error }">
<label :class="{ error: $v.description.$error }">
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.DESC.LABEL') }}
<textarea
v-model.trim="description"
rows="5"
type="text"
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.DESC.PLACEHOLDER')"
@blur="v$.description.$touch"
@blur="$v.description.$touch"
/>
<span v-if="v$.description.$error" class="message">
<span v-if="$v.description.$error" class="message">
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.DESC.ERROR') }}
</span>
</label>
<label :class="{ error: v$.attributeType.$error }">
<label :class="{ error: $v.attributeType.$error }">
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.LABEL') }}
<select v-model="attributeType" disabled>
<option v-for="type in types" :key="type.id" :value="type.id">
{{ type.option }}
</option>
</select>
<span v-if="v$.attributeType.$error" class="message">
<span v-if="$v.attributeType.$error" class="message">
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.ERROR') }}
</span>
</label>
@@ -109,13 +109,12 @@
<script>
import { mapGetters } from 'vuex';
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import { ATTRIBUTE_TYPES } from './constants';
import alertMixin from 'shared/mixins/alertMixin';
import customAttributeMixin from '../../../../mixins/customAttributeMixin';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {},
mixins: [alertMixin, customAttributeMixin],
props: {
selectedAttribute: {
@@ -127,9 +126,6 @@ export default {
default: false,
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
displayName: '',
@@ -177,7 +173,7 @@ export default {
return this.values.map(item => item.name);
},
isButtonDisabled() {
return this.v$.description.$invalid || this.isMultiselectInvalid;
return this.$v.description.$invalid || this.isMultiselectInvalid;
},
isMultiselectInvalid() {
return (
@@ -198,7 +194,7 @@ export default {
).id;
},
keyErrorMessage() {
if (!this.v$.attributeKey.isKey) {
if (!this.$v.attributeKey.isKey) {
return this.$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.IN_VALID');
}
return this.$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.ERROR');
@@ -241,8 +237,8 @@ export default {
this.values = this.setAttributeListValue;
},
async editAttributes() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
if (!this.regexEnabled) {
@@ -281,16 +277,13 @@ export default {
padding: 0 var(--space-small) var(--space-small) 0;
font-family: monospace;
}
.multiselect--wrap {
margin-bottom: var(--space-normal);
.error-message {
color: var(--r-400);
font-size: var(--font-size-small);
font-weight: var(--font-weight-normal);
}
.invalid {
::v-deep {
.multiselect__tags {
@@ -299,16 +292,13 @@ export default {
}
}
}
::v-deep {
.multiselect {
margin-bottom: 0;
}
.multiselect__content-wrapper {
display: none;
}
.multiselect--active .multiselect__tags {
border-radius: var(--border-radius-normal);
}
@@ -7,30 +7,30 @@
v-model="automation.name"
:label="$t('AUTOMATION.ADD.FORM.NAME.LABEL')"
type="text"
:class="{ error: v$.automation.name.$error }"
:class="{ error: $v.automation.name.$error }"
:error="
v$.automation.name.$error
$v.automation.name.$error
? $t('AUTOMATION.ADD.FORM.NAME.ERROR')
: ''
"
:placeholder="$t('AUTOMATION.ADD.FORM.NAME.PLACEHOLDER')"
@blur="v$.automation.name.$touch"
@blur="$v.automation.name.$touch"
/>
<woot-input
v-model="automation.description"
:label="$t('AUTOMATION.ADD.FORM.DESC.LABEL')"
type="text"
:class="{ error: v$.automation.description.$error }"
:class="{ error: $v.automation.description.$error }"
:error="
v$.automation.description.$error
$v.automation.description.$error
? $t('AUTOMATION.ADD.FORM.DESC.ERROR')
: ''
"
:placeholder="$t('AUTOMATION.ADD.FORM.DESC.PLACEHOLDER')"
@blur="v$.automation.description.$touch"
@blur="$v.automation.description.$touch"
/>
<div class="event_wrapper">
<label :class="{ error: v$.automation.event_name.$error }">
<label :class="{ error: $v.automation.event_name.$error }">
{{ $t('AUTOMATION.ADD.FORM.EVENT.LABEL') }}
<select v-model="automation.event_name" @change="onEventChange()">
<option
@@ -41,7 +41,7 @@
{{ event.value }}
</option>
</select>
<span v-if="v$.automation.event_name.$error" class="message">
<span v-if="$v.automation.event_name.$error" class="message">
{{ $t('AUTOMATION.ADD.FORM.EVENT.ERROR') }}
</span>
</label>
@@ -73,7 +73,7 @@
:custom-attribute-type="
getCustomAttributeType(automation.conditions[i].attribute_key)
"
:v="v$.automation.conditions.$each[i]"
:v="$v.automation.conditions.$each[i]"
@resetFilter="resetFilter(i, automation.conditions[i])"
@removeFilter="removeFilter(i)"
/>
@@ -110,7 +110,7 @@
:show-action-input="
showActionInput(automation.actions[i].action_name)
"
:v="v$.automation.actions.$each[i]"
:v="$v.automation.actions.$each[i]"
@resetAction="resetAction(i)"
@removeAction="removeAction(i)"
/>
@@ -228,7 +228,6 @@ export default {
select {
@apply m-0;
}
.info-message {
@apply text-xs text-green-500 dark:text-green-500 text-right;
}
@@ -7,30 +7,30 @@
v-model="automation.name"
:label="$t('AUTOMATION.ADD.FORM.NAME.LABEL')"
type="text"
:class="{ error: v$.automation.name.$error }"
:class="{ error: $v.automation.name.$error }"
:error="
v$.automation.name.$error
$v.automation.name.$error
? $t('AUTOMATION.ADD.FORM.NAME.ERROR')
: ''
"
:placeholder="$t('AUTOMATION.ADD.FORM.NAME.PLACEHOLDER')"
@blur="v$.automation.name.$touch"
@blur="$v.automation.name.$touch"
/>
<woot-input
v-model="automation.description"
:label="$t('AUTOMATION.ADD.FORM.DESC.LABEL')"
type="text"
:class="{ error: v$.automation.description.$error }"
:class="{ error: $v.automation.description.$error }"
:error="
v$.automation.description.$error
$v.automation.description.$error
? $t('AUTOMATION.ADD.FORM.DESC.ERROR')
: ''
"
:placeholder="$t('AUTOMATION.ADD.FORM.DESC.PLACEHOLDER')"
@blur="v$.automation.description.$touch"
@blur="$v.automation.description.$touch"
/>
<div class="event_wrapper">
<label :class="{ error: v$.automation.event_name.$error }">
<label :class="{ error: $v.automation.event_name.$error }">
{{ $t('AUTOMATION.ADD.FORM.EVENT.LABEL') }}
<select v-model="automation.event_name" @change="onEventChange()">
<option
@@ -41,7 +41,7 @@
{{ event.value }}
</option>
</select>
<span v-if="v$.automation.event_name.$error" class="message">
<span v-if="$v.automation.event_name.$error" class="message">
{{ $t('AUTOMATION.ADD.FORM.EVENT.ERROR') }}
</span>
</label>
@@ -70,7 +70,7 @@
getCustomAttributeType(automation.conditions[i].attribute_key)
"
:show-query-operator="i !== automation.conditions.length - 1"
:v="v$.automation.conditions.$each[i]"
:v="$v.automation.conditions.$each[i]"
@resetFilter="resetFilter(i, automation.conditions[i])"
@removeFilter="removeFilter(i)"
/>
@@ -103,7 +103,7 @@
:action-types="automationActionTypes"
:dropdown-values="getActionDropdownValues(action.action_name)"
:show-action-input="showActionInput(action.action_name)"
:v="v$.automation.actions.$each[i]"
:v="$v.automation.actions.$each[i]"
:initial-file-name="getFileName(action, automation.files)"
@resetAction="resetAction(i)"
@removeAction="removeAction(i)"
@@ -206,7 +206,6 @@ export default {
select {
@apply m-0;
}
.info-message {
@apply text-xs text-green-500 dark:text-green-500 text-right;
}
@@ -10,10 +10,10 @@
v-model="title"
:label="$t('CAMPAIGN.ADD.FORM.TITLE.LABEL')"
type="text"
:class="{ error: v$.title.$error }"
:error="v$.title.$error ? $t('CAMPAIGN.ADD.FORM.TITLE.ERROR') : ''"
:class="{ error: $v.title.$error }"
:error="$v.title.$error ? $t('CAMPAIGN.ADD.FORM.TITLE.ERROR') : ''"
:placeholder="$t('CAMPAIGN.ADD.FORM.TITLE.PLACEHOLDER')"
@blur="v$.title.$touch"
@blur="$v.title.$touch"
/>
<div v-if="isOngoingType" class="editor-wrap">
@@ -24,38 +24,38 @@
<woot-message-editor
v-model="message"
class="message-editor"
:class="{ editor_warning: v$.message.$error }"
:class="{ editor_warning: $v.message.$error }"
:placeholder="$t('CAMPAIGN.ADD.FORM.MESSAGE.PLACEHOLDER')"
@blur="v$.message.$touch"
@blur="$v.message.$touch"
/>
<span v-if="v$.message.$error" class="editor-warning__message">
<span v-if="$v.message.$error" class="editor-warning__message">
{{ $t('CAMPAIGN.ADD.FORM.MESSAGE.ERROR') }}
</span>
</div>
</div>
<label v-else :class="{ error: v$.message.$error }">
<label v-else :class="{ error: $v.message.$error }">
{{ $t('CAMPAIGN.ADD.FORM.MESSAGE.LABEL') }}
<textarea
v-model="message"
rows="5"
type="text"
:placeholder="$t('CAMPAIGN.ADD.FORM.MESSAGE.PLACEHOLDER')"
@blur="v$.message.$touch"
@blur="$v.message.$touch"
/>
<span v-if="v$.message.$error" class="message">
<span v-if="$v.message.$error" class="message">
{{ $t('CAMPAIGN.ADD.FORM.MESSAGE.ERROR') }}
</span>
</label>
<label :class="{ error: v$.selectedInbox.$error }">
<label :class="{ error: $v.selectedInbox.$error }">
{{ $t('CAMPAIGN.ADD.FORM.INBOX.LABEL') }}
<select v-model="selectedInbox" @change="onChangeInbox($event)">
<option v-for="item in inboxes" :key="item.name" :value="item.id">
{{ item.name }}
</option>
</select>
<span v-if="v$.selectedInbox.$error" class="message">
<span v-if="$v.selectedInbox.$error" class="message">
{{ $t('CAMPAIGN.ADD.FORM.INBOX.ERROR') }}
</span>
</label>
@@ -63,7 +63,7 @@
<label
v-if="isOnOffType"
class="multiselect-wrap--small"
:class="{ error: v$.selectedAudience.$error }"
:class="{ error: $v.selectedAudience.$error }"
>
{{ $t('CAMPAIGN.ADD.FORM.AUDIENCE.LABEL') }}
<multiselect
@@ -79,17 +79,17 @@
selected-label
:select-label="$t('FORMS.MULTISELECT.ENTER_TO_SELECT')"
:deselect-label="$t('FORMS.MULTISELECT.ENTER_TO_REMOVE')"
@blur="v$.selectedAudience.$touch"
@select="v$.selectedAudience.$touch"
@blur="$v.selectedAudience.$touch"
@select="$v.selectedAudience.$touch"
/>
<span v-if="v$.selectedAudience.$error" class="message">
<span v-if="$v.selectedAudience.$error" class="message">
{{ $t('CAMPAIGN.ADD.FORM.AUDIENCE.ERROR') }}
</span>
</label>
<label
v-if="isOngoingType"
:class="{ error: v$.selectedSender.$error }"
:class="{ error: $v.selectedSender.$error }"
>
{{ $t('CAMPAIGN.ADD.FORM.SENT_BY.LABEL') }}
<select v-model="selectedSender">
@@ -101,7 +101,7 @@
{{ sender.name }}
</option>
</select>
<span v-if="v$.selectedSender.$error" class="message">
<span v-if="$v.selectedSender.$error" class="message">
{{ $t('CAMPAIGN.ADD.FORM.SENT_BY.ERROR') }}
</span>
</label>
@@ -121,26 +121,26 @@
v-model="endPoint"
:label="$t('CAMPAIGN.ADD.FORM.END_POINT.LABEL')"
type="text"
:class="{ error: v$.endPoint.$error }"
:class="{ error: $v.endPoint.$error }"
:error="
v$.endPoint.$error ? $t('CAMPAIGN.ADD.FORM.END_POINT.ERROR') : ''
$v.endPoint.$error ? $t('CAMPAIGN.ADD.FORM.END_POINT.ERROR') : ''
"
:placeholder="$t('CAMPAIGN.ADD.FORM.END_POINT.PLACEHOLDER')"
@blur="v$.endPoint.$touch"
@blur="$v.endPoint.$touch"
/>
<woot-input
v-if="isOngoingType"
v-model="timeOnPage"
:label="$t('CAMPAIGN.ADD.FORM.TIME_ON_PAGE.LABEL')"
type="text"
:class="{ error: v$.timeOnPage.$error }"
:class="{ error: $v.timeOnPage.$error }"
:error="
v$.timeOnPage.$error
$v.timeOnPage.$error
? $t('CAMPAIGN.ADD.FORM.TIME_ON_PAGE.ERROR')
: ''
"
:placeholder="$t('CAMPAIGN.ADD.FORM.TIME_ON_PAGE.PLACEHOLDER')"
@blur="v$.timeOnPage.$touch"
@blur="$v.timeOnPage.$touch"
/>
<label v-if="isOngoingType">
<input
@@ -176,14 +176,13 @@
<script>
import { mapGetters } from 'vuex';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import alertMixin from 'shared/mixins/alertMixin';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import campaignMixin from 'shared/mixins/campaignMixin';
import WootDateTimePicker from 'dashboard/components/ui/DateTimePicker.vue';
import { URLPattern } from 'urlpattern-polyfill';
import { CAMPAIGNS_EVENTS } from '../../../../helper/AnalyticsHelper/events';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -192,9 +191,6 @@ export default {
},
mixins: [alertMixin, campaignMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
title: '',
@@ -347,8 +343,8 @@ export default {
return campaignDetails;
},
async addCampaign() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
try {
@@ -7,10 +7,10 @@
v-model="title"
:label="$t('CAMPAIGN.ADD.FORM.TITLE.LABEL')"
type="text"
:class="{ error: v$.title.$error }"
:error="v$.title.$error ? $t('CAMPAIGN.ADD.FORM.TITLE.ERROR') : ''"
:class="{ error: $v.title.$error }"
:error="$v.title.$error ? $t('CAMPAIGN.ADD.FORM.TITLE.ERROR') : ''"
:placeholder="$t('CAMPAIGN.ADD.FORM.TITLE.PLACEHOLDER')"
@blur="v$.title.$touch"
@blur="$v.title.$touch"
/>
<div class="editor-wrap">
<label>
@@ -20,28 +20,28 @@
v-model="message"
class="message-editor"
:is-format-mode="true"
:class="{ editor_warning: v$.message.$error }"
:class="{ editor_warning: $v.message.$error }"
:placeholder="$t('CAMPAIGN.ADD.FORM.MESSAGE.PLACEHOLDER')"
@input="v$.message.$touch"
@input="$v.message.$touch"
/>
<span v-if="v$.message.$error" class="editor-warning__message">
<span v-if="$v.message.$error" class="editor-warning__message">
{{ $t('CAMPAIGN.ADD.FORM.MESSAGE.ERROR') }}
</span>
</div>
<label :class="{ error: v$.selectedInbox.$error }">
<label :class="{ error: $v.selectedInbox.$error }">
{{ $t('CAMPAIGN.ADD.FORM.INBOX.LABEL') }}
<select v-model="selectedInbox" @change="onChangeInbox($event)">
<option v-for="item in inboxes" :key="item.id" :value="item.id">
{{ item.name }}
</option>
</select>
<span v-if="v$.selectedInbox.$error" class="message">
<span v-if="$v.selectedInbox.$error" class="message">
{{ $t('CAMPAIGN.ADD.FORM.INBOX.ERROR') }}
</span>
</label>
<label :class="{ error: v$.selectedSender.$error }">
<label :class="{ error: $v.selectedSender.$error }">
{{ $t('CAMPAIGN.ADD.FORM.SENT_BY.LABEL') }}
<select v-model="selectedSender">
<option
@@ -52,7 +52,7 @@
{{ sender.name }}
</option>
</select>
<span v-if="v$.selectedSender.$error" class="message">
<span v-if="$v.selectedSender.$error" class="message">
{{ $t('CAMPAIGN.ADD.FORM.SENT_BY.ERROR') }}
</span>
</label>
@@ -60,25 +60,25 @@
v-model="endPoint"
:label="$t('CAMPAIGN.ADD.FORM.END_POINT.LABEL')"
type="text"
:class="{ error: v$.endPoint.$error }"
:class="{ error: $v.endPoint.$error }"
:error="
v$.endPoint.$error ? $t('CAMPAIGN.ADD.FORM.END_POINT.ERROR') : ''
$v.endPoint.$error ? $t('CAMPAIGN.ADD.FORM.END_POINT.ERROR') : ''
"
:placeholder="$t('CAMPAIGN.ADD.FORM.END_POINT.PLACEHOLDER')"
@blur="v$.endPoint.$touch"
@blur="$v.endPoint.$touch"
/>
<woot-input
v-model="timeOnPage"
:label="$t('CAMPAIGN.ADD.FORM.TIME_ON_PAGE.LABEL')"
type="text"
:class="{ error: v$.timeOnPage.$error }"
:class="{ error: $v.timeOnPage.$error }"
:error="
v$.timeOnPage.$error
$v.timeOnPage.$error
? $t('CAMPAIGN.ADD.FORM.TIME_ON_PAGE.ERROR')
: ''
"
:placeholder="$t('CAMPAIGN.ADD.FORM.TIME_ON_PAGE.PLACEHOLDER')"
@blur="v$.timeOnPage.$touch"
@blur="$v.timeOnPage.$touch"
/>
<label>
<input
@@ -113,12 +113,11 @@
<script>
import { mapGetters } from 'vuex';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import alertMixin from 'shared/mixins/alertMixin';
import campaignMixin from 'shared/mixins/campaignMixin';
import { URLPattern } from 'urlpattern-polyfill';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -131,9 +130,6 @@ export default {
default: () => {},
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
title: '',
@@ -256,8 +252,8 @@ export default {
this.loadInboxMembers();
},
async editCampaign() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
try {
@@ -7,38 +7,38 @@
/>
<form class="flex flex-col w-full" @submit.prevent="addCannedResponse()">
<div class="w-full">
<label :class="{ error: v$.shortCode.$error }">
<label :class="{ error: $v.shortCode.$error }">
{{ $t('CANNED_MGMT.ADD.FORM.SHORT_CODE.LABEL') }}
<input
v-model.trim="shortCode"
type="text"
:placeholder="$t('CANNED_MGMT.ADD.FORM.SHORT_CODE.PLACEHOLDER')"
@input="v$.shortCode.$touch"
@input="$v.shortCode.$touch"
/>
</label>
</div>
<div class="w-full">
<label :class="{ error: v$.content.$error }">
<label :class="{ error: $v.content.$error }">
{{ $t('CANNED_MGMT.ADD.FORM.CONTENT.LABEL') }}
</label>
<div class="editor-wrap">
<woot-message-editor
v-model="content"
class="message-editor"
:class="{ editor_warning: v$.content.$error }"
:class="{ editor_warning: $v.content.$error }"
:enable-variables="true"
:enable-canned-responses="false"
:placeholder="$t('CANNED_MGMT.ADD.FORM.CONTENT.PLACEHOLDER')"
@blur="v$.content.$touch"
@blur="$v.content.$touch"
/>
</div>
</div>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
<woot-submit-button
:disabled="
v$.content.$invalid ||
v$.shortCode.$invalid ||
$v.content.$invalid ||
$v.shortCode.$invalid ||
addCanned.showLoading
"
:button-text="$t('CANNED_MGMT.ADD.FORM.SUBMIT')"
@@ -54,13 +54,12 @@
</template>
<script>
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import WootSubmitButton from '../../../../components/buttons/FormSubmitButton.vue';
import Modal from '../../../../components/Modal.vue';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -79,9 +78,6 @@ export default {
default: () => {},
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
shortCode: '',
@@ -106,8 +102,8 @@ export default {
resetForm() {
this.shortCode = '';
this.content = '';
this.v$.shortCode.$reset();
this.v$.content.$reset();
this.$v.shortCode.$reset();
this.$v.content.$reset();
},
addCannedResponse() {
// Show loading on button
@@ -4,38 +4,38 @@
<woot-modal-header :header-title="pageTitle" />
<form class="flex flex-col w-full" @submit.prevent="editCannedResponse()">
<div class="w-full">
<label :class="{ error: v$.shortCode.$error }">
<label :class="{ error: $v.shortCode.$error }">
{{ $t('CANNED_MGMT.EDIT.FORM.SHORT_CODE.LABEL') }}
<input
v-model.trim="shortCode"
type="text"
:placeholder="$t('CANNED_MGMT.EDIT.FORM.SHORT_CODE.PLACEHOLDER')"
@input="v$.shortCode.$touch"
@input="$v.shortCode.$touch"
/>
</label>
</div>
<div class="w-full">
<label :class="{ error: v$.content.$error }">
<label :class="{ error: $v.content.$error }">
{{ $t('CANNED_MGMT.EDIT.FORM.CONTENT.LABEL') }}
</label>
<div class="editor-wrap">
<woot-message-editor
v-model="content"
class="message-editor"
:class="{ editor_warning: v$.content.$error }"
:class="{ editor_warning: $v.content.$error }"
:enable-variables="true"
:enable-canned-responses="false"
:placeholder="$t('CANNED_MGMT.EDIT.FORM.CONTENT.PLACEHOLDER')"
@blur="v$.content.$touch"
@blur="$v.content.$touch"
/>
</div>
</div>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
<woot-submit-button
:disabled="
v$.content.$invalid ||
v$.shortCode.$invalid ||
$v.content.$invalid ||
$v.shortCode.$invalid ||
editCanned.showLoading
"
:button-text="$t('CANNED_MGMT.EDIT.FORM.SUBMIT')"
@@ -52,12 +52,11 @@
<script>
/* eslint no-console: 0 */
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor.vue';
import WootSubmitButton from '../../../../components/buttons/FormSubmitButton.vue';
import alertMixin from 'shared/mixins/alertMixin';
import Modal from '../../../../components/Modal.vue';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -72,9 +71,6 @@ export default {
edshortCode: { type: String, default: '' },
onClose: { type: Function, default: () => {} },
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
editCanned: {
@@ -102,14 +98,14 @@ export default {
},
methods: {
setPageName({ name }) {
this.v$.content.$touch();
this.$v.content.$touch();
this.content = name;
},
resetForm() {
this.shortCode = '';
this.content = '';
this.v$.shortCode.$reset();
this.v$.content.$reset();
this.$v.shortCode.$reset();
this.$v.content.$reset();
},
editCannedResponse() {
// Show loading on button
@@ -9,7 +9,7 @@
</div>
<div class="w-[60%]">
<div class="w-full">
<label :class="{ error: v$.selectedAgents.$error }">
<label :class="{ error: $v.selectedAgents.$error }">
{{ $t('INBOX_MGMT.ADD.AGENTS.TITLE') }}
<multiselect
v-model="selectedAgents"
@@ -24,9 +24,9 @@
:select-label="$t('FORMS.MULTISELECT.ENTER_TO_SELECT')"
:deselect-label="$t('FORMS.MULTISELECT.ENTER_TO_REMOVE')"
:placeholder="$t('INBOX_MGMT.ADD.AGENTS.PICK_AGENTS')"
@select="v$.selectedAgents.$touch"
@select="$v.selectedAgents.$touch"
/>
<span v-if="v$.selectedAgents.$error" class="message">
<span v-if="$v.selectedAgents.$error" class="message">
{{ $t('INBOX_MGMT.ADD.AGENTS.VALIDATION_ERROR') }}
</span>
</label>
@@ -18,37 +18,37 @@
<div v-if="isIMAPEnabled" class="imap-details-wrap">
<woot-input
v-model.trim="address"
:class="{ error: v$.address.$error }"
:class="{ error: $v.address.$error }"
class="medium-9 columns"
:label="$t('INBOX_MGMT.IMAP.ADDRESS.LABEL')"
:placeholder="$t('INBOX_MGMT.IMAP.ADDRESS.PLACE_HOLDER')"
@blur="v$.address.$touch"
@blur="$v.address.$touch"
/>
<woot-input
v-model="port"
type="number"
:class="{ error: v$.port.$error }"
:class="{ error: $v.port.$error }"
class="medium-9 columns"
:label="$t('INBOX_MGMT.IMAP.PORT.LABEL')"
:placeholder="$t('INBOX_MGMT.IMAP.PORT.PLACE_HOLDER')"
@blur="v$.port.$touch"
@blur="$v.port.$touch"
/>
<woot-input
v-model="login"
:class="{ error: v$.login.$error }"
:class="{ error: $v.login.$error }"
class="medium-9 columns"
:label="$t('INBOX_MGMT.IMAP.LOGIN.LABEL')"
:placeholder="$t('INBOX_MGMT.IMAP.LOGIN.PLACE_HOLDER')"
@blur="v$.login.$touch"
@blur="$v.login.$touch"
/>
<woot-input
v-model="password"
:class="{ error: v$.password.$error }"
:class="{ error: $v.password.$error }"
class="medium-9 columns"
:label="$t('INBOX_MGMT.IMAP.PASSWORD.LABEL')"
:placeholder="$t('INBOX_MGMT.IMAP.PASSWORD.PLACE_HOLDER')"
type="password"
@blur="v$.password.$touch"
@blur="$v.password.$touch"
/>
<label for="toggle-enable-ssl">
<input
@@ -62,7 +62,7 @@
<woot-submit-button
:button-text="$t('INBOX_MGMT.IMAP.UPDATE')"
:loading="uiFlags.isUpdatingIMAP"
:disabled="(v$.$invalid && isIMAPEnabled) || uiFlags.isUpdatingIMAP"
:disabled="($v.$invalid && isIMAPEnabled) || uiFlags.isUpdatingIMAP"
/>
</form>
</settings-section>
@@ -73,8 +73,7 @@
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import SettingsSection from 'dashboard/components/SettingsSection.vue';
import { required, minLength } from '@vuelidate/validators';
import { useVuelidate } from '@vuelidate/core';
import { required, minLength } from 'vuelidate/lib/validators';
export default {
components: {
@@ -87,9 +86,6 @@ export default {
default: () => ({}),
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
isIMAPEnabled: false,
@@ -38,21 +38,21 @@
<woot-input
v-model.trim="selectedInboxName"
class="w-[75%] pb-4"
:class="{ error: v$.selectedInboxName.$error }"
:class="{ error: $v.selectedInboxName.$error }"
:label="inboxNameLabel"
:placeholder="inboxNamePlaceHolder"
:error="
v$.selectedInboxName.$error
$v.selectedInboxName.$error
? $t('INBOX_MGMT.ADD.CHANNEL_NAME.ERROR')
: ''
"
@blur="v$.selectedInboxName.$touch"
@blur="$v.selectedInboxName.$touch"
/>
<woot-input
v-if="isAPIInbox"
v-model.trim="webhookUrl"
class="w-[75%] pb-4"
:class="{ error: v$.webhookUrl.$error }"
:class="{ error: $v.webhookUrl.$error }"
:label="
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WEBHOOK_URL.LABEL')
"
@@ -60,11 +60,11 @@
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WEBHOOK_URL.PLACEHOLDER')
"
:error="
v$.webhookUrl.$error
$v.webhookUrl.$error
? $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WEBHOOK_URL.ERROR')
: ''
"
@blur="v$.webhookUrl.$touch"
@blur="$v.webhookUrl.$touch"
/>
<woot-input
v-if="isAWebWidgetInbox"
@@ -383,7 +383,7 @@
<woot-submit-button
v-if="isAPIInbox"
type="submit"
:disabled="v$.webhookUrl.$invalid"
:disabled="$v.webhookUrl.$invalid"
:button-text="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
:loading="uiFlags.isUpdating"
@click="updateInbox"
@@ -391,7 +391,7 @@
<woot-submit-button
v-else
type="submit"
:disabled="v$.$invalid"
:disabled="$v.$invalid"
:button-text="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
:loading="uiFlags.isUpdating"
@click="updateInbox"
@@ -17,45 +17,45 @@
<div v-if="isSMTPEnabled" class="smtp-details-wrap">
<woot-input
v-model.trim="address"
:class="{ error: v$.address.$error }"
:class="{ error: $v.address.$error }"
class="medium-9 columns"
:label="$t('INBOX_MGMT.SMTP.ADDRESS.LABEL')"
:placeholder="$t('INBOX_MGMT.SMTP.ADDRESS.PLACE_HOLDER')"
@blur="v$.address.$touch"
@blur="$v.address.$touch"
/>
<woot-input
v-model="port"
type="number"
:class="{ error: v$.port.$error }"
:class="{ error: $v.port.$error }"
class="medium-9 columns"
:label="$t('INBOX_MGMT.SMTP.PORT.LABEL')"
:placeholder="$t('INBOX_MGMT.SMTP.PORT.PLACE_HOLDER')"
@blur="v$.port.$touch"
@blur="$v.port.$touch"
/>
<woot-input
v-model="login"
:class="{ error: v$.login.$error }"
:class="{ error: $v.login.$error }"
class="medium-9 columns"
:label="$t('INBOX_MGMT.SMTP.LOGIN.LABEL')"
:placeholder="$t('INBOX_MGMT.SMTP.LOGIN.PLACE_HOLDER')"
@blur="v$.login.$touch"
@blur="$v.login.$touch"
/>
<woot-input
v-model="password"
:class="{ error: v$.password.$error }"
:class="{ error: $v.password.$error }"
class="medium-9 columns"
:label="$t('INBOX_MGMT.SMTP.PASSWORD.LABEL')"
:placeholder="$t('INBOX_MGMT.SMTP.PASSWORD.PLACE_HOLDER')"
type="password"
@blur="v$.password.$touch"
@blur="$v.password.$touch"
/>
<woot-input
v-model.trim="domain"
:class="{ error: v$.domain.$error }"
:class="{ error: $v.domain.$error }"
class="medium-9 columns"
:label="$t('INBOX_MGMT.SMTP.DOMAIN.LABEL')"
:placeholder="$t('INBOX_MGMT.SMTP.DOMAIN.PLACE_HOLDER')"
@blur="v$.domain.$touch"
@blur="$v.domain.$touch"
/>
<input-radio-group
:label="$t('INBOX_MGMT.SMTP.ENCRYPTION')"
@@ -80,7 +80,7 @@
<woot-submit-button
:button-text="$t('INBOX_MGMT.SMTP.UPDATE')"
:loading="uiFlags.isUpdatingSMTP"
:disabled="(v$.$invalid && isSMTPEnabled) || uiFlags.isUpdatingSMTP"
:disabled="($v.$invalid && isSMTPEnabled) || uiFlags.isUpdatingSMTP"
/>
</form>
</settings-section>
@@ -91,10 +91,9 @@
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import SettingsSection from 'dashboard/components/SettingsSection.vue';
import { required, minLength } from '@vuelidate/validators';
import { required, minLength } from 'vuelidate/lib/validators';
import InputRadioGroup from './components/InputRadioGroup.vue';
import SingleSelectDropdown from './components/SingleSelectDropdown.vue';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -109,9 +108,6 @@ export default {
default: () => ({}),
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
isSMTPEnabled: false,
@@ -5,8 +5,9 @@
<div class="settings-content">
<form @submit.prevent="updateWidget">
<woot-avatar-uploader
:label="$t('INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.AVATAR.LABEL')
"
:label="
$t('INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.AVATAR.LABEL')
"
:src="avatarUrl"
delete-avatar
@change="handleImageUpload"
@@ -14,39 +15,45 @@
/>
<woot-input
v-model.trim="websiteName"
:class="{ error: v$.websiteName.$error }"
:label="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WEBSITE_NAME.LABEL'
)
"
:placeholder="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WEBSITE_NAME.PLACE_HOLDER'
)
"
:class="{ error: $v.websiteName.$error }"
:label="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WEBSITE_NAME.LABEL'
)
"
:placeholder="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WEBSITE_NAME.PLACE_HOLDER'
)
"
:error="websiteNameValidationErrorMsg"
@blur="v$.websiteName.$touch"
@blur="$v.websiteName.$touch"
/>
<woot-input
v-model.trim="welcomeHeading"
:label="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WELCOME_HEADING.LABEL'
)
"
:placeholder="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WELCOME_HEADING.PLACE_HOLDER'
)
"
:label="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WELCOME_HEADING.LABEL'
)
"
:placeholder="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WELCOME_HEADING.PLACE_HOLDER'
)
"
/>
<woot-input
v-model.trim="welcomeTagline"
:label="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WELCOME_TAGLINE.LABEL'
)
"
:placeholder="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WELCOME_TAGLINE.PLACE_HOLDER'
)
"
:label="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WELCOME_TAGLINE.LABEL'
)
"
:placeholder="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WELCOME_TAGLINE.PLACE_HOLDER'
)
"
/>
<label>
{{
@@ -72,41 +79,46 @@
</label>
<input-radio-group
name="widget-bubble-position"
:label="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WIDGET_BUBBLE_POSITION_LABEL'
)
"
:label="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WIDGET_BUBBLE_POSITION_LABEL'
)
"
:items="widgetBubblePositions"
:action="handleWidgetBubblePositionChange"
/>
<input-radio-group
name="widget-bubble-type"
:label="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WIDGET_BUBBLE_TYPE_LABEL'
)
"
:label="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WIDGET_BUBBLE_TYPE_LABEL'
)
"
:items="widgetBubbleTypes"
:action="handleWidgetBubbleTypeChange"
/>
<woot-input
v-model.trim="widgetBubbleLauncherTitle"
:label="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WIDGET_BUBBLE_LAUNCHER_TITLE.LABEL'
)
"
:placeholder="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WIDGET_BUBBLE_LAUNCHER_TITLE.PLACE_HOLDER'
)
"
:label="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WIDGET_BUBBLE_LAUNCHER_TITLE.LABEL'
)
"
:placeholder="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WIDGET_BUBBLE_LAUNCHER_TITLE.PLACE_HOLDER'
)
"
/>
<woot-submit-button
class="submit-button"
:button-text="$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.UPDATE.BUTTON_TEXT'
)
"
:button-text="
$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.UPDATE.BUTTON_TEXT'
)
"
:loading="uiFlags.isUpdating"
:disabled="v$.$invalid || uiFlags.isUpdating"
:disabled="$v.$invalid || uiFlags.isUpdating"
/>
</form>
</div>
@@ -118,10 +130,7 @@
:action="handleWidgetViewChange"
:style="{ 'text-align': 'center' }"
/>
<div
v-if="isWidgetPreview"
class="widget-preview"
>
<div v-if="isWidgetPreview" class="widget-preview">
<Widget
:welcome-heading="welcomeHeading"
:welcome-tagline="welcomeTagline"
@@ -135,10 +144,7 @@
:widget-bubble-type="widgetBubbleType"
/>
</div>
<div
v-else
class="widget-script"
>
<div v-else class="widget-script">
<woot-code :script="widgetScript" />
</div>
</div>
@@ -151,10 +157,9 @@ import { mapGetters } from 'vuex';
import Widget from 'dashboard/modules/widget-preview/components/Widget.vue';
import InputRadioGroup from './components/InputRadioGroup.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
import { LocalStorage } from 'shared/helpers/localStorage';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -165,12 +170,9 @@ export default {
props: {
inbox: {
type: Object,
default: () => { },
default: () => {},
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
isWidgetPreview: true,
@@ -286,7 +288,7 @@ export default {
];
},
websiteNameValidationErrorMsg() {
return this.v$.websiteName.$error
return this.$v.websiteName.$error
? this.$t('INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.WEBSITE_NAME.ERROR')
: '';
},
@@ -363,8 +365,8 @@ export default {
error.message
? error.message
: this.$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.AVATAR.DELETE.API.ERROR_MESSAGE'
)
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.AVATAR.DELETE.API.ERROR_MESSAGE'
)
);
}
},
@@ -400,9 +402,9 @@ export default {
} catch (error) {
this.showAlert(
error.message ||
this.$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.UPDATE.API.ERROR_MESSAGE'
)
this.$t(
'INBOX_MGMT.WIDGET_BUILDER.WIDGET_OPTIONS.UPDATE.API.ERROR_MESSAGE'
)
);
}
},
@@ -414,12 +416,15 @@ export default {
</script>
<style lang="scss" scoped>
@import 'dashboard/assets/scss/woot';
@import '~dashboard/assets/scss/woot';
.widget-builder-container {
display: flex;
flex-direction: row;
padding: var(--space-one);
@include breakpoint(900px down) {
flex-direction: column;
}
}
.settings-container {
@@ -445,11 +450,10 @@ export default {
padding: var(--space-one) var(--space-one) var(--space-one) var(--space-one);
@apply bg-slate-50 dark:bg-slate-700;
// @include breakpoint(500px down) {
// background: none;
// }
@include breakpoint(500px down) {
background: none;
}
}
.widget-script {
@apply mx-5 p-2.5 bg-slate-50 dark:bg-slate-700;
}
@@ -1,12 +1,12 @@
import Facebook from './channels/Facebook.vue';
import Website from './channels/Website.vue';
import Twitter from './channels/Twitter.vue';
import Api from './channels/Api.vue';
import Email from './channels/Email.vue';
import Sms from './channels/Sms.vue';
import Whatsapp from './channels/Whatsapp.vue';
import Line from './channels/Line.vue';
import Telegram from './channels/Telegram.vue';
import Facebook from './channels/Facebook';
import Website from './channels/Website';
import Twitter from './channels/Twitter';
import Api from './channels/Api';
import Email from './channels/Email';
import Sms from './channels/Sms';
import Whatsapp from './channels/Whatsapp';
import Line from './channels/Line';
import Telegram from './channels/Telegram';
const channelViewList = {
facebook: Facebook,
@@ -1,37 +1,37 @@
<template>
<form class="mx-0 flex flex-wrap" @submit.prevent="createChannel()">
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.inboxName.$error }">
<label :class="{ error: $v.inboxName.$error }">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.INBOX_NAME.LABEL') }}
<input
v-model.trim="inboxName"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.WHATSAPP.INBOX_NAME.PLACEHOLDER')"
@blur="v$.inboxName.$touch"
@blur="$v.inboxName.$touch"
/>
<span v-if="v$.inboxName.$error" class="message">
<span v-if="$v.inboxName.$error" class="message">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.INBOX_NAME.ERROR') }}
</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.phoneNumber.$error }">
<label :class="{ error: $v.phoneNumber.$error }">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.PHONE_NUMBER.LABEL') }}
<input
v-model.trim="phoneNumber"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.WHATSAPP.PHONE_NUMBER.PLACEHOLDER')"
@blur="v$.phoneNumber.$touch"
@blur="$v.phoneNumber.$touch"
/>
<span v-if="v$.phoneNumber.$error" class="message">
<span v-if="$v.phoneNumber.$error" class="message">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.PHONE_NUMBER.ERROR') }}
</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.apiKey.$error }">
<label :class="{ error: $v.apiKey.$error }">
<span>
{{ $t('INBOX_MGMT.ADD.WHATSAPP.API_KEY.LABEL') }}
</span>
@@ -39,9 +39,9 @@
v-model.trim="apiKey"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.WHATSAPP.API_KEY.PLACEHOLDER')"
@blur="v$.apiKey.$touch"
@blur="$v.apiKey.$touch"
/>
<span v-if="v$.apiKey.$error" class="message">
<span v-if="$v.apiKey.$error" class="message">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.API_KEY.ERROR') }}
</span>
</label>
@@ -59,17 +59,13 @@
<script>
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import router from '../../../../index';
import { isPhoneE164OrEmpty } from 'shared/helpers/Validators';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [alertMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
inboxName: '',
@@ -87,8 +83,8 @@ export default {
},
methods: {
async createChannel() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
@@ -6,7 +6,7 @@
/>
<form class="mx-0 flex flex-wrap" @submit.prevent="createChannel()">
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.channelName.$error }">
<label :class="{ error: $v.channelName.$error }">
{{ $t('INBOX_MGMT.ADD.API_CHANNEL.CHANNEL_NAME.LABEL') }}
<input
v-model.trim="channelName"
@@ -14,16 +14,16 @@
:placeholder="
$t('INBOX_MGMT.ADD.API_CHANNEL.CHANNEL_NAME.PLACEHOLDER')
"
@blur="v$.channelName.$touch"
@blur="$v.channelName.$touch"
/>
<span v-if="v$.channelName.$error" class="message">{{
<span v-if="$v.channelName.$error" class="message">{{
$t('INBOX_MGMT.ADD.API_CHANNEL.CHANNEL_NAME.ERROR')
}}</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.webhookUrl.$error }">
<label :class="{ error: $v.webhookUrl.$error }">
{{ $t('INBOX_MGMT.ADD.API_CHANNEL.WEBHOOK_URL.LABEL') }}
<input
v-model.trim="webhookUrl"
@@ -31,7 +31,7 @@
:placeholder="
$t('INBOX_MGMT.ADD.API_CHANNEL.WEBHOOK_URL.PLACEHOLDER')
"
@blur="v$.webhookUrl.$touch"
@blur="$v.webhookUrl.$touch"
/>
</label>
<p class="help-text">
@@ -52,10 +52,9 @@
<script>
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import router from '../../../../index';
import PageHeader from '../../SettingsSubPageHeader.vue';
import { useVuelidate } from '@vuelidate/core';
const shouldBeWebhookUrl = (value = '') =>
value ? value.startsWith('http') : true;
@@ -65,9 +64,6 @@ export default {
PageHeader,
},
mixins: [alertMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
channelName: '',
@@ -85,8 +81,8 @@ export default {
},
methods: {
async createChannel() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
@@ -1,7 +1,7 @@
<template>
<form class="mx-0 flex flex-wrap" @submit.prevent="createChannel()">
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.inboxName.$error }">
<label :class="{ error: $v.inboxName.$error }">
{{ $t('INBOX_MGMT.ADD.SMS.BANDWIDTH.INBOX_NAME.LABEL') }}
<input
v-model.trim="inboxName"
@@ -9,16 +9,16 @@
:placeholder="
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.INBOX_NAME.PLACEHOLDER')
"
@blur="v$.inboxName.$touch"
@blur="$v.inboxName.$touch"
/>
<span v-if="v$.inboxName.$error" class="message">{{
<span v-if="$v.inboxName.$error" class="message">{{
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.INBOX_NAME.ERROR')
}}</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.phoneNumber.$error }">
<label :class="{ error: $v.phoneNumber.$error }">
{{ $t('INBOX_MGMT.ADD.SMS.BANDWIDTH.PHONE_NUMBER.LABEL') }}
<input
v-model.trim="phoneNumber"
@@ -26,16 +26,16 @@
:placeholder="
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.PHONE_NUMBER.PLACEHOLDER')
"
@blur="v$.phoneNumber.$touch"
@blur="$v.phoneNumber.$touch"
/>
<span v-if="v$.phoneNumber.$error" class="message">{{
<span v-if="$v.phoneNumber.$error" class="message">{{
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.PHONE_NUMBER.ERROR')
}}</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.accountId.$error }">
<label :class="{ error: $v.accountId.$error }">
{{ $t('INBOX_MGMT.ADD.SMS.BANDWIDTH.ACCOUNT_ID.LABEL') }}
<input
v-model.trim="accountId"
@@ -43,16 +43,16 @@
:placeholder="
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.ACCOUNT_ID.PLACEHOLDER')
"
@blur="v$.accountId.$touch"
@blur="$v.accountId.$touch"
/>
<span v-if="v$.accountId.$error" class="message">{{
<span v-if="$v.accountId.$error" class="message">{{
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.ACCOUNT_ID.ERROR')
}}</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.applicationId.$error }">
<label :class="{ error: $v.applicationId.$error }">
{{ $t('INBOX_MGMT.ADD.SMS.BANDWIDTH.APPLICATION_ID.LABEL') }}
<input
v-model.trim="applicationId"
@@ -60,31 +60,31 @@
:placeholder="
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.APPLICATION_ID.PLACEHOLDER')
"
@blur="v$.applicationId.$touch"
@blur="$v.applicationId.$touch"
/>
<span v-if="v$.applicationId.$error" class="message">{{
<span v-if="$v.applicationId.$error" class="message">{{
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.APPLICATION_ID.ERROR')
}}</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.apiKey.$error }">
<label :class="{ error: $v.apiKey.$error }">
{{ $t('INBOX_MGMT.ADD.SMS.BANDWIDTH.API_KEY.LABEL') }}
<input
v-model.trim="apiKey"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.API_KEY.PLACEHOLDER')"
@blur="v$.apiKey.$touch"
@blur="$v.apiKey.$touch"
/>
<span v-if="v$.apiKey.$error" class="message">{{
<span v-if="$v.apiKey.$error" class="message">{{
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.API_KEY.ERROR')
}}</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.apiSecret.$error }">
<label :class="{ error: $v.apiSecret.$error }">
{{ $t('INBOX_MGMT.ADD.SMS.BANDWIDTH.API_SECRET.LABEL') }}
<input
v-model.trim="apiSecret"
@@ -92,9 +92,9 @@
:placeholder="
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.API_SECRET.PLACEHOLDER')
"
@blur="v$.apiSecret.$touch"
@blur="$v.apiSecret.$touch"
/>
<span v-if="v$.apiSecret.$error" class="message">{{
<span v-if="$v.apiSecret.$error" class="message">{{
$t('INBOX_MGMT.ADD.SMS.BANDWIDTH.API_SECRET.ERROR')
}}</span>
</label>
@@ -112,17 +112,13 @@
<script>
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import router from '../../../../index';
const shouldStartWithPlusSign = (value = '') => value.startsWith('+');
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [alertMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
accountId: '',
@@ -149,8 +145,8 @@ export default {
},
methods: {
async createChannel() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
@@ -1,37 +1,37 @@
<template>
<form class="mx-0 flex flex-wrap" @submit.prevent="createChannel()">
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.inboxName.$error }">
<label :class="{ error: $v.inboxName.$error }">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.INBOX_NAME.LABEL') }}
<input
v-model.trim="inboxName"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.WHATSAPP.INBOX_NAME.PLACEHOLDER')"
@blur="v$.inboxName.$touch"
@blur="$v.inboxName.$touch"
/>
<span v-if="v$.inboxName.$error" class="message">
<span v-if="$v.inboxName.$error" class="message">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.INBOX_NAME.ERROR') }}
</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.phoneNumber.$error }">
<label :class="{ error: $v.phoneNumber.$error }">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.PHONE_NUMBER.LABEL') }}
<input
v-model.trim="phoneNumber"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.WHATSAPP.PHONE_NUMBER.PLACEHOLDER')"
@blur="v$.phoneNumber.$touch"
@blur="$v.phoneNumber.$touch"
/>
<span v-if="v$.phoneNumber.$error" class="message">
<span v-if="$v.phoneNumber.$error" class="message">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.PHONE_NUMBER.ERROR') }}
</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.phoneNumberId.$error }">
<label :class="{ error: $v.phoneNumberId.$error }">
<span>
{{ $t('INBOX_MGMT.ADD.WHATSAPP.PHONE_NUMBER_ID.LABEL') }}
</span>
@@ -41,16 +41,16 @@
:placeholder="
$t('INBOX_MGMT.ADD.WHATSAPP.PHONE_NUMBER_ID.PLACEHOLDER')
"
@blur="v$.phoneNumberId.$touch"
@blur="$v.phoneNumberId.$touch"
/>
<span v-if="v$.phoneNumberId.$error" class="message">
<span v-if="$v.phoneNumberId.$error" class="message">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.PHONE_NUMBER_ID.ERROR') }}
</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.businessAccountId.$error }">
<label :class="{ error: $v.businessAccountId.$error }">
<span>
{{ $t('INBOX_MGMT.ADD.WHATSAPP.BUSINESS_ACCOUNT_ID.LABEL') }}
</span>
@@ -60,16 +60,16 @@
:placeholder="
$t('INBOX_MGMT.ADD.WHATSAPP.BUSINESS_ACCOUNT_ID.PLACEHOLDER')
"
@blur="v$.businessAccountId.$touch"
@blur="$v.businessAccountId.$touch"
/>
<span v-if="v$.businessAccountId.$error" class="message">
<span v-if="$v.businessAccountId.$error" class="message">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.BUSINESS_ACCOUNT_ID.ERROR') }}
</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.apiKey.$error }">
<label :class="{ error: $v.apiKey.$error }">
<span>
{{ $t('INBOX_MGMT.ADD.WHATSAPP.API_KEY.LABEL') }}
</span>
@@ -77,9 +77,9 @@
v-model.trim="apiKey"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.WHATSAPP.API_KEY.PLACEHOLDER')"
@blur="v$.apiKey.$touch"
@blur="$v.apiKey.$touch"
/>
<span v-if="v$.apiKey.$error" class="message">
<span v-if="$v.apiKey.$error" class="message">
{{ $t('INBOX_MGMT.ADD.WHATSAPP.API_KEY.ERROR') }}
</span>
</label>
@@ -97,16 +97,12 @@
<script>
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import router from '../../../../index';
import { isPhoneE164OrEmpty, isNumber } from 'shared/helpers/Validators';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [alertMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
inboxName: '',
@@ -128,8 +124,8 @@ export default {
},
methods: {
async createChannel() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
@@ -43,7 +43,7 @@
</div>
<div class="w-[60%]">
<div class="w-full">
<div class="input-wrap" :class="{ error: v$.selectedPage.$error }">
<div class="input-wrap" :class="{ error: $v.selectedPage.$error }">
{{ $t('INBOX_MGMT.ADD.FB.CHOOSE_PAGE') }}
<multiselect
v-model.trim="selectedPage"
@@ -58,21 +58,21 @@
selected-label
@select="setPageName"
/>
<span v-if="v$.selectedPage.$error" class="message">
<span v-if="$v.selectedPage.$error" class="message">
{{ $t('INBOX_MGMT.ADD.FB.CHOOSE_PLACEHOLDER') }}
</span>
</div>
</div>
<div class="w-full">
<label :class="{ error: v$.pageName.$error }">
<label :class="{ error: $v.pageName.$error }">
{{ $t('INBOX_MGMT.ADD.FB.INBOX_NAME') }}
<input
v-model.trim="pageName"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.FB.PICK_NAME')"
@input="v$.pageName.$touch"
@input="$v.pageName.$touch"
/>
<span v-if="v$.pageName.$error" class="message">
<span v-if="$v.pageName.$error" class="message">
{{ $t('INBOX_MGMT.ADD.FB.ADD_NAME') }}
</span>
</label>
@@ -88,7 +88,7 @@
<script>
/* eslint-env browser */
/* global FB */
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import LoadingState from 'dashboard/components/widgets/LoadingState.vue';
import { mapGetters } from 'vuex';
import ChannelApi from '../../../../../api/channels';
@@ -96,7 +96,6 @@ import PageHeader from '../../SettingsSubPageHeader.vue';
import router from '../../../../index';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import accountMixin from '../../../../../mixins/account';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -104,9 +103,6 @@ export default {
PageHeader,
},
mixins: [globalConfigMixin, accountMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
isCreating: false,
@@ -165,7 +161,7 @@ export default {
},
setPageName({ name }) {
this.v$.selectedPage.$touch();
this.$v.selectedPage.$touch();
this.pageName = name;
},
@@ -267,8 +263,8 @@ export default {
},
createChannel() {
this.v$.$touch();
if (!this.v$.$error) {
this.$v.$touch();
if (!this.$v.$error) {
this.emptyStateMessage = this.$t('INBOX_MGMT.DETAILS.CREATING_CHANNEL');
this.isCreating = true;
this.$store
@@ -6,7 +6,7 @@
/>
<form class="mx-0 flex flex-wrap" @submit.prevent="createChannel()">
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.channelName.$error }">
<label :class="{ error: $v.channelName.$error }">
{{ $t('INBOX_MGMT.ADD.LINE_CHANNEL.CHANNEL_NAME.LABEL') }}
<input
v-model.trim="channelName"
@@ -14,16 +14,16 @@
:placeholder="
$t('INBOX_MGMT.ADD.LINE_CHANNEL.CHANNEL_NAME.PLACEHOLDER')
"
@blur="v$.channelName.$touch"
@blur="$v.channelName.$touch"
/>
<span v-if="v$.channelName.$error" class="message">{{
<span v-if="$v.channelName.$error" class="message">{{
$t('INBOX_MGMT.ADD.LINE_CHANNEL.CHANNEL_NAME.ERROR')
}}</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.lineChannelId.$error }">
<label :class="{ error: $v.lineChannelId.$error }">
{{ $t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_ID.LABEL') }}
<input
v-model.trim="lineChannelId"
@@ -31,13 +31,13 @@
:placeholder="
$t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_ID.PLACEHOLDER')
"
@blur="v$.lineChannelId.$touch"
@blur="$v.lineChannelId.$touch"
/>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.lineChannelSecret.$error }">
<label :class="{ error: $v.lineChannelSecret.$error }">
{{ $t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_SECRET.LABEL') }}
<input
v-model.trim="lineChannelSecret"
@@ -45,13 +45,13 @@
:placeholder="
$t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_SECRET.PLACEHOLDER')
"
@blur="v$.lineChannelSecret.$touch"
@blur="$v.lineChannelSecret.$touch"
/>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.lineChannelToken.$error }">
<label :class="{ error: $v.lineChannelToken.$error }">
{{ $t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_TOKEN.LABEL') }}
<input
v-model.trim="lineChannelToken"
@@ -59,7 +59,7 @@
:placeholder="
$t('INBOX_MGMT.ADD.LINE_CHANNEL.LINE_CHANNEL_TOKEN.PLACEHOLDER')
"
@blur="v$.lineChannelToken.$touch"
@blur="$v.lineChannelToken.$touch"
/>
</label>
</div>
@@ -77,19 +77,15 @@
<script>
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import router from '../../../../index';
import PageHeader from '../../SettingsSubPageHeader.vue';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
PageHeader,
},
mixins: [alertMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
channelName: '',
@@ -111,8 +107,8 @@ export default {
},
methods: {
async createChannel() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
@@ -6,7 +6,7 @@
/>
<form class="mx-0 flex flex-wrap" @submit.prevent="createChannel()">
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.botToken.$error }">
<label :class="{ error: $v.botToken.$error }">
{{ $t('INBOX_MGMT.ADD.TELEGRAM_CHANNEL.BOT_TOKEN.LABEL') }}
<input
v-model.trim="botToken"
@@ -14,7 +14,7 @@
:placeholder="
$t('INBOX_MGMT.ADD.TELEGRAM_CHANNEL.BOT_TOKEN.PLACEHOLDER')
"
@blur="v$.botToken.$touch"
@blur="$v.botToken.$touch"
/>
</label>
<p class="help-text">
@@ -35,19 +35,15 @@
<script>
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import router from '../../../../index';
import PageHeader from '../../SettingsSubPageHeader.vue';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
PageHeader,
},
mixins: [alertMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
botToken: '',
@@ -63,8 +59,8 @@ export default {
},
methods: {
async createChannel() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
@@ -2,15 +2,15 @@
<template>
<form class="mx-0 flex flex-wrap" @submit.prevent="createChannel()">
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.channelName.$error }">
<label :class="{ error: $v.channelName.$error }">
{{ $t('INBOX_MGMT.ADD.TWILIO.CHANNEL_NAME.LABEL') }}
<input
v-model.trim="channelName"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.CHANNEL_NAME.PLACEHOLDER')"
@blur="v$.channelName.$touch"
@blur="$v.channelName.$touch"
/>
<span v-if="v$.channelName.$error" class="message">{{
<span v-if="$v.channelName.$error" class="message">{{
$t('INBOX_MGMT.ADD.TWILIO.CHANNEL_NAME.ERROR')
}}</span>
</label>
@@ -19,7 +19,7 @@
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label
v-if="useMessagingService"
:class="{ error: v$.messagingServiceSID.$error }"
:class="{ error: $v.messagingServiceSID.$error }"
>
{{ $t('INBOX_MGMT.ADD.TWILIO.MESSAGING_SERVICE_SID.LABEL') }}
<input
@@ -28,9 +28,9 @@
:placeholder="
$t('INBOX_MGMT.ADD.TWILIO.MESSAGING_SERVICE_SID.PLACEHOLDER')
"
@blur="v$.messagingServiceSID.$touch"
@blur="$v.messagingServiceSID.$touch"
/>
<span v-if="v$.messagingServiceSID.$error" class="message">{{
<span v-if="$v.messagingServiceSID.$error" class="message">{{
$t('INBOX_MGMT.ADD.TWILIO.MESSAGING_SERVICE_SID.ERROR')
}}</span>
</label>
@@ -40,15 +40,15 @@
v-if="!useMessagingService"
class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]"
>
<label :class="{ error: v$.phoneNumber.$error }">
<label :class="{ error: $v.phoneNumber.$error }">
{{ $t('INBOX_MGMT.ADD.TWILIO.PHONE_NUMBER.LABEL') }}
<input
v-model.trim="phoneNumber"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.PHONE_NUMBER.PLACEHOLDER')"
@blur="v$.phoneNumber.$touch"
@blur="$v.phoneNumber.$touch"
/>
<span v-if="v$.phoneNumber.$error" class="message">{{
<span v-if="$v.phoneNumber.$error" class="message">{{
$t('INBOX_MGMT.ADD.TWILIO.PHONE_NUMBER.ERROR')
}}</span>
</label>
@@ -71,15 +71,15 @@
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.accountSID.$error }">
<label :class="{ error: $v.accountSID.$error }">
{{ $t('INBOX_MGMT.ADD.TWILIO.ACCOUNT_SID.LABEL') }}
<input
v-model.trim="accountSID"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.ACCOUNT_SID.PLACEHOLDER')"
@blur="v$.accountSID.$touch"
@blur="$v.accountSID.$touch"
/>
<span v-if="v$.accountSID.$error" class="message">{{
<span v-if="$v.accountSID.$error" class="message">{{
$t('INBOX_MGMT.ADD.TWILIO.ACCOUNT_SID.ERROR')
}}</span>
</label>
@@ -96,21 +96,21 @@
</label>
</div>
<div v-if="useAPIKey" class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.apiKeySID.$error }">
<label :class="{ error: $v.apiKeySID.$error }">
{{ $t('INBOX_MGMT.ADD.TWILIO.API_KEY.LABEL') }}
<input
v-model.trim="apiKeySID"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.API_KEY.PLACEHOLDER')"
@blur="v$.apiKeySID.$touch"
@blur="$v.apiKeySID.$touch"
/>
<span v-if="v$.apiKeySID.$error" class="message">{{
<span v-if="$v.apiKeySID.$error" class="message">{{
$t('INBOX_MGMT.ADD.TWILIO.API_KEY.ERROR')
}}</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.authToken.$error }">
<label :class="{ error: $v.authToken.$error }">
{{ $t(`INBOX_MGMT.ADD.TWILIO.${authTokeni18nKey}.LABEL`) }}
<input
v-model.trim="authToken"
@@ -118,9 +118,9 @@
:placeholder="
$t(`INBOX_MGMT.ADD.TWILIO.${authTokeni18nKey}.PLACEHOLDER`)
"
@blur="v$.authToken.$touch"
@blur="$v.authToken.$touch"
/>
<span v-if="v$.authToken.$error" class="message">
<span v-if="$v.authToken.$error" class="message">
{{ $t(`INBOX_MGMT.ADD.TWILIO.${authTokeni18nKey}.ERROR`) }}
</span>
</label>
@@ -138,10 +138,9 @@
<script>
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import { required } from '@vuelidate/validators';
import { required } from 'vuelidate/lib/validators';
import router from '../../../../index';
import { isPhoneE164OrEmpty } from 'shared/helpers/Validators';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [alertMixin],
@@ -151,9 +150,6 @@ export default {
required: true,
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
accountSID: '',
@@ -207,8 +203,8 @@ export default {
},
methods: {
async createChannel() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
@@ -6,7 +6,7 @@
/>
<form class="mx-0 flex flex-wrap" @submit.prevent="createChannel()">
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.channelName.$error }">
<label :class="{ error: $v.channelName.$error }">
{{ $t('INBOX_MGMT.ADD.EMAIL_CHANNEL.CHANNEL_NAME.LABEL') }}
<input
v-model.trim="channelName"
@@ -14,22 +14,22 @@
:placeholder="
$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.CHANNEL_NAME.PLACEHOLDER')
"
@blur="v$.channelName.$touch"
@blur="$v.channelName.$touch"
/>
<span v-if="v$.channelName.$error" class="message">{{
<span v-if="$v.channelName.$error" class="message">{{
$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.CHANNEL_NAME.ERROR')
}}</span>
</label>
</div>
<div class="w-[65%] flex-shrink-0 flex-grow-0 max-w-[65%]">
<label :class="{ error: v$.email.$error }">
<label :class="{ error: $v.email.$error }">
{{ $t('INBOX_MGMT.ADD.EMAIL_CHANNEL.EMAIL.LABEL') }}
<input
v-model.trim="email"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.EMAIL.PLACEHOLDER')"
@blur="v$.email.$touch"
@blur="$v.email.$touch"
/>
</label>
<p class="help-text">
@@ -50,19 +50,15 @@
<script>
import { mapGetters } from 'vuex';
import alertMixin from 'shared/mixins/alertMixin';
import { required, email } from '@vuelidate/validators';
import { required, email } from 'vuelidate/lib/validators';
import router from '../../../../../index';
import PageHeader from '../../../SettingsSubPageHeader.vue';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
PageHeader,
},
mixins: [alertMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return {
channelName: '',
@@ -81,8 +77,8 @@ export default {
},
methods: {
async createChannel() {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
@@ -12,7 +12,7 @@
v-model.trim="email"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.MICROSOFT.EMAIL_PLACEHOLDER')"
@blur="v$.email.$touch"
@blur="$v.email.$touch"
/>
<woot-submit-button
icon="brand-twitter"
@@ -27,15 +27,11 @@
import alertMixin from 'shared/mixins/alertMixin';
import microsoftClient from 'dashboard/api/channel/microsoftClient';
import SettingsSubPageHeader from '../../../SettingsSubPageHeader.vue';
import { required, email } from '@vuelidate/validators';
import { useVuelidate } from '@vuelidate/core';
import { required, email } from 'vuelidate/lib/validators';
export default {
components: { SettingsSubPageHeader },
mixins: [alertMixin],
setup() {
return { v$: useVuelidate() };
},
data() {
return { email: '', isRequestingAuthorization: false };
},
@@ -45,8 +41,8 @@ export default {
methods: {
async requestAuthorization() {
try {
this.v$.$touch();
if (this.v$.$invalid) return;
this.$v.$touch();
if (this.$v.$invalid) return;
this.isRequestingAuthorization = true;
const response = await microsoftClient.generateAuthorization({
@@ -105,7 +105,7 @@ export default {
</script>
<style lang="scss" scoped>
@import 'dashboard/assets/scss/variables';
@import '~dashboard/assets/scss/variables';
.fb--login {
img {
@@ -17,7 +17,7 @@
selected-label
:select-label="$t('FORMS.MULTISELECT.ENTER_TO_SELECT')"
:deselect-label="$t('FORMS.MULTISELECT.ENTER_TO_REMOVE')"
@select="v$.selectedAgents.$touch"
@select="$v.selectedAgents.$touch"
/>
<woot-submit-button
@@ -56,10 +56,10 @@
<woot-input
v-model.trim="maxAssignmentLimit"
type="number"
:class="{ error: v$.maxAssignmentLimit.$error }"
:class="{ error: $v.maxAssignmentLimit.$error }"
:error="maxAssignmentLimitErrors"
:label="$t('INBOX_MGMT.AUTO_ASSIGNMENT.MAX_ASSIGNMENT_LIMIT')"
@blur="v$.maxAssignmentLimit.$touch"
@blur="$v.maxAssignmentLimit.$touch"
/>
<p class="pb-1 text-sm not-italic text-slate-600 dark:text-slate-400">
@@ -68,7 +68,7 @@
<woot-submit-button
:button-text="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
:disabled="v$.maxAssignmentLimit.$invalid"
:disabled="$v.maxAssignmentLimit.$invalid"
@click="updateInbox"
/>
</div>
@@ -78,11 +78,10 @@
<script>
import { mapGetters } from 'vuex';
import { minValue } from '@vuelidate/validators';
import { minValue } from 'vuelidate/lib/validators';
import alertMixin from 'shared/mixins/alertMixin';
import configMixin from 'shared/mixins/configMixin';
import SettingsSection from '../../../../../components/SettingsSection.vue';
import { useVuelidate } from '@vuelidate/core';
export default {
components: {
@@ -95,9 +94,6 @@ export default {
default: () => ({}),
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
selectedAgents: [],
@@ -111,7 +107,7 @@ export default {
agentList: 'agents/getAgents',
}),
maxAssignmentLimitErrors() {
if (this.v$.maxAssignmentLimit.$error) {
if (this.$v.maxAssignmentLimit.$error) {
return this.$t(
'INBOX_MGMT.AUTO_ASSIGNMENT.MAX_ASSIGNMENT_LIMIT_RANGE_ERROR'
);
@@ -195,8 +191,8 @@ export default {
</script>
<style scoped lang="scss">
@import 'dashboard/assets/scss/variables';
@import 'dashboard/assets/scss/mixins';
@import '~dashboard/assets/scss/variables';
@import '~dashboard/assets/scss/mixins';
.max-assignment-container {
padding-top: var(--space-slab);
@@ -141,7 +141,7 @@
"
/>
<woot-button
:disabled="v$.whatsAppInboxAPIKey.$invalid"
:disabled="$v.whatsAppInboxAPIKey.$invalid"
@click="updateWhatsAppInboxAPIKey"
>
{{ $t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_SECTION_UPDATE_BUTTON') }}
@@ -159,8 +159,7 @@ import SettingsSection from '../../../../../components/SettingsSection.vue';
import ImapSettings from '../ImapSettings.vue';
import SmtpSettings from '../SmtpSettings.vue';
import MicrosoftReauthorize from '../channels/microsoft/Reauthorize.vue';
import { required } from '@vuelidate/validators';
import { useVuelidate } from '@vuelidate/core';
import { required } from 'vuelidate/lib/validators';
export default {
components: {
@@ -176,9 +175,6 @@ export default {
default: () => ({}),
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
hmacMandatory: false,
@@ -251,7 +247,6 @@ export default {
.input {
flex: 1;
margin-right: var(--space-small);
::v-deep input {
margin-bottom: 0;
}
@@ -6,40 +6,40 @@
<form class="mx-0 flex flex-wrap" @submit.prevent="submit">
<woot-input
v-model.trim="app.title"
:class="{ error: v$.app.title.$error }"
:class="{ error: $v.app.title.$error }"
class="w-full"
:label="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.FORM.TITLE_LABEL')"
:placeholder="
$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.FORM.TITLE_PLACEHOLDER')
"
:error="
v$.app.title.$error
$v.app.title.$error
? $t('INTEGRATION_SETTINGS.DASHBOARD_APPS.FORM.TITLE_ERROR')
: null
"
data-testid="app-title"
@input="v$.app.title.$touch"
@input="$v.app.title.$touch"
/>
<woot-input
v-model.trim="app.content.url"
:class="{ error: v$.app.content.url.$error }"
:class="{ error: $v.app.content.url.$error }"
class="w-full"
:label="$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.FORM.URL_LABEL')"
:placeholder="
$t('INTEGRATION_SETTINGS.DASHBOARD_APPS.FORM.URL_PLACEHOLDER')
"
:error="
v$.app.content.url.$error
$v.app.content.url.$error
? $t('INTEGRATION_SETTINGS.DASHBOARD_APPS.FORM.URL_ERROR')
: null
"
data-testid="app-url"
@input="v$.app.content.url.$touch"
@input="$v.app.content.url.$touch"
/>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
<woot-button
:is-loading="isLoading"
:is-disabled="v$.$invalid"
:is-disabled="$v.$invalid"
data-testid="label-submit"
>
{{ submitButtonLabel }}
@@ -54,9 +54,8 @@
</template>
<script>
import { required, url } from '@vuelidate/validators';
import { required, url } from 'vuelidate/lib/validators';
import alertMixin from 'shared/mixins/alertMixin';
import { useVuelidate } from '@vuelidate/core';
export default {
mixins: [alertMixin],
@@ -74,9 +73,6 @@ export default {
default: () => ({}),
},
},
setup() {
return { v$: useVuelidate() };
},
validations: {
app: {
title: { required },
@@ -125,8 +121,8 @@ export default {
},
async submit() {
try {
this.v$.$touch();
if (this.v$.$invalid) {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
@@ -1,20 +1,20 @@
<template>
<form class="flex flex-col w-full" @submit.prevent="onSubmit">
<div class="w-full">
<label :class="{ error: v$.url.$error }">
<label :class="{ error: $v.url.$error }">
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.END_POINT.LABEL') }}
<input
v-model.trim="url"
type="text"
name="url"
:placeholder="webhookURLInputPlaceholder"
@input="v$.url.$touch"
@input="$v.url.$touch"
/>
<span v-if="v$.url.$error" class="message">
<span v-if="$v.url.$error" class="message">
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.END_POINT.ERROR') }}
</span>
</label>
<label :class="{ error: v$.url.$error }" class="mb-2">
<label :class="{ error: $v.url.$error }" class="mb-2">
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.SUBSCRIPTIONS.LABEL') }}
</label>
<div v-for="event in supportedWebhookEvents" :key="event">
@@ -35,7 +35,7 @@
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
<div class="w-full">
<woot-button
:disabled="v$.$invalid || isSubmitting"
:disabled="$v.$invalid || isSubmitting"
:is-loading="isSubmitting"
>
{{ submitLabel }}
@@ -49,10 +49,9 @@
</template>
<script>
import { required, url, minLength } from '@vuelidate/validators';
import { required, url, minLength } from 'vuelidate/lib/validators';
import webhookMixin from './webhookMixin';
import wootConstants from 'dashboard/constants/globals';
import { useVuelidate } from '@vuelidate/core';
const { EXAMPLE_WEBHOOK_URL } = wootConstants;
@@ -83,9 +82,6 @@ export default {
required: true,
},
},
setup() {
return { v$: useVuelidate() };
},
validations: {
url: {
required,
@@ -7,23 +7,23 @@
<form class="mx-0 flex flex-wrap" @submit.prevent="addLabel">
<woot-input
v-model.trim="title"
:class="{ error: v$.title.$error }"
:class="{ error: $v.title.$error }"
class="w-full label-name--input"
:label="$t('LABEL_MGMT.FORM.NAME.LABEL')"
:placeholder="$t('LABEL_MGMT.FORM.NAME.PLACEHOLDER')"
:error="getLabelTitleErrorMessage"
data-testid="label-title"
@input="v$.title.$touch"
@input="$v.title.$touch"
/>
<woot-input
v-model.trim="description"
:class="{ error: v$.description.$error }"
:class="{ error: $v.description.$error }"
class="w-full"
:label="$t('LABEL_MGMT.FORM.DESCRIPTION.LABEL')"
:placeholder="$t('LABEL_MGMT.FORM.DESCRIPTION.PLACEHOLDER')"
data-testid="label-description"
@input="v$.description.$touch"
@input="$v.description.$touch"
/>
<div class="w-full">
@@ -40,7 +40,7 @@
</div>
<div class="flex justify-end items-center py-2 px-0 gap-2 w-full">
<woot-button
:is-disabled="v$.title.$invalid || uiFlags.isCreating"
:is-disabled="$v.title.$invalid || uiFlags.isCreating"
:is-loading="uiFlags.isCreating"
data-testid="label-submit"
>
@@ -4,20 +4,20 @@
<form class="mx-0 flex flex-wrap" @submit.prevent="editLabel">
<woot-input
v-model.trim="title"
:class="{ error: v$.title.$error }"
:class="{ error: $v.title.$error }"
class="w-full label-name--input"
:label="$t('LABEL_MGMT.FORM.NAME.LABEL')"
:placeholder="$t('LABEL_MGMT.FORM.NAME.PLACEHOLDER')"
:error="getLabelTitleErrorMessage"
@input="v$.title.$touch"
@input="$v.title.$touch"
/>
<woot-input
v-model.trim="description"
:class="{ error: v$.description.$error }"
:class="{ error: $v.description.$error }"
class="w-full"
:label="$t('LABEL_MGMT.FORM.DESCRIPTION.LABEL')"
:placeholder="$t('LABEL_MGMT.FORM.DESCRIPTION.PLACEHOLDER')"
@input="v$.description.$touch"
@input="$v.description.$touch"
/>
<div class="w-full">
@@ -34,7 +34,7 @@
</div>
<div class="flex justify-end items-center py-2 px-0 gap-2 w-full">
<woot-button
:is-disabled="v$.title.$invalid || uiFlags.isUpdating"
:is-disabled="$v.title.$invalid || uiFlags.isUpdating"
:is-loading="uiFlags.isUpdating"
>
{{ $t('LABEL_MGMT.FORM.EDIT') }}
@@ -188,7 +188,7 @@ export default {
</script>
<style scoped lang="scss">
@import 'dashboard/assets/scss/variables';
@import '~dashboard/assets/scss/variables';
.label-color--container {
@apply flex items-center;
@@ -197,7 +197,6 @@ export default {
.label-color--display {
@apply rounded h-4 w-4 mr-1 rtl:mr-0 rtl:ml-1 border border-solid border-slate-50 dark:border-slate-700;
}
.label-title {
span {
@apply w-60 inline-block;
@@ -1,5 +1,6 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueI18n from 'vue-i18n';
import Vuelidate from 'vuelidate';
import validationMixin from '../validationMixin';
import validations from '../validations';
@@ -7,6 +8,7 @@ import i18n from 'dashboard/i18n';
const localVue = createLocalVue();
localVue.use(VueI18n);
localVue.use(Vuelidate);
const i18nConfig = new VueI18n({
locale: 'en',
messages: i18n,
@@ -27,7 +29,7 @@ describe('validationMixin', () => {
return { title: 'sales' };
},
});
wrapper.vm.v$.$touch();
wrapper.vm.$v.$touch();
expect(wrapper.vm.getLabelTitleErrorMessage).toBe('');
});
it('it should return label required error message if empty name is passed', async () => {
@@ -38,7 +40,7 @@ describe('validationMixin', () => {
return { title: '' };
},
});
wrapper.vm.v$.$touch();
wrapper.vm.$v.$touch();
expect(wrapper.vm.getLabelTitleErrorMessage).toBe('Label name is required');
});
it('it should return label minimum length error message if one charceter label name is passed', async () => {
@@ -49,7 +51,7 @@ describe('validationMixin', () => {
return { title: 's' };
},
});
wrapper.vm.v$.$touch();
wrapper.vm.$v.$touch();
expect(wrapper.vm.getLabelTitleErrorMessage).toBe(
'Minimum length 2 is required'
);
@@ -62,7 +64,7 @@ describe('validationMixin', () => {
return { title: 'sales enquiry' };
},
});
wrapper.vm.v$.$touch();
wrapper.vm.$v.$touch();
expect(wrapper.vm.getLabelTitleErrorMessage).toBe(
'Only Alphabets, Numbers, Hyphen and Underscore are allowed'
);

Some files were not shown because too many files have changed in this diff Show More