Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97fd4885fc | ||
|
|
8498c92fdd |
@@ -6,13 +6,6 @@
|
||||
# Use `rake secret` to generate this variable
|
||||
SECRET_KEY_BASE=replace_with_lengthy_secure_hex
|
||||
|
||||
# Active Record Encryption keys (required for MFA/2FA functionality)
|
||||
# Generate these keys by running: rails db:encryption:init
|
||||
# IMPORTANT: Use different keys for each environment (development, staging, production)
|
||||
# ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=
|
||||
# ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=
|
||||
# ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=
|
||||
|
||||
# Replace with the URL you are planning to use for your app
|
||||
FRONTEND_URL=http://0.0.0.0:3000
|
||||
# To use a dedicated URL for help center pages
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
name: Run MFA Tests
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
# If two pushes happen within a short time in the same PR, cancel the run of the oldest push
|
||||
concurrency:
|
||||
group: pr-${{ github.workflow }}-${{ github.head_ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-22.04
|
||||
# Only run if MFA test keys are available
|
||||
if: github.event_name == 'workflow_dispatch' || (github.repository == 'chatwoot/chatwoot' && github.actor != 'dependabot[bot]')
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: pgvector/pgvector:pg15
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: ''
|
||||
POSTGRES_DB: postgres
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--mount type=tmpfs,destination=/var/lib/postgresql/data
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
options: --entrypoint redis-server
|
||||
|
||||
env:
|
||||
RAILS_ENV: test
|
||||
POSTGRES_HOST: localhost
|
||||
# Active Record encryption keys required for MFA - test keys only, not for production use
|
||||
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: 'test_key_a6cde8f7b9c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7'
|
||||
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: 'test_key_b7def9a8c0d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d8'
|
||||
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: 'test_salt_c8efa0b9d1e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d9'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
bundler-cache: true
|
||||
|
||||
- name: Create database
|
||||
run: bundle exec rake db:create
|
||||
|
||||
- name: Install pgvector extension
|
||||
run: |
|
||||
PGPASSWORD="" psql -h localhost -U postgres -d chatwoot_test -c "CREATE EXTENSION IF NOT EXISTS vector;"
|
||||
|
||||
- name: Seed database
|
||||
run: bundle exec rake db:schema:load
|
||||
|
||||
- name: Run MFA-related backend tests
|
||||
run: |
|
||||
bundle exec rspec \
|
||||
spec/services/mfa/token_service_spec.rb \
|
||||
spec/services/mfa/authentication_service_spec.rb \
|
||||
spec/requests/api/v1/profile/mfa_controller_spec.rb \
|
||||
spec/controllers/devise_overrides/sessions_controller_spec.rb \
|
||||
--profile=10 \
|
||||
--format documentation
|
||||
env:
|
||||
NODE_OPTIONS: --openssl-legacy-provider
|
||||
|
||||
- name: Run MFA-related tests in user_spec
|
||||
run: |
|
||||
# Run specific MFA-related tests from user_spec
|
||||
bundle exec rspec spec/models/user_spec.rb \
|
||||
-e "two factor" \
|
||||
-e "2FA" \
|
||||
-e "MFA" \
|
||||
-e "otp" \
|
||||
-e "backup code" \
|
||||
--profile=10 \
|
||||
--format documentation
|
||||
env:
|
||||
NODE_OPTIONS: --openssl-legacy-provider
|
||||
|
||||
- name: Upload test logs
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: mfa-test-logs
|
||||
path: |
|
||||
log/test.log
|
||||
tmp/screenshots/
|
||||
@@ -95,7 +95,3 @@ yarn-debug.log*
|
||||
.claude/settings.local.json
|
||||
.cursor
|
||||
CLAUDE.local.md
|
||||
|
||||
# Histoire deployment
|
||||
.netlify
|
||||
.histoire
|
||||
|
||||
@@ -78,12 +78,9 @@ gem 'barnes'
|
||||
gem 'devise', '>= 4.9.4'
|
||||
gem 'devise-secure_password', git: 'https://github.com/chatwoot/devise-secure_password', branch: 'chatwoot'
|
||||
gem 'devise_token_auth', '>= 1.2.3'
|
||||
# two-factor authentication
|
||||
gem 'devise-two-factor', '>= 5.0.0'
|
||||
# authorization
|
||||
gem 'jwt'
|
||||
gem 'pundit'
|
||||
|
||||
# super admin
|
||||
gem 'administrate', '>= 0.20.1'
|
||||
gem 'administrate-field-active_storage', '>= 1.0.3'
|
||||
@@ -174,7 +171,6 @@ gem 'audited', '~> 5.4', '>= 5.4.1'
|
||||
|
||||
# need for google auth
|
||||
gem 'omniauth', '>= 2.1.2'
|
||||
gem 'omniauth-saml'
|
||||
gem 'omniauth-google-oauth2', '>= 1.1.3'
|
||||
gem 'omniauth-rails_csrf_protection', '~> 1.0', '>= 1.0.2'
|
||||
|
||||
|
||||
+2
-17
@@ -212,11 +212,6 @@ GEM
|
||||
railties (>= 4.1.0)
|
||||
responders
|
||||
warden (~> 1.2.3)
|
||||
devise-two-factor (6.1.0)
|
||||
activesupport (>= 7.0, < 8.1)
|
||||
devise (~> 4.0)
|
||||
railties (>= 7.0, < 8.1)
|
||||
rotp (~> 6.0)
|
||||
devise_token_auth (1.2.5)
|
||||
bcrypt (~> 3.0)
|
||||
devise (> 3.5.2, < 5)
|
||||
@@ -594,9 +589,8 @@ GEM
|
||||
oj (3.16.10)
|
||||
bigdecimal (>= 3.0)
|
||||
ostruct (>= 0.2)
|
||||
omniauth (2.1.3)
|
||||
omniauth (2.1.2)
|
||||
hashie (>= 3.4.6)
|
||||
logger
|
||||
rack (>= 2.2.3)
|
||||
rack-protection
|
||||
omniauth-google-oauth2 (1.1.3)
|
||||
@@ -610,9 +604,6 @@ GEM
|
||||
omniauth-rails_csrf_protection (1.0.2)
|
||||
actionpack (>= 4.2)
|
||||
omniauth (~> 2.0)
|
||||
omniauth-saml (2.2.4)
|
||||
omniauth (~> 2.1)
|
||||
ruby-saml (~> 1.18)
|
||||
opensearch-ruby (3.4.0)
|
||||
faraday (>= 1.0, < 3)
|
||||
multi_json (>= 1.0)
|
||||
@@ -727,8 +718,7 @@ GEM
|
||||
retriable (3.1.2)
|
||||
reverse_markdown (2.1.1)
|
||||
nokogiri
|
||||
rexml (3.4.4)
|
||||
rotp (6.3.0)
|
||||
rexml (3.4.1)
|
||||
rspec-core (3.13.0)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-expectations (3.13.2)
|
||||
@@ -783,9 +773,6 @@ GEM
|
||||
faraday (>= 1)
|
||||
faraday-multipart (>= 1)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby-saml (1.18.1)
|
||||
nokogiri (>= 1.13.10)
|
||||
rexml
|
||||
ruby-vips (2.1.4)
|
||||
ffi (~> 1.12)
|
||||
ruby2_keywords (0.0.5)
|
||||
@@ -1011,7 +998,6 @@ DEPENDENCIES
|
||||
debug (~> 1.8)
|
||||
devise (>= 4.9.4)
|
||||
devise-secure_password!
|
||||
devise-two-factor (>= 5.0.0)
|
||||
devise_token_auth (>= 1.2.3)
|
||||
dotenv-rails (>= 3.0.0)
|
||||
down
|
||||
@@ -1061,7 +1047,6 @@ DEPENDENCIES
|
||||
omniauth-google-oauth2 (>= 1.1.3)
|
||||
omniauth-oauth2
|
||||
omniauth-rails_csrf_protection (~> 1.0, >= 1.0.2)
|
||||
omniauth-saml
|
||||
opensearch-ruby
|
||||
pg
|
||||
pg_search
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
||||
|
||||
require_relative 'config/application'
|
||||
# Load Enterprise Edition rake tasks if they exist
|
||||
enterprise_tasks_path = Rails.root.join('enterprise/tasks_railtie.rb').to_s
|
||||
require enterprise_tasks_path if File.exist?(enterprise_tasks_path)
|
||||
|
||||
Rails.application.load_tasks
|
||||
|
||||
# Load Enterprise Edition rake tasks if they exist
|
||||
enterprise_tasks_path = Rails.root.join('enterprise/lib/tasks.rb').to_s
|
||||
require enterprise_tasks_path if File.exist?(enterprise_tasks_path)
|
||||
|
||||
@@ -52,5 +52,3 @@ class AgentBuilder
|
||||
}.compact))
|
||||
end
|
||||
end
|
||||
|
||||
AgentBuilder.prepend_mod_with('AgentBuilder')
|
||||
|
||||
@@ -85,8 +85,7 @@ class Api::V1::Accounts::PortalsController < Api::V1::Accounts::BaseController
|
||||
|
||||
def live_chat_widget_params
|
||||
permitted_params = params.permit(:inbox_id)
|
||||
return {} unless permitted_params.key?(:inbox_id)
|
||||
return { channel_web_widget_id: nil } if permitted_params[:inbox_id].blank?
|
||||
return {} if permitted_params[:inbox_id].blank?
|
||||
|
||||
inbox = Inbox.find(permitted_params[:inbox_id])
|
||||
return {} unless inbox.web_widget?
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts::BaseController
|
||||
before_action :validate_feature_enabled!
|
||||
before_action :fetch_and_validate_inbox, if: -> { params[:inbox_id].present? }
|
||||
|
||||
# POST /api/v1/accounts/:account_id/whatsapp/authorization
|
||||
@@ -64,6 +65,15 @@ class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts:
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def validate_feature_enabled!
|
||||
return if Current.account.feature_whatsapp_embedded_signup?
|
||||
|
||||
render json: {
|
||||
success: false,
|
||||
error: 'WhatsApp embedded signup is not enabled for this account'
|
||||
}, status: :forbidden
|
||||
end
|
||||
|
||||
def validate_embedded_signup_params!
|
||||
missing_params = []
|
||||
missing_params << 'code' if params[:code].blank?
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
class Api::V1::Profile::MfaController < Api::BaseController
|
||||
before_action :check_mfa_feature_available
|
||||
before_action :check_mfa_enabled, only: [:destroy, :backup_codes]
|
||||
before_action :check_mfa_disabled, only: [:create, :verify]
|
||||
before_action :validate_otp, only: [:verify, :backup_codes, :destroy]
|
||||
before_action :validate_password, only: [:destroy]
|
||||
|
||||
def show; end
|
||||
|
||||
def create
|
||||
mfa_service.enable_two_factor!
|
||||
end
|
||||
|
||||
def verify
|
||||
@backup_codes = mfa_service.verify_and_activate!
|
||||
end
|
||||
|
||||
def destroy
|
||||
mfa_service.disable_two_factor!
|
||||
end
|
||||
|
||||
def backup_codes
|
||||
@backup_codes = mfa_service.generate_backup_codes!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def mfa_service
|
||||
@mfa_service ||= Mfa::ManagementService.new(user: current_user)
|
||||
end
|
||||
|
||||
def check_mfa_enabled
|
||||
render_could_not_create_error(I18n.t('errors.mfa.not_enabled')) unless current_user.mfa_enabled?
|
||||
end
|
||||
|
||||
def check_mfa_feature_available
|
||||
return if Chatwoot.mfa_enabled?
|
||||
|
||||
render json: {
|
||||
error: I18n.t('errors.mfa.feature_unavailable')
|
||||
}, status: :forbidden
|
||||
end
|
||||
|
||||
def check_mfa_disabled
|
||||
render_could_not_create_error(I18n.t('errors.mfa.already_enabled')) if current_user.mfa_enabled?
|
||||
end
|
||||
|
||||
def validate_otp
|
||||
authenticated = Mfa::AuthenticationService.new(
|
||||
user: current_user,
|
||||
otp_code: mfa_params[:otp_code]
|
||||
).authenticate
|
||||
|
||||
return if authenticated
|
||||
|
||||
render_could_not_create_error(I18n.t('errors.mfa.invalid_code'))
|
||||
end
|
||||
|
||||
def validate_password
|
||||
return if current_user.valid_password?(mfa_params[:password])
|
||||
|
||||
render_could_not_create_error(I18n.t('errors.mfa.invalid_credentials'))
|
||||
end
|
||||
|
||||
def mfa_params
|
||||
params.permit(:otp_code, :password)
|
||||
end
|
||||
end
|
||||
@@ -47,8 +47,10 @@ class DeviseOverrides::OmniauthCallbacksController < DeviseTokenAuth::OmniauthCa
|
||||
end
|
||||
|
||||
def get_resource_from_auth_hash # rubocop:disable Naming/AccessorMethodName
|
||||
email = auth_hash.dig('info', 'email')
|
||||
@resource = resource_class.from_email(email)
|
||||
# find the user with their email instead of UID and token
|
||||
@resource = resource_class.where(
|
||||
email: auth_hash['info']['email']
|
||||
).first
|
||||
end
|
||||
|
||||
def validate_signup_email_is_business_domain?
|
||||
@@ -73,5 +75,3 @@ class DeviseOverrides::OmniauthCallbacksController < DeviseTokenAuth::OmniauthCa
|
||||
'user'
|
||||
end
|
||||
end
|
||||
|
||||
DeviseOverrides::OmniauthCallbacksController.prepend_mod_with('DeviseOverrides::OmniauthCallbacksController')
|
||||
|
||||
@@ -44,5 +44,3 @@ class DeviseOverrides::PasswordsController < Devise::PasswordsController
|
||||
}, status: status
|
||||
end
|
||||
end
|
||||
|
||||
DeviseOverrides::PasswordsController.prepend_mod_with('DeviseOverrides::PasswordsController')
|
||||
|
||||
@@ -9,11 +9,13 @@ class DeviseOverrides::SessionsController < DeviseTokenAuth::SessionsController
|
||||
end
|
||||
|
||||
def create
|
||||
return handle_mfa_verification if mfa_verification_request?
|
||||
return handle_sso_authentication if sso_authentication_request?
|
||||
|
||||
super do |resource|
|
||||
return handle_mfa_required(resource) if resource&.mfa_enabled?
|
||||
# Authenticate user via the temporary sso auth token
|
||||
if params[:sso_auth_token].present? && @resource.present?
|
||||
authenticate_resource_with_sso_token
|
||||
yield @resource if block_given?
|
||||
render_create_success
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,20 +25,6 @@ class DeviseOverrides::SessionsController < DeviseTokenAuth::SessionsController
|
||||
|
||||
private
|
||||
|
||||
def mfa_verification_request?
|
||||
params[:mfa_token].present?
|
||||
end
|
||||
|
||||
def sso_authentication_request?
|
||||
params[:sso_auth_token].present? && @resource.present?
|
||||
end
|
||||
|
||||
def handle_sso_authentication
|
||||
authenticate_resource_with_sso_token
|
||||
yield @resource if block_given?
|
||||
render_create_success
|
||||
end
|
||||
|
||||
def login_page_url(error: nil)
|
||||
frontend_url = ENV.fetch('FRONTEND_URL', nil)
|
||||
|
||||
@@ -58,41 +46,6 @@ class DeviseOverrides::SessionsController < DeviseTokenAuth::SessionsController
|
||||
user = User.from_email(params[:email])
|
||||
@resource = user if user&.valid_sso_auth_token?(params[:sso_auth_token])
|
||||
end
|
||||
|
||||
def handle_mfa_required(resource)
|
||||
render json: {
|
||||
mfa_required: true,
|
||||
mfa_token: Mfa::TokenService.new(user: resource).generate_token
|
||||
}, status: :partial_content
|
||||
end
|
||||
|
||||
def handle_mfa_verification
|
||||
user = Mfa::TokenService.new(token: params[:mfa_token]).verify_token
|
||||
return render_mfa_error('errors.mfa.invalid_token', :unauthorized) unless user
|
||||
|
||||
authenticated = Mfa::AuthenticationService.new(
|
||||
user: user,
|
||||
otp_code: params[:otp_code],
|
||||
backup_code: params[:backup_code]
|
||||
).authenticate
|
||||
|
||||
return render_mfa_error('errors.mfa.invalid_code') unless authenticated
|
||||
|
||||
sign_in_mfa_user(user)
|
||||
end
|
||||
|
||||
def sign_in_mfa_user(user)
|
||||
@resource = user
|
||||
@token = @resource.create_token
|
||||
@resource.save!
|
||||
|
||||
sign_in(:user, @resource, store: false, bypass: false)
|
||||
render_create_success
|
||||
end
|
||||
|
||||
def render_mfa_error(message_key, status = :bad_request)
|
||||
render json: { error: I18n.t(message_key) }, status: status
|
||||
end
|
||||
end
|
||||
|
||||
DeviseOverrides::SessionsController.prepend_mod_with('DeviseOverrides::SessionsController')
|
||||
|
||||
@@ -70,12 +70,7 @@ class WidgetsController < ActionController::Base
|
||||
end
|
||||
|
||||
def allow_iframe_requests
|
||||
if @web_widget.allowed_domains.blank?
|
||||
response.headers.delete('X-Frame-Options')
|
||||
else
|
||||
domains = @web_widget.allowed_domains.split(',').map(&:strip).join(' ')
|
||||
response.headers['Content-Security-Policy'] = "frame-ancestors #{domains}"
|
||||
end
|
||||
response.headers.delete('X-Frame-Options')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
module PortalHelper
|
||||
include UrlHelper
|
||||
def set_og_image_url(portal_name, title)
|
||||
cdn_url = GlobalConfig.get('OG_IMAGE_CDN_URL')['OG_IMAGE_CDN_URL']
|
||||
return if cdn_url.blank?
|
||||
@@ -80,7 +79,7 @@ module PortalHelper
|
||||
query_params = Rack::Utils.parse_query(url.query)
|
||||
query_params['utm_medium'] = 'helpcenter'
|
||||
query_params['utm_campaign'] = 'branding'
|
||||
query_params['utm_source'] = URI.parse(referer).host if url_valid?(referer)
|
||||
query_params['utm_source'] = URI.parse(referer).host if referer.present? && referer.match?(URI::DEFAULT_PARSER.make_regexp)
|
||||
|
||||
url.query = query_params.to_query
|
||||
url.to_s
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/* global axios */
|
||||
|
||||
import ApiClient from './ApiClient';
|
||||
|
||||
class AgentCapacityPolicies extends ApiClient {
|
||||
constructor() {
|
||||
super('agent_capacity_policies', { accountScoped: true });
|
||||
}
|
||||
|
||||
getUsers(policyId) {
|
||||
return axios.get(`${this.url}/${policyId}/users`);
|
||||
}
|
||||
|
||||
addUser(policyId, userData) {
|
||||
return axios.post(`${this.url}/${policyId}/users`, {
|
||||
user_id: userData.id,
|
||||
capacity: userData.capacity,
|
||||
});
|
||||
}
|
||||
|
||||
removeUser(policyId, userId) {
|
||||
return axios.delete(`${this.url}/${policyId}/users/${userId}`);
|
||||
}
|
||||
|
||||
createInboxLimit(policyId, limitData) {
|
||||
return axios.post(`${this.url}/${policyId}/inbox_limits`, {
|
||||
inbox_id: limitData.inboxId,
|
||||
conversation_limit: limitData.conversationLimit,
|
||||
});
|
||||
}
|
||||
|
||||
updateInboxLimit(policyId, limitId, limitData) {
|
||||
return axios.put(`${this.url}/${policyId}/inbox_limits/${limitId}`, {
|
||||
conversation_limit: limitData.conversationLimit,
|
||||
});
|
||||
}
|
||||
|
||||
deleteInboxLimit(policyId, limitId) {
|
||||
return axios.delete(`${this.url}/${policyId}/inbox_limits/${limitId}`);
|
||||
}
|
||||
}
|
||||
|
||||
export default new AgentCapacityPolicies();
|
||||
@@ -1,36 +0,0 @@
|
||||
/* global axios */
|
||||
|
||||
import ApiClient from './ApiClient';
|
||||
|
||||
class AssignmentPolicies extends ApiClient {
|
||||
constructor() {
|
||||
super('assignment_policies', { accountScoped: true });
|
||||
}
|
||||
|
||||
getInboxes(policyId) {
|
||||
return axios.get(`${this.url}/${policyId}/inboxes`);
|
||||
}
|
||||
|
||||
setInboxPolicy(inboxId, policyId) {
|
||||
return axios.post(
|
||||
`/api/v1/accounts/${this.accountIdFromRoute}/inboxes/${inboxId}/assignment_policy`,
|
||||
{
|
||||
assignment_policy_id: policyId,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
getInboxPolicy(inboxId) {
|
||||
return axios.get(
|
||||
`/api/v1/accounts/${this.accountIdFromRoute}/inboxes/${inboxId}/assignment_policy`
|
||||
);
|
||||
}
|
||||
|
||||
removeInboxPolicy(inboxId) {
|
||||
return axios.delete(
|
||||
`/api/v1/accounts/${this.accountIdFromRoute}/inboxes/${inboxId}/assignment_policy`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default new AssignmentPolicies();
|
||||
@@ -6,11 +6,11 @@ class CaptainResponses extends ApiClient {
|
||||
super('captain/assistant_responses', { accountScoped: true });
|
||||
}
|
||||
|
||||
get({ page = 1, search, assistantId, documentId, status } = {}) {
|
||||
get({ page = 1, searchKey, assistantId, documentId, status } = {}) {
|
||||
return axios.get(this.url, {
|
||||
params: {
|
||||
page,
|
||||
search,
|
||||
searchKey,
|
||||
assistant_id: assistantId,
|
||||
document_id: documentId,
|
||||
status,
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/* global axios */
|
||||
import ApiClient from './ApiClient';
|
||||
|
||||
class MfaAPI extends ApiClient {
|
||||
constructor() {
|
||||
super('profile/mfa', { accountScoped: false });
|
||||
}
|
||||
|
||||
enable() {
|
||||
return axios.post(`${this.url}`);
|
||||
}
|
||||
|
||||
verify(otpCode) {
|
||||
return axios.post(`${this.url}/verify`, { otp_code: otpCode });
|
||||
}
|
||||
|
||||
disable(password, otpCode) {
|
||||
return axios.delete(this.url, {
|
||||
data: { password, otp_code: otpCode },
|
||||
});
|
||||
}
|
||||
|
||||
regenerateBackupCodes(otpCode) {
|
||||
return axios.post(`${this.url}/backup_codes`, { otp_code: otpCode });
|
||||
}
|
||||
}
|
||||
|
||||
export default new MfaAPI();
|
||||
@@ -1,26 +0,0 @@
|
||||
/* global axios */
|
||||
import ApiClient from './ApiClient';
|
||||
|
||||
class SamlSettingsAPI extends ApiClient {
|
||||
constructor() {
|
||||
super('saml_settings', { accountScoped: true });
|
||||
}
|
||||
|
||||
get() {
|
||||
return axios.get(this.url);
|
||||
}
|
||||
|
||||
create(data) {
|
||||
return axios.post(this.url, { saml_settings: data });
|
||||
}
|
||||
|
||||
update(data) {
|
||||
return axios.put(this.url, { saml_settings: data });
|
||||
}
|
||||
|
||||
delete() {
|
||||
return axios.delete(this.url);
|
||||
}
|
||||
}
|
||||
|
||||
export default new SamlSettingsAPI();
|
||||
@@ -1,98 +0,0 @@
|
||||
import agentCapacityPolicies from '../agentCapacityPolicies';
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
describe('#AgentCapacityPoliciesAPI', () => {
|
||||
it('creates correct instance', () => {
|
||||
expect(agentCapacityPolicies).toBeInstanceOf(ApiClient);
|
||||
expect(agentCapacityPolicies).toHaveProperty('get');
|
||||
expect(agentCapacityPolicies).toHaveProperty('show');
|
||||
expect(agentCapacityPolicies).toHaveProperty('create');
|
||||
expect(agentCapacityPolicies).toHaveProperty('update');
|
||||
expect(agentCapacityPolicies).toHaveProperty('delete');
|
||||
expect(agentCapacityPolicies).toHaveProperty('getUsers');
|
||||
expect(agentCapacityPolicies).toHaveProperty('addUser');
|
||||
expect(agentCapacityPolicies).toHaveProperty('removeUser');
|
||||
expect(agentCapacityPolicies).toHaveProperty('createInboxLimit');
|
||||
expect(agentCapacityPolicies).toHaveProperty('updateInboxLimit');
|
||||
expect(agentCapacityPolicies).toHaveProperty('deleteInboxLimit');
|
||||
});
|
||||
|
||||
describe('API calls', () => {
|
||||
const originalAxios = window.axios;
|
||||
const axiosMock = {
|
||||
get: vi.fn(() => Promise.resolve()),
|
||||
post: vi.fn(() => Promise.resolve()),
|
||||
put: vi.fn(() => Promise.resolve()),
|
||||
delete: vi.fn(() => Promise.resolve()),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
window.axios = axiosMock;
|
||||
// Mock accountIdFromRoute
|
||||
Object.defineProperty(agentCapacityPolicies, 'accountIdFromRoute', {
|
||||
get: () => '1',
|
||||
configurable: true,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.axios = originalAxios;
|
||||
});
|
||||
|
||||
it('#getUsers', () => {
|
||||
agentCapacityPolicies.getUsers(123);
|
||||
expect(axiosMock.get).toHaveBeenCalledWith(
|
||||
'/api/v1/accounts/1/agent_capacity_policies/123/users'
|
||||
);
|
||||
});
|
||||
|
||||
it('#addUser', () => {
|
||||
const userData = { id: 456, capacity: 20 };
|
||||
agentCapacityPolicies.addUser(123, userData);
|
||||
expect(axiosMock.post).toHaveBeenCalledWith(
|
||||
'/api/v1/accounts/1/agent_capacity_policies/123/users',
|
||||
{
|
||||
user_id: 456,
|
||||
capacity: 20,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('#removeUser', () => {
|
||||
agentCapacityPolicies.removeUser(123, 456);
|
||||
expect(axiosMock.delete).toHaveBeenCalledWith(
|
||||
'/api/v1/accounts/1/agent_capacity_policies/123/users/456'
|
||||
);
|
||||
});
|
||||
|
||||
it('#createInboxLimit', () => {
|
||||
const limitData = { inboxId: 1, conversationLimit: 10 };
|
||||
agentCapacityPolicies.createInboxLimit(123, limitData);
|
||||
expect(axiosMock.post).toHaveBeenCalledWith(
|
||||
'/api/v1/accounts/1/agent_capacity_policies/123/inbox_limits',
|
||||
{
|
||||
inbox_id: 1,
|
||||
conversation_limit: 10,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('#updateInboxLimit', () => {
|
||||
const limitData = { conversationLimit: 15 };
|
||||
agentCapacityPolicies.updateInboxLimit(123, 789, limitData);
|
||||
expect(axiosMock.put).toHaveBeenCalledWith(
|
||||
'/api/v1/accounts/1/agent_capacity_policies/123/inbox_limits/789',
|
||||
{
|
||||
conversation_limit: 15,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('#deleteInboxLimit', () => {
|
||||
agentCapacityPolicies.deleteInboxLimit(123, 789);
|
||||
expect(axiosMock.delete).toHaveBeenCalledWith(
|
||||
'/api/v1/accounts/1/agent_capacity_policies/123/inbox_limits/789'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,70 +0,0 @@
|
||||
import assignmentPolicies from '../assignmentPolicies';
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
describe('#AssignmentPoliciesAPI', () => {
|
||||
it('creates correct instance', () => {
|
||||
expect(assignmentPolicies).toBeInstanceOf(ApiClient);
|
||||
expect(assignmentPolicies).toHaveProperty('get');
|
||||
expect(assignmentPolicies).toHaveProperty('show');
|
||||
expect(assignmentPolicies).toHaveProperty('create');
|
||||
expect(assignmentPolicies).toHaveProperty('update');
|
||||
expect(assignmentPolicies).toHaveProperty('delete');
|
||||
expect(assignmentPolicies).toHaveProperty('getInboxes');
|
||||
expect(assignmentPolicies).toHaveProperty('setInboxPolicy');
|
||||
expect(assignmentPolicies).toHaveProperty('getInboxPolicy');
|
||||
expect(assignmentPolicies).toHaveProperty('removeInboxPolicy');
|
||||
});
|
||||
|
||||
describe('API calls', () => {
|
||||
const originalAxios = window.axios;
|
||||
const axiosMock = {
|
||||
get: vi.fn(() => Promise.resolve()),
|
||||
post: vi.fn(() => Promise.resolve()),
|
||||
delete: vi.fn(() => Promise.resolve()),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
window.axios = axiosMock;
|
||||
// Mock accountIdFromRoute
|
||||
Object.defineProperty(assignmentPolicies, 'accountIdFromRoute', {
|
||||
get: () => '1',
|
||||
configurable: true,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.axios = originalAxios;
|
||||
});
|
||||
|
||||
it('#getInboxes', () => {
|
||||
assignmentPolicies.getInboxes(123);
|
||||
expect(axiosMock.get).toHaveBeenCalledWith(
|
||||
'/api/v1/accounts/1/assignment_policies/123/inboxes'
|
||||
);
|
||||
});
|
||||
|
||||
it('#setInboxPolicy', () => {
|
||||
assignmentPolicies.setInboxPolicy(456, 123);
|
||||
expect(axiosMock.post).toHaveBeenCalledWith(
|
||||
'/api/v1/accounts/1/inboxes/456/assignment_policy',
|
||||
{
|
||||
assignment_policy_id: 123,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('#getInboxPolicy', () => {
|
||||
assignmentPolicies.getInboxPolicy(456);
|
||||
expect(axiosMock.get).toHaveBeenCalledWith(
|
||||
'/api/v1/accounts/1/inboxes/456/assignment_policy'
|
||||
);
|
||||
});
|
||||
|
||||
it('#removeInboxPolicy', () => {
|
||||
assignmentPolicies.removeInboxPolicy(456);
|
||||
expect(axiosMock.delete).toHaveBeenCalledWith(
|
||||
'/api/v1/accounts/1/inboxes/456/assignment_policy'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
-116
@@ -1,116 +0,0 @@
|
||||
<script setup>
|
||||
import AgentCapacityPolicyCard from './AgentCapacityPolicyCard.vue';
|
||||
|
||||
const mockUsers = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'John Smith',
|
||||
email: 'john.smith@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Sarah Johnson',
|
||||
email: 'sarah.johnson@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=2',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Mike Chen',
|
||||
email: 'mike.chen@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=3',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Emily Davis',
|
||||
email: 'emily.davis@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=4',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Alex Rodriguez',
|
||||
email: 'alex.rodriguez@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=5',
|
||||
},
|
||||
];
|
||||
|
||||
const withCount = policy => ({
|
||||
...policy,
|
||||
assignedAgentCount: policy.users.length,
|
||||
});
|
||||
|
||||
const policyA = withCount({
|
||||
id: 1,
|
||||
name: 'High Volume Support',
|
||||
description:
|
||||
'Capacity-based policy for handling high conversation volumes with experienced agents',
|
||||
users: [mockUsers[0], mockUsers[1], mockUsers[2]],
|
||||
isFetchingUsers: false,
|
||||
});
|
||||
|
||||
const policyB = withCount({
|
||||
id: 2,
|
||||
name: 'Specialized Team',
|
||||
description: 'Custom capacity limits for specialized support team members',
|
||||
users: [mockUsers[3], mockUsers[4]],
|
||||
isFetchingUsers: false,
|
||||
});
|
||||
|
||||
const emptyPolicy = withCount({
|
||||
id: 3,
|
||||
name: 'New Policy',
|
||||
description: 'Recently created policy with no assigned agents yet',
|
||||
users: [],
|
||||
isFetchingUsers: false,
|
||||
});
|
||||
|
||||
const loadingPolicy = withCount({
|
||||
id: 4,
|
||||
name: 'Loading Policy',
|
||||
description: 'Policy currently loading agent information',
|
||||
users: [],
|
||||
isFetchingUsers: true,
|
||||
});
|
||||
|
||||
const onEdit = id => console.log('Edit policy:', id);
|
||||
const onDelete = id => console.log('Delete policy:', id);
|
||||
const onFetchUsers = id => console.log('Fetch users for policy:', id);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/AgentManagementPolicy/AgentCapacityPolicyCard"
|
||||
:layout="{ type: 'grid', width: '1200px' }"
|
||||
>
|
||||
<Variant title="Multiple Cards (Various States)">
|
||||
<div class="p-4 bg-n-background">
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<AgentCapacityPolicyCard
|
||||
v-bind="policyA"
|
||||
@edit="onEdit"
|
||||
@delete="onDelete"
|
||||
@fetch-users="onFetchUsers"
|
||||
/>
|
||||
<AgentCapacityPolicyCard
|
||||
v-bind="policyB"
|
||||
@edit="onEdit"
|
||||
@delete="onDelete"
|
||||
@fetch-users="onFetchUsers"
|
||||
/>
|
||||
<AgentCapacityPolicyCard
|
||||
v-bind="emptyPolicy"
|
||||
@edit="onEdit"
|
||||
@delete="onDelete"
|
||||
@fetch-users="onFetchUsers"
|
||||
/>
|
||||
<AgentCapacityPolicyCard
|
||||
v-bind="loadingPolicy"
|
||||
@edit="onEdit"
|
||||
@delete="onDelete"
|
||||
@fetch-users="onFetchUsers"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import CardLayout from 'dashboard/components-next/CardLayout.vue';
|
||||
import CardPopover from '../components/CardPopover.vue';
|
||||
|
||||
const props = defineProps({
|
||||
id: { type: Number, required: true },
|
||||
name: { type: String, default: '' },
|
||||
description: { type: String, default: '' },
|
||||
assignedAgentCount: { type: Number, default: 0 },
|
||||
users: { type: Array, default: () => [] },
|
||||
isFetchingUsers: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
const emit = defineEmits(['edit', 'delete', 'fetchUsers']);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const users = computed(() => {
|
||||
return props.users.map(user => {
|
||||
return {
|
||||
name: user.name,
|
||||
key: user.id,
|
||||
email: user.email,
|
||||
avatarUrl: user.avatarUrl,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const handleEdit = () => {
|
||||
emit('edit', props.id);
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
emit('delete', props.id);
|
||||
};
|
||||
|
||||
const handleFetchUsers = () => {
|
||||
if (props.users?.length > 0) return;
|
||||
emit('fetchUsers', props.id);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CardLayout class="[&>div]:px-5">
|
||||
<div class="flex flex-col gap-2 relative justify-between w-full">
|
||||
<div class="flex items-center gap-3 justify-between w-full">
|
||||
<div class="flex items-center gap-3">
|
||||
<h3 class="text-base font-medium text-n-slate-12 line-clamp-1">
|
||||
{{ name }}
|
||||
</h3>
|
||||
<CardPopover
|
||||
:title="
|
||||
t('ASSIGNMENT_POLICY.AGENT_CAPACITY_POLICY.INDEX.CARD.POPOVER')
|
||||
"
|
||||
icon="i-lucide-users-round"
|
||||
:count="assignedAgentCount"
|
||||
:items="users"
|
||||
:is-fetching="isFetchingUsers"
|
||||
@fetch="handleFetchUsers"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
:label="
|
||||
t('ASSIGNMENT_POLICY.AGENT_CAPACITY_POLICY.INDEX.CARD.EDIT')
|
||||
"
|
||||
sm
|
||||
slate
|
||||
link
|
||||
class="px-2"
|
||||
@click="handleEdit"
|
||||
/>
|
||||
<div class="w-px h-2.5 bg-n-slate-5" />
|
||||
<Button icon="i-lucide-trash" sm slate ghost @click="handleDelete" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-n-slate-11 text-sm line-clamp-1 mb-0 py-1">
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
</CardLayout>
|
||||
</template>
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
<script setup>
|
||||
import AssignmentPolicyCard from './AssignmentPolicyCard.vue';
|
||||
|
||||
const mockInboxes = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Website Support',
|
||||
channel_type: 'Channel::WebWidget',
|
||||
inbox_type: 'Website',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Email Support',
|
||||
channel_type: 'Channel::Email',
|
||||
inbox_type: 'Email',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'WhatsApp Business',
|
||||
channel_type: 'Channel::Whatsapp',
|
||||
inbox_type: 'WhatsApp',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Facebook Messenger',
|
||||
channel_type: 'Channel::FacebookPage',
|
||||
inbox_type: 'Messenger',
|
||||
},
|
||||
];
|
||||
|
||||
const withCount = policy => ({
|
||||
...policy,
|
||||
assignedInboxCount: policy.inboxes.length,
|
||||
});
|
||||
|
||||
const policyA = withCount({
|
||||
id: 1,
|
||||
name: 'Website & Email',
|
||||
description: 'Distributes conversations evenly among available agents',
|
||||
assignmentOrder: 'round_robin',
|
||||
conversationPriority: 'high',
|
||||
enabled: true,
|
||||
inboxes: [mockInboxes[0], mockInboxes[1]],
|
||||
isFetchingInboxes: false,
|
||||
});
|
||||
|
||||
const policyB = withCount({
|
||||
id: 2,
|
||||
name: 'WhatsApp & Messenger',
|
||||
description: 'Assigns based on capacity and workload',
|
||||
assignmentOrder: 'capacity_based',
|
||||
conversationPriority: 'medium',
|
||||
enabled: true,
|
||||
inboxes: [mockInboxes[2], mockInboxes[3]],
|
||||
isFetchingInboxes: false,
|
||||
});
|
||||
|
||||
const emptyPolicy = withCount({
|
||||
id: 3,
|
||||
name: 'No Inboxes Yet',
|
||||
description: 'Policy with no assigned inboxes',
|
||||
assignmentOrder: 'manual',
|
||||
conversationPriority: 'low',
|
||||
enabled: false,
|
||||
inboxes: [],
|
||||
isFetchingInboxes: false,
|
||||
});
|
||||
|
||||
const onEdit = id => console.log('Edit policy:', id);
|
||||
const onDelete = id => console.log('Delete policy:', id);
|
||||
const onFetch = () => console.log('Fetch inboxes');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/AgentManagementPolicy/AssignmentPolicyCard"
|
||||
:layout="{ type: 'grid', width: '1200px' }"
|
||||
>
|
||||
<Variant title="Three Cards (Two with inboxes, One empty)">
|
||||
<div class="p-4 bg-n-background">
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<AssignmentPolicyCard
|
||||
v-bind="policyA"
|
||||
@edit="onEdit"
|
||||
@delete="onDelete"
|
||||
@fetch-inboxes="onFetch"
|
||||
/>
|
||||
<AssignmentPolicyCard
|
||||
v-bind="policyB"
|
||||
@edit="onEdit"
|
||||
@delete="onDelete"
|
||||
@fetch-inboxes="onFetch"
|
||||
/>
|
||||
<AssignmentPolicyCard
|
||||
v-bind="emptyPolicy"
|
||||
@edit="onEdit"
|
||||
@delete="onDelete"
|
||||
@fetch-inboxes="onFetch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
-133
@@ -1,133 +0,0 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { getInboxIconByType } from 'dashboard/helper/inbox';
|
||||
import { formatToTitleCase } from 'dashboard/helper/commons';
|
||||
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import CardLayout from 'dashboard/components-next/CardLayout.vue';
|
||||
import CardPopover from '../components/CardPopover.vue';
|
||||
|
||||
const props = defineProps({
|
||||
id: { type: Number, required: true },
|
||||
name: { type: String, default: '' },
|
||||
description: { type: String, default: '' },
|
||||
assignmentOrder: { type: String, default: '' },
|
||||
conversationPriority: { type: String, default: '' },
|
||||
assignedInboxCount: { type: Number, default: 0 },
|
||||
enabled: { type: Boolean, default: false },
|
||||
inboxes: { type: Array, default: () => [] },
|
||||
isFetchingInboxes: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
const emit = defineEmits(['edit', 'delete', 'fetchInboxes']);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const inboxes = computed(() => {
|
||||
return props.inboxes.map(inbox => {
|
||||
return {
|
||||
name: inbox.name,
|
||||
id: inbox.id,
|
||||
icon: getInboxIconByType(inbox.channelType, inbox.medium, 'line'),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const order = computed(() => {
|
||||
return formatToTitleCase(props.assignmentOrder);
|
||||
});
|
||||
|
||||
const priority = computed(() => {
|
||||
return formatToTitleCase(props.conversationPriority);
|
||||
});
|
||||
|
||||
const handleEdit = () => {
|
||||
emit('edit', props.id);
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
emit('delete', props.id);
|
||||
};
|
||||
|
||||
const handleFetchInboxes = () => {
|
||||
if (props.inboxes?.length > 0) return;
|
||||
emit('fetchInboxes', props.id);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CardLayout class="[&>div]:px-5">
|
||||
<div class="flex flex-col gap-2 relative justify-between w-full">
|
||||
<div class="flex items-center gap-3 justify-between w-full">
|
||||
<div class="flex items-center gap-3">
|
||||
<h3 class="text-base font-medium text-n-slate-12 line-clamp-1">
|
||||
{{ name }}
|
||||
</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center rounded-md bg-n-alpha-2 h-6 px-2">
|
||||
<span
|
||||
class="text-xs"
|
||||
:class="enabled ? 'text-n-teal-11' : 'text-n-slate-12'"
|
||||
>
|
||||
{{
|
||||
enabled
|
||||
? t(
|
||||
'ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.INDEX.CARD.ACTIVE'
|
||||
)
|
||||
: t(
|
||||
'ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.INDEX.CARD.INACTIVE'
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<CardPopover
|
||||
:title="
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.INDEX.CARD.POPOVER'
|
||||
)
|
||||
"
|
||||
icon="i-lucide-inbox"
|
||||
:count="assignedInboxCount"
|
||||
:items="inboxes"
|
||||
:is-fetching="isFetchingInboxes"
|
||||
@fetch="handleFetchInboxes"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
:label="
|
||||
t('ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.INDEX.CARD.EDIT')
|
||||
"
|
||||
sm
|
||||
slate
|
||||
link
|
||||
class="px-2"
|
||||
@click="handleEdit"
|
||||
/>
|
||||
<div v-if="order" class="w-px h-2.5 bg-n-slate-5" />
|
||||
<Button icon="i-lucide-trash" sm slate ghost @click="handleDelete" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-n-slate-11 text-sm line-clamp-1 mb-0 py-1">
|
||||
{{ description }}
|
||||
</p>
|
||||
<div class="flex items-center gap-3 py-1.5">
|
||||
<span v-if="order" class="text-n-slate-11 text-sm">
|
||||
{{
|
||||
`${t('ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.INDEX.CARD.ORDER')}:`
|
||||
}}
|
||||
<span class="text-n-slate-12">{{ order }}</span>
|
||||
</span>
|
||||
<div v-if="order" class="w-px h-3 bg-n-strong" />
|
||||
<span v-if="priority" class="text-n-slate-11 text-sm">
|
||||
{{
|
||||
`${t('ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.INDEX.CARD.PRIORITY')}:`
|
||||
}}
|
||||
<span class="text-n-slate-12">{{ priority }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardLayout>
|
||||
</template>
|
||||
-169
@@ -1,169 +0,0 @@
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useToggle, useWindowSize, useElementBounding } from '@vueuse/core';
|
||||
import { vOnClickOutside } from '@vueuse/components';
|
||||
import { picoSearch } from '@scmmishra/pico-search';
|
||||
|
||||
import Avatar from 'next/avatar/Avatar.vue';
|
||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import Input from 'dashboard/components-next/input/Input.vue';
|
||||
|
||||
const props = defineProps({
|
||||
label: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
searchPlaceholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['add']);
|
||||
|
||||
const BUFFER_SPACE = 20;
|
||||
|
||||
const [showPopover, togglePopover] = useToggle();
|
||||
const buttonRef = ref();
|
||||
const dropdownRef = ref();
|
||||
|
||||
const searchValue = ref('');
|
||||
|
||||
const { width: windowWidth, height: windowHeight } = useWindowSize();
|
||||
const {
|
||||
top: buttonTop,
|
||||
left: buttonLeft,
|
||||
width: buttonWidth,
|
||||
height: buttonHeight,
|
||||
} = useElementBounding(buttonRef);
|
||||
const { width: dropdownWidth, height: dropdownHeight } =
|
||||
useElementBounding(dropdownRef);
|
||||
|
||||
const filteredItems = computed(() => {
|
||||
if (!searchValue.value) return props.items;
|
||||
const query = searchValue.value.toLowerCase();
|
||||
|
||||
return picoSearch(props.items, query, ['name']);
|
||||
});
|
||||
|
||||
const handleAdd = item => {
|
||||
emit('add', item);
|
||||
togglePopover(false);
|
||||
};
|
||||
|
||||
const shouldShowAbove = computed(() => {
|
||||
if (!buttonRef.value || !dropdownRef.value) return false;
|
||||
const spaceBelow =
|
||||
windowHeight.value - (buttonTop.value + buttonHeight.value);
|
||||
const spaceAbove = buttonTop.value;
|
||||
return (
|
||||
spaceBelow < dropdownHeight.value + BUFFER_SPACE && spaceAbove > spaceBelow
|
||||
);
|
||||
});
|
||||
|
||||
const shouldAlignRight = computed(() => {
|
||||
if (!buttonRef.value || !dropdownRef.value) return false;
|
||||
const spaceRight = windowWidth.value - buttonLeft.value;
|
||||
const spaceLeft = buttonLeft.value + buttonWidth.value;
|
||||
|
||||
return (
|
||||
spaceRight < dropdownWidth.value + BUFFER_SPACE && spaceLeft > spaceRight
|
||||
);
|
||||
});
|
||||
|
||||
const handleClickOutside = () => {
|
||||
if (showPopover.value) {
|
||||
togglePopover(false);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-on-click-outside="handleClickOutside"
|
||||
class="relative flex items-center group"
|
||||
>
|
||||
<Button
|
||||
ref="buttonRef"
|
||||
slate
|
||||
type="button"
|
||||
icon="i-lucide-plus"
|
||||
sm
|
||||
:label="label"
|
||||
@click="togglePopover(!showPopover)"
|
||||
/>
|
||||
<div
|
||||
v-if="showPopover"
|
||||
ref="dropdownRef"
|
||||
class="z-50 flex flex-col items-start absolute bg-n-alpha-3 backdrop-blur-[50px] border-0 gap-4 outline outline-1 outline-n-weak rounded-xl max-w-96 min-w-80 max-h-[20rem] overflow-y-auto py-2"
|
||||
:class="[
|
||||
shouldShowAbove ? 'bottom-full mb-2' : 'top-full mt-2',
|
||||
shouldAlignRight ? 'right-0' : 'left-0',
|
||||
]"
|
||||
>
|
||||
<div class="flex flex-col divide-y divide-n-slate-4 w-full">
|
||||
<Input
|
||||
v-model="searchValue"
|
||||
:placeholder="searchPlaceholder"
|
||||
custom-input-class="bg-transparent !outline-none w-full ltr:!pl-10 rtl:!pr-10 h-10"
|
||||
>
|
||||
<template #prefix>
|
||||
<Icon
|
||||
icon="i-lucide-search"
|
||||
class="absolute -translate-y-1/2 text-n-slate-11 size-4 top-1/2 ltr:left-3 rtl:right-3"
|
||||
/>
|
||||
</template>
|
||||
</Input>
|
||||
|
||||
<div
|
||||
v-for="item in filteredItems"
|
||||
:key="item.id"
|
||||
class="flex gap-3 min-w-0 w-full py-4 px-3 hover:bg-n-alpha-2 cursor-pointer"
|
||||
:class="{ 'items-center': item.color, 'items-start': !item.color }"
|
||||
@click="handleAdd(item)"
|
||||
>
|
||||
<Icon
|
||||
v-if="item.icon"
|
||||
:icon="item.icon"
|
||||
class="size-4 text-n-slate-12 flex-shrink-0 mt-0.5"
|
||||
/>
|
||||
<span
|
||||
v-else-if="item.color"
|
||||
:style="{ backgroundColor: item.color }"
|
||||
class="size-3 rounded-sm"
|
||||
/>
|
||||
<Avatar
|
||||
v-else
|
||||
:title="item.name"
|
||||
:src="item.avatarUrl"
|
||||
:name="item.name"
|
||||
:size="20"
|
||||
rounded-full
|
||||
/>
|
||||
<div class="flex flex-col items-start gap-2 min-w-0 flex-1">
|
||||
<div class="flex items-center gap-1 min-w-0 w-full">
|
||||
<span
|
||||
:title="item.name || item.title"
|
||||
class="text-sm text-n-slate-12 truncate min-w-0 flex-1"
|
||||
>
|
||||
{{ item.name || item.title }}
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
v-if="item.email || item.phoneNumber"
|
||||
:title="item.email || item.phoneNumber"
|
||||
class="text-sm text-n-slate-11 truncate min-w-0 w-full block"
|
||||
>
|
||||
{{ item.email || item.phoneNumber }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,127 +0,0 @@
|
||||
<script setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import { useVuelidate } from '@vuelidate/core';
|
||||
import { required, minLength } from '@vuelidate/validators';
|
||||
|
||||
import WithLabel from 'v3/components/Form/WithLabel.vue';
|
||||
import Input from 'dashboard/components-next/input/Input.vue';
|
||||
import Switch from 'dashboard/components-next/switch/Switch.vue';
|
||||
|
||||
defineProps({
|
||||
nameLabel: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
namePlaceholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
descriptionLabel: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
descriptionPlaceholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
statusLabel: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
statusPlaceholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['validationChange']);
|
||||
|
||||
const policyName = defineModel('policyName', {
|
||||
type: String,
|
||||
default: '',
|
||||
});
|
||||
|
||||
const description = defineModel('description', {
|
||||
type: String,
|
||||
default: '',
|
||||
});
|
||||
|
||||
const enabled = defineModel('enabled', {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
});
|
||||
|
||||
const validationRules = {
|
||||
policyName: { required, minLength: minLength(1) },
|
||||
description: { required, minLength: minLength(1) },
|
||||
};
|
||||
|
||||
const v$ = useVuelidate(validationRules, { policyName, description });
|
||||
|
||||
const isValid = computed(() => !v$.value.$invalid);
|
||||
|
||||
watch(
|
||||
isValid,
|
||||
() => {
|
||||
emit('validationChange', {
|
||||
isValid: isValid.value,
|
||||
section: 'baseInfo',
|
||||
});
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-4 pb-4">
|
||||
<!-- Policy Name Field -->
|
||||
<div class="flex items-center gap-6">
|
||||
<WithLabel
|
||||
:label="nameLabel"
|
||||
name="policyName"
|
||||
class="flex items-center w-full [&>label]:min-w-[120px]"
|
||||
>
|
||||
<div class="flex-1">
|
||||
<Input
|
||||
v-model="policyName"
|
||||
type="text"
|
||||
:placeholder="namePlaceholder"
|
||||
/>
|
||||
</div>
|
||||
</WithLabel>
|
||||
</div>
|
||||
|
||||
<!-- Description Field -->
|
||||
<div class="flex items-center gap-6">
|
||||
<WithLabel
|
||||
:label="descriptionLabel"
|
||||
name="description"
|
||||
class="flex items-center w-full [&>label]:min-w-[120px]"
|
||||
>
|
||||
<div class="flex-1">
|
||||
<Input
|
||||
v-model="description"
|
||||
type="text"
|
||||
:placeholder="descriptionPlaceholder"
|
||||
/>
|
||||
</div>
|
||||
</WithLabel>
|
||||
</div>
|
||||
|
||||
<!-- Status Field -->
|
||||
<div v-if="statusLabel" class="flex items-center gap-6">
|
||||
<WithLabel
|
||||
:label="statusLabel"
|
||||
name="enabled"
|
||||
class="flex items-center w-full [&>label]:min-w-[120px]"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Switch v-model="enabled" />
|
||||
<span class="text-sm text-n-slate-11">
|
||||
{{ statusPlaceholder }}
|
||||
</span>
|
||||
</div>
|
||||
</WithLabel>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,121 +0,0 @@
|
||||
<script setup>
|
||||
import { useToggle } from '@vueuse/core';
|
||||
import { vOnClickOutside } from '@vueuse/components';
|
||||
|
||||
import Avatar from 'next/avatar/Avatar.vue';
|
||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
||||
|
||||
defineProps({
|
||||
count: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
isFetching: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['fetch']);
|
||||
|
||||
const [showPopover, togglePopover] = useToggle();
|
||||
|
||||
const handleButtonClick = () => {
|
||||
emit('fetch');
|
||||
togglePopover(!showPopover.value);
|
||||
};
|
||||
|
||||
const handleClickOutside = () => {
|
||||
if (showPopover.value) {
|
||||
togglePopover(false);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-on-click-outside="handleClickOutside"
|
||||
class="relative flex items-center group"
|
||||
>
|
||||
<button
|
||||
v-if="count"
|
||||
class="h-6 px-2 rounded-md bg-n-alpha-2 gap-1.5 flex items-center"
|
||||
@click="handleButtonClick()"
|
||||
>
|
||||
<Icon :icon="icon" class="size-3.5 text-n-slate-12" />
|
||||
<span class="text-n-slate-12 text-sm">
|
||||
{{ count }}
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
v-if="showPopover"
|
||||
class="top-full mt-1 ltr:left-0 rtl:right-0 z-50 flex flex-col items-start absolute bg-n-alpha-3 backdrop-blur-[50px] border-0 gap-4 outline outline-1 outline-n-weak p-3 rounded-xl max-w-96 min-w-80 max-h-[20rem] overflow-y-auto"
|
||||
>
|
||||
<div class="flex items-center gap-2.5 pb-2">
|
||||
<Icon :icon="icon" class="size-3.5" />
|
||||
<span class="text-sm text-n-slate-12 font-medium">{{ title }}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isFetching"
|
||||
class="flex items-center justify-center py-3 w-full text-n-slate-11"
|
||||
>
|
||||
<Spinner />
|
||||
</div>
|
||||
|
||||
<div v-else class="flex flex-col gap-4 w-full">
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
class="flex items-center justify-between gap-2 min-w-0 w-full"
|
||||
>
|
||||
<div class="flex items-center gap-2 min-w-0 w-full">
|
||||
<Icon
|
||||
v-if="item.icon"
|
||||
:icon="item.icon"
|
||||
class="size-4 text-n-slate-12 flex-shrink-0"
|
||||
/>
|
||||
<Avatar
|
||||
v-else
|
||||
:title="item.name"
|
||||
:src="item.avatarUrl"
|
||||
:name="item.name"
|
||||
:size="20"
|
||||
rounded-full
|
||||
/>
|
||||
<div class="flex items-center gap-1 min-w-0 flex-1">
|
||||
<span
|
||||
:title="item.name"
|
||||
class="text-sm text-n-slate-12 truncate min-w-0"
|
||||
>
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<span
|
||||
v-if="item.id"
|
||||
class="text-sm text-n-slate-11 flex-shrink-0"
|
||||
>
|
||||
{{ `#${item.id}` }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<span v-if="item.email" class="text-sm text-n-slate-11 flex-shrink-0">
|
||||
{{ item.email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,90 +0,0 @@
|
||||
<script setup>
|
||||
import Avatar from 'next/avatar/Avatar.vue';
|
||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
||||
|
||||
defineProps({
|
||||
items: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
isFetching: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
emptyStateMessage: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['delete']);
|
||||
|
||||
const handleDelete = itemId => {
|
||||
emit('delete', itemId);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="isFetching"
|
||||
class="flex items-center justify-center py-3 w-full text-n-slate-11"
|
||||
>
|
||||
<Spinner />
|
||||
</div>
|
||||
<div
|
||||
v-else-if="items.length === 0 && emptyStateMessage"
|
||||
class="custom-dashed-border flex items-center justify-center py-6 w-full"
|
||||
>
|
||||
<span class="text-sm text-n-slate-11">
|
||||
{{ emptyStateMessage }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="flex flex-col divide-y divide-n-weak">
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
class="grid grid-cols-4 items-center gap-3 min-w-0 w-full justify-between h-[3.25rem] ltr:pr-2 rtl:pl-2"
|
||||
>
|
||||
<div class="flex items-center gap-2 col-span-2">
|
||||
<Icon
|
||||
v-if="item.icon"
|
||||
:icon="item.icon"
|
||||
class="size-4 text-n-slate-12 flex-shrink-0"
|
||||
/>
|
||||
<Avatar
|
||||
v-else
|
||||
:title="item.name"
|
||||
:src="item.avatarUrl"
|
||||
:name="item.name"
|
||||
:size="20"
|
||||
rounded-full
|
||||
/>
|
||||
<span class="text-sm text-n-slate-12 truncate min-w-0">
|
||||
{{ item.name }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-start gap-2 col-span-1">
|
||||
<span
|
||||
:title="item.email || item.phoneNumber"
|
||||
class="text-sm text-n-slate-12 truncate min-w-0"
|
||||
>
|
||||
{{ item.email || item.phoneNumber }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="col-span-1 justify-end flex items-center">
|
||||
<Button
|
||||
icon="i-lucide-trash"
|
||||
slate
|
||||
ghost
|
||||
sm
|
||||
type="button"
|
||||
@click="handleDelete(item.id)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
-149
@@ -1,149 +0,0 @@
|
||||
<script setup>
|
||||
import { computed, ref, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import AddDataDropdown from 'dashboard/components-next/AssignmentPolicy/components/AddDataDropdown.vue';
|
||||
import LabelItem from 'dashboard/components-next/Label/LabelItem.vue';
|
||||
import DurationInput from 'dashboard/components-next/input/DurationInput.vue';
|
||||
import { DURATION_UNITS } from 'dashboard/components-next/input/constants';
|
||||
|
||||
const props = defineProps({
|
||||
tagsList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const excludedLabels = defineModel('excludedLabels', {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
});
|
||||
|
||||
const excludeOlderThanMinutes = defineModel('excludeOlderThanMinutes', {
|
||||
type: Number,
|
||||
default: 10,
|
||||
});
|
||||
|
||||
// Duration limits: 10 minutes to 999 days (in minutes)
|
||||
const MIN_DURATION_MINUTES = 10;
|
||||
const MAX_DURATION_MINUTES = 1438560; // 999 days * 24 hours * 60 minutes
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const hoveredLabel = ref(null);
|
||||
const windowUnit = ref(DURATION_UNITS.MINUTES);
|
||||
|
||||
const addedTags = computed(() =>
|
||||
props.tagsList
|
||||
.filter(label => excludedLabels.value.includes(label.name))
|
||||
.map(label => ({ id: label.id, title: label.name, ...label }))
|
||||
);
|
||||
|
||||
const filteredTags = computed(() =>
|
||||
props.tagsList.filter(
|
||||
label => !addedTags.value.some(tag => tag.id === label.id)
|
||||
)
|
||||
);
|
||||
|
||||
const detectUnit = minutes => {
|
||||
const m = Number(minutes) || 0;
|
||||
if (m === 0) return DURATION_UNITS.MINUTES;
|
||||
if (m % (24 * 60) === 0) return DURATION_UNITS.DAYS;
|
||||
if (m % 60 === 0) return DURATION_UNITS.HOURS;
|
||||
return DURATION_UNITS.MINUTES;
|
||||
};
|
||||
|
||||
const onClickAddTag = tag => {
|
||||
excludedLabels.value = [...excludedLabels.value, tag.name];
|
||||
};
|
||||
|
||||
const onClickRemoveTag = tag => {
|
||||
excludedLabels.value = excludedLabels.value.filter(
|
||||
name => name !== tag.title
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
windowUnit.value = detectUnit(excludeOlderThanMinutes.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="py-4 flex-col flex gap-6">
|
||||
<div class="flex flex-col items-start gap-1 py-1">
|
||||
<label class="text-sm font-medium text-n-slate-12 py-1">
|
||||
{{
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_CAPACITY_POLICY.FORM.EXCLUSION_RULES.LABEL'
|
||||
)
|
||||
}}
|
||||
</label>
|
||||
<p class="mb-0 text-n-slate-11 text-sm">
|
||||
{{
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_CAPACITY_POLICY.FORM.EXCLUSION_RULES.DESCRIPTION'
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-start gap-4">
|
||||
<label class="text-sm font-medium text-n-slate-12 py-1">
|
||||
{{
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_CAPACITY_POLICY.FORM.EXCLUSION_RULES.TAGS.LABEL'
|
||||
)
|
||||
}}
|
||||
</label>
|
||||
<div
|
||||
class="flex items-start gap-2 flex-wrap"
|
||||
@mouseleave="hoveredLabel = null"
|
||||
>
|
||||
<LabelItem
|
||||
v-for="tag in addedTags"
|
||||
:key="tag.id"
|
||||
:label="tag"
|
||||
:is-hovered="hoveredLabel === tag.id"
|
||||
class="h-8"
|
||||
@remove="onClickRemoveTag"
|
||||
@hover="hoveredLabel = tag.id"
|
||||
/>
|
||||
<AddDataDropdown
|
||||
:label="
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_CAPACITY_POLICY.FORM.EXCLUSION_RULES.TAGS.ADD_TAG'
|
||||
)
|
||||
"
|
||||
:search-placeholder="
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_CAPACITY_POLICY.FORM.EXCLUSION_RULES.TAGS.DROPDOWN.SEARCH_PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
:items="filteredTags"
|
||||
class="[&>button]:!text-n-blue-text [&>div]:min-w-64"
|
||||
@add="onClickAddTag"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-start gap-4">
|
||||
<label class="text-sm font-medium text-n-slate-12 py-1">
|
||||
{{
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_CAPACITY_POLICY.FORM.EXCLUSION_RULES.DURATION.LABEL'
|
||||
)
|
||||
}}
|
||||
</label>
|
||||
<div
|
||||
class="flex items-center gap-2 flex-1 [&>select]:!bg-n-alpha-2 [&>select]:!outline-none [&>select]:hover:brightness-110"
|
||||
>
|
||||
<!-- allow 10 mins to 999 days -->
|
||||
<DurationInput
|
||||
v-model:unit="windowUnit"
|
||||
v-model:model-value="excludeOlderThanMinutes"
|
||||
:min="MIN_DURATION_MINUTES"
|
||||
:max="MAX_DURATION_MINUTES"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import Input from 'dashboard/components-next/input/Input.vue';
|
||||
import DurationInput from 'dashboard/components-next/input/DurationInput.vue';
|
||||
import { DURATION_UNITS } from 'dashboard/components-next/input/constants';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const fairDistributionLimit = defineModel('fairDistributionLimit', {
|
||||
type: Number,
|
||||
default: 100,
|
||||
set(value) {
|
||||
return Number(value) || 0;
|
||||
},
|
||||
});
|
||||
|
||||
const fairDistributionWindow = defineModel('fairDistributionWindow', {
|
||||
type: Number,
|
||||
default: 3600,
|
||||
set(value) {
|
||||
return Number(value) || 0;
|
||||
},
|
||||
});
|
||||
|
||||
const windowUnit = ref(DURATION_UNITS.MINUTES);
|
||||
|
||||
const detectUnit = minutes => {
|
||||
const m = Number(minutes) || 0;
|
||||
if (m === 0) return DURATION_UNITS.MINUTES;
|
||||
if (m % (24 * 60) === 0) return DURATION_UNITS.DAYS;
|
||||
if (m % 60 === 0) return DURATION_UNITS.HOURS;
|
||||
return DURATION_UNITS.MINUTES;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
windowUnit.value = detectUnit(fairDistributionWindow.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-start xl:items-center flex-col md:flex-row gap-4 lg:gap-3 bg-n-solid-1 p-4 outline outline-1 outline-n-weak rounded-xl"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<label class="text-sm font-medium text-n-slate-12">
|
||||
{{
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.FORM.FAIR_DISTRIBUTION.INPUT_MAX'
|
||||
)
|
||||
}}
|
||||
</label>
|
||||
<div class="flex-1">
|
||||
<Input
|
||||
v-model="fairDistributionLimit"
|
||||
type="number"
|
||||
placeholder="100"
|
||||
max="100000"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex sm:flex-row flex-col items-start sm:items-center gap-4">
|
||||
<label class="text-sm font-medium text-n-slate-12">
|
||||
{{
|
||||
t(
|
||||
'ASSIGNMENT_POLICY.AGENT_ASSIGNMENT_POLICY.FORM.FAIR_DISTRIBUTION.DURATION'
|
||||
)
|
||||
}}
|
||||
</label>
|
||||
|
||||
<div
|
||||
class="flex items-center gap-2 flex-1 [&>select]:!bg-n-alpha-2 [&>select]:!outline-none [&>select]:hover:brightness-110"
|
||||
>
|
||||
<!-- allow 10 mins to 999 days -->
|
||||
<DurationInput
|
||||
v-model:model-value="fairDistributionWindow"
|
||||
v-model:unit="windowUnit"
|
||||
:min="10"
|
||||
:max="1438560"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
-177
@@ -1,177 +0,0 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
||||
import AddDataDropdown from 'dashboard/components-next/AssignmentPolicy/components/AddDataDropdown.vue';
|
||||
|
||||
const props = defineProps({
|
||||
inboxList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
isFetching: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['delete', 'add', 'update']);
|
||||
|
||||
const inboxCapacityLimits = defineModel('inboxCapacityLimits', {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const BASE_KEY = 'ASSIGNMENT_POLICY.AGENT_CAPACITY_POLICY';
|
||||
const DEFAULT_CONVERSATION_LIMIT = 10;
|
||||
const MIN_CONVERSATION_LIMIT = 1;
|
||||
const MAX_CONVERSATION_LIMIT = 100000;
|
||||
|
||||
const selectedInboxIds = computed(
|
||||
() => new Set(inboxCapacityLimits.value.map(limit => limit.inboxId))
|
||||
);
|
||||
|
||||
const availableInboxes = computed(() =>
|
||||
props.inboxList.filter(
|
||||
inbox => inbox && !selectedInboxIds.value.has(inbox.id)
|
||||
)
|
||||
);
|
||||
|
||||
const isLimitValid = limit => {
|
||||
return (
|
||||
limit.conversationLimit >= MIN_CONVERSATION_LIMIT &&
|
||||
limit.conversationLimit <= MAX_CONVERSATION_LIMIT
|
||||
);
|
||||
};
|
||||
|
||||
const inboxMap = computed(
|
||||
() => new Map(props.inboxList.map(inbox => [inbox.id, inbox]))
|
||||
);
|
||||
|
||||
const handleAddInbox = inbox => {
|
||||
emit('add', {
|
||||
inboxId: inbox.id,
|
||||
conversationLimit: DEFAULT_CONVERSATION_LIMIT,
|
||||
});
|
||||
};
|
||||
|
||||
const handleRemoveLimit = limitId => {
|
||||
emit('delete', limitId);
|
||||
};
|
||||
|
||||
const handleLimitChange = limit => {
|
||||
if (isLimitValid(limit)) {
|
||||
emit('update', limit);
|
||||
}
|
||||
};
|
||||
|
||||
const getInboxName = inboxId => {
|
||||
return inboxMap.value.get(inboxId)?.name || '';
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="py-4 flex-col flex gap-3">
|
||||
<div class="flex items-center w-full gap-8 justify-between pt-1 pb-3">
|
||||
<label class="text-sm font-medium text-n-slate-12">
|
||||
{{ t(`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.LABEL`) }}
|
||||
</label>
|
||||
|
||||
<AddDataDropdown
|
||||
:label="t(`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.ADD_BUTTON`)"
|
||||
:search-placeholder="
|
||||
t(`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.FIELD.SELECT_INBOX`)
|
||||
"
|
||||
:items="availableInboxes"
|
||||
@add="handleAddInbox"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="isFetching"
|
||||
class="flex items-center justify-center py-3 w-full text-n-slate-11"
|
||||
>
|
||||
<Spinner />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="!inboxCapacityLimits.length"
|
||||
class="custom-dashed-border flex items-center justify-center py-6 w-full"
|
||||
>
|
||||
<span class="text-sm text-n-slate-11">
|
||||
{{ t(`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.EMPTY_STATE`) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-else class="flex-col flex gap-3">
|
||||
<div
|
||||
v-for="(limit, index) in inboxCapacityLimits"
|
||||
:key="limit.id || `temp-${index}`"
|
||||
class="flex flex-col xs:flex-row items-stretch gap-3"
|
||||
>
|
||||
<div
|
||||
class="flex items-center rounded-lg outline-1 outline cursor-not-allowed text-n-slate-11 outline-n-weak py-2.5 px-3 text-sm w-full min-w-0"
|
||||
:title="getInboxName(limit.inboxId)"
|
||||
>
|
||||
<span class="truncate min-w-0">
|
||||
{{ getInboxName(limit.inboxId) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3 w-full xs:w-auto">
|
||||
<div
|
||||
class="py-2.5 px-3 rounded-lg gap-2 outline outline-1 flex-1 xs:flex-shrink-0 flex items-center min-w-0"
|
||||
:class="[
|
||||
!isLimitValid(limit) ? 'outline-n-ruby-8' : 'outline-n-weak',
|
||||
]"
|
||||
>
|
||||
<label
|
||||
class="text-sm text-n-slate-12 ltr:pr-2 rtl:pl-2 truncate min-w-0 flex-shrink"
|
||||
:title="
|
||||
t(
|
||||
`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.FIELD.MAX_CONVERSATIONS`
|
||||
)
|
||||
"
|
||||
>
|
||||
{{
|
||||
t(
|
||||
`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.FIELD.MAX_CONVERSATIONS`
|
||||
)
|
||||
}}
|
||||
</label>
|
||||
|
||||
<div class="h-5 w-px bg-n-weak" />
|
||||
|
||||
<input
|
||||
v-model.number="limit.conversationLimit"
|
||||
type="number"
|
||||
:min="MIN_CONVERSATION_LIMIT"
|
||||
:max="MAX_CONVERSATION_LIMIT"
|
||||
class="reset-base bg-transparent focus:outline-none min-w-16 w-24 text-sm flex-shrink-0"
|
||||
:class="[
|
||||
!isLimitValid(limit)
|
||||
? 'placeholder:text-n-ruby-9 !text-n-ruby-9'
|
||||
: 'placeholder:text-n-slate-10 text-n-slate-12',
|
||||
]"
|
||||
:placeholder="
|
||||
t(`${BASE_KEY}.FORM.INBOX_CAPACITY_LIMIT.FIELD.SET_LIMIT`)
|
||||
"
|
||||
@blur="handleLimitChange(limit)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
slate
|
||||
icon="i-lucide-trash"
|
||||
class="flex-shrink-0"
|
||||
@click="handleRemoveLimit(limit.id)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,60 +0,0 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['select']);
|
||||
|
||||
const handleChange = () => {
|
||||
if (!props.isActive) {
|
||||
emit('select', props.id);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="relative cursor-pointer rounded-xl outline outline-1 p-4 transition-all duration-200 bg-n-solid-1 py-4 ltr:pl-4 rtl:pr-4 ltr:pr-6 rtl:pl-6"
|
||||
:class="[
|
||||
isActive ? 'outline-n-blue-9' : 'outline-n-weak hover:outline-n-strong',
|
||||
]"
|
||||
@click="handleChange"
|
||||
>
|
||||
<div class="absolute top-4 right-4">
|
||||
<input
|
||||
:id="`${id}`"
|
||||
:checked="isActive"
|
||||
:value="id"
|
||||
:name="id"
|
||||
type="radio"
|
||||
class="h-4 w-4 border-n-slate-6 text-n-brand focus:ring-n-brand focus:ring-offset-0"
|
||||
@change="handleChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="flex flex-col gap-3 items-start">
|
||||
<h3 class="text-sm font-medium text-n-slate-12">
|
||||
{{ label }}
|
||||
</h3>
|
||||
<p class="text-sm text-n-slate-11">
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
<script setup>
|
||||
import AddDataDropdown from '../AddDataDropdown.vue';
|
||||
|
||||
const mockInboxes = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Website Support',
|
||||
email: 'support@company.com',
|
||||
icon: 'i-lucide-globe',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Email Support',
|
||||
email: 'help@company.com',
|
||||
icon: 'i-lucide-mail',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'WhatsApp Business',
|
||||
phoneNumber: '+1 555-0123',
|
||||
icon: 'i-lucide-message-circle',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Facebook Messenger',
|
||||
email: 'messenger@company.com',
|
||||
icon: 'i-lucide-facebook',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Twitter DM',
|
||||
email: 'twitter@company.com',
|
||||
icon: 'i-lucide-twitter',
|
||||
},
|
||||
];
|
||||
|
||||
const mockTags = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'urgent',
|
||||
color: '#ff4757',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'bug',
|
||||
color: '#ff6b6b',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'feature-request',
|
||||
color: '#4834d4',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'documentation',
|
||||
color: '#26de81',
|
||||
},
|
||||
];
|
||||
|
||||
const handleAdd = item => {
|
||||
console.log('Add item:', item);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/AgentManagementPolicy/AddDataDropdown"
|
||||
:layout="{ type: 'grid', width: '500px' }"
|
||||
>
|
||||
<Variant title="Basic Usage - Inboxes">
|
||||
<div class="p-8 bg-n-background flex gap-4 h-[400px] items-start">
|
||||
<AddDataDropdown
|
||||
label="Add Inbox"
|
||||
search-placeholder="Search inboxes..."
|
||||
:items="mockInboxes"
|
||||
@add="handleAdd"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
|
||||
<Variant title="Basic Usage - Tags">
|
||||
<div class="p-8 bg-n-background flex gap-4 h-[400px] items-start">
|
||||
<AddDataDropdown
|
||||
label="Add Tag"
|
||||
search-placeholder="Search tags..."
|
||||
:items="mockTags"
|
||||
@add="handleAdd"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import BaseInfo from '../BaseInfo.vue';
|
||||
|
||||
const policyName = ref('Round Robin Policy');
|
||||
const description = ref(
|
||||
'Distributes conversations evenly among available agents'
|
||||
);
|
||||
const enabled = ref(true);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/AgentManagementPolicy/BaseInfo"
|
||||
:layout="{ type: 'grid', width: '600px' }"
|
||||
>
|
||||
<Variant title="Basic Usage">
|
||||
<div class="p-8 bg-n-background">
|
||||
<BaseInfo
|
||||
v-model:policy-name="policyName"
|
||||
v-model:description="description"
|
||||
v-model:enabled="enabled"
|
||||
name-label="Policy Name"
|
||||
name-placeholder="Enter policy name"
|
||||
description-label="Description"
|
||||
description-placeholder="Enter policy description"
|
||||
status-label="Status"
|
||||
status-placeholder="Active"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
<script setup>
|
||||
import CardPopover from '../CardPopover.vue';
|
||||
|
||||
const mockItems = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Website Support',
|
||||
icon: 'i-lucide-globe',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Email Support',
|
||||
icon: 'i-lucide-mail',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'WhatsApp Business',
|
||||
icon: 'i-lucide-message-circle',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Facebook Messenger',
|
||||
icon: 'i-lucide-facebook',
|
||||
},
|
||||
];
|
||||
|
||||
const mockUsers = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'John Smith',
|
||||
email: 'john.smith@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Sarah Johnson',
|
||||
email: 'sarah.johnson@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=2',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Mike Chen',
|
||||
email: 'mike.chen@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=3',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Emily Davis',
|
||||
email: 'emily.davis@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=4',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Alex Rodriguez',
|
||||
email: 'alex.rodriguez@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=5',
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/AgentManagementPolicy/CardPopover"
|
||||
:layout="{ type: 'grid', width: '800px' }"
|
||||
>
|
||||
<Variant title="Basic Usage">
|
||||
<div class="p-8 bg-n-background flex gap-4 h-96 items-start">
|
||||
<CardPopover
|
||||
:count="3"
|
||||
title="Added Inboxes"
|
||||
icon="i-lucide-inbox"
|
||||
:items="mockItems.slice(0, 3)"
|
||||
@fetch="() => console.log('Fetch triggered')"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
<Variant title="Basic Usage">
|
||||
<div class="p-8 bg-n-background flex gap-4 h-96 items-start">
|
||||
<CardPopover
|
||||
:count="3"
|
||||
title="Added Agents"
|
||||
icon="i-lucide-users-round"
|
||||
:items="mockUsers.slice(0, 3)"
|
||||
@fetch="() => console.log('Fetch triggered')"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
<script setup>
|
||||
import DataTable from '../DataTable.vue';
|
||||
|
||||
const mockItems = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Website Support',
|
||||
email: 'support@company.com',
|
||||
icon: 'i-lucide-globe',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Email Support',
|
||||
email: 'help@company.com',
|
||||
icon: 'i-lucide-mail',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'WhatsApp Business',
|
||||
phoneNumber: '+1 555-0123',
|
||||
icon: 'i-lucide-message-circle',
|
||||
},
|
||||
];
|
||||
|
||||
const mockAgentList = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'John Doe',
|
||||
email: 'john.doe@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Jane Smith',
|
||||
email: 'jane.smith@example.com',
|
||||
avatarUrl: 'https://i.pravatar.cc/150?img=2',
|
||||
},
|
||||
];
|
||||
|
||||
const handleDelete = itemId => {
|
||||
console.log('Delete item:', itemId);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/AgentManagementPolicy/DataTable"
|
||||
:layout="{ type: 'grid', width: '800px' }"
|
||||
>
|
||||
<Variant title="With Data">
|
||||
<div class="p-8 bg-n-background">
|
||||
<DataTable
|
||||
:items="mockItems"
|
||||
:is-fetching="false"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
|
||||
<Variant title="With Agents">
|
||||
<div class="p-8 bg-n-background">
|
||||
<DataTable
|
||||
:items="mockAgentList"
|
||||
:is-fetching="false"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
|
||||
<Variant title="Loading State">
|
||||
<div class="p-8 bg-n-background">
|
||||
<DataTable :items="[]" is-fetching @delete="handleDelete" />
|
||||
</div>
|
||||
</Variant>
|
||||
|
||||
<Variant title="Empty State">
|
||||
<div class="p-8 bg-n-background">
|
||||
<DataTable
|
||||
:items="[]"
|
||||
:is-fetching="false"
|
||||
empty-state-message="No items found"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
<script setup>
|
||||
import ExclusionRules from '../ExclusionRules.vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const mockTagsList = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'urgent',
|
||||
color: '#ff4757',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'bug',
|
||||
color: '#ff6b6b',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'feature-request',
|
||||
color: '#4834d4',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'documentation',
|
||||
color: '#26de81',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'enhancement',
|
||||
color: '#2ed573',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'question',
|
||||
color: '#ffa502',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'duplicate',
|
||||
color: '#747d8c',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'wontfix',
|
||||
color: '#57606f',
|
||||
},
|
||||
];
|
||||
|
||||
const excludedLabelsBasic = ref([]);
|
||||
const excludeOlderThanHoursBasic = ref(10);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/AgentManagementPolicy/ExclusionRules"
|
||||
:layout="{ type: 'grid', width: '1200px' }"
|
||||
>
|
||||
<Variant title="Basic Usage">
|
||||
<div class="p-8 bg-n-background h-[600px]">
|
||||
<ExclusionRules
|
||||
v-model:excluded-labels="excludedLabelsBasic"
|
||||
v-model:exclude-older-than-minutes="excludeOlderThanHoursBasic"
|
||||
:tags-list="mockTagsList"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import FairDistribution from '../FairDistribution.vue';
|
||||
|
||||
const fairDistributionLimit = ref(100);
|
||||
const fairDistributionWindow = ref(3600);
|
||||
const windowUnit = ref('minutes');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/AgentManagementPolicy/FairDistribution"
|
||||
:layout="{ type: 'grid', width: '800px' }"
|
||||
>
|
||||
<Variant title="Basic Usage">
|
||||
<div class="p-8 bg-n-background">
|
||||
<FairDistribution
|
||||
v-model:fair-distribution-limit="fairDistributionLimit"
|
||||
v-model:fair-distribution-window="fairDistributionWindow"
|
||||
v-model:window-unit="windowUnit"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
<script setup>
|
||||
import InboxCapacityLimits from '../InboxCapacityLimits.vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const mockInboxList = [
|
||||
{
|
||||
value: 1,
|
||||
label: 'Website Support',
|
||||
icon: 'i-lucide-globe',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: 'Email Support',
|
||||
icon: 'i-lucide-mail',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: 'WhatsApp Business',
|
||||
icon: 'i-lucide-message-circle',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
label: 'Facebook Messenger',
|
||||
icon: 'i-lucide-facebook',
|
||||
},
|
||||
{
|
||||
value: 5,
|
||||
label: 'Twitter DM',
|
||||
icon: 'i-lucide-twitter',
|
||||
},
|
||||
{
|
||||
value: 6,
|
||||
label: 'Telegram',
|
||||
icon: 'i-lucide-send',
|
||||
},
|
||||
];
|
||||
|
||||
const inboxCapacityLimitsEmpty = ref([]);
|
||||
const inboxCapacityLimitsNew = ref([
|
||||
{ id: 1, inboxId: 1, conversationLimit: 5 },
|
||||
{ inboxId: null, conversationLimit: null },
|
||||
]);
|
||||
|
||||
const handleDelete = id => {
|
||||
console.log('Delete capacity limit:', id);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/AgentManagementPolicy/InboxCapacityLimits"
|
||||
:layout="{ type: 'grid', width: '900px' }"
|
||||
>
|
||||
<Variant title="Empty State">
|
||||
<div class="p-8 bg-n-background">
|
||||
<InboxCapacityLimits
|
||||
v-model:inbox-capacity-limits="inboxCapacityLimitsEmpty"
|
||||
:inbox-list="mockInboxList"
|
||||
:is-fetching="false"
|
||||
:is-updating="false"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
|
||||
<Variant title="Loading State">
|
||||
<div class="p-8 bg-n-background">
|
||||
<InboxCapacityLimits
|
||||
v-model:inbox-capacity-limits="inboxCapacityLimitsEmpty"
|
||||
:inbox-list="mockInboxList"
|
||||
is-fetching
|
||||
:is-updating="false"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
|
||||
<Variant title="With New Row and existing data">
|
||||
<div class="p-8 bg-n-background">
|
||||
<InboxCapacityLimits
|
||||
v-model:inbox-capacity-limits="inboxCapacityLimitsNew"
|
||||
:inbox-list="mockInboxList"
|
||||
:is-fetching="false"
|
||||
:is-updating="false"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
|
||||
<Variant title="Interactive Demo">
|
||||
<div class="p-8 bg-n-background">
|
||||
<InboxCapacityLimits
|
||||
v-model:inbox-capacity-limits="inboxCapacityLimitsEmpty"
|
||||
:inbox-list="mockInboxList"
|
||||
:is-fetching="false"
|
||||
:is-updating="false"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
<div class="mt-4 p-4 bg-n-alpha-2 rounded-lg">
|
||||
<h4 class="text-sm font-medium mb-2">Current Limits:</h4>
|
||||
<pre class="text-xs">{{
|
||||
JSON.stringify(inboxCapacityLimitsEmpty, null, 2)
|
||||
}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import RadioCard from '../RadioCard.vue';
|
||||
|
||||
const selectedOption = ref('round_robin');
|
||||
|
||||
const handleSelect = value => {
|
||||
selectedOption.value = value;
|
||||
console.log('Selected:', value);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story
|
||||
title="Components/AgentManagementPolicy/RadioCard"
|
||||
:layout="{ type: 'grid', width: '600px' }"
|
||||
>
|
||||
<Variant title="Basic Usage">
|
||||
<div class="p-8 bg-n-background space-y-4">
|
||||
<RadioCard
|
||||
id="round_robin"
|
||||
label="Round Robin"
|
||||
description="Distributes conversations evenly among all available agents in a rotating manner"
|
||||
:is-active="selectedOption === 'round_robin'"
|
||||
@select="handleSelect"
|
||||
/>
|
||||
<RadioCard
|
||||
id="balanced"
|
||||
label="Balanced Assignment"
|
||||
description="Assigns conversations based on agent workload to maintain balance"
|
||||
:is-active="selectedOption === 'balanced'"
|
||||
@select="handleSelect"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
|
||||
<Variant title="Active State">
|
||||
<div class="p-8 bg-n-background">
|
||||
<RadioCard
|
||||
id="active_option"
|
||||
label="Active Option"
|
||||
description="This option is currently selected and active"
|
||||
is-active
|
||||
@select="handleSelect"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
|
||||
<Variant title="Inactive State">
|
||||
<div class="p-8 bg-n-background">
|
||||
<RadioCard
|
||||
id="inactive_option"
|
||||
label="Inactive Option"
|
||||
description="This option is not selected and can be clicked to activate"
|
||||
is-active
|
||||
@select="handleSelect"
|
||||
/>
|
||||
</div>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
@@ -86,8 +86,8 @@ const handleLabelAction = async ({ value }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveLabel = label => {
|
||||
return handleLabelAction({ value: label.id });
|
||||
const handleRemoveLabel = labelId => {
|
||||
return handleLabelAction({ value: labelId });
|
||||
};
|
||||
|
||||
watch(
|
||||
|
||||
+2
-10
@@ -51,20 +51,12 @@ const originalState = reactive({ ...state });
|
||||
|
||||
const liveChatWidgets = computed(() => {
|
||||
const inboxes = store.getters['inboxes/getInboxes'];
|
||||
const widgetOptions = inboxes
|
||||
return inboxes
|
||||
.filter(inbox => inbox.channel_type === 'Channel::WebWidget')
|
||||
.map(inbox => ({
|
||||
value: inbox.id,
|
||||
label: inbox.name,
|
||||
}));
|
||||
|
||||
return [
|
||||
{
|
||||
value: '',
|
||||
label: t('HELP_CENTER.PORTAL_SETTINGS.FORM.LIVE_CHAT_WIDGET.NONE_OPTION'),
|
||||
},
|
||||
...widgetOptions,
|
||||
];
|
||||
});
|
||||
|
||||
const rules = {
|
||||
@@ -116,7 +108,7 @@ watch(
|
||||
widgetColor: newVal.color,
|
||||
homePageLink: newVal.homepage_link,
|
||||
slug: newVal.slug,
|
||||
liveChatWidgetInboxId: newVal.inbox?.id || '',
|
||||
liveChatWidgetInboxId: newVal.inbox?.id,
|
||||
});
|
||||
if (newVal.logo) {
|
||||
const {
|
||||
|
||||
@@ -15,7 +15,7 @@ const props = defineProps({
|
||||
const emit = defineEmits(['remove', 'hover']);
|
||||
|
||||
const handleRemoveLabel = () => {
|
||||
emit('remove', props.label);
|
||||
emit('remove', props.label?.id);
|
||||
};
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
@@ -45,7 +45,6 @@ const handleMouseEnter = () => {
|
||||
<Button
|
||||
class="transition-opacity duration-200 !h-7 ltr:rounded-r-md rtl:rounded-l-md ltr:rounded-l-none rtl:rounded-r-none w-6 bg-transparent"
|
||||
:class="{ 'opacity-0': !isHovered, 'opacity-100': isHovered }"
|
||||
type="button"
|
||||
slate
|
||||
xs
|
||||
faded
|
||||
|
||||
@@ -103,12 +103,6 @@ const validationError = computed(() => {
|
||||
);
|
||||
});
|
||||
|
||||
const inputFieldType = computed(() => {
|
||||
if (inputType.value === 'date') return 'date';
|
||||
if (inputType.value === 'number') return 'number';
|
||||
return 'text';
|
||||
});
|
||||
|
||||
const resetModelOnAttributeKeyChange = newAttributeKey => {
|
||||
/**
|
||||
* Resets the filter values and operator when the attribute key changes. This ensures that
|
||||
@@ -188,7 +182,7 @@ defineExpose({ validate });
|
||||
<Input
|
||||
v-else
|
||||
v-model="values"
|
||||
:type="inputFieldType"
|
||||
:type="inputType === 'date' ? 'date' : 'text'"
|
||||
class="[&>input]:h-8 [&>input]:py-1.5 [&>input]:outline-offset-0"
|
||||
:placeholder="t('FILTER.INPUT_PLACEHOLDER')"
|
||||
/>
|
||||
|
||||
@@ -164,8 +164,8 @@ export function useConversationFilterContext() {
|
||||
value: CONVERSATION_ATTRIBUTES.DISPLAY_ID,
|
||||
attributeName: t('FILTER.ATTRIBUTES.CONVERSATION_IDENTIFIER'),
|
||||
label: t('FILTER.ATTRIBUTES.CONVERSATION_IDENTIFIER'),
|
||||
inputType: 'number',
|
||||
dataType: 'number',
|
||||
inputType: 'plainText',
|
||||
datatype: 'number',
|
||||
filterOperators: containmentOperators.value,
|
||||
attributeModel: 'standard',
|
||||
},
|
||||
@@ -179,7 +179,7 @@ export function useConversationFilterContext() {
|
||||
id: campaign.id,
|
||||
name: campaign.title,
|
||||
})),
|
||||
dataType: 'number',
|
||||
datatype: 'number',
|
||||
filterOperators: presenceOperators.value,
|
||||
attributeModel: 'standard',
|
||||
},
|
||||
|
||||
@@ -78,8 +78,6 @@ watch(unit, () => {
|
||||
<option :value="DURATION_UNITS.HOURS">
|
||||
{{ t('DURATION_INPUT.HOURS') }}
|
||||
</option>
|
||||
<option :value="DURATION_UNITS.DAYS">
|
||||
{{ t('DURATION_INPUT.DAYS') }}
|
||||
</option>
|
||||
<option :value="DURATION_UNITS.DAYS">{{ t('DURATION_INPUT.DAYS') }}</option>
|
||||
</select>
|
||||
</template>
|
||||
|
||||
@@ -7,11 +7,6 @@ const props = defineProps({
|
||||
placeholder: { type: String, default: '' },
|
||||
label: { type: String, default: '' },
|
||||
id: { type: String, default: '' },
|
||||
size: {
|
||||
type: String,
|
||||
default: 'md',
|
||||
validator: value => ['sm', 'md'].includes(value),
|
||||
},
|
||||
message: { type: String, default: '' },
|
||||
disabled: { type: Boolean, default: false },
|
||||
messageType: {
|
||||
@@ -20,7 +15,6 @@ const props = defineProps({
|
||||
validator: value => ['info', 'error', 'success'].includes(value),
|
||||
},
|
||||
min: { type: String, default: '' },
|
||||
max: { type: String, default: '' },
|
||||
autofocus: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
@@ -60,12 +54,7 @@ const inputOutlineClass = computed(() => {
|
||||
});
|
||||
|
||||
const handleInput = event => {
|
||||
let value = event.target.value;
|
||||
// Convert to number if type is number and value is not empty
|
||||
if (props.type === 'number' && value !== '') {
|
||||
value = Number(value);
|
||||
}
|
||||
emit('update:modelValue', value);
|
||||
emit('update:modelValue', event.target.value);
|
||||
emit('input', event);
|
||||
};
|
||||
|
||||
@@ -74,17 +63,6 @@ const handleFocus = event => {
|
||||
isFocused.value = true;
|
||||
};
|
||||
|
||||
const sizeClass = computed(() => {
|
||||
switch (props.size) {
|
||||
case 'sm':
|
||||
return 'h-8 !px-3 !py-2';
|
||||
case 'md':
|
||||
return 'h-10 !px-3 !py-2.5';
|
||||
default:
|
||||
return 'h-10 !px-3 !py-2.5';
|
||||
}
|
||||
});
|
||||
|
||||
const handleBlur = event => {
|
||||
emit('blur', event);
|
||||
isFocused.value = false;
|
||||
@@ -116,13 +94,11 @@ onMounted(() => {
|
||||
<slot name="prefix" />
|
||||
<input
|
||||
:id="uniqueId"
|
||||
v-bind="$attrs"
|
||||
ref="inputRef"
|
||||
:value="modelValue"
|
||||
:class="[
|
||||
customInputClass,
|
||||
inputOutlineClass,
|
||||
sizeClass,
|
||||
{
|
||||
error: messageType === 'error',
|
||||
focus: isFocused,
|
||||
@@ -132,12 +108,7 @@ onMounted(() => {
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:min="['date', 'datetime-local', 'time'].includes(type) ? min : undefined"
|
||||
:max="
|
||||
['date', 'datetime-local', 'time', 'number'].includes(type)
|
||||
? max
|
||||
: undefined
|
||||
"
|
||||
class="block w-full reset-base text-sm !mb-0 outline outline-1 border-none border-0 outline-offset-[-1px] rounded-lg bg-n-alpha-black2 file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-n-slate-10 dark:placeholder:text-n-slate-10 disabled:cursor-not-allowed disabled:opacity-50 text-n-slate-12 transition-all duration-500 ease-in-out [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
||||
class="block w-full reset-base text-sm h-10 !px-3 !py-2.5 !mb-0 outline outline-1 border-none border-0 outline-offset-[-1px] rounded-lg bg-n-alpha-black2 file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-n-slate-10 dark:placeholder:text-n-slate-10 disabled:cursor-not-allowed disabled:opacity-50 text-n-slate-12 transition-all duration-500 ease-in-out"
|
||||
@input="handleInput"
|
||||
@focus="handleFocus"
|
||||
@blur="handleBlur"
|
||||
|
||||
@@ -131,8 +131,6 @@ const props = defineProps({
|
||||
sourceId: { type: String, default: '' }, // eslint-disable-line vue/no-unused-properties
|
||||
});
|
||||
|
||||
const emit = defineEmits(['retry']);
|
||||
|
||||
const contextMenuPosition = ref({});
|
||||
const showBackgroundHighlight = ref(false);
|
||||
const showContextMenu = ref(false);
|
||||
@@ -526,7 +524,6 @@ provideMessageContext({
|
||||
class="[grid-area:meta]"
|
||||
:class="flexOrientationClass"
|
||||
:error="contentAttributes.externalError"
|
||||
@retry="emit('retry')"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="shouldShowContextMenu" class="context-menu-wrap">
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import Icon from 'next/icon/Icon.vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useMessageContext } from './provider.js';
|
||||
import { hasOneDayPassed } from 'shared/helpers/timeHelper';
|
||||
import { ORIENTATION, MESSAGE_STATUS } from './constants';
|
||||
import { ORIENTATION } from './constants';
|
||||
|
||||
defineProps({
|
||||
error: { type: String, required: true },
|
||||
});
|
||||
|
||||
const emit = defineEmits(['retry']);
|
||||
|
||||
const { orientation, status, createdAt } = useMessageContext();
|
||||
const { orientation } = useMessageContext();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const canRetry = computed(() => !hasOneDayPassed(createdAt.value));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -41,14 +35,5 @@ const canRetry = computed(() => !hasOneDayPassed(createdAt.value));
|
||||
{{ error }}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
v-if="canRetry"
|
||||
type="button"
|
||||
:disabled="status !== MESSAGE_STATUS.FAILED"
|
||||
class="bg-n-alpha-2 rounded-md size-5 grid place-content-center cursor-pointer"
|
||||
@click="emit('retry')"
|
||||
>
|
||||
<Icon icon="i-lucide-refresh-ccw" class="text-n-ruby-11 size-[14px]" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -37,8 +37,6 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['retry']);
|
||||
|
||||
const allMessages = computed(() => {
|
||||
return useCamelCase(props.messages, { deep: true });
|
||||
});
|
||||
@@ -115,7 +113,6 @@ const getInReplyToMessage = parentMessage => {
|
||||
:inbox-supports-reply-to="inboxSupportsReplyTo"
|
||||
:current-user-id="currentUserId"
|
||||
data-clarity-mask="True"
|
||||
@retry="emit('retry', message)"
|
||||
/>
|
||||
</template>
|
||||
<slot name="after" />
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
<script setup>
|
||||
import {
|
||||
computed,
|
||||
onMounted,
|
||||
useTemplateRef,
|
||||
ref,
|
||||
getCurrentInstance,
|
||||
} from 'vue';
|
||||
import { computed, onMounted, useTemplateRef, ref } from 'vue';
|
||||
import Icon from 'next/icon/Icon.vue';
|
||||
import { timeStampAppendedURL } from 'dashboard/helper/URLHelper';
|
||||
import { downloadFile } from '@chatwoot/utils';
|
||||
import { useEmitter } from 'dashboard/composables/emitter';
|
||||
import { emitter } from 'shared/helpers/mitt';
|
||||
|
||||
const { attachment } = defineProps({
|
||||
attachment: {
|
||||
@@ -35,8 +27,6 @@ const currentTime = ref(0);
|
||||
const duration = ref(0);
|
||||
const playbackSpeed = ref(1);
|
||||
|
||||
const { uid } = getCurrentInstance();
|
||||
|
||||
const onLoadedMetadata = () => {
|
||||
duration.value = audioPlayer.value?.duration;
|
||||
};
|
||||
@@ -53,18 +43,6 @@ onMounted(() => {
|
||||
audioPlayer.value.playbackRate = playbackSpeed.value;
|
||||
});
|
||||
|
||||
// Listen for global audio play events and pause if it's not this audio
|
||||
useEmitter('pause_playing_audio', currentPlayingId => {
|
||||
if (currentPlayingId !== uid && isPlaying.value) {
|
||||
try {
|
||||
audioPlayer.value.pause();
|
||||
} catch {
|
||||
/* ignore pause errors */
|
||||
}
|
||||
isPlaying.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
const formatTime = time => {
|
||||
if (!time || Number.isNaN(time)) return '00:00';
|
||||
const minutes = Math.floor(time / 60);
|
||||
@@ -92,8 +70,6 @@ const playOrPause = () => {
|
||||
audioPlayer.value.pause();
|
||||
isPlaying.value = false;
|
||||
} else {
|
||||
// Emit event to pause all other audio
|
||||
emitter.emit('pause_playing_audio', uid);
|
||||
audioPlayer.value.play();
|
||||
isPlaying.value = true;
|
||||
}
|
||||
@@ -125,7 +101,6 @@ const downloadAudio = async () => {
|
||||
ref="audioPlayer"
|
||||
controls
|
||||
class="hidden"
|
||||
playsinline
|
||||
@loadedmetadata="onLoadedMetadata"
|
||||
@timeupdate="onTimeUpdate"
|
||||
@ended="onEnd"
|
||||
|
||||
@@ -494,12 +494,6 @@ const menuItems = computed(() => {
|
||||
icon: 'i-lucide-clock-alert',
|
||||
to: accountScopedRoute('sla_list'),
|
||||
},
|
||||
{
|
||||
name: 'Settings Security',
|
||||
label: t('SIDEBAR.SECURITY'),
|
||||
icon: 'i-lucide-shield',
|
||||
to: accountScopedRoute('security_settings_index'),
|
||||
},
|
||||
{
|
||||
name: 'Settings Billing',
|
||||
label: t('SIDEBAR.BILLING'),
|
||||
|
||||
@@ -72,10 +72,6 @@ const formatType = computed(() => {
|
||||
return format ? format.charAt(0) + format.slice(1).toLowerCase() : '';
|
||||
});
|
||||
|
||||
const isDocumentTemplate = computed(() => {
|
||||
return headerComponent.value?.format?.toLowerCase() === 'document';
|
||||
});
|
||||
|
||||
const hasVariables = computed(() => {
|
||||
return bodyText.value?.match(/{{([^}]+)}}/g) !== null;
|
||||
});
|
||||
@@ -130,11 +126,6 @@ const updateMediaUrl = value => {
|
||||
processedParams.value.header.media_url = value;
|
||||
};
|
||||
|
||||
const updateMediaName = value => {
|
||||
processedParams.value.header ??= {};
|
||||
processedParams.value.header.media_name = value;
|
||||
};
|
||||
|
||||
const sendMessage = () => {
|
||||
v$.value.$touch();
|
||||
if (v$.value.$invalid) return;
|
||||
@@ -177,12 +168,10 @@ defineExpose({
|
||||
processedParams,
|
||||
hasVariables,
|
||||
hasMediaHeader,
|
||||
isDocumentTemplate,
|
||||
headerComponent,
|
||||
renderedTemplate,
|
||||
v$,
|
||||
updateMediaUrl,
|
||||
updateMediaName,
|
||||
sendMessage,
|
||||
resetTemplate,
|
||||
goBack,
|
||||
@@ -236,17 +225,6 @@ defineExpose({
|
||||
@update:model-value="updateMediaUrl"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="isDocumentTemplate" class="flex items-center mb-2.5">
|
||||
<Input
|
||||
:model-value="processedParams.header?.media_name || ''"
|
||||
type="text"
|
||||
class="flex-1"
|
||||
:placeholder="
|
||||
t('WHATSAPP_TEMPLATES.PARSER.DOCUMENT_NAME_PLACEHOLDER')
|
||||
"
|
||||
@update:model-value="updateMediaName"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Body Variables Section -->
|
||||
|
||||
@@ -1,328 +0,0 @@
|
||||
<script setup>
|
||||
import axios from 'axios';
|
||||
import { ref, computed, nextTick } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { handleOtpPaste } from 'shared/helpers/clipboard';
|
||||
import { parseAPIErrorResponse } from 'dashboard/store/utils/api';
|
||||
import { useAccount } from 'dashboard/composables/useAccount';
|
||||
|
||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||
import FormInput from 'v3/components/Form/Input.vue';
|
||||
import NextButton from 'dashboard/components-next/button/Button.vue';
|
||||
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
||||
|
||||
const props = defineProps({
|
||||
mfaToken: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['verified', 'cancel']);
|
||||
|
||||
const { t } = useI18n();
|
||||
const { isOnChatwootCloud } = useAccount();
|
||||
|
||||
const OTP = 'otp';
|
||||
const BACKUP = 'backup';
|
||||
|
||||
// State
|
||||
const verificationMethod = ref(OTP);
|
||||
const otpDigits = ref(['', '', '', '', '', '']);
|
||||
const backupCode = ref('');
|
||||
const isVerifying = ref(false);
|
||||
const errorMessage = ref('');
|
||||
const helpModalRef = ref(null);
|
||||
const otpInputRefs = ref([]);
|
||||
|
||||
// Computed
|
||||
const otpCode = computed(() => otpDigits.value.join(''));
|
||||
const canSubmit = computed(() =>
|
||||
verificationMethod.value === OTP
|
||||
? otpCode.value.length === 6
|
||||
: backupCode.value.length === 8
|
||||
);
|
||||
|
||||
const contactDescKey = computed(() =>
|
||||
isOnChatwootCloud.value ? 'CONTACT_DESC_CLOUD' : 'CONTACT_DESC_SELF_HOSTED'
|
||||
);
|
||||
|
||||
const focusInput = i => otpInputRefs.value[i]?.focus();
|
||||
|
||||
// Verification
|
||||
const handleVerification = async () => {
|
||||
if (!canSubmit.value || isVerifying.value) return;
|
||||
|
||||
isVerifying.value = true;
|
||||
errorMessage.value = '';
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
mfa_token: props.mfaToken,
|
||||
};
|
||||
|
||||
if (verificationMethod.value === OTP) {
|
||||
payload.otp_code = otpCode.value;
|
||||
} else {
|
||||
payload.backup_code = backupCode.value;
|
||||
}
|
||||
|
||||
const response = await axios.post('/auth/sign_in', payload);
|
||||
|
||||
// Set auth credentials and redirect
|
||||
if (response.data && response.headers) {
|
||||
// Store auth credentials in cookies
|
||||
const authData = {
|
||||
'access-token': response.headers['access-token'],
|
||||
'token-type': response.headers['token-type'],
|
||||
client: response.headers.client,
|
||||
expiry: response.headers.expiry,
|
||||
uid: response.headers.uid,
|
||||
};
|
||||
|
||||
// Store in cookies for auth
|
||||
document.cookie = `cw_d_session_info=${encodeURIComponent(JSON.stringify(authData))}; path=/; SameSite=Lax`;
|
||||
|
||||
// Redirect to dashboard
|
||||
window.location.href = '/app/';
|
||||
} else {
|
||||
emit('verified', response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
errorMessage.value =
|
||||
parseAPIErrorResponse(error) || t('MFA_VERIFICATION.VERIFICATION_FAILED');
|
||||
|
||||
// Clear inputs on error
|
||||
if (verificationMethod.value === OTP) {
|
||||
otpDigits.value.fill('');
|
||||
await nextTick();
|
||||
focusInput(0);
|
||||
} else {
|
||||
backupCode.value = '';
|
||||
}
|
||||
} finally {
|
||||
isVerifying.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// OTP Input Handling
|
||||
const handleOtpInput = async i => {
|
||||
const v = otpDigits.value[i];
|
||||
|
||||
// Only allow numbers
|
||||
if (!/^\d*$/.test(v)) {
|
||||
otpDigits.value[i] = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// Move to next input if value entered
|
||||
if (v && i < 5) {
|
||||
await nextTick();
|
||||
focusInput(i + 1);
|
||||
}
|
||||
|
||||
// Auto-submit if all digits entered
|
||||
if (otpCode.value.length === 6) {
|
||||
handleVerification();
|
||||
}
|
||||
};
|
||||
|
||||
const handleBackspace = (e, i) => {
|
||||
if (!otpDigits.value[i] && i > 0) {
|
||||
e.preventDefault();
|
||||
focusInput(i - 1);
|
||||
otpDigits.value[i - 1] = '';
|
||||
}
|
||||
};
|
||||
|
||||
const handleOtpCodePaste = e => {
|
||||
e.preventDefault();
|
||||
const code = handleOtpPaste(e, 6);
|
||||
|
||||
if (code) {
|
||||
otpDigits.value = code.split('');
|
||||
handleVerification();
|
||||
}
|
||||
};
|
||||
|
||||
// Alternative Actions
|
||||
const handleTryAnotherMethod = () => {
|
||||
// Toggle between methods
|
||||
verificationMethod.value = verificationMethod.value === OTP ? BACKUP : OTP;
|
||||
otpDigits.value.fill('');
|
||||
backupCode.value = '';
|
||||
errorMessage.value = '';
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full max-w-md mx-auto">
|
||||
<div
|
||||
class="bg-white shadow sm:mx-auto sm:w-full sm:max-w-lg dark:bg-n-solid-2 p-11 sm:shadow-lg sm:rounded-lg"
|
||||
>
|
||||
<!-- Header -->
|
||||
<div class="text-center mb-6">
|
||||
<div
|
||||
class="inline-flex items-center justify-center size-14 bg-n-solid-1 outline outline-n-weak rounded-full mb-4"
|
||||
>
|
||||
<Icon icon="i-lucide-lock-keyhole" class="size-6 text-n-slate-10" />
|
||||
</div>
|
||||
<h2 class="text-2xl font-semibold text-n-slate-12">
|
||||
{{ $t('MFA_VERIFICATION.TITLE') }}
|
||||
</h2>
|
||||
<p class="text-sm text-n-slate-11 mt-2">
|
||||
{{ $t('MFA_VERIFICATION.DESCRIPTION') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Tab Selection -->
|
||||
<div class="flex rounded-lg bg-n-alpha-black2 p-1 mb-6">
|
||||
<button
|
||||
v-for="method in [OTP, BACKUP]"
|
||||
:key="method"
|
||||
class="flex-1 py-2 px-4 text-sm font-medium rounded-md transition-colors"
|
||||
:class="
|
||||
verificationMethod === method
|
||||
? 'bg-n-solid-active text-n-slate-12 shadow-sm'
|
||||
: 'text-n-slate-12'
|
||||
"
|
||||
@click="verificationMethod = method"
|
||||
>
|
||||
{{
|
||||
$t(
|
||||
`MFA_VERIFICATION.${method === OTP ? 'AUTHENTICATOR_APP' : 'BACKUP_CODE'}`
|
||||
)
|
||||
}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Verification Form -->
|
||||
<form class="space-y-4" @submit.prevent="handleVerification">
|
||||
<!-- OTP Code Input -->
|
||||
<div v-if="verificationMethod === OTP">
|
||||
<label class="block text-sm font-medium text-n-slate-12 mb-2">
|
||||
{{ $t('MFA_VERIFICATION.ENTER_OTP_CODE') }}
|
||||
</label>
|
||||
<div class="flex justify-between gap-2">
|
||||
<input
|
||||
v-for="(_, i) in otpDigits"
|
||||
:key="i"
|
||||
ref="otpInputRefs"
|
||||
v-model="otpDigits[i]"
|
||||
type="text"
|
||||
maxlength="1"
|
||||
pattern="[0-9]"
|
||||
inputmode="numeric"
|
||||
class="w-12 h-12 text-center text-lg font-semibold border-2 border-n-weak hover:border-n-strong rounded-lg focus:border-n-brand bg-n-alpha-black2 text-n-slate-12 placeholder:text-n-slate-10"
|
||||
@input="handleOtpInput(i)"
|
||||
@keydown.left.prevent="focusInput(i - 1)"
|
||||
@keydown.right.prevent="focusInput(i + 1)"
|
||||
@keydown.backspace="handleBackspace($event, i)"
|
||||
@paste="handleOtpCodePaste"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Backup Code Input -->
|
||||
<div v-if="verificationMethod === BACKUP">
|
||||
<FormInput
|
||||
v-model="backupCode"
|
||||
name="backup_code"
|
||||
type="text"
|
||||
data-testid="backup_code_input"
|
||||
:tabindex="1"
|
||||
required
|
||||
:label="$t('MFA_VERIFICATION.ENTER_BACKUP_CODE')"
|
||||
:placeholder="
|
||||
$t('MFA_VERIFICATION.BACKUP_CODE_PLACEHOLDER') || '000000'
|
||||
"
|
||||
@keyup.enter="handleVerification"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Error Message -->
|
||||
<div
|
||||
v-if="errorMessage"
|
||||
class="p-3 bg-n-ruby-3 outline outline-n-ruby-5 outline-1 rounded-lg"
|
||||
>
|
||||
<p class="text-sm text-n-ruby-9">{{ errorMessage }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<NextButton
|
||||
lg
|
||||
type="submit"
|
||||
data-testid="submit_button"
|
||||
class="w-full"
|
||||
:tabindex="2"
|
||||
:label="$t('MFA_VERIFICATION.VERIFY_BUTTON')"
|
||||
:disabled="!canSubmit || isVerifying"
|
||||
:is-loading="isVerifying"
|
||||
/>
|
||||
|
||||
<!-- Alternative Actions -->
|
||||
<div class="text-center flex items-center flex-col gap-2 pt-4">
|
||||
<NextButton
|
||||
sm
|
||||
link
|
||||
type="button"
|
||||
class="w-full hover:!no-underline"
|
||||
:tabindex="2"
|
||||
:label="$t('MFA_VERIFICATION.TRY_ANOTHER_METHOD')"
|
||||
@click="handleTryAnotherMethod"
|
||||
/>
|
||||
<NextButton
|
||||
sm
|
||||
slate
|
||||
link
|
||||
type="button"
|
||||
class="w-full hover:!no-underline"
|
||||
:tabindex="3"
|
||||
:label="$t('MFA_VERIFICATION.CANCEL_LOGIN')"
|
||||
@click="() => emit('cancel')"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Help Text -->
|
||||
<div class="mt-6 text-center">
|
||||
<p class="text-sm text-n-slate-11">
|
||||
{{ $t('MFA_VERIFICATION.HELP_TEXT') }}
|
||||
</p>
|
||||
<NextButton
|
||||
sm
|
||||
link
|
||||
type="button"
|
||||
class="w-full hover:!no-underline"
|
||||
:tabindex="4"
|
||||
:label="$t('MFA_VERIFICATION.LEARN_MORE')"
|
||||
@click="helpModalRef?.open()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Help Modal -->
|
||||
<Dialog
|
||||
ref="helpModalRef"
|
||||
:title="$t('MFA_VERIFICATION.HELP_MODAL.TITLE')"
|
||||
:show-confirm-button="false"
|
||||
class="[&>dialog>div]:bg-n-alpha-3 [&>dialog>div]:rounded-lg"
|
||||
@confirm="helpModalRef?.close()"
|
||||
>
|
||||
<div class="space-y-4 text-sm text-n-slate-11">
|
||||
<div v-for="section in ['AUTHENTICATOR', 'BACKUP']" :key="section">
|
||||
<h4 class="font-medium text-n-slate-12 mb-2">
|
||||
{{ $t(`MFA_VERIFICATION.HELP_MODAL.${section}_TITLE`) }}
|
||||
</h4>
|
||||
<p>{{ $t(`MFA_VERIFICATION.HELP_MODAL.${section}_DESC`) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-medium text-n-slate-12 mb-2">
|
||||
{{ $t('MFA_VERIFICATION.HELP_MODAL.CONTACT_TITLE') }}
|
||||
</h4>
|
||||
<p>{{ $t(`MFA_VERIFICATION.HELP_MODAL.${contactDescKey}`) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
@@ -4,7 +4,6 @@ import { ref, provide } from 'vue';
|
||||
import { useConfig } from 'dashboard/composables/useConfig';
|
||||
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
|
||||
import { useAI } from 'dashboard/composables/useAI';
|
||||
import { useSnakeCase } from 'dashboard/composables/useTransformKeys';
|
||||
|
||||
// components
|
||||
import ReplyBox from './ReplyBox.vue';
|
||||
@@ -438,11 +437,6 @@ export default {
|
||||
makeMessagesRead() {
|
||||
this.$store.dispatch('markMessagesRead', { id: this.currentChat.id });
|
||||
},
|
||||
async handleMessageRetry(message) {
|
||||
if (!message) return;
|
||||
const payload = useSnakeCase(message);
|
||||
await this.$store.dispatch('sendMessageWithData', payload);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -471,7 +465,6 @@ export default {
|
||||
:is-an-email-channel="isAnEmailChannel"
|
||||
:inbox-supports-reply-to="inboxSupportsReplyTo"
|
||||
:messages="getMessages"
|
||||
@retry="handleMessageRetry"
|
||||
>
|
||||
<template #beforeAll>
|
||||
<transition name="slide-up">
|
||||
|
||||
@@ -104,7 +104,6 @@ export default function useAutomationValues() {
|
||||
contacts: contacts.value,
|
||||
customAttributes: getters['attributes/getAttributes'].value,
|
||||
inboxes: inboxes.value,
|
||||
labels: labels.value,
|
||||
statusFilterOptions: statusFilterOptions.value,
|
||||
priorityOptions: priorityOptions.value,
|
||||
messageTypeOptions: messageTypeOptions.value,
|
||||
|
||||
@@ -35,8 +35,6 @@ export default {
|
||||
HELP_CENTER_DOCS_URL:
|
||||
'https://www.chatwoot.com/docs/product/others/help-center',
|
||||
TESTIMONIAL_URL: 'https://testimonials.cdn.chatwoot.com/content.json',
|
||||
WHATSAPP_EMBEDDED_SIGNUP_DOCS_URL:
|
||||
'https://developers.facebook.com/docs/whatsapp/embedded-signup/custom-flows/onboarding-business-app-users#limitations',
|
||||
SMALL_SCREEN_BREAKPOINT: 768,
|
||||
AVAILABILITY_STATUS_KEYS: ['online', 'busy', 'offline'],
|
||||
SNOOZE_OPTIONS: {
|
||||
|
||||
@@ -38,8 +38,8 @@ export const FEATURE_FLAGS = {
|
||||
REPORT_V4: 'report_v4',
|
||||
CHANNEL_INSTAGRAM: 'channel_instagram',
|
||||
CONTACT_CHATWOOT_SUPPORT_TEAM: 'contact_chatwoot_support_team',
|
||||
WHATSAPP_EMBEDDED_SIGNUP: 'whatsapp_embedded_signup',
|
||||
CAPTAIN_V2: 'captain_integration_v2',
|
||||
SAML: 'saml',
|
||||
};
|
||||
|
||||
export const PREMIUM_FEATURES = [
|
||||
|
||||
@@ -124,7 +124,6 @@ export const getConditionOptions = ({
|
||||
customAttributes,
|
||||
inboxes,
|
||||
languages,
|
||||
labels,
|
||||
statusFilterOptions,
|
||||
teams,
|
||||
type,
|
||||
@@ -151,7 +150,6 @@ export const getConditionOptions = ({
|
||||
country_code: countries,
|
||||
message_type: messageTypeOptions,
|
||||
priority: priorityOptions,
|
||||
labels: generateConditionOptions(labels, 'title'),
|
||||
};
|
||||
|
||||
return conditionFilterMaps[type];
|
||||
|
||||
@@ -96,18 +96,3 @@ export const sanitizeVariableSearchKey = (searchKey = '') => {
|
||||
.replace(/,/g, '') // remove commas
|
||||
.trim();
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert underscore-separated string to title case.
|
||||
* Eg. "round_robin" => "Round Robin"
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
export const formatToTitleCase = str => {
|
||||
return (
|
||||
str
|
||||
?.replace(/_/g, ' ')
|
||||
.replace(/\b\w/g, l => l.toUpperCase())
|
||||
.trim() || ''
|
||||
);
|
||||
};
|
||||
|
||||
@@ -19,7 +19,6 @@ const FEATURE_HELP_URLS = {
|
||||
team_management: 'https://chwt.app/hc/teams',
|
||||
webhook: 'https://chwt.app/hc/webhooks',
|
||||
billing: 'https://chwt.app/pricing',
|
||||
saml: 'https://chwt.app/hc/saml',
|
||||
};
|
||||
|
||||
export function getHelpUrlForFeature(featureName) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
convertToCategorySlug,
|
||||
convertToPortalSlug,
|
||||
sanitizeVariableSearchKey,
|
||||
formatToTitleCase,
|
||||
} from '../commons';
|
||||
|
||||
describe('#getTypingUsersText', () => {
|
||||
@@ -143,51 +142,3 @@ describe('sanitizeVariableSearchKey', () => {
|
||||
expect(sanitizeVariableSearchKey()).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatToTitleCase', () => {
|
||||
it('converts underscore-separated string to title case', () => {
|
||||
expect(formatToTitleCase('round_robin')).toBe('Round Robin');
|
||||
});
|
||||
|
||||
it('converts single word to title case', () => {
|
||||
expect(formatToTitleCase('priority')).toBe('Priority');
|
||||
});
|
||||
|
||||
it('converts multiple underscores to title case', () => {
|
||||
expect(formatToTitleCase('auto_assignment_policy')).toBe(
|
||||
'Auto Assignment Policy'
|
||||
);
|
||||
});
|
||||
|
||||
it('handles already capitalized words', () => {
|
||||
expect(formatToTitleCase('HIGH_PRIORITY')).toBe('HIGH PRIORITY');
|
||||
});
|
||||
|
||||
it('handles mixed case with underscores', () => {
|
||||
expect(formatToTitleCase('first_Name_last')).toBe('First Name Last');
|
||||
});
|
||||
|
||||
it('handles empty string', () => {
|
||||
expect(formatToTitleCase('')).toBe('');
|
||||
});
|
||||
|
||||
it('handles null input', () => {
|
||||
expect(formatToTitleCase(null)).toBe('');
|
||||
});
|
||||
|
||||
it('handles undefined input', () => {
|
||||
expect(formatToTitleCase(undefined)).toBe('');
|
||||
});
|
||||
|
||||
it('handles string without underscores', () => {
|
||||
expect(formatToTitleCase('hello')).toBe('Hello');
|
||||
});
|
||||
|
||||
it('handles string with numbers', () => {
|
||||
expect(formatToTitleCase('priority_1_high')).toBe('Priority 1 High');
|
||||
});
|
||||
|
||||
it('handles leading and trailing underscores', () => {
|
||||
expect(formatToTitleCase('_leading_trailing_')).toBe('Leading Trailing');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -218,7 +218,6 @@ describe('templateHelper', () => {
|
||||
expect(result.header).toEqual({
|
||||
media_url: '',
|
||||
media_type: 'document',
|
||||
media_name: '',
|
||||
});
|
||||
expect(result.body).toEqual({
|
||||
1: '',
|
||||
|
||||
@@ -51,11 +51,6 @@ export const buildTemplateParameters = (template, hasMediaHeaderValue) => {
|
||||
if (!allVariables.header) allVariables.header = {};
|
||||
allVariables.header.media_url = '';
|
||||
allVariables.header.media_type = headerComponent.format.toLowerCase();
|
||||
|
||||
// For document templates, include media_name field for filename support
|
||||
if (headerComponent.format.toLowerCase() === 'document') {
|
||||
allVariables.header.media_name = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Process button variables
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "Show labels",
|
||||
"HIDE_LABELS": "Hide labels"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Resolve",
|
||||
"REOPEN_ACTION": "Reopen",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "Labels",
|
||||
"REPORTS_INBOX": "Inbox",
|
||||
"REPORTS_TEAM": "Team",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "Set yourself as",
|
||||
"SET_YOUR_AVAILABILITY": "Set your availability",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "Priority",
|
||||
"ACTIVE": "Active",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "Edit"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Description:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "Status:",
|
||||
"PLACEHOLDER": "Select status",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "Add"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "Edit"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Description:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "Add"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "Delete",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "إظهار السمات",
|
||||
"HIDE_LABELS": "إخفاء السمات"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "حل المحادثة",
|
||||
"REOPEN_ACTION": "إعادة فتح",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "الوسوم",
|
||||
"REPORTS_INBOX": "صندوق الوارد",
|
||||
"REPORTS_TEAM": "الفريق",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "تعيين نفسك كـ",
|
||||
"SET_YOUR_AVAILABILITY": "قم بتعيين توافرك",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "التبديل إلى الرد",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "تبديل القائمة المنسدلة"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "الأولوية",
|
||||
"ACTIVE": "مفعل",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "تعديل"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "إلغاء"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "الوصف:",
|
||||
"PLACEHOLDER": "أدخل الوصف"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "الحالة:",
|
||||
"PLACEHOLDER": "اختر الحالة",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "إضافة"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "تعديل"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "إلغاء"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "الوصف:",
|
||||
"PLACEHOLDER": "أدخل الوصف"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "إضافة"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "حذف",
|
||||
"CANCEL_BUTTON_LABEL": "إلغاء"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "Show labels",
|
||||
"HIDE_LABELS": "Hide labels"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Resolve",
|
||||
"REOPEN_ACTION": "Reopen",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "Labels",
|
||||
"REPORTS_INBOX": "Inbox",
|
||||
"REPORTS_TEAM": "Team",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "Set yourself as",
|
||||
"SET_YOUR_AVAILABILITY": "Set your availability",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "Priority",
|
||||
"ACTIVE": "Active",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "Edit"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Description:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "Status:",
|
||||
"PLACEHOLDER": "Select status",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "Add"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "Edit"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Description:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "Add"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "Delete",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "Show labels",
|
||||
"HIDE_LABELS": "Hide labels"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Resolve",
|
||||
"REOPEN_ACTION": "Reopen",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "Labels",
|
||||
"REPORTS_INBOX": "Входяща кутия",
|
||||
"REPORTS_TEAM": "Team",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "Set yourself as",
|
||||
"SET_YOUR_AVAILABILITY": "Set your availability",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "Priority",
|
||||
"ACTIVE": "Активен",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "Редактирай"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Отмени"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Описание:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "Статус:",
|
||||
"PLACEHOLDER": "Select status",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "Добавяне"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "Редактирай"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Отмени"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Описание:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "Добавяне"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "Изтрий",
|
||||
"CANCEL_BUTTON_LABEL": "Отмени"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "Mostra etiquetes",
|
||||
"HIDE_LABELS": "Amaga etiquetes"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Resoldre",
|
||||
"REOPEN_ACTION": "Tornar a obrir",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "Etiquetes",
|
||||
"REPORTS_INBOX": "Safata d'entrada",
|
||||
"REPORTS_TEAM": "Equip",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "Posa't com",
|
||||
"SET_YOUR_AVAILABILITY": "Estableix la vostra disponibilitat",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "Canvia a Respon",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Commuta el menú desplegable de posposar"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "Prioritat",
|
||||
"ACTIVE": "Actiu",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "Edita"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel·la"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Descripció:",
|
||||
"PLACEHOLDER": "Introdueix la descripció"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "Estat:",
|
||||
"PLACEHOLDER": "Selecciona l'estat",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "Afegir"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "Edita"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel·la"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Descripció:",
|
||||
"PLACEHOLDER": "Introdueix la descripció"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "Afegir"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "Esborrar",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel·la"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "Show labels",
|
||||
"HIDE_LABELS": "Hide labels"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Vyřešit",
|
||||
"REOPEN_ACTION": "Znovu otevřít",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "Štítky",
|
||||
"REPORTS_INBOX": "Inbox",
|
||||
"REPORTS_TEAM": "Team",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "Set yourself as",
|
||||
"SET_YOUR_AVAILABILITY": "Nastavte svou dostupnost",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "Priority",
|
||||
"ACTIVE": "Active",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "Upravit"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Zrušit"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Description:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "Stav:",
|
||||
"PLACEHOLDER": "Select status",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "Přidat"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "Upravit"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Zrušit"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Description:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "Přidat"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "Vymazat",
|
||||
"CANCEL_BUTTON_LABEL": "Zrušit"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "Vis etiketter",
|
||||
"HIDE_LABELS": "Skjul etiketter"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Løs",
|
||||
"REOPEN_ACTION": "Genåben",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "Etiketter",
|
||||
"REPORTS_INBOX": "Indbakke",
|
||||
"REPORTS_TEAM": "Team",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "Sæt dig selv som",
|
||||
"SET_YOUR_AVAILABILITY": "Indstil din tilgængelighed",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "Skift til svar",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Skift snooze dropdown"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "Priority",
|
||||
"ACTIVE": "Aktiv",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "Rediger"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Annuller"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Beskrivelse:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "Status:",
|
||||
"PLACEHOLDER": "Select status",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "Tilføj"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "Rediger"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Annuller"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Beskrivelse:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "Tilføj"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "Slet",
|
||||
"CANCEL_BUTTON_LABEL": "Annuller"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "Labels anzeigen",
|
||||
"HIDE_LABELS": "Labels ausblenden"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Fall schließen",
|
||||
"REOPEN_ACTION": "Wieder öffnen",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "Labels",
|
||||
"REPORTS_INBOX": "Posteingang",
|
||||
"REPORTS_TEAM": "Team",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "Setzen Sie sich als",
|
||||
"SET_YOUR_AVAILABILITY": "Legen Sie Ihre Verfügbarkeit fest",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "Zur Antwort wechseln",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Schlummer-Dropdown ein-/ausblenden"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "Priorität",
|
||||
"ACTIVE": "Aktiv",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "Bearbeiten"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Stornieren"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Beschreibung:",
|
||||
"PLACEHOLDER": "Beschreibung eingeben"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "Status:",
|
||||
"PLACEHOLDER": "Status auswählen",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "Hinzufügen"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "Bearbeiten"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Stornieren"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Beschreibung:",
|
||||
"PLACEHOLDER": "Beschreibung eingeben"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "Hinzufügen"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "Löschen",
|
||||
"CANCEL_BUTTON_LABEL": "Stornieren"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "Προβολή ετικετών",
|
||||
"HIDE_LABELS": "Απόκρυψη ετικετών"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Επίλυση",
|
||||
"REOPEN_ACTION": "Επαναφορά",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "Ετικέτες",
|
||||
"REPORTS_INBOX": "Εισερχόμενα",
|
||||
"REPORTS_TEAM": "Ομάδα",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "Ορίστε τον εαυτό σας ως",
|
||||
"SET_YOUR_AVAILABILITY": "Ορίστε τη διαθεσιμότητά σας",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "Εναλλαγή σε απάντηση",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Εναλλαγή αναβολής dropdown"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "Priority",
|
||||
"ACTIVE": "Ενεργή",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "Επεξεργασία"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Άκυρο"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Περιγραφή:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "Κατάσταση:",
|
||||
"PLACEHOLDER": "Select status",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "Προσθήκη"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "Επεξεργασία"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Άκυρο"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Περιγραφή:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "Προσθήκη"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "Διαγραφή",
|
||||
"CANCEL_BUTTON_LABEL": "Άκυρο"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,8 +177,7 @@
|
||||
"REFERER_LINK": "Referrer Link",
|
||||
"ASSIGNEE_NAME": "Assignee",
|
||||
"TEAM_NAME": "Team",
|
||||
"PRIORITY": "Priority",
|
||||
"LABELS": "Labels"
|
||||
"PRIORITY": "Priority"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,8 +741,7 @@
|
||||
"LIVE_CHAT_WIDGET": {
|
||||
"LABEL": "Live chat widget",
|
||||
"PLACEHOLDER": "Select live chat widget",
|
||||
"HELP_TEXT": "Select a live chat widget that will appear on your help center",
|
||||
"NONE_OPTION": "No widget"
|
||||
"HELP_TEXT": "Select a live chat widget that will appear on your help center"
|
||||
},
|
||||
"BRAND_COLOR": {
|
||||
"LABEL": "Brand color"
|
||||
|
||||
@@ -272,8 +272,8 @@
|
||||
},
|
||||
"SUBMIT_BUTTON": "Create WhatsApp Channel",
|
||||
"EMBEDDED_SIGNUP": {
|
||||
"TITLE": "Quick setup with Meta",
|
||||
"DESC": "Use the WhatsApp Embedded Signup flow to quickly connect new numbers. You will be redirected to Meta to log into your WhatsApp Business account. Having admin access will help make the setup smooth and easy.",
|
||||
"TITLE": "Quick Setup with Meta",
|
||||
"DESC": "You will be redirected to Meta to log into your WhatsApp Business account. Having admin access will help make the setup smooth and easy.",
|
||||
"BENEFITS": {
|
||||
"TITLE": "Benefits of Embedded Signup:",
|
||||
"EASY_SETUP": "No manual configuration required",
|
||||
@@ -281,8 +281,9 @@
|
||||
"AUTO_CONFIG": "Automatic webhook and phone number configuration"
|
||||
},
|
||||
"LEARN_MORE": {
|
||||
"TEXT": "To learn more about integrated signup, pricing, and limitations, visit {link}.",
|
||||
"LINK_TEXT": "this link"
|
||||
"TEXT": "To learn more about integrated signup, pricing, and limitations, visit",
|
||||
"LINK_TEXT": "this link.",
|
||||
"LINK_URL": "https://developers.facebook.com/docs/whatsapp/embedded-signup/custom-flows/onboarding-business-app-users#limitations"
|
||||
},
|
||||
"SUBMIT_BUTTON": "Connect with WhatsApp Business",
|
||||
"AUTH_PROCESSING": "Authenticating with Meta",
|
||||
@@ -295,9 +296,7 @@
|
||||
"INVALID_BUSINESS_DATA": "Invalid business data received from Facebook. Please try again.",
|
||||
"SIGNUP_ERROR": "Signup error occurred",
|
||||
"AUTH_NOT_COMPLETED": "Authentication not completed. Please restart the process.",
|
||||
"SUCCESS_FALLBACK": "WhatsApp Business Account has been successfully configured",
|
||||
"MANUAL_FALLBACK": "If your number is already connected to the WhatsApp Business Platform (API), or if you’re a tech provider onboarding your own number, please use the {link} flow",
|
||||
"MANUAL_LINK_TEXT": "manual setup flow"
|
||||
"SUCCESS_FALLBACK": "WhatsApp Business Account has been successfully configured"
|
||||
},
|
||||
"API": {
|
||||
"ERROR_MESSAGE": "We were not able to save the WhatsApp channel"
|
||||
|
||||
@@ -36,7 +36,6 @@ import sla from './sla.json';
|
||||
import teamsSettings from './teamsSettings.json';
|
||||
import whatsappTemplates from './whatsappTemplates.json';
|
||||
import contentTemplates from './contentTemplates.json';
|
||||
import mfa from './mfa.json';
|
||||
|
||||
export default {
|
||||
...advancedFilters,
|
||||
@@ -77,5 +76,4 @@ export default {
|
||||
...teamsSettings,
|
||||
...whatsappTemplates,
|
||||
...contentTemplates,
|
||||
...mfa,
|
||||
};
|
||||
|
||||
@@ -759,7 +759,6 @@
|
||||
"SELECTED": "{count} selected",
|
||||
"SELECT_ALL": "Select all ({count})",
|
||||
"UNSELECT_ALL": "Unselect all ({count})",
|
||||
"SEARCH_PLACEHOLDER": "Search FAQs...",
|
||||
"BULK_APPROVE_BUTTON": "Approve",
|
||||
"BULK_DELETE_BUTTON": "Delete",
|
||||
"BULK_APPROVE": {
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
{
|
||||
"MFA_SETTINGS": {
|
||||
"TITLE": "Two-Factor Authentication",
|
||||
"SUBTITLE": "Secure your account with TOTP-based authentication",
|
||||
"DESCRIPTION": "Add an extra layer of security to your account using a time-based one-time password (TOTP)",
|
||||
"STATUS_TITLE": "Authentication Status",
|
||||
"STATUS_DESCRIPTION": "Manage your two-factor authentication settings and backup recovery codes",
|
||||
"ENABLED": "Enabled",
|
||||
"DISABLED": "Disabled",
|
||||
"STATUS_ENABLED": "Two-factor authentication is active",
|
||||
"STATUS_ENABLED_DESC": "Your account is protected with an additional layer of security",
|
||||
"ENABLE_BUTTON": "Enable Two-Factor Authentication",
|
||||
"ENHANCE_SECURITY": "Enhance Your Account Security",
|
||||
"ENHANCE_SECURITY_DESC": "Two-factor authentication adds an extra layer of security by requiring a verification code from your authenticator app in addition to your password.",
|
||||
"SETUP": {
|
||||
"STEP_NUMBER_1": "1",
|
||||
"STEP_NUMBER_2": "2",
|
||||
"STEP1_TITLE": "Scan QR Code with Your Authenticator App",
|
||||
"STEP1_DESCRIPTION": "Use Google Authenticator, Authy, or any TOTP-compatible app",
|
||||
"LOADING_QR": "Loading...",
|
||||
"MANUAL_ENTRY": "Can't scan? Enter code manually",
|
||||
"SECRET_KEY": "Secret Key",
|
||||
"COPY": "Copy",
|
||||
"ENTER_CODE": "Enter the 6-digit code from your authenticator app",
|
||||
"ENTER_CODE_PLACEHOLDER": "000000",
|
||||
"VERIFY_BUTTON": "Verify & Continue",
|
||||
"CANCEL": "Cancel",
|
||||
"ERROR_STARTING": "MFA not enabled. Please contact administrator.",
|
||||
"INVALID_CODE": "Invalid verification code",
|
||||
"SECRET_COPIED": "Secret key copied to clipboard",
|
||||
"SUCCESS": "Two-factor authentication has been enabled successfully"
|
||||
},
|
||||
"BACKUP": {
|
||||
"TITLE": "Save Your Backup Codes",
|
||||
"DESCRIPTION": "Keep these codes safe. Each can be used once if you lose access to your authenticator",
|
||||
"IMPORTANT": "Important:",
|
||||
"IMPORTANT_NOTE": " Save these codes in a secure location. You won't be able to see them again.",
|
||||
"DOWNLOAD": "Download",
|
||||
"COPY_ALL": "Copy All",
|
||||
"CONFIRM": "I have saved my backup codes in a secure location and understand that I won't be able to see them again",
|
||||
"COMPLETE_SETUP": "Complete Setup",
|
||||
"CODES_COPIED": "Backup codes copied to clipboard"
|
||||
},
|
||||
"MANAGEMENT": {
|
||||
"BACKUP_CODES": "Backup Codes",
|
||||
"BACKUP_CODES_DESC": "Generate new codes if you've lost or used your existing ones",
|
||||
"REGENERATE": "Regenerate Backup Codes",
|
||||
"DISABLE_MFA": "Disable 2FA",
|
||||
"DISABLE_MFA_DESC": "Remove two-factor authentication from your account",
|
||||
"DISABLE_BUTTON": "Disable Two-Factor Authentication"
|
||||
},
|
||||
"DISABLE": {
|
||||
"TITLE": "Disable Two-Factor Authentication",
|
||||
"DESCRIPTION": "You'll need to enter your password and a verification code to disable two-factor authentication.",
|
||||
"PASSWORD": "Password",
|
||||
"OTP_CODE": "Verification Code",
|
||||
"OTP_CODE_PLACEHOLDER": "000000",
|
||||
"CONFIRM": "Disable 2FA",
|
||||
"CANCEL": "Cancel",
|
||||
"SUCCESS": "Two-factor authentication has been disabled",
|
||||
"ERROR": "Failed to disable MFA. Please check your credentials."
|
||||
},
|
||||
"REGENERATE": {
|
||||
"TITLE": "Regenerate Backup Codes",
|
||||
"DESCRIPTION": "This will invalidate your existing backup codes and generate new ones. Enter your verification code to continue.",
|
||||
"OTP_CODE": "Verification Code",
|
||||
"OTP_CODE_PLACEHOLDER": "000000",
|
||||
"CONFIRM": "Generate New Codes",
|
||||
"CANCEL": "Cancel",
|
||||
"NEW_CODES_TITLE": "New Backup Codes Generated",
|
||||
"NEW_CODES_DESC": "Your old backup codes have been invalidated. Save these new codes in a secure location.",
|
||||
"CODES_IMPORTANT": "Important:",
|
||||
"CODES_IMPORTANT_NOTE": " Each code can only be used once. Save them before closing this window.",
|
||||
"DOWNLOAD_CODES": "Download Codes",
|
||||
"COPY_ALL_CODES": "Copy All Codes",
|
||||
"CODES_SAVED": "I've Saved My Codes",
|
||||
"SUCCESS": "New backup codes have been generated",
|
||||
"ERROR": "Failed to regenerate backup codes"
|
||||
}
|
||||
},
|
||||
"MFA_VERIFICATION": {
|
||||
"TITLE": "Two-Factor Authentication",
|
||||
"DESCRIPTION": "Enter your verification code to continue",
|
||||
"AUTHENTICATOR_APP": "Authenticator App",
|
||||
"BACKUP_CODE": "Backup Code",
|
||||
"ENTER_OTP_CODE": "Enter 6-digit code from your authenticator app",
|
||||
"ENTER_BACKUP_CODE": "Enter one of your backup codes",
|
||||
"BACKUP_CODE_PLACEHOLDER": "000000",
|
||||
"VERIFY_BUTTON": "Verify",
|
||||
"TRY_ANOTHER_METHOD": "Try another verification method",
|
||||
"CANCEL_LOGIN": "Cancel and return to login",
|
||||
"HELP_TEXT": "Having trouble signing in?",
|
||||
"LEARN_MORE": "Learn more about 2FA",
|
||||
"HELP_MODAL": {
|
||||
"TITLE": "Two-Factor Authentication Help",
|
||||
"AUTHENTICATOR_TITLE": "Using an Authenticator App",
|
||||
"AUTHENTICATOR_DESC": "Open your authenticator app (Google Authenticator, Authy, etc.) and enter the 6-digit code shown for your account.",
|
||||
"BACKUP_TITLE": "Using a Backup Code",
|
||||
"BACKUP_DESC": "If you don't have access to your authenticator app, you can use one of the backup codes you saved when setting up 2FA. Each code can only be used once.",
|
||||
"CONTACT_TITLE": "Need More Help?",
|
||||
"CONTACT_DESC_CLOUD": "If you've lost access to both your authenticator app and backup codes, please reach out to Chatwoot support for assistance.",
|
||||
"CONTACT_DESC_SELF_HOSTED": "If you've lost access to both your authenticator app and backup codes, please contact your administrator for assistance."
|
||||
},
|
||||
"VERIFICATION_FAILED": "Verification failed. Please try again."
|
||||
}
|
||||
}
|
||||
@@ -80,11 +80,6 @@
|
||||
"NOTE": "Updating your password would reset your logins in multiple devices.",
|
||||
"BTN_TEXT": "Change password"
|
||||
},
|
||||
"SECURITY_SECTION": {
|
||||
"TITLE": "Security",
|
||||
"NOTE": "Manage additional security features for your account.",
|
||||
"MFA_BUTTON": "Manage Two-Factor Authentication"
|
||||
},
|
||||
"ACCESS_TOKEN": {
|
||||
"TITLE": "Access Token",
|
||||
"NOTE": "This token can be used if you are building an API based integration",
|
||||
@@ -363,8 +358,7 @@
|
||||
"INFO_TEXT": "Let the system automatically mark you offline when you aren't using the app or dashboard.",
|
||||
"INFO_SHORT": "Automatically mark offline when you aren't using the app."
|
||||
},
|
||||
"DOCS": "Read docs",
|
||||
"SECURITY": "Security"
|
||||
"DOCS": "Read docs"
|
||||
},
|
||||
"BILLING_SETTINGS": {
|
||||
"TITLE": "Billing",
|
||||
@@ -396,77 +390,6 @@
|
||||
},
|
||||
"NO_BILLING_USER": "Your billing account is being configured. Please refresh the page and try again."
|
||||
},
|
||||
"SECURITY_SETTINGS": {
|
||||
"TITLE": "Security",
|
||||
"DESCRIPTION": "Manage your account security settings.",
|
||||
"LINK_TEXT": "Learn more about SAML SSO",
|
||||
"SAML": {
|
||||
"TITLE": "SAML SSO",
|
||||
"NOTE": "Configure SAML single sign-on for your account. Users will authenticate through your identity provider instead of using email/password.",
|
||||
"ACS_URL": {
|
||||
"LABEL": "ACS URL",
|
||||
"TOOLTIP": "Assertion Consumer Service URL - Configure this URL in your IdP as the destination for SAML responses"
|
||||
},
|
||||
"SSO_URL": {
|
||||
"LABEL": "SSO URL",
|
||||
"HELP": "The URL where SAML authentication requests will be sent",
|
||||
"PLACEHOLDER": "https://your-idp.com/saml/sso"
|
||||
},
|
||||
"CERTIFICATE": {
|
||||
"LABEL": "Signing certificate in PEM format",
|
||||
"HELP": "The public certificate from your identity provider used to verify SAML responses",
|
||||
"PLACEHOLDER": "-----BEGIN CERTIFICATE-----\nMIIC..."
|
||||
},
|
||||
"FINGERPRINT": {
|
||||
"LABEL": "Fingerprint",
|
||||
"TOOLTIP": "SHA-1 fingerprint of the certificate - Use this to verify the certificate in your IdP configuration"
|
||||
},
|
||||
"COPY_SUCCESS": "Copied to clipboard",
|
||||
"SP_ENTITY_ID": {
|
||||
"LABEL": "SP Entity ID",
|
||||
"HELP": "Unique identifier for this application as a service provider (auto-generated).",
|
||||
"TOOLTIP": "Unique identifier for Chatwoot as the Service Provider - Configure this in your IdP settings"
|
||||
},
|
||||
"IDP_ENTITY_ID": {
|
||||
"LABEL": "Identity Provider Entity ID",
|
||||
"HELP": "Unique identifier for your identity provider (usually found in IdP configuration)",
|
||||
"PLACEHOLDER": "https://your-idp.com/saml"
|
||||
},
|
||||
"UPDATE_BUTTON": "Update SAML Settings",
|
||||
"API": {
|
||||
"SUCCESS": "SAML settings updated successfully",
|
||||
"ERROR": "Failed to update SAML settings",
|
||||
"ERROR_LOADING": "Failed to load SAML settings",
|
||||
"DISABLED": "SAML settings disabled successfully"
|
||||
},
|
||||
"VALIDATION": {
|
||||
"REQUIRED_FIELDS": "SSO URL, Identity Provider Entity ID, and Certificate are required fields",
|
||||
"SSO_URL_ERROR": "Please enter a valid SSO URL",
|
||||
"CERTIFICATE_ERROR": "Certificate is required",
|
||||
"IDP_ENTITY_ID_ERROR": "Identity Provider Entity ID is required"
|
||||
},
|
||||
"ENTERPRISE_PAYWALL": {
|
||||
"AVAILABLE_ON": "The SAML SSO feature is only available in the Enterprise plans.",
|
||||
"UPGRADE_PROMPT": "Upgrade to an Enterprise plan to access SAML single sign-on and other advanced security features.",
|
||||
"ASK_ADMIN": "Please reach out to your administrator for the upgrade."
|
||||
},
|
||||
"PAYWALL": {
|
||||
"TITLE": "Upgrade to enable SAML SSO",
|
||||
"AVAILABLE_ON": "The SAML SSO feature is only available in the Enterprise plans.",
|
||||
"UPGRADE_PROMPT": "Upgrade your plan to get access to SAML single sign-on and other advanced features.",
|
||||
"UPGRADE_NOW": "Upgrade now",
|
||||
"CANCEL_ANYTIME": "You can change or cancel your plan anytime"
|
||||
},
|
||||
"ATTRIBUTE_MAPPING": {
|
||||
"TITLE": "SAML Attribute Setup",
|
||||
"DESCRIPTION": "The following attribute mappings must be configured in your identity provider"
|
||||
},
|
||||
"INFO_SECTION": {
|
||||
"TITLE": "Service Provider Information",
|
||||
"TOOLTIP": "Copy these values and configure them in your Identity Provider to establish the SAML connection"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CREATE_ACCOUNT": {
|
||||
"NO_ACCOUNT_WARNING": "Uh oh! We could not find any Chatwoot accounts. Please create a new account to continue.",
|
||||
"NEW_ACCOUNT": "New Account",
|
||||
@@ -528,230 +451,6 @@
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "Priority",
|
||||
"ACTIVE": "Active",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "Edit"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Description:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "Status:",
|
||||
"PLACEHOLDER": "Select status",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "Add"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "Edit"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Description:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "Add"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "Delete",
|
||||
"CANCEL_BUTTON_LABEL": "Cancel"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
"BUTTON_LABEL": "Button {index}",
|
||||
"COUPON_CODE": "Enter coupon code (max 15 chars)",
|
||||
"MEDIA_URL_LABEL": "Enter {type} URL",
|
||||
"DOCUMENT_NAME_PLACEHOLDER": "Enter document filename (e.g., Invoice_2025.pdf)",
|
||||
"BUTTON_PARAMETER": "Enter button parameter"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
"NEW_CAMPAIGN": "Crear campaña",
|
||||
"EMPTY_STATE": {
|
||||
"TITLE": "No WhatsApp campaigns are available",
|
||||
"SUBTITLE": "Lanza una campaña de WhatsApp para conectar con tus clientes directamente. Envía ofertas o has anuncios fácilmente. Haz clic en 'Crear campaña' para comenzar."
|
||||
"SUBTITLE": "Launch a WhatsApp campaign to reach your customers directly. Send offers or make announcements with ease. Click 'Create campaign' to get started."
|
||||
},
|
||||
"CARD": {
|
||||
"STATUS": {
|
||||
@@ -155,7 +155,7 @@
|
||||
}
|
||||
},
|
||||
"CREATE": {
|
||||
"TITLE": "Crear campaña de WhatsApp",
|
||||
"TITLE": "Create WhatsApp campaign",
|
||||
"CANCEL_BUTTON_TEXT": "Cancelar",
|
||||
"CREATE_BUTTON_TEXT": "Crear",
|
||||
"FORM": {
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"SEND_MESSAGE_LABEL": "Enviar mensaje",
|
||||
"FORM_ERROR_MESSAGE": "Por favor, rellene todas las variables antes de enviar",
|
||||
"MEDIA_HEADER_LABEL": "{type} Header",
|
||||
"MEDIA_URL_LABEL": "Ingrese la URL completa",
|
||||
"MEDIA_URL_LABEL": "Enter full media URL",
|
||||
"MEDIA_URL_PLACEHOLDER": "https://example.com/image.jpg"
|
||||
},
|
||||
"FORM": {
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "Mostrar etiquetas",
|
||||
"HIDE_LABELS": "Ocultar etiquetas"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Resolver",
|
||||
"REOPEN_ACTION": "Reabrir",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -233,7 +226,7 @@
|
||||
"APPEARANCE": "Cambiar apariencia",
|
||||
"SUPER_ADMIN_CONSOLE": "Consola SuperAdmin",
|
||||
"DOCS": "Leer la documentación",
|
||||
"CHANGELOG": "Notas de versión",
|
||||
"CHANGELOG": "Changelog",
|
||||
"LOGOUT": "Cerrar sesión"
|
||||
},
|
||||
"APP_GLOBAL": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "Etiquetas",
|
||||
"REPORTS_INBOX": "Bandeja de entrada",
|
||||
"REPORTS_TEAM": "Equipo",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "Ponte como",
|
||||
"SET_YOUR_AVAILABILITY": "Establecer su disponibilidad",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "Cambiar a respuesta",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Cambiar el menú desplegable"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "Prioridad",
|
||||
"ACTIVE": "Activo",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "Editar"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Cancelar"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Descripción:",
|
||||
"PLACEHOLDER": "Introducir descripción"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "Estado:",
|
||||
"PLACEHOLDER": "Seleccionar estado",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "Añadir"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "Editar"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "Cancelar"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "Descripción:",
|
||||
"PLACEHOLDER": "Introducir descripción"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "Añadir"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "Eliminar",
|
||||
"CANCEL_BUTTON_LABEL": "Cancelar"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"IP_ADDRESS": "آدرس آیپی",
|
||||
"CREATED_AT_LABEL": "ایجاد شده",
|
||||
"NEW_MESSAGE": "پیام جدید",
|
||||
"CALL": "تماس",
|
||||
"CALL": "Call",
|
||||
"CALL_UNDER_DEVELOPMENT": "Calling is under development",
|
||||
"VOICE_INBOX_PICKER": {
|
||||
"TITLE": "Choose a voice inbox"
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "مشاهده کردن برچسبها",
|
||||
"HIDE_LABELS": "پنهان کردن برچسبها"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "حل شد",
|
||||
"REOPEN_ACTION": "دوباره باز کنید",
|
||||
|
||||
@@ -51,13 +51,6 @@
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
},
|
||||
"LANGUAGE": {
|
||||
"TITLE": "Preferred Language",
|
||||
"NOTE": "Choose the language you want to use.",
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -337,7 +330,6 @@
|
||||
"REPORTS_LABEL": "برچسبها",
|
||||
"REPORTS_INBOX": "صندوق ورودی",
|
||||
"REPORTS_TEAM": "تیم",
|
||||
"AGENT_ASSIGNMENT": "Agent Assignment",
|
||||
"SET_AVAILABILITY_TITLE": "خود را به عنوان",
|
||||
"SET_YOUR_AVAILABILITY": "در دسترس بودن خود را تنظیم کنید",
|
||||
"SLA": "SLA",
|
||||
@@ -426,255 +418,5 @@
|
||||
"SWITCH_TO_REPLY": "رفتن به پاسخ",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "تغییر حالت بازکردن تعویق"
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent assignment",
|
||||
"DESCRIPTION": "Define policies to effectively manage workload and route conversations based on the needs of inboxes and agents. Learn more here"
|
||||
},
|
||||
"ASSIGNMENT_POLICY": {
|
||||
"TITLE": "Assignment policy",
|
||||
"DESCRIPTION": "Manage how conversations get assigned in inboxes.",
|
||||
"FEATURES": [
|
||||
"Assign by conversations evenly or by available capacity",
|
||||
"Add fair distribution rules to avoid overloading any agent",
|
||||
"Add inboxes to a policy - one policy per inbox"
|
||||
]
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"TITLE": "Agent capacity policy",
|
||||
"DESCRIPTION": "Manage workload for agents.",
|
||||
"FEATURES": [
|
||||
"Define maximum conversations per inbox",
|
||||
"Create exceptions based on labels and time",
|
||||
"Add agents to a policy - one policy per agent"
|
||||
]
|
||||
}
|
||||
},
|
||||
"AGENT_ASSIGNMENT_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Assignment policy",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"ORDER": "Order",
|
||||
"PRIORITY": "اولویت",
|
||||
"ACTIVE": "فعال",
|
||||
"INACTIVE": "Inactive",
|
||||
"POPOVER": "Added inboxes",
|
||||
"EDIT": "ویرایش"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No assignment policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create assignment policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create assignment policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit assignment policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_INBOX_DIALOG": {
|
||||
"TITLE": "Add inbox",
|
||||
"DESCRIPTION": "{inboxName} inbox is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "انصراف"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update assignment policy"
|
||||
},
|
||||
"INBOX_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Inbox added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Inbox removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove inbox from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "توضیحات:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"STATUS": {
|
||||
"LABEL": "وضعیت:",
|
||||
"PLACEHOLDER": "Select status",
|
||||
"ACTIVE": "Policy is active",
|
||||
"INACTIVE": "Policy is inactive"
|
||||
},
|
||||
"ASSIGNMENT_ORDER": {
|
||||
"LABEL": "Assignment order",
|
||||
"ROUND_ROBIN": {
|
||||
"LABEL": "Round robin",
|
||||
"DESCRIPTION": "Assign conversations evenly among agents."
|
||||
},
|
||||
"BALANCED": {
|
||||
"LABEL": "Balanced",
|
||||
"DESCRIPTION": "Assign conversations based on available capacity."
|
||||
}
|
||||
},
|
||||
"ASSIGNMENT_PRIORITY": {
|
||||
"LABEL": "Assignment priority",
|
||||
"EARLIEST_CREATED": {
|
||||
"LABEL": "Earliest created",
|
||||
"DESCRIPTION": "The conversation that was created first gets assigned first."
|
||||
},
|
||||
"LONGEST_WAITING": {
|
||||
"LABEL": "Longest waiting",
|
||||
"DESCRIPTION": "The conversation waiting the longest gets assigned first."
|
||||
}
|
||||
},
|
||||
"FAIR_DISTRIBUTION": {
|
||||
"LABEL": "Fair distribution policy",
|
||||
"DESCRIPTION": "Set the maximum number of conversations that can be assigned per agent within a time window to avoid overloading any one agent. This required field defaults to 100 conversations per hour.",
|
||||
"INPUT_MAX": "Assign max",
|
||||
"DURATION": "Conversations per agent in every"
|
||||
},
|
||||
"INBOXES": {
|
||||
"LABEL": "Added inboxes",
|
||||
"DESCRIPTION": "Add inboxes for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select inboxes to add",
|
||||
"ADD_BUTTON": "افزودن"
|
||||
},
|
||||
"EMPTY_STATE": "No inboxes added to this policy, add an inbox to get started",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Inbox successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add inbox to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Assignment policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete assignment policy"
|
||||
}
|
||||
},
|
||||
"AGENT_CAPACITY_POLICY": {
|
||||
"INDEX": {
|
||||
"HEADER": {
|
||||
"TITLE": "Agent capacity",
|
||||
"CREATE_POLICY": "New policy"
|
||||
},
|
||||
"CARD": {
|
||||
"POPOVER": "Added agents",
|
||||
"EDIT": "ویرایش"
|
||||
},
|
||||
"NO_RECORDS_FOUND": "No agent capacity policies found"
|
||||
},
|
||||
"CREATE": {
|
||||
"HEADER": {
|
||||
"TITLE": "Create agent capacity policy"
|
||||
},
|
||||
"CREATE_BUTTON": "Create policy",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy created successfully",
|
||||
"ERROR_MESSAGE": "Failed to create agent capacity policy"
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
"HEADER": {
|
||||
"TITLE": "Edit agent capacity policy"
|
||||
},
|
||||
"EDIT_BUTTON": "Update policy",
|
||||
"CONFIRM_ADD_AGENT_DIALOG": {
|
||||
"TITLE": "Add agent",
|
||||
"DESCRIPTION": "{agentName} is already linked to another policy. Are you sure you want to link it to this policy? It will be unlinked from the other policy.",
|
||||
"CONFIRM_BUTTON_LABEL": "Continue",
|
||||
"CANCEL_BUTTON_LABEL": "انصراف"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy updated successfully",
|
||||
"ERROR_MESSAGE": "Failed to update agent capacity policy"
|
||||
},
|
||||
"AGENT_API": {
|
||||
"ADD": {
|
||||
"SUCCESS_MESSAGE": "Agent added to policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
},
|
||||
"REMOVE": {
|
||||
"SUCCESS_MESSAGE": "Agent removed from policy successfully",
|
||||
"ERROR_MESSAGE": "Failed to remove agent from policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": {
|
||||
"LABEL": "Policy name:",
|
||||
"PLACEHOLDER": "Enter policy name"
|
||||
},
|
||||
"DESCRIPTION": {
|
||||
"LABEL": "توضیحات:",
|
||||
"PLACEHOLDER": "Enter description"
|
||||
},
|
||||
"INBOX_CAPACITY_LIMIT": {
|
||||
"LABEL": "Inbox capacity limits",
|
||||
"ADD_BUTTON": "Add inbox",
|
||||
"FIELD": {
|
||||
"SELECT_INBOX": "Select inbox",
|
||||
"MAX_CONVERSATIONS": "Max conversations",
|
||||
"SET_LIMIT": "Set limit"
|
||||
},
|
||||
"EMPTY_STATE": "No inbox limit set"
|
||||
},
|
||||
"EXCLUSION_RULES": {
|
||||
"LABEL": "Exclusion rules",
|
||||
"DESCRIPTION": "Conversations that satisfy the following conditions would not count towards agent capacity",
|
||||
"TAGS": {
|
||||
"LABEL": "Exclude conversations tagged with specific labels",
|
||||
"ADD_TAG": "add tag",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select tags to add"
|
||||
},
|
||||
"EMPTY_STATE": "No tags added to this policy."
|
||||
},
|
||||
"DURATION": {
|
||||
"LABEL": "Exclude conversations older than a specified duration",
|
||||
"PLACEHOLDER": "Set time"
|
||||
}
|
||||
},
|
||||
"USERS": {
|
||||
"LABEL": "Assigned agents",
|
||||
"DESCRIPTION": "Add agents for which this policy will be applicable.",
|
||||
"ADD_BUTTON": "Add agent",
|
||||
"DROPDOWN": {
|
||||
"SEARCH_PLACEHOLDER": "Search and select agents to add",
|
||||
"ADD_BUTTON": "افزودن"
|
||||
},
|
||||
"EMPTY_STATE": "No agents added",
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Agent successfully added to policy",
|
||||
"ERROR_MESSAGE": "Failed to add agent to policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"SUCCESS_MESSAGE": "Agent capacity policy deleted successfully",
|
||||
"ERROR_MESSAGE": "Failed to delete agent capacity policy"
|
||||
}
|
||||
},
|
||||
"DELETE_POLICY": {
|
||||
"TITLE": "Delete policy",
|
||||
"DESCRIPTION": "Are you sure you want to delete this policy? This action cannot be undone.",
|
||||
"CONFIRM_BUTTON_LABEL": "حذف",
|
||||
"CANCEL_BUTTON_LABEL": "انصراف"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +71,6 @@
|
||||
"SHOW_LABELS": "Show labels",
|
||||
"HIDE_LABELS": "Hide labels"
|
||||
},
|
||||
"VOICE_CALL": {
|
||||
"INCOMING_CALL": "Incoming call",
|
||||
"OUTGOING_CALL": "Outgoing call",
|
||||
"CALL_IN_PROGRESS": "Call in progress",
|
||||
"NO_ANSWER": "No answer",
|
||||
"MISSED_CALL": "Missed call",
|
||||
"CALL_ENDED": "Call ended",
|
||||
"NOT_ANSWERED_YET": "Not answered yet",
|
||||
"THEY_ANSWERED": "They answered",
|
||||
"YOU_ANSWERED": "You answered"
|
||||
},
|
||||
"HEADER": {
|
||||
"RESOLVE_ACTION": "Ratkaise",
|
||||
"REOPEN_ACTION": "Uudelleenavaa",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user