Compare commits
29
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6f6263f3c | ||
|
|
5f03418ac9 | ||
|
|
11370316b2 | ||
|
|
9a09df4563 | ||
|
|
364dbdd69f | ||
|
|
f1832148fd | ||
|
|
8f9c45ea8c | ||
|
|
24c7171a4e | ||
|
|
b5f3daafc9 | ||
|
|
2c204326e5 | ||
|
|
a33ae58452 | ||
|
|
a96e75b904 | ||
|
|
5bb88192c4 | ||
|
|
6475a6a593 | ||
|
|
441cc065ae | ||
|
|
0b74be82a3 | ||
|
|
cbc2807296 | ||
|
|
c09e875c83 | ||
|
|
87313ecc35 | ||
|
|
8262123481 | ||
|
|
420be64c45 | ||
|
|
9acb0d86b5 | ||
|
|
2a5ecf84a1 | ||
|
|
286e3a449d | ||
|
|
e5ee6027b4 | ||
|
|
eb412b67bd | ||
|
|
6fb762f96c | ||
|
|
ab1ba1c4c7 | ||
|
|
d276025419 |
@@ -121,6 +121,8 @@ gem 'sentry-sidekiq', '>= 5.19.0', require: false
|
||||
gem 'sidekiq', '>= 7.3.1'
|
||||
# We want cron jobs
|
||||
gem 'sidekiq-cron', '>= 1.12.0'
|
||||
# for sidekiq healthcheck
|
||||
gem 'sidekiq_alive'
|
||||
|
||||
##-- Push notification service --##
|
||||
gem 'fcm'
|
||||
|
||||
+11
-6
@@ -359,6 +359,7 @@ GEM
|
||||
grpc (1.72.0-x86_64-linux)
|
||||
google-protobuf (>= 3.25, < 5.0)
|
||||
googleapis-common-protos-types (~> 1.0)
|
||||
gserver (0.0.1)
|
||||
haikunator (1.1.1)
|
||||
hairtrigger (1.0.0)
|
||||
activerecord (>= 6.0, < 8)
|
||||
@@ -477,7 +478,7 @@ GEM
|
||||
mime-types-data (3.2023.0218.1)
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.8)
|
||||
mini_portile2 (2.8.9)
|
||||
minitest (5.25.5)
|
||||
mock_redis (0.36.0)
|
||||
ruby2_keywords
|
||||
@@ -508,14 +509,14 @@ GEM
|
||||
newrelic_rpm (9.6.0)
|
||||
base64
|
||||
nio4r (2.7.3)
|
||||
nokogiri (1.18.8)
|
||||
nokogiri (1.18.9)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.8-arm64-darwin)
|
||||
nokogiri (1.18.9-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.8-x86_64-darwin)
|
||||
nokogiri (1.18.9-x86_64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.8-x86_64-linux-gnu)
|
||||
nokogiri (1.18.9-x86_64-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
oauth (1.1.0)
|
||||
oauth-tty (~> 1.0, >= 1.0.1)
|
||||
@@ -785,6 +786,9 @@ GEM
|
||||
fugit (~> 1.8)
|
||||
globalid (>= 1.0.1)
|
||||
sidekiq (>= 6)
|
||||
sidekiq_alive (2.5.0)
|
||||
gserver (~> 0.0.1)
|
||||
sidekiq (>= 5, < 9)
|
||||
signet (0.17.0)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.5, < 3.a)
|
||||
@@ -823,7 +827,7 @@ GEM
|
||||
stripe (8.5.0)
|
||||
telephone_number (1.4.20)
|
||||
test-prof (1.2.1)
|
||||
thor (1.3.1)
|
||||
thor (1.4.0)
|
||||
tilt (2.3.0)
|
||||
time_diff (0.3.0)
|
||||
activesupport
|
||||
@@ -1010,6 +1014,7 @@ DEPENDENCIES
|
||||
shoulda-matchers
|
||||
sidekiq (>= 7.3.1)
|
||||
sidekiq-cron (>= 1.12.0)
|
||||
sidekiq_alive
|
||||
simplecov (= 0.17.1)
|
||||
slack-ruby-client (~> 2.5.2)
|
||||
spring
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
# We don't want to update the name of the identified original contact.
|
||||
|
||||
class ContactIdentifyAction
|
||||
include UrlHelper
|
||||
pattr_initialize [:contact!, :params!, { retain_original_contact_name: false, discard_invalid_attrs: false }]
|
||||
|
||||
def perform
|
||||
@@ -104,7 +105,14 @@ class ContactIdentifyAction
|
||||
# TODO: replace reject { |_k, v| v.blank? } with compact_blank when rails is upgraded
|
||||
@contact.discard_invalid_attrs if discard_invalid_attrs
|
||||
@contact.save!
|
||||
Avatar::AvatarFromUrlJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present? && !@contact.avatar.attached?
|
||||
enqueue_avatar_job
|
||||
end
|
||||
|
||||
def enqueue_avatar_job
|
||||
return unless params[:avatar_url].present? && !@contact.avatar.attached?
|
||||
return unless url_valid?(params[:avatar_url])
|
||||
|
||||
Avatar::AvatarFromUrlJob.perform_later(@contact, params[:avatar_url])
|
||||
end
|
||||
|
||||
def merge_contact(base_contact, merge_contact)
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Accounts::AgentCapacityPoliciesController < Api::V1::Accounts::BaseController
|
||||
before_action :ensure_enterprise_account
|
||||
before_action :fetch_agent_capacity_policy, only: [:show, :update, :destroy, :set_inbox_limit, :remove_inbox_limit, :assign_user, :remove_user]
|
||||
before_action :check_authorization
|
||||
|
||||
def index
|
||||
@agent_capacity_policies = Enterprise::AgentCapacityPolicy.where(account_id: Current.account.id).includes(:users, :inbox_capacity_limits)
|
||||
render json: { agent_capacity_policies: serialize_agent_capacity_policies(@agent_capacity_policies) }
|
||||
end
|
||||
|
||||
def show
|
||||
render json: { agent_capacity_policy: serialize_agent_capacity_policy(@agent_capacity_policy) }
|
||||
end
|
||||
|
||||
def create
|
||||
@agent_capacity_policy = Enterprise::AgentCapacityPolicy.new(agent_capacity_policy_params)
|
||||
@agent_capacity_policy.account_id = Current.account.id
|
||||
|
||||
if @agent_capacity_policy.save
|
||||
render json: { agent_capacity_policy: serialize_agent_capacity_policy(@agent_capacity_policy) }, status: :created
|
||||
else
|
||||
render json: { errors: @agent_capacity_policy.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @agent_capacity_policy.update(agent_capacity_policy_params)
|
||||
render json: { agent_capacity_policy: serialize_agent_capacity_policy(@agent_capacity_policy) }
|
||||
else
|
||||
render json: { errors: @agent_capacity_policy.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @agent_capacity_policy.destroy
|
||||
head :ok
|
||||
else
|
||||
render json: { errors: @agent_capacity_policy.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
# Set inbox capacity limit for a policy
|
||||
def set_inbox_limit
|
||||
inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
inbox_limit = @agent_capacity_policy.inbox_capacity_limits.find_or_initialize_by(inbox: inbox)
|
||||
|
||||
if inbox_limit.update(conversation_limit: params[:conversation_limit])
|
||||
render json: {
|
||||
inbox_capacity_limit: serialize_inbox_capacity_limit(inbox_limit)
|
||||
}
|
||||
else
|
||||
render json: { errors: inbox_limit.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
# Remove inbox capacity limit from a policy
|
||||
def remove_inbox_limit
|
||||
inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
inbox_limit = @agent_capacity_policy.inbox_capacity_limits.find_by(inbox: inbox)
|
||||
|
||||
if inbox_limit
|
||||
if inbox_limit.destroy
|
||||
head :ok
|
||||
else
|
||||
render json: { errors: inbox_limit.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
render json: { error: 'Inbox limit not found' }, status: :not_found
|
||||
end
|
||||
end
|
||||
|
||||
# Assign a user to a capacity policy
|
||||
def assign_user
|
||||
user = Current.account.users.find(params[:user_id])
|
||||
account_user = Current.account.account_users.find_by!(user: user)
|
||||
|
||||
# Update the account_user to assign to this policy
|
||||
if account_user.update(agent_capacity_policy_id: @agent_capacity_policy.id)
|
||||
render json: {
|
||||
message: 'User assigned successfully',
|
||||
user_id: user.id,
|
||||
agent_capacity_policy_id: @agent_capacity_policy.id
|
||||
}
|
||||
else
|
||||
render json: { errors: account_user.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
# Remove a user from a capacity policy
|
||||
def remove_user
|
||||
user = Current.account.users.find(params[:user_id])
|
||||
account_user = Current.account.account_users.find_by!(user: user)
|
||||
|
||||
if account_user.agent_capacity_policy_id == @agent_capacity_policy.id
|
||||
if account_user.update(agent_capacity_policy_id: nil)
|
||||
head :ok
|
||||
else
|
||||
render json: { errors: account_user.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
render json: { error: 'User not assigned to this policy' }, status: :not_found
|
||||
end
|
||||
end
|
||||
|
||||
# Get current capacity status for an agent
|
||||
def agent_capacity
|
||||
user = Current.account.users.find(params[:agent_id])
|
||||
inbox = params[:inbox_id] ? Current.account.inboxes.find(params[:inbox_id]) : nil
|
||||
|
||||
capacity_service = Enterprise::AssignmentV2::CapacityService.new
|
||||
capacity_data = if inbox
|
||||
capacity_service.get_agent_capacity(user, inbox)
|
||||
else
|
||||
capacity_service.get_agent_overall_capacity(user)
|
||||
end
|
||||
|
||||
render json: { agent_capacity: capacity_data }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_enterprise_account
|
||||
return if Current.account.feature_enabled?(:enterprise_agent_capacity)
|
||||
|
||||
render json: {
|
||||
error: 'Agent capacity policies are only available for enterprise accounts'
|
||||
}, status: :forbidden
|
||||
end
|
||||
|
||||
def fetch_agent_capacity_policy
|
||||
@agent_capacity_policy = Enterprise::AgentCapacityPolicy
|
||||
.where(account_id: Current.account.id)
|
||||
.includes(:users, inbox_capacity_limits: :inbox)
|
||||
.find(params[:id])
|
||||
end
|
||||
|
||||
def agent_capacity_policy_params
|
||||
params.require(:agent_capacity_policy).permit(:name, :description, exclusion_rules: {})
|
||||
end
|
||||
|
||||
def check_authorization
|
||||
authorize(Enterprise::AgentCapacityPolicy) if defined?(Enterprise::AgentCapacityPolicy)
|
||||
end
|
||||
|
||||
def serialize_agent_capacity_policy(policy)
|
||||
{
|
||||
id: policy.id,
|
||||
name: policy.name,
|
||||
description: policy.description,
|
||||
exclusion_rules: policy.exclusion_rules,
|
||||
user_count: policy.users.count,
|
||||
inbox_limit_count: policy.inbox_capacity_limits.count,
|
||||
inbox_limits: policy.inbox_capacity_limits.map { |limit| serialize_inbox_capacity_limit(limit) },
|
||||
users: policy.users.map { |user| { id: user.id, name: user.name, email: user.email, avatar_url: user.avatar_url } },
|
||||
created_at: policy.created_at,
|
||||
updated_at: policy.updated_at
|
||||
}
|
||||
end
|
||||
|
||||
def serialize_agent_capacity_policies(policies)
|
||||
policies.map { |policy| serialize_agent_capacity_policy(policy) }
|
||||
end
|
||||
|
||||
def serialize_inbox_capacity_limit(limit)
|
||||
{
|
||||
id: limit.id,
|
||||
inbox_id: limit.inbox_id,
|
||||
inbox_name: limit.inbox.name,
|
||||
conversation_limit: limit.conversation_limit,
|
||||
created_at: limit.created_at,
|
||||
updated_at: limit.updated_at
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,79 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Accounts::AssignmentPoliciesController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_assignment_policy, only: [:show, :update, :destroy]
|
||||
before_action :check_authorization
|
||||
|
||||
def index
|
||||
@assignment_policies = Current.account.assignment_policies.includes(:inboxes)
|
||||
render json: { assignment_policies: serialize_assignment_policies(@assignment_policies) }
|
||||
end
|
||||
|
||||
def show
|
||||
render json: { assignment_policy: serialize_assignment_policy(@assignment_policy) }
|
||||
end
|
||||
|
||||
def create
|
||||
@assignment_policy = Current.account.assignment_policies.build(assignment_policy_params)
|
||||
|
||||
if @assignment_policy.save
|
||||
render json: { assignment_policy: serialize_assignment_policy(@assignment_policy) }, status: :created
|
||||
else
|
||||
render json: { errors: @assignment_policy.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @assignment_policy.update(assignment_policy_params)
|
||||
render json: { assignment_policy: serialize_assignment_policy(@assignment_policy) }
|
||||
else
|
||||
render json: { errors: @assignment_policy.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @assignment_policy.destroy
|
||||
head :ok
|
||||
else
|
||||
render json: { errors: @assignment_policy.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_assignment_policy
|
||||
@assignment_policy = Current.account.assignment_policies.find(params[:id])
|
||||
end
|
||||
|
||||
def assignment_policy_params
|
||||
params.require(:assignment_policy).permit(
|
||||
:name, :description, :assignment_order, :conversation_priority,
|
||||
:fair_distribution_limit, :fair_distribution_window, :enabled
|
||||
)
|
||||
end
|
||||
|
||||
def serialize_assignment_policy(policy)
|
||||
{
|
||||
id: policy.id,
|
||||
name: policy.name,
|
||||
description: policy.description,
|
||||
assignment_order: policy.assignment_order,
|
||||
conversation_priority: policy.conversation_priority,
|
||||
fair_distribution_limit: policy.fair_distribution_limit,
|
||||
fair_distribution_window: policy.fair_distribution_window,
|
||||
enabled: policy.enabled,
|
||||
inbox_count: policy.inboxes.count,
|
||||
inboxes: policy.inboxes.map { |inbox| { id: inbox.id, name: inbox.name } },
|
||||
created_at: policy.created_at,
|
||||
updated_at: policy.updated_at
|
||||
}
|
||||
end
|
||||
|
||||
def serialize_assignment_policies(policies)
|
||||
policies.map { |policy| serialize_assignment_policy(policy) }
|
||||
end
|
||||
|
||||
def check_authorization
|
||||
authorize(AssignmentPolicy)
|
||||
end
|
||||
end
|
||||
@@ -122,7 +122,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
||||
def resolved_contacts
|
||||
return @resolved_contacts if @resolved_contacts
|
||||
|
||||
@resolved_contacts = Current.account.contacts.resolved_contacts
|
||||
@resolved_contacts = Current.account.contacts.resolved_contacts(use_crm_v2: Current.account.feature_enabled?('crm_v2'))
|
||||
|
||||
@resolved_contacts = @resolved_contacts.tagged_with(params[:labels], any: true) if params[:labels].present?
|
||||
@resolved_contacts
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Accounts::InboxAssignmentPoliciesController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_inbox
|
||||
before_action :check_authorization
|
||||
|
||||
def show
|
||||
@inbox_assignment_policy = @inbox.inbox_assignment_policy
|
||||
|
||||
if @inbox_assignment_policy
|
||||
render json: {
|
||||
inbox_assignment_policy: serialize_inbox_assignment_policy(@inbox_assignment_policy)
|
||||
}
|
||||
else
|
||||
render json: {
|
||||
inbox_assignment_policy: nil,
|
||||
message: 'No assignment policy assigned to this inbox'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
# Remove existing assignment if any
|
||||
@inbox.inbox_assignment_policy&.destroy
|
||||
|
||||
@assignment_policy = Current.account.assignment_policies.find(params[:assignment_policy_id])
|
||||
@inbox_assignment_policy = @inbox.build_inbox_assignment_policy(assignment_policy: @assignment_policy)
|
||||
|
||||
if @inbox_assignment_policy.save
|
||||
render json: {
|
||||
inbox_assignment_policy: serialize_inbox_assignment_policy(@inbox_assignment_policy)
|
||||
}, status: :created
|
||||
else
|
||||
render json: { errors: @inbox_assignment_policy.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@inbox_assignment_policy = @inbox.inbox_assignment_policy
|
||||
|
||||
if @inbox_assignment_policy
|
||||
if @inbox_assignment_policy.destroy
|
||||
head :ok
|
||||
else
|
||||
render json: { errors: @inbox_assignment_policy.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
else
|
||||
render json: { error: 'No assignment policy found for this inbox' }, status: :not_found
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_inbox
|
||||
@inbox = Current.account.inboxes.find(params[:inbox_id])
|
||||
end
|
||||
|
||||
def check_authorization
|
||||
authorize(@inbox, :update?)
|
||||
end
|
||||
|
||||
def serialize_inbox_assignment_policy(inbox_assignment_policy)
|
||||
{
|
||||
id: inbox_assignment_policy.id,
|
||||
inbox_id: inbox_assignment_policy.inbox_id,
|
||||
assignment_policy_id: inbox_assignment_policy.assignment_policy_id,
|
||||
assignment_policy: {
|
||||
id: inbox_assignment_policy.assignment_policy.id,
|
||||
name: inbox_assignment_policy.assignment_policy.name,
|
||||
description: inbox_assignment_policy.assignment_policy.description,
|
||||
assignment_order: inbox_assignment_policy.assignment_policy.assignment_order,
|
||||
conversation_priority: inbox_assignment_policy.assignment_policy.conversation_priority,
|
||||
fair_distribution_limit: inbox_assignment_policy.assignment_policy.fair_distribution_limit,
|
||||
fair_distribution_window: inbox_assignment_policy.assignment_policy.fair_distribution_window,
|
||||
enabled: inbox_assignment_policy.assignment_policy.enabled
|
||||
},
|
||||
created_at: inbox_assignment_policy.created_at,
|
||||
updated_at: inbox_assignment_policy.updated_at
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -69,6 +69,17 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||
render status: :ok, json: { message: I18n.t('messages.inbox_deletetion_response') }
|
||||
end
|
||||
|
||||
def sync_templates
|
||||
unless @inbox.channel.is_a?(Channel::Whatsapp)
|
||||
return render status: :unprocessable_entity, json: { error: 'Template sync is only available for WhatsApp channels' }
|
||||
end
|
||||
|
||||
Channels::Whatsapp::TemplatesSyncJob.perform_later(@inbox.channel)
|
||||
render status: :ok, json: { message: 'Template sync initiated successfully' }
|
||||
rescue StandardError => e
|
||||
render status: :internal_server_error, json: { error: e.message }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_inbox
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Accounts::LeavesController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_leave, only: [:show, :update, :destroy, :approve, :reject]
|
||||
before_action -> { check_authorization(Leave) }, only: [:index, :create]
|
||||
before_action :authorize_leave, only: [:show, :update, :destroy]
|
||||
before_action :authorize_approval, only: [:approve, :reject]
|
||||
|
||||
def index
|
||||
@leaves = leave_service.list(filter_params)
|
||||
render json: { leaves: serialize_leaves(@leaves) }
|
||||
end
|
||||
|
||||
def show
|
||||
render json: { leave: serialize_leave(@leave) }
|
||||
end
|
||||
|
||||
def create
|
||||
account_user = find_or_authorize_account_user
|
||||
service = Leaves::LeaveService.new(
|
||||
account: Current.account,
|
||||
account_user: account_user,
|
||||
current_user: Current.user
|
||||
)
|
||||
|
||||
result = service.create(leave_params)
|
||||
|
||||
if result[:success]
|
||||
render json: { leave: serialize_leave(result[:leave]) }, status: :created
|
||||
else
|
||||
render json: { errors: result[:errors] }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
result = leave_service.update(@leave, leave_params)
|
||||
|
||||
if result[:success]
|
||||
render json: { leave: serialize_leave(result[:leave]) }
|
||||
else
|
||||
render json: { errors: result[:errors] }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @leave.destroy
|
||||
head :ok
|
||||
else
|
||||
render json: { errors: @leave.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def approve
|
||||
service = Leaves::LeaveApprovalService.new(leave: @leave, approver: Current.user)
|
||||
result = service.approve(params[:comments])
|
||||
|
||||
if result[:success]
|
||||
render json: { leave: serialize_leave(result[:leave]) }
|
||||
else
|
||||
render json: { errors: result[:errors] }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def reject
|
||||
service = Leaves::LeaveApprovalService.new(leave: @leave, approver: Current.user)
|
||||
result = service.reject(params[:reason])
|
||||
|
||||
if result[:success]
|
||||
render json: { leave: serialize_leave(result[:leave]) }
|
||||
else
|
||||
render json: { errors: result[:errors] }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_leave
|
||||
@leave = Current.account.leaves.find(params[:id])
|
||||
end
|
||||
|
||||
def authorize_leave
|
||||
authorize @leave
|
||||
end
|
||||
|
||||
def authorize_approval
|
||||
authorize @leave, :approve?
|
||||
end
|
||||
|
||||
def find_or_authorize_account_user
|
||||
if params[:user_id].present? && Current.account_user.administrator?
|
||||
user = Current.account.users.find(params[:user_id])
|
||||
Current.account.account_users.find_by!(user: user)
|
||||
else
|
||||
Current.account.account_users.find_by!(user: Current.user)
|
||||
end
|
||||
end
|
||||
|
||||
def leave_service
|
||||
@leave_service ||= if @leave
|
||||
Leaves::LeaveService.new(
|
||||
account: Current.account,
|
||||
account_user: @leave.account_user,
|
||||
current_user: Current.user
|
||||
)
|
||||
else
|
||||
# For index action, we don't have a specific leave
|
||||
Leaves::LeaveService.new(
|
||||
account: Current.account,
|
||||
account_user: nil,
|
||||
current_user: Current.user
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def leave_params
|
||||
params.require(:leave).permit(:start_date, :end_date, :leave_type, :reason)
|
||||
end
|
||||
|
||||
def filter_params
|
||||
params.permit(:status, :leave_type, :start_date, :end_date, :user_id)
|
||||
end
|
||||
|
||||
def serialize_leave(leave)
|
||||
{
|
||||
id: leave.id,
|
||||
start_date: leave.start_date,
|
||||
end_date: leave.end_date,
|
||||
leave_type: leave.leave_type,
|
||||
status: leave.status,
|
||||
reason: leave.reason,
|
||||
days_count: leave.days_count,
|
||||
approved_by: leave.approved_by&.name,
|
||||
approved_at: leave.approved_at,
|
||||
user: {
|
||||
id: leave.user.id,
|
||||
name: leave.user.name,
|
||||
email: leave.user.email,
|
||||
avatar_url: leave.user.avatar_url
|
||||
},
|
||||
created_at: leave.created_at,
|
||||
updated_at: leave.updated_at
|
||||
}
|
||||
end
|
||||
|
||||
def serialize_leaves(leaves)
|
||||
leaves.map { |leave| serialize_leave(leave) }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,101 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Accounts::Reports::AssignmentMetricsController < Api::V1::Accounts::BaseController
|
||||
include AssignmentMetricsHelper
|
||||
include DistributionMetrics
|
||||
|
||||
before_action :check_authorization
|
||||
before_action :validate_date_range
|
||||
|
||||
def index
|
||||
@metrics = metrics_service.compute_assignment_metrics
|
||||
render json: { assignment_metrics: @metrics }
|
||||
end
|
||||
|
||||
def agent_history
|
||||
history_service = Reports::AgentHistoryService.new(Current.account, params)
|
||||
|
||||
if params[:agent_id].present?
|
||||
@agent = Current.account.users.find(params[:agent_id])
|
||||
@assignment_history = history_service.fetch_agent_assignment_history(@agent)
|
||||
|
||||
render json: {
|
||||
agent: serialize_agent(@agent),
|
||||
assignment_history: @assignment_history,
|
||||
meta: pagination_meta
|
||||
}
|
||||
else
|
||||
agents_summary = history_service.compute_all_agents_history
|
||||
render json: { agents_history: agents_summary }
|
||||
end
|
||||
end
|
||||
|
||||
def policy_performance
|
||||
@policies = Current.account.assignment_policies.includes(:inboxes)
|
||||
performance_data = @policies.map do |policy|
|
||||
metrics_service.compute_policy_performance(policy)
|
||||
end
|
||||
|
||||
render json: { policy_performance: performance_data }
|
||||
end
|
||||
|
||||
def agent_utilization
|
||||
agents = Current.account.users.joins(:account_users).where(account_users: { role: %w[agent administrator] })
|
||||
utilization_data = agents.map do |agent|
|
||||
metrics_service.compute_agent_utilization(agent)
|
||||
end
|
||||
|
||||
render json: { agent_utilization: utilization_data }
|
||||
end
|
||||
|
||||
def assignment_distribution
|
||||
distribution_data = {
|
||||
by_inbox: metrics_service.compute_distribution_by_inbox,
|
||||
by_team: metrics_service.compute_distribution_by_team,
|
||||
by_hour: metrics_service.compute_distribution_by_hour,
|
||||
by_day_of_week: compute_distribution_by_day_of_week
|
||||
}
|
||||
|
||||
render json: { assignment_distribution: distribution_data }
|
||||
end
|
||||
|
||||
def export
|
||||
type = params[:type] || 'csv'
|
||||
data = metrics_service.compute_assignment_metrics
|
||||
|
||||
case type
|
||||
when 'csv'
|
||||
export_service = Reports::AssignmentExportService.new(data)
|
||||
send_data export_service.generate_csv, filename: "assignment_metrics_#{Date.current}.csv", type: 'text/csv'
|
||||
when 'json'
|
||||
send_data data.to_json, filename: "assignment_metrics_#{Date.current}.json", type: 'application/json'
|
||||
else
|
||||
render json: { error: 'Unsupported export type' }, status: :bad_request
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_date_range
|
||||
return if params[:since].blank? || params[:until].blank?
|
||||
|
||||
start_date = Date.parse(params[:since])
|
||||
end_date = Date.parse(params[:until])
|
||||
|
||||
if start_date > end_date
|
||||
render json: { error: 'Start date must be before end date' }, status: :unprocessable_entity
|
||||
elsif (end_date - start_date).to_i > 365
|
||||
render json: { error: 'Date range cannot exceed 365 days' }, status: :unprocessable_entity
|
||||
end
|
||||
rescue Date::Error
|
||||
render json: { error: 'Invalid date format' }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def check_authorization
|
||||
authorize Current.account, :show_metrics?
|
||||
end
|
||||
|
||||
def metrics_service
|
||||
@metrics_service ||= Reports::AssignmentMetricsService.new(Current.account, params)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,117 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module AssignmentMetricsHelper
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
private
|
||||
|
||||
def compute_summary_metrics
|
||||
conversations = filter_conversations_by_date_range
|
||||
|
||||
{
|
||||
total_assignments: conversations.count,
|
||||
average_assignment_time: calculate_average_assignment_time(conversations),
|
||||
assignments_per_agent: calculate_assignments_per_agent(conversations),
|
||||
unassigned_conversations: Current.account.conversations.open.unassigned.count,
|
||||
policies_active: Current.account.assignment_policies.enabled.count
|
||||
}
|
||||
end
|
||||
|
||||
def compute_inbox_metrics
|
||||
inboxes = params[:inbox_id].present? ? Current.account.inboxes.where(id: params[:inbox_id]) : Current.account.inboxes
|
||||
|
||||
inboxes.map do |inbox|
|
||||
conversations = filter_conversations_by_date_range.where(inbox_id: inbox.id)
|
||||
{
|
||||
inbox_id: inbox.id,
|
||||
inbox_name: inbox.name,
|
||||
total_assignments: conversations.count,
|
||||
average_assignment_time: calculate_average_assignment_time(conversations),
|
||||
unique_agents: conversations.where.not(assignee_id: nil).distinct.count(:assignee_id),
|
||||
assignment_policy: inbox.assignment_policy&.name
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def compute_agent_metrics
|
||||
agents = Current.account.users.joins(:account_users).where(account_users: { role: %w[agent administrator] })
|
||||
|
||||
agents.map do |agent|
|
||||
conversations = filter_conversations_by_date_range.where(assignee_id: agent.id)
|
||||
{
|
||||
agent_id: agent.id,
|
||||
agent_name: agent.name,
|
||||
agent_email: agent.email,
|
||||
assignment_count: conversations.count,
|
||||
average_resolution_time: calculate_average_resolution_time(conversations),
|
||||
current_load: agent.assigned_conversations.open.count,
|
||||
capacity_utilization: compute_agent_capacity_utilization(agent)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def compute_policy_metrics
|
||||
Current.account.assignment_policies.enabled.map do |policy|
|
||||
compute_policy_performance(policy)
|
||||
end
|
||||
end
|
||||
|
||||
def filter_conversations_by_date_range
|
||||
Current.account.conversations.where(created_at: date_range)
|
||||
end
|
||||
|
||||
def date_range
|
||||
@date_range ||= params[:since]..params[:until]
|
||||
end
|
||||
|
||||
def calculate_average_assignment_time(_conversations)
|
||||
# Implementation
|
||||
0
|
||||
end
|
||||
|
||||
def calculate_assignments_per_agent(conversations)
|
||||
agents_count = conversations.where.not(assignee_id: nil).distinct.count(:assignee_id)
|
||||
return 0 if agents_count.zero?
|
||||
|
||||
(conversations.count.to_f / agents_count).round(2)
|
||||
end
|
||||
|
||||
def calculate_average_resolution_time(_conversations)
|
||||
# Implementation
|
||||
0
|
||||
end
|
||||
|
||||
def compute_agent_capacity_utilization(_agent)
|
||||
# Implementation
|
||||
0.0
|
||||
end
|
||||
|
||||
def calculate_assignment_success_rate(_conversations)
|
||||
# Implementation
|
||||
100.0
|
||||
end
|
||||
|
||||
def serialize_agent(agent)
|
||||
{
|
||||
id: agent.id,
|
||||
name: agent.name,
|
||||
email: agent.email
|
||||
}
|
||||
end
|
||||
|
||||
def group_by_hour(conversations)
|
||||
conversations.group_by_hour(:created_at).count
|
||||
end
|
||||
|
||||
def group_by_day(conversations)
|
||||
conversations.group_by_day(:created_at).count
|
||||
end
|
||||
|
||||
def group_by_week(conversations)
|
||||
conversations.group_by_week(:created_at).count
|
||||
end
|
||||
|
||||
def group_by_month(conversations)
|
||||
conversations.group_by_month(:created_at).count
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,92 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DistributionMetrics
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def compute_distribution_by_day_of_week
|
||||
filter_conversations_by_date_range
|
||||
.group_by_day_of_week(:created_at)
|
||||
.count
|
||||
end
|
||||
|
||||
def compute_policy_performance(policy)
|
||||
inbox_ids = policy.inboxes.pluck(:id)
|
||||
conversations = filter_conversations_by_date_range.where(inbox_id: inbox_ids)
|
||||
|
||||
{
|
||||
policy_id: policy.id,
|
||||
policy_name: policy.name,
|
||||
assignment_order: policy.assignment_order,
|
||||
total_assignments: conversations.count,
|
||||
average_assignment_time: calculate_average_assignment_time(conversations),
|
||||
success_rate: calculate_assignment_success_rate(conversations),
|
||||
inbox_count: inbox_ids.count
|
||||
}
|
||||
end
|
||||
|
||||
def compute_agent_utilization(agent)
|
||||
capacity_policy = agent.account_users.first&.agent_capacity_policy
|
||||
assigned_conversations = agent.assigned_conversations.open.count
|
||||
|
||||
utilization = if capacity_policy
|
||||
policy_limit = capacity_policy.inbox_capacity_limits.sum(:conversation_limit)
|
||||
policy_limit.positive? ? (assigned_conversations.to_f / policy_limit * 100).round(2) : 0
|
||||
else
|
||||
0
|
||||
end
|
||||
|
||||
{
|
||||
agent: serialize_agent(agent),
|
||||
assigned_conversations: assigned_conversations,
|
||||
capacity_policy: capacity_policy&.name,
|
||||
utilization_percentage: utilization,
|
||||
available_capacity: capacity_policy ? capacity_policy.inbox_capacity_limits.sum(:conversation_limit) - assigned_conversations : nil
|
||||
}
|
||||
end
|
||||
|
||||
def compute_distribution_by_inbox
|
||||
filter_conversations_by_date_range
|
||||
.joins(:inbox)
|
||||
.group('inboxes.id', 'inboxes.name')
|
||||
.count
|
||||
.map { |k, v| { inbox_id: k[0], inbox_name: k[1], count: v } }
|
||||
end
|
||||
|
||||
def compute_distribution_by_team
|
||||
filter_conversations_by_date_range
|
||||
.joins(assignee: { team_members: :team })
|
||||
.group('teams.id', 'teams.name')
|
||||
.count
|
||||
.map { |k, v| { team_id: k[0], team_name: k[1], count: v } }
|
||||
end
|
||||
|
||||
def compute_distribution_by_hour
|
||||
filter_conversations_by_date_range
|
||||
.group_by_hour_of_day(:created_at)
|
||||
.count
|
||||
end
|
||||
|
||||
def calculate_average_resolution_time(conversations)
|
||||
resolved = conversations.resolved
|
||||
return 0 if resolved.empty?
|
||||
|
||||
total_time = resolved.sum { |c| (c.last_activity_at - c.created_at) / 1.hour }
|
||||
(total_time / resolved.count).round(2)
|
||||
end
|
||||
|
||||
def calculate_assignment_success_rate(conversations)
|
||||
total = conversations.count
|
||||
return 0.0 if total.zero?
|
||||
|
||||
successful = conversations.where(status: %w[resolved snoozed]).count
|
||||
(successful.to_f / total * 100).round(2)
|
||||
end
|
||||
|
||||
def pagination_meta
|
||||
{
|
||||
current_page: params[:page] || 1,
|
||||
per_page: params[:per_page] || 50,
|
||||
total_count: @assignment_history&.total_count || 0
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,7 @@ class MicrosoftController < ApplicationController
|
||||
after_action :set_version_header
|
||||
|
||||
def identity_association
|
||||
microsoft_indentity
|
||||
microsoft_identity
|
||||
end
|
||||
|
||||
private
|
||||
@@ -11,7 +11,7 @@ class MicrosoftController < ApplicationController
|
||||
response.headers['Content-Length'] = { associatedApplications: [{ applicationId: @identity_json }] }.to_json.length
|
||||
end
|
||||
|
||||
def microsoft_indentity
|
||||
def microsoft_identity
|
||||
@identity_json = GlobalConfigService.load('AZURE_APP_ID', nil)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,16 @@ class Webhooks::InstagramController < ActionController::API
|
||||
def events
|
||||
Rails.logger.info('Instagram webhook received events')
|
||||
if params['object'].casecmp('instagram').zero?
|
||||
::Webhooks::InstagramEventsJob.perform_later(params.to_unsafe_hash[:entry])
|
||||
entry_params = params.to_unsafe_hash[:entry]
|
||||
|
||||
if contains_echo_event?(entry_params)
|
||||
# Add delay to prevent race condition where echo arrives before send message API completes
|
||||
# This avoids duplicate messages when echo comes early during API processing
|
||||
::Webhooks::InstagramEventsJob.set(wait: 2.seconds).perform_later(entry_params)
|
||||
else
|
||||
::Webhooks::InstagramEventsJob.perform_later(entry_params)
|
||||
end
|
||||
|
||||
render json: :ok
|
||||
else
|
||||
Rails.logger.warn("Message is not received from the instagram webhook event: #{params['object']}")
|
||||
@@ -14,6 +23,16 @@ class Webhooks::InstagramController < ActionController::API
|
||||
|
||||
private
|
||||
|
||||
def contains_echo_event?(entry_params)
|
||||
return false unless entry_params.is_a?(Array)
|
||||
|
||||
entry_params.any? do |entry|
|
||||
# Check messaging array for echo events
|
||||
messaging_events = entry[:messaging] || []
|
||||
messaging_events.any? { |messaging| messaging.dig(:message, :is_echo).present? }
|
||||
end
|
||||
end
|
||||
|
||||
def valid_token?(token)
|
||||
# Validates against both IG_VERIFY_TOKEN (Instagram channel via Facebook page) and
|
||||
# INSTAGRAM_VERIFY_TOKEN (Instagram channel via direct Instagram login)
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/* global axios */
|
||||
import ApiClient from './ApiClient';
|
||||
|
||||
export class AgentCapacityPoliciesAPI extends ApiClient {
|
||||
constructor() {
|
||||
super('agent_capacity_policies', { accountScoped: true });
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/agent_capacity_policies
|
||||
get(params = {}) {
|
||||
return axios.get(this.url, { params });
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/agent_capacity_policies/:id
|
||||
show(id) {
|
||||
return axios.get(`${this.url}/${id}`);
|
||||
}
|
||||
|
||||
// POST /api/v1/accounts/:accountId/agent_capacity_policies
|
||||
create(data) {
|
||||
return axios.post(this.url, { agent_capacity_policy: data });
|
||||
}
|
||||
|
||||
// PUT /api/v1/accounts/:accountId/agent_capacity_policies/:id
|
||||
update(id, data) {
|
||||
return axios.put(`${this.url}/${id}`, { agent_capacity_policy: data });
|
||||
}
|
||||
|
||||
// DELETE /api/v1/accounts/:accountId/agent_capacity_policies/:id
|
||||
delete(id) {
|
||||
return axios.delete(`${this.url}/${id}`);
|
||||
}
|
||||
|
||||
// POST /api/v1/accounts/:accountId/agent_capacity_policies/:id/users
|
||||
assignUser(id, userId) {
|
||||
return axios.post(`${this.url}/${id}/users`, {
|
||||
user_id: userId,
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE /api/v1/accounts/:accountId/agent_capacity_policies/:id/users/:userId
|
||||
removeUser(id, userId) {
|
||||
return axios.delete(`${this.url}/${id}/users/${userId}`);
|
||||
}
|
||||
|
||||
// POST /api/v1/accounts/:accountId/agent_capacity_policies/:id/inbox_limits/:inboxId
|
||||
setInboxLimit(id, inboxId, conversationLimit) {
|
||||
return axios.post(`${this.url}/${id}/inbox_limits/${inboxId}`, {
|
||||
conversation_limit: conversationLimit,
|
||||
});
|
||||
}
|
||||
|
||||
// DELETE /api/v1/accounts/:accountId/agent_capacity_policies/:id/inbox_limits/:inboxId
|
||||
removeInboxLimit(id, inboxId) {
|
||||
return axios.delete(`${this.url}/${id}/inbox_limits/${inboxId}`);
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/agents/:agentId/capacity
|
||||
getAgentCapacity(accountId, agentId, inboxId = null) {
|
||||
const url = `/api/v1/accounts/${accountId}/agents/${agentId}/capacity`;
|
||||
const params = inboxId ? { inbox_id: inboxId } : {};
|
||||
return axios.get(url, { params });
|
||||
}
|
||||
}
|
||||
|
||||
export default new AgentCapacityPoliciesAPI();
|
||||
@@ -0,0 +1,52 @@
|
||||
/* global axios */
|
||||
import ApiClient from './ApiClient';
|
||||
|
||||
export class AssignmentMetricsAPI extends ApiClient {
|
||||
constructor() {
|
||||
super('reports/assignment_metrics', { accountScoped: true });
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/reports/assignment_metrics
|
||||
get(params = {}) {
|
||||
return axios.get(this.url, { params });
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/agents/:userId/assignment_history
|
||||
getAgentHistory(userId, params = {}) {
|
||||
return axios.get(
|
||||
`/api/v1/accounts/${this.accountId}/agents/${userId}/assignment_history`,
|
||||
{ params }
|
||||
);
|
||||
}
|
||||
|
||||
// Get all agents assignment history
|
||||
getAllAgentsHistory(params = {}) {
|
||||
return axios.get(this.url, {
|
||||
params: { ...params, include_agent_history: true },
|
||||
});
|
||||
}
|
||||
|
||||
// Get policy performance metrics
|
||||
getPolicyPerformance(params = {}) {
|
||||
return axios.get(this.url, {
|
||||
params: { ...params, include_policy_performance: true },
|
||||
});
|
||||
}
|
||||
|
||||
// Get agent utilization metrics
|
||||
getAgentUtilization(params = {}) {
|
||||
return axios.get(this.url, {
|
||||
params: { ...params, include_utilization: true },
|
||||
});
|
||||
}
|
||||
|
||||
// Export report data
|
||||
exportReport(type, params = {}) {
|
||||
return axios.get(`${this.url}/export`, {
|
||||
params: { type, ...params },
|
||||
responseType: 'blob',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new AssignmentMetricsAPI();
|
||||
@@ -0,0 +1,35 @@
|
||||
/* global axios */
|
||||
import ApiClient from './ApiClient';
|
||||
|
||||
export class AssignmentPoliciesAPI extends ApiClient {
|
||||
constructor() {
|
||||
super('assignment_policies', { accountScoped: true });
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/assignment_policies
|
||||
get() {
|
||||
return axios.get(this.url);
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/assignment_policies/:id
|
||||
show(id) {
|
||||
return axios.get(`${this.url}/${id}`);
|
||||
}
|
||||
|
||||
// POST /api/v1/accounts/:accountId/assignment_policies
|
||||
create(data) {
|
||||
return axios.post(this.url, { assignment_policy: data });
|
||||
}
|
||||
|
||||
// PUT /api/v1/accounts/:accountId/assignment_policies/:id
|
||||
update(id, data) {
|
||||
return axios.put(`${this.url}/${id}`, { assignment_policy: data });
|
||||
}
|
||||
|
||||
// DELETE /api/v1/accounts/:accountId/assignment_policies/:id
|
||||
delete(id) {
|
||||
return axios.delete(`${this.url}/${id}`);
|
||||
}
|
||||
}
|
||||
|
||||
export default new AssignmentPoliciesAPI();
|
||||
@@ -28,6 +28,20 @@ class Inboxes extends CacheEnabledApiClient {
|
||||
agent_bot: botId,
|
||||
});
|
||||
}
|
||||
|
||||
syncTemplates(inboxId) {
|
||||
return axios.post(`${this.url}/${inboxId}/sync_templates`);
|
||||
}
|
||||
|
||||
assignPolicy(inboxId, policyId) {
|
||||
return axios.post(`${this.url}/${inboxId}/assignment_policy`, {
|
||||
assignment_policy_id: policyId,
|
||||
});
|
||||
}
|
||||
|
||||
removePolicy(inboxId) {
|
||||
return axios.delete(`${this.url}/${inboxId}/assignment_policy`);
|
||||
}
|
||||
}
|
||||
|
||||
export default new Inboxes();
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/* global axios */
|
||||
import ApiClient from './ApiClient';
|
||||
|
||||
export class LeavesAPI extends ApiClient {
|
||||
constructor() {
|
||||
super('leaves', { accountScoped: true });
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/leaves
|
||||
get(params = {}) {
|
||||
return axios.get(this.url, { params });
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/leaves/:id
|
||||
show(id) {
|
||||
return axios.get(`${this.url}/${id}`);
|
||||
}
|
||||
|
||||
// POST /api/v1/accounts/:accountId/leaves
|
||||
create(data) {
|
||||
return axios.post(this.url, { leave: data.leave, user_id: data.user_id });
|
||||
}
|
||||
|
||||
// PUT /api/v1/accounts/:accountId/leaves/:id
|
||||
update(id, data) {
|
||||
return axios.put(`${this.url}/${id}`, { leave: data });
|
||||
}
|
||||
|
||||
// DELETE /api/v1/accounts/:accountId/leaves/:id
|
||||
delete(id) {
|
||||
return axios.delete(`${this.url}/${id}`);
|
||||
}
|
||||
|
||||
// POST /api/v1/accounts/:accountId/leaves/:id/approve
|
||||
approve(id, data = {}) {
|
||||
return axios.post(`${this.url}/${id}/approve`, data);
|
||||
}
|
||||
|
||||
// POST /api/v1/accounts/:accountId/leaves/:id/reject
|
||||
reject(id, data = {}) {
|
||||
return axios.post(`${this.url}/${id}/reject`, data);
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/leaves/my_leaves
|
||||
getMyLeaves(params = {}) {
|
||||
return axios.get(`${this.url}/my_leaves`, { params });
|
||||
}
|
||||
|
||||
// GET /api/v1/accounts/:accountId/leaves/pending_approvals
|
||||
getPendingApprovals(params = {}) {
|
||||
return axios.get(`${this.url}/pending_approvals`, { params });
|
||||
}
|
||||
}
|
||||
|
||||
export default new LeavesAPI();
|
||||
@@ -12,6 +12,7 @@ describe('#InboxesAPI', () => {
|
||||
expect(inboxesAPI).toHaveProperty('getCampaigns');
|
||||
expect(inboxesAPI).toHaveProperty('getAgentBot');
|
||||
expect(inboxesAPI).toHaveProperty('setAgentBot');
|
||||
expect(inboxesAPI).toHaveProperty('syncTemplates');
|
||||
});
|
||||
|
||||
describe('API calls', () => {
|
||||
@@ -40,5 +41,12 @@ describe('#InboxesAPI', () => {
|
||||
inboxesAPI.deleteInboxAvatar(2);
|
||||
expect(axiosMock.delete).toHaveBeenCalledWith('/api/v1/inboxes/2/avatar');
|
||||
});
|
||||
|
||||
it('#syncTemplates', () => {
|
||||
inboxesAPI.syncTemplates(2);
|
||||
expect(axiosMock.post).toHaveBeenCalledWith(
|
||||
'/api/v1/inboxes/2/sync_templates'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -54,6 +54,11 @@ const filteredAttrs = computed(() => {
|
||||
standardAttrs[key] = value;
|
||||
});
|
||||
|
||||
// Default to type="button" to prevent accidental form submissions
|
||||
if (!standardAttrs.type) {
|
||||
standardAttrs.type = 'button';
|
||||
}
|
||||
|
||||
return standardAttrs;
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import DropdownBody from './base/DropdownBody.vue';
|
||||
import DropdownSection from './base/DropdownSection.vue';
|
||||
import DropdownItem from './base/DropdownItem.vue';
|
||||
import DropdownSeparator from './base/DropdownSeparator.vue';
|
||||
import WootSwitch from 'components/ui/Switch.vue';
|
||||
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
|
||||
|
||||
const currentUserAutoOffline = ref(false);
|
||||
|
||||
@@ -61,7 +61,7 @@ const menuItems = ref([
|
||||
<DropdownItem label="Contact Support" class="justify-between">
|
||||
<span>{{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }}</span>
|
||||
<div class="flex-shrink-0">
|
||||
<WootSwitch v-model="currentUserAutoOffline" />
|
||||
<ToggleSwitch v-model="currentUserAutoOffline" />
|
||||
</div>
|
||||
</DropdownItem>
|
||||
</DropdownSection>
|
||||
|
||||
@@ -91,6 +91,7 @@ const toggleOption = option => {
|
||||
<template #trigger="{ toggle }">
|
||||
<button
|
||||
v-if="hasItems"
|
||||
type="button"
|
||||
class="bg-n-alpha-2 py-2 rounded-lg h-8 flex items-center px-0"
|
||||
@click="toggle"
|
||||
>
|
||||
|
||||
@@ -450,6 +450,12 @@ const menuItems = computed(() => {
|
||||
icon: 'i-lucide-message-square-quote',
|
||||
to: accountScopedRoute('canned_list'),
|
||||
},
|
||||
{
|
||||
name: 'Settings Assignment',
|
||||
label: t('SIDEBAR.ASSIGNMENT'),
|
||||
icon: 'i-lucide-users-round',
|
||||
to: accountScopedRoute('assignment_settings'),
|
||||
},
|
||||
{
|
||||
name: 'Settings Integrations',
|
||||
label: t('SIDEBAR.INTEGRATIONS'),
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
} from 'next/dropdown-menu/base';
|
||||
import Icon from 'next/icon/Icon.vue';
|
||||
import Button from 'next/button/Button.vue';
|
||||
import ToggleSwitch from 'dashboard/components-next/switch/Switch.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const store = useStore();
|
||||
@@ -48,6 +49,16 @@ const activeStatus = computed(() => {
|
||||
return availabilityStatuses.value.find(status => status.active);
|
||||
});
|
||||
|
||||
const autoOfflineToggle = computed({
|
||||
get: () => currentUserAutoOffline.value,
|
||||
set: autoOffline => {
|
||||
store.dispatch('updateAutoOffline', {
|
||||
accountId: currentAccountId.value,
|
||||
autoOffline,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
function changeAvailabilityStatus(availability) {
|
||||
if (isImpersonating.value) {
|
||||
useAlert(t('PROFILE_SETTINGS.FORM.AVAILABILITY.IMPERSONATING_ERROR'));
|
||||
@@ -62,13 +73,6 @@ function changeAvailabilityStatus(availability) {
|
||||
useAlert(t('PROFILE_SETTINGS.FORM.AVAILABILITY.SET_AVAILABILITY_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
function updateAutoOffline(autoOffline) {
|
||||
store.dispatch('updateAutoOffline', {
|
||||
accountId: currentAccountId.value,
|
||||
autoOffline,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -118,11 +122,7 @@ function updateAutoOffline(autoOffline) {
|
||||
class="size-4 text-n-slate-10"
|
||||
/>
|
||||
</div>
|
||||
<woot-switch
|
||||
class="flex-shrink-0"
|
||||
:model-value="currentUserAutoOffline"
|
||||
@input="updateAutoOffline"
|
||||
/>
|
||||
<ToggleSwitch v-model="autoOfflineToggle" />
|
||||
</DropdownItem>
|
||||
</div>
|
||||
</DropdownSection>
|
||||
|
||||
@@ -19,8 +19,8 @@ const updateValue = () => {
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="relative h-4 transition-colors duration-200 ease-in-out rounded-full w-7 focus:outline-none focus:ring-1 focus:ring-n-brand focus:ring-offset-n-slate-2 focus:ring-offset-2"
|
||||
:class="modelValue ? 'bg-n-brand' : 'bg-n-alpha-1 dark:bg-n-alpha-2'"
|
||||
class="relative h-4 transition-colors duration-200 ease-in-out rounded-full w-7 focus:outline-none focus:ring-1 focus:ring-n-brand focus:ring-offset-n-slate-2 focus:ring-offset-2 flex-shrink-0"
|
||||
:class="modelValue ? 'bg-n-brand' : 'bg-n-slate-6 disabled:bg-n-slate-6/60'"
|
||||
role="switch"
|
||||
:aria-checked="modelValue"
|
||||
@click="updateValue"
|
||||
|
||||
@@ -61,7 +61,9 @@ const onCopy = async e => {
|
||||
|
||||
<template>
|
||||
<div class="relative text-left">
|
||||
<div class="top-1.5 absolute right-1.5 flex items-center gap-1">
|
||||
<div
|
||||
class="top-1.5 absolute ltr:right-1.5 rtl:left-1.5 flex backdrop-blur-sm rounded-lg items-center gap-1"
|
||||
>
|
||||
<form
|
||||
v-if="enableCodePen"
|
||||
class="flex items-center"
|
||||
@@ -86,6 +88,11 @@ const onCopy = async e => {
|
||||
@click="onCopy"
|
||||
/>
|
||||
</div>
|
||||
<highlightjs v-if="script" :language="lang" :code="scrubbedScript" />
|
||||
<highlightjs
|
||||
v-if="script"
|
||||
:language="lang"
|
||||
:code="scrubbedScript"
|
||||
class="[&_code]:text-start"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
modelValue: { type: Boolean, default: false },
|
||||
size: { type: String, default: '' },
|
||||
},
|
||||
emits: ['update:modelValue', 'input'],
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit('update:modelValue', !this.modelValue);
|
||||
this.$emit('input', !this.modelValue);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="toggle-button p-0"
|
||||
:class="{ active: modelValue, small: size === 'small' }"
|
||||
role="switch"
|
||||
:aria-checked="modelValue.toString()"
|
||||
@click="onClick"
|
||||
>
|
||||
<span aria-hidden="true" :class="{ active: modelValue }" />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.toggle-button {
|
||||
@apply bg-n-slate-5;
|
||||
--toggle-button-box-shadow: rgb(255, 255, 255) 0px 0px 0px 0px,
|
||||
rgba(59, 130, 246, 0.5) 0px 0px 0px 0px, rgba(0, 0, 0, 0.1) 0px 1px 3px 0px,
|
||||
rgba(0, 0, 0, 0.06) 0px 1px 2px 0px;
|
||||
border-radius: 0.5625rem;
|
||||
border: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
height: 1.188rem;
|
||||
position: relative;
|
||||
transition-duration: 200ms;
|
||||
transition-property: background-color;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
width: 2.125rem;
|
||||
|
||||
&.active {
|
||||
@apply bg-n-brand;
|
||||
}
|
||||
|
||||
&.small {
|
||||
width: 1.375rem;
|
||||
height: 0.875rem;
|
||||
|
||||
span {
|
||||
@apply size-2.5;
|
||||
|
||||
&.active {
|
||||
@apply ltr:translate-x-[0.5rem] ltr:translate-y-0 rtl:translate-x-[-0.5rem] rtl:translate-y-0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
@apply bg-n-background;
|
||||
|
||||
border-radius: 100%;
|
||||
box-shadow: var(--toggle-button-box-shadow);
|
||||
display: inline-block;
|
||||
height: 0.9375rem;
|
||||
transform: translate(0, 0);
|
||||
transition-duration: 200ms;
|
||||
transition-property: transform;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
width: 0.9375rem;
|
||||
|
||||
&.active {
|
||||
@apply ltr:translate-x-[0.9375rem] ltr:translate-y-0 rtl:translate-x-[-0.9375rem] rtl:translate-y-0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -94,7 +94,7 @@ export default {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
hasWhatsappTemplates: {
|
||||
enableWhatsAppTemplates: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
@@ -333,7 +333,7 @@ export default {
|
||||
@click="toggleMessageSignature"
|
||||
/>
|
||||
<NextButton
|
||||
v-if="hasWhatsappTemplates"
|
||||
v-if="enableWhatsAppTemplates"
|
||||
v-tooltip.top-end="$t('CONVERSATION.FOOTER.WHATSAPP_TEMPLATES')"
|
||||
icon="i-ph-whatsapp-logo"
|
||||
slate
|
||||
|
||||
@@ -184,9 +184,8 @@ export default {
|
||||
|
||||
return false;
|
||||
},
|
||||
hasWhatsappTemplates() {
|
||||
return !!this.$store.getters['inboxes/getWhatsAppTemplates'](this.inboxId)
|
||||
.length;
|
||||
showWhatsappTemplates() {
|
||||
return this.isAWhatsAppCloudChannel && !this.isPrivate;
|
||||
},
|
||||
isPrivate() {
|
||||
if (this.currentChat.can_reply || this.isAWhatsAppChannel) {
|
||||
@@ -1212,7 +1211,7 @@ export default {
|
||||
<ReplyBottomPanel
|
||||
:conversation-id="conversationId"
|
||||
:enable-multiple-file-upload="enableMultipleFileUpload"
|
||||
:has-whatsapp-templates="hasWhatsappTemplates"
|
||||
:enable-whats-app-templates="showWhatsappTemplates"
|
||||
:inbox="inbox"
|
||||
:is-on-private-note="isOnPrivateNote"
|
||||
:is-recording-audio="isRecordingAudio"
|
||||
|
||||
+56
-18
@@ -1,8 +1,13 @@
|
||||
<script>
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||
// TODO: Remove this when we support all formats
|
||||
const formatsToRemove = ['DOCUMENT', 'IMAGE', 'VIDEO'];
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Icon,
|
||||
},
|
||||
props: {
|
||||
inboxId: {
|
||||
type: Number,
|
||||
@@ -13,6 +18,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
query: '',
|
||||
isRefreshing: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -37,38 +43,63 @@ export default {
|
||||
return template.components.find(component => component.type === 'BODY')
|
||||
.text;
|
||||
},
|
||||
async refreshTemplates() {
|
||||
this.isRefreshing = true;
|
||||
try {
|
||||
await this.$store.dispatch('inboxes/syncTemplates', this.inboxId);
|
||||
useAlert(this.$t('WHATSAPP_TEMPLATES.PICKER.REFRESH_SUCCESS'));
|
||||
} catch (error) {
|
||||
useAlert(this.$t('WHATSAPP_TEMPLATES.PICKER.REFRESH_ERROR'));
|
||||
} finally {
|
||||
this.isRefreshing = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<div
|
||||
class="gap-1 bg-n-alpha-black2 items-center flex mb-2.5 py-0 px-2.5 rounded-lg outline outline-1 outline-n-weak hover:outline-n-slate-6 dark:hover:outline-n-slate-6 focus-within:outline-n-brand dark:focus-within:outline-n-brand"
|
||||
>
|
||||
<fluent-icon icon="search" class="text-n-slate-12" size="16" />
|
||||
<input
|
||||
v-model="query"
|
||||
type="search"
|
||||
:placeholder="$t('WHATSAPP_TEMPLATES.PICKER.SEARCH_PLACEHOLDER')"
|
||||
class="reset-base w-full h-9 bg-transparent text-n-slate-12 !text-sm !outline-0"
|
||||
/>
|
||||
<div class="flex gap-2 mb-2.5">
|
||||
<div
|
||||
class="flex flex-1 gap-1 items-center px-2.5 py-0 rounded-lg bg-n-alpha-black2 outline outline-1 outline-n-weak hover:outline-n-slate-6 dark:hover:outline-n-slate-6 focus-within:outline-n-brand dark:focus-within:outline-n-brand"
|
||||
>
|
||||
<fluent-icon icon="search" class="text-n-slate-12" size="16" />
|
||||
<input
|
||||
v-model="query"
|
||||
type="search"
|
||||
:placeholder="$t('WHATSAPP_TEMPLATES.PICKER.SEARCH_PLACEHOLDER')"
|
||||
class="reset-base w-full h-9 bg-transparent text-n-slate-12 !text-sm !outline-0"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
:disabled="isRefreshing"
|
||||
class="flex justify-center items-center w-9 h-9 rounded-lg bg-n-alpha-black2 outline outline-1 outline-n-weak hover:outline-n-slate-6 dark:hover:outline-n-slate-6 hover:bg-n-alpha-2 dark:hover:bg-n-solid-2 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
:title="$t('WHATSAPP_TEMPLATES.PICKER.REFRESH_BUTTON')"
|
||||
@click="refreshTemplates"
|
||||
>
|
||||
<Icon
|
||||
icon="i-lucide-refresh-ccw"
|
||||
class="text-n-slate-12 size-4"
|
||||
:class="{ 'animate-spin': isRefreshing }"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="bg-n-background outline-n-container outline outline-1 rounded-lg max-h-[18.75rem] overflow-y-auto p-2.5"
|
||||
>
|
||||
<div v-for="(template, i) in filteredTemplateMessages" :key="template.id">
|
||||
<button
|
||||
class="rounded-lg cursor-pointer block p-2.5 text-left w-full hover:bg-n-alpha-2 dark:hover:bg-n-solid-2"
|
||||
class="block p-2.5 w-full text-left rounded-lg cursor-pointer hover:bg-n-alpha-2 dark:hover:bg-n-solid-2"
|
||||
@click="$emit('onSelect', template)"
|
||||
>
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-2.5">
|
||||
<div class="flex justify-between items-center mb-2.5">
|
||||
<p class="text-sm">
|
||||
{{ template.name }}
|
||||
</p>
|
||||
<span
|
||||
class="inline-block px-2 py-1 text-xs leading-none bg-n-slate-3 rounded-lg cursor-default text-n-slate-12"
|
||||
class="inline-block px-2 py-1 text-xs leading-none rounded-lg cursor-default bg-n-slate-3 text-n-slate-12"
|
||||
>
|
||||
{{ $t('WHATSAPP_TEMPLATES.PICKER.LABELS.LANGUAGE') }} :
|
||||
{{ template.language }}
|
||||
@@ -94,11 +125,18 @@ export default {
|
||||
class="border-b border-solid border-n-weak my-2.5 mx-auto max-w-[95%]"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="!filteredTemplateMessages.length">
|
||||
<p>
|
||||
{{ $t('WHATSAPP_TEMPLATES.PICKER.NO_TEMPLATES_FOUND') }}
|
||||
<strong>{{ query }}</strong>
|
||||
</p>
|
||||
<div v-if="!filteredTemplateMessages.length" class="py-8 text-center">
|
||||
<div v-if="query && whatsAppTemplateMessages.length">
|
||||
<p>
|
||||
{{ $t('WHATSAPP_TEMPLATES.PICKER.NO_TEMPLATES_FOUND') }}
|
||||
<strong>{{ query }}</strong>
|
||||
</p>
|
||||
</div>
|
||||
<div v-else-if="!whatsAppTemplateMessages.length" class="space-y-4">
|
||||
<p class="text-n-slate-11">
|
||||
{{ $t('WHATSAPP_TEMPLATES.PICKER.NO_TEMPLATES_AVAILABLE') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,10 @@ export default {
|
||||
NextButton,
|
||||
},
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: 'This is a title',
|
||||
@@ -25,35 +29,49 @@ export default {
|
||||
default: 'No',
|
||||
},
|
||||
},
|
||||
emits: ['update:show', 'confirm', 'cancel'],
|
||||
data: () => ({
|
||||
show: false,
|
||||
localShow: false,
|
||||
resolvePromise: undefined,
|
||||
rejectPromise: undefined,
|
||||
}),
|
||||
|
||||
watch: {
|
||||
show(val) {
|
||||
this.localShow = val;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
showConfirmation() {
|
||||
this.show = true;
|
||||
this.localShow = true;
|
||||
this.$emit('update:show', true);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.resolvePromise = resolve;
|
||||
this.rejectPromise = reject;
|
||||
});
|
||||
},
|
||||
confirm() {
|
||||
this.resolvePromise(true);
|
||||
this.show = false;
|
||||
if (this.resolvePromise) {
|
||||
this.resolvePromise(true);
|
||||
}
|
||||
this.$emit('confirm');
|
||||
this.localShow = false;
|
||||
this.$emit('update:show', false);
|
||||
},
|
||||
|
||||
cancel() {
|
||||
this.resolvePromise(false);
|
||||
this.show = false;
|
||||
if (this.resolvePromise) {
|
||||
this.resolvePromise(false);
|
||||
}
|
||||
this.$emit('cancel');
|
||||
this.localShow = false;
|
||||
this.$emit('update:show', false);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal v-model:show="show" :on-close="cancel">
|
||||
<Modal v-model:show="localShow" :on-close="cancel">
|
||||
<div class="h-auto overflow-auto flex flex-col">
|
||||
<woot-modal-header :header-title="title" :header-content="description" />
|
||||
<div class="flex flex-row justify-end gap-2 py-4 px-6 w-full">
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "تحديث",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "رمز التحقق من Webhook",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "نماذج البحث",
|
||||
"NO_TEMPLATES_FOUND": "لم يتم العثور على قوالب",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "اللغة",
|
||||
"TEMPLATE_BODY": "نص القالب",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Обновяване",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Actualitza",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Token de verificació del webhook",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "Aquest testimoni s'utilitza per verificar l'autenticitat del punt final del webhook.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Actualitza la configuració del formulari de xat prèvia"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Cerca plantilles",
|
||||
"NO_TEMPLATES_FOUND": "No s'han trobat plantilles per a",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Idioma",
|
||||
"TEMPLATE_BODY": "Cos de la plantilla",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Aktualizovat",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Opdater",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook verifikations token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Søg Skabeloner",
|
||||
"NO_TEMPLATES_FOUND": "Ingen skabeloner fundet for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Sprog",
|
||||
"TEMPLATE_BODY": "Skabelon Krop",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Aktualisieren",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook-Verifizierungstoken",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "Mit diesem Token wird die Authentizität des Webhook Endpunktes überprüft.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Pre Chat Einstellungen aktualisieren"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Vorlagen suchen",
|
||||
"NO_TEMPLATES_FOUND": "Keine Vorlagen gefunden für",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Sprache",
|
||||
"TEMPLATE_BODY": "Vorlagenbody",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Ενημέρωση",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Token Επαλήθευσης Webhook",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Αναζήτηση Προτύπων",
|
||||
"NO_TEMPLATES_FOUND": "Δεν βρέθηκαν πρότυπα για",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Γλώσσα",
|
||||
"TEMPLATE_BODY": "Σώμα Προτύπου",
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
{
|
||||
"ASSIGNMENT_SETTINGS": {
|
||||
"HEADER": "Assignment Settings",
|
||||
"DESCRIPTION": "Manage conversation assignment policies, agent leave requests, capacity planning, and view assignment metrics.",
|
||||
"POLICIES": {
|
||||
"TITLE": "Assignment Policies",
|
||||
"DESCRIPTION": "Configure how conversations are assigned to agents",
|
||||
"HEADER": "Assignment Policies",
|
||||
"SUBHEADER": "Create and manage policies to automatically assign conversations to agents based on various criteria.",
|
||||
"NEW_BUTTON": "New Policy",
|
||||
"BACK_BUTTON": "Back to Policies",
|
||||
"NEW_HEADER": "Create Assignment Policy",
|
||||
"EDIT_HEADER": "Edit Assignment Policy",
|
||||
"FORM_DESCRIPTION": "Configure the policy settings for automatic conversation assignment.",
|
||||
"EMPTY": {
|
||||
"TITLE": "No assignment policies found",
|
||||
"MESSAGE": "Create your first assignment policy to start automatically assigning conversations to agents."
|
||||
},
|
||||
"TABLE": {
|
||||
"NAME": "Policy Name",
|
||||
"DESCRIPTION": "Description",
|
||||
"PRIORITY": "Priority",
|
||||
"STATUS": "Status",
|
||||
"ACTIONS": "Actions"
|
||||
},
|
||||
"FORM": {
|
||||
"BASIC_INFO": "Basic Information",
|
||||
"NAME": "Policy Name",
|
||||
"NAME_PLACEHOLDER": "Enter policy name",
|
||||
"NAME_REQUIRED": "Policy name is required",
|
||||
"DESCRIPTION": "Description",
|
||||
"DESCRIPTION_PLACEHOLDER": "Describe what this policy does",
|
||||
"ACTIVE": "Active",
|
||||
"POLICY_TYPE": "Policy Type",
|
||||
"TYPE_REQUIRED": "Policy type is required",
|
||||
"CONDITIONS": "Conditions",
|
||||
"INBOXES": "Apply to Inboxes",
|
||||
"INBOXES_PLACEHOLDER": "Select inboxes where this policy applies",
|
||||
"TEAMS": "Apply to Teams",
|
||||
"TEAMS_PLACEHOLDER": "Select teams to include",
|
||||
"AGENTS": "Specific Agents",
|
||||
"AGENTS_PLACEHOLDER": "Select specific agents (leave empty for all)",
|
||||
"BUSINESS_HOURS_ONLY": "Apply only during business hours",
|
||||
"EXCLUDED_AGENTS": "Excluded Agents",
|
||||
"EXCLUDED_AGENTS_PLACEHOLDER": "Select agents to exclude from assignments",
|
||||
"ADVANCED": "Advanced Settings",
|
||||
"WEIGHT": "Policy Weight",
|
||||
"WEIGHT_PLACEHOLDER": "100",
|
||||
"WEIGHT_HELP": "Higher weight policies get more assignments (1-100)",
|
||||
"MAX_ASSIGNMENTS": "Max Assignments per Agent",
|
||||
"MAX_ASSIGNMENTS_PLACEHOLDER": "No limit",
|
||||
"MAX_ASSIGNMENTS_HELP": "Maximum concurrent conversations per agent",
|
||||
"REASSIGNMENT_INTERVAL": "Reassignment Interval (minutes)",
|
||||
"REASSIGNMENT_INTERVAL_PLACEHOLDER": "0",
|
||||
"REASSIGNMENT_INTERVAL_HELP": "Time before unresponded conversations are reassigned"
|
||||
},
|
||||
"TYPES": {
|
||||
"ROUND_ROBIN": "Round Robin",
|
||||
"ROUND_ROBIN_DESC": "Distribute conversations evenly among available agents",
|
||||
"LOAD_BALANCED": "Load Balanced",
|
||||
"LOAD_BALANCED_DESC": "Assign to agents with the least active conversations",
|
||||
"SKILL_BASED": "Skill Based",
|
||||
"SKILL_BASED_DESC": "Match conversations to agents based on required skills",
|
||||
"CUSTOM": "Custom",
|
||||
"CUSTOM_DESC": "Use custom logic for assignment"
|
||||
},
|
||||
"DELETE": {
|
||||
"TITLE": "Delete Policy",
|
||||
"MESSAGE": "Are you sure you want to delete the policy '{name}'? This action cannot be undone.",
|
||||
"SUCCESS": "Policy deleted successfully",
|
||||
"ERROR": "Failed to delete policy"
|
||||
},
|
||||
"CREATE": {
|
||||
"SUCCESS": "Policy created successfully",
|
||||
"ERROR": "Failed to create policy"
|
||||
},
|
||||
"UPDATE": {
|
||||
"SUCCESS": "Policy updated successfully",
|
||||
"ERROR": "Failed to update policy"
|
||||
},
|
||||
"LOAD": {
|
||||
"ERROR": "Failed to load policy"
|
||||
},
|
||||
"PRIORITY": {
|
||||
"ERROR": "Failed to update priority"
|
||||
}
|
||||
},
|
||||
"PAYWALL": {
|
||||
"TITLE": "Premium Feature",
|
||||
"UPGRADE_NOW": "Upgrade Now",
|
||||
"CANCEL_ANYTIME": "Cancel anytime"
|
||||
},
|
||||
"ENTERPRISE_PAYWALL": {
|
||||
"ASK_ADMIN": "Please contact your administrator to upgrade."
|
||||
},
|
||||
"LEAVES": {
|
||||
"TITLE": "Leave Management",
|
||||
"DESCRIPTION": "Manage agent leave requests and approvals",
|
||||
"HEADER": "Leave Management",
|
||||
"SUBHEADER": "View and manage leave requests for agents. Approved leaves will exclude agents from automatic assignments.",
|
||||
"NEW_BUTTON": "Request Leave",
|
||||
"BACK_BUTTON": "Back to Leaves",
|
||||
"NEW_HEADER": "Request Leave",
|
||||
"NEW_DESCRIPTION": "Submit a leave request for approval.",
|
||||
"DETAILS_HEADER": "Leave Details",
|
||||
"DETAILS_DESCRIPTION": "View complete information about this leave request.",
|
||||
"EMPTY": {
|
||||
"TITLE": "No leave requests found",
|
||||
"MESSAGE": "There are no leave requests matching your filters."
|
||||
},
|
||||
"TABS": {
|
||||
"ALL": "All Leaves",
|
||||
"MY_LEAVES": "My Leaves",
|
||||
"PENDING_APPROVALS": "Pending Approvals"
|
||||
},
|
||||
"FILTER": {
|
||||
"STATUS": "Status"
|
||||
},
|
||||
"TABLE": {
|
||||
"AGENT": "Agent",
|
||||
"TYPE": "Leave Type",
|
||||
"DATES": "Dates",
|
||||
"REASON": "Reason",
|
||||
"STATUS": "Status",
|
||||
"ACTIONS": "Actions"
|
||||
},
|
||||
"STATUS": {
|
||||
"PENDING": "Pending",
|
||||
"APPROVED": "Approved",
|
||||
"REJECTED": "Rejected"
|
||||
},
|
||||
"TYPES": {
|
||||
"ANNUAL": "Annual Leave",
|
||||
"SICK": "Sick Leave",
|
||||
"PERSONAL": "Personal Leave",
|
||||
"MATERNITY": "Maternity Leave",
|
||||
"PATERNITY": "Paternity Leave",
|
||||
"UNPAID": "Unpaid Leave",
|
||||
"OTHER": "Other"
|
||||
},
|
||||
"FORM": {
|
||||
"TYPE": "Leave Type",
|
||||
"TYPE_PLACEHOLDER": "Select leave type",
|
||||
"TYPE_REQUIRED": "Leave type is required",
|
||||
"START_DATE": "Start Date",
|
||||
"START_DATE_PLACEHOLDER": "Select start date",
|
||||
"START_DATE_REQUIRED": "Start date is required",
|
||||
"END_DATE": "End Date",
|
||||
"END_DATE_PLACEHOLDER": "Select end date",
|
||||
"END_DATE_REQUIRED": "End date is required",
|
||||
"END_DATE_INVALID": "End date must be after start date",
|
||||
"IS_HALF_DAY": "Half day leave",
|
||||
"HALF_DAY_PERIOD": "Half Day Period",
|
||||
"HALF_DAY_INVALID": "Half day leave must be for a single date",
|
||||
"TOTAL_DAYS": "Total Days",
|
||||
"REASON": "Reason",
|
||||
"REASON_PLACEHOLDER": "Provide reason for leave",
|
||||
"REASON_REQUIRED": "Reason is required",
|
||||
"SUBMIT": "Submit Request"
|
||||
},
|
||||
"HALF_DAY": {
|
||||
"MORNING": "Morning",
|
||||
"AFTERNOON": "Afternoon"
|
||||
},
|
||||
"DETAILS": {
|
||||
"TYPE": "Leave Type",
|
||||
"DATES": "Leave Period",
|
||||
"REASON": "Reason",
|
||||
"REQUESTED_ON": "Requested On",
|
||||
"APPROVED_BY": "Approved By",
|
||||
"REJECTED_BY": "Rejected By",
|
||||
"APPROVER_NOTES": "Approver Notes"
|
||||
},
|
||||
"APPROVAL_NOTES": "Notes (Optional)",
|
||||
"APPROVAL_NOTES_PLACEHOLDER": "Add any notes for this decision",
|
||||
"DELETE": {
|
||||
"TITLE": "Delete Leave Request",
|
||||
"MESSAGE": "Are you sure you want to delete this leave request?",
|
||||
"CONFIRM": "Are you sure you want to delete this leave request?",
|
||||
"SUCCESS": "Leave request deleted successfully",
|
||||
"ERROR": "Failed to delete leave request"
|
||||
},
|
||||
"CREATE": {
|
||||
"SUCCESS": "Leave request submitted successfully",
|
||||
"ERROR": "Failed to submit leave request"
|
||||
},
|
||||
"LOAD": {
|
||||
"ERROR": "Failed to load leave details"
|
||||
},
|
||||
"APPROVE": {
|
||||
"BUTTON": "Approve",
|
||||
"MODAL_TITLE": "Approve Leave Request",
|
||||
"MODAL_MESSAGE": "Approve leave request for {name} from {dates}?",
|
||||
"CONFIRM": "Approve Leave",
|
||||
"SUCCESS": "Leave request approved successfully",
|
||||
"ERROR": "Failed to approve leave request"
|
||||
},
|
||||
"REJECT": {
|
||||
"BUTTON": "Reject",
|
||||
"MODAL_TITLE": "Reject Leave Request",
|
||||
"MODAL_MESSAGE": "Reject leave request for {name} from {dates}?",
|
||||
"CONFIRM": "Reject Leave",
|
||||
"SUCCESS": "Leave request rejected successfully",
|
||||
"ERROR": "Failed to reject leave request"
|
||||
}
|
||||
},
|
||||
"CAPACITY": {
|
||||
"TITLE": "Agent Capacity",
|
||||
"DESCRIPTION": "Set maximum conversation limits for agents (Enterprise)",
|
||||
"HEADER": "Agent Capacity Management",
|
||||
"SUBHEADER": "Configure maximum conversation capacity for agents to prevent overload and ensure quality support.",
|
||||
"NEW_BUTTON": "New Capacity Policy",
|
||||
"BACK_BUTTON": "Back to Capacity",
|
||||
"NEW_HEADER": "Create Capacity Policy",
|
||||
"EDIT_HEADER": "Edit Capacity Policy",
|
||||
"FORM_DESCRIPTION": "Set the maximum number of concurrent conversations agents can handle.",
|
||||
"ENTERPRISE_ONLY": "Agent capacity management is available in the Enterprise edition.",
|
||||
"EMPTY": {
|
||||
"TITLE": "No capacity policies found",
|
||||
"MESSAGE": "Create capacity policies to limit the number of concurrent conversations assigned to agents."
|
||||
},
|
||||
"AGENTS_EMPTY": {
|
||||
"TITLE": "No agent capacities configured",
|
||||
"MESSAGE": "Create capacity policies and assign agents to manage their workload."
|
||||
},
|
||||
"TABS": {
|
||||
"POLICIES": "Capacity Policies",
|
||||
"AGENTS": "Agent Capacities"
|
||||
},
|
||||
"TABLE": {
|
||||
"NAME": "Policy Name",
|
||||
"DESCRIPTION": "Description",
|
||||
"MAX_CAPACITY": "Max Capacity",
|
||||
"INBOX_LIMITS": "Inbox Limits",
|
||||
"AGENTS_COUNT": "Agents",
|
||||
"ACTIONS": "Actions",
|
||||
"AGENT": "Agent",
|
||||
"POLICY": "Policy",
|
||||
"CURRENT_LOAD": "Current Load",
|
||||
"UTILIZATION": "Utilization"
|
||||
},
|
||||
"FORM": {
|
||||
"NAME": "Policy Name",
|
||||
"NAME_PLACEHOLDER": "e.g., Standard Agent Capacity",
|
||||
"NAME_REQUIRED": "Policy name is required",
|
||||
"DESCRIPTION": "Description",
|
||||
"DESCRIPTION_PLACEHOLDER": "Describe this capacity policy",
|
||||
"MAX_CAPACITY": "Maximum Capacity",
|
||||
"MAX_CAPACITY_PLACEHOLDER": "10",
|
||||
"MAX_CAPACITY_HELP": "Maximum number of concurrent conversations per agent",
|
||||
"CAPACITY_REQUIRED": "Capacity must be at least 1",
|
||||
"AGENTS": "Assign Agents",
|
||||
"AGENTS_PLACEHOLDER": "Select agents for this policy",
|
||||
"AGENTS_REQUIRED": "Please select at least one agent",
|
||||
"NOTE_TITLE": "Note",
|
||||
"NOTE_MESSAGE": "Agents can only be assigned to one capacity policy at a time. Assigning an agent to this policy will remove them from any other capacity policy."
|
||||
},
|
||||
"DELETE": {
|
||||
"TITLE": "Delete Capacity Policy",
|
||||
"MESSAGE": "Are you sure you want to delete the policy '{name}'? This will remove capacity limits for all assigned agents.",
|
||||
"SUCCESS": "Capacity policy deleted successfully",
|
||||
"ERROR": "Failed to delete capacity policy"
|
||||
},
|
||||
"CREATE": {
|
||||
"SUCCESS": "Capacity policy created successfully",
|
||||
"ERROR": "Failed to create capacity policy"
|
||||
},
|
||||
"UPDATE": {
|
||||
"SUCCESS": "Capacity policy updated successfully",
|
||||
"ERROR": "Failed to update capacity policy"
|
||||
},
|
||||
"LOAD": {
|
||||
"ERROR": "Failed to load capacity policy"
|
||||
},
|
||||
"AVAILABLE_ON": "Agent capacity management is available on <b>Enterprise</b> plans.",
|
||||
"UPGRADE_PROMPT": "Upgrade to Enterprise to set conversation limits for your agents."
|
||||
},
|
||||
"METRICS": {
|
||||
"TITLE": "Assignment Metrics",
|
||||
"DESCRIPTION": "View detailed analytics and performance metrics",
|
||||
"HEADER": "Assignment Metrics",
|
||||
"SUBHEADER": "Monitor assignment performance, agent utilization, and policy effectiveness.",
|
||||
"EXPORT": "Export Report",
|
||||
"FILTERS": {
|
||||
"TITLE": "Filters",
|
||||
"AGENTS": "Agents",
|
||||
"POLICIES": "Policies",
|
||||
"POLICIES_PLACEHOLDER": "All policies"
|
||||
},
|
||||
"TABS": {
|
||||
"OVERVIEW": "Overview",
|
||||
"AGENT_PERFORMANCE": "Agent Performance",
|
||||
"POLICY_PERFORMANCE": "Policy Performance",
|
||||
"UTILIZATION": "Utilization"
|
||||
},
|
||||
"CARDS": {
|
||||
"TOTAL_ASSIGNMENTS": "Total Assignments",
|
||||
"AVG_RESPONSE_TIME": "Avg Response Time",
|
||||
"SATISFACTION_SCORE": "Satisfaction Score",
|
||||
"REASSIGNMENT_RATE": "Reassignment Rate"
|
||||
},
|
||||
"CHARTS": {
|
||||
"ASSIGNMENT_TRENDS": "Assignment Trends",
|
||||
"ASSIGNMENTS": "Assignments",
|
||||
"UTILIZATION": "Utilization %",
|
||||
"POLICY_DISTRIBUTION": "Assignments by Policy",
|
||||
"POLICY_SUCCESS_RATES": "Policy Success Rates",
|
||||
"SUCCESS_RATE": "Success Rate %",
|
||||
"AGENT_UTILIZATION": "Agent Utilization"
|
||||
},
|
||||
"TABLE": {
|
||||
"AGENT": "Agent",
|
||||
"ASSIGNMENTS_HANDLED": "Assignments",
|
||||
"AVG_RESPONSE_TIME": "Avg Response",
|
||||
"SATISFACTION_SCORE": "Satisfaction",
|
||||
"EFFICIENCY_SCORE": "Efficiency",
|
||||
"POLICY": "Policy",
|
||||
"TOTAL_ASSIGNMENTS": "Total",
|
||||
"SUCCESS_RATE": "Success Rate",
|
||||
"AVG_HANDLING_TIME": "Avg Handling",
|
||||
"REASSIGNMENT_RATE": "Reassignments"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -246,6 +246,18 @@
|
||||
},
|
||||
"COMMON": {
|
||||
"OR": "Or",
|
||||
"CLICK_HERE": "click here"
|
||||
"CLICK_HERE": "click here",
|
||||
"DELETE": "Delete",
|
||||
"CANCEL": "Cancel",
|
||||
"EDIT": "Edit",
|
||||
"UPDATE": "Update",
|
||||
"CREATE": "Create",
|
||||
"SAVE": "Save",
|
||||
"AGENTS": "Agents",
|
||||
"VIEW": "View",
|
||||
"ACTIVE": "Active",
|
||||
"INACTIVE": "Inactive",
|
||||
"ALL": "All",
|
||||
"DAYS": "Days"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import advancedFilters from './advancedFilters.json';
|
||||
import agentBots from './agentBots.json';
|
||||
import agentMgmt from './agentMgmt.json';
|
||||
import assignmentSettings from './assignmentSettings.json';
|
||||
import attributesMgmt from './attributesMgmt.json';
|
||||
import auditLogs from './auditLogs.json';
|
||||
import automation from './automation.json';
|
||||
@@ -40,6 +41,7 @@ export default {
|
||||
...advancedFilters,
|
||||
...agentBots,
|
||||
...agentMgmt,
|
||||
...assignmentSettings,
|
||||
...attributesMgmt,
|
||||
...auditLogs,
|
||||
...automation,
|
||||
|
||||
@@ -308,6 +308,7 @@
|
||||
"MACROS": "Macros",
|
||||
"TEAMS": "Teams",
|
||||
"BILLING": "Billing",
|
||||
"ASSIGNMENT": "Assignment",
|
||||
"CUSTOM_VIEWS_FOLDER": "Folders",
|
||||
"CUSTOM_VIEWS_SEGMENTS": "Segments",
|
||||
"ALL_CONTACTS": "All Contacts",
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Actualizar",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Token de verificación del Webhook",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "Este token se utiliza para verificar la autenticidad del extremo del webhook.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Actualizar configuración de Formulario de Chat"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Buscar plantillas",
|
||||
"NO_TEMPLATES_FOUND": "No se encontraron plantillas para",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Idioma",
|
||||
"TEMPLATE_BODY": "Cuerpo de plantilla",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "اعمال شود",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "توکن تایید Webhook",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "این توکن برای تأیید صحت نقطه پایانی webhook استفاده می شود.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "بهروزرسانی تنظیمات فرم قبل از گفتگو"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "جستجوی الگوها",
|
||||
"NO_TEMPLATES_FOUND": "هیچ قالبی برای",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "زبان",
|
||||
"TEMPLATE_BODY": "بدنه الگو",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Päivitä",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Etsi Pohjia",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Mettre à jour",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Jeton de vérification du Webhook",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "Ce jeton est utilisé pour vérifier l'authenticité du point de terminaison du webhook.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Mettre à jour les paramètres du formulaire de pré-chat"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Rechercher des modèles",
|
||||
"NO_TEMPLATES_FOUND": "Aucun modèle trouvé pour",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Langue",
|
||||
"TEMPLATE_BODY": "Corps du modèle",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "עדכן",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "אסימון אימות Webhook",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "עדכון הגדרות טופס טרום צ'אט"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "חפש תבניות",
|
||||
"NO_TEMPLATES_FOUND": "לא נמצאו תבניות עבור",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "שפה",
|
||||
"TEMPLATE_BODY": "גוף התבנית",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "Ovaj token se koristi za verifikaciju autentičnosti webhook endpoint-a.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Pretraži Predloške",
|
||||
"NO_TEMPLATES_FOUND": "Nije pronađen predložak za",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Jezik",
|
||||
"TEMPLATE_BODY": "Tijelo predloška",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Frissítés",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "Ez a token a webhook-végpont hitelességének ellenőrzésére szolgál.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Csevegés előtti űrlap beállításainak frissítése"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Sablon keresése",
|
||||
"NO_TEMPLATES_FOUND": "Nem található sablon erre:",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Nyelv",
|
||||
"TEMPLATE_BODY": "Sablon törzse",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Perbarui",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Token Verifikasi Webhook",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "Token ini digunakan untuk memverifikasi keaslian titik akhir webhook.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Perbarui Pengaturan Formulir Pra Obrolan"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Cari Templat",
|
||||
"NO_TEMPLATES_FOUND": "Tidak ditemukan templat untuk",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Bahasa",
|
||||
"TEMPLATE_BODY": "Isi Templat",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Uppfæra",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Aggiorna",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Cerca modelli",
|
||||
"NO_TEMPLATES_FOUND": "Nessun modello trovato per",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Lingua",
|
||||
"TEMPLATE_BODY": "Corpo modello",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "更新",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook検証トークン",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "このトークンはWebhookエンドポイントの信頼性を検証するために使用されます。",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "プレチャットフォーム設定を更新する"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "テンプレートを検索",
|
||||
"NO_TEMPLATES_FOUND": "該当するテンプレートが見つかりません:",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "言語",
|
||||
"TEMPLATE_BODY": "テンプレート本文",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "업데이트",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "언어",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Atnaujinti",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Patikros Prieigos Raktas",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "Šis prieigos raktas naudojamas „webhook“ galutinio taško autentiškumui patikrinti.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Atnaujinkite išankstinio pokalbio internetu formos nustatymus"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Ieškoti šablonų",
|
||||
"NO_TEMPLATES_FOUND": "Šablonų nerasta",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Kalba",
|
||||
"TEMPLATE_BODY": "Šablono tekstas",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Atjaunināt",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verifikācijas Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "Šis marķieris tiek izmantots, lai pārbaudītu webhook endpoint autentiskumu.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Atjaunināt pirms-tērzēšanas veidlapas iestatījumus"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Meklēt Veidnes",
|
||||
"NO_TEMPLATES_FOUND": "Veidnes nav atrastas",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Valoda",
|
||||
"TEMPLATE_BODY": "Veidnes Pamatteksts",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "അപ്ഡേറ്റ്",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Vernieuwen",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Templates zoeken",
|
||||
"NO_TEMPLATES_FOUND": "Geen templates gevonden voor",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Taal",
|
||||
"TEMPLATE_BODY": "Template bericht",
|
||||
|
||||
@@ -600,6 +600,10 @@
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Oppdater",
|
||||
"WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates",
|
||||
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
|
||||
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings"
|
||||
},
|
||||
"HELP_CENTER": {
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"PICKER": {
|
||||
"SEARCH_PLACEHOLDER": "Search Templates",
|
||||
"NO_TEMPLATES_FOUND": "No templates found for",
|
||||
"NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.",
|
||||
"REFRESH_BUTTON": "Refresh templates",
|
||||
"REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.",
|
||||
"REFRESH_ERROR": "Failed to refresh templates. Please try again.",
|
||||
"LABELS": {
|
||||
"LANGUAGE": "Language",
|
||||
"TEMPLATE_BODY": "Template Body",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user