Merge branch 'release/1.20.0'
This commit is contained in:
commit
b474e39feb
737 changed files with 18270 additions and 3396 deletions
|
@ -7,7 +7,7 @@ defaults: &defaults
|
||||||
working_directory: ~/build
|
working_directory: ~/build
|
||||||
docker:
|
docker:
|
||||||
# specify the version you desire here
|
# specify the version you desire here
|
||||||
- image: circleci/ruby:3.0.2-node-browsers
|
- image: cimg/ruby:3.0.2-node
|
||||||
|
|
||||||
# Specify service dependencies here if necessary
|
# Specify service dependencies here if necessary
|
||||||
# CircleCI maintains a library of pre-built images
|
# CircleCI maintains a library of pre-built images
|
||||||
|
@ -40,20 +40,20 @@ jobs:
|
||||||
|
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- chatwoot-bundle-{{ checksum "Gemfile.lock" }}
|
- chatwoot-bundle-{{ .Environment.CACHE_VERSION }}-{{ checksum "Gemfile.lock" }}
|
||||||
- chatwoot-bundle
|
- chatwoot-bundle
|
||||||
|
|
||||||
- run: bundle install --frozen --path ~/.bundle
|
- run: bundle install --frozen --path ~/.bundle
|
||||||
- save_cache:
|
- save_cache:
|
||||||
paths:
|
paths:
|
||||||
- ~/.bundle
|
- ~/.bundle
|
||||||
key: chatwoot-bundle-{{ checksum "Gemfile.lock" }}
|
key: chatwoot-bundle-{{ .Environment.CACHE_VERSION }}-{{ checksum "Gemfile.lock" }}
|
||||||
|
|
||||||
|
|
||||||
# Only necessary if app uses webpacker or yarn in some other way
|
# Only necessary if app uses webpacker or yarn in some other way
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- chatwoot-yarn-{{ checksum "yarn.lock" }}
|
- chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }}
|
||||||
- chatwoot-yarn-
|
- chatwoot-yarn-
|
||||||
|
|
||||||
- run:
|
- run:
|
||||||
|
@ -62,7 +62,7 @@ jobs:
|
||||||
|
|
||||||
# Store yarn / webpacker cache
|
# Store yarn / webpacker cache
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: chatwoot-yarn-{{ checksum "yarn.lock" }}
|
key: chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }}
|
||||||
paths:
|
paths:
|
||||||
- ~/.cache/yarn
|
- ~/.cache/yarn
|
||||||
|
|
||||||
|
|
21
.env.example
21
.env.example
|
@ -85,8 +85,6 @@ AWS_ACCESS_KEY_ID=
|
||||||
AWS_SECRET_ACCESS_KEY=
|
AWS_SECRET_ACCESS_KEY=
|
||||||
AWS_REGION=
|
AWS_REGION=
|
||||||
|
|
||||||
# Sentry
|
|
||||||
SENTRY_DSN=
|
|
||||||
|
|
||||||
# Log settings
|
# Log settings
|
||||||
# Disable if you want to write logs to a file
|
# Disable if you want to write logs to a file
|
||||||
|
@ -139,6 +137,25 @@ ANDROID_SHA256_CERT_FINGERPRINT=AC:73:8E:DE:EB:56:EA:CC:10:87:02:A7:65:37:7B:38:
|
||||||
USE_INBOX_AVATAR_FOR_BOT=true
|
USE_INBOX_AVATAR_FOR_BOT=true
|
||||||
|
|
||||||
|
|
||||||
|
### APM and Error Monitoring configurations
|
||||||
|
## Sentry
|
||||||
|
# SENTRY_DSN=
|
||||||
|
|
||||||
|
## Scout
|
||||||
|
## https://scoutapm.com/docs/ruby/configuration
|
||||||
|
# SCOUT_KEY=YOURKEY
|
||||||
|
# SCOUT_NAME=YOURAPPNAME (Production)
|
||||||
|
# SCOUT_MONITOR=true
|
||||||
|
|
||||||
|
## NewRelic
|
||||||
|
# https://docs.newrelic.com/docs/agents/ruby-agent/configuration/ruby-agent-configuration/
|
||||||
|
# NEW_RELIC_LICENSE_KEY=
|
||||||
|
|
||||||
|
## Datadog
|
||||||
|
## https://github.com/DataDog/dd-trace-rb/blob/master/docs/GettingStarted.md#environment-variables
|
||||||
|
# DD_TRACE_AGENT_URL=
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## IP look up configuration
|
## IP look up configuration
|
||||||
## ref https://github.com/alexreisner/geocoder/blob/master/README_API_GUIDE.md
|
## ref https://github.com/alexreisner/geocoder/blob/master/README_API_GUIDE.md
|
||||||
|
|
|
@ -100,6 +100,7 @@ Metrics/AbcSize:
|
||||||
- 'app/controllers/concerns/auth_helper.rb'
|
- 'app/controllers/concerns/auth_helper.rb'
|
||||||
- 'db/migrate/20190819005836_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb'
|
- 'db/migrate/20190819005836_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb'
|
||||||
- 'db/migrate/20161123131628_devise_token_auth_create_users.rb'
|
- 'db/migrate/20161123131628_devise_token_auth_create_users.rb'
|
||||||
|
- 'app/controllers/api/v1/accounts/inboxes_controller.rb'
|
||||||
Metrics/CyclomaticComplexity:
|
Metrics/CyclomaticComplexity:
|
||||||
Max: 7
|
Max: 7
|
||||||
Exclude:
|
Exclude:
|
||||||
|
|
7
Gemfile
7
Gemfile
|
@ -63,7 +63,7 @@ gem 'barnes'
|
||||||
|
|
||||||
##--- gems for authentication & authorization ---##
|
##--- gems for authentication & authorization ---##
|
||||||
gem 'devise'
|
gem 'devise'
|
||||||
gem 'devise-secure_password', '~> 2.0'
|
gem 'devise-secure_password', '~> 2.0', git: 'https://github.com/chatwoot/devise-secure_password'
|
||||||
gem 'devise_token_auth'
|
gem 'devise_token_auth'
|
||||||
# authorization
|
# authorization
|
||||||
gem 'jwt'
|
gem 'jwt'
|
||||||
|
@ -78,7 +78,7 @@ gem 'wisper', '2.0.0'
|
||||||
##--- gems for channels ---##
|
##--- gems for channels ---##
|
||||||
# TODO: bump up gem to 2.0
|
# TODO: bump up gem to 2.0
|
||||||
gem 'facebook-messenger'
|
gem 'facebook-messenger'
|
||||||
gem 'telegram-bot-ruby'
|
gem 'line-bot-api'
|
||||||
gem 'twilio-ruby', '~> 5.32.0'
|
gem 'twilio-ruby', '~> 5.32.0'
|
||||||
# twitty will handle subscription of twitter account events
|
# twitty will handle subscription of twitter account events
|
||||||
# gem 'twitty', git: 'https://github.com/chatwoot/twitty'
|
# gem 'twitty', git: 'https://github.com/chatwoot/twitty'
|
||||||
|
@ -93,7 +93,10 @@ gem 'google-cloud-dialogflow'
|
||||||
##--- gems for debugging and error reporting ---##
|
##--- gems for debugging and error reporting ---##
|
||||||
# static analysis
|
# static analysis
|
||||||
gem 'brakeman'
|
gem 'brakeman'
|
||||||
|
|
||||||
|
##-- apm and error monitoring ---#
|
||||||
gem 'ddtrace'
|
gem 'ddtrace'
|
||||||
|
gem 'newrelic_rpm'
|
||||||
gem 'scout_apm'
|
gem 'scout_apm'
|
||||||
gem 'sentry-rails'
|
gem 'sentry-rails'
|
||||||
gem 'sentry-ruby'
|
gem 'sentry-ruby'
|
||||||
|
|
157
Gemfile.lock
157
Gemfile.lock
|
@ -1,63 +1,71 @@
|
||||||
|
GIT
|
||||||
|
remote: https://github.com/chatwoot/devise-secure_password
|
||||||
|
revision: de11e8765654b8242d42101ee9c8ffc8126f7975
|
||||||
|
specs:
|
||||||
|
devise-secure_password (2.0.1)
|
||||||
|
devise (>= 4.0.0, < 5.0.0)
|
||||||
|
railties (>= 5.0.0, < 7.0.0)
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.1.4)
|
actioncable (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.1.4)
|
actionmailbox (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
activejob (= 6.1.4)
|
activejob (= 6.1.4.1)
|
||||||
activerecord (= 6.1.4)
|
activerecord (= 6.1.4.1)
|
||||||
activestorage (= 6.1.4)
|
activestorage (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.1.4)
|
actionmailer (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
actionview (= 6.1.4)
|
actionview (= 6.1.4.1)
|
||||||
activejob (= 6.1.4)
|
activejob (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (6.1.4)
|
actionpack (6.1.4.1)
|
||||||
actionview (= 6.1.4)
|
actionview (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
rack (~> 2.0, >= 2.0.9)
|
rack (~> 2.0, >= 2.0.9)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||||
actiontext (6.1.4)
|
actiontext (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
activerecord (= 6.1.4)
|
activerecord (= 6.1.4.1)
|
||||||
activestorage (= 6.1.4)
|
activestorage (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.1.4)
|
actionview (6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||||
active_record_query_trace (1.8)
|
active_record_query_trace (1.8)
|
||||||
activejob (6.1.4)
|
activejob (6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.1.4)
|
activemodel (6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
activerecord (6.1.4)
|
activerecord (6.1.4.1)
|
||||||
activemodel (= 6.1.4)
|
activemodel (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
activerecord-import (1.2.0)
|
activerecord-import (1.2.0)
|
||||||
activerecord (>= 3.2)
|
activerecord (>= 3.2)
|
||||||
activestorage (6.1.4)
|
activestorage (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
activejob (= 6.1.4)
|
activejob (= 6.1.4.1)
|
||||||
activerecord (= 6.1.4)
|
activerecord (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
marcel (~> 1.0.0)
|
marcel (~> 1.0.0)
|
||||||
mini_mime (>= 1.1.0)
|
mini_mime (>= 1.1.0)
|
||||||
activesupport (6.1.4)
|
activesupport (6.1.4.1)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
|
@ -98,10 +106,6 @@ GEM
|
||||||
aws-sigv4 (~> 1.1)
|
aws-sigv4 (~> 1.1)
|
||||||
aws-sigv4 (1.2.4)
|
aws-sigv4 (1.2.4)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
axiom-types (0.1.1)
|
|
||||||
descendants_tracker (~> 0.0.4)
|
|
||||||
ice_nine (~> 0.11.0)
|
|
||||||
thread_safe (~> 0.3, >= 0.3.1)
|
|
||||||
azure-storage-blob (2.0.1)
|
azure-storage-blob (2.0.1)
|
||||||
azure-storage-common (~> 2.0)
|
azure-storage-common (~> 2.0)
|
||||||
nokogiri (~> 1.11.0.rc2)
|
nokogiri (~> 1.11.0.rc2)
|
||||||
|
@ -115,7 +119,7 @@ GEM
|
||||||
statsd-ruby (~> 1.1)
|
statsd-ruby (~> 1.1)
|
||||||
bcrypt (3.1.16)
|
bcrypt (3.1.16)
|
||||||
bindex (0.8.1)
|
bindex (0.8.1)
|
||||||
bootsnap (1.7.6)
|
bootsnap (1.7.7)
|
||||||
msgpack (~> 1.0)
|
msgpack (~> 1.0)
|
||||||
brakeman (5.1.1)
|
brakeman (5.1.1)
|
||||||
browser (5.3.1)
|
browser (5.3.1)
|
||||||
|
@ -130,8 +134,6 @@ GEM
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
byebug (11.1.3)
|
byebug (11.1.3)
|
||||||
coderay (1.1.3)
|
coderay (1.1.3)
|
||||||
coercible (1.0.0)
|
|
||||||
descendants_tracker (~> 0.0.1)
|
|
||||||
commonmarker (0.22.0)
|
commonmarker (0.22.0)
|
||||||
concurrent-ruby (1.1.9)
|
concurrent-ruby (1.1.9)
|
||||||
connection_pool (2.2.5)
|
connection_pool (2.2.5)
|
||||||
|
@ -152,17 +154,12 @@ GEM
|
||||||
ffi (~> 1.0)
|
ffi (~> 1.0)
|
||||||
msgpack
|
msgpack
|
||||||
declarative (0.0.20)
|
declarative (0.0.20)
|
||||||
descendants_tracker (0.0.4)
|
|
||||||
thread_safe (~> 0.3, >= 0.3.1)
|
|
||||||
devise (4.8.0)
|
devise (4.8.0)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
railties (>= 4.1.0)
|
railties (>= 4.1.0)
|
||||||
responders
|
responders
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
devise-secure_password (2.0.1)
|
|
||||||
devise (>= 4.0.0, < 5.0.0)
|
|
||||||
railties (>= 5.0.0, < 7.0.0)
|
|
||||||
devise_token_auth (1.2.0)
|
devise_token_auth (1.2.0)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
devise (> 3.5.2, < 5)
|
devise (> 3.5.2, < 5)
|
||||||
|
@ -179,7 +176,6 @@ GEM
|
||||||
railties (>= 3.2)
|
railties (>= 3.2)
|
||||||
down (5.2.3)
|
down (5.2.3)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
dry-inflector (0.2.1)
|
|
||||||
ecma-re-validator (0.3.0)
|
ecma-re-validator (0.3.0)
|
||||||
regexp_parser (~> 2.0)
|
regexp_parser (~> 2.0)
|
||||||
erubi (1.10.0)
|
erubi (1.10.0)
|
||||||
|
@ -216,7 +212,7 @@ GEM
|
||||||
grpc (~> 1.25)
|
grpc (~> 1.25)
|
||||||
geocoder (1.6.7)
|
geocoder (1.6.7)
|
||||||
gli (2.20.1)
|
gli (2.20.1)
|
||||||
globalid (0.5.1)
|
globalid (0.5.2)
|
||||||
activesupport (>= 5.0)
|
activesupport (>= 5.0)
|
||||||
google-apis-core (0.4.1)
|
google-apis-core (0.4.1)
|
||||||
addressable (~> 2.5, >= 2.5.1)
|
addressable (~> 2.5, >= 2.5.1)
|
||||||
|
@ -292,7 +288,6 @@ GEM
|
||||||
httpclient (2.8.3)
|
httpclient (2.8.3)
|
||||||
i18n (1.8.10)
|
i18n (1.8.10)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
ice_nine (0.11.2)
|
|
||||||
image_processing (1.12.1)
|
image_processing (1.12.1)
|
||||||
mini_magick (>= 4.9.5, < 5)
|
mini_magick (>= 4.9.5, < 5)
|
||||||
ruby-vips (>= 2.0.17, < 3)
|
ruby-vips (>= 2.0.17, < 3)
|
||||||
|
@ -332,11 +327,12 @@ GEM
|
||||||
addressable (~> 2.7)
|
addressable (~> 2.7)
|
||||||
letter_opener (1.7.0)
|
letter_opener (1.7.0)
|
||||||
launchy (~> 2.2)
|
launchy (~> 2.2)
|
||||||
|
line-bot-api (1.21.0)
|
||||||
liquid (5.0.1)
|
liquid (5.0.1)
|
||||||
listen (3.6.0)
|
listen (3.6.0)
|
||||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||||
rb-inotify (~> 0.9, >= 0.9.10)
|
rb-inotify (~> 0.9, >= 0.9.10)
|
||||||
loofah (2.11.0)
|
loofah (2.12.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.7.1)
|
mail (2.7.1)
|
||||||
|
@ -349,7 +345,7 @@ GEM
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2021.0704)
|
mime-types-data (3.2021.0704)
|
||||||
mini_magick (4.11.0)
|
mini_magick (4.11.0)
|
||||||
mini_mime (1.1.0)
|
mini_mime (1.1.1)
|
||||||
minitest (5.14.4)
|
minitest (5.14.4)
|
||||||
mock_redis (0.28.0)
|
mock_redis (0.28.0)
|
||||||
ruby2_keywords
|
ruby2_keywords
|
||||||
|
@ -362,7 +358,8 @@ GEM
|
||||||
net-http-persistent (4.0.1)
|
net-http-persistent (4.0.1)
|
||||||
connection_pool (~> 2.2)
|
connection_pool (~> 2.2)
|
||||||
netrc (0.11.0)
|
netrc (0.11.0)
|
||||||
nio4r (2.5.7)
|
newrelic_rpm (7.2.0)
|
||||||
|
nio4r (2.5.8)
|
||||||
nokogiri (1.11.7-arm64-darwin)
|
nokogiri (1.11.7-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.11.7-x86_64-darwin)
|
nokogiri (1.11.7-x86_64-darwin)
|
||||||
|
@ -400,29 +397,29 @@ GEM
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rack-timeout (0.6.0)
|
rack-timeout (0.6.0)
|
||||||
rails (6.1.4)
|
rails (6.1.4.1)
|
||||||
actioncable (= 6.1.4)
|
actioncable (= 6.1.4.1)
|
||||||
actionmailbox (= 6.1.4)
|
actionmailbox (= 6.1.4.1)
|
||||||
actionmailer (= 6.1.4)
|
actionmailer (= 6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
actiontext (= 6.1.4)
|
actiontext (= 6.1.4.1)
|
||||||
actionview (= 6.1.4)
|
actionview (= 6.1.4.1)
|
||||||
activejob (= 6.1.4)
|
activejob (= 6.1.4.1)
|
||||||
activemodel (= 6.1.4)
|
activemodel (= 6.1.4.1)
|
||||||
activerecord (= 6.1.4)
|
activerecord (= 6.1.4.1)
|
||||||
activestorage (= 6.1.4)
|
activestorage (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 6.1.4)
|
railties (= 6.1.4.1)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-dom-testing (2.0.3)
|
rails-dom-testing (2.0.3)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
rails-html-sanitizer (1.3.0)
|
rails-html-sanitizer (1.4.1)
|
||||||
loofah (~> 2.3)
|
loofah (~> 2.3)
|
||||||
railties (6.1.4)
|
railties (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.13)
|
rake (>= 0.13)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
|
@ -563,13 +560,8 @@ GEM
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
squasher (0.6.2)
|
squasher (0.6.2)
|
||||||
statsd-ruby (1.5.0)
|
statsd-ruby (1.5.0)
|
||||||
telegram-bot-ruby (0.16.0)
|
|
||||||
dry-inflector
|
|
||||||
faraday
|
|
||||||
virtus (~> 2.0)
|
|
||||||
telephone_number (1.4.12)
|
telephone_number (1.4.12)
|
||||||
thor (1.1.0)
|
thor (1.1.0)
|
||||||
thread_safe (0.3.6)
|
|
||||||
tilt (2.0.10)
|
tilt (2.0.10)
|
||||||
time_diff (0.3.0)
|
time_diff (0.3.0)
|
||||||
activesupport
|
activesupport
|
||||||
|
@ -597,10 +589,6 @@ GEM
|
||||||
valid_email2 (4.0.0)
|
valid_email2 (4.0.0)
|
||||||
activemodel (>= 3.2)
|
activemodel (>= 3.2)
|
||||||
mail (~> 2.5)
|
mail (~> 2.5)
|
||||||
virtus (2.0.0)
|
|
||||||
axiom-types (~> 0.1)
|
|
||||||
coercible (~> 1.0)
|
|
||||||
descendants_tracker (~> 0.0, >= 0.0.3)
|
|
||||||
warden (1.2.9)
|
warden (1.2.9)
|
||||||
rack (>= 2.0.9)
|
rack (>= 2.0.9)
|
||||||
web-console (4.1.0)
|
web-console (4.1.0)
|
||||||
|
@ -629,6 +617,8 @@ GEM
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
arm64-darwin-20
|
arm64-darwin-20
|
||||||
|
x86_64-darwin-18
|
||||||
|
x86_64-darwin-20
|
||||||
x86_64-darwin-21
|
x86_64-darwin-21
|
||||||
x86_64-linux
|
x86_64-linux
|
||||||
|
|
||||||
|
@ -653,7 +643,7 @@ DEPENDENCIES
|
||||||
database_cleaner
|
database_cleaner
|
||||||
ddtrace
|
ddtrace
|
||||||
devise
|
devise
|
||||||
devise-secure_password (~> 2.0)
|
devise-secure_password (~> 2.0)!
|
||||||
devise_token_auth
|
devise_token_auth
|
||||||
dotenv-rails
|
dotenv-rails
|
||||||
down (~> 5.0)
|
down (~> 5.0)
|
||||||
|
@ -678,10 +668,12 @@ DEPENDENCIES
|
||||||
kaminari
|
kaminari
|
||||||
koala
|
koala
|
||||||
letter_opener
|
letter_opener
|
||||||
|
line-bot-api
|
||||||
liquid
|
liquid
|
||||||
listen
|
listen
|
||||||
maxminddb
|
maxminddb
|
||||||
mock_redis
|
mock_redis
|
||||||
|
newrelic_rpm
|
||||||
pg
|
pg
|
||||||
procore-sift
|
procore-sift
|
||||||
pry-rails
|
pry-rails
|
||||||
|
@ -713,7 +705,6 @@ DEPENDENCIES
|
||||||
spring
|
spring
|
||||||
spring-watcher-listen
|
spring-watcher-listen
|
||||||
squasher
|
squasher
|
||||||
telegram-bot-ruby
|
|
||||||
telephone_number
|
telephone_number
|
||||||
time_diff
|
time_diff
|
||||||
twilio-ruby (~> 5.32.0)
|
twilio-ruby (~> 5.32.0)
|
||||||
|
|
|
@ -22,6 +22,8 @@ ___
|
||||||
<a title="Crowdin" target="_self" href="https://chatwoot.crowdin.com/chatwoot"><img src="https://badges.crowdin.net/e/37ced7eba411064bd792feb3b7a28b16/localized.svg"></a>
|
<a title="Crowdin" target="_self" href="https://chatwoot.crowdin.com/chatwoot"><img src="https://badges.crowdin.net/e/37ced7eba411064bd792feb3b7a28b16/localized.svg"></a>
|
||||||
<a href="https://discord.gg/cJXdrwS"><img src="https://img.shields.io/discord/647412545203994635" alt="Discord"></a>
|
<a href="https://discord.gg/cJXdrwS"><img src="https://img.shields.io/discord/647412545203994635" alt="Discord"></a>
|
||||||
<a href="https://huntr.dev/bounties/disclose"><img src="https://cdn.huntr.dev/huntr_security_badge_mono.svg" alt="Huntr"></a>
|
<a href="https://huntr.dev/bounties/disclose"><img src="https://cdn.huntr.dev/huntr_security_badge_mono.svg" alt="Huntr"></a>
|
||||||
|
<a href="https://status.chatwoot.com"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fchatwoot%2Fstatus%2Fmaster%2Fapi%2Fchatwoot%2Fuptime.json" alt="uptime"></a>
|
||||||
|
<a href="https://status.chatwoot.com"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fchatwoot%2Fstatus%2Fmaster%2Fapi%2Fchatwoot%2Fresponse-time.json" alt="response time"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<img src="https://s3.us-west-2.amazonaws.com/gh-assets.chatwoot.com/chatwoot-dashboard-assets.png" width="100%" alt="Chat dashboard"/>
|
<img src="https://s3.us-west-2.amazonaws.com/gh-assets.chatwoot.com/chatwoot-dashboard-assets.png" width="100%" alt="Chat dashboard"/>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class ContactMergeAction
|
class ContactMergeAction
|
||||||
|
include Events::Types
|
||||||
pattr_initialize [:account!, :base_contact!, :mergee_contact!]
|
pattr_initialize [:account!, :base_contact!, :mergee_contact!]
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
|
@ -11,7 +12,7 @@ class ContactMergeAction
|
||||||
merge_conversations
|
merge_conversations
|
||||||
merge_messages
|
merge_messages
|
||||||
merge_contact_inboxes
|
merge_contact_inboxes
|
||||||
remove_mergee_contact
|
merge_and_remove_mergee_contact
|
||||||
end
|
end
|
||||||
@base_contact
|
@base_contact
|
||||||
end
|
end
|
||||||
|
@ -40,7 +41,18 @@ class ContactMergeAction
|
||||||
ContactInbox.where(contact_id: @mergee_contact.id).update(contact_id: @base_contact.id)
|
ContactInbox.where(contact_id: @mergee_contact.id).update(contact_id: @base_contact.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_mergee_contact
|
def merge_and_remove_mergee_contact
|
||||||
|
mergable_attribute_keys = %w[identifier name email phone_number custom_attributes]
|
||||||
|
base_contact_attributes = base_contact.attributes.slice(*mergable_attribute_keys).compact_blank
|
||||||
|
mergee_contact_attributes = mergee_contact.attributes.slice(*mergable_attribute_keys).compact_blank
|
||||||
|
|
||||||
|
# attributes in base contact are given preference
|
||||||
|
merged_attributes = mergee_contact_attributes.deep_merge(base_contact_attributes)
|
||||||
|
# retaining old pubsub token to notify the contacts that are listening
|
||||||
|
mergee_pubsub_token = mergee_contact.pubsub_token
|
||||||
|
|
||||||
@mergee_contact.destroy!
|
@mergee_contact.destroy!
|
||||||
|
Rails.configuration.dispatcher.dispatch(CONTACT_MERGED, Time.zone.now, contact: @base_contact, tokens: [mergee_pubsub_token])
|
||||||
|
@base_contact.update!(merged_attributes)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,7 +43,7 @@ $woot-logo-padding: $space-large $space-two;
|
||||||
// Colors
|
// Colors
|
||||||
$color-woot: #1f93ff;
|
$color-woot: #1f93ff;
|
||||||
$color-gray: #6e6f73;
|
$color-gray: #6e6f73;
|
||||||
$color-light-gray: #999a9b;
|
$color-light-gray: #747677;
|
||||||
$color-border: #e0e6ed;
|
$color-border: #e0e6ed;
|
||||||
$color-border-light: #f0f4f5;
|
$color-border-light: #f0f4f5;
|
||||||
$color-background: #f4f6fb;
|
$color-background: #f4f6fb;
|
||||||
|
|
|
@ -148,6 +148,14 @@ class Messages::Facebook::MessageBuilder
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def process_contact_params_result(result)
|
||||||
|
{
|
||||||
|
name: "#{result['first_name'] || 'John'} #{result['last_name'] || 'Doe'}",
|
||||||
|
account_id: @inbox.account_id,
|
||||||
|
remote_avatar_url: result['profile_pic'] || ''
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def contact_params
|
def contact_params
|
||||||
begin
|
begin
|
||||||
k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook?
|
k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook?
|
||||||
|
@ -155,14 +163,15 @@ class Messages::Facebook::MessageBuilder
|
||||||
rescue Koala::Facebook::AuthenticationError
|
rescue Koala::Facebook::AuthenticationError
|
||||||
@inbox.channel.authorization_error!
|
@inbox.channel.authorization_error!
|
||||||
raise
|
raise
|
||||||
|
rescue Koala::Facebook::ClientError => e
|
||||||
|
result = {}
|
||||||
|
# OAuthException, code: 100, error_subcode: 2018218, message: (#100) No profile available for this user
|
||||||
|
# We don't need to capture this error as we don't care about contact params in case of echo messages
|
||||||
|
Sentry.capture_exception(e) unless outgoing_echo?
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
result = {}
|
result = {}
|
||||||
Sentry.capture_exception(e)
|
Sentry.capture_exception(e)
|
||||||
end
|
end
|
||||||
{
|
process_contact_params_result(result)
|
||||||
name: "#{result['first_name'] || 'John'} #{result['last_name'] || 'Doe'}",
|
|
||||||
account_id: @inbox.account_id,
|
|
||||||
remote_avatar_url: result['profile_pic'] || ''
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,21 +15,25 @@ class Messages::MessageBuilder
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
@message = @conversation.messages.build(message_params)
|
@message = @conversation.messages.build(message_params)
|
||||||
if @attachments.present?
|
process_attachments
|
||||||
@attachments.each do |uploaded_attachment|
|
@message.save!
|
||||||
attachment = @message.attachments.new(
|
|
||||||
account_id: @message.account_id,
|
|
||||||
file_type: file_type(uploaded_attachment&.content_type)
|
|
||||||
)
|
|
||||||
attachment.file.attach(uploaded_attachment)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@message.save
|
|
||||||
@message
|
@message
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def process_attachments
|
||||||
|
return if @attachments.blank?
|
||||||
|
|
||||||
|
@attachments.each do |uploaded_attachment|
|
||||||
|
@message.attachments.build(
|
||||||
|
account_id: @message.account_id,
|
||||||
|
file_type: file_type(uploaded_attachment&.content_type),
|
||||||
|
file: uploaded_attachment
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def message_type
|
def message_type
|
||||||
if @conversation.inbox.channel_type != 'Channel::Api' && @message_type == 'incoming'
|
if @conversation.inbox.channel_type != 'Channel::Api' && @message_type == 'incoming'
|
||||||
raise StandardError, 'Incoming messages are only allowed in Api inboxes'
|
raise StandardError, 'Incoming messages are only allowed in Api inboxes'
|
||||||
|
|
|
@ -4,7 +4,7 @@ class NotificationSubscriptionBuilder
|
||||||
def perform
|
def perform
|
||||||
# if multiple accounts were used to login in same browser
|
# if multiple accounts were used to login in same browser
|
||||||
move_subscription_to_user if identifier_subscription && identifier_subscription.user_id != user.id
|
move_subscription_to_user if identifier_subscription && identifier_subscription.user_id != user.id
|
||||||
build_identifier_subscription if identifier_subscription.blank?
|
identifier_subscription.blank? ? build_identifier_subscription : update_identifier_subscription
|
||||||
identifier_subscription
|
identifier_subscription
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -25,6 +25,10 @@ class NotificationSubscriptionBuilder
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_identifier_subscription
|
def build_identifier_subscription
|
||||||
user.notification_subscriptions.create(params.merge(identifier: identifier))
|
@identifier_subscription = user.notification_subscriptions.create(params.merge(identifier: identifier))
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_identifier_subscription
|
||||||
|
identifier_subscription.update(params.merge(identifier: identifier))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,9 +32,16 @@ class V2::ReportBuilder
|
||||||
private
|
private
|
||||||
|
|
||||||
def scope
|
def scope
|
||||||
return account if params[:type].match?('account')
|
case params[:type]
|
||||||
return inbox if params[:type].match?('inbox')
|
when :account
|
||||||
return user if params[:type].match?('agent')
|
account
|
||||||
|
when :inbox
|
||||||
|
inbox
|
||||||
|
when :agent
|
||||||
|
user
|
||||||
|
when :label
|
||||||
|
label
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def inbox
|
def inbox
|
||||||
|
@ -45,6 +52,10 @@ class V2::ReportBuilder
|
||||||
@user ||= account.users.where(id: params[:id]).first
|
@user ||= account.users.where(id: params[:id]).first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def label
|
||||||
|
@label ||= account.labels.where(id: params[:id]).first
|
||||||
|
end
|
||||||
|
|
||||||
def conversations_count
|
def conversations_count
|
||||||
scope.conversations
|
scope.conversations
|
||||||
.group_by_day(:created_at, range: range, default_value: 0)
|
.group_by_day(:created_at, range: range, default_value: 0)
|
||||||
|
|
|
@ -79,6 +79,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
||||||
@resolved_contacts = Current.account.contacts
|
@resolved_contacts = Current.account.contacts
|
||||||
.where.not(email: [nil, ''])
|
.where.not(email: [nil, ''])
|
||||||
.or(Current.account.contacts.where.not(phone_number: [nil, '']))
|
.or(Current.account.contacts.where.not(phone_number: [nil, '']))
|
||||||
|
.or(Current.account.contacts.where.not(identifier: [nil, '']))
|
||||||
@resolved_contacts = @resolved_contacts.tagged_with(params[:labels], any: true) if params[:labels].present?
|
@resolved_contacts = @resolved_contacts.tagged_with(params[:labels], any: true) if params[:labels].present?
|
||||||
@resolved_contacts
|
@resolved_contacts
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,20 +1,34 @@
|
||||||
class Api::V1::Accounts::Conversations::AssignmentsController < Api::V1::Accounts::Conversations::BaseController
|
class Api::V1::Accounts::Conversations::AssignmentsController < Api::V1::Accounts::Conversations::BaseController
|
||||||
# assigns agent/team to a conversation
|
# assigns agent/team to a conversation
|
||||||
def create
|
def create
|
||||||
set_assignee
|
if params.key?(:assignee_id)
|
||||||
render json: @assignee
|
set_agent
|
||||||
|
elsif params.key?(:team_id)
|
||||||
|
set_team
|
||||||
|
else
|
||||||
|
render json: nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_assignee
|
def set_agent
|
||||||
# if params[:assignee_id] is not a valid id, it will set to nil, hence unassigning the conversation
|
@agent = Current.account.users.find_by(id: params[:assignee_id])
|
||||||
if params.key?(:assignee_id)
|
@conversation.update_assignee(@agent)
|
||||||
@assignee = Current.account.users.find_by(id: params[:assignee_id])
|
render_agent
|
||||||
@conversation.update_assignee(@assignee)
|
end
|
||||||
elsif params.key?(:team_id)
|
|
||||||
@assignee = Current.account.teams.find_by(id: params[:team_id])
|
def render_agent
|
||||||
@conversation.update!(team: @assignee)
|
if @agent.nil?
|
||||||
|
render json: nil
|
||||||
|
else
|
||||||
|
render partial: 'api/v1/models/agent', formats: [:json], locals: { resource: @agent }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_team
|
||||||
|
@team = Current.account.teams.find_by(id: params[:team_id])
|
||||||
|
@conversation.update!(team: @team)
|
||||||
|
render json: @team
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,12 +31,13 @@ class Api::V1::Accounts::CustomAttributeDefinitionsController < Api::V1::Account
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_custom_attribute_definition
|
def fetch_custom_attribute_definition
|
||||||
@custom_attribute_definition = @custom_attribute_definitions.find(permitted_params[:id])
|
@custom_attribute_definition = Current.account.custom_attribute_definitions.find(permitted_params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def permitted_payload
|
def permitted_payload
|
||||||
params.require(:custom_attribute_definition).permit(
|
params.require(:custom_attribute_definition).permit(
|
||||||
:attribute_display_name,
|
:attribute_display_name,
|
||||||
|
:attribute_description,
|
||||||
:attribute_display_type,
|
:attribute_display_type,
|
||||||
:attribute_key,
|
:attribute_key,
|
||||||
:attribute_model,
|
:attribute_model,
|
||||||
|
@ -45,6 +46,6 @@ class Api::V1::Accounts::CustomAttributeDefinitionsController < Api::V1::Account
|
||||||
end
|
end
|
||||||
|
|
||||||
def permitted_params
|
def permitted_params
|
||||||
params.permit(:id, :filter_type)
|
params.permit(:id, :filter_type, :attribute_model)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,26 +1,40 @@
|
||||||
class Api::V1::Accounts::InboxMembersController < Api::V1::Accounts::BaseController
|
class Api::V1::Accounts::InboxMembersController < Api::V1::Accounts::BaseController
|
||||||
before_action :fetch_inbox, only: [:create, :show]
|
before_action :fetch_inbox
|
||||||
before_action :current_agents_ids, only: [:create]
|
before_action :current_agents_ids, only: [:update]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
authorize @inbox, :create?
|
authorize @inbox, :create?
|
||||||
begin
|
ActiveRecord::Base.transaction do
|
||||||
# update also done via same action
|
params[:user_ids].map { |user_id| @inbox.add_member(user_id) }
|
||||||
update_agents_list
|
|
||||||
head :ok
|
|
||||||
rescue StandardError => e
|
|
||||||
Rails.logger.debug { "Rescued: #{e.inspect}" }
|
|
||||||
render_could_not_create_error('Could not add agents to inbox')
|
|
||||||
end
|
end
|
||||||
|
fetch_updated_agents
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
authorize @inbox, :show?
|
authorize @inbox, :show?
|
||||||
@agents = Current.account.users.where(id: @inbox.members.select(:user_id))
|
fetch_updated_agents
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
authorize @inbox, :update?
|
||||||
|
update_agents_list
|
||||||
|
fetch_updated_agents
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
authorize @inbox, :destroy?
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
params[:user_ids].map { |user_id| @inbox.remove_member(user_id) }
|
||||||
|
end
|
||||||
|
head :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def fetch_updated_agents
|
||||||
|
@agents = Current.account.users.where(id: @inbox.members.select(:user_id))
|
||||||
|
end
|
||||||
|
|
||||||
def update_agents_list
|
def update_agents_list
|
||||||
# get all the user_ids which the inbox currently has as members.
|
# get all the user_ids which the inbox currently has as members.
|
||||||
# get the list of user_ids from params
|
# get the list of user_ids from params
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||||
before_action :fetch_inbox, except: [:index, :create]
|
before_action :fetch_inbox, except: [:index, :create]
|
||||||
before_action :fetch_agent_bot, only: [:set_agent_bot]
|
before_action :fetch_agent_bot, only: [:set_agent_bot]
|
||||||
before_action :check_authorization
|
# we are already handling the authorization in fetch inbox
|
||||||
|
before_action :check_authorization, except: [:show]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@inboxes = policy_scope(Current.account.inboxes.order_by_name.includes(:channel, { avatar_attachment: [:blob] }))
|
@inboxes = policy_scope(Current.account.inboxes.order_by_name.includes(:channel, { avatar_attachment: [:blob] }))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show; end
|
||||||
|
|
||||||
def assignable_agents
|
def assignable_agents
|
||||||
@assignable_agents = (Current.account.users.where(id: @inbox.members.select(:user_id)) + Current.account.administrators).uniq
|
@assignable_agents = (Current.account.users.where(id: @inbox.members.select(:user_id)) + Current.account.administrators).uniq
|
||||||
end
|
end
|
||||||
|
@ -15,26 +18,32 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||||
@campaigns = @inbox.campaigns
|
@campaigns = @inbox.campaigns
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def avatar
|
||||||
|
@inbox.avatar.attachment.destroy! if @inbox.avatar.attached?
|
||||||
|
head :ok
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
channel = create_channel
|
channel = create_channel
|
||||||
@inbox = Current.account.inboxes.build(
|
@inbox = Current.account.inboxes.build(
|
||||||
name: permitted_params[:name],
|
{
|
||||||
greeting_message: permitted_params[:greeting_message],
|
name: inbox_name(channel),
|
||||||
greeting_enabled: permitted_params[:greeting_enabled],
|
|
||||||
channel: channel
|
channel: channel
|
||||||
|
}.merge(
|
||||||
|
permitted_params.except(:channel)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
@inbox.avatar.attach(permitted_params[:avatar])
|
|
||||||
@inbox.save!
|
@inbox.save!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@inbox.update(inbox_update_params.except(:channel))
|
@inbox.update(permitted_params.except(:channel))
|
||||||
@inbox.update_working_hours(params.permit(working_hours: Inbox::OFFISABLE_ATTRS)[:working_hours]) if params[:working_hours]
|
@inbox.update_working_hours(params.permit(working_hours: Inbox::OFFISABLE_ATTRS)[:working_hours]) if params[:working_hours]
|
||||||
return unless @inbox.channel.is_a?(Channel::WebWidget) && inbox_update_params[:channel].present?
|
|
||||||
|
|
||||||
@inbox.channel.update!(inbox_update_params[:channel])
|
channel_attributes = get_channel_attributes(@inbox.channel_type)
|
||||||
|
@inbox.channel.update!(permitted_params(channel_attributes)[:channel]) if permitted_params(channel_attributes)[:channel].present?
|
||||||
update_channel_feature_flags
|
update_channel_feature_flags
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -69,43 +78,57 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||||
@agent_bot = AgentBot.find(params[:agent_bot]) if params[:agent_bot]
|
@agent_bot = AgentBot.find(params[:agent_bot]) if params[:agent_bot]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def inbox_name(channel)
|
||||||
|
return channel.try(:bot_name) if channel.is_a?(Channel::Telegram)
|
||||||
|
|
||||||
|
permitted_params[:name]
|
||||||
|
end
|
||||||
|
|
||||||
def create_channel
|
def create_channel
|
||||||
case permitted_params[:channel][:type]
|
case permitted_params[:channel][:type]
|
||||||
when 'web_widget'
|
when 'web_widget'
|
||||||
Current.account.web_widgets.create!(permitted_params[:channel].except(:type))
|
Current.account.web_widgets.create!(permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel].except(:type))
|
||||||
when 'api'
|
when 'api'
|
||||||
Current.account.api_channels.create!(permitted_params[:channel].except(:type))
|
Current.account.api_channels.create!(permitted_params(Channel::Api::EDITABLE_ATTRS)[:channel].except(:type))
|
||||||
when 'email'
|
when 'email'
|
||||||
Current.account.email_channels.create!(permitted_params[:channel].except(:type))
|
Current.account.email_channels.create!(permitted_params(Channel::Email::EDITABLE_ATTRS)[:channel].except(:type))
|
||||||
|
when 'line'
|
||||||
|
Current.account.line_channels.create!(permitted_params(Channel::Line::EDITABLE_ATTRS)[:channel].except(:type))
|
||||||
|
when 'telegram'
|
||||||
|
Current.account.telegram_channels.create!(permitted_params(Channel::Telegram::EDITABLE_ATTRS)[:channel].except(:type))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_channel_feature_flags
|
def update_channel_feature_flags
|
||||||
return unless inbox_update_params[:channel].key? :selected_feature_flags
|
return unless @inbox.web_widget?
|
||||||
|
return unless permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel].key? :selected_feature_flags
|
||||||
|
|
||||||
@inbox.channel.selected_feature_flags = inbox_update_params[:channel][:selected_feature_flags]
|
@inbox.channel.selected_feature_flags = permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel][:selected_feature_flags]
|
||||||
@inbox.channel.save!
|
@inbox.channel.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def permitted_params
|
def permitted_params(channel_attributes = [])
|
||||||
params.permit(:id, :avatar, :name, :greeting_message, :greeting_enabled, :enable_email_collect, :csat_survey_enabled, channel:
|
params.permit(
|
||||||
[:type, :website_url, :widget_color, :welcome_title, :welcome_tagline, :webhook_url, :email, :reply_time])
|
:name, :avatar, :greeting_enabled, :greeting_message, :enable_email_collect, :csat_survey_enabled,
|
||||||
|
:enable_auto_assignment, :working_hours_enabled, :out_of_office_message, :timezone,
|
||||||
|
channel: [:type, *channel_attributes]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def inbox_update_params
|
def get_channel_attributes(channel_type)
|
||||||
params.permit(:enable_auto_assignment, :enable_email_collect, :name, :avatar, :greeting_message, :greeting_enabled, :csat_survey_enabled,
|
case channel_type
|
||||||
:working_hours_enabled, :out_of_office_message, :timezone,
|
when 'Channel::WebWidget'
|
||||||
channel: [
|
Channel::WebWidget::EDITABLE_ATTRS
|
||||||
:website_url,
|
when 'Channel::Api'
|
||||||
:widget_color,
|
Channel::Api::EDITABLE_ATTRS
|
||||||
:welcome_title,
|
when 'Channel::Email'
|
||||||
:welcome_tagline,
|
Channel::Email::EDITABLE_ATTRS
|
||||||
:webhook_url,
|
when 'Channel::Telegram'
|
||||||
:email,
|
Channel::Telegram::EDITABLE_ATTRS
|
||||||
:reply_time,
|
when 'Channel::Line'
|
||||||
:pre_chat_form_enabled,
|
Channel::Line::EDITABLE_ATTRS
|
||||||
{ pre_chat_form_options: [:pre_chat_message, :require_email] },
|
else
|
||||||
{ selected_feature_flags: [] }
|
[]
|
||||||
])
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,8 +8,8 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@message = conversation.messages.new(message_params)
|
@message = conversation.messages.new(message_params)
|
||||||
@message.save
|
|
||||||
build_attachment
|
build_attachment
|
||||||
|
@message.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
@ -29,13 +29,12 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
|
||||||
return if params[:message][:attachments].blank?
|
return if params[:message][:attachments].blank?
|
||||||
|
|
||||||
params[:message][:attachments].each do |uploaded_attachment|
|
params[:message][:attachments].each do |uploaded_attachment|
|
||||||
attachment = @message.attachments.new(
|
@message.attachments.new(
|
||||||
account_id: @message.account_id,
|
account_id: @message.account_id,
|
||||||
file_type: helpers.file_type(uploaded_attachment&.content_type)
|
file_type: helpers.file_type(uploaded_attachment&.content_type),
|
||||||
|
file: uploaded_attachment
|
||||||
)
|
)
|
||||||
attachment.file.attach(uploaded_attachment)
|
|
||||||
end
|
end
|
||||||
@message.save!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_conversation
|
def set_conversation
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
|
class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
|
||||||
before_action :check_authorization
|
before_action :check_authorization
|
||||||
|
|
||||||
def account
|
def index
|
||||||
builder = V2::ReportBuilder.new(Current.account, account_report_params)
|
builder = V2::ReportBuilder.new(Current.account, report_params)
|
||||||
data = builder.build
|
data = builder.build
|
||||||
render json: data
|
render json: data
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_summary
|
def summary
|
||||||
render json: account_summary_metrics
|
render json: summary_metrics
|
||||||
end
|
end
|
||||||
|
|
||||||
def agents
|
def agents
|
||||||
|
@ -23,31 +23,39 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
|
||||||
render layout: false, template: 'api/v2/accounts/reports/inboxes.csv.erb', format: 'csv'
|
render layout: false, template: 'api/v2/accounts/reports/inboxes.csv.erb', format: 'csv'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def labels
|
||||||
|
response.headers['Content-Type'] = 'text/csv'
|
||||||
|
response.headers['Content-Disposition'] = 'attachment; filename=labels_report.csv'
|
||||||
|
render layout: false, template: 'api/v2/accounts/reports/labels.csv.erb', format: 'csv'
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def check_authorization
|
def check_authorization
|
||||||
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_summary_params
|
def summary_params
|
||||||
{
|
{
|
||||||
type: :account,
|
type: params[:type].to_sym,
|
||||||
since: params[:since],
|
since: params[:since],
|
||||||
until: params[:until]
|
until: params[:until],
|
||||||
|
id: params[:id]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_report_params
|
def report_params
|
||||||
{
|
{
|
||||||
metric: params[:metric],
|
metric: params[:metric],
|
||||||
type: :account,
|
type: params[:type].to_sym,
|
||||||
since: params[:since],
|
since: params[:since],
|
||||||
until: params[:until]
|
until: params[:until],
|
||||||
|
id: params[:id]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_summary_metrics
|
def summary_metrics
|
||||||
builder = V2::ReportBuilder.new(Current.account, account_summary_params)
|
builder = V2::ReportBuilder.new(Current.account, summary_params)
|
||||||
builder.summary
|
builder.summary
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
include DeviseTokenAuth::Concerns::SetUserByToken
|
include DeviseTokenAuth::Concerns::SetUserByToken
|
||||||
|
include RequestExceptionHandler
|
||||||
include Pundit
|
include Pundit
|
||||||
include SwitchLocale
|
include SwitchLocale
|
||||||
|
|
||||||
|
@ -9,22 +10,8 @@ class ApplicationController < ActionController::Base
|
||||||
around_action :switch_locale
|
around_action :switch_locale
|
||||||
around_action :handle_with_exception, unless: :devise_controller?
|
around_action :handle_with_exception, unless: :devise_controller?
|
||||||
|
|
||||||
rescue_from ActiveRecord::RecordInvalid, with: :render_record_invalid
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def handle_with_exception
|
|
||||||
yield
|
|
||||||
rescue ActiveRecord::RecordNotFound => e
|
|
||||||
Sentry.capture_exception(e)
|
|
||||||
render_not_found_error('Resource could not be found')
|
|
||||||
rescue Pundit::NotAuthorizedError
|
|
||||||
render_unauthorized('You are not authorized to do this action')
|
|
||||||
ensure
|
|
||||||
# to address the thread variable leak issues in Puma/Thin webserver
|
|
||||||
Current.reset
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_current_user
|
def set_current_user
|
||||||
@user ||= current_user
|
@user ||= current_user
|
||||||
Current.user = @user
|
Current.user = @user
|
||||||
|
@ -34,32 +21,6 @@ class ApplicationController < ActionController::Base
|
||||||
@subscription ||= Current.account.subscription
|
@subscription ||= Current.account.subscription
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_unauthorized(message)
|
|
||||||
render json: { error: message }, status: :unauthorized
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_not_found_error(message)
|
|
||||||
render json: { error: message }, status: :not_found
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_could_not_create_error(message)
|
|
||||||
render json: { error: message }, status: :unprocessable_entity
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_internal_server_error(message)
|
|
||||||
render json: { error: message }, status: :internal_server_error
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_record_invalid(exception)
|
|
||||||
render json: {
|
|
||||||
message: exception.record.errors.full_messages.join(', ')
|
|
||||||
}, status: :unprocessable_entity
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_error_response(exception)
|
|
||||||
render json: exception.to_hash, status: exception.http_status
|
|
||||||
end
|
|
||||||
|
|
||||||
def pundit_user
|
def pundit_user
|
||||||
{
|
{
|
||||||
user: Current.user,
|
user: Current.user,
|
||||||
|
|
47
app/controllers/concerns/request_exception_handler.rb
Normal file
47
app/controllers/concerns/request_exception_handler.rb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
module RequestExceptionHandler
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
rescue_from ActiveRecord::RecordInvalid, with: :render_record_invalid
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def handle_with_exception
|
||||||
|
yield
|
||||||
|
rescue ActiveRecord::RecordNotFound => e
|
||||||
|
Sentry.capture_exception(e)
|
||||||
|
render_not_found_error('Resource could not be found')
|
||||||
|
rescue Pundit::NotAuthorizedError
|
||||||
|
render_unauthorized('You are not authorized to do this action')
|
||||||
|
ensure
|
||||||
|
# to address the thread variable leak issues in Puma/Thin webserver
|
||||||
|
Current.reset
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_unauthorized(message)
|
||||||
|
render json: { error: message }, status: :unauthorized
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_not_found_error(message)
|
||||||
|
render json: { error: message }, status: :not_found
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_could_not_create_error(message)
|
||||||
|
render json: { error: message }, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_internal_server_error(message)
|
||||||
|
render json: { error: message }, status: :internal_server_error
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_record_invalid(exception)
|
||||||
|
render json: {
|
||||||
|
message: exception.record.errors.full_messages.join(', ')
|
||||||
|
}, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_error_response(exception)
|
||||||
|
render json: exception.to_hash, status: exception.http_status
|
||||||
|
end
|
||||||
|
end
|
|
@ -23,7 +23,9 @@ class DashboardController < ActionController::Base
|
||||||
'CREATE_NEW_ACCOUNT_FROM_DASHBOARD',
|
'CREATE_NEW_ACCOUNT_FROM_DASHBOARD',
|
||||||
'CHATWOOT_INBOX_TOKEN',
|
'CHATWOOT_INBOX_TOKEN',
|
||||||
'API_CHANNEL_NAME',
|
'API_CHANNEL_NAME',
|
||||||
'API_CHANNEL_THUMBNAIL'
|
'API_CHANNEL_THUMBNAIL',
|
||||||
|
'ANALYTICS_TOKEN',
|
||||||
|
'ANALYTICS_HOST'
|
||||||
).merge(
|
).merge(
|
||||||
APP_VERSION: Chatwoot.config[:version]
|
APP_VERSION: Chatwoot.config[:version]
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,7 +16,7 @@ class Platform::Api::V1::AccountsController < PlatformController
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
# TODO: obfusicate account
|
DeleteObjectJob.perform_later(@resource)
|
||||||
head :ok
|
head :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ class Platform::Api::V1::UsersController < PlatformController
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@resource = (User.find_by(email: user_params[:email]) || User.new(user_params))
|
@resource = (User.find_by(email: user_params[:email]) || User.new(user_params))
|
||||||
@resource.confirm
|
|
||||||
@resource.save!
|
@resource.save!
|
||||||
|
@resource.confirm
|
||||||
@platform_app.platform_app_permissibles.find_or_create_by(permissible: @resource)
|
@platform_app.platform_app_permissibles.find_or_create_by(permissible: @resource)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -19,21 +19,33 @@ class Platform::Api::V1::UsersController < PlatformController
|
||||||
def show; end
|
def show; end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@resource.update!(user_params)
|
@resource.assign_attributes(user_update_params)
|
||||||
|
@resource.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
# TODO: obfusicate user
|
DeleteObjectJob.perform_later(@resource)
|
||||||
head :ok
|
head :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def user_custom_attributes
|
||||||
|
return @resource.custom_attributes.merge(user_params[:custom_attributes]) if user_params[:custom_attributes]
|
||||||
|
|
||||||
|
@resource.custom_attributes
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_update_params
|
||||||
|
# we want the merged custom attributes not the original one
|
||||||
|
user_params.except(:custom_attributes).merge({ custom_attributes: user_custom_attributes })
|
||||||
|
end
|
||||||
|
|
||||||
def set_resource
|
def set_resource
|
||||||
@resource = User.find(params[:id])
|
@resource = User.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
params.permit(:name, :email, :password)
|
params.permit(:name, :email, :password, custom_attributes: {})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
class PlatformController < ActionController::API
|
class PlatformController < ActionController::API
|
||||||
|
include RequestExceptionHandler
|
||||||
|
|
||||||
before_action :ensure_access_token
|
before_action :ensure_access_token
|
||||||
before_action :set_platform_app
|
before_action :set_platform_app
|
||||||
before_action :set_resource, only: [:update, :show, :destroy]
|
before_action :set_resource, only: [:update, :show, :destroy]
|
||||||
|
|
|
@ -7,8 +7,8 @@ class Public::Api::V1::Inboxes::MessagesController < Public::Api::V1::InboxesCon
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@message = @conversation.messages.new(message_params)
|
@message = @conversation.messages.new(message_params)
|
||||||
@message.save
|
|
||||||
build_attachment
|
build_attachment
|
||||||
|
@message.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
@ -23,13 +23,12 @@ class Public::Api::V1::Inboxes::MessagesController < Public::Api::V1::InboxesCon
|
||||||
return if params[:attachments].blank?
|
return if params[:attachments].blank?
|
||||||
|
|
||||||
params[:attachments].each do |uploaded_attachment|
|
params[:attachments].each do |uploaded_attachment|
|
||||||
attachment = @message.attachments.new(
|
@message.attachments.new(
|
||||||
account_id: @message.account_id,
|
account_id: @message.account_id,
|
||||||
file_type: helpers.file_type(uploaded_attachment&.content_type)
|
file_type: helpers.file_type(uploaded_attachment&.content_type),
|
||||||
|
file: uploaded_attachment
|
||||||
)
|
)
|
||||||
attachment.file.attach(uploaded_attachment)
|
|
||||||
end
|
end
|
||||||
@message.save!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def message_finder_params
|
def message_finder_params
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# TODO: we should switch to ActionController::API for the base classes
|
# TODO: we should switch to ActionController::API for the base classes
|
||||||
# One of the specs is failing when I tried doing that, lets revisit in future
|
# One of the specs is failing when I tried doing that, lets revisit in future
|
||||||
class PublicController < ActionController::Base
|
class PublicController < ActionController::Base
|
||||||
|
include RequestExceptionHandler
|
||||||
skip_before_action :verify_authenticity_token
|
skip_before_action :verify_authenticity_token
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,10 +3,9 @@ class SuperAdmin::DashboardController < SuperAdmin::ApplicationController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@data = Conversation.unscoped.group_by_day(:created_at, range: 30.days.ago..2.seconds.ago).count.to_a
|
@data = Conversation.unscoped.group_by_day(:created_at, range: 30.days.ago..2.seconds.ago).count.to_a
|
||||||
@accounts_count = number_with_delimiter(Account.all.length)
|
@accounts_count = number_with_delimiter(Account.count)
|
||||||
@users_count = number_with_delimiter(User.all.length)
|
@users_count = number_with_delimiter(User.count)
|
||||||
@inboxes_count = number_with_delimiter(Inbox.all.length)
|
@inboxes_count = number_with_delimiter(Inbox.count)
|
||||||
@conversations_count = number_with_delimiter(Conversation.all.length)
|
@conversations_count = number_with_delimiter(Conversation.count)
|
||||||
@messages_count = number_with_delimiter(Message.all.length)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
6
app/controllers/webhooks/line_controller.rb
Normal file
6
app/controllers/webhooks/line_controller.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class Webhooks::LineController < ActionController::API
|
||||||
|
def process_payload
|
||||||
|
Webhooks::LineEventsJob.perform_later(params: params.to_unsafe_hash, signature: request.headers['x-line-signature'], post_body: request.raw_post)
|
||||||
|
head :ok
|
||||||
|
end
|
||||||
|
end
|
6
app/controllers/webhooks/telegram_controller.rb
Normal file
6
app/controllers/webhooks/telegram_controller.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class Webhooks::TelegramController < ActionController::API
|
||||||
|
def process_payload
|
||||||
|
Webhooks::TelegramEventsJob.perform_later(params.to_unsafe_hash)
|
||||||
|
head :ok
|
||||||
|
end
|
||||||
|
end
|
12
app/drops/message_drop.rb
Normal file
12
app/drops/message_drop.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
class MessageDrop < BaseDrop
|
||||||
|
include MessageFormatHelper
|
||||||
|
|
||||||
|
def sender_display_name
|
||||||
|
@obj.sender.try(:available_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def text_content
|
||||||
|
content = @obj.try(:content)
|
||||||
|
transform_user_mention_content content
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,12 +3,12 @@ module FileTypeHelper
|
||||||
return :image if [
|
return :image if [
|
||||||
'image/jpeg',
|
'image/jpeg',
|
||||||
'image/png',
|
'image/png',
|
||||||
'image/svg+xml',
|
|
||||||
'image/gif',
|
'image/gif',
|
||||||
'image/tiff',
|
'image/tiff',
|
||||||
'image/bmp'
|
'image/bmp'
|
||||||
].include?(content_type)
|
].include?(content_type)
|
||||||
|
|
||||||
|
return :video if content_type.include?('video/')
|
||||||
return :audio if content_type.include?('audio/')
|
return :audio if content_type.include?('audio/')
|
||||||
|
|
||||||
:file
|
:file
|
||||||
|
|
14
app/javascript/dashboard/api/attributes.js
Normal file
14
app/javascript/dashboard/api/attributes.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/* global axios */
|
||||||
|
import ApiClient from './ApiClient';
|
||||||
|
|
||||||
|
class AttributeAPI extends ApiClient {
|
||||||
|
constructor() {
|
||||||
|
super('custom_attribute_definitions', { accountScoped: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
getAttributesByModel(modelId) {
|
||||||
|
return axios.get(`${this.url}?attribute_model=${modelId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new AttributeAPI();
|
|
@ -6,8 +6,8 @@ class InboxMembers extends ApiClient {
|
||||||
super('inbox_members', { accountScoped: true });
|
super('inbox_members', { accountScoped: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
create({ inboxId, agentList }) {
|
update({ inboxId, agentList }) {
|
||||||
return axios.post(this.url, {
|
return axios.patch(this.url, {
|
||||||
inbox_id: inboxId,
|
inbox_id: inboxId,
|
||||||
user_ids: agentList,
|
user_ids: agentList,
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,6 +13,10 @@ class Inboxes extends ApiClient {
|
||||||
getCampaigns(inboxId) {
|
getCampaigns(inboxId) {
|
||||||
return axios.get(`${this.url}/${inboxId}/campaigns`);
|
return axios.get(`${this.url}/${inboxId}/campaigns`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteInboxAvatar(inboxId) {
|
||||||
|
return axios.delete(`${this.url}/${inboxId}/avatar`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Inboxes();
|
export default new Inboxes();
|
||||||
|
|
|
@ -7,14 +7,14 @@ class ReportsAPI extends ApiClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountReports(metric, since, until) {
|
getAccountReports(metric, since, until) {
|
||||||
return axios.get(`${this.url}/account`, {
|
return axios.get(`${this.url}`, {
|
||||||
params: { metric, since, until },
|
params: { metric, since, until, type: 'account' },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getAccountSummary(since, until) {
|
getAccountSummary(since, until) {
|
||||||
return axios.get(`${this.url}/account_summary`, {
|
return axios.get(`${this.url}/summary`, {
|
||||||
params: { since, until },
|
params: { since, until, type: 'account' },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,5 +27,12 @@ describe('#InboxesAPI', () => {
|
||||||
'/api/v1/inboxes/2/campaigns'
|
'/api/v1/inboxes/2/campaigns'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('#deleteInboxAvatar', () => {
|
||||||
|
inboxesAPI.deleteInboxAvatar(2);
|
||||||
|
expect(context.axiosMock.delete).toHaveBeenCalledWith(
|
||||||
|
'/api/v1/inboxes/2/avatar'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,12 +23,13 @@ describe('#Reports API', () => {
|
||||||
1621621800
|
1621621800
|
||||||
);
|
);
|
||||||
expect(context.axiosMock.get).toHaveBeenCalledWith(
|
expect(context.axiosMock.get).toHaveBeenCalledWith(
|
||||||
'/api/v2/reports/account',
|
'/api/v2/reports',
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
metric: 'conversations_count',
|
metric: 'conversations_count',
|
||||||
since: 1621103400,
|
since: 1621103400,
|
||||||
until: 1621621800,
|
until: 1621621800,
|
||||||
|
type: 'account'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -37,11 +38,12 @@ describe('#Reports API', () => {
|
||||||
it('#getAccountSummary', () => {
|
it('#getAccountSummary', () => {
|
||||||
reportsAPI.getAccountSummary(1621103400, 1621621800);
|
reportsAPI.getAccountSummary(1621103400, 1621621800);
|
||||||
expect(context.axiosMock.get).toHaveBeenCalledWith(
|
expect(context.axiosMock.get).toHaveBeenCalledWith(
|
||||||
'/api/v2/reports/account_summary',
|
'/api/v2/reports/summary',
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
since: 1621103400,
|
since: 1621103400,
|
||||||
until: 1621621800,
|
until: 1621621800,
|
||||||
|
type: 'account'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
@import 'shared/assets/stylesheets/font-weights';
|
@import 'shared/assets/stylesheets/font-weights';
|
||||||
@import 'shared/assets/stylesheets/shadows';
|
@import 'shared/assets/stylesheets/shadows';
|
||||||
@import 'shared/assets/stylesheets/border-radius';
|
@import 'shared/assets/stylesheets/border-radius';
|
||||||
|
@import 'shared/assets/stylesheets/z-index';
|
||||||
|
|
||||||
@import 'variables';
|
@import 'variables';
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.over {
|
&.over {
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
background: $color-woot;
|
background: $color-woot;
|
||||||
}
|
}
|
||||||
|
@ -132,10 +131,13 @@
|
||||||
@include padding($space-medium);
|
@include padding($space-medium);
|
||||||
@include border-light;
|
@include border-light;
|
||||||
@include full-height();
|
@include full-height();
|
||||||
|
|
||||||
|
&.height-auto {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.inoboxes-list {
|
.inoboxes-list {
|
||||||
|
|
||||||
.inbox-item {
|
.inbox-item {
|
||||||
@include margin($space-normal);
|
@include margin($space-normal);
|
||||||
@include flex;
|
@include flex;
|
||||||
|
@ -189,9 +191,9 @@
|
||||||
align-self: center;
|
align-self: center;
|
||||||
color: $medium-gray;
|
color: $medium-gray;
|
||||||
font-size: $font-size-small;
|
font-size: $font-size-small;
|
||||||
opacity: .7;
|
opacity: 0.7;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
transition: opacity 0.100s ease-in 0s, transform 0.200s ease-in 0.030s;
|
transition: opacity 0.1s ease-in 0s, transform 0.2s ease-in 0.03s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,10 @@
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
|
|
||||||
.conversation--details {
|
.conversation--details {
|
||||||
|
border-radius: var(--border-radius-small);
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
|
padding-left: var(--space-two);
|
||||||
|
padding-right: var(--space-small);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,10 +113,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: $space-small;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.unread--toast {
|
&.unread--toast {
|
||||||
|
+.right {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+.left {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
@include elegant-card;
|
@include elegant-card;
|
||||||
@include round-corner;
|
@include round-corner;
|
||||||
|
@ -140,6 +148,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
&.left {
|
&.left {
|
||||||
|
|
||||||
.bubble {
|
.bubble {
|
||||||
|
@ -183,6 +192,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+.unread--toast {
|
||||||
|
+.right {
|
||||||
|
margin-top: $space-one;
|
||||||
|
|
||||||
|
.bubble {
|
||||||
|
border-top-right-radius: $space-one;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+.left {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.right {
|
&.right {
|
||||||
|
@ -226,6 +248,21 @@
|
||||||
border-top-left-radius: $space-one;
|
border-top-left-radius: $space-one;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+.unread--toast {
|
||||||
|
+.left {
|
||||||
|
margin-top: $space-one;
|
||||||
|
|
||||||
|
.bubble {
|
||||||
|
border-top-left-radius: $space-one;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+.right {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.center {
|
&.center {
|
||||||
|
@ -259,11 +296,11 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: var(--space-small) var(--space-normal);
|
margin: var(--space-smaller) 0;
|
||||||
padding: var(--space-small) var(--space-normal);
|
padding: var(--space-smaller) var(--space-micro) var(--space-smaller) var(--space-one);
|
||||||
|
|
||||||
.is-text {
|
.is-text {
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
text-align: start;
|
text-align: start;
|
||||||
|
|
||||||
@include breakpoint(xxxlarge up) {
|
@include breakpoint(xxxlarge up) {
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { action } from '@storybook/addon-actions';
|
||||||
|
import AccordionItemComponent from './AccordionItem';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Components/Generic/Accordion',
|
||||||
|
component: AccordionItemComponent,
|
||||||
|
argTypes: {
|
||||||
|
title: {
|
||||||
|
control: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Template = (args, { argTypes }) => ({
|
||||||
|
props: Object.keys(argTypes),
|
||||||
|
components: { AccordionItem: AccordionItemComponent },
|
||||||
|
template: `
|
||||||
|
<accordion-item v-bind="$props" @click="onClick">
|
||||||
|
This is a sample content you can pass as a slot
|
||||||
|
</accordion-item>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const AccordionItem = Template.bind({});
|
||||||
|
AccordionItem.args = {
|
||||||
|
onClick: action('Added'),
|
||||||
|
title: 'Title of the accordion item',
|
||||||
|
};
|
110
app/javascript/dashboard/components/Accordion/AccordionItem.vue
Normal file
110
app/javascript/dashboard/components/Accordion/AccordionItem.vue
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
<template>
|
||||||
|
<div class="cw-accordion">
|
||||||
|
<button class="cw-accordion--title" @click="$emit('click')">
|
||||||
|
<div class="cw-accordion--title-wrap">
|
||||||
|
<emoji-or-icon class="icon-or-emoji" :icon="icon" :emoji="emoji" />
|
||||||
|
<h5>
|
||||||
|
{{ title }}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div class="button-icon--wrap">
|
||||||
|
<slot name="button" />
|
||||||
|
<div class="chevron-icon__wrap">
|
||||||
|
<i v-if="isOpen" class="ion-minus chevron-icon"></i>
|
||||||
|
<i v-else class="ion-plus chevron-icon"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<div v-if="isOpen" class="cw-accordion--content">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import EmojiOrIcon from 'shared/components/EmojiOrIcon';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
EmojiOrIcon,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
emoji: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
isOpen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.cw-accordion {
|
||||||
|
// This is done to fix contact sidebar border issues
|
||||||
|
// If you are using it else, find a fix to remove this hack
|
||||||
|
margin-top: -1px;
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
}
|
||||||
|
.cw-accordion--title {
|
||||||
|
align-items: center;
|
||||||
|
background: var(--b-50);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 0;
|
||||||
|
padding: var(--space-small) var(--space-normal);
|
||||||
|
user-select: none;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: var(--font-size-normal);
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 0 var(--space-small) 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cw-accordion--title-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: var(--space-micro);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-icon__wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-or-emoji {
|
||||||
|
display: inline-block;
|
||||||
|
width: var(--space-two);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-icon--wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chevron-icon__wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: var(--space-slab);
|
||||||
|
color: var(--w-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cw-accordion--content {
|
||||||
|
padding: var(--space-normal);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -194,7 +194,7 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleKeyEvents(e) {
|
getKeyboardListenerParams() {
|
||||||
const allConversations = this.$refs.activeConversation.querySelectorAll(
|
const allConversations = this.$refs.activeConversation.querySelectorAll(
|
||||||
'div.conversations-list div.conversation'
|
'div.conversations-list div.conversation'
|
||||||
);
|
);
|
||||||
|
@ -205,7 +205,19 @@ export default {
|
||||||
activeConversation
|
activeConversation
|
||||||
);
|
);
|
||||||
const lastConversationIndex = allConversations.length - 1;
|
const lastConversationIndex = allConversations.length - 1;
|
||||||
|
return {
|
||||||
|
allConversations,
|
||||||
|
activeConversation,
|
||||||
|
activeConversationIndex,
|
||||||
|
lastConversationIndex,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
handleKeyEvents(e) {
|
||||||
if (hasPressedAltAndJKey(e)) {
|
if (hasPressedAltAndJKey(e)) {
|
||||||
|
const {
|
||||||
|
allConversations,
|
||||||
|
activeConversationIndex,
|
||||||
|
} = this.getKeyboardListenerParams();
|
||||||
if (activeConversationIndex === -1) {
|
if (activeConversationIndex === -1) {
|
||||||
allConversations[0].click();
|
allConversations[0].click();
|
||||||
}
|
}
|
||||||
|
@ -214,6 +226,11 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasPressedAltAndKKey(e)) {
|
if (hasPressedAltAndKKey(e)) {
|
||||||
|
const {
|
||||||
|
allConversations,
|
||||||
|
activeConversationIndex,
|
||||||
|
lastConversationIndex,
|
||||||
|
} = this.getKeyboardListenerParams();
|
||||||
if (activeConversationIndex === -1) {
|
if (activeConversationIndex === -1) {
|
||||||
allConversations[lastConversationIndex].click();
|
allConversations[lastConversationIndex].click();
|
||||||
} else if (activeConversationIndex < lastConversationIndex) {
|
} else if (activeConversationIndex < lastConversationIndex) {
|
||||||
|
|
|
@ -54,7 +54,7 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
document.addEventListener('keydown', e => {
|
document.addEventListener('keydown', e => {
|
||||||
if (this.show && e.keyCode === 27) {
|
if (this.show && e.code === 'Escape') {
|
||||||
this.onClose();
|
this.onClose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -176,8 +176,10 @@ export default {
|
||||||
'.conversations-list .conversation'
|
'.conversations-list .conversation'
|
||||||
);
|
);
|
||||||
if (hasPressedAltAndMKey(e)) {
|
if (hasPressedAltAndMKey(e)) {
|
||||||
|
if (this.$refs.arrowDownButton) {
|
||||||
this.$refs.arrowDownButton.$el.click();
|
this.$refs.arrowDownButton.$el.click();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (hasPressedAltAndEKey(e)) {
|
if (hasPressedAltAndEKey(e)) {
|
||||||
const activeConversation = document.querySelector(
|
const activeConversation = document.querySelector(
|
||||||
'div.conversations-list div.conversation.active'
|
'div.conversations-list div.conversation.active'
|
||||||
|
@ -198,6 +200,7 @@ export default {
|
||||||
allConversations[0].click();
|
allConversations[0].click();
|
||||||
document.querySelector('.conversations-list').scrollTop = 0;
|
document.querySelector('.conversations-list').scrollTop = 0;
|
||||||
}
|
}
|
||||||
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -94,8 +94,16 @@ import AccountSelector from './sidebarComponents/AccountSelector.vue';
|
||||||
import AddAccountModal from './sidebarComponents/AddAccountModal.vue';
|
import AddAccountModal from './sidebarComponents/AddAccountModal.vue';
|
||||||
import AddLabelModal from '../../routes/dashboard/settings/labels/AddLabel';
|
import AddLabelModal from '../../routes/dashboard/settings/labels/AddLabel';
|
||||||
import WootKeyShortcutModal from 'components/widgets/modal/WootKeyShortcutModal';
|
import WootKeyShortcutModal from 'components/widgets/modal/WootKeyShortcutModal';
|
||||||
import { hasPressedCommandAndForwardSlash } from 'shared/helpers/KeyboardHelpers';
|
import {
|
||||||
|
hasPressedAltAndCKey,
|
||||||
|
hasPressedAltAndRKey,
|
||||||
|
hasPressedAltAndSKey,
|
||||||
|
hasPressedAltAndVKey,
|
||||||
|
hasPressedCommandAndForwardSlash,
|
||||||
|
isEscape,
|
||||||
|
} from 'shared/helpers/KeyboardHelpers';
|
||||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||||
|
import router from '../../routes';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -252,19 +260,11 @@ export default {
|
||||||
return frontendURL(`accounts/${this.accountId}/dashboard`);
|
return frontendURL(`accounts/${this.accountId}/dashboard`);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
currentUser(newUserInfo, oldUserInfo) {
|
|
||||||
if (!oldUserInfo.email && newUserInfo.email) {
|
|
||||||
this.setChatwootUser();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$store.dispatch('labels/get');
|
this.$store.dispatch('labels/get');
|
||||||
this.$store.dispatch('inboxes/get');
|
this.$store.dispatch('inboxes/get');
|
||||||
this.$store.dispatch('notifications/unReadCount');
|
this.$store.dispatch('notifications/unReadCount');
|
||||||
this.$store.dispatch('teams/get');
|
this.$store.dispatch('teams/get');
|
||||||
this.setChatwootUser();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -278,21 +278,34 @@ export default {
|
||||||
if (hasPressedCommandAndForwardSlash(e)) {
|
if (hasPressedCommandAndForwardSlash(e)) {
|
||||||
this.toggleKeyShortcutModal();
|
this.toggleKeyShortcutModal();
|
||||||
}
|
}
|
||||||
|
if (isEscape(e)) {
|
||||||
|
this.closeKeyShortcutModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasPressedAltAndCKey(e)) {
|
||||||
|
if (!this.isCurrentRouteSameAsNavigation('home')) {
|
||||||
|
router.push({ name: 'home' });
|
||||||
|
}
|
||||||
|
} else if (hasPressedAltAndVKey(e)) {
|
||||||
|
if (!this.isCurrentRouteSameAsNavigation('contacts_dashboard')) {
|
||||||
|
router.push({ name: 'contacts_dashboard' });
|
||||||
|
}
|
||||||
|
} else if (hasPressedAltAndRKey(e)) {
|
||||||
|
if (!this.isCurrentRouteSameAsNavigation('settings_account_reports')) {
|
||||||
|
router.push({ name: 'settings_account_reports' });
|
||||||
|
}
|
||||||
|
} else if (hasPressedAltAndSKey(e)) {
|
||||||
|
if (!this.isCurrentRouteSameAsNavigation('agent_list')) {
|
||||||
|
router.push({ name: 'agent_list' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isCurrentRouteSameAsNavigation(routeName) {
|
||||||
|
return router.currentRoute && router.currentRoute.name === routeName;
|
||||||
},
|
},
|
||||||
toggleSupportChatWindow() {
|
toggleSupportChatWindow() {
|
||||||
window.$chatwoot.toggle();
|
window.$chatwoot.toggle();
|
||||||
},
|
},
|
||||||
setChatwootUser() {
|
|
||||||
if (!this.currentUser.email || !this.globalConfig.chatwootInboxToken) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.$chatwoot.setUser(this.currentUser.email, {
|
|
||||||
name: this.currentUser.name,
|
|
||||||
email: this.currentUser.email,
|
|
||||||
avatar_url: this.currentUser.avatar_url,
|
|
||||||
identifier_hash: this.currentUser.hmac_identifier,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
filterMenuItemsByRole(menuItems) {
|
filterMenuItemsByRole(menuItems) {
|
||||||
if (!this.currentRole) {
|
if (!this.currentRole) {
|
||||||
return [];
|
return [];
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
<a href="#" :class="computedChildClass(child)">
|
<a href="#" :class="computedChildClass(child)">
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<i
|
<i
|
||||||
v-if="computedInboxClass(child)"
|
v-if="menuItem.key === 'inbox'"
|
||||||
class="inbox-icon"
|
class="inbox-icon"
|
||||||
:class="computedInboxClass(child)"
|
:class="computedInboxClass(child)"
|
||||||
/>
|
/>
|
||||||
|
@ -59,17 +59,10 @@
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
import router from '../../routes';
|
import router from '../../routes';
|
||||||
import {
|
|
||||||
hasPressedAltAndCKey,
|
|
||||||
hasPressedAltAndVKey,
|
|
||||||
hasPressedAltAndRKey,
|
|
||||||
hasPressedAltAndSKey,
|
|
||||||
} from 'shared/helpers/KeyboardHelpers';
|
|
||||||
import adminMixin from '../../mixins/isAdmin';
|
import adminMixin from '../../mixins/isAdmin';
|
||||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
|
||||||
import { getInboxClassByType } from 'dashboard/helper/inbox';
|
import { getInboxClassByType } from 'dashboard/helper/inbox';
|
||||||
export default {
|
export default {
|
||||||
mixins: [adminMixin, eventListenerMixins],
|
mixins: [adminMixin],
|
||||||
props: {
|
props: {
|
||||||
menuItem: {
|
menuItem: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -124,20 +117,6 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleKeyEvents(e) {
|
|
||||||
if (hasPressedAltAndCKey(e)) {
|
|
||||||
router.push({ name: 'home' });
|
|
||||||
}
|
|
||||||
if (hasPressedAltAndVKey(e)) {
|
|
||||||
router.push({ name: 'contacts_dashboard' });
|
|
||||||
}
|
|
||||||
if (hasPressedAltAndRKey(e)) {
|
|
||||||
router.push({ name: 'settings_account_reports' });
|
|
||||||
}
|
|
||||||
if (hasPressedAltAndSKey(e)) {
|
|
||||||
router.push({ name: 'settings_home' });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showItem(item) {
|
showItem(item) {
|
||||||
return this.isAdmin && item.newLink !== undefined;
|
return this.isAdmin && item.newLink !== undefined;
|
||||||
},
|
},
|
||||||
|
|
|
@ -94,10 +94,6 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
logout() {
|
logout() {
|
||||||
Auth.logout();
|
Auth.logout();
|
||||||
|
|
||||||
if (this.globalConfig.chatwootInboxToken) {
|
|
||||||
window.$chatwoot.reset();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -76,7 +76,16 @@ export default {
|
||||||
if (key === 'email') {
|
if (key === 'email') {
|
||||||
return this.enabledFeatures.channel_email;
|
return this.enabledFeatures.channel_email;
|
||||||
}
|
}
|
||||||
return ['website', 'twilio', 'api', 'whatsapp', 'sms'].includes(key);
|
|
||||||
|
return [
|
||||||
|
'website',
|
||||||
|
'twilio',
|
||||||
|
'api',
|
||||||
|
'whatsapp',
|
||||||
|
'sms',
|
||||||
|
'telegram',
|
||||||
|
'line',
|
||||||
|
].includes(key);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
|
||||||
<h6 class="text-block-title">
|
|
||||||
<i class="title-icon ion-pricetags" />
|
|
||||||
{{ $t('CONTACT_PANEL.LABELS.CONTACT.TITLE') }}
|
|
||||||
</h6>
|
|
||||||
<div v-on-clickaway="closeDropdownLabel" class="label-wrap">
|
<div v-on-clickaway="closeDropdownLabel" class="label-wrap">
|
||||||
<add-label @add="toggleLabels" />
|
<add-label @add="toggleLabels" />
|
||||||
<woot-label
|
<woot-label
|
||||||
|
@ -30,7 +25,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -96,7 +90,6 @@ export default {
|
||||||
|
|
||||||
.label-wrap {
|
.label-wrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-left: var(--space-two);
|
|
||||||
line-height: var(--space-medium);
|
line-height: var(--space-medium);
|
||||||
|
|
||||||
.dropdown-wrap {
|
.dropdown-wrap {
|
||||||
|
|
|
@ -35,6 +35,20 @@
|
||||||
:style="badgeStyle"
|
:style="badgeStyle"
|
||||||
src="~dashboard/assets/images/channels/whatsapp.png"
|
src="~dashboard/assets/images/channels/whatsapp.png"
|
||||||
/>
|
/>
|
||||||
|
<img
|
||||||
|
v-if="badge === 'Channel::Line'"
|
||||||
|
id="badge"
|
||||||
|
class="source-badge"
|
||||||
|
:style="badgeStyle"
|
||||||
|
src="~dashboard/assets/images/channels/line.png"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
v-if="badge === 'Channel::Telegram'"
|
||||||
|
id="badge"
|
||||||
|
class="source-badge"
|
||||||
|
:style="badgeStyle"
|
||||||
|
src="~dashboard/assets/images/channels/telegram.png"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="showStatusIndicator"
|
v-if="showStatusIndicator"
|
||||||
:class="`source-badge user-online-status user-online-status--${status}`"
|
:class="`source-badge user-online-status user-online-status--${status}`"
|
||||||
|
|
|
@ -38,6 +38,11 @@ import CannedResponse from '../conversation/CannedResponse';
|
||||||
const TYPING_INDICATOR_IDLE_TIME = 4000;
|
const TYPING_INDICATOR_IDLE_TIME = 4000;
|
||||||
|
|
||||||
import '@chatwoot/prosemirror-schema/src/woot-editor.css';
|
import '@chatwoot/prosemirror-schema/src/woot-editor.css';
|
||||||
|
import {
|
||||||
|
hasPressedAltAndPKey,
|
||||||
|
hasPressedAltAndLKey,
|
||||||
|
} from 'shared/helpers/KeyboardHelpers';
|
||||||
|
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||||
|
|
||||||
const createState = (content, placeholder, plugins = []) => {
|
const createState = (content, placeholder, plugins = []) => {
|
||||||
return EditorState.create({
|
return EditorState.create({
|
||||||
|
@ -53,6 +58,7 @@ const createState = (content, placeholder, plugins = []) => {
|
||||||
export default {
|
export default {
|
||||||
name: 'WootMessageEditor',
|
name: 'WootMessageEditor',
|
||||||
components: { TagAgents, CannedResponse },
|
components: { TagAgents, CannedResponse },
|
||||||
|
mixins: [eventListenerMixins],
|
||||||
props: {
|
props: {
|
||||||
value: { type: String, default: '' },
|
value: { type: String, default: '' },
|
||||||
placeholder: { type: String, default: '' },
|
placeholder: { type: String, default: '' },
|
||||||
|
@ -177,8 +183,20 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
this.focusEditorInputField();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleKeyEvents(e) {
|
||||||
|
if (hasPressedAltAndPKey(e)) {
|
||||||
|
this.focusEditorInputField();
|
||||||
|
}
|
||||||
|
if (hasPressedAltAndLKey(e)) {
|
||||||
|
this.focusEditorInputField();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
focusEditorInputField() {
|
||||||
|
this.$refs.editor.querySelector('div.ProseMirror-woot-style').focus();
|
||||||
|
},
|
||||||
insertMentionNode(mentionItem) {
|
insertMentionNode(mentionItem) {
|
||||||
if (!this.view) {
|
if (!this.view) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -11,10 +11,11 @@
|
||||||
@click="toggleEmojiPicker"
|
@click="toggleEmojiPicker"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- ensure the same validations for attachment types are implemented in backend models as well -->
|
||||||
<file-upload
|
<file-upload
|
||||||
ref="upload"
|
ref="upload"
|
||||||
:size="4096 * 4096"
|
:size="4096 * 4096"
|
||||||
accept="image/*, application/pdf, audio/mpeg, video/mp4, audio/ogg, text/csv"
|
accept="image/png, image/jpeg, image/gif, image/bmp, image/tiff, application/pdf, audio/mpeg, video/mp4, audio/ogg, text/csv"
|
||||||
:drop="true"
|
:drop="true"
|
||||||
:drop-directory="false"
|
:drop-directory="false"
|
||||||
@input-file="onFileUpload"
|
@input-file="onFileUpload"
|
||||||
|
|
|
@ -26,6 +26,24 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<woot-button
|
||||||
|
v-if="popoutReplyBox"
|
||||||
|
variant="clear"
|
||||||
|
size="large"
|
||||||
|
icon="ion-android-close"
|
||||||
|
color-scheme="secondary"
|
||||||
|
class-names="popout-button"
|
||||||
|
@click="$emit('click')"
|
||||||
|
/>
|
||||||
|
<woot-button
|
||||||
|
v-else
|
||||||
|
variant="clear"
|
||||||
|
size="large"
|
||||||
|
icon="ion-arrow-resize"
|
||||||
|
color-scheme="secondary"
|
||||||
|
class-names="popout-button"
|
||||||
|
@click="$emit('click')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -60,6 +78,10 @@ export default {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: () => 0,
|
default: () => 0,
|
||||||
},
|
},
|
||||||
|
popoutReplyBox: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
replyButtonClass() {
|
replyButtonClass() {
|
||||||
|
@ -105,7 +127,7 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
background: var(--b-100);
|
background: var(--b-50);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group {
|
.button-group {
|
||||||
|
@ -167,4 +189,11 @@ export default {
|
||||||
color: var(--s-600);
|
color: var(--s-600);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popout-button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
height: auto;
|
||||||
|
padding-right: var(--space-normal);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -119,7 +119,6 @@ export default {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
padding: var(--space-normal) var(--space-two);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
:message="message"
|
:message="message"
|
||||||
:is-email="isEmailContentType"
|
:is-email="isEmailContentType"
|
||||||
:readable-time="readableTime"
|
:readable-time="readableTime"
|
||||||
|
:display-quoted-button="displayQuotedButton"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
v-if="isPending && hasAttachments"
|
v-if="isPending && hasAttachments"
|
||||||
|
@ -36,7 +37,6 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<bubble-actions
|
<bubble-actions
|
||||||
:id="data.id"
|
:id="data.id"
|
||||||
:sender="data.sender"
|
:sender="data.sender"
|
||||||
|
@ -128,6 +128,24 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
contentToBeParsed() {
|
||||||
|
const {
|
||||||
|
html_content: { full: fullHTMLContent } = {},
|
||||||
|
text_content: { full: fullTextContent } = {},
|
||||||
|
} = this.contentAttributes.email || {};
|
||||||
|
return fullHTMLContent || fullTextContent || '';
|
||||||
|
},
|
||||||
|
displayQuotedButton() {
|
||||||
|
if (!this.isIncoming) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.contentToBeParsed.includes('<blockquote')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
message() {
|
message() {
|
||||||
const botMessageContent = generateBotMessageContent(
|
const botMessageContent = generateBotMessageContent(
|
||||||
this.contentType,
|
this.contentType,
|
||||||
|
@ -142,20 +160,10 @@ export default {
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
email: {
|
email: { content_type: contentType = '' } = {},
|
||||||
content_type: contentType = '',
|
|
||||||
html_content: { full: fullHTMLContent, reply: replyHTMLContent } = {},
|
|
||||||
text_content: { full: fullTextContent, reply: replyTextContent } = {},
|
|
||||||
} = {},
|
|
||||||
} = this.contentAttributes;
|
} = this.contentAttributes;
|
||||||
let contentToBeParsed =
|
if (this.contentToBeParsed && this.isIncoming) {
|
||||||
replyHTMLContent ||
|
const parsedContent = this.stripStyleCharacters(this.contentToBeParsed);
|
||||||
replyTextContent ||
|
|
||||||
fullHTMLContent ||
|
|
||||||
fullTextContent ||
|
|
||||||
'';
|
|
||||||
if (contentToBeParsed && this.isIncoming) {
|
|
||||||
const parsedContent = this.stripStyleCharacters(contentToBeParsed);
|
|
||||||
if (parsedContent) {
|
if (parsedContent) {
|
||||||
// This is a temporary fix for line-breaks in text/plain emails
|
// This is a temporary fix for line-breaks in text/plain emails
|
||||||
// Now, It is not rendered properly in the email preview.
|
// Now, It is not rendered properly in the email preview.
|
||||||
|
|
|
@ -78,7 +78,10 @@
|
||||||
:is-a-tweet="isATweet"
|
:is-a-tweet="isATweet"
|
||||||
/>
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="conversation-footer">
|
<div
|
||||||
|
class="conversation-footer"
|
||||||
|
:class="{ 'modal-mask': isPopoutReplyBox }"
|
||||||
|
>
|
||||||
<div v-if="isAnyoneTyping" class="typing-indicator-wrap">
|
<div v-if="isAnyoneTyping" class="typing-indicator-wrap">
|
||||||
<div class="typing-indicator">
|
<div class="typing-indicator">
|
||||||
{{ typingUserNames }}
|
{{ typingUserNames }}
|
||||||
|
@ -90,9 +93,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<reply-box
|
<reply-box
|
||||||
|
v-on-clickaway="closePopoutReplyBox"
|
||||||
:conversation-id="currentChat.id"
|
:conversation-id="currentChat.id"
|
||||||
:is-a-tweet="isATweet"
|
:is-a-tweet="isATweet"
|
||||||
:selected-tweet="selectedTweet"
|
:selected-tweet="selectedTweet"
|
||||||
|
:popout-reply-box="isPopoutReplyBox"
|
||||||
|
@click="showPopoutReplyBox"
|
||||||
@scrollToMessage="scrollToBottom"
|
@scrollToMessage="scrollToBottom"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -110,13 +116,16 @@ import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||||
import { REPLY_POLICY } from 'shared/constants/links';
|
import { REPLY_POLICY } from 'shared/constants/links';
|
||||||
import inboxMixin from 'shared/mixins/inboxMixin';
|
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||||
import { calculateScrollTop } from './helpers/scrollTopCalculationHelper';
|
import { calculateScrollTop } from './helpers/scrollTopCalculationHelper';
|
||||||
|
import { isEscape } from 'shared/helpers/KeyboardHelpers';
|
||||||
|
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||||
|
import { mixin as clickaway } from 'vue-clickaway';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Message,
|
Message,
|
||||||
ReplyBox,
|
ReplyBox,
|
||||||
},
|
},
|
||||||
mixins: [conversationMixin, inboxMixin],
|
mixins: [conversationMixin, inboxMixin, eventListenerMixins, clickaway],
|
||||||
props: {
|
props: {
|
||||||
isContactPanelOpen: {
|
isContactPanelOpen: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -130,6 +139,7 @@ export default {
|
||||||
heightBeforeLoad: null,
|
heightBeforeLoad: null,
|
||||||
conversationPanel: null,
|
conversationPanel: null,
|
||||||
selectedTweetId: null,
|
selectedTweetId: null,
|
||||||
|
isPopoutReplyBox: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -252,6 +262,17 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
showPopoutReplyBox() {
|
||||||
|
this.isPopoutReplyBox = !this.isPopoutReplyBox;
|
||||||
|
},
|
||||||
|
closePopoutReplyBox() {
|
||||||
|
this.isPopoutReplyBox = false;
|
||||||
|
},
|
||||||
|
handleKeyEvents(e) {
|
||||||
|
if (isEscape(e)) {
|
||||||
|
this.closePopoutReplyBox();
|
||||||
|
}
|
||||||
|
},
|
||||||
addScrollListener() {
|
addScrollListener() {
|
||||||
this.conversationPanel = this.$el.querySelector('.conversation-panel');
|
this.conversationPanel = this.$el.querySelector('.conversation-panel');
|
||||||
this.setScrollParams();
|
this.setScrollParams();
|
||||||
|
@ -361,4 +382,39 @@ export default {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-mask {
|
||||||
|
&::v-deep {
|
||||||
|
.ProseMirror-woot-style {
|
||||||
|
max-height: 40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-box {
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
max-width: 120rem;
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-box .reply-box__top {
|
||||||
|
position: relative;
|
||||||
|
min-height: 44rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-box__top .input {
|
||||||
|
min-height: 44rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-dialog {
|
||||||
|
position: fixed;
|
||||||
|
left: unset;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-dialog::before {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
left: 5px;
|
||||||
|
bottom: var(--space-minus-slab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a
|
<a
|
||||||
href="https://changelog.chatwoot.com"
|
href="https://www.chatwoot.com/changelog"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener nofollow noreferrer"
|
rel="noopener nofollow noreferrer"
|
||||||
class="onboarding--link"
|
class="onboarding--link"
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
:set-reply-mode="setReplyMode"
|
:set-reply-mode="setReplyMode"
|
||||||
:is-message-length-reaching-threshold="isMessageLengthReachingThreshold"
|
:is-message-length-reaching-threshold="isMessageLengthReachingThreshold"
|
||||||
:characters-remaining="charactersRemaining"
|
:characters-remaining="charactersRemaining"
|
||||||
|
:popout-reply-box="popoutReplyBox"
|
||||||
|
@click="$emit('click')"
|
||||||
/>
|
/>
|
||||||
<div class="reply-box__top">
|
<div class="reply-box__top">
|
||||||
<canned-response
|
<canned-response
|
||||||
|
@ -74,7 +76,6 @@
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { mixin as clickaway } from 'vue-clickaway';
|
import { mixin as clickaway } from 'vue-clickaway';
|
||||||
import alertMixin from 'shared/mixins/alertMixin';
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
|
||||||
|
|
||||||
import EmojiInput from 'shared/components/emoji/EmojiInput';
|
import EmojiInput from 'shared/components/emoji/EmojiInput';
|
||||||
import CannedResponse from './CannedResponse';
|
import CannedResponse from './CannedResponse';
|
||||||
|
@ -106,13 +107,7 @@ export default {
|
||||||
ReplyBottomPanel,
|
ReplyBottomPanel,
|
||||||
WootMessageEditor,
|
WootMessageEditor,
|
||||||
},
|
},
|
||||||
mixins: [
|
mixins: [clickaway, inboxMixin, uiSettingsMixin, alertMixin],
|
||||||
clickaway,
|
|
||||||
inboxMixin,
|
|
||||||
uiSettingsMixin,
|
|
||||||
alertMixin,
|
|
||||||
eventListenerMixins,
|
|
||||||
],
|
|
||||||
props: {
|
props: {
|
||||||
selectedTweet: {
|
selectedTweet: {
|
||||||
type: [Object, String],
|
type: [Object, String],
|
||||||
|
@ -122,6 +117,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
popoutReplyBox: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -222,7 +221,9 @@ export default {
|
||||||
this.isAWebWidgetInbox ||
|
this.isAWebWidgetInbox ||
|
||||||
this.isAFacebookInbox ||
|
this.isAFacebookInbox ||
|
||||||
this.isATwilioWhatsappChannel ||
|
this.isATwilioWhatsappChannel ||
|
||||||
this.isAPIInbox
|
this.isAPIInbox ||
|
||||||
|
this.isAnEmailChannel ||
|
||||||
|
this.isATwilioSMSChannel
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
replyButtonLabel() {
|
replyButtonLabel() {
|
||||||
|
@ -296,6 +297,15 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
// Donot use the keyboard listener mixin here as the events here are supposed to be
|
||||||
|
// working even if input/textarea is focussed.
|
||||||
|
document.addEventListener('keydown', this.handleKeyEvents);
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
document.removeEventListener('keydown', this.handleKeyEvents);
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleUserMention(currentMentionState) {
|
toggleUserMention(currentMentionState) {
|
||||||
this.hasUserMention = currentMentionState;
|
this.hasUserMention = currentMentionState;
|
||||||
|
@ -354,9 +364,6 @@ export default {
|
||||||
if (this.showRichContentEditor) {
|
if (this.showRichContentEditor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.$refs.messageInput === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.$nextTick(() => this.$refs.messageInput.focus());
|
this.$nextTick(() => this.$refs.messageInput.focus());
|
||||||
},
|
},
|
||||||
emojiOnClick(emoji) {
|
emojiOnClick(emoji) {
|
||||||
|
@ -390,13 +397,11 @@ export default {
|
||||||
this.isFocused = true;
|
this.isFocused = true;
|
||||||
},
|
},
|
||||||
toggleTyping(status) {
|
toggleTyping(status) {
|
||||||
if (this.isAWebWidgetInbox && !this.isPrivate) {
|
|
||||||
const conversationId = this.currentChat.id;
|
const conversationId = this.currentChat.id;
|
||||||
this.$store.dispatch('conversationTypingStatus/toggleTyping', {
|
this.$store.dispatch('conversationTypingStatus/toggleTyping', {
|
||||||
status,
|
status,
|
||||||
conversationId,
|
conversationId,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
},
|
||||||
onFileUpload(file) {
|
onFileUpload(file) {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
|
|
|
@ -1,6 +1,26 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="message-text__wrap">
|
<div
|
||||||
|
class="message-text__wrap"
|
||||||
|
:class="{
|
||||||
|
'show--quoted': showQuotedContent,
|
||||||
|
'hide--quoted': !showQuotedContent,
|
||||||
|
}"
|
||||||
|
>
|
||||||
<div class="text-content" v-html="message"></div>
|
<div class="text-content" v-html="message"></div>
|
||||||
|
<button
|
||||||
|
v-if="displayQuotedButton"
|
||||||
|
class="quoted-text--button"
|
||||||
|
@click="toggleQuotedContent"
|
||||||
|
>
|
||||||
|
<span v-if="showQuotedContent">
|
||||||
|
<i class="ion-chevron-up" />
|
||||||
|
{{ $t('CHAT_LIST.HIDE_QUOTED_TEXT') }}
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
<i class="ion-chevron-down" />
|
||||||
|
{{ $t('CHAT_LIST.SHOW_QUOTED_TEXT') }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -19,10 +39,24 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
displayQuotedButton: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showQuotedContent: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleQuotedContent() {
|
||||||
|
this.showQuotedContent = !this.showQuotedContent;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss">
|
||||||
.text-content {
|
.text-content {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
|
@ -32,5 +66,45 @@ export default {
|
||||||
margin-left: var(--space-normal);
|
margin-left: var(--space-normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
table {
|
||||||
|
all: revert;
|
||||||
|
|
||||||
|
td {
|
||||||
|
all: revert;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
all: revert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-size: var(--font-size-normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.show--quoted {
|
||||||
|
blockquote {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide--quoted {
|
||||||
|
blockquote {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quoted-text--button {
|
||||||
|
color: var(--s-400);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
padding-bottom: var(--space-small);
|
||||||
|
padding-top: var(--space-small);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,16 +1,32 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
<label>
|
<label>
|
||||||
<span v-if="label">{{ label }}</span>
|
<span v-if="label">{{ label }}</span>
|
||||||
|
</label>
|
||||||
<woot-thumbnail v-if="src" size="80px" :src="src" />
|
<woot-thumbnail v-if="src" size="80px" :src="src" />
|
||||||
|
<div v-if="src && deleteAvatar" class="avatar-delete-btn">
|
||||||
|
<woot-button
|
||||||
|
color-scheme="alert"
|
||||||
|
variant="hollow"
|
||||||
|
size="tiny"
|
||||||
|
@click="onAvatarDelete"
|
||||||
|
>{{
|
||||||
|
this.$t('INBOX_MGMT.DELETE.AVATAR_DELETE_BUTTON_TEXT')
|
||||||
|
}}</woot-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<label>
|
||||||
<input
|
<input
|
||||||
id="file"
|
id="file"
|
||||||
ref="file"
|
ref="file"
|
||||||
type="file"
|
type="file"
|
||||||
accept="image/*"
|
accept="image/png, image/jpeg, image/gif"
|
||||||
@change="handleImageUpload"
|
@change="handleImageUpload"
|
||||||
/>
|
/>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</label>
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -24,6 +40,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
deleteAvatar: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {},
|
watch: {},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -35,6 +55,17 @@ export default {
|
||||||
url: URL.createObjectURL(file),
|
url: URL.createObjectURL(file),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
onAvatarDelete() {
|
||||||
|
this.$refs.file.value = null;
|
||||||
|
this.$emit('onAvatarDelete');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.avatar-delete-btn {
|
||||||
|
margin-top: var(--space-smaller);
|
||||||
|
margin-bottom: var(--space-smaller);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
</h2>
|
</h2>
|
||||||
<div class="shortcut-key__wrap">
|
<div class="shortcut-key__wrap">
|
||||||
<p class="shortcut-key">
|
<p class="shortcut-key">
|
||||||
{{ $t('KEYBOARD_SHORTCUTS.KEYS.COMMAND_KEY') }}
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.WINDOWS_KEY_AND_COMMAND_KEY') }}
|
||||||
</p>
|
</p>
|
||||||
<p class="shortcut-key key">
|
<p class="shortcut-key key">
|
||||||
{{ $t('KEYBOARD_SHORTCUTS.KEYS.FORWARD_SLASH_KEY') }}
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.FORWARD_SLASH_KEY') }}
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
</span>
|
</span>
|
||||||
<div class="shortcut-key__wrap">
|
<div class="shortcut-key__wrap">
|
||||||
<span class="shortcut-key">
|
<span class="shortcut-key">
|
||||||
{{ $t('KEYBOARD_SHORTCUTS.KEYS.COMMAND_KEY') }}
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.WINDOWS_KEY_AND_COMMAND_KEY') }}
|
||||||
</span>
|
</span>
|
||||||
<span class="shortcut-key">
|
<span class="shortcut-key">
|
||||||
{{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }}
|
{{ $t('KEYBOARD_SHORTCUTS.KEYS.ALT_OR_OPTION_KEY') }}
|
||||||
|
|
|
@ -61,3 +61,10 @@ export const createPendingMessage = data => {
|
||||||
|
|
||||||
return pendingMessage;
|
return pendingMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const convertToSlug = text => {
|
||||||
|
return text
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^\w ]+/g, '')
|
||||||
|
.replace(/ +/g, '_');
|
||||||
|
};
|
||||||
|
|
|
@ -22,7 +22,10 @@ export const getInboxClassByType = (type, phoneNumber) => {
|
||||||
case INBOX_TYPES.EMAIL:
|
case INBOX_TYPES.EMAIL:
|
||||||
return 'ion-ios-email';
|
return 'ion-ios-email';
|
||||||
|
|
||||||
|
case INBOX_TYPES.TELEGRAM:
|
||||||
|
return 'ion-ios-navigate';
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return '';
|
return 'ion-ios-chatbubble';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
43
app/javascript/dashboard/helper/scriptHelpers.js
Normal file
43
app/javascript/dashboard/helper/scriptHelpers.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import posthog from 'posthog-js';
|
||||||
|
|
||||||
|
export const CHATWOOT_SET_USER = 'CHATWOOT_SET_USER';
|
||||||
|
export const CHATWOOT_RESET = 'CHATWOOT_RESET';
|
||||||
|
|
||||||
|
export const ANALYTICS_IDENTITY = 'ANALYTICS_IDENTITY';
|
||||||
|
export const ANALYTICS_RESET = 'ANALYTICS_RESET';
|
||||||
|
|
||||||
|
export const initializeAnalyticsEvents = () => {
|
||||||
|
window.bus.$on(ANALYTICS_IDENTITY, ({ user }) => {
|
||||||
|
if (window.analyticsConfig) {
|
||||||
|
posthog.identify(user.id, { name: user.name, email: user.email });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.bus.$on(ANALYTICS_RESET, () => {
|
||||||
|
if (window.analyticsConfig) {
|
||||||
|
posthog.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const initializeChatwootEvents = () => {
|
||||||
|
window.bus.$on(CHATWOOT_RESET, () => {
|
||||||
|
if (window.$chatwoot) {
|
||||||
|
window.$chatwoot.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.bus.$on(CHATWOOT_SET_USER, ({ user }) => {
|
||||||
|
if (window.$chatwoot) {
|
||||||
|
window.$chatwoot.setUser(user.email, {
|
||||||
|
avatar_url: user.avatar_url,
|
||||||
|
email: user.email,
|
||||||
|
identifier_hash: user.hmac_identifier,
|
||||||
|
name: user.name,
|
||||||
|
});
|
||||||
|
window.$chatwoot.setCustomAttributes({
|
||||||
|
signedUpAt: user.created_at,
|
||||||
|
cloudCustomer: 'true',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -1,4 +1,8 @@
|
||||||
import { getTypingUsersText, createPendingMessage } from '../commons';
|
import {
|
||||||
|
getTypingUsersText,
|
||||||
|
createPendingMessage,
|
||||||
|
convertToSlug,
|
||||||
|
} from '../commons';
|
||||||
|
|
||||||
describe('#getTypingUsersText', () => {
|
describe('#getTypingUsersText', () => {
|
||||||
it('returns the correct text is there is only one typing user', () => {
|
it('returns the correct text is there is only one typing user', () => {
|
||||||
|
@ -83,3 +87,9 @@ describe('#createPendingMessage', () => {
|
||||||
expect(pending.attachments.length).toBe(1);
|
expect(pending.attachments.length).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('convertToSlug', () => {
|
||||||
|
it('should convert to slug', () => {
|
||||||
|
expect(convertToSlug('Test@%^&*(){}>.!@`~_ ing')).toBe('test__ing');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -144,6 +144,7 @@ export const getSidebarItems = accountId => ({
|
||||||
'canned_list',
|
'canned_list',
|
||||||
'labels_list',
|
'labels_list',
|
||||||
'settings_inbox',
|
'settings_inbox',
|
||||||
|
'attributes_list',
|
||||||
'settings_inbox_new',
|
'settings_inbox_new',
|
||||||
'settings_inbox_list',
|
'settings_inbox_list',
|
||||||
'settings_inbox_show',
|
'settings_inbox_show',
|
||||||
|
@ -202,6 +203,13 @@ export const getSidebarItems = accountId => ({
|
||||||
toState: frontendURL(`accounts/${accountId}/settings/labels/list`),
|
toState: frontendURL(`accounts/${accountId}/settings/labels/list`),
|
||||||
toStateName: 'labels_list',
|
toStateName: 'labels_list',
|
||||||
},
|
},
|
||||||
|
attributes: {
|
||||||
|
icon: 'ion-code',
|
||||||
|
label: 'ATTRIBUTES',
|
||||||
|
hasSubMenu: false,
|
||||||
|
toState: frontendURL(`accounts/${accountId}/settings/attributes/list`),
|
||||||
|
toStateName: 'attributes_list',
|
||||||
|
},
|
||||||
cannedResponses: {
|
cannedResponses: {
|
||||||
icon: 'ion-chatbox-working',
|
icon: 'ion-chatbox-working',
|
||||||
label: 'CANNED_RESPONSES',
|
label: 'CANNED_RESPONSES',
|
||||||
|
|
|
@ -91,6 +91,23 @@
|
||||||
},
|
},
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"NO_RESULTS": "لم يتم العثور على النتائج."
|
"NO_RESULTS": "لم يتم العثور على النتائج."
|
||||||
|
},
|
||||||
|
"MULTI_SELECTOR": {
|
||||||
|
"PLACEHOLDER": "لا شيء",
|
||||||
|
"TITLE": {
|
||||||
|
"AGENT": "اختر وكيل",
|
||||||
|
"TEAM": "اختيار فريق"
|
||||||
|
},
|
||||||
|
"SEARCH": {
|
||||||
|
"NO_RESULTS": {
|
||||||
|
"AGENT": "لم يتم العثور على موظفين",
|
||||||
|
"TEAM": "لم يتم العثور على موظفين"
|
||||||
|
},
|
||||||
|
"PLACEHOLDER": {
|
||||||
|
"AGENT": "البحث عن وكلاء",
|
||||||
|
"TEAM": "البحث عن فريق"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
85
app/javascript/dashboard/i18n/locale/ar/attributesMgmt.json
Normal file
85
app/javascript/dashboard/i18n/locale/ar/attributesMgmt.json
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
{
|
||||||
|
"ATTRIBUTES_MGMT": {
|
||||||
|
"HEADER": "السمات",
|
||||||
|
"HEADER_BTN_TXT": "إضافة سمة",
|
||||||
|
"LOADING": "Fetching attributes",
|
||||||
|
"SIDEBAR_TXT": "<p><b>Attributes</b> <p>A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc. <br /><br />For creating a Attributes, just click on the <b>Add Attribute.</b> You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.</p>",
|
||||||
|
"ADD": {
|
||||||
|
"TITLE": "أضف سمة",
|
||||||
|
"SUBMIT": "إنشاء",
|
||||||
|
"CANCEL_BUTTON_TEXT": "إلغاء",
|
||||||
|
"FORM": {
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "اسم العرض",
|
||||||
|
"PLACEHOLDER": "أدخل اسم عرض السمة",
|
||||||
|
"ERROR": "Name is required"
|
||||||
|
},
|
||||||
|
"DESC": {
|
||||||
|
"LABEL": "الوصف",
|
||||||
|
"PLACEHOLDER": "أدخل وصف السمة",
|
||||||
|
"ERROR": "Description is required"
|
||||||
|
},
|
||||||
|
"MODEL": {
|
||||||
|
"LABEL": "نموذج",
|
||||||
|
"PLACEHOLDER": "الرجاء اختيار نموذج",
|
||||||
|
"ERROR": "النموذج مطلوب"
|
||||||
|
},
|
||||||
|
"TYPE": {
|
||||||
|
"LABEL": "النوع",
|
||||||
|
"PLACEHOLDER": "الرجاء تحديد نوع",
|
||||||
|
"ERROR": "النوع مطلوب"
|
||||||
|
},
|
||||||
|
"KEY": {
|
||||||
|
"LABEL": "المفتاح"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"API": {
|
||||||
|
"SUCCESS_MESSAGE": "تمت إضافة السمة بنجاح",
|
||||||
|
"ERROR_MESSAGE": "Could not able to create an attribute, Please try again later"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DELETE": {
|
||||||
|
"BUTTON_TEXT": "حذف",
|
||||||
|
"API": {
|
||||||
|
"SUCCESS_MESSAGE": "Attribute deleted successfully.",
|
||||||
|
"ERROR_MESSAGE": "Couldn't delete the attribute. Try again."
|
||||||
|
},
|
||||||
|
"CONFIRM": {
|
||||||
|
"TITLE": "هل أنت متأكد من أنك تريد حذف - %{attributeName}",
|
||||||
|
"PLACE_HOLDER": "Please type {attributeName} to confirm",
|
||||||
|
"MESSAGE": "Deleting will remove the attribute",
|
||||||
|
"YES": "حذف ",
|
||||||
|
"NO": "إلغاء"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"EDIT": {
|
||||||
|
"TITLE": "Edit attribute",
|
||||||
|
"UPDATE_BUTTON_TEXT": "تحديث",
|
||||||
|
"API": {
|
||||||
|
"SUCCESS_MESSAGE": "Attribute updated successfully",
|
||||||
|
"ERROR_MESSAGE": "There was an error updating attribute, please try again"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"TABS": {
|
||||||
|
"HEADER": "سمات مخصصة",
|
||||||
|
"CONVERSATION": "Conversation",
|
||||||
|
"CONTACT": "جهات الاتصال"
|
||||||
|
},
|
||||||
|
"LIST": {
|
||||||
|
"TABLE_HEADER": [
|
||||||
|
"الاسم",
|
||||||
|
"الوصف",
|
||||||
|
"النوع",
|
||||||
|
"المفتاح"
|
||||||
|
],
|
||||||
|
"BUTTONS": {
|
||||||
|
"EDIT": "تعديل",
|
||||||
|
"DELETE": "حذف"
|
||||||
|
},
|
||||||
|
"EMPTY_RESULT": {
|
||||||
|
"404": "There are no attributes created",
|
||||||
|
"NOT_FOUND": "There are no attributes configured"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,56 +1,64 @@
|
||||||
{
|
{
|
||||||
"CAMPAIGN": {
|
"CAMPAIGN": {
|
||||||
"HEADER": "Campaigns",
|
"HEADER": "الحملات",
|
||||||
"SIDEBAR_TXT": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations. Click on <b>Add Campaign</b> to create a new campaign. You can also edit or delete an existing campaign by clicking on the Edit or Delete button.",
|
"SIDEBAR_TXT": "الرسائل الاستباقية تسمح للعميل بإرسال رسائل صادرة إلى جهات اتصاله التي من شأنها أن تشغل المزيد من المحادثات. انقر فوق <b>أضف الحملة</b> لإنشاء حملة جديدة. يمكنك أيضا تعديل أو حذف حملة موجودة عن طريق النقر على زر التحرير أو الحذف.",
|
||||||
"HEADER_BTN_TXT": "Create a campaign",
|
"HEADER_BTN_TXT": {
|
||||||
|
"ONE_OFF": "إنشاء حملة واحدة مغلقة",
|
||||||
|
"ONGOING": "إنشاء حملة مستمرة"
|
||||||
|
},
|
||||||
"ADD": {
|
"ADD": {
|
||||||
"TITLE": "Create a campaign",
|
"TITLE": "إنشاء حملة",
|
||||||
"DESC": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations.",
|
"DESC": "الرسائل الاستباقية تسمح للعميل بإرسال رسائل صادرة إلى جهات اتصاله التي من شأنها أن تشغل المزيد من المحادثات.",
|
||||||
"CANCEL_BUTTON_TEXT": "إلغاء",
|
"CANCEL_BUTTON_TEXT": "إلغاء",
|
||||||
"CREATE_BUTTON_TEXT": "إنشاء",
|
"CREATE_BUTTON_TEXT": "إنشاء",
|
||||||
"FORM": {
|
"FORM": {
|
||||||
"TITLE": {
|
"TITLE": {
|
||||||
"LABEL": "Title",
|
"LABEL": "العنوان",
|
||||||
"PLACEHOLDER": "Please enter the title of campaign",
|
"PLACEHOLDER": "الرجاء إدخال عنوان الحملة",
|
||||||
"ERROR": "Title is required"
|
"ERROR": "العنوان مطلوب"
|
||||||
},
|
},
|
||||||
"SCHEDULED_AT": {
|
"SCHEDULED_AT": {
|
||||||
"LABEL": "Scheduled time",
|
"LABEL": "الوقت المجدول",
|
||||||
"PLACEHOLDER": "Please select the time",
|
"PLACEHOLDER": "الرجاء اختيار الوقت",
|
||||||
"CONFIRM": "Confirm",
|
"CONFIRM": "تأكيد",
|
||||||
"ERROR": "Scheduled time is required"
|
"ERROR": "الوقت المجدول مطلوب"
|
||||||
},
|
},
|
||||||
"AUDIENCE": {
|
"AUDIENCE": {
|
||||||
"LABEL": "Audience",
|
"LABEL": "الجمهور",
|
||||||
"PLACEHOLDER": "Select the customer labels",
|
"PLACEHOLDER": "حدد أوسمة العملاء",
|
||||||
"ERROR": "Audience is required"
|
"ERROR": "الجمهور مطلوب"
|
||||||
|
},
|
||||||
|
"INBOX": {
|
||||||
|
"LABEL": "اختر صندوق الوارد",
|
||||||
|
"PLACEHOLDER": "اختر صندوق الوارد",
|
||||||
|
"ERROR": "صندوق الوارد مطلوب"
|
||||||
},
|
},
|
||||||
"MESSAGE": {
|
"MESSAGE": {
|
||||||
"LABEL": "رسالة",
|
"LABEL": "رسالة",
|
||||||
"PLACEHOLDER": "Please enter the message of campaign",
|
"PLACEHOLDER": "الرجاء إدخال رسالة الحملة",
|
||||||
"ERROR": "Message is required"
|
"ERROR": "الرسالة مطلوبة"
|
||||||
},
|
},
|
||||||
"SENT_BY": {
|
"SENT_BY": {
|
||||||
"LABEL": "أرسلت بواسطة",
|
"LABEL": "أرسلت بواسطة",
|
||||||
"PLACEHOLDER": "Please select the the content of campaign",
|
"PLACEHOLDER": "الرجاء تحديد محتوى الحملة",
|
||||||
"ERROR": "Sender is required"
|
"ERROR": "المرسل مطلوب"
|
||||||
},
|
},
|
||||||
"END_POINT": {
|
"END_POINT": {
|
||||||
"LABEL": "URL",
|
"LABEL": "الرابط",
|
||||||
"PLACEHOLDER": "Please enter the URL",
|
"PLACEHOLDER": "الرجاء إدخال الرابط",
|
||||||
"ERROR": "الرجاء إدخال عنوان URL صالح"
|
"ERROR": "الرجاء إدخال عنوان URL صالح"
|
||||||
},
|
},
|
||||||
"TIME_ON_PAGE": {
|
"TIME_ON_PAGE": {
|
||||||
"LABEL": "Time on page(Seconds)",
|
"LABEL": "الوقت على الصفحة (ثواني)",
|
||||||
"PLACEHOLDER": "Please enter the time",
|
"PLACEHOLDER": "الرجاء إدخال الوقت",
|
||||||
"ERROR": "Time on page is required"
|
"ERROR": "الوقت على الصفحة مطلوب"
|
||||||
},
|
},
|
||||||
"ENABLED": "Enable campaign",
|
"ENABLED": "تفعيل الحملة",
|
||||||
"SUBMIT": "Add Campaign"
|
"SUBMIT": "إضافة حملة"
|
||||||
},
|
},
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS_MESSAGE": "Campaign created successfully",
|
"SUCCESS_MESSAGE": "تم إنشاء الحملة بنجاح",
|
||||||
"ERROR_MESSAGE": "There was an error. Please try again."
|
"ERROR_MESSAGE": "حدث خطأ، الرجاء المحاولة مرة أخرى."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"DELETE": {
|
"DELETE": {
|
||||||
|
@ -62,45 +70,56 @@
|
||||||
"NO": "لا، احتفظ "
|
"NO": "لا، احتفظ "
|
||||||
},
|
},
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS_MESSAGE": "Campaign deleted successfully",
|
"SUCCESS_MESSAGE": "تم حذف الحملة بنجاح",
|
||||||
"ERROR_MESSAGE": "Could not delete the campaign. Please try again later."
|
"ERROR_MESSAGE": "تعذر حذف الحملة. الرجاء المحاولة مرة أخرى لاحقاً."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"EDIT": {
|
"EDIT": {
|
||||||
"TITLE": "Edit campaign",
|
"TITLE": "تعديل الحملة",
|
||||||
"UPDATE_BUTTON_TEXT": "تحديث",
|
"UPDATE_BUTTON_TEXT": "تحديث",
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS_MESSAGE": "Campaign updated successfully",
|
"SUCCESS_MESSAGE": "تم تحديث الحملة بنجاح",
|
||||||
"ERROR_MESSAGE": "حدث خطأ، الرجاء المحاولة مرة أخرى"
|
"ERROR_MESSAGE": "حدث خطأ، الرجاء المحاولة مرة أخرى"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"LIST": {
|
"LIST": {
|
||||||
"LOADING_MESSAGE": "Loading campaigns...",
|
"LOADING_MESSAGE": "جاري تحميل الحملات...",
|
||||||
"404": "There are no campaigns created for this inbox.",
|
"404": "لا توجد حملات منشئة لهذا البريد الوارد.",
|
||||||
"TABLE_HEADER": {
|
"TABLE_HEADER": {
|
||||||
"TITLE": "Title",
|
"TITLE": "العنوان",
|
||||||
"MESSAGE": "رسالة",
|
"MESSAGE": "رسالة",
|
||||||
|
"INBOX": "صندوق الوارد",
|
||||||
"STATUS": "الحالة",
|
"STATUS": "الحالة",
|
||||||
"SENDER": "Sender",
|
"SENDER": "المرسل",
|
||||||
"URL": "URL",
|
"URL": "الرابط",
|
||||||
"SCHEDULED_AT": "Scheduled time",
|
"SCHEDULED_AT": "الوقت المجدول",
|
||||||
"TIME_ON_PAGE": "Time(Seconds)",
|
"TIME_ON_PAGE": "الوقت(ثواني)",
|
||||||
"CREATED_AT": "Created at"
|
"CREATED_AT": "تم إنشاؤها في"
|
||||||
},
|
},
|
||||||
"BUTTONS": {
|
"BUTTONS": {
|
||||||
"ADD": "Add",
|
"ADD": "إضافة",
|
||||||
"EDIT": "تعديل",
|
"EDIT": "تعديل",
|
||||||
"DELETE": "حذف"
|
"DELETE": "حذف"
|
||||||
},
|
},
|
||||||
"STATUS": {
|
"STATUS": {
|
||||||
"ENABLED": "مفعل",
|
"ENABLED": "مفعل",
|
||||||
"DISABLED": "معطّل",
|
"DISABLED": "معطّل",
|
||||||
"COMPLETED": "Completed",
|
"COMPLETED": "مكتمل",
|
||||||
"ACTIVE": "Active"
|
"ACTIVE": "مفعل"
|
||||||
},
|
},
|
||||||
"SENDER": {
|
"SENDER": {
|
||||||
"BOT": "رد آلي"
|
"BOT": "رد آلي"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ONE_OFF": {
|
||||||
|
"HEADER": "حملة واحدة مغلقة",
|
||||||
|
"404": "لم يتم إنشاء أي حملة ",
|
||||||
|
"INBOXES_NOT_FOUND": "الرجاء إنشاء بريد وارد للرسائل القصيرة ثم إبدء في إضافة حملات"
|
||||||
|
},
|
||||||
|
"ONGOING": {
|
||||||
|
"HEADER": "الحملات المستمرة",
|
||||||
|
"404": "لا توجد حملات مستمرة منشئة",
|
||||||
|
"INBOXES_NOT_FOUND": "الرجاء إنشاء بريد وارد لمحادثات الموقع الحية ثم إبدء في إضافة حملات"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,12 @@
|
||||||
"VALUE": "resolved"
|
"VALUE": "resolved"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"TEXT": "رد آلي",
|
"TEXT": "معلق",
|
||||||
"VALUE": "bot"
|
"VALUE": "pending"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TEXT": "غفوة",
|
||||||
|
"VALUE": "snoozed"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ATTACHMENTS": {
|
"ATTACHMENTS": {
|
||||||
|
@ -81,6 +85,6 @@
|
||||||
"VIEW_TWEET_IN_TWITTER": "عرض التغريدة في تويتر",
|
"VIEW_TWEET_IN_TWITTER": "عرض التغريدة في تويتر",
|
||||||
"REPLY_TO_TWEET": "الرد على هذه التغريدة",
|
"REPLY_TO_TWEET": "الرد على هذه التغريدة",
|
||||||
"NO_MESSAGES": "لا توجد رسائل",
|
"NO_MESSAGES": "لا توجد رسائل",
|
||||||
"NO_CONTENT": "No content available"
|
"NO_CONTENT": "لم يتم العثور على محتوى"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,24 +12,24 @@
|
||||||
"INITIATED_FROM": "تم البدء من",
|
"INITIATED_FROM": "تم البدء من",
|
||||||
"INITIATED_AT": "تم البدء في",
|
"INITIATED_AT": "تم البدء في",
|
||||||
"IP_ADDRESS": "عنوان IP",
|
"IP_ADDRESS": "عنوان IP",
|
||||||
"NEW_MESSAGE": "New message",
|
"NEW_MESSAGE": "رسالة جديدة",
|
||||||
"CONVERSATIONS": {
|
"CONVERSATIONS": {
|
||||||
"NO_RECORDS_FOUND": "لا توجد محادثات سابقة مرتبطة بجهة الاتصال هذه.",
|
"NO_RECORDS_FOUND": "لا توجد محادثات سابقة مرتبطة بجهة الاتصال هذه.",
|
||||||
"TITLE": "المحادثات السابقة"
|
"TITLE": "المحادثات السابقة"
|
||||||
},
|
},
|
||||||
"LABELS": {
|
"LABELS": {
|
||||||
"CONTACT": {
|
"CONTACT": {
|
||||||
"TITLE": "Contact Labels",
|
"TITLE": "تصنفيات جهات الاتصال",
|
||||||
"ERROR": "Couldn't update labels"
|
"ERROR": "تعذر تحديث التصنيفات"
|
||||||
},
|
},
|
||||||
"CONVERSATION": {
|
"CONVERSATION": {
|
||||||
"TITLE": "وسوم المحادثة",
|
"TITLE": "وسوم المحادثة",
|
||||||
"ADD_BUTTON": "Add Labels"
|
"ADD_BUTTON": "اضافة تصنيف جديد"
|
||||||
},
|
},
|
||||||
"LABEL_SELECT": {
|
"LABEL_SELECT": {
|
||||||
"TITLE": "Add Labels",
|
"TITLE": "اضافة تصنيف جديد",
|
||||||
"PLACEHOLDER": "Search labels",
|
"PLACEHOLDER": "ابحث عن تصنيفات",
|
||||||
"NO_RESULT": "No labels found"
|
"NO_RESULT": "لم يتم العثور على تصنيفات"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"MUTE_CONTACT": "كتم المحادثة",
|
"MUTE_CONTACT": "كتم المحادثة",
|
||||||
|
@ -37,7 +37,12 @@
|
||||||
"MUTED_SUCCESS": "تم كتم هذه المحادثة لمدة 6 ساعات",
|
"MUTED_SUCCESS": "تم كتم هذه المحادثة لمدة 6 ساعات",
|
||||||
"UNMUTED_SUCCESS": "تم إلغاء كتم هذه المحادثة",
|
"UNMUTED_SUCCESS": "تم إلغاء كتم هذه المحادثة",
|
||||||
"SEND_TRANSCRIPT": "إرسال النص",
|
"SEND_TRANSCRIPT": "إرسال النص",
|
||||||
"EDIT_LABEL": "تعديل"
|
"EDIT_LABEL": "تعديل",
|
||||||
|
"SIDEBAR_SECTIONS": {
|
||||||
|
"CUSTOM_ATTRIBUTES": "سمات مخصصة",
|
||||||
|
"CONTACT_LABELS": "تصنفيات جهات الاتصال",
|
||||||
|
"PREVIOUS_CONVERSATIONS": "المحادثات السابقة"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"EDIT_CONTACT": {
|
"EDIT_CONTACT": {
|
||||||
"BUTTON_LABEL": "تعديل جهة الاتصال",
|
"BUTTON_LABEL": "تعديل جهة الاتصال",
|
||||||
|
@ -71,8 +76,8 @@
|
||||||
"PHONE_NUMBER": {
|
"PHONE_NUMBER": {
|
||||||
"PLACEHOLDER": "أدخل رقم الهاتف الخاص بجهة الاتصال",
|
"PLACEHOLDER": "أدخل رقم الهاتف الخاص بجهة الاتصال",
|
||||||
"LABEL": "رقم الهاتف",
|
"LABEL": "رقم الهاتف",
|
||||||
"HELP": "Phone number should be of E.164 format eg: +1415555555 [+][country code][area code][local phone number]",
|
"HELP": "يجب ان يحتوى رقم الهاتف على كود دولتك تسبقها علامة +\nمثال: +20101243567",
|
||||||
"ERROR": "Phone number should be either empty or of E.164 format"
|
"ERROR": "يجب ان تكون خانة رقم الهاتف إما فارغة او مكتملة مع رمز الدولة"
|
||||||
},
|
},
|
||||||
"LOCATION": {
|
"LOCATION": {
|
||||||
"PLACEHOLDER": "أدخل موقع جهة الاتصال",
|
"PLACEHOLDER": "أدخل موقع جهة الاتصال",
|
||||||
|
@ -106,38 +111,38 @@
|
||||||
"ERROR_MESSAGE": "حدث خطأ، الرجاء المحاولة مرة أخرى"
|
"ERROR_MESSAGE": "حدث خطأ، الرجاء المحاولة مرة أخرى"
|
||||||
},
|
},
|
||||||
"NEW_CONVERSATION": {
|
"NEW_CONVERSATION": {
|
||||||
"BUTTON_LABEL": "Start conversation",
|
"BUTTON_LABEL": "محادثة جديدة",
|
||||||
"TITLE": "محادثة جديدة",
|
"TITLE": "محادثة جديدة",
|
||||||
"DESC": "Start a new conversation by sending a new message.",
|
"DESC": "بدء محادثة جديدة بإرسال رسالة جديدة.",
|
||||||
"NO_INBOX": "Couldn't find an inbox to initiate a new conversation with this contact.",
|
"NO_INBOX": "تعذر العثور على صندوق الوارد لبدء محادثة جديدة مع جهة الاتصال هذه.",
|
||||||
"FORM": {
|
"FORM": {
|
||||||
"TO": {
|
"TO": {
|
||||||
"LABEL": "To"
|
"LABEL": "إلى"
|
||||||
},
|
},
|
||||||
"INBOX": {
|
"INBOX": {
|
||||||
"LABEL": "Inbox",
|
"LABEL": "صندوق الوارد",
|
||||||
"ERROR": "Select an inbox"
|
"ERROR": "حدد صندوق الوارد"
|
||||||
},
|
},
|
||||||
"MESSAGE": {
|
"MESSAGE": {
|
||||||
"LABEL": "رسالة",
|
"LABEL": "رسالة",
|
||||||
"PLACEHOLDER": "Write your message here",
|
"PLACEHOLDER": "اكتب رسالتك هنا",
|
||||||
"ERROR": "Message can't be empty"
|
"ERROR": "لا يمكن أن تكون الرسالة فارغة"
|
||||||
},
|
},
|
||||||
"SUBMIT": "Send message",
|
"SUBMIT": "إرسال الرسالة",
|
||||||
"CANCEL": "إلغاء",
|
"CANCEL": "إلغاء",
|
||||||
"SUCCESS_MESSAGE": "Message sent!",
|
"SUCCESS_MESSAGE": "تم إرسال الرسالة!",
|
||||||
"ERROR_MESSAGE": "Couldn't send! try again"
|
"ERROR_MESSAGE": "تعذر الإرسال! حاول مرة أخرى"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CONTACTS_PAGE": {
|
"CONTACTS_PAGE": {
|
||||||
"HEADER": "جهات الاتصال",
|
"HEADER": "جهات الاتصال",
|
||||||
"FIELDS": "Contact fields",
|
"FIELDS": "تصنفيات جهات الاتصال",
|
||||||
"SEARCH_BUTTON": "بحث",
|
"SEARCH_BUTTON": "بحث",
|
||||||
"SEARCH_INPUT_PLACEHOLDER": "بحث عن جهات الاتصال",
|
"SEARCH_INPUT_PLACEHOLDER": "بحث عن جهات الاتصال",
|
||||||
"LIST": {
|
"LIST": {
|
||||||
"LOADING_MESSAGE": "جاري تحميل جهات الاتصال...",
|
"LOADING_MESSAGE": "جاري تحميل جهات الاتصال...",
|
||||||
"404": "لا توجد جهات اتصال تطابق بحثك 🔍",
|
"404": "لا توجد جهات اتصال تطابق بحثك 🔍",
|
||||||
"NO_CONTACTS": "There are no available contacts",
|
"NO_CONTACTS": "لا توجد جهات اتصال متوفرة",
|
||||||
"TABLE_HEADER": {
|
"TABLE_HEADER": {
|
||||||
"NAME": "الاسم",
|
"NAME": "الاسم",
|
||||||
"PHONE_NUMBER": "رقم الهاتف",
|
"PHONE_NUMBER": "رقم الهاتف",
|
||||||
|
@ -154,84 +159,84 @@
|
||||||
},
|
},
|
||||||
"REMINDER": {
|
"REMINDER": {
|
||||||
"ADD_BUTTON": {
|
"ADD_BUTTON": {
|
||||||
"BUTTON": "Add",
|
"BUTTON": "إضافة",
|
||||||
"TITLE": "Shift + Enter to create a task"
|
"TITLE": "Shift + Enter لإنشاء مهمة"
|
||||||
},
|
},
|
||||||
"FOOTER": {
|
"FOOTER": {
|
||||||
"DUE_DATE": "Due date",
|
"DUE_DATE": "تاريخ التسليم",
|
||||||
"LABEL_TITLE": "Set type"
|
"LABEL_TITLE": "تعيين النوع"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"NOTES": {
|
"NOTES": {
|
||||||
"HEADER": {
|
"HEADER": {
|
||||||
"TITLE": "Notes"
|
"TITLE": "ملاحظات"
|
||||||
},
|
},
|
||||||
"ADD": {
|
"ADD": {
|
||||||
"BUTTON": "Add",
|
"BUTTON": "إضافة",
|
||||||
"PLACEHOLDER": "Add a note",
|
"PLACEHOLDER": "إضافة ملاحظة",
|
||||||
"TITLE": "Shift + Enter to create a note"
|
"TITLE": "Shift + Enter لإنشاء مهمة"
|
||||||
},
|
},
|
||||||
"FOOTER": {
|
"FOOTER": {
|
||||||
"BUTTON": "View all notes"
|
"BUTTON": "عرض جميع الملاحظات"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"EVENTS": {
|
"EVENTS": {
|
||||||
"HEADER": {
|
"HEADER": {
|
||||||
"TITLE": "Activities"
|
"TITLE": "الأنشطة"
|
||||||
},
|
},
|
||||||
"BUTTON": {
|
"BUTTON": {
|
||||||
"PILL_BUTTON_NOTES": "notes",
|
"PILL_BUTTON_NOTES": "ملاحظات",
|
||||||
"PILL_BUTTON_EVENTS": "events",
|
"PILL_BUTTON_EVENTS": "الأحداث",
|
||||||
"PILL_BUTTON_CONVO": "المحادثات"
|
"PILL_BUTTON_CONVO": "المحادثات"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CUSTOM_ATTRIBUTES": {
|
"CUSTOM_ATTRIBUTES": {
|
||||||
"TITLE": "سمات مخصصة",
|
"BUTTON": "إضافة سمة خاصة",
|
||||||
"BUTTON": "Add custom attribute",
|
"NOT_AVAILABLE": "There are no custom attributes available for this contact.",
|
||||||
"ADD": {
|
"ADD": {
|
||||||
"TITLE": "Create custom attribute",
|
"TITLE": "إنشاء سمة خاصة",
|
||||||
"DESC": "Add custom information to this contact."
|
"DESC": "أضف معلومات خاصة إلى جهة الاتصال هذه."
|
||||||
},
|
},
|
||||||
"FORM": {
|
"FORM": {
|
||||||
"CREATE": "Add attribute",
|
"CREATE": "أضف سمة",
|
||||||
"CANCEL": "إلغاء",
|
"CANCEL": "إلغاء",
|
||||||
"NAME": {
|
"NAME": {
|
||||||
"LABEL": "Custom attribute name",
|
"LABEL": "اسم السمة الخاصة",
|
||||||
"PLACEHOLDER": "Eg: shopify id",
|
"PLACEHOLDER": "مثال: shopify id",
|
||||||
"ERROR": "Invalid custom attribute name"
|
"ERROR": "اسم السمة المخصصة غير صالح"
|
||||||
},
|
},
|
||||||
"VALUE": {
|
"VALUE": {
|
||||||
"LABEL": "Attribute value",
|
"LABEL": "قيمة السمة",
|
||||||
"PLACEHOLDER": "Eg: 11901 "
|
"PLACEHOLDER": "Eg: 11901 "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"MERGE_CONTACTS": {
|
"MERGE_CONTACTS": {
|
||||||
"TITLE": "Merge contacts",
|
"TITLE": "دمج جهة الاتصال",
|
||||||
"DESCRIPTION": "Merge contact is helpful when you have duplicated entries of the same contact. Merging action takes a primary contact and a child contact. After merging, all details in the primary contact will remain the same. If the primary contact doesn't have a field, then the value from the child contact will be used after merging. If a conflict happens, fields in primary contact will remain unaffected, but fields from secondary will be copied to the custom attributes in the primary contact.",
|
"DESCRIPTION": "دمج جهة الاتصال مفيد عندما يكون لديك مدخلات مكررة لنفس جهة الاتصال. عملية الدمج تأخذ جهة اتصال رئيسية وتدمجها بجهة الاتصال المكررة. بعد الدمج، ستبقى جميع التفاصيل في جهة الاتصال الرئيسية كما هي. إذا لم يكن لدى جهة الاتصال الرئيسية حقل ، فسيتم استخدام القيمة من جهة الاتصال المكررة بعد الدمج. إذا حدث تضارب بالبيانات، ستبقى الحقول في جهة الاتصال الأساسية غير متأثرة، ولكن الحقول من جهة الاتصال الثانوية سيتم نسخها إلى السمات المخصصة في جهة الاتصال الرئيسية.",
|
||||||
"PRIMARY": {
|
"PRIMARY": {
|
||||||
"TITLE": "Primary contact"
|
"TITLE": "جهة الاتصال الرئيسية"
|
||||||
},
|
},
|
||||||
"CHILD": {
|
"CHILD": {
|
||||||
"TITLE": "Contact to merge",
|
"TITLE": "دمج جهة الإتصال",
|
||||||
"PLACEHOLDER": "Choose a contact"
|
"PLACEHOLDER": "اختر جهة اتصال"
|
||||||
},
|
},
|
||||||
"SUMMARY": {
|
"SUMMARY": {
|
||||||
"TITLE": "Summary",
|
"TITLE": "ملخص",
|
||||||
"DELETE_WARNING": "Contact of <strong>%{childContactName}</strong>will be deleted.",
|
"DELETE_WARNING": "الاتصال بـ <strong>%{childContactName}</strong>سيتم حذفه.",
|
||||||
"ATTRIBUTE_WARNING": "Contact details of <strong>%{childContactName}</strong> will be copied to <strong>%{primaryContactName}</strong>."
|
"ATTRIBUTE_WARNING": "سيتم نسخ تفاصيل الاتصال بـ <strong>%{childContactName}</strong> إلى <strong>%{primaryContactName}</strong>."
|
||||||
},
|
},
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"ERROR": "ERROR_MESSAGE"
|
"ERROR": "رسالة_خطأ"
|
||||||
},
|
},
|
||||||
"FORM": {
|
"FORM": {
|
||||||
"SUBMIT": " Merge contacts",
|
"SUBMIT": " دمج جهة الاتصال",
|
||||||
"CANCEL": "إلغاء",
|
"CANCEL": "إلغاء",
|
||||||
"CHILD_CONTACT": {
|
"CHILD_CONTACT": {
|
||||||
"ERROR": "Select a child contact to merge"
|
"ERROR": "حدد جهة اتصال فرعية للدمج"
|
||||||
},
|
},
|
||||||
"SUCCESS_MESSAGE": "Contact merged successfully",
|
"SUCCESS_MESSAGE": "تم دمج جهة الاتصال بنجاح",
|
||||||
"ERROR_MESSAGE": "Could not merge contcts, try again!"
|
"ERROR_MESSAGE": "تعذر دمج جهات الاتصال ، حاول مرة أخرى!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"SEARCH_MESSAGES": "البحث عن رسائل في المحادثات",
|
"SEARCH_MESSAGES": "البحث عن رسائل في المحادثات",
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"TITLE": "البحث في الرسائل",
|
"TITLE": "البحث في الرسائل",
|
||||||
|
"RESULT_TITLE": "نتائج البحث",
|
||||||
"LOADING_MESSAGE": "جار تجزئة البيانات...",
|
"LOADING_MESSAGE": "جار تجزئة البيانات...",
|
||||||
"PLACEHOLDER": "اكتب أي نص للبحث في الرسائل",
|
"PLACEHOLDER": "اكتب أي نص للبحث في الرسائل",
|
||||||
"NO_MATCHING_RESULTS": "لم يتم العثور على النتائج."
|
"NO_MATCHING_RESULTS": "لم يتم العثور على النتائج."
|
||||||
|
@ -20,18 +21,18 @@
|
||||||
"LOADING_CONVERSATIONS": "جاري تحميل المحادثات",
|
"LOADING_CONVERSATIONS": "جاري تحميل المحادثات",
|
||||||
"CANNOT_REPLY": "لا يمكنك الرد بسبب",
|
"CANNOT_REPLY": "لا يمكنك الرد بسبب",
|
||||||
"24_HOURS_WINDOW": "قيد نافذة الـ 24 ساعة",
|
"24_HOURS_WINDOW": "قيد نافذة الـ 24 ساعة",
|
||||||
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
|
"TWILIO_WHATSAPP_CAN_REPLY": "يمكنك فقط الرد على هذه المحادثة باستخدام رسالة قالب بسبب",
|
||||||
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "قيد نافذة الـ 24 ساعة",
|
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "قيد نافذة الـ 24 ساعة",
|
||||||
"LAST_INCOMING_TWEET": "أنت ترد على آخر تغريدة واردة",
|
"SELECT_A_TWEET_TO_REPLY": "الرجاء تحديد تغريدة للرد عليها.",
|
||||||
"REPLYING_TO": "أنت ترد على:",
|
"REPLYING_TO": "أنت ترد على:",
|
||||||
"REMOVE_SELECTION": "إزالة التحديد",
|
"REMOVE_SELECTION": "إزالة التحديد",
|
||||||
"DOWNLOAD": "تنزيل",
|
"DOWNLOAD": "تنزيل",
|
||||||
"UPLOADING_ATTACHMENTS": "جاري تحميل المرفقات...",
|
"UPLOADING_ATTACHMENTS": "جاري تحميل المرفقات...",
|
||||||
"SUCCESS_DELETE_MESSAGE": "Message deleted successfully",
|
"SUCCESS_DELETE_MESSAGE": "تم حذف الرسالة بنجاح",
|
||||||
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again",
|
"FAIL_DELETE_MESSSAGE": "تعذر حذف الرسالة! حاول مرة أخرى",
|
||||||
"NO_RESPONSE": "لا توجد استجابة",
|
"NO_RESPONSE": "لا توجد استجابة",
|
||||||
"RATING_TITLE": "Rating",
|
"RATING_TITLE": "التقييم",
|
||||||
"FEEDBACK_TITLE": "Feedback",
|
"FEEDBACK_TITLE": "الملاحظات",
|
||||||
"HEADER": {
|
"HEADER": {
|
||||||
"RESOLVE_ACTION": "إغلاق المحادثة",
|
"RESOLVE_ACTION": "إغلاق المحادثة",
|
||||||
"REOPEN_ACTION": "إعادة فتح",
|
"REOPEN_ACTION": "إعادة فتح",
|
||||||
|
@ -41,7 +42,13 @@
|
||||||
"DETAILS": "التفاصيل"
|
"DETAILS": "التفاصيل"
|
||||||
},
|
},
|
||||||
"RESOLVE_DROPDOWN": {
|
"RESOLVE_DROPDOWN": {
|
||||||
"OPEN_BOT": "Open with bot"
|
"MARK_PENDING": "تحديد كمعلق",
|
||||||
|
"SNOOZE": {
|
||||||
|
"TITLE": "تأجيل حتى",
|
||||||
|
"NEXT_REPLY": "الرد القادم",
|
||||||
|
"TOMORROW": "غداً",
|
||||||
|
"NEXT_WEEK": "الأسبوع المقبل"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"FOOTER": {
|
"FOOTER": {
|
||||||
"MSG_INPUT": "زر Shift + Enter لإضافة سطر جديد. ابدأ بزر / للاختيار من الردود السريعة.",
|
"MSG_INPUT": "زر Shift + Enter لإضافة سطر جديد. ابدأ بزر / للاختيار من الردود السريعة.",
|
||||||
|
@ -57,13 +64,26 @@
|
||||||
"TIP_EMOJI_ICON": "إظهار قائمة الرموز التعبيرية",
|
"TIP_EMOJI_ICON": "إظهار قائمة الرموز التعبيرية",
|
||||||
"TIP_ATTACH_ICON": "إرفاق الملفات",
|
"TIP_ATTACH_ICON": "إرفاق الملفات",
|
||||||
"ENTER_TO_SEND": "زر الإدخل للإرسال",
|
"ENTER_TO_SEND": "زر الإدخل للإرسال",
|
||||||
"DRAG_DROP": "Drag and drop here to attach"
|
"DRAG_DROP": "اسحب و أسقط هنا للإرفاق",
|
||||||
|
"EMAIL_HEAD": {
|
||||||
|
"ADD_BCC": "إضافة bcc",
|
||||||
|
"CC": {
|
||||||
|
"LABEL": "CC",
|
||||||
|
"PLACEHOLDER": "البريد الإلكتروني مفصولة بفاصلة",
|
||||||
|
"ERROR": "الرجاء إدخال عنوان بريد إلكتروني صحيح"
|
||||||
|
},
|
||||||
|
"BCC": {
|
||||||
|
"LABEL": "BCC",
|
||||||
|
"PLACEHOLDER": "البريد الإلكتروني مفصولة بفاصلة",
|
||||||
|
"ERROR": "الرجاء إدخال عنوان بريد إلكتروني صحيح"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"VISIBLE_TO_AGENTS": "ملاحظة خاصة: مرئية فقط لأعضاء فريق العمل والموظفين",
|
"VISIBLE_TO_AGENTS": "ملاحظة خاصة: مرئية فقط لأعضاء فريق العمل والموظفين",
|
||||||
"CHANGE_STATUS": "تم تغيير حالة المحادثة",
|
"CHANGE_STATUS": "تم تغيير حالة المحادثة",
|
||||||
"CHANGE_AGENT": "تم تغيير الموظف الذي تم إحالة المحادثة إليه",
|
"CHANGE_AGENT": "تم تغيير الموظف الذي تم إحالة المحادثة إليه",
|
||||||
"CHANGE_TEAM": "تم تغيير فريق المحادثة",
|
"CHANGE_TEAM": "تم تغيير فريق المحادثة",
|
||||||
"FILE_SIZE_LIMIT": "File exceeds the {MAXIMUM_FILE_UPLOAD_SIZE} attachment limit",
|
"FILE_SIZE_LIMIT": "حجم الملف يتجاوز حد الاقصى وهو {MAXIMUM_FILE_UPLOAD_SIZE}",
|
||||||
"SENT_BY": "أرسلت بواسطة:",
|
"SENT_BY": "أرسلت بواسطة:",
|
||||||
"ASSIGNMENT": {
|
"ASSIGNMENT": {
|
||||||
"SELECT_AGENT": "اختر وكيل",
|
"SELECT_AGENT": "اختر وكيل",
|
||||||
|
@ -118,10 +138,24 @@
|
||||||
},
|
},
|
||||||
"CONVERSATION_SIDEBAR": {
|
"CONVERSATION_SIDEBAR": {
|
||||||
"ASSIGNEE_LABEL": "الوكيل المكلف",
|
"ASSIGNEE_LABEL": "الوكيل المكلف",
|
||||||
"SELF_ASSIGN": "Assign to me",
|
"SELF_ASSIGN": "إسناد لي",
|
||||||
"TEAM_LABEL": "العضو المكلف",
|
"TEAM_LABEL": "العضو المكلف",
|
||||||
"SELECT": {
|
"SELECT": {
|
||||||
"PLACEHOLDER": "لا شيء"
|
"PLACEHOLDER": "لا شيء"
|
||||||
}
|
},
|
||||||
|
"ACCORDION": {
|
||||||
|
"CONTACT_DETAILS": "Contact Details",
|
||||||
|
"CONVERSATION_ACTIONS": "Conversation Actions",
|
||||||
|
"CONVERSATION_LABELS": "وسوم المحادثة",
|
||||||
|
"CONVERSATION_INFO": "Conversation Information",
|
||||||
|
"CONTACT_ATTRIBUTES": "Contact Attributes",
|
||||||
|
"PREVIOUS_CONVERSATION": "المحادثات السابقة"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"EMAIL_HEADER": {
|
||||||
|
"TO": "إلى",
|
||||||
|
"BCC": "Bcc",
|
||||||
|
"CC": "Cc",
|
||||||
|
"SUBJECT": "الموضوع"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"CSAT": {
|
"CSAT": {
|
||||||
"TITLE": "Rate your conversation",
|
"TITLE": "قيم محادثتك",
|
||||||
"PLACEHOLDER": "Tell us more..."
|
"PLACEHOLDER": "أخبرنا المزيد..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
"ADD": {
|
"ADD": {
|
||||||
"CHANNEL_NAME": {
|
"CHANNEL_NAME": {
|
||||||
"LABEL": "اسم صندوق الوارد لقناة التواصل",
|
"LABEL": "اسم صندوق الوارد لقناة التواصل",
|
||||||
"PLACEHOLDER": "Enter your inbox name (eg: Acme Inc)"
|
"PLACEHOLDER": "أدخل اسم صندوق الوارد الخاص بك (مثال: Acme Inc)"
|
||||||
},
|
},
|
||||||
"WEBSITE_NAME": {
|
"WEBSITE_NAME": {
|
||||||
"LABEL": "اسم الموقع",
|
"LABEL": "اسم الموقع",
|
||||||
|
@ -128,12 +128,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"SMS": {
|
"SMS": {
|
||||||
"TITLE": "SMS Channel via Twilio",
|
"TITLE": "قناة SMS عبر Twilio",
|
||||||
"DESC": "Start supporting your customers via SMS with Twilio integration."
|
"DESC": "ابدأ في دعم عملائك عبر الرسائل القصيرة بإستخدام Twilio."
|
||||||
},
|
},
|
||||||
"WHATSAPP": {
|
"WHATSAPP": {
|
||||||
"TITLE": "Whatsapp Channel via Twilio",
|
"TITLE": "قناة Whatsapp عبر Twilio",
|
||||||
"DESC": "Start supporting your customers via Whatsapp with Twilio integration."
|
"DESC": "ابدأ في دعم عملائك عبر الواتساب بإستخدام Twilio."
|
||||||
},
|
},
|
||||||
"API_CHANNEL": {
|
"API_CHANNEL": {
|
||||||
"TITLE": "قناة API",
|
"TITLE": "قناة API",
|
||||||
|
@ -172,9 +172,47 @@
|
||||||
},
|
},
|
||||||
"FINISH_MESSAGE": "بدء إعادة توجيه رسائل البريد الإلكتروني الخاصة بك إلى عنوان البريد الإلكتروني التالي."
|
"FINISH_MESSAGE": "بدء إعادة توجيه رسائل البريد الإلكتروني الخاصة بك إلى عنوان البريد الإلكتروني التالي."
|
||||||
},
|
},
|
||||||
|
"LINE_CHANNEL": {
|
||||||
|
"TITLE": "LINE Channel",
|
||||||
|
"DESC": "Integrate with LINE channel and start supporting your customers.",
|
||||||
|
"CHANNEL_NAME": {
|
||||||
|
"LABEL": "اسم القناة",
|
||||||
|
"PLACEHOLDER": "الرجاء إدخال اسم القناة",
|
||||||
|
"ERROR": "هذا الحقل مطلوب"
|
||||||
|
},
|
||||||
|
"LINE_CHANNEL_ID": {
|
||||||
|
"LABEL": "LINE Channel ID",
|
||||||
|
"PLACEHOLDER": "LINE Channel ID"
|
||||||
|
},
|
||||||
|
"LINE_CHANNEL_SECRET": {
|
||||||
|
"LABEL": "LINE Channel Secret",
|
||||||
|
"PLACEHOLDER": "LINE Channel Secret"
|
||||||
|
},
|
||||||
|
"LINE_CHANNEL_TOKEN": {
|
||||||
|
"LABEL": "LINE Channel Token",
|
||||||
|
"PLACEHOLDER": "LINE Channel Token"
|
||||||
|
},
|
||||||
|
"SUBMIT_BUTTON": "Create LINE Channel",
|
||||||
|
"API": {
|
||||||
|
"ERROR_MESSAGE": "We were not able to save the LINE channel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"TELEGRAM_CHANNEL": {
|
||||||
|
"TITLE": "Telegram Channel",
|
||||||
|
"DESC": "Integrate with Telegram channel and start supporting your customers.",
|
||||||
|
"BOT_TOKEN": {
|
||||||
|
"LABEL": "Bot Token",
|
||||||
|
"SUBTITLE": "Configure the bot token you have obtained from Telegram BotFather.",
|
||||||
|
"PLACEHOLDER": "Bot Token"
|
||||||
|
},
|
||||||
|
"SUBMIT_BUTTON": "Create Telegram Channel",
|
||||||
|
"API": {
|
||||||
|
"ERROR_MESSAGE": "We were not able to save the telegram channel"
|
||||||
|
}
|
||||||
|
},
|
||||||
"AUTH": {
|
"AUTH": {
|
||||||
"TITLE": "Choose a channel",
|
"TITLE": "اختر قناة",
|
||||||
"DESC": "Chatwoot supports live-chat widget, Facebook page, Twitter profile, Whatsapp, Email etc., as channels. If you want to build a custom channel, you can create it using the API channel. Select one channel from the options below to proceed."
|
"DESC": "شاتوت يدعم أداة الدردشة المباشرة، صفحة الفيسبوك، ملف تويتر الشخصي، واتسب، البريد الإلكتروني وما إلى ذلك، كقنوات. إذا كنت ترغب في إنشاء قناة مخصصة، يمكنك إنشاءها باستخدام قناة API. حدد قناة واحدة من الخيارات أدناه للمتابعة."
|
||||||
},
|
},
|
||||||
"AGENTS": {
|
"AGENTS": {
|
||||||
"TITLE": "موظف الدعم",
|
"TITLE": "موظف الدعم",
|
||||||
|
@ -232,6 +270,7 @@
|
||||||
},
|
},
|
||||||
"DELETE": {
|
"DELETE": {
|
||||||
"BUTTON_TEXT": "حذف",
|
"BUTTON_TEXT": "حذف",
|
||||||
|
"AVATAR_DELETE_BUTTON_TEXT": "Delete Avatar",
|
||||||
"CONFIRM": {
|
"CONFIRM": {
|
||||||
"TITLE": "تأكيد الحذف",
|
"TITLE": "تأكيد الحذف",
|
||||||
"MESSAGE": "هل أنت متأكد من الحذف ",
|
"MESSAGE": "هل أنت متأكد من الحذف ",
|
||||||
|
@ -241,14 +280,16 @@
|
||||||
},
|
},
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS_MESSAGE": "تم حذف قناة التواصل بنجاح",
|
"SUCCESS_MESSAGE": "تم حذف قناة التواصل بنجاح",
|
||||||
"ERROR_MESSAGE": "تعذر حذف قناة التواصل. الرجاء المحاولة مرة أخرى لاحقاً."
|
"ERROR_MESSAGE": "تعذر حذف قناة التواصل. الرجاء المحاولة مرة أخرى لاحقاً.",
|
||||||
|
"AVATAR_SUCCESS_MESSAGE": "Inbox avatar deleted successfully",
|
||||||
|
"AVATAR_ERROR_MESSAGE": "Could not delete the inbox avatar. Please try again later."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TABS": {
|
"TABS": {
|
||||||
"SETTINGS": "الإعدادات",
|
"SETTINGS": "الإعدادات",
|
||||||
"COLLABORATORS": "المتعاونون",
|
"COLLABORATORS": "المتعاونون",
|
||||||
"CONFIGURATION": "الإعدادات",
|
"CONFIGURATION": "الإعدادات",
|
||||||
"CAMPAIGN": "Campaigns",
|
"CAMPAIGN": "الحملات",
|
||||||
"PRE_CHAT_FORM": "نموذج ما قبل الدردشة",
|
"PRE_CHAT_FORM": "نموذج ما قبل الدردشة",
|
||||||
"BUSINESS_HOURS": "ساعات العمل"
|
"BUSINESS_HOURS": "ساعات العمل"
|
||||||
},
|
},
|
||||||
|
@ -273,7 +314,11 @@
|
||||||
"INBOX_UPDATE_SUB_TEXT": "تحديث إعدادات قناة التواصل",
|
"INBOX_UPDATE_SUB_TEXT": "تحديث إعدادات قناة التواصل",
|
||||||
"AUTO_ASSIGNMENT_SUB_TEXT": "تمكين أو تعطيل الإسناد التلقائي للمحادثات الجديدة إلى الموظفين المضافين إلى قناة التواصل هذه.",
|
"AUTO_ASSIGNMENT_SUB_TEXT": "تمكين أو تعطيل الإسناد التلقائي للمحادثات الجديدة إلى الموظفين المضافين إلى قناة التواصل هذه.",
|
||||||
"HMAC_VERIFICATION": "التحقق من هوية المستخدم",
|
"HMAC_VERIFICATION": "التحقق من هوية المستخدم",
|
||||||
"HMAC_DESCRIPTION": "للتحقق من هوية المستخدمين، يسمح لك SDK بتمرير 'identifier_hash' لكل مستخدم. يمكنك إنشاء HMAC باستخدام 'sha256' مع المفتاح المعروض هنا."
|
"HMAC_DESCRIPTION": "Inorder to validate the user's identity, the SDK allows you to pass an `identifier_hash` for each user. You can generate HMAC using 'sha256' with the key shown here.",
|
||||||
|
"INBOX_IDENTIFIER": "Inbox Identifier",
|
||||||
|
"INBOX_IDENTIFIER_SUB_TEXT": "Use the `inbox_identifier` token shown here to authentication your API clients.",
|
||||||
|
"FORWARD_EMAIL_TITLE": "Forward to Email",
|
||||||
|
"FORWARD_EMAIL_SUB_TEXT": "بدء إعادة توجيه رسائل البريد الإلكتروني الخاصة بك إلى عنوان البريد الإلكتروني التالي."
|
||||||
},
|
},
|
||||||
"FACEBOOK_REAUTHORIZE": {
|
"FACEBOOK_REAUTHORIZE": {
|
||||||
"TITLE": "إعادة التصريح",
|
"TITLE": "إعادة التصريح",
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { default as _agentMgmt } from './agentMgmt.json';
|
import { default as _agentMgmt } from './agentMgmt.json';
|
||||||
|
import { default as _attributesMgmt } from './attributesMgmt.json';
|
||||||
import { default as _campaign } from './campaign.json';
|
import { default as _campaign } from './campaign.json';
|
||||||
import { default as _cannedMgmt } from './cannedMgmt.json';
|
import { default as _cannedMgmt } from './cannedMgmt.json';
|
||||||
import { default as _chatlist } from './chatlist.json';
|
import { default as _chatlist } from './chatlist.json';
|
||||||
import { default as _contact } from './contact.json';
|
import { default as _contact } from './contact.json';
|
||||||
import { default as _conversation } from './conversation.json';
|
import { default as _conversation } from './conversation.json';
|
||||||
|
import { default as _csatMgmtMgmt } from './csatMgmt.json';
|
||||||
import { default as _generalSettings } from './generalSettings.json';
|
import { default as _generalSettings } from './generalSettings.json';
|
||||||
import { default as _inboxMgmt } from './inboxMgmt.json';
|
import { default as _inboxMgmt } from './inboxMgmt.json';
|
||||||
|
import { default as _integrationApps } from './integrationApps.json';
|
||||||
import { default as _integrations } from './integrations.json';
|
import { default as _integrations } from './integrations.json';
|
||||||
import { default as _labelsMgmt } from './labelsMgmt.json';
|
import { default as _labelsMgmt } from './labelsMgmt.json';
|
||||||
import { default as _login } from './login.json';
|
import { default as _login } from './login.json';
|
||||||
|
@ -18,13 +21,16 @@ import { default as _teamsSettings } from './teamsSettings.json';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
..._agentMgmt,
|
..._agentMgmt,
|
||||||
|
..._attributesMgmt,
|
||||||
..._campaign,
|
..._campaign,
|
||||||
..._cannedMgmt,
|
..._cannedMgmt,
|
||||||
..._chatlist,
|
..._chatlist,
|
||||||
..._contact,
|
..._contact,
|
||||||
..._conversation,
|
..._conversation,
|
||||||
|
..._csatMgmtMgmt,
|
||||||
..._generalSettings,
|
..._generalSettings,
|
||||||
..._inboxMgmt,
|
..._inboxMgmt,
|
||||||
|
..._integrationApps,
|
||||||
..._integrations,
|
..._integrations,
|
||||||
..._labelsMgmt,
|
..._labelsMgmt,
|
||||||
..._login,
|
..._login,
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
},
|
},
|
||||||
"LIST": {
|
"LIST": {
|
||||||
"FETCHING": "Fetching integration hooks",
|
"FETCHING": "Fetching integration hooks",
|
||||||
"INBOX": "Inbox",
|
"INBOX": "صندوق الوارد",
|
||||||
"DELETE": {
|
"DELETE": {
|
||||||
"BUTTON_TEXT": "حذف"
|
"BUTTON_TEXT": "حذف"
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,41 +49,41 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"name": "Last year"
|
"name": "العام الماضي"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 5,
|
||||||
"name": "Custom date range"
|
"name": "تحديد نطاق المدة"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"CUSTOM_DATE_RANGE": {
|
"CUSTOM_DATE_RANGE": {
|
||||||
"CONFIRM": "Apply",
|
"CONFIRM": "تطبيق",
|
||||||
"PLACEHOLDER": "Select date range"
|
"PLACEHOLDER": "اختر نطاق المدة"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CSAT_REPORTS": {
|
"CSAT_REPORTS": {
|
||||||
"HEADER": "CSAT Reports",
|
"HEADER": "تقارير CSAT",
|
||||||
"NO_RECORDS": "There are no CSAT survey responses available.",
|
"NO_RECORDS": "لا توجد ردود متوفرة على الدراسة الاستقصائية CSAT.",
|
||||||
"TABLE": {
|
"TABLE": {
|
||||||
"HEADER": {
|
"HEADER": {
|
||||||
"CONTACT_NAME": "Contact",
|
"CONTACT_NAME": "جهات الاتصال",
|
||||||
"AGENT_NAME": "Assigned agent",
|
"AGENT_NAME": "الوكيل المكلف",
|
||||||
"RATING": "Rating",
|
"RATING": "التقييم",
|
||||||
"FEEDBACK_TEXT": "Feedback comment"
|
"FEEDBACK_TEXT": "تعليق الملاحظات"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"METRIC": {
|
"METRIC": {
|
||||||
"TOTAL_RESPONSES": {
|
"TOTAL_RESPONSES": {
|
||||||
"LABEL": "Total responses",
|
"LABEL": "إجمالي الردود",
|
||||||
"TOOLTIP": "Total number of responses collected"
|
"TOOLTIP": "العدد الإجمالي للردود التي تم جمعها"
|
||||||
},
|
},
|
||||||
"SATISFACTION_SCORE": {
|
"SATISFACTION_SCORE": {
|
||||||
"LABEL": "Satisfaction score",
|
"LABEL": "درجة الرضا",
|
||||||
"TOOLTIP": "Total number of positive responses / Total number of responses * 100"
|
"TOOLTIP": "العدد الإجمالي للردود الإيجابية/ العدد الإجمالي للردود * 100"
|
||||||
},
|
},
|
||||||
"RESPONSE_RATE": {
|
"RESPONSE_RATE": {
|
||||||
"LABEL": "Response rate",
|
"LABEL": "معدل الاستجابة",
|
||||||
"TOOLTIP": "Total number of responses / Total number of CSAT survey messages sent * 100"
|
"TOOLTIP": "العدد الإجمالي للردود / العدد الإجمالي لرسائل الاستقصاء التي أرسلتها CSAT * 100"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
"TITLE": "الإشعارات الصوتية",
|
"TITLE": "الإشعارات الصوتية",
|
||||||
"NOTE": "تمكين التنبيهات الصوتية في لوحة التحكم للرسائل والمحادثات الجديدة.",
|
"NOTE": "تمكين التنبيهات الصوتية في لوحة التحكم للرسائل والمحادثات الجديدة.",
|
||||||
"NONE": "لا شيء",
|
"NONE": "لا شيء",
|
||||||
"ASSIGNED": "Assigned Conversations",
|
"ASSIGNED": "المحادثات المسندة",
|
||||||
"ALL_CONVERSATIONS": "All Conversations"
|
"ALL_CONVERSATIONS": "كل المحادثات"
|
||||||
},
|
},
|
||||||
"EMAIL_NOTIFICATIONS_SECTION": {
|
"EMAIL_NOTIFICATIONS_SECTION": {
|
||||||
"TITLE": "إشعارات البريد الإلكتروني",
|
"TITLE": "إشعارات البريد الإلكتروني",
|
||||||
|
@ -81,9 +81,9 @@
|
||||||
"PLACEHOLDER": "الرجاء إدخال عنوان البريد الإلكتروني الخاص بك، سيتم عرضه في المحادثات"
|
"PLACEHOLDER": "الرجاء إدخال عنوان البريد الإلكتروني الخاص بك، سيتم عرضه في المحادثات"
|
||||||
},
|
},
|
||||||
"CURRENT_PASSWORD": {
|
"CURRENT_PASSWORD": {
|
||||||
"LABEL": "Current password",
|
"LABEL": "كلمة المرور الحالية",
|
||||||
"ERROR": "Please enter the current password",
|
"ERROR": "الرجاء إدخال كلمة مرور جديدة",
|
||||||
"PLACEHOLDER": "Please enter the current password"
|
"PLACEHOLDER": "الرجاء إدخال كلمة مرور جديدة"
|
||||||
},
|
},
|
||||||
"PASSWORD": {
|
"PASSWORD": {
|
||||||
"LABEL": "كلمة المرور",
|
"LABEL": "كلمة المرور",
|
||||||
|
@ -102,6 +102,7 @@
|
||||||
"CHANGE_ACCOUNTS": "تبديل الحساب",
|
"CHANGE_ACCOUNTS": "تبديل الحساب",
|
||||||
"SELECTOR_SUBTITLE": "اختر حساباً من القائمة التالية",
|
"SELECTOR_SUBTITLE": "اختر حساباً من القائمة التالية",
|
||||||
"PROFILE_SETTINGS": "إعدادات الملف الشخصي",
|
"PROFILE_SETTINGS": "إعدادات الملف الشخصي",
|
||||||
|
"KEYBOARD_SHORTCUTS": "اختصارات لوحة المفاتيح",
|
||||||
"LOGOUT": "تسجيل الخروج"
|
"LOGOUT": "تسجيل الخروج"
|
||||||
},
|
},
|
||||||
"APP_GLOBAL": {
|
"APP_GLOBAL": {
|
||||||
|
@ -130,8 +131,8 @@
|
||||||
"SIDEBAR": {
|
"SIDEBAR": {
|
||||||
"CONVERSATIONS": "المحادثات",
|
"CONVERSATIONS": "المحادثات",
|
||||||
"REPORTS": "التقارير",
|
"REPORTS": "التقارير",
|
||||||
"CONTACTS": "جهات الاتصال",
|
|
||||||
"SETTINGS": "الإعدادات",
|
"SETTINGS": "الإعدادات",
|
||||||
|
"CONTACTS": "جهات الاتصال",
|
||||||
"HOME": "الرئيسية",
|
"HOME": "الرئيسية",
|
||||||
"AGENTS": "موظف الدعم",
|
"AGENTS": "موظف الدعم",
|
||||||
"INBOXES": "قنوات التواصل",
|
"INBOXES": "قنوات التواصل",
|
||||||
|
@ -139,15 +140,20 @@
|
||||||
"CANNED_RESPONSES": "الردود السريعة",
|
"CANNED_RESPONSES": "الردود السريعة",
|
||||||
"INTEGRATIONS": "خيارات الربط",
|
"INTEGRATIONS": "خيارات الربط",
|
||||||
"ACCOUNT_SETTINGS": "إعدادات الحساب",
|
"ACCOUNT_SETTINGS": "إعدادات الحساب",
|
||||||
"APPLICATIONS": "Applications",
|
"APPLICATIONS": "التطبيقات",
|
||||||
"LABELS": "الوسوم",
|
"LABELS": "الوسوم",
|
||||||
|
"ATTRIBUTES": "السمات",
|
||||||
"TEAMS": "الفرق",
|
"TEAMS": "الفرق",
|
||||||
"ALL_CONTACTS": "All Contacts",
|
"ALL_CONTACTS": "جميع جهات الاتصال",
|
||||||
"TAGGED_WITH": "Tagged with",
|
"TAGGED_WITH": "Tagged with",
|
||||||
"REPORTS_OVERVIEW": "Overview",
|
"REPORTS_OVERVIEW": "نظرة عامة",
|
||||||
"CSAT": "CSAT"
|
"CSAT": "CSAT",
|
||||||
|
"CAMPAIGNS": "الحملات",
|
||||||
|
"ONGOING": "جارية",
|
||||||
|
"ONE_OFF": "إيقاف واحد"
|
||||||
},
|
},
|
||||||
"CREATE_ACCOUNT": {
|
"CREATE_ACCOUNT": {
|
||||||
|
"NO_ACCOUNT_WARNING": "أوه! لم نتمكن من العثور على الحساب. الرجاء إنشاء حساب جديد للمتابعة.",
|
||||||
"NEW_ACCOUNT": "حساب جديد",
|
"NEW_ACCOUNT": "حساب جديد",
|
||||||
"SELECTOR_SUBTITLE": "إنشاء حساب جديد",
|
"SELECTOR_SUBTITLE": "إنشاء حساب جديد",
|
||||||
"API": {
|
"API": {
|
||||||
|
@ -162,5 +168,30 @@
|
||||||
},
|
},
|
||||||
"SUBMIT": "إرسال"
|
"SUBMIT": "إرسال"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"KEYBOARD_SHORTCUTS": {
|
||||||
|
"TITLE": {
|
||||||
|
"OPEN_CONVERSATION": "فتح المحادثة",
|
||||||
|
"RESOLVE_AND_NEXT": "حل وانتقل إلى التالي",
|
||||||
|
"NAVIGATE_DROPDOWN": "تصفح العناصر المنسدلة",
|
||||||
|
"RESOLVE_CONVERSATION": "إعادة فتح المحادثة",
|
||||||
|
"GO_TO_CONVERSATION_DASHBOARD": "الذهاب إلى لوحة المحادثة",
|
||||||
|
"ADD_ATTACHMENT": "إضافة مرفقات",
|
||||||
|
"GO_TO_CONTACTS_DASHBOARD": "الذهاب إلى لوحة جهات الاتصال",
|
||||||
|
"TOGGLE_SIDEBAR": "تبديل الشريط الجانبي",
|
||||||
|
"GO_TO_REPORTS_SIDEBAR": "الذهاب إلى شريط التقارير الجانبي",
|
||||||
|
"MOVE_TO_NEXT_TAB": "نقل إلى علامة التبويب التالية في قائمة المحادثات",
|
||||||
|
"GO_TO_SETTINGS": "انتقل إلى الإعدادات",
|
||||||
|
"SWITCH_CONVERSATION_STATUS": "Switch to the next conversation status",
|
||||||
|
"SWITCH_TO_PRIVATE_NOTE": "Switch to Private Note",
|
||||||
|
"TOGGLE_RICH_CONTENT_EDITOR": "Toggle Rich Content editor",
|
||||||
|
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||||
|
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||||
|
},
|
||||||
|
"KEYS": {
|
||||||
|
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||||
|
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||||
|
"FORWARD_SLASH_KEY": "/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,23 @@
|
||||||
},
|
},
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"NO_RESULTS": "No results found."
|
"NO_RESULTS": "No results found."
|
||||||
|
},
|
||||||
|
"MULTI_SELECTOR": {
|
||||||
|
"PLACEHOLDER": "None",
|
||||||
|
"TITLE": {
|
||||||
|
"AGENT": "Select agent",
|
||||||
|
"TEAM": "Select team"
|
||||||
|
},
|
||||||
|
"SEARCH": {
|
||||||
|
"NO_RESULTS": {
|
||||||
|
"AGENT": "No s'han trobat agents",
|
||||||
|
"TEAM": "No teams found"
|
||||||
|
},
|
||||||
|
"PLACEHOLDER": {
|
||||||
|
"AGENT": "Search agents",
|
||||||
|
"TEAM": "Search teams"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
85
app/javascript/dashboard/i18n/locale/ca/attributesMgmt.json
Normal file
85
app/javascript/dashboard/i18n/locale/ca/attributesMgmt.json
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
{
|
||||||
|
"ATTRIBUTES_MGMT": {
|
||||||
|
"HEADER": "Attributes",
|
||||||
|
"HEADER_BTN_TXT": "Add Attribute",
|
||||||
|
"LOADING": "Fetching attributes",
|
||||||
|
"SIDEBAR_TXT": "<p><b>Attributes</b> <p>A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc. <br /><br />For creating a Attributes, just click on the <b>Add Attribute.</b> You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.</p>",
|
||||||
|
"ADD": {
|
||||||
|
"TITLE": "Add attribute",
|
||||||
|
"SUBMIT": "Crear",
|
||||||
|
"CANCEL_BUTTON_TEXT": "Cancel·la",
|
||||||
|
"FORM": {
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Display Name",
|
||||||
|
"PLACEHOLDER": "Enter attribute display name",
|
||||||
|
"ERROR": "Name is required"
|
||||||
|
},
|
||||||
|
"DESC": {
|
||||||
|
"LABEL": "Descripció",
|
||||||
|
"PLACEHOLDER": "Enter attribute description",
|
||||||
|
"ERROR": "Description is required"
|
||||||
|
},
|
||||||
|
"MODEL": {
|
||||||
|
"LABEL": "Model",
|
||||||
|
"PLACEHOLDER": "Please select a model",
|
||||||
|
"ERROR": "Model is required"
|
||||||
|
},
|
||||||
|
"TYPE": {
|
||||||
|
"LABEL": "Type",
|
||||||
|
"PLACEHOLDER": "Selecciona un tipus",
|
||||||
|
"ERROR": "Type is required"
|
||||||
|
},
|
||||||
|
"KEY": {
|
||||||
|
"LABEL": "Key"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"API": {
|
||||||
|
"SUCCESS_MESSAGE": "Attribute added successfully",
|
||||||
|
"ERROR_MESSAGE": "Could not able to create an attribute, Please try again later"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DELETE": {
|
||||||
|
"BUTTON_TEXT": "Esborrar",
|
||||||
|
"API": {
|
||||||
|
"SUCCESS_MESSAGE": "Attribute deleted successfully.",
|
||||||
|
"ERROR_MESSAGE": "Couldn't delete the attribute. Try again."
|
||||||
|
},
|
||||||
|
"CONFIRM": {
|
||||||
|
"TITLE": "Are you sure want to delete - %{attributeName}",
|
||||||
|
"PLACE_HOLDER": "Please type {attributeName} to confirm",
|
||||||
|
"MESSAGE": "Deleting will remove the attribute",
|
||||||
|
"YES": "Suprimeix ",
|
||||||
|
"NO": "Cancel·la"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"EDIT": {
|
||||||
|
"TITLE": "Edit attribute",
|
||||||
|
"UPDATE_BUTTON_TEXT": "Actualitza",
|
||||||
|
"API": {
|
||||||
|
"SUCCESS_MESSAGE": "Attribute updated successfully",
|
||||||
|
"ERROR_MESSAGE": "There was an error updating attribute, please try again"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"TABS": {
|
||||||
|
"HEADER": "Atributs personalitzats",
|
||||||
|
"CONVERSATION": "Conversation",
|
||||||
|
"CONTACT": "Contact"
|
||||||
|
},
|
||||||
|
"LIST": {
|
||||||
|
"TABLE_HEADER": [
|
||||||
|
"Nom",
|
||||||
|
"Descripció",
|
||||||
|
"Type",
|
||||||
|
"Key"
|
||||||
|
],
|
||||||
|
"BUTTONS": {
|
||||||
|
"EDIT": "Edita",
|
||||||
|
"DELETE": "Esborrar"
|
||||||
|
},
|
||||||
|
"EMPTY_RESULT": {
|
||||||
|
"404": "There are no attributes created",
|
||||||
|
"NOT_FOUND": "There are no attributes configured"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,10 @@
|
||||||
"CAMPAIGN": {
|
"CAMPAIGN": {
|
||||||
"HEADER": "Campaigns",
|
"HEADER": "Campaigns",
|
||||||
"SIDEBAR_TXT": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations. Click on <b>Add Campaign</b> to create a new campaign. You can also edit or delete an existing campaign by clicking on the Edit or Delete button.",
|
"SIDEBAR_TXT": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations. Click on <b>Add Campaign</b> to create a new campaign. You can also edit or delete an existing campaign by clicking on the Edit or Delete button.",
|
||||||
"HEADER_BTN_TXT": "Create a campaign",
|
"HEADER_BTN_TXT": {
|
||||||
|
"ONE_OFF": "Create a one off campaign",
|
||||||
|
"ONGOING": "Create a ongoing campaign"
|
||||||
|
},
|
||||||
"ADD": {
|
"ADD": {
|
||||||
"TITLE": "Create a campaign",
|
"TITLE": "Create a campaign",
|
||||||
"DESC": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations.",
|
"DESC": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations.",
|
||||||
|
@ -25,6 +28,11 @@
|
||||||
"PLACEHOLDER": "Select the customer labels",
|
"PLACEHOLDER": "Select the customer labels",
|
||||||
"ERROR": "Audience is required"
|
"ERROR": "Audience is required"
|
||||||
},
|
},
|
||||||
|
"INBOX": {
|
||||||
|
"LABEL": "Select Inbox",
|
||||||
|
"PLACEHOLDER": "Select Inbox",
|
||||||
|
"ERROR": "Inbox is required"
|
||||||
|
},
|
||||||
"MESSAGE": {
|
"MESSAGE": {
|
||||||
"LABEL": "Missatge",
|
"LABEL": "Missatge",
|
||||||
"PLACEHOLDER": "Please enter the message of campaign",
|
"PLACEHOLDER": "Please enter the message of campaign",
|
||||||
|
@ -80,6 +88,7 @@
|
||||||
"TABLE_HEADER": {
|
"TABLE_HEADER": {
|
||||||
"TITLE": "Title",
|
"TITLE": "Title",
|
||||||
"MESSAGE": "Missatge",
|
"MESSAGE": "Missatge",
|
||||||
|
"INBOX": "Inbox",
|
||||||
"STATUS": "Estat",
|
"STATUS": "Estat",
|
||||||
"SENDER": "Sender",
|
"SENDER": "Sender",
|
||||||
"URL": "URL",
|
"URL": "URL",
|
||||||
|
@ -101,6 +110,16 @@
|
||||||
"SENDER": {
|
"SENDER": {
|
||||||
"BOT": "Bot"
|
"BOT": "Bot"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ONE_OFF": {
|
||||||
|
"HEADER": "One off campaigns",
|
||||||
|
"404": "There are no one off campaigns created",
|
||||||
|
"INBOXES_NOT_FOUND": "Please create an sms inbox and start adding campaigns"
|
||||||
|
},
|
||||||
|
"ONGOING": {
|
||||||
|
"HEADER": "Ongoing campaigns",
|
||||||
|
"404": "There are no ongoing campaigns created",
|
||||||
|
"INBOXES_NOT_FOUND": "Please create an website inbox and start adding campaigns"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,12 @@
|
||||||
"VALUE": "resolved"
|
"VALUE": "resolved"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"TEXT": "Bot",
|
"TEXT": "Pending",
|
||||||
"VALUE": "bot"
|
"VALUE": "pending"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TEXT": "Snoozed",
|
||||||
|
"VALUE": "snoozed"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ATTACHMENTS": {
|
"ATTACHMENTS": {
|
||||||
|
|
|
@ -37,7 +37,12 @@
|
||||||
"MUTED_SUCCESS": "Aquesta conversa s'ha silenciat durant 6 hores",
|
"MUTED_SUCCESS": "Aquesta conversa s'ha silenciat durant 6 hores",
|
||||||
"UNMUTED_SUCCESS": "La conversa te desactivat el silenci",
|
"UNMUTED_SUCCESS": "La conversa te desactivat el silenci",
|
||||||
"SEND_TRANSCRIPT": "Envia la transcripció",
|
"SEND_TRANSCRIPT": "Envia la transcripció",
|
||||||
"EDIT_LABEL": "Edita"
|
"EDIT_LABEL": "Edita",
|
||||||
|
"SIDEBAR_SECTIONS": {
|
||||||
|
"CUSTOM_ATTRIBUTES": "Atributs personalitzats",
|
||||||
|
"CONTACT_LABELS": "Contact Labels",
|
||||||
|
"PREVIOUS_CONVERSATIONS": "Converses prèvies"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"EDIT_CONTACT": {
|
"EDIT_CONTACT": {
|
||||||
"BUTTON_LABEL": "Edita el contacte",
|
"BUTTON_LABEL": "Edita el contacte",
|
||||||
|
@ -186,8 +191,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CUSTOM_ATTRIBUTES": {
|
"CUSTOM_ATTRIBUTES": {
|
||||||
"TITLE": "Atributs personalitzats",
|
|
||||||
"BUTTON": "Add custom attribute",
|
"BUTTON": "Add custom attribute",
|
||||||
|
"NOT_AVAILABLE": "There are no custom attributes available for this contact.",
|
||||||
"ADD": {
|
"ADD": {
|
||||||
"TITLE": "Create custom attribute",
|
"TITLE": "Create custom attribute",
|
||||||
"DESC": "Add custom information to this contact."
|
"DESC": "Add custom information to this contact."
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"SEARCH_MESSAGES": "Cerca missatges a les converses",
|
"SEARCH_MESSAGES": "Cerca missatges a les converses",
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"TITLE": "Cerca missatges",
|
"TITLE": "Cerca missatges",
|
||||||
|
"RESULT_TITLE": "Search Results",
|
||||||
"LOADING_MESSAGE": "S'estan restringint les dades...",
|
"LOADING_MESSAGE": "S'estan restringint les dades...",
|
||||||
"PLACEHOLDER": "Escriu qualsevol text per cercar missatges",
|
"PLACEHOLDER": "Escriu qualsevol text per cercar missatges",
|
||||||
"NO_MATCHING_RESULTS": "No results found."
|
"NO_MATCHING_RESULTS": "No results found."
|
||||||
|
@ -22,7 +23,7 @@
|
||||||
"24_HOURS_WINDOW": "Restricció de finestra de missatges de 24 hores",
|
"24_HOURS_WINDOW": "Restricció de finestra de missatges de 24 hores",
|
||||||
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
|
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
|
||||||
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "Restricció de finestra de missatges de 24 hores",
|
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "Restricció de finestra de missatges de 24 hores",
|
||||||
"LAST_INCOMING_TWEET": "Estas responent a l'últim tuit entrant",
|
"SELECT_A_TWEET_TO_REPLY": "Please select a tweet to reply to.",
|
||||||
"REPLYING_TO": "Estas responent a:",
|
"REPLYING_TO": "Estas responent a:",
|
||||||
"REMOVE_SELECTION": "Elimina la selecció",
|
"REMOVE_SELECTION": "Elimina la selecció",
|
||||||
"DOWNLOAD": "Descarrega",
|
"DOWNLOAD": "Descarrega",
|
||||||
|
@ -41,7 +42,13 @@
|
||||||
"DETAILS": "detalls"
|
"DETAILS": "detalls"
|
||||||
},
|
},
|
||||||
"RESOLVE_DROPDOWN": {
|
"RESOLVE_DROPDOWN": {
|
||||||
"OPEN_BOT": "Open with bot"
|
"MARK_PENDING": "Mark as pending",
|
||||||
|
"SNOOZE": {
|
||||||
|
"TITLE": "Snooze until",
|
||||||
|
"NEXT_REPLY": "Next reply",
|
||||||
|
"TOMORROW": "Tomorrow",
|
||||||
|
"NEXT_WEEK": "Next week"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"FOOTER": {
|
"FOOTER": {
|
||||||
"MSG_INPUT": "Shift + enter per a una línia nova. Comença amb '/' per seleccionar una resposta predeterminada.",
|
"MSG_INPUT": "Shift + enter per a una línia nova. Comença amb '/' per seleccionar una resposta predeterminada.",
|
||||||
|
@ -57,7 +64,20 @@
|
||||||
"TIP_EMOJI_ICON": "Mostra la selecció d'emoticones",
|
"TIP_EMOJI_ICON": "Mostra la selecció d'emoticones",
|
||||||
"TIP_ATTACH_ICON": "Ajuntar fitxers",
|
"TIP_ATTACH_ICON": "Ajuntar fitxers",
|
||||||
"ENTER_TO_SEND": "Intro per enviar",
|
"ENTER_TO_SEND": "Intro per enviar",
|
||||||
"DRAG_DROP": "Drag and drop here to attach"
|
"DRAG_DROP": "Drag and drop here to attach",
|
||||||
|
"EMAIL_HEAD": {
|
||||||
|
"ADD_BCC": "Add bcc",
|
||||||
|
"CC": {
|
||||||
|
"LABEL": "CC",
|
||||||
|
"PLACEHOLDER": "Emails separated by commas",
|
||||||
|
"ERROR": "Please enter valid email addresses"
|
||||||
|
},
|
||||||
|
"BCC": {
|
||||||
|
"LABEL": "BCC",
|
||||||
|
"PLACEHOLDER": "Emails separated by commas",
|
||||||
|
"ERROR": "Please enter valid email addresses"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"VISIBLE_TO_AGENTS": "Nota privada: Només és visible per tu i el vostre equip",
|
"VISIBLE_TO_AGENTS": "Nota privada: Només és visible per tu i el vostre equip",
|
||||||
"CHANGE_STATUS": "Estat de la conversa canviat",
|
"CHANGE_STATUS": "Estat de la conversa canviat",
|
||||||
|
@ -122,6 +142,20 @@
|
||||||
"TEAM_LABEL": "Assigned Team",
|
"TEAM_LABEL": "Assigned Team",
|
||||||
"SELECT": {
|
"SELECT": {
|
||||||
"PLACEHOLDER": "None"
|
"PLACEHOLDER": "None"
|
||||||
}
|
},
|
||||||
|
"ACCORDION": {
|
||||||
|
"CONTACT_DETAILS": "Contact Details",
|
||||||
|
"CONVERSATION_ACTIONS": "Conversation Actions",
|
||||||
|
"CONVERSATION_LABELS": "Etiquetes de converses",
|
||||||
|
"CONVERSATION_INFO": "Conversation Information",
|
||||||
|
"CONTACT_ATTRIBUTES": "Contact Attributes",
|
||||||
|
"PREVIOUS_CONVERSATION": "Converses prèvies"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"EMAIL_HEADER": {
|
||||||
|
"TO": "To",
|
||||||
|
"BCC": "Bcc",
|
||||||
|
"CC": "Cc",
|
||||||
|
"SUBJECT": "Subject"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,44 @@
|
||||||
},
|
},
|
||||||
"FINISH_MESSAGE": "Comença a reenviar els teus correus electrònics a la següent adreça electrònica."
|
"FINISH_MESSAGE": "Comença a reenviar els teus correus electrònics a la següent adreça electrònica."
|
||||||
},
|
},
|
||||||
|
"LINE_CHANNEL": {
|
||||||
|
"TITLE": "LINE Channel",
|
||||||
|
"DESC": "Integrate with LINE channel and start supporting your customers.",
|
||||||
|
"CHANNEL_NAME": {
|
||||||
|
"LABEL": "Nom del canal",
|
||||||
|
"PLACEHOLDER": "Introduïu el nom del canal",
|
||||||
|
"ERROR": "Aquest camp és obligatori"
|
||||||
|
},
|
||||||
|
"LINE_CHANNEL_ID": {
|
||||||
|
"LABEL": "LINE Channel ID",
|
||||||
|
"PLACEHOLDER": "LINE Channel ID"
|
||||||
|
},
|
||||||
|
"LINE_CHANNEL_SECRET": {
|
||||||
|
"LABEL": "LINE Channel Secret",
|
||||||
|
"PLACEHOLDER": "LINE Channel Secret"
|
||||||
|
},
|
||||||
|
"LINE_CHANNEL_TOKEN": {
|
||||||
|
"LABEL": "LINE Channel Token",
|
||||||
|
"PLACEHOLDER": "LINE Channel Token"
|
||||||
|
},
|
||||||
|
"SUBMIT_BUTTON": "Create LINE Channel",
|
||||||
|
"API": {
|
||||||
|
"ERROR_MESSAGE": "We were not able to save the LINE channel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"TELEGRAM_CHANNEL": {
|
||||||
|
"TITLE": "Telegram Channel",
|
||||||
|
"DESC": "Integrate with Telegram channel and start supporting your customers.",
|
||||||
|
"BOT_TOKEN": {
|
||||||
|
"LABEL": "Bot Token",
|
||||||
|
"SUBTITLE": "Configure the bot token you have obtained from Telegram BotFather.",
|
||||||
|
"PLACEHOLDER": "Bot Token"
|
||||||
|
},
|
||||||
|
"SUBMIT_BUTTON": "Create Telegram Channel",
|
||||||
|
"API": {
|
||||||
|
"ERROR_MESSAGE": "We were not able to save the telegram channel"
|
||||||
|
}
|
||||||
|
},
|
||||||
"AUTH": {
|
"AUTH": {
|
||||||
"TITLE": "Choose a channel",
|
"TITLE": "Choose a channel",
|
||||||
"DESC": "Chatwoot supports live-chat widget, Facebook page, Twitter profile, Whatsapp, Email etc., as channels. If you want to build a custom channel, you can create it using the API channel. Select one channel from the options below to proceed."
|
"DESC": "Chatwoot supports live-chat widget, Facebook page, Twitter profile, Whatsapp, Email etc., as channels. If you want to build a custom channel, you can create it using the API channel. Select one channel from the options below to proceed."
|
||||||
|
@ -232,6 +270,7 @@
|
||||||
},
|
},
|
||||||
"DELETE": {
|
"DELETE": {
|
||||||
"BUTTON_TEXT": "Suprimeix",
|
"BUTTON_TEXT": "Suprimeix",
|
||||||
|
"AVATAR_DELETE_BUTTON_TEXT": "Delete Avatar",
|
||||||
"CONFIRM": {
|
"CONFIRM": {
|
||||||
"TITLE": "Confirma esborrat",
|
"TITLE": "Confirma esborrat",
|
||||||
"MESSAGE": "N'estas segur? ",
|
"MESSAGE": "N'estas segur? ",
|
||||||
|
@ -241,7 +280,9 @@
|
||||||
},
|
},
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS_MESSAGE": "S'ha suprimit la safata d'entrada correctament",
|
"SUCCESS_MESSAGE": "S'ha suprimit la safata d'entrada correctament",
|
||||||
"ERROR_MESSAGE": "No s'ha pogut eliminar la safata d'entrada. Torneu-ho a provar més endavant."
|
"ERROR_MESSAGE": "No s'ha pogut eliminar la safata d'entrada. Torneu-ho a provar més endavant.",
|
||||||
|
"AVATAR_SUCCESS_MESSAGE": "Inbox avatar deleted successfully",
|
||||||
|
"AVATAR_ERROR_MESSAGE": "Could not delete the inbox avatar. Please try again later."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TABS": {
|
"TABS": {
|
||||||
|
@ -273,7 +314,11 @@
|
||||||
"INBOX_UPDATE_SUB_TEXT": "Actualitza la configuració de la safata d'entrada",
|
"INBOX_UPDATE_SUB_TEXT": "Actualitza la configuració de la safata d'entrada",
|
||||||
"AUTO_ASSIGNMENT_SUB_TEXT": "Activa o desactiva l'assignació automàtica d'agents disponibles a les noves converses",
|
"AUTO_ASSIGNMENT_SUB_TEXT": "Activa o desactiva l'assignació automàtica d'agents disponibles a les noves converses",
|
||||||
"HMAC_VERIFICATION": "Validació de la Identitat del Usuari",
|
"HMAC_VERIFICATION": "Validació de la Identitat del Usuari",
|
||||||
"HMAC_DESCRIPTION": "Inorder validate the users identity, the SDK allows you to pass an `identifier_hash` for each user. You can generate HMAC using 'sha256' with the key shown here."
|
"HMAC_DESCRIPTION": "Inorder to validate the user's identity, the SDK allows you to pass an `identifier_hash` for each user. You can generate HMAC using 'sha256' with the key shown here.",
|
||||||
|
"INBOX_IDENTIFIER": "Inbox Identifier",
|
||||||
|
"INBOX_IDENTIFIER_SUB_TEXT": "Use the `inbox_identifier` token shown here to authentication your API clients.",
|
||||||
|
"FORWARD_EMAIL_TITLE": "Forward to Email",
|
||||||
|
"FORWARD_EMAIL_SUB_TEXT": "Comença a reenviar els teus correus electrònics a la següent adreça electrònica."
|
||||||
},
|
},
|
||||||
"FACEBOOK_REAUTHORIZE": {
|
"FACEBOOK_REAUTHORIZE": {
|
||||||
"TITLE": "Reautoritza",
|
"TITLE": "Reautoritza",
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { default as _agentMgmt } from './agentMgmt.json';
|
import { default as _agentMgmt } from './agentMgmt.json';
|
||||||
|
import { default as _attributesMgmt } from './attributesMgmt.json';
|
||||||
import { default as _campaign } from './campaign.json';
|
import { default as _campaign } from './campaign.json';
|
||||||
import { default as _cannedMgmt } from './cannedMgmt.json';
|
import { default as _cannedMgmt } from './cannedMgmt.json';
|
||||||
import { default as _chatlist } from './chatlist.json';
|
import { default as _chatlist } from './chatlist.json';
|
||||||
import { default as _contact } from './contact.json';
|
import { default as _contact } from './contact.json';
|
||||||
import { default as _conversation } from './conversation.json';
|
import { default as _conversation } from './conversation.json';
|
||||||
|
import { default as _csatMgmtMgmt } from './csatMgmt.json';
|
||||||
import { default as _generalSettings } from './generalSettings.json';
|
import { default as _generalSettings } from './generalSettings.json';
|
||||||
import { default as _inboxMgmt } from './inboxMgmt.json';
|
import { default as _inboxMgmt } from './inboxMgmt.json';
|
||||||
|
import { default as _integrationApps } from './integrationApps.json';
|
||||||
import { default as _integrations } from './integrations.json';
|
import { default as _integrations } from './integrations.json';
|
||||||
import { default as _labelsMgmt } from './labelsMgmt.json';
|
import { default as _labelsMgmt } from './labelsMgmt.json';
|
||||||
import { default as _login } from './login.json';
|
import { default as _login } from './login.json';
|
||||||
|
@ -18,13 +21,16 @@ import { default as _teamsSettings } from './teamsSettings.json';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
..._agentMgmt,
|
..._agentMgmt,
|
||||||
|
..._attributesMgmt,
|
||||||
..._campaign,
|
..._campaign,
|
||||||
..._cannedMgmt,
|
..._cannedMgmt,
|
||||||
..._chatlist,
|
..._chatlist,
|
||||||
..._contact,
|
..._contact,
|
||||||
..._conversation,
|
..._conversation,
|
||||||
|
..._csatMgmtMgmt,
|
||||||
..._generalSettings,
|
..._generalSettings,
|
||||||
..._inboxMgmt,
|
..._inboxMgmt,
|
||||||
|
..._integrationApps,
|
||||||
..._integrations,
|
..._integrations,
|
||||||
..._labelsMgmt,
|
..._labelsMgmt,
|
||||||
..._login,
|
..._login,
|
||||||
|
|
|
@ -102,6 +102,7 @@
|
||||||
"CHANGE_ACCOUNTS": "Canvia de compte",
|
"CHANGE_ACCOUNTS": "Canvia de compte",
|
||||||
"SELECTOR_SUBTITLE": "Selecciona un compte de la llista següent",
|
"SELECTOR_SUBTITLE": "Selecciona un compte de la llista següent",
|
||||||
"PROFILE_SETTINGS": "Configuració del Perfil",
|
"PROFILE_SETTINGS": "Configuració del Perfil",
|
||||||
|
"KEYBOARD_SHORTCUTS": "Keyboard Shortcuts",
|
||||||
"LOGOUT": "Sortir"
|
"LOGOUT": "Sortir"
|
||||||
},
|
},
|
||||||
"APP_GLOBAL": {
|
"APP_GLOBAL": {
|
||||||
|
@ -130,8 +131,8 @@
|
||||||
"SIDEBAR": {
|
"SIDEBAR": {
|
||||||
"CONVERSATIONS": "Converses",
|
"CONVERSATIONS": "Converses",
|
||||||
"REPORTS": "Informes",
|
"REPORTS": "Informes",
|
||||||
"CONTACTS": "Contactes",
|
|
||||||
"SETTINGS": "Configuracions",
|
"SETTINGS": "Configuracions",
|
||||||
|
"CONTACTS": "Contactes",
|
||||||
"HOME": "Inici",
|
"HOME": "Inici",
|
||||||
"AGENTS": "Agents",
|
"AGENTS": "Agents",
|
||||||
"INBOXES": "Safates d'entrada",
|
"INBOXES": "Safates d'entrada",
|
||||||
|
@ -141,13 +142,18 @@
|
||||||
"ACCOUNT_SETTINGS": "Configuració del compte",
|
"ACCOUNT_SETTINGS": "Configuració del compte",
|
||||||
"APPLICATIONS": "Applications",
|
"APPLICATIONS": "Applications",
|
||||||
"LABELS": "Etiquetes",
|
"LABELS": "Etiquetes",
|
||||||
|
"ATTRIBUTES": "Attributes",
|
||||||
"TEAMS": "Equips",
|
"TEAMS": "Equips",
|
||||||
"ALL_CONTACTS": "All Contacts",
|
"ALL_CONTACTS": "All Contacts",
|
||||||
"TAGGED_WITH": "Tagged with",
|
"TAGGED_WITH": "Tagged with",
|
||||||
"REPORTS_OVERVIEW": "Overview",
|
"REPORTS_OVERVIEW": "Overview",
|
||||||
"CSAT": "CSAT"
|
"CSAT": "CSAT",
|
||||||
|
"CAMPAIGNS": "Campaigns",
|
||||||
|
"ONGOING": "Ongoing",
|
||||||
|
"ONE_OFF": "One off"
|
||||||
},
|
},
|
||||||
"CREATE_ACCOUNT": {
|
"CREATE_ACCOUNT": {
|
||||||
|
"NO_ACCOUNT_WARNING": "Uh oh! We could not find any Chatwoot accounts. Please create a new account to continue.",
|
||||||
"NEW_ACCOUNT": "Compte nou",
|
"NEW_ACCOUNT": "Compte nou",
|
||||||
"SELECTOR_SUBTITLE": "Crear un compte nou",
|
"SELECTOR_SUBTITLE": "Crear un compte nou",
|
||||||
"API": {
|
"API": {
|
||||||
|
@ -162,5 +168,30 @@
|
||||||
},
|
},
|
||||||
"SUBMIT": "Envia"
|
"SUBMIT": "Envia"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"KEYBOARD_SHORTCUTS": {
|
||||||
|
"TITLE": {
|
||||||
|
"OPEN_CONVERSATION": "Open conversation",
|
||||||
|
"RESOLVE_AND_NEXT": "Resolve and move to next",
|
||||||
|
"NAVIGATE_DROPDOWN": "Navigate dropdown items",
|
||||||
|
"RESOLVE_CONVERSATION": "Resolve Conversation",
|
||||||
|
"GO_TO_CONVERSATION_DASHBOARD": "Go to Conversation Dashboard",
|
||||||
|
"ADD_ATTACHMENT": "Add Attachment",
|
||||||
|
"GO_TO_CONTACTS_DASHBOARD": "Go to Contacts Dashboard",
|
||||||
|
"TOGGLE_SIDEBAR": "Toggle Sidebar",
|
||||||
|
"GO_TO_REPORTS_SIDEBAR": "Go to Reports sidebar",
|
||||||
|
"MOVE_TO_NEXT_TAB": "Move to next tab in conversation list",
|
||||||
|
"GO_TO_SETTINGS": "Go to Settings",
|
||||||
|
"SWITCH_CONVERSATION_STATUS": "Switch to the next conversation status",
|
||||||
|
"SWITCH_TO_PRIVATE_NOTE": "Switch to Private Note",
|
||||||
|
"TOGGLE_RICH_CONTENT_EDITOR": "Toggle Rich Content editor",
|
||||||
|
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||||
|
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||||
|
},
|
||||||
|
"KEYS": {
|
||||||
|
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||||
|
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||||
|
"FORWARD_SLASH_KEY": "/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"HEADER": "Agenti",
|
"HEADER": "Agenti",
|
||||||
"HEADER_BTN_TXT": "Přidat agenta",
|
"HEADER_BTN_TXT": "Přidat agenta",
|
||||||
"LOADING": "Načítání seznamu agentů",
|
"LOADING": "Načítání seznamu agentů",
|
||||||
"SIDEBAR_TXT": "<p><b>Agents</b></p> <p> An <b>Agent</b> is a member of your Customer Support team. </p><p> Agents will be able to view and reply to messages from your users. The list shows all agents currently in your account. </p><p> Click on <b>Add Agent</b> to add a new agent. Agent you add will receive an email with a confirmation link to activate their account, after which they can access Chatwoot and respond to messages. </p><p> Access to Chatwoot's features are based on following roles. </p><p> <b>Agent</b> - Agents with this role can only access inboxes, reports and conversations. They can assign conversations to other agents or themselves and resolve conversations.</p><p> <b>Administrator</b> - Administrator will have access to all Chatwoot features enabled for your account, including settings, along with all of a normal agents' privileges.</p>",
|
"SIDEBAR_TXT": "<p><b>Agenti</b></p> <p> <b>Agent</b> je členem vašeho týmu zákaznické podpory. </p><p> Agenti budou moci prohlížet a odpovídat na zprávy od uživatelů. Seznam zobrazuje všechny agenty aktuálně na vašem účtu. </p><p> Pro přidání nového agenta klikněte na <b>Přidat agenta</b>. Přidaný agent obdrží e-mail s potvrzovacím odkazem pro aktivaci jejich účtu, poté bude mít přístup k Chatwoot a bude reagovat na zprávy. </p><p> Přístup k funkcím Chatwootu je založen na následujících rolích. </p><p> <b>Agent</b> - Agent s touto rolí může přistupovat pouze k doručeným zprávám, zprávám a konverzacím. Mohou přiřadit konverzace jiným agentům nebo sobě a řešit konverzace.</p><p> <b>Administrátor</b> - Správce bude mít přístup ke všem funkcím Chatwoot povoleným pro váš účet, včetně nastavení spolu se všemi obvyklými právy agenta.</p>",
|
||||||
"AGENT_TYPES": {
|
"AGENT_TYPES": {
|
||||||
"ADMINISTRATOR": "Administrátor",
|
"ADMINISTRATOR": "Administrátor",
|
||||||
"AGENT": "Agent"
|
"AGENT": "Agent"
|
||||||
|
@ -91,6 +91,23 @@
|
||||||
},
|
},
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"NO_RESULTS": "Žádné výsledky."
|
"NO_RESULTS": "Žádné výsledky."
|
||||||
|
},
|
||||||
|
"MULTI_SELECTOR": {
|
||||||
|
"PLACEHOLDER": "Nic",
|
||||||
|
"TITLE": {
|
||||||
|
"AGENT": "Vybrat agenta",
|
||||||
|
"TEAM": "Vybrat tým"
|
||||||
|
},
|
||||||
|
"SEARCH": {
|
||||||
|
"NO_RESULTS": {
|
||||||
|
"AGENT": "Nenalezeni žádní agenti",
|
||||||
|
"TEAM": "Nenalezeny žádné týmy"
|
||||||
|
},
|
||||||
|
"PLACEHOLDER": {
|
||||||
|
"AGENT": "Hledat agenty",
|
||||||
|
"TEAM": "Hledat týmy"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
85
app/javascript/dashboard/i18n/locale/cs/attributesMgmt.json
Normal file
85
app/javascript/dashboard/i18n/locale/cs/attributesMgmt.json
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
{
|
||||||
|
"ATTRIBUTES_MGMT": {
|
||||||
|
"HEADER": "Attributes",
|
||||||
|
"HEADER_BTN_TXT": "Add Attribute",
|
||||||
|
"LOADING": "Fetching attributes",
|
||||||
|
"SIDEBAR_TXT": "<p><b>Attributes</b> <p>A custom attribute tracks facts about your contacts/conversation — like the subscription plan, or when they ordered the first item etc. <br /><br />For creating a Attributes, just click on the <b>Add Attribute.</b> You can also edit or delete an existing Attribute by clicking on the Edit or Delete button.</p>",
|
||||||
|
"ADD": {
|
||||||
|
"TITLE": "Add attribute",
|
||||||
|
"SUBMIT": "Create",
|
||||||
|
"CANCEL_BUTTON_TEXT": "Zrušit",
|
||||||
|
"FORM": {
|
||||||
|
"NAME": {
|
||||||
|
"LABEL": "Display Name",
|
||||||
|
"PLACEHOLDER": "Enter attribute display name",
|
||||||
|
"ERROR": "Name is required"
|
||||||
|
},
|
||||||
|
"DESC": {
|
||||||
|
"LABEL": "Description",
|
||||||
|
"PLACEHOLDER": "Enter attribute description",
|
||||||
|
"ERROR": "Description is required"
|
||||||
|
},
|
||||||
|
"MODEL": {
|
||||||
|
"LABEL": "Model",
|
||||||
|
"PLACEHOLDER": "Please select a model",
|
||||||
|
"ERROR": "Model is required"
|
||||||
|
},
|
||||||
|
"TYPE": {
|
||||||
|
"LABEL": "Type",
|
||||||
|
"PLACEHOLDER": "Please select a type",
|
||||||
|
"ERROR": "Type is required"
|
||||||
|
},
|
||||||
|
"KEY": {
|
||||||
|
"LABEL": "Key"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"API": {
|
||||||
|
"SUCCESS_MESSAGE": "Attribute added successfully",
|
||||||
|
"ERROR_MESSAGE": "Could not able to create an attribute, Please try again later"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DELETE": {
|
||||||
|
"BUTTON_TEXT": "Vymazat",
|
||||||
|
"API": {
|
||||||
|
"SUCCESS_MESSAGE": "Attribute deleted successfully.",
|
||||||
|
"ERROR_MESSAGE": "Couldn't delete the attribute. Try again."
|
||||||
|
},
|
||||||
|
"CONFIRM": {
|
||||||
|
"TITLE": "Are you sure want to delete - %{attributeName}",
|
||||||
|
"PLACE_HOLDER": "Please type {attributeName} to confirm",
|
||||||
|
"MESSAGE": "Deleting will remove the attribute",
|
||||||
|
"YES": "Vymazat ",
|
||||||
|
"NO": "Zrušit"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"EDIT": {
|
||||||
|
"TITLE": "Edit attribute",
|
||||||
|
"UPDATE_BUTTON_TEXT": "Aktualizovat",
|
||||||
|
"API": {
|
||||||
|
"SUCCESS_MESSAGE": "Attribute updated successfully",
|
||||||
|
"ERROR_MESSAGE": "There was an error updating attribute, please try again"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"TABS": {
|
||||||
|
"HEADER": "Vlastní atributy",
|
||||||
|
"CONVERSATION": "Conversation",
|
||||||
|
"CONTACT": "Contact"
|
||||||
|
},
|
||||||
|
"LIST": {
|
||||||
|
"TABLE_HEADER": [
|
||||||
|
"Název",
|
||||||
|
"Description",
|
||||||
|
"Type",
|
||||||
|
"Key"
|
||||||
|
],
|
||||||
|
"BUTTONS": {
|
||||||
|
"EDIT": "Upravit",
|
||||||
|
"DELETE": "Vymazat"
|
||||||
|
},
|
||||||
|
"EMPTY_RESULT": {
|
||||||
|
"404": "There are no attributes created",
|
||||||
|
"NOT_FOUND": "There are no attributes configured"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
{
|
{
|
||||||
"CAMPAIGN": {
|
"CAMPAIGN": {
|
||||||
"HEADER": "Campaigns",
|
"HEADER": "Kampaně",
|
||||||
"SIDEBAR_TXT": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations. Click on <b>Add Campaign</b> to create a new campaign. You can also edit or delete an existing campaign by clicking on the Edit or Delete button.",
|
"SIDEBAR_TXT": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations. Click on <b>Add Campaign</b> to create a new campaign. You can also edit or delete an existing campaign by clicking on the Edit or Delete button.",
|
||||||
"HEADER_BTN_TXT": "Create a campaign",
|
"HEADER_BTN_TXT": {
|
||||||
|
"ONE_OFF": "Create a one off campaign",
|
||||||
|
"ONGOING": "Create a ongoing campaign"
|
||||||
|
},
|
||||||
"ADD": {
|
"ADD": {
|
||||||
"TITLE": "Create a campaign",
|
"TITLE": "Create a campaign",
|
||||||
"DESC": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations.",
|
"DESC": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations.",
|
||||||
|
@ -25,6 +28,11 @@
|
||||||
"PLACEHOLDER": "Select the customer labels",
|
"PLACEHOLDER": "Select the customer labels",
|
||||||
"ERROR": "Audience is required"
|
"ERROR": "Audience is required"
|
||||||
},
|
},
|
||||||
|
"INBOX": {
|
||||||
|
"LABEL": "Select Inbox",
|
||||||
|
"PLACEHOLDER": "Select Inbox",
|
||||||
|
"ERROR": "Inbox is required"
|
||||||
|
},
|
||||||
"MESSAGE": {
|
"MESSAGE": {
|
||||||
"LABEL": "Zpráva",
|
"LABEL": "Zpráva",
|
||||||
"PLACEHOLDER": "Please enter the message of campaign",
|
"PLACEHOLDER": "Please enter the message of campaign",
|
||||||
|
@ -80,6 +88,7 @@
|
||||||
"TABLE_HEADER": {
|
"TABLE_HEADER": {
|
||||||
"TITLE": "Title",
|
"TITLE": "Title",
|
||||||
"MESSAGE": "Zpráva",
|
"MESSAGE": "Zpráva",
|
||||||
|
"INBOX": "Inbox",
|
||||||
"STATUS": "Stav",
|
"STATUS": "Stav",
|
||||||
"SENDER": "Sender",
|
"SENDER": "Sender",
|
||||||
"URL": "URL",
|
"URL": "URL",
|
||||||
|
@ -101,6 +110,16 @@
|
||||||
"SENDER": {
|
"SENDER": {
|
||||||
"BOT": "Bot"
|
"BOT": "Bot"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ONE_OFF": {
|
||||||
|
"HEADER": "One off campaigns",
|
||||||
|
"404": "There are no one off campaigns created",
|
||||||
|
"INBOXES_NOT_FOUND": "Please create an sms inbox and start adding campaigns"
|
||||||
|
},
|
||||||
|
"ONGOING": {
|
||||||
|
"HEADER": "Ongoing campaigns",
|
||||||
|
"404": "There are no ongoing campaigns created",
|
||||||
|
"INBOXES_NOT_FOUND": "Please create an website inbox and start adding campaigns"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,12 @@
|
||||||
"VALUE": "resolved"
|
"VALUE": "resolved"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"TEXT": "Bot",
|
"TEXT": "Čekající",
|
||||||
"VALUE": "bot"
|
"VALUE": "pending"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TEXT": "Odložené",
|
||||||
|
"VALUE": "snoozed"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ATTACHMENTS": {
|
"ATTACHMENTS": {
|
||||||
|
@ -81,6 +85,6 @@
|
||||||
"VIEW_TWEET_IN_TWITTER": "Zobrazit tweet na Twitteru",
|
"VIEW_TWEET_IN_TWITTER": "Zobrazit tweet na Twitteru",
|
||||||
"REPLY_TO_TWEET": "Odpovědět na tento tweet",
|
"REPLY_TO_TWEET": "Odpovědět na tento tweet",
|
||||||
"NO_MESSAGES": "Žádné zprávy",
|
"NO_MESSAGES": "Žádné zprávy",
|
||||||
"NO_CONTENT": "No content available"
|
"NO_CONTENT": "Žádný obsah k dispozici"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,12 @@
|
||||||
"MUTED_SUCCESS": "Tato konverzace je ztlumena na 6 hodin",
|
"MUTED_SUCCESS": "Tato konverzace je ztlumena na 6 hodin",
|
||||||
"UNMUTED_SUCCESS": "Tato konverzace je odtlumena",
|
"UNMUTED_SUCCESS": "Tato konverzace je odtlumena",
|
||||||
"SEND_TRANSCRIPT": "Poslat přepis",
|
"SEND_TRANSCRIPT": "Poslat přepis",
|
||||||
"EDIT_LABEL": "Upravit"
|
"EDIT_LABEL": "Upravit",
|
||||||
|
"SIDEBAR_SECTIONS": {
|
||||||
|
"CUSTOM_ATTRIBUTES": "Vlastní atributy",
|
||||||
|
"CONTACT_LABELS": "Contact Labels",
|
||||||
|
"PREVIOUS_CONVERSATIONS": "Předchozí konverzace"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"EDIT_CONTACT": {
|
"EDIT_CONTACT": {
|
||||||
"BUTTON_LABEL": "Upravit kontakt",
|
"BUTTON_LABEL": "Upravit kontakt",
|
||||||
|
@ -107,7 +112,7 @@
|
||||||
},
|
},
|
||||||
"NEW_CONVERSATION": {
|
"NEW_CONVERSATION": {
|
||||||
"BUTTON_LABEL": "Start conversation",
|
"BUTTON_LABEL": "Start conversation",
|
||||||
"TITLE": "New conversation",
|
"TITLE": "Nová konverzace",
|
||||||
"DESC": "Start a new conversation by sending a new message.",
|
"DESC": "Start a new conversation by sending a new message.",
|
||||||
"NO_INBOX": "Couldn't find an inbox to initiate a new conversation with this contact.",
|
"NO_INBOX": "Couldn't find an inbox to initiate a new conversation with this contact.",
|
||||||
"FORM": {
|
"FORM": {
|
||||||
|
@ -186,8 +191,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CUSTOM_ATTRIBUTES": {
|
"CUSTOM_ATTRIBUTES": {
|
||||||
"TITLE": "Vlastní atributy",
|
|
||||||
"BUTTON": "Add custom attribute",
|
"BUTTON": "Add custom attribute",
|
||||||
|
"NOT_AVAILABLE": "There are no custom attributes available for this contact.",
|
||||||
"ADD": {
|
"ADD": {
|
||||||
"TITLE": "Create custom attribute",
|
"TITLE": "Create custom attribute",
|
||||||
"DESC": "Add custom information to this contact."
|
"DESC": "Add custom information to this contact."
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"SEARCH_MESSAGES": "Hledat zprávy v konverzacích",
|
"SEARCH_MESSAGES": "Hledat zprávy v konverzacích",
|
||||||
"SEARCH": {
|
"SEARCH": {
|
||||||
"TITLE": "Hledat zprávy",
|
"TITLE": "Hledat zprávy",
|
||||||
|
"RESULT_TITLE": "Výsledky hledání",
|
||||||
"LOADING_MESSAGE": "Načítám data...",
|
"LOADING_MESSAGE": "Načítám data...",
|
||||||
"PLACEHOLDER": "Zadejte jakýkoli text k hledání",
|
"PLACEHOLDER": "Zadejte jakýkoli text k hledání",
|
||||||
"NO_MATCHING_RESULTS": "Žádné výsledky."
|
"NO_MATCHING_RESULTS": "Žádné výsledky."
|
||||||
|
@ -22,16 +23,16 @@
|
||||||
"24_HOURS_WINDOW": "24 hodinové omezení okna",
|
"24_HOURS_WINDOW": "24 hodinové omezení okna",
|
||||||
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
|
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
|
||||||
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hodinové omezení okna",
|
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hodinové omezení okna",
|
||||||
"LAST_INCOMING_TWEET": "Odpovídáte na poslední příchozí tweet",
|
"SELECT_A_TWEET_TO_REPLY": "Please select a tweet to reply to.",
|
||||||
"REPLYING_TO": "Odpovídáte uživateli:",
|
"REPLYING_TO": "Odpovídáte uživateli:",
|
||||||
"REMOVE_SELECTION": "Odstranit výběr",
|
"REMOVE_SELECTION": "Odstranit výběr",
|
||||||
"DOWNLOAD": "Stáhnout",
|
"DOWNLOAD": "Stáhnout",
|
||||||
"UPLOADING_ATTACHMENTS": "Nahrávání příloh...",
|
"UPLOADING_ATTACHMENTS": "Nahrávání příloh...",
|
||||||
"SUCCESS_DELETE_MESSAGE": "Message deleted successfully",
|
"SUCCESS_DELETE_MESSAGE": "Zpráva byla úspěšně smazána",
|
||||||
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again",
|
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again",
|
||||||
"NO_RESPONSE": "Bez odpovědi",
|
"NO_RESPONSE": "Bez odpovědi",
|
||||||
"RATING_TITLE": "Rating",
|
"RATING_TITLE": "Hodnocení",
|
||||||
"FEEDBACK_TITLE": "Feedback",
|
"FEEDBACK_TITLE": "Zpětná vazba",
|
||||||
"HEADER": {
|
"HEADER": {
|
||||||
"RESOLVE_ACTION": "Vyřešit",
|
"RESOLVE_ACTION": "Vyřešit",
|
||||||
"REOPEN_ACTION": "Znovu otevřít",
|
"REOPEN_ACTION": "Znovu otevřít",
|
||||||
|
@ -41,7 +42,13 @@
|
||||||
"DETAILS": "Podrobnosti"
|
"DETAILS": "Podrobnosti"
|
||||||
},
|
},
|
||||||
"RESOLVE_DROPDOWN": {
|
"RESOLVE_DROPDOWN": {
|
||||||
"OPEN_BOT": "Open with bot"
|
"MARK_PENDING": "Mark as pending",
|
||||||
|
"SNOOZE": {
|
||||||
|
"TITLE": "Odložit do",
|
||||||
|
"NEXT_REPLY": "Další odpověď",
|
||||||
|
"TOMORROW": "Zítra",
|
||||||
|
"NEXT_WEEK": "Příští týden"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"FOOTER": {
|
"FOOTER": {
|
||||||
"MSG_INPUT": "Shift + zadejte pro nový řádek. Začněte '/' pro výběr zrušené odpovědi.",
|
"MSG_INPUT": "Shift + zadejte pro nový řádek. Začněte '/' pro výběr zrušené odpovědi.",
|
||||||
|
@ -57,13 +64,26 @@
|
||||||
"TIP_EMOJI_ICON": "Zobrazit výběr emoji",
|
"TIP_EMOJI_ICON": "Zobrazit výběr emoji",
|
||||||
"TIP_ATTACH_ICON": "Přiložit soubory",
|
"TIP_ATTACH_ICON": "Přiložit soubory",
|
||||||
"ENTER_TO_SEND": "Enter to send",
|
"ENTER_TO_SEND": "Enter to send",
|
||||||
"DRAG_DROP": "Drag and drop here to attach"
|
"DRAG_DROP": "Drag and drop here to attach",
|
||||||
|
"EMAIL_HEAD": {
|
||||||
|
"ADD_BCC": "Přidat bcc",
|
||||||
|
"CC": {
|
||||||
|
"LABEL": "CC",
|
||||||
|
"PLACEHOLDER": "E-maily oddělené čárkami",
|
||||||
|
"ERROR": "Zadejte prosím platnou e-mailovou adresu"
|
||||||
|
},
|
||||||
|
"BCC": {
|
||||||
|
"LABEL": "BCC",
|
||||||
|
"PLACEHOLDER": "E-maily oddělené čárkami",
|
||||||
|
"ERROR": "Zadejte prosím platnou e-mailovou adresu"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"VISIBLE_TO_AGENTS": "Soukromá poznámka: Viditelné pouze pro vás a váš tým",
|
"VISIBLE_TO_AGENTS": "Soukromá poznámka: Viditelné pouze pro vás a váš tým",
|
||||||
"CHANGE_STATUS": "Stav konverzace byl změněn",
|
"CHANGE_STATUS": "Stav konverzace byl změněn",
|
||||||
"CHANGE_AGENT": "Konverzace pověřená osoba změněna",
|
"CHANGE_AGENT": "Konverzace pověřená osoba změněna",
|
||||||
"CHANGE_TEAM": "Tým konverzace se změnil",
|
"CHANGE_TEAM": "Tým konverzace se změnil",
|
||||||
"FILE_SIZE_LIMIT": "File exceeds the {MAXIMUM_FILE_UPLOAD_SIZE} attachment limit",
|
"FILE_SIZE_LIMIT": "Soubor překračuje limit {MAXIMUM_FILE_UPLOAD_SIZE} přílohy",
|
||||||
"SENT_BY": "Odeslal:",
|
"SENT_BY": "Odeslal:",
|
||||||
"ASSIGNMENT": {
|
"ASSIGNMENT": {
|
||||||
"SELECT_AGENT": "Vybrat agenta",
|
"SELECT_AGENT": "Vybrat agenta",
|
||||||
|
@ -98,11 +118,11 @@
|
||||||
"READ_LATEST_UPDATES": "Přečtěte si nejnovější aktualizace",
|
"READ_LATEST_UPDATES": "Přečtěte si nejnovější aktualizace",
|
||||||
"ALL_CONVERSATION": {
|
"ALL_CONVERSATION": {
|
||||||
"TITLE": "Všechny vaše konverzace na jednom místě",
|
"TITLE": "Všechny vaše konverzace na jednom místě",
|
||||||
"DESCRIPTION": "View all the conversations from your customers in one single dashboard. You can filter the conversations by the incoming channel, label and status."
|
"DESCRIPTION": "Zobrazit všechny konverzace od zákazníků na jednom nástěnce. Můžete filtrovat konverzace podle příchozího kanálu, popisku a stavu."
|
||||||
},
|
},
|
||||||
"TEAM_MEMBERS": {
|
"TEAM_MEMBERS": {
|
||||||
"TITLE": "Pozvěte své členy týmu",
|
"TITLE": "Pozvěte své členy týmu",
|
||||||
"DESCRIPTION": "Since you are getting ready to talk to your customer, bring in your teammates to assist you. You can invite your teammates by adding their email address to the agent list.",
|
"DESCRIPTION": "Vzhledem k tomu, že se připravujete na rozhovory se zákazníkem, vdechněte své týmové spolupracovníky, kteří vám pomohou. Můžete pozvat své přátele přidáním jejich e-mailové adresy do seznamu agentů.",
|
||||||
"NEW_LINK": "Klikněte zde pro pozvání člena týmu"
|
"NEW_LINK": "Klikněte zde pro pozvání člena týmu"
|
||||||
},
|
},
|
||||||
"INBOXES": {
|
"INBOXES": {
|
||||||
|
@ -118,10 +138,24 @@
|
||||||
},
|
},
|
||||||
"CONVERSATION_SIDEBAR": {
|
"CONVERSATION_SIDEBAR": {
|
||||||
"ASSIGNEE_LABEL": "Přiřazený agent",
|
"ASSIGNEE_LABEL": "Přiřazený agent",
|
||||||
"SELF_ASSIGN": "Assign to me",
|
"SELF_ASSIGN": "Přiřadit mi",
|
||||||
"TEAM_LABEL": "Přiřazený tým",
|
"TEAM_LABEL": "Přiřazený tým",
|
||||||
"SELECT": {
|
"SELECT": {
|
||||||
"PLACEHOLDER": "Nic"
|
"PLACEHOLDER": "Nic"
|
||||||
}
|
},
|
||||||
|
"ACCORDION": {
|
||||||
|
"CONTACT_DETAILS": "Contact Details",
|
||||||
|
"CONVERSATION_ACTIONS": "Conversation Actions",
|
||||||
|
"CONVERSATION_LABELS": "Conversation Labels",
|
||||||
|
"CONVERSATION_INFO": "Conversation Information",
|
||||||
|
"CONTACT_ATTRIBUTES": "Contact Attributes",
|
||||||
|
"PREVIOUS_CONVERSATION": "Předchozí konverzace"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"EMAIL_HEADER": {
|
||||||
|
"TO": "Komu",
|
||||||
|
"BCC": "Bcc",
|
||||||
|
"CC": "Cc",
|
||||||
|
"SUBJECT": "Předmět"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"CSAT": {
|
"CSAT": {
|
||||||
"TITLE": "Rate your conversation",
|
"TITLE": "Ohodnoťte svou konverzaci",
|
||||||
"PLACEHOLDER": "Tell us more..."
|
"PLACEHOLDER": "Řekněte nám více..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Nyní můžete přijímat e-maily na vaši vlastní doménu."
|
"CUSTOM_EMAIL_DOMAIN_ENABLED": "Nyní můžete přijímat e-maily na vaši vlastní doménu."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"UPDATE_CHATWOOT": "An update %{latestChatwootVersion} for Chatwoot is available. Please update your instance."
|
"UPDATE_CHATWOOT": "Je dostupná aktualizace %{latestChatwootVersion} pro Chatwoot. Aktualizujte prosím svou instanci."
|
||||||
},
|
},
|
||||||
"FORMS": {
|
"FORMS": {
|
||||||
"MULTISELECT": {
|
"MULTISELECT": {
|
||||||
|
@ -53,11 +53,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"NOTIFICATIONS_PAGE": {
|
"NOTIFICATIONS_PAGE": {
|
||||||
"HEADER": "Notifications",
|
"HEADER": "Oznámení",
|
||||||
"MARK_ALL_DONE": "Mark All Done",
|
"MARK_ALL_DONE": "Označit vše dokončeno",
|
||||||
"LIST": {
|
"LIST": {
|
||||||
"LOADING_MESSAGE": "Loading notifications...",
|
"LOADING_MESSAGE": "Načítání upozornění...",
|
||||||
"404": "No Notifications",
|
"404": "Žádná upozornění",
|
||||||
"TABLE_HEADER": [
|
"TABLE_HEADER": [
|
||||||
"Název",
|
"Název",
|
||||||
"Telefonní číslo",
|
"Telefonní číslo",
|
||||||
|
@ -66,10 +66,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"TYPE_LABEL": {
|
"TYPE_LABEL": {
|
||||||
"conversation_creation": "New conversation",
|
"conversation_creation": "Nová konverzace",
|
||||||
"conversation_assignment": "Conversation Assigned",
|
"conversation_assignment": "Přiřazená konverzace",
|
||||||
"assigned_conversation_new_message": "New Message",
|
"assigned_conversation_new_message": "Nová zpráva",
|
||||||
"conversation_mention": "Mention"
|
"conversation_mention": "Zmínka"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,44 @@
|
||||||
},
|
},
|
||||||
"FINISH_MESSAGE": "Start forwarding your emails to the following email address."
|
"FINISH_MESSAGE": "Start forwarding your emails to the following email address."
|
||||||
},
|
},
|
||||||
|
"LINE_CHANNEL": {
|
||||||
|
"TITLE": "LINE Channel",
|
||||||
|
"DESC": "Integrate with LINE channel and start supporting your customers.",
|
||||||
|
"CHANNEL_NAME": {
|
||||||
|
"LABEL": "Název kanálu",
|
||||||
|
"PLACEHOLDER": "Zadejte název kanálu",
|
||||||
|
"ERROR": "Toto pole je povinné"
|
||||||
|
},
|
||||||
|
"LINE_CHANNEL_ID": {
|
||||||
|
"LABEL": "LINE Channel ID",
|
||||||
|
"PLACEHOLDER": "LINE Channel ID"
|
||||||
|
},
|
||||||
|
"LINE_CHANNEL_SECRET": {
|
||||||
|
"LABEL": "LINE Channel Secret",
|
||||||
|
"PLACEHOLDER": "LINE Channel Secret"
|
||||||
|
},
|
||||||
|
"LINE_CHANNEL_TOKEN": {
|
||||||
|
"LABEL": "LINE Channel Token",
|
||||||
|
"PLACEHOLDER": "LINE Channel Token"
|
||||||
|
},
|
||||||
|
"SUBMIT_BUTTON": "Create LINE Channel",
|
||||||
|
"API": {
|
||||||
|
"ERROR_MESSAGE": "We were not able to save the LINE channel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"TELEGRAM_CHANNEL": {
|
||||||
|
"TITLE": "Telegram Channel",
|
||||||
|
"DESC": "Integrate with Telegram channel and start supporting your customers.",
|
||||||
|
"BOT_TOKEN": {
|
||||||
|
"LABEL": "Bot Token",
|
||||||
|
"SUBTITLE": "Configure the bot token you have obtained from Telegram BotFather.",
|
||||||
|
"PLACEHOLDER": "Bot Token"
|
||||||
|
},
|
||||||
|
"SUBMIT_BUTTON": "Create Telegram Channel",
|
||||||
|
"API": {
|
||||||
|
"ERROR_MESSAGE": "We were not able to save the telegram channel"
|
||||||
|
}
|
||||||
|
},
|
||||||
"AUTH": {
|
"AUTH": {
|
||||||
"TITLE": "Choose a channel",
|
"TITLE": "Choose a channel",
|
||||||
"DESC": "Chatwoot supports live-chat widget, Facebook page, Twitter profile, Whatsapp, Email etc., as channels. If you want to build a custom channel, you can create it using the API channel. Select one channel from the options below to proceed."
|
"DESC": "Chatwoot supports live-chat widget, Facebook page, Twitter profile, Whatsapp, Email etc., as channels. If you want to build a custom channel, you can create it using the API channel. Select one channel from the options below to proceed."
|
||||||
|
@ -232,6 +270,7 @@
|
||||||
},
|
},
|
||||||
"DELETE": {
|
"DELETE": {
|
||||||
"BUTTON_TEXT": "Vymazat",
|
"BUTTON_TEXT": "Vymazat",
|
||||||
|
"AVATAR_DELETE_BUTTON_TEXT": "Delete Avatar",
|
||||||
"CONFIRM": {
|
"CONFIRM": {
|
||||||
"TITLE": "Potvrdit odstranění",
|
"TITLE": "Potvrdit odstranění",
|
||||||
"MESSAGE": "Opravdu chcete odstranit ",
|
"MESSAGE": "Opravdu chcete odstranit ",
|
||||||
|
@ -241,14 +280,16 @@
|
||||||
},
|
},
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS_MESSAGE": "Doručená pošta byla úspěšně smazána",
|
"SUCCESS_MESSAGE": "Doručená pošta byla úspěšně smazána",
|
||||||
"ERROR_MESSAGE": "Nelze odstranit doručenou poštu. Opakujte akci později."
|
"ERROR_MESSAGE": "Nelze odstranit doručenou poštu. Opakujte akci později.",
|
||||||
|
"AVATAR_SUCCESS_MESSAGE": "Inbox avatar deleted successfully",
|
||||||
|
"AVATAR_ERROR_MESSAGE": "Could not delete the inbox avatar. Please try again later."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TABS": {
|
"TABS": {
|
||||||
"SETTINGS": "Nastavení",
|
"SETTINGS": "Nastavení",
|
||||||
"COLLABORATORS": "Spolupracující",
|
"COLLABORATORS": "Spolupracující",
|
||||||
"CONFIGURATION": "Nastavení",
|
"CONFIGURATION": "Nastavení",
|
||||||
"CAMPAIGN": "Campaigns",
|
"CAMPAIGN": "Kampaně",
|
||||||
"PRE_CHAT_FORM": "Formulář před chatem",
|
"PRE_CHAT_FORM": "Formulář před chatem",
|
||||||
"BUSINESS_HOURS": "Pracovní doba"
|
"BUSINESS_HOURS": "Pracovní doba"
|
||||||
},
|
},
|
||||||
|
@ -273,13 +314,17 @@
|
||||||
"INBOX_UPDATE_SUB_TEXT": "Aktualizujte nastavení doručené pošty",
|
"INBOX_UPDATE_SUB_TEXT": "Aktualizujte nastavení doručené pošty",
|
||||||
"AUTO_ASSIGNMENT_SUB_TEXT": "Povolit nebo zakázat automatické přiřazování nových konverzací agentům přidaným do této schránky.",
|
"AUTO_ASSIGNMENT_SUB_TEXT": "Povolit nebo zakázat automatické přiřazování nových konverzací agentům přidaným do této schránky.",
|
||||||
"HMAC_VERIFICATION": "User Identity Validation",
|
"HMAC_VERIFICATION": "User Identity Validation",
|
||||||
"HMAC_DESCRIPTION": "Inorder validate the users identity, the SDK allows you to pass an `identifier_hash` for each user. You can generate HMAC using 'sha256' with the key shown here."
|
"HMAC_DESCRIPTION": "Inorder to validate the user's identity, the SDK allows you to pass an `identifier_hash` for each user. You can generate HMAC using 'sha256' with the key shown here.",
|
||||||
|
"INBOX_IDENTIFIER": "Inbox Identifier",
|
||||||
|
"INBOX_IDENTIFIER_SUB_TEXT": "Use the `inbox_identifier` token shown here to authentication your API clients.",
|
||||||
|
"FORWARD_EMAIL_TITLE": "Forward to Email",
|
||||||
|
"FORWARD_EMAIL_SUB_TEXT": "Start forwarding your emails to the following email address."
|
||||||
},
|
},
|
||||||
"FACEBOOK_REAUTHORIZE": {
|
"FACEBOOK_REAUTHORIZE": {
|
||||||
"TITLE": "Znovu autorizovat",
|
"TITLE": "Znovu autorizovat",
|
||||||
"SUBTITLE": "Your Facebook connection has expired, please reconnect your Facebook page to continue services",
|
"SUBTITLE": "Your Facebook connection has expired, please reconnect your Facebook page to continue services",
|
||||||
"MESSAGE_SUCCESS": "Reconnection successful",
|
"MESSAGE_SUCCESS": "Reconnection successful",
|
||||||
"MESSAGE_ERROR": "There was an error, please try again"
|
"MESSAGE_ERROR": "Došlo k chybě, zkuste to prosím znovu"
|
||||||
},
|
},
|
||||||
"PRE_CHAT_FORM": {
|
"PRE_CHAT_FORM": {
|
||||||
"DESCRIPTION": "Pre chat forms enable you to capture user information before they start conversation with you.",
|
"DESCRIPTION": "Pre chat forms enable you to capture user information before they start conversation with you.",
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { default as _agentMgmt } from './agentMgmt.json';
|
import { default as _agentMgmt } from './agentMgmt.json';
|
||||||
|
import { default as _attributesMgmt } from './attributesMgmt.json';
|
||||||
import { default as _campaign } from './campaign.json';
|
import { default as _campaign } from './campaign.json';
|
||||||
import { default as _cannedMgmt } from './cannedMgmt.json';
|
import { default as _cannedMgmt } from './cannedMgmt.json';
|
||||||
import { default as _chatlist } from './chatlist.json';
|
import { default as _chatlist } from './chatlist.json';
|
||||||
import { default as _contact } from './contact.json';
|
import { default as _contact } from './contact.json';
|
||||||
import { default as _conversation } from './conversation.json';
|
import { default as _conversation } from './conversation.json';
|
||||||
|
import { default as _csatMgmtMgmt } from './csatMgmt.json';
|
||||||
import { default as _generalSettings } from './generalSettings.json';
|
import { default as _generalSettings } from './generalSettings.json';
|
||||||
import { default as _inboxMgmt } from './inboxMgmt.json';
|
import { default as _inboxMgmt } from './inboxMgmt.json';
|
||||||
|
import { default as _integrationApps } from './integrationApps.json';
|
||||||
import { default as _integrations } from './integrations.json';
|
import { default as _integrations } from './integrations.json';
|
||||||
import { default as _labelsMgmt } from './labelsMgmt.json';
|
import { default as _labelsMgmt } from './labelsMgmt.json';
|
||||||
import { default as _login } from './login.json';
|
import { default as _login } from './login.json';
|
||||||
|
@ -18,13 +21,16 @@ import { default as _teamsSettings } from './teamsSettings.json';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
..._agentMgmt,
|
..._agentMgmt,
|
||||||
|
..._attributesMgmt,
|
||||||
..._campaign,
|
..._campaign,
|
||||||
..._cannedMgmt,
|
..._cannedMgmt,
|
||||||
..._chatlist,
|
..._chatlist,
|
||||||
..._contact,
|
..._contact,
|
||||||
..._conversation,
|
..._conversation,
|
||||||
|
..._csatMgmtMgmt,
|
||||||
..._generalSettings,
|
..._generalSettings,
|
||||||
..._inboxMgmt,
|
..._inboxMgmt,
|
||||||
|
..._integrationApps,
|
||||||
..._integrations,
|
..._integrations,
|
||||||
..._labelsMgmt,
|
..._labelsMgmt,
|
||||||
..._login,
|
..._login,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue