Compare commits

...
Author SHA1 Message Date
Muhsin Keloth 6e90600c03 chore: add packages 2024-04-30 09:13:36 +05:30
Muhsin Keloth 19410dfa3d feat: add linear 2024-04-29 13:27:18 +05:30
Shivam MishraandGitHub 78f94511ff feat: add sitemap for help center (#9280)
* feat: start sitemap

* feat: add base url and last mod to sitemap

* fix: typo

* test: sitemap generation

* test: add draft articles

* fix: escape dots in regex matching

* feat: perpend protocol to the url

* feat: use ChatwootApp.help_center_root

* feat: don't parse the URL

* fix: function declaration
2024-04-26 21:36:39 +05:30
d88d0bdd80 feat: Add user profile avatar (#9298)
* feat: add avatar

* chore: add more colors

* chore: add helpers

* chore: build prettier issues

* chore: refactor shouldShowImage

* chore: code cleanup

* Update app/javascript/v3/components/Form/InitialsAvatar.vue

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

* chore: revire comments

---------

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2024-04-26 16:02:10 +05:30
47f8b2cd0c refactor: handling keyboard shortcuts (#9242)
* fix: Resolve and go next keyboard shortcuts doesn't work

* refactor: use buildHotKeys instead of  hasPressedCommandPlusAltAndEKey

* feat: install tinykeys

* refactor: use tinykeys

* test: update buildKeyEvents

* fix: remove stray import

* feat: handle action list globally

* feat: allow configuring `allowOnFocusedInput`

* chore: Navigate chat list item

* chore: Navigate dashboard

* feat: Navigate editor top panel

* feat: Toggle file upload

* chore: More keyboard shortcuts

* chore: Update mention selection mixin

* chore: Phone input

* chore: Clean up

* chore: Clean up

* chore: Dropdown and editor

* chore: Enter key to send and clean up

* chore: Rename mixin

* chore: Review fixes

* chore: Removed unused shortcut from modal

* fix: Specs

---------

Co-authored-by: iamsivin <iamsivin@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2024-04-26 15:41:02 +05:30
PranavandGitHub ffd47081bd chore(cleanup): Delete sentiment feature (#9304)
- The feature is unused, removing it for now, will bring it back with better models later.
2024-04-25 22:49:10 -07:00
PranavandGitHub 77db0d0701 feat: Add configurable interval for IMAP sync (#9302) 2024-04-25 18:58:20 -07:00
Shivam MishraandGitHub e757237029 feat: don't show widget on plain layout (#9297) 2024-04-25 15:26:25 +05:30
04ae38076f feat: Add button component (#9276)
* feat: Add button component

* chore: code cleanup

* chore: code cleanup

* feat: update styles

* chore: cleanup button

* chore: review comments

* chore: code cleanup

* chore: review comments

* chore: fix spacing

* chore: remove unused code

* chore: remove custom click event

* feat: update props validation

* chore: review comments

* refactor: use trailingIcon as a boolean prop

* fix: build issues

---------

Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
2024-04-25 14:21:23 +05:30
Sivin VargheseandGitHub 2ddf613c58 fix: Audio attachment issues (#9260)
* fix: Audio attachment issues

* chore: Style fix

* chore: Minor fix

* chore: Minor fix

* chore: Review fixes
2024-04-25 13:42:46 +05:30
Muhsin KelothandGitHub 1bf3ad9a08 fix: Remove unnecessary attributes from notification deleted action cable event payload (#9295)
fix: simplify notification deleted payload event
2024-04-25 11:25:19 +05:30
9086650fe2 fix: heatmap colors for dark mode [CW-3241] (#9278)
* feat: add new heatmap colors

* fix: loader

* fix: move new styles to tailwind

* feat: update tw classes

* refactor: update styles

* feat: add useI18n composable

* feat: use composition api

* fix: empty div

* chore: don't import defineProps

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

---------

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2024-04-25 10:23:15 +05:30
Shivam MishraandGitHub 8c813097db feat: update SLA upgrade banner (#9291)
feat: add cancel anytime notice
2024-04-24 17:19:35 +05:30
12403b75d6 feat: remove log rocket (#9279)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2024-04-24 12:36:36 +05:30
Shivam MishraandGitHub 480cf4952d fix: set size limit to 300KB (#9289) 2024-04-24 12:09:31 +05:30
Muhsin KelothandGitHub d7e928df26 feat: Add loom video embed support for help center articles (#9288)
* feat: Add loom support for helpcenter articles

* fix: responsiveness

* fix: style issues

* fix: review comments

* Update custom_markdown_renderer.rb
2024-04-24 11:44:10 +05:30
Muhsin KelothandGitHub 8957277e5d feat: Add new colors (#9258) 2024-04-22 14:08:12 +05:30
Sojan JoseandGitHub 60b355b500 fix: Avoid vector search if query is not present in the params (#9265) 2024-04-19 14:50:49 -07:00
Sivin VargheseandGitHub d2e324b5fd fix: Remove duplicate tooltip for failed messages on the conversation UI (#9259) 2024-04-19 09:47:41 -07:00
Sojan JoseandGitHub 15638e9b8b chore: Add validation to prevent message flooding (#9254)
- Add a validation to limit messages created per minute to avoid message flooding cases.
2024-04-18 00:14:59 -07:00
ca2fa5ff06 fix: Clicking on contact attributes doesn't do anything if contact attributes list is empty (#9257)
* fix: Clicking on contact attributes doesn't do anything if contact attributes list is empty

* Update app/javascript/dashboard/i18n/locale/en/conversation.json

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>

* Update app/javascript/dashboard/i18n/locale/en/contact.json

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2024-04-18 12:31:32 +05:30
PranavandGitHub 888d3cb3fa chore: Increase the rate limit for contact search (#9256) 2024-04-17 16:59:38 -07:00
Sojan 8fcf476206 Merge branch 'release/3.8.0' into develop 2024-04-16 17:09:17 -07:00
Sojan 29f07e7e06 Bump version to 3.8.0 2024-04-16 17:08:36 -07:00
2cde42c7ec feat: add upgrade banner for SLA feature (#9240)
- Add an upgrade CTA for the SLA feature

-------------------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
Co-authored-by: Pranav <pranav@chatwoot.com>
2024-04-16 16:59:39 -07:00
Sojan JoseandGitHub d12c38c344 chore: Move embedding generation to sidekiq (#9238)
chore: Move embedding generation to a job
2024-04-16 09:43:16 -07:00
Sivin VargheseandGitHub 5cc41c9ed5 fix: Reports filter style issue (#9241) 2024-04-16 11:12:04 +05:30
c05a79cf61 fix: Add more filters for SLA download reports (#9231)
Co-authored-by: iamsivin <iamsivin@gmail.com>
2024-04-16 09:00:52 +05:30
f71f43e54a chore: Update translations (#9236)
- update translations 

------------------
Co-authored-by: Sojan <sojan@pepalo.com>
2024-04-15 18:49:04 -07:00
Sojan JoseandGitHub db87cde09e chore: Fix typo in help center embedding search helper (#9237)
chore: fix typo in helpcenter embedding search helper
2024-04-15 17:54:52 -07:00
634 changed files with 12094 additions and 3177 deletions
-5
View File
@@ -180,8 +180,6 @@ ANDROID_SHA256_CERT_FINGERPRINT=AC:73:8E:DE:EB:56:EA:CC:10:87:02:A7:65:37:7B:38:
## Sentry ## Sentry
# SENTRY_DSN= # SENTRY_DSN=
## LogRocket
# LOG_ROCKET_PROJECT_ID=xxxxx/some-project
# MICROSOFT CLARITY # MICROSOFT CLARITY
# MS_CLARITY_TOKEN=xxxxxxxxx # MS_CLARITY_TOKEN=xxxxxxxxx
@@ -251,9 +249,6 @@ AZURE_APP_SECRET=
## OpenAI key ## OpenAI key
# OPENAI_API_KEY= # OPENAI_API_KEY=
# Sentiment analysis model file path
SENTIMENT_FILE_PATH=
# Housekeeping/Performance related configurations # Housekeeping/Performance related configurations
# Set to true if you want to remove stale contact inboxes # Set to true if you want to remove stale contact inboxes
# contact_inboxes with no conversation older than 90 days will be removed # contact_inboxes with no conversation older than 90 days will be removed
-3
View File
@@ -175,9 +175,6 @@ gem 'pgvector'
# Convert Website HTML to Markdown # Convert Website HTML to Markdown
gem 'reverse_markdown' gem 'reverse_markdown'
# Sentiment analysis
gem 'informers'
### Gems required only in specific deployment environments ### ### Gems required only in specific deployment environments ###
############################################################## ##############################################################
+14 -26
View File
@@ -151,7 +151,6 @@ GEM
base64 (0.1.1) base64 (0.1.1)
bcrypt (3.1.20) bcrypt (3.1.20)
bindex (0.8.1) bindex (0.8.1)
blingfire (0.1.8)
bootsnap (1.16.0) bootsnap (1.16.0)
msgpack (~> 1.2) msgpack (~> 1.2)
brakeman (5.4.1) brakeman (5.4.1)
@@ -316,15 +315,15 @@ GEM
google-cloud-translate-v3 (0.6.0) google-cloud-translate-v3 (0.6.0)
gapic-common (>= 0.17.1, < 2.a) gapic-common (>= 0.17.1, < 2.a)
google-cloud-errors (~> 1.0) google-cloud-errors (~> 1.0)
google-protobuf (3.25.2) google-protobuf (3.25.3)
google-protobuf (3.25.2-arm64-darwin) google-protobuf (3.25.3-arm64-darwin)
google-protobuf (3.25.2-x86_64-darwin) google-protobuf (3.25.3-x86_64-darwin)
google-protobuf (3.25.2-x86_64-linux) google-protobuf (3.25.3-x86_64-linux)
googleapis-common-protos (1.4.0) googleapis-common-protos (1.4.0)
google-protobuf (~> 3.14) google-protobuf (~> 3.14)
googleapis-common-protos-types (~> 1.2) googleapis-common-protos-types (~> 1.2)
grpc (~> 1.27) grpc (~> 1.27)
googleapis-common-protos-types (1.11.0) googleapis-common-protos-types (1.14.0)
google-protobuf (~> 3.18) google-protobuf (~> 3.18)
googleauth (1.5.2) googleauth (1.5.2)
faraday (>= 0.17.3, < 3.a) faraday (>= 0.17.3, < 3.a)
@@ -335,14 +334,17 @@ GEM
signet (>= 0.16, < 2.a) signet (>= 0.16, < 2.a)
groupdate (6.2.1) groupdate (6.2.1)
activesupport (>= 5.2) activesupport (>= 5.2)
grpc (1.54.3) grpc (1.62.0)
google-protobuf (~> 3.21) google-protobuf (~> 3.25)
googleapis-common-protos-types (~> 1.0) googleapis-common-protos-types (~> 1.0)
grpc (1.54.3-x86_64-darwin) grpc (1.62.0-arm64-darwin)
google-protobuf (~> 3.21) google-protobuf (~> 3.25)
googleapis-common-protos-types (~> 1.0) googleapis-common-protos-types (~> 1.0)
grpc (1.54.3-x86_64-linux) grpc (1.62.0-x86_64-darwin)
google-protobuf (~> 3.21) google-protobuf (~> 3.25)
googleapis-common-protos-types (~> 1.0)
grpc (1.62.0-x86_64-linux)
google-protobuf (~> 3.25)
googleapis-common-protos-types (~> 1.0) googleapis-common-protos-types (~> 1.0)
haikunator (1.1.1) haikunator (1.1.1)
hairtrigger (1.0.0) hairtrigger (1.0.0)
@@ -371,10 +373,6 @@ GEM
image_processing (1.12.2) image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5) mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3) ruby-vips (>= 2.0.17, < 3)
informers (0.2.0)
blingfire (>= 0.1.7)
numo-narray
onnxruntime (>= 0.5.1)
io-console (0.6.0) io-console (0.6.0)
irb (1.7.2) irb (1.7.2)
reline (>= 0.3.6) reline (>= 0.3.6)
@@ -500,7 +498,6 @@ GEM
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.16.4-x86_64-linux) nokogiri (1.16.4-x86_64-linux)
racc (~> 1.4) racc (~> 1.4)
numo-narray (0.9.2.1)
oauth (1.1.0) oauth (1.1.0)
oauth-tty (~> 1.0, >= 1.0.1) oauth-tty (~> 1.0, >= 1.0.1)
snaky_hash (~> 2.0) snaky_hash (~> 2.0)
@@ -529,14 +526,6 @@ GEM
omniauth-rails_csrf_protection (1.0.1) omniauth-rails_csrf_protection (1.0.1)
actionpack (>= 4.2) actionpack (>= 4.2)
omniauth (~> 2.0) omniauth (~> 2.0)
onnxruntime (0.7.6)
ffi
onnxruntime (0.7.6-arm64-darwin)
ffi
onnxruntime (0.7.6-x86_64-darwin)
ffi
onnxruntime (0.7.6-x86_64-linux)
ffi
openssl (3.1.0) openssl (3.1.0)
orm_adapter (0.5.0) orm_adapter (0.5.0)
os (1.1.4) os (1.1.4)
@@ -892,7 +881,6 @@ DEPENDENCIES
hashie hashie
html2text! html2text!
image_processing image_processing
informers
jbuilder jbuilder
json_refs json_refs
json_schemer json_schemer
@@ -6,6 +6,12 @@ class Public::Api::V1::PortalsController < Public::Api::V1::Portals::BaseControl
def show; end def show; end
def sitemap
@help_center_url = @portal.custom_domain || ChatwootApp.help_center_root
# if help_center_url does not contain a protocol, prepend it with https
@help_center_url = "https://#{@help_center_url}" unless @help_center_url.include?('://')
end
private private
def portal def portal
@@ -37,6 +37,7 @@ class SLAReportsAPI extends ApiClient {
inbox_id, inbox_id,
team_id, team_id,
sla_policy_id, sla_policy_id,
label_list,
} = {}) { } = {}) {
return axios.get(`${this.url}/download`, { return axios.get(`${this.url}/download`, {
params: { params: {
@@ -45,6 +46,7 @@ class SLAReportsAPI extends ApiClient {
assigned_agent_id, assigned_agent_id,
inbox_id, inbox_id,
team_id, team_id,
label_list,
sla_policy_id, sla_policy_id,
}, },
}); });
@@ -83,6 +83,7 @@ describe('#SLAReports API', () => {
inbox_id: 1, inbox_id: 1,
team_id: 1, team_id: 1,
sla_policy_id: 1, sla_policy_id: 1,
label_list: ['label1'],
}); });
expect(axiosMock.get).toHaveBeenCalledWith( expect(axiosMock.get).toHaveBeenCalledWith(
'/api/v1/applied_slas/download', '/api/v1/applied_slas/download',
@@ -94,6 +95,7 @@ describe('#SLAReports API', () => {
inbox_id: 1, inbox_id: 1,
team_id: 1, team_id: 1,
sla_policy_id: 1, sla_policy_id: 1,
label_list: ['label1'],
}, },
} }
); );
@@ -40,3 +40,347 @@
.hide { .hide {
@apply hidden; @apply hidden;
} }
@layer base {
// scss-lint:disable PropertySortOrder
:root {
--color-amber-25: 254 253 251;
--color-amber-50: 255 249 237;
--color-amber-75: 255 243 208;
--color-amber-100: 255 236 183;
--color-amber-200: 255 224 161;
--color-amber-300: 245 208 140;
--color-amber-400: 228 187 120;
--color-amber-500: 214 163 92;
--color-amber-600: 214 163 92;
--color-amber-700: 255 186 26;
--color-amber-800: 145 89 48;
--color-amber-900: 79 52 34;
--color-ash-100: 235 235 239;
--color-ash-200: 228 228 233;
--color-ash-25: 252 252 253;
--color-ash-300: 221 221 227;
--color-ash-400: 211 212 219;
--color-ash-50: 249 249 251;
--color-ash-500: 185 187 198;
--color-ash-600: 139 141 152;
--color-ash-700: 126 128 138;
--color-ash-75: 242 242 245;
--color-ash-800: 96 100 108;
--color-ash-900: 28 32 36;
--color-primary-25: 251 253 255;
--color-primary-50: 245 249 255;
--color-primary-75: 233 243 255;
--color-primary-100: 218 236 255;
--color-primary-200: 201 226 255;
--color-primary-300: 181 213 255;
--color-primary-400: 155 195 252;
--color-primary-500: 117 171 247;
--color-primary-600: 39 129 246;
--color-primary-700: 16 115 233;
--color-primary-800: 8 109 224;
--color-primary-900: 11 50 101;
--color-ruby-100: 255 220 225;
--color-ruby-200: 255 206 214;
--color-ruby-25: 255 252 253;
--color-ruby-300: 248 191 200;
--color-ruby-400: 239 172 184;
--color-ruby-50: 255 247 248;
--color-ruby-500: 229 146 163;
--color-ruby-600: 229 70 102;
--color-ruby-700: 220 59 93;
--color-ruby-75: 254 234 237;
--color-ruby-800: 202 36 77;
--color-ruby-900: 100 23 43;
--color-teal-100: 224 248 243;
--color-teal-200: 204 243 234;
--color-teal-25: 250 254 253;
--color-teal-300: 184 234 224;
--color-teal-400: 161 222 210;
--color-teal-50: 243 251 249;
--color-teal-500: 83 185 171;
--color-teal-600: 18 165 148;
--color-teal-700: 13 155 138;
--color-teal-75: 236 249 255;
--color-teal-800: 0 133 115;
--color-teal-900: 13 61 56;
--color-green-25: 251 254 252;
--color-green-50: 244 251 246;
--color-green-75: 230 246 235;
--color-green-100: 214 241 223;
--color-green-200: 196 232 209;
--color-green-300: 173 221 192;
--color-green-400: 142 206 170;
--color-green-500: 91 185 139;
--color-green-600: 48 164 108;
--color-green-700: 43 154 102;
--color-green-800: 33 131 88;
--color-green-900: 25 59 45;
--color-mint-25: 249 254 253;
--color-mint-50: 242 251 249;
--color-mint-75: 221 249 242;
--color-mint-100: 200 244 233;
--color-mint-200: 179 236 222;
--color-mint-300: 156 224 208;
--color-mint-400: 126 207 189;
--color-mint-500: 76 187 165;
--color-mint-600: 134 234 212;
--color-mint-700: 125 224 203;
--color-mint-800: 2 120 100;
--color-mint-900: 22 67 60;
--color-sky-25: 249 254 255;
--color-sky-50: 241 250 253;
--color-sky-75: 225 246 253;
--color-sky-100: 209 240 250;
--color-sky-200: 190 231 245;
--color-sky-300: 169 218 237;
--color-sky-400: 141 202 227;
--color-sky-500: 96 179 215;
--color-sky-600: 124 226 254;
--color-sky-700: 116 218 248;
--color-sky-800: 0 116 158;
--color-sky-900: 29 62 86;
--color-indigo-25: 253 253 254;
--color-indigo-50: 247 249 255;
--color-indigo-75: 237 242 254;
--color-indigo-100: 225 233 255;
--color-indigo-200: 210 222 255;
--color-indigo-300: 193 208 255;
--color-indigo-400: 171 189 249;
--color-indigo-500: 141 164 239;
--color-indigo-600: 62 99 221;
--color-indigo-700: 51 88 212;
--color-indigo-800: 58 91 199;
--color-indigo-900: 31 45 92;
--color-iris-25: 253 253 255;
--color-iris-50: 248 248 255;
--color-iris-75: 240 241 254;
--color-iris-100: 230 231 255;
--color-iris-200: 218 220 255;
--color-iris-300: 203 205 255;
--color-iris-400: 184 186 248;
--color-iris-500: 155 158 240;
--color-iris-600: 91 91 214;
--color-iris-700: 81 81 205;
--color-iris-800: 87 83 198;
--color-iris-900: 39 41 98;
--color-violet-25: 253 252 254;
--color-violet-50: 250 248 255;
--color-violet-75: 244 240 254;
--color-violet-100: 235 228 255;
--color-violet-200: 225 217 255;
--color-violet-300: 212 202 254;
--color-violet-400: 194 181 245;
--color-violet-500: 170 153 236;
--color-violet-600: 110 86 207;
--color-violet-700: 101 77 196;
--color-violet-800: 101 80 185;
--color-violet-900: 47 38 95;
--color-pink-25: 255 252 254;
--color-pink-50: 254 247 251;
--color-pink-75: 254 233 245;
--color-pink-100: 251 220 239;
--color-pink-200: 246 206 231;
--color-pink-300: 239 191 221;
--color-pink-400: 231 172 208;
--color-pink-500: 221 147 194;
--color-pink-600: 214 64 159;
--color-pink-700: 207 56 151;
--color-pink-800: 194 41 138;
--color-pink-900: 101 18 73;
--color-orange-25: 254 252 251;
--color-orange-50: 255 247 237;
--color-orange-75: 255 239 214;
--color-orange-100: 255 223 181;
--color-orange-200: 255 209 154;
--color-orange-300: 255 193 130;
--color-orange-400: 245 174 115;
--color-orange-500: 236 148 85;
--color-orange-600: 247 107 21;
--color-orange-700: 239 95 0;
--color-orange-800: 204 78 0;
--color-orange-900: 88 45 29;
}
// scss-lint:disable QualifyingElement
body.dark {
--color-amber-25: 31 19 0;
--color-amber-50: 37 24 4;
--color-amber-75: 48 32 11;
--color-amber-100: 57 39 15;
--color-amber-200: 67 46 18;
--color-amber-300: 83 57 22;
--color-amber-400: 111 77 29;
--color-amber-500: 169 118 42;
--color-amber-600: 169 118 42;
--color-amber-700: 255 203 71;
--color-amber-800: 255 204 77;
--color-amber-900: 255 231 179;
--color-ash-100: 46 48 53;
--color-ash-200: 53 55 60;
--color-ash-25: 24 24 26;
--color-ash-300: 60 63 68;
--color-ash-400: 70 75 80;
--color-ash-50: 27 27 31;
--color-ash-500: 90 97 101;
--color-ash-600: 105 110 119;
--color-ash-700: 120 127 133;
--color-ash-75: 39 40 45;
--color-ash-800: 173 177 184;
--color-ash-900: 237 238 240;
--color-primary-25: 10 17 28;
--color-primary-50: 15 24 38;
--color-primary-75: 15 39 72;
--color-primary-100: 10 49 99;
--color-primary-200: 18 61 117;
--color-primary-300: 29 74 134;
--color-primary-400: 40 89 156;
--color-primary-500: 48 106 186;
--color-primary-600: 39 129 246;
--color-primary-700: 21 116 231;
--color-primary-800: 126 182 255;
--color-primary-900: 205 227 255;
--color-ruby-100: 78 19 37;
--color-ruby-200: 94 26 46;
--color-ruby-25: 25 17 19;
--color-ruby-300: 111 37 57;
--color-ruby-400: 136 52 71;
--color-ruby-50: 30 21 23;
--color-ruby-500: 179 68 90;
--color-ruby-600: 229 70 102;
--color-ruby-700: 236 90 114;
--color-ruby-75: 58 20 30;
--color-ruby-800: 255 148 157;
--color-ruby-900: 254 210 225;
--color-teal-100: 2 59 55;
--color-teal-200: 8 72 67;
--color-teal-25: 13 21 20;
--color-teal-300: 28 105 97;
--color-teal-400: 28 105 97;
--color-teal-50: 17 28 27;
--color-teal-500: 32 126 115;
--color-teal-600: 41 163 131;
--color-teal-700: 14 179 158;
--color-teal-75: 13 45 42;
--color-teal-800: 11 216 182;
--color-teal-900: 173 240 221;
--color-green-25: 14 21 18;
--color-green-50: 18 27 23;
--color-green-75: 19 45 33;
--color-green-100: 17 59 41;
--color-green-200: 23 73 51;
--color-green-300: 32 87 62;
--color-green-400: 40 104 74;
--color-green-500: 47 124 87;
--color-green-600: 48 164 108;
--color-green-700: 51 176 116;
--color-green-800: 61 214 140;
--color-green-900: 177 241 203;
--color-mint-25: 14 21 21;
--color-mint-50: 15 27 27;
--color-mint-75: 9 44 43;
--color-mint-100: 0 58 56;
--color-mint-200: 0 71 68;
--color-mint-300: 16 86 80;
--color-mint-400: 30 104 95;
--color-mint-500: 39 127 112;
--color-mint-600: 134 234 212;
--color-mint-700: 168 245 229;
--color-mint-800: 88 213 186;
--color-mint-900: 196 245 225;
--color-sky-25: 14 21 21;
--color-sky-50: 15 27 27;
--color-sky-75: 9 44 43;
--color-sky-100: 0 58 56;
--color-sky-200: 0 71 68;
--color-sky-300: 16 86 80;
--color-sky-400: 30 104 95;
--color-sky-500: 39 127 112;
--color-sky-600: 134 234 212;
--color-sky-700: 168 245 229;
--color-sky-800: 88 213 186;
--color-sky-900: 196 245 225;
--color-indigo-25: 17 19 31;
--color-indigo-50: 20 23 38;
--color-indigo-75: 24 36 73;
--color-indigo-100: 29 46 98;
--color-indigo-200: 37 57 116;
--color-indigo-300: 48 67 132;
--color-indigo-400: 58 79 151;
--color-indigo-500: 67 93 177;
--color-indigo-600: 62 99 221;
--color-indigo-700: 84 114 228;
--color-indigo-800: 158 177 255;
--color-indigo-900: 214 225 255;
--color-iris-25: 19 19 30;
--color-iris-50: 23 22 37;
--color-iris-75: 32 34 72;
--color-iris-100: 38 42 101;
--color-iris-200: 48 51 116;
--color-iris-300: 61 62 130;
--color-iris-400: 74 74 149;
--color-iris-500: 89 88 177;
--color-iris-600: 91 91 214;
--color-iris-700: 110 106 222;
--color-iris-800: 177 169 255;
--color-iris-900: 224 223 254;
--color-violet-25: 20 18 31;
--color-violet-50: 27 21 37;
--color-violet-75: 41 31 67;
--color-violet-100: 51 37 91;
--color-violet-200: 60 46 105;
--color-violet-300: 71 56 118;
--color-violet-400: 86 70 139;
--color-violet-500: 105 88 173;
--color-violet-600: 110 86 207;
--color-violet-700: 125 102 217;
--color-violet-800: 186 167 255;
--color-violet-900: 226 221 254;
--color-pink-25: 25 17 23;
--color-pink-50: 33 18 29;
--color-pink-75: 55 23 47;
--color-pink-100: 75 20 61;
--color-pink-200: 89 28 71;
--color-pink-300: 105 41 85;
--color-pink-400: 131 56 105;
--color-pink-500: 168 72 133;
--color-pink-600: 214 64 159;
--color-pink-700: 222 81 168;
--color-pink-800: 255 141 204;
--color-pink-900: 253 209 234;
--color-orange-25: 23 18 14;
--color-orange-50: 30 22 15;
--color-orange-75: 51 30 11;
--color-orange-100: 70 33 0;
--color-orange-200: 86 40 0;
--color-orange-300: 102 53 12;
--color-orange-400: 126 69 29;
--color-orange-500: 163 88 41;
--color-orange-600: 247 107 21;
--color-orange-700: 255 128 31;
--color-orange-800: 255 160 87;
--color-orange-900: 255 224 194;
}
}
@@ -185,7 +185,7 @@ import ConversationBasicFilter from './widgets/conversation/ConversationBasicFil
import ChatTypeTabs from './widgets/ChatTypeTabs.vue'; import ChatTypeTabs from './widgets/ChatTypeTabs.vue';
import ConversationItem from './ConversationItem.vue'; import ConversationItem from './ConversationItem.vue';
import timeMixin from '../mixins/time'; import timeMixin from '../mixins/time';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import conversationMixin from '../mixins/conversations'; import conversationMixin from '../mixins/conversations';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import advancedFilterTypes from './widgets/conversation/advancedFilterItems'; import advancedFilterTypes from './widgets/conversation/advancedFilterItems';
@@ -199,11 +199,6 @@ import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import languages from 'dashboard/components/widgets/conversation/advancedFilterItems/languages'; import languages from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
import countries from 'shared/constants/countries'; import countries from 'shared/constants/countries';
import { generateValuesForEditCustomViews } from 'dashboard/helper/customViewsHelper'; import { generateValuesForEditCustomViews } from 'dashboard/helper/customViewsHelper';
import {
hasPressedAltAndJKey,
hasPressedAltAndKKey,
} from 'shared/helpers/KeyboardHelpers';
import { conversationListPageURL } from '../helper/URLHelper'; import { conversationListPageURL } from '../helper/URLHelper';
import { import {
isOnMentionsView, isOnMentionsView,
@@ -228,7 +223,7 @@ export default {
mixins: [ mixins: [
timeMixin, timeMixin,
conversationMixin, conversationMixin,
eventListenerMixins, keyboardEventListenerMixins,
alertMixin, alertMixin,
filterMixin, filterMixin,
uiSettingsMixin, uiSettingsMixin,
@@ -691,30 +686,40 @@ export default {
lastConversationIndex, lastConversationIndex,
}; };
}, },
handleKeyEvents(e) { handlePreviousConversation() {
if (hasPressedAltAndJKey(e)) { const { allConversations, activeConversationIndex } =
const { allConversations, activeConversationIndex } = this.getKeyboardListenerParams();
this.getKeyboardListenerParams(); if (activeConversationIndex === -1) {
if (activeConversationIndex === -1) { allConversations[0].click();
allConversations[0].click();
}
if (activeConversationIndex >= 1) {
allConversations[activeConversationIndex - 1].click();
}
} }
if (hasPressedAltAndKKey(e)) { if (activeConversationIndex >= 1) {
const { allConversations[activeConversationIndex - 1].click();
allConversations,
activeConversationIndex,
lastConversationIndex,
} = this.getKeyboardListenerParams();
if (activeConversationIndex === -1) {
allConversations[lastConversationIndex].click();
} else if (activeConversationIndex < lastConversationIndex) {
allConversations[activeConversationIndex + 1].click();
}
} }
}, },
handleNextConversation() {
const {
allConversations,
activeConversationIndex,
lastConversationIndex,
} = this.getKeyboardListenerParams();
if (activeConversationIndex === -1) {
allConversations[lastConversationIndex].click();
} else if (activeConversationIndex < lastConversationIndex) {
allConversations[activeConversationIndex + 1].click();
}
},
getKeyboardEvents() {
return {
'Alt+KeyJ': {
action: () => this.handlePreviousConversation(),
allowOnFocusedInput: true,
},
'Alt+KeyK': {
action: () => this.handleNextConversation(),
allowOnFocusedInput: true,
},
};
},
resetAndFetchData() { resetAndFetchData() {
this.appliedFilter = []; this.appliedFilter = [];
this.resetBulkActions(); this.resetBulkActions();
@@ -91,12 +91,7 @@ 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 CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue'; import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import {
hasPressedAltAndEKey,
hasPressedCommandPlusAltAndEKey,
hasPressedAltAndMKey,
} from 'shared/helpers/KeyboardHelpers';
import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers'; import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue'; import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue'; import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
@@ -114,7 +109,7 @@ export default {
WootDropdownMenu, WootDropdownMenu,
CustomSnoozeModal, CustomSnoozeModal,
}, },
mixins: [clickaway, alertMixin, eventListenerMixins], mixins: [clickaway, alertMixin, keyboardEventListenerMixins],
props: { conversationId: { type: [String, Number], required: true } }, props: { conversationId: { type: [String, Number], required: true } },
data() { data() {
return { return {
@@ -159,37 +154,52 @@ export default {
bus.$off(CMD_RESOLVE_CONVERSATION, this.onCmdResolveConversation); bus.$off(CMD_RESOLVE_CONVERSATION, this.onCmdResolveConversation);
}, },
methods: { methods: {
async handleKeyEvents(e) { getKeyboardEvents() {
return {
'Alt+KeyM': {
action: () => this.$refs.arrowDownButton?.$el.click(),
allowOnFocusedInput: true,
},
'Alt+KeyE': this.resolveOrToast,
'$mod+Alt+KeyE': async event => {
const { all, activeIndex, lastIndex } = this.getConversationParams();
await this.resolveOrToast();
if (activeIndex < lastIndex) {
all[activeIndex + 1].click();
} else if (all.length > 1) {
all[0].click();
document.querySelector('.conversations-list').scrollTop = 0;
}
event.preventDefault();
},
};
},
getConversationParams() {
const allConversations = document.querySelectorAll( const allConversations = document.querySelectorAll(
'.conversations-list .conversation' '.conversations-list .conversation'
); );
if (hasPressedAltAndMKey(e)) {
if (this.$refs.arrowDownButton) { const activeConversation = document.querySelector(
this.$refs.arrowDownButton.$el.click(); 'div.conversations-list div.conversation.active'
} );
} const activeConversationIndex = [...allConversations].indexOf(
if (hasPressedAltAndEKey(e)) { activeConversation
const activeConversation = document.querySelector( );
'div.conversations-list div.conversation.active' const lastConversationIndex = allConversations.length - 1;
);
const activeConversationIndex = [...allConversations].indexOf( return {
activeConversation all: allConversations,
); activeIndex: activeConversationIndex,
const lastConversationIndex = allConversations.length - 1; lastIndex: lastConversationIndex,
try { };
await this.toggleStatus(wootConstants.STATUS_TYPE.RESOLVED); },
} catch (error) { async resolveOrToast() {
// error try {
} await this.toggleStatus(wootConstants.STATUS_TYPE.RESOLVED);
if (hasPressedCommandPlusAltAndEKey(e)) { } catch (error) {
if (activeConversationIndex < lastConversationIndex) { // error
allConversations[activeConversationIndex + 1].click();
} else if (allConversations.length > 1) {
allConversations[0].click();
document.querySelector('.conversations-list').scrollTop = 0;
}
e.preventDefault();
}
} }
}, },
onCmdSnoozeConversation(snoozeType) { onCmdSnoozeConversation(snoozeType) {
@@ -1,5 +1,5 @@
<template> <template>
<aside class="h-full flex"> <aside class="flex h-full">
<primary-sidebar <primary-sidebar
:logo-source="globalConfig.logoThumbnail" :logo-source="globalConfig.logoThumbnail"
:installation-name="globalConfig.installationName" :installation-name="globalConfig.installationName"
@@ -36,15 +36,7 @@ import alertMixin from 'shared/mixins/alertMixin';
import PrimarySidebar from './sidebarComponents/Primary.vue'; import PrimarySidebar from './sidebarComponents/Primary.vue';
import SecondarySidebar from './sidebarComponents/Secondary.vue'; import SecondarySidebar from './sidebarComponents/Secondary.vue';
import { import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
hasPressedAltAndCKey,
hasPressedAltAndRKey,
hasPressedAltAndSKey,
hasPressedAltAndVKey,
hasPressedCommandAndForwardSlash,
isEscape,
} from 'shared/helpers/KeyboardHelpers';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import router from '../../routes'; import router from '../../routes';
export default { export default {
@@ -52,7 +44,7 @@ export default {
PrimarySidebar, PrimarySidebar,
SecondarySidebar, SecondarySidebar,
}, },
mixins: [adminMixin, alertMixin, eventListenerMixins], mixins: [adminMixin, alertMixin, keyboardEventListenerMixins],
props: { props: {
showSecondarySidebar: { showSecondarySidebar: {
type: Boolean, type: Boolean,
@@ -173,30 +165,27 @@ export default {
closeKeyShortcutModal() { closeKeyShortcutModal() {
this.$emit('close-key-shortcut-modal'); this.$emit('close-key-shortcut-modal');
}, },
handleKeyEvents(e) { getKeyboardEvents() {
if (hasPressedCommandAndForwardSlash(e)) { return {
this.toggleKeyShortcutModal(); '$mod+Slash': this.toggleKeyShortcutModal,
} '$mod+Escape': this.closeKeyShortcutModal,
if (isEscape(e)) { 'Alt+KeyC': {
this.closeKeyShortcutModal(); action: () => this.navigateToRoute('home'),
} },
'Alt+KeyV': {
if (hasPressedAltAndCKey(e)) { action: () => this.navigateToRoute('contacts_dashboard'),
if (!this.isCurrentRouteSameAsNavigation('home')) { },
router.push({ name: 'home' }); 'Alt+KeyR': {
} action: () => this.navigateToRoute('account_overview_reports'),
} else if (hasPressedAltAndVKey(e)) { },
if (!this.isCurrentRouteSameAsNavigation('contacts_dashboard')) { 'Alt+KeyS': {
router.push({ name: 'contacts_dashboard' }); action: () => this.navigateToRoute('agent_list'),
} },
} else if (hasPressedAltAndRKey(e)) { };
if (!this.isCurrentRouteSameAsNavigation('settings_account_reports')) { },
router.push({ name: 'settings_account_reports' }); navigateToRoute(routeName) {
} if (!this.isCurrentRouteSameAsNavigation(routeName)) {
} else if (hasPressedAltAndSKey(e)) { router.push({ name: routeName });
if (!this.isCurrentRouteSameAsNavigation('agent_list')) {
router.push({ name: 'agent_list' });
}
} }
}, },
isCurrentRouteSameAsNavigation(routeName) { isCurrentRouteSameAsNavigation(routeName) {
@@ -142,20 +142,13 @@ const settings = accountId => ({
toStateName: 'settings_applications', toStateName: 'settings_applications',
featureFlag: FEATURE_FLAGS.INTEGRATIONS, featureFlag: FEATURE_FLAGS.INTEGRATIONS,
}, },
{
icon: 'credit-card-person',
label: 'BILLING',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/billing`),
toStateName: 'billing_settings_index',
showOnlyOnCloud: true,
},
{ {
icon: 'key', icon: 'key',
label: 'AUDIT_LOGS', label: 'AUDIT_LOGS',
hasSubMenu: false, hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/audit-log/list`), toState: frontendURL(`accounts/${accountId}/settings/audit-log/list`),
toStateName: 'auditlogs_list', toStateName: 'auditlogs_list',
isEnterpriseOnly: true,
featureFlag: FEATURE_FLAGS.AUDIT_LOGS, featureFlag: FEATURE_FLAGS.AUDIT_LOGS,
beta: true, beta: true,
}, },
@@ -165,9 +158,18 @@ const settings = accountId => ({
hasSubMenu: false, hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/sla/list`), toState: frontendURL(`accounts/${accountId}/settings/sla/list`),
toStateName: 'sla_list', toStateName: 'sla_list',
isEnterpriseOnly: true,
featureFlag: FEATURE_FLAGS.SLA, featureFlag: FEATURE_FLAGS.SLA,
beta: true, beta: true,
}, },
{
icon: 'credit-card-person',
label: 'BILLING',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/billing`),
toStateName: 'billing_settings_index',
showOnlyOnCloud: true,
},
], ],
}); });
@@ -2,7 +2,7 @@
<li v-show="isMenuItemVisible" class="mt-1"> <li v-show="isMenuItemVisible" class="mt-1">
<div v-if="hasSubMenu" class="flex justify-between"> <div v-if="hasSubMenu" class="flex justify-between">
<span <span
class="text-sm text-slate-700 dark:text-slate-200 font-semibold my-2 px-2 pt-1" class="px-2 pt-1 my-2 text-sm font-semibold text-slate-700 dark:text-slate-200"
> >
{{ $t(`SIDEBAR.${menuItem.label}`) }} {{ $t(`SIDEBAR.${menuItem.label}`) }}
</span> </span>
@@ -19,7 +19,7 @@
</div> </div>
<router-link <router-link
v-else v-else
class="rounded-lg leading-4 font-medium flex items-center p-2 m-0 text-sm text-slate-700 dark:text-slate-100 hover:bg-slate-25 dark:hover:bg-slate-800" class="flex items-center p-2 m-0 text-sm font-medium leading-4 rounded-lg text-slate-700 dark:text-slate-100 hover:bg-slate-25 dark:hover:bg-slate-800"
:class="computedClass" :class="computedClass"
:to="menuItem && menuItem.toState" :to="menuItem && menuItem.toState"
> >
@@ -31,7 +31,7 @@
{{ $t(`SIDEBAR.${menuItem.label}`) }} {{ $t(`SIDEBAR.${menuItem.label}`) }}
<span <span
v-if="showChildCount(menuItem.count)" v-if="showChildCount(menuItem.count)"
class="rounded-md text-xxs font-medium mx-1 py-0 px-1" class="px-1 py-0 mx-1 font-medium rounded-md text-xxs"
:class="{ :class="{
'text-slate-300 dark:text-slate-600': isCountZero && !isActiveView, 'text-slate-300 dark:text-slate-600': isCountZero && !isActiveView,
'text-slate-600 dark:text-slate-50': !isCountZero && !isActiveView, 'text-slate-600 dark:text-slate-50': !isCountZero && !isActiveView,
@@ -46,13 +46,13 @@
v-if="menuItem.beta" v-if="menuItem.beta"
data-view-component="true" data-view-component="true"
label="Beta" label="Beta"
class="px-1 mx-1 inline-block font-medium leading-4 border border-green-400 text-green-500 rounded-lg text-xxs" class="inline-block px-1 mx-1 font-medium leading-4 text-green-500 border border-green-400 rounded-lg text-xxs"
> >
{{ $t('SIDEBAR.BETA') }} {{ $t('SIDEBAR.BETA') }}
</span> </span>
</router-link> </router-link>
<ul v-if="hasSubMenu" class="list-none ml-0 mb-0"> <ul v-if="hasSubMenu" class="mb-0 ml-0 list-none">
<secondary-child-nav-item <secondary-child-nav-item
v-for="child in menuItem.children" v-for="child in menuItem.children"
:key="child.id" :key="child.id"
@@ -94,6 +94,7 @@
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import adminMixin from '../../../mixins/isAdmin'; import adminMixin from '../../../mixins/isAdmin';
import configMixin from 'shared/mixins/configMixin';
import { import {
getInboxClassByType, getInboxClassByType,
getInboxWarningIconClass, getInboxWarningIconClass,
@@ -107,7 +108,7 @@ import {
export default { export default {
components: { SecondaryChildNavItem }, components: { SecondaryChildNavItem },
mixins: [adminMixin], mixins: [adminMixin, configMixin],
props: { props: {
menuItem: { menuItem: {
type: Object, type: Object,
@@ -132,15 +133,33 @@ export default {
}, },
isMenuItemVisible() { isMenuItemVisible() {
if (this.menuItem.globalConfigFlag) { if (this.menuItem.globalConfigFlag) {
// this checks for the `csmlEditorHost` flag in the global config
// if this is present, we toggle the CSML editor menu item
// TODO: This is very specific, and can be handled better, fix it
return !!this.globalConfig[this.menuItem.globalConfigFlag]; return !!this.globalConfig[this.menuItem.globalConfigFlag];
} }
let isFeatureEnabled = true;
if (this.menuItem.featureFlag) {
isFeatureEnabled = this.isFeatureEnabledonAccount(
this.accountId,
this.menuItem.featureFlag
);
}
if (this.menuItem.isEnterpriseOnly) {
if (!this.isEnterprise) return false;
return isFeatureEnabled || this.globalConfig.displayManifest;
}
if (this.menuItem.featureFlag) { if (this.menuItem.featureFlag) {
return this.isFeatureEnabledonAccount( return this.isFeatureEnabledonAccount(
this.accountId, this.accountId,
this.menuItem.featureFlag this.menuItem.featureFlag
); );
} }
return true;
return isFeatureEnabled;
}, },
isAllConversations() { isAllConversations() {
return ( return (
@@ -40,8 +40,7 @@ import AIAssistanceModal from './AIAssistanceModal.vue';
import adminMixin from 'dashboard/mixins/aiMixin'; import adminMixin from 'dashboard/mixins/aiMixin';
import aiMixin from 'dashboard/mixins/isAdmin'; import aiMixin from 'dashboard/mixins/isAdmin';
import { CMD_AI_ASSIST } from 'dashboard/routes/dashboard/commands/commandBarBusEvents'; import { CMD_AI_ASSIST } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import { buildHotKeys } from 'shared/helpers/KeyboardHelpers';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import AIAssistanceCTAButton from './AIAssistanceCTAButton.vue'; import AIAssistanceCTAButton from './AIAssistanceCTAButton.vue';
@@ -51,7 +50,7 @@ export default {
AICTAModal, AICTAModal,
AIAssistanceCTAButton, AIAssistanceCTAButton,
}, },
mixins: [aiMixin, eventListenerMixins, adminMixin, uiSettingsMixin], mixins: [aiMixin, keyboardEventListenerMixins, adminMixin, uiSettingsMixin],
data: () => ({ data: () => ({
showAIAssistanceModal: false, showAIAssistanceModal: false,
showAICtaModal: false, showAICtaModal: false,
@@ -87,14 +86,17 @@ export default {
}, },
methods: { methods: {
onKeyDownHandler(event) { getKeyboardEvents() {
const keyPattern = buildHotKeys(event); return {
const shouldRevertTheContent = '$mod+KeyZ': {
['meta+z', 'ctrl+z'].includes(keyPattern) && !!this.initialMessage; action: () => {
if (shouldRevertTheContent) { if (this.initialMessage) {
this.$emit('replace-text', this.initialMessage); this.$emit('replace-text', this.initialMessage);
this.initialMessage = ''; this.initialMessage = '';
} }
},
},
};
}, },
hideAIAssistanceModal() { hideAIAssistanceModal() {
this.recordAnalytics('DISMISS_AI_SUGGESTION', { this.recordAnalytics('DISMISS_AI_SUGGESTION', {
@@ -1,17 +1,17 @@
<template> <template>
<div class="preview-item__wrap flex overflow-auto max-h-[12.5rem]"> <div class="flex overflow-auto max-h-[12.5rem]">
<div <div
v-for="(attachment, index) in attachments" v-for="(attachment, index) in nonRecordedAudioAttachments"
:key="attachment.id" :key="attachment.id"
class="preview-item flex items-center p-1 bg-slate-50 dark:bg-slate-800 gap-1 rounded-md w-[15rem] mb-1" class="preview-item flex items-center p-1 bg-slate-50 dark:bg-slate-800 gap-1 rounded-md w-[15rem] mb-1"
> >
<div class="max-w-[4rem] flex-shrink-0 w-6 flex items-center"> <div class="max-w-[4rem] flex-shrink-0 w-6 flex items-center">
<img <img
v-if="isTypeImage(attachment.resource)" v-if="isTypeImage(attachment.resource)"
class="image-thumb" class="object-cover w-6 h-6 rounded-sm"
:src="attachment.thumb" :src="attachment.thumb"
/> />
<span v-else class="w-6 h-6 text-lg relative -top-px text-left"> <span v-else class="relative w-6 h-6 text-lg text-left -top-px">
📄 📄
</span> </span>
</div> </div>
@@ -23,73 +23,62 @@
</span> </span>
</div> </div>
<div class="w-[30%] justify-center"> <div class="w-[30%] justify-center">
<span <span class="overflow-hidden text-xs text-ellipsis whitespace-nowrap">
class="item overflow-hidden text-xs text-ellipsis whitespace-nowrap"
>
{{ formatFileSize(attachment.resource) }} {{ formatFileSize(attachment.resource) }}
</span> </span>
</div> </div>
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
<woot-button <woot-button
v-if="!isTypeAudio(attachment.resource)" class="!w-6 !h-6 text-sm rounded-md hover:bg-slate-50 dark:hover:bg-slate-800 clear secondary"
class="remove--attachment clear secondary"
icon="dismiss" icon="dismiss"
@click="() => onRemoveAttachment(index)" @click="onRemoveAttachment(index)"
/> />
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script>
<script setup>
import { computed } from 'vue';
import { formatBytes } from 'shared/helpers/FileHelper'; import { formatBytes } from 'shared/helpers/FileHelper';
export default {
props: { const props = defineProps({
attachments: { attachments: {
type: Array, type: Array,
default: () => [], default: () => [],
},
removeAttachment: {
type: Function,
default: () => {},
},
},
methods: {
onRemoveAttachment(index) {
this.removeAttachment(index);
},
formatFileSize(file) {
const size = file.byte_size || file.size;
return formatBytes(size, 0);
},
isTypeImage(file) {
const type = file.content_type || file.type;
return type.includes('image');
},
isTypeAudio(file) {
const type = file.content_type || file.type;
return type.includes('audio');
},
fileName(file) {
return file.filename || file.name;
},
}, },
});
const emits = defineEmits(['remove-attachment']);
const nonRecordedAudioAttachments = computed(() => {
return props.attachments.filter(attachment => !attachment?.isRecordedAudio);
});
const recordedAudioAttachments = computed(() =>
props.attachments.filter(attachment => attachment.isRecordedAudio)
);
const onRemoveAttachment = itemIndex => {
emits(
'remove-attachment',
nonRecordedAudioAttachments.value
.filter((_, index) => index !== itemIndex)
.concat(recordedAudioAttachments.value)
);
};
const formatFileSize = file => {
const size = file.byte_size || file.size;
return formatBytes(size, 0);
};
const isTypeImage = file => {
const type = file.content_type || file.type;
return type.includes('image');
};
const fileName = file => {
return file.filename || file.name;
}; };
</script> </script>
<style lang="scss" scoped>
.image-thumb {
@apply w-6 h-6 object-cover rounded-sm;
}
.file-name-wrap,
.file-size-wrap {
@apply flex items-center py-0 px-1;
> .item {
@apply m-0 overflow-hidden text-xs font-medium;
}
}
.remove--attachment {
@apply w-6 h-6 rounded-md text-sm cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-800;
}
</style>
@@ -10,11 +10,10 @@
</template> </template>
<script> <script>
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import { hasPressedAltAndNKey } from 'shared/helpers/KeyboardHelpers';
export default { export default {
mixins: [eventListenerMixins], mixins: [keyboardEventListenerMixins],
props: { props: {
items: { items: {
type: Array, type: Array,
@@ -31,14 +30,18 @@ export default {
}, },
}, },
methods: { methods: {
handleKeyEvents(e) { getKeyboardEvents() {
if (hasPressedAltAndNKey(e)) { return {
if (this.activeTab === wootConstants.ASSIGNEE_TYPE.ALL) { 'Alt+KeyN': {
this.onTabChange(0); action: () => {
} else { if (this.activeTab === wootConstants.ASSIGNEE_TYPE.ALL) {
this.onTabChange(this.activeTabIndex + 1); this.onTabChange(0);
} } else {
} this.onTabChange(this.activeTabIndex + 1);
}
},
},
};
}, },
onTabChange(selectedTabIndex) { onTabChange(selectedTabIndex) {
if (this.items[selectedTabIndex].key !== this.activeTab) { if (this.items[selectedTabIndex].key !== this.activeTab) {
@@ -31,15 +31,10 @@
<script> <script>
import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue'; import AddLabel from 'shared/components/ui/dropdown/AddLabel.vue';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue'; import LabelDropdown from 'shared/components/ui/label/LabelDropdown.vue';
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import adminMixin from 'dashboard/mixins/isAdmin'; import adminMixin from 'dashboard/mixins/isAdmin';
import {
buildHotKeys,
isEscape,
isActiveElementTypeable,
} from 'shared/helpers/KeyboardHelpers';
export default { export default {
components: { components: {
@@ -47,7 +42,7 @@ export default {
LabelDropdown, LabelDropdown,
}, },
mixins: [clickaway, adminMixin, eventListenerMixins], mixins: [clickaway, adminMixin, keyboardEventListenerMixins],
props: { props: {
allLabels: { allLabels: {
@@ -88,17 +83,19 @@ export default {
closeDropdownLabel() { closeDropdownLabel() {
this.showSearchDropdownLabel = false; this.showSearchDropdownLabel = false;
}, },
getKeyboardEvents() {
handleKeyEvents(e) { return {
const keyPattern = buildHotKeys(e); KeyL: {
action: e => {
if (keyPattern === 'l' && !isActiveElementTypeable(e)) { this.toggleLabels();
this.toggleLabels(); e.preventDefault();
e.preventDefault(); },
} else if (isEscape(e) && this.showSearchDropdownLabel) { },
this.closeDropdownLabel(); Escape: {
e.preventDefault(); action: () => this.closeDropdownLabel(),
} allowOnFocusedInput: true,
},
};
}, },
}, },
}; };
@@ -231,7 +231,18 @@ export default {
@apply bg-transparent max-h-60 min-h-[3rem] pt-4 px-0 pb-0 resize-none; @apply bg-transparent max-h-60 min-h-[3rem] pt-4 px-0 pb-0 resize-none;
} }
} }
.video-js .vjs-control-bar { // Added to override the default text and bg style to support dark and light mode.
background-color: transparent; .video-js .vjs-control-bar,
.vjs-record.video-js .vjs-control.vjs-record-indicator:before {
@apply text-slate-600 dark:text-slate-200 bg-transparent dark:bg-transparent;
}
// Added to fix div overlays the screen and takes over the button clicks
// https://github.com/collab-project/videojs-record/issues/688
// https://github.com/collab-project/videojs-record/pull/709
.vjs-record.video-js .vjs-control.vjs-record-indicator.vjs-hidden,
.vjs-record.video-js .vjs-control.vjs-record-indicator,
.vjs-record.video-js .vjs-control.vjs-record-indicator:before,
.vjs-record.video-js .vjs-control.vjs-record-indicator:after {
@apply pointer-events-none;
} }
</style> </style>
@@ -78,10 +78,8 @@ const MAXIMUM_FILE_UPLOAD_SIZE = 4; // in MB
import { import {
hasPressedEnterAndNotCmdOrShift, hasPressedEnterAndNotCmdOrShift,
hasPressedCommandAndEnter, hasPressedCommandAndEnter,
hasPressedAltAndPKey,
hasPressedAltAndLKey,
} from 'shared/helpers/KeyboardHelpers'; } from 'shared/helpers/KeyboardHelpers';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { isEditorHotKeyEnabled } from 'dashboard/mixins/uiSettings'; import { isEditorHotKeyEnabled } from 'dashboard/mixins/uiSettings';
import { import {
@@ -121,7 +119,7 @@ const createState = (
export default { export default {
name: 'WootMessageEditor', name: 'WootMessageEditor',
components: { TagAgents, CannedResponse, VariableList }, components: { TagAgents, CannedResponse, VariableList },
mixins: [eventListenerMixins, uiSettingsMixin, alertMixin], mixins: [keyboardEventListenerMixins, uiSettingsMixin, alertMixin],
props: { props: {
value: { type: String, default: '' }, value: { type: String, default: '' },
editorId: { type: String, default: '' }, editorId: { type: String, default: '' },
@@ -522,13 +520,21 @@ export default {
isCmdPlusEnterToSendEnabled() { isCmdPlusEnterToSendEnabled() {
return isEditorHotKeyEnabled(this.uiSettings, 'cmd_enter'); return isEditorHotKeyEnabled(this.uiSettings, 'cmd_enter');
}, },
handleKeyEvents(e) { getKeyboardEvents() {
if (hasPressedAltAndPKey(e)) { return {
this.focusEditorInputField(); 'Alt+KeyP': {
} action: () => {
if (hasPressedAltAndLKey(e)) { this.focusEditorInputField();
this.focusEditorInputField(); },
} allowOnFocusedInput: true,
},
'Alt+KeyL': {
action: () => {
this.focusEditorInputField();
},
allowOnFocusedInput: true,
},
};
}, },
focusEditorInputField(pos = 'end') { focusEditorInputField(pos = 'end') {
const { tr } = this.editorView.state; const { tr } = this.editorView.state;
@@ -25,7 +25,7 @@ import {
} from '@chatwoot/prosemirror-schema'; } from '@chatwoot/prosemirror-schema';
import { checkFileSizeLimit } from 'shared/helpers/FileHelper'; import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
const MAXIMUM_FILE_UPLOAD_SIZE = 4; // in MB const MAXIMUM_FILE_UPLOAD_SIZE = 4; // in MB
@@ -51,7 +51,7 @@ const createState = (
}; };
export default { export default {
mixins: [eventListenerMixins, uiSettingsMixin, alertMixin], mixins: [keyboardEventListenerMixins, uiSettingsMixin, alertMixin],
props: { props: {
value: { type: String, default: '' }, value: { type: String, default: '' },
editorId: { type: String, default: '' }, editorId: { type: String, default: '' },
@@ -136,8 +136,7 @@
<script> <script>
import FileUpload from 'vue-upload-component'; import FileUpload from 'vue-upload-component';
import * as ActiveStorage from 'activestorage'; import * as ActiveStorage from 'activestorage';
import { hasPressedAltAndAKey } from 'shared/helpers/KeyboardHelpers'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import inboxMixin from 'shared/mixins/inboxMixin'; import inboxMixin from 'shared/mixins/inboxMixin';
import { FEATURE_FLAGS } from 'dashboard/featureFlags'; import { FEATURE_FLAGS } from 'dashboard/featureFlags';
@@ -154,7 +153,7 @@ import { mapGetters } from 'vuex';
export default { export default {
name: 'ReplyBottomPanel', name: 'ReplyBottomPanel',
components: { FileUpload, VideoCallButton, AIAssistanceButton }, components: { FileUpload, VideoCallButton, AIAssistanceButton },
mixins: [eventListenerMixins, uiSettingsMixin, inboxMixin], mixins: [keyboardEventListenerMixins, uiSettingsMixin, inboxMixin],
props: { props: {
mode: { mode: {
type: String, type: String,
@@ -340,10 +339,15 @@ export default {
ActiveStorage.start(); ActiveStorage.start();
}, },
methods: { methods: {
handleKeyEvents(e) { getKeyboardEvents() {
if (hasPressedAltAndAKey(e)) { return {
this.$refs.upload.$children[1].$el.click(); 'Alt+KeyA': {
} action: () => {
this.$refs.upload.$children[1].$el.click();
},
allowOnFocusedInput: true,
},
};
}, },
toggleMessageSignature() { toggleMessageSignature() {
this.setSignatureFlagForInbox(this.channelType, !this.sendWithSignature); this.setSignatureFlagForInbox(this.channelType, !this.sendWithSignature);
@@ -1,5 +1,5 @@
<template> <template>
<div class="bg-black-50 flex justify-between dark:bg-slate-800"> <div class="flex justify-between bg-black-50 dark:bg-slate-800">
<div class="button-group"> <div class="button-group">
<woot-button <woot-button
variant="clear" variant="clear"
@@ -20,7 +20,7 @@
{{ $t('CONVERSATION.REPLYBOX.PRIVATE_NOTE') }} {{ $t('CONVERSATION.REPLYBOX.PRIVATE_NOTE') }}
</woot-button> </woot-button>
</div> </div>
<div class="flex items-center my-0 mx-4"> <div class="flex items-center mx-4 my-0">
<div v-if="isMessageLengthReachingThreshold" class="text-xs"> <div v-if="isMessageLengthReachingThreshold" class="text-xs">
<span :class="charLengthClass"> <span :class="charLengthClass">
{{ characterLengthWarning }} {{ characterLengthWarning }}
@@ -48,14 +48,10 @@
<script> <script>
import { REPLY_EDITOR_MODES, CHAR_LENGTH_WARNING } from './constants'; import { REPLY_EDITOR_MODES, CHAR_LENGTH_WARNING } from './constants';
import { import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
hasPressedAltAndPKey,
hasPressedAltAndLKey,
} from 'shared/helpers/KeyboardHelpers';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
export default { export default {
name: 'ReplyTopPanel', name: 'ReplyTopPanel',
mixins: [eventListenerMixins], mixins: [keyboardEventListenerMixins],
props: { props: {
mode: { mode: {
type: String, type: String,
@@ -99,13 +95,17 @@ export default {
}, },
}, },
methods: { methods: {
handleKeyEvents(e) { getKeyboardEvents() {
if (hasPressedAltAndPKey(e)) { return {
this.handleNoteClick(); 'Alt+KeyP': {
} action: () => this.handleNoteClick(),
if (hasPressedAltAndLKey(e)) { allowOnFocusedInput: true,
this.handleReplyClick(); },
} 'Alt+KeyL': {
action: () => this.handleReplyClick(),
allowOnFocusedInput: true,
},
};
}, },
handleReplyClick() { handleReplyClick() {
this.setReplyMode(REPLY_EDITOR_MODES.REPLY); this.setReplyMode(REPLY_EDITOR_MODES.REPLY);
@@ -2,7 +2,7 @@
<div <div
class="relative flex items-start flex-grow-0 flex-shrink-0 w-auto max-w-full px-4 py-0 border-t-0 border-b-0 border-l-2 border-r-0 border-transparent border-solid cursor-pointer conversation hover:bg-slate-25 dark:hover:bg-slate-800 group" class="relative flex items-start flex-grow-0 flex-shrink-0 w-auto max-w-full px-4 py-0 border-t-0 border-b-0 border-l-2 border-r-0 border-transparent border-solid cursor-pointer conversation hover:bg-slate-25 dark:hover:bg-slate-800 group"
:class="{ :class="{
'animate-card-select bg-slate-25 dark:bg-slate-800 border-woot-500': 'active animate-card-select bg-slate-25 dark:bg-slate-800 border-woot-500':
isActiveChat, isActiveChat,
'unread-chat': hasUnread, 'unread-chat': hasUnread,
'has-inbox-name': showInboxName, 'has-inbox-name': showInboxName,
@@ -77,11 +77,10 @@
</div> </div>
</template> </template>
<script> <script>
import { hasPressedAltAndOKey } from 'shared/helpers/KeyboardHelpers';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import agentMixin from '../../../mixins/agentMixin.js'; import agentMixin from '../../../mixins/agentMixin.js';
import BackButton from '../BackButton.vue'; import BackButton from '../BackButton.vue';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import inboxMixin from 'shared/mixins/inboxMixin'; import inboxMixin from 'shared/mixins/inboxMixin';
import InboxName from '../InboxName.vue'; import InboxName from '../InboxName.vue';
import MoreActions from './MoreActions.vue'; import MoreActions from './MoreActions.vue';
@@ -99,7 +98,7 @@ export default {
Thumbnail, Thumbnail,
SLACardLabel, SLACardLabel,
}, },
mixins: [inboxMixin, agentMixin, eventListenerMixins], mixins: [inboxMixin, agentMixin, keyboardEventListenerMixins],
props: { props: {
chat: { chat: {
type: Object, type: Object,
@@ -182,10 +181,12 @@ export default {
}, },
methods: { methods: {
handleKeyEvents(e) { getKeyboardEvents() {
if (hasPressedAltAndOKey(e)) { return {
this.$emit('contact-panel-toggle'); 'Alt+KeyO': {
} action: () => this.$emit('contact-panel-toggle'),
},
};
}, },
}, },
}; };
@@ -14,11 +14,7 @@
@click="retrySendMessage" @click="retrySendMessage"
/> />
</div> </div>
<div <div :class="bubbleClass" @contextmenu="openContextMenu($event)">
v-tooltip.top-start="messageToolTip"
:class="bubbleClass"
@contextmenu="openContextMenu($event)"
>
<bubble-mail-head <bubble-mail-head
:email-attributes="contentAttributes.email" :email-attributes="contentAttributes.email"
:cc="emailHeadAttributes.cc" :cc="emailHeadAttributes.cc"
@@ -90,7 +86,7 @@
:id="data.id" :id="data.id"
:sender="data.sender" :sender="data.sender"
:story-sender="storySender" :story-sender="storySender"
:external-error="externalError" :external-error="errorMessageTooltip"
:story-id="`${storyId}`" :story-id="`${storyId}`"
:is-a-tweet="isATweet" :is-a-tweet="isATweet"
:is-a-whatsapp-channel="isAWhatsAppChannel" :is-a-whatsapp-channel="isAWhatsAppChannel"
@@ -412,14 +408,11 @@ export default {
} }
: false; : false;
}, },
messageToolTip() { errorMessageTooltip() {
if (this.isMessageDeleted) {
return false;
}
if (this.isFailed) { if (this.isFailed) {
return this.externalError || this.$t(`CONVERSATION.SEND_FAILED`); return this.externalError || this.$t(`CONVERSATION.SEND_FAILED`);
} }
return false; return '';
}, },
wrapClass() { wrapClass() {
return { return {
@@ -116,13 +116,12 @@ import conversationMixin, {
} from '../../../mixins/conversations'; } from '../../../mixins/conversations';
import inboxMixin, { INBOX_FEATURES } from 'shared/mixins/inboxMixin'; import inboxMixin, { INBOX_FEATURES } from 'shared/mixins/inboxMixin';
import configMixin from 'shared/mixins/configMixin'; import configMixin from 'shared/mixins/configMixin';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import aiMixin from 'dashboard/mixins/aiMixin'; import aiMixin from 'dashboard/mixins/aiMixin';
// utils // utils
import { getTypingUsersText } from '../../../helper/commons'; import { getTypingUsersText } from '../../../helper/commons';
import { calculateScrollTop } from './helpers/scrollTopCalculationHelper'; import { calculateScrollTop } from './helpers/scrollTopCalculationHelper';
import { isEscape } from 'shared/helpers/KeyboardHelpers';
import { LocalStorage } from 'shared/helpers/localStorage'; import { LocalStorage } from 'shared/helpers/localStorage';
// constants // constants
@@ -141,7 +140,7 @@ export default {
mixins: [ mixins: [
conversationMixin, conversationMixin,
inboxMixin, inboxMixin,
eventListenerMixins, keyboardEventListenerMixins,
configMixin, configMixin,
aiMixin, aiMixin,
], ],
@@ -418,10 +417,12 @@ export default {
closePopoutReplyBox() { closePopoutReplyBox() {
this.isPopoutReplyBox = false; this.isPopoutReplyBox = false;
}, },
handleKeyEvents(e) { getKeyboardEvents() {
if (isEscape(e)) { return {
this.closePopoutReplyBox(); Escape: {
} action: () => this.closePopoutReplyBox(),
},
};
}, },
addScrollListener() { addScrollListener() {
this.conversationPanel = this.$el.querySelector('.conversation-panel'); this.conversationPanel = this.$el.querySelector('.conversation-panel');
@@ -100,7 +100,7 @@
<attachment-preview <attachment-preview
class="flex-col mt-4" class="flex-col mt-4"
:attachments="attachedFiles" :attachments="attachedFiles"
:remove-attachment="removeAttachment" @remove-attachment="removeAttachment"
/> />
</div> </div>
<message-signature-missing-alert <message-signature-missing-alert
@@ -155,6 +155,7 @@
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 keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import CannedResponse from './CannedResponse.vue'; import CannedResponse from './CannedResponse.vue';
import ReplyToMessage from './ReplyToMessage.vue'; import ReplyToMessage from './ReplyToMessage.vue';
@@ -178,7 +179,6 @@ import {
replaceVariablesInMessage, replaceVariablesInMessage,
} from '@chatwoot/utils'; } from '@chatwoot/utils';
import WhatsappTemplates from './WhatsappTemplates/Modal.vue'; import WhatsappTemplates from './WhatsappTemplates/Modal.vue';
import { buildHotKeys } from 'shared/helpers/KeyboardHelpers';
import { MESSAGE_MAX_LENGTH } from 'shared/helpers/MessageTypeHelper'; import { MESSAGE_MAX_LENGTH } from 'shared/helpers/MessageTypeHelper';
import inboxMixin, { INBOX_FEATURES } from 'shared/mixins/inboxMixin'; import inboxMixin, { INBOX_FEATURES } from 'shared/mixins/inboxMixin';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
@@ -225,6 +225,7 @@ export default {
messageFormatterMixin, messageFormatterMixin,
rtlMixin, rtlMixin,
fileUploadMixin, fileUploadMixin,
keyboardEventListenerMixins,
], ],
props: { props: {
popoutReplyBox: { popoutReplyBox: {
@@ -701,24 +702,41 @@ export default {
this.$store.dispatch('draftMessages/delete', { key }); this.$store.dispatch('draftMessages/delete', { key });
} }
}, },
handleKeyEvents(e) { getKeyboardEvents() {
const keyCode = buildHotKeys(e); return {
if (keyCode === 'escape') { Escape: {
this.hideEmojiPicker(); action: () => {
this.hideMentions(); this.hideEmojiPicker();
} else if (keyCode === 'meta+k') { this.hideMentions();
const ninja = document.querySelector('ninja-keys'); },
ninja.open(); allowOnFocusedInput: true,
e.preventDefault(); },
} else if (keyCode === 'enter' && this.isAValidEvent('enter')) { '$mod+KeyK': {
this.onSendReply(); action: e => {
e.preventDefault(); e.preventDefault();
} else if ( const ninja = document.querySelector('ninja-keys');
['meta+enter', 'ctrl+enter'].includes(keyCode) && ninja.open();
this.isAValidEvent('cmd_enter') },
) { allowOnFocusedInput: true,
this.onSendReply(); },
} Enter: {
action: e => {
if (this.isAValidEvent('enter')) {
this.onSendReply();
e.preventDefault();
}
},
allowOnFocusedInput: true,
},
'$mod+Enter': {
action: () => {
if (this.isAValidEvent('cmd_enter')) {
this.onSendReply();
}
},
allowOnFocusedInput: true,
},
};
}, },
isAValidEvent(selectedKey) { isAValidEvent(selectedKey) {
return ( return (
@@ -937,6 +955,13 @@ export default {
this.bccEmails = ''; this.bccEmails = '';
this.toEmails = ''; this.toEmails = '';
}, },
clearRecorder() {
this.isRecordingAudio = false;
// Only clear the recorded audio when we click toggle button.
this.attachedFiles = this.attachedFiles.filter(
file => !file?.isRecordedAudio
);
},
toggleEmojiPicker() { toggleEmojiPicker() {
this.showEmojiPicker = !this.showEmojiPicker; this.showEmojiPicker = !this.showEmojiPicker;
}, },
@@ -944,8 +969,7 @@ export default {
this.isRecordingAudio = !this.isRecordingAudio; this.isRecordingAudio = !this.isRecordingAudio;
this.isRecorderAudioStopped = !this.isRecordingAudio; this.isRecorderAudioStopped = !this.isRecordingAudio;
if (!this.isRecordingAudio) { if (!this.isRecordingAudio) {
this.clearMessage(); this.clearRecorder();
this.clearEmailField();
} }
}, },
toggleAudioRecorderPlayPause() { toggleAudioRecorderPlayPause() {
@@ -989,7 +1013,13 @@ export default {
} }
}, },
onFinishRecorder(file) { onFinishRecorder(file) {
return file && this.onFileUpload(file); // Added a new key isRecordedAudio to the file to find it's and recorded audio
// Because to filter and show only non recorded audio and other attachments
const autoRecordedFile = {
...file,
isRecordedAudio: true,
};
return file && this.onFileUpload(autoRecordedFile);
}, },
toggleTyping(status) { toggleTyping(status) {
const conversationId = this.currentChat.id; const conversationId = this.currentChat.id;
@@ -1015,13 +1045,12 @@ export default {
isPrivate: this.isPrivate, isPrivate: this.isPrivate,
thumb: reader.result, thumb: reader.result,
blobSignedId: blob ? blob.signed_id : undefined, blobSignedId: blob ? blob.signed_id : undefined,
isRecordedAudio: file?.isRecordedAudio || false,
}); });
}; };
}, },
removeAttachment(itemIndex) { removeAttachment(attachments) {
this.attachedFiles = this.attachedFiles.filter( this.attachedFiles = attachments;
(item, index) => itemIndex !== index
);
}, },
setReplyToInPayload(payload) { setReplyToInPayload(payload) {
if (this.inReplyTo?.id) { if (this.inReplyTo?.id) {
@@ -75,9 +75,10 @@ export default {
}, },
methods: { methods: {
handleKeyboardEvent(e) { adjustScroll() {
this.processKeyDownEvent(e); this.$nextTick(() => {
this.$el.scrollTop = 50 * this.selectedIndex; this.$el.scrollTop = 50 * this.selectedIndex;
});
}, },
onHover(index) { onHover(index) {
this.selectedIndex = index; this.selectedIndex = index;
@@ -17,7 +17,7 @@
@error="onImgError" @error="onImgError"
@click="onClick" @click="onClick"
/> />
<audio v-else-if="isAudio" controls class="skip-context-menu"> <audio v-else-if="isAudio" controls class="skip-context-menu mb-0.5">
<source :src="`${dataUrl}?t=${Date.now()}`" /> <source :src="`${dataUrl}?t=${Date.now()}`" />
</audio> </audio>
<gallery-view <gallery-view
@@ -182,12 +182,7 @@
<script> <script>
import { mixin as clickaway } from 'vue-clickaway'; import { mixin as clickaway } from 'vue-clickaway';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
isEscape,
hasPressedArrowLeftKey,
hasPressedArrowRightKey,
} from 'shared/helpers/KeyboardHelpers';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import timeMixin from 'dashboard/mixins/time'; import timeMixin from 'dashboard/mixins/time';
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
@@ -205,7 +200,7 @@ export default {
components: { components: {
Thumbnail, Thumbnail,
}, },
mixins: [eventListenerMixins, clickaway, timeMixin], mixins: [keyboardEventListenerMixins, clickaway, timeMixin],
props: { props: {
show: { show: {
type: Boolean, type: Boolean,
@@ -304,20 +299,30 @@ export default {
this.activeAttachment = attachment; this.activeAttachment = attachment;
this.activeFileType = type; this.activeFileType = type;
}, },
onKeyDownHandler(e) { getKeyboardEvents() {
if (isEscape(e)) { return {
this.onClose(); Escape: {
} else if (hasPressedArrowLeftKey(e)) { action: () => {
this.onClickChangeAttachment( this.onClose();
this.allAttachments[this.activeImageIndex - 1], },
this.activeImageIndex - 1 },
); ArrowLeft: {
} else if (hasPressedArrowRightKey(e)) { action: () => {
this.onClickChangeAttachment( this.onClickChangeAttachment(
this.allAttachments[this.activeImageIndex + 1], this.allAttachments[this.activeImageIndex - 1],
this.activeImageIndex + 1 this.activeImageIndex - 1
); );
} },
},
ArrowRight: {
action: () => {
this.onClickChangeAttachment(
this.allAttachments[this.activeImageIndex + 1],
this.activeImageIndex + 1
);
},
},
};
}, },
onClickDownload() { onClickDownload() {
const { file_type: type, data_url: url } = this.activeAttachment; const { file_type: type, data_url: url } = this.activeAttachment;
@@ -74,15 +74,10 @@
<script> <script>
import countries from 'shared/constants/countries.js'; import countries from 'shared/constants/countries.js';
import parsePhoneNumber from 'libphonenumber-js'; import parsePhoneNumber from 'libphonenumber-js';
import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
import {
hasPressedArrowUpKey,
hasPressedArrowDownKey,
isEnter,
} from 'shared/helpers/KeyboardHelpers';
export default { export default {
mixins: [eventListenerMixins], mixins: [keyboardEventListenerMixins],
props: { props: {
value: { value: {
type: [String, Number], type: [String, Number],
@@ -183,6 +178,7 @@ export default {
this.$emit('blur', e.target.value); this.$emit('blur', e.target.value);
}, },
dropdownItem() { dropdownItem() {
if (!this.showDropdown) return [];
return Array.from( return Array.from(
this.$refs.dropdown.querySelectorAll( this.$refs.dropdown.querySelectorAll(
'div.country-dropdown div.country-dropdown--item' 'div.country-dropdown div.country-dropdown--item'
@@ -190,34 +186,27 @@ export default {
); );
}, },
focusedItem() { focusedItem() {
if (!this.showDropdown) return [];
return Array.from( return Array.from(
this.$refs.dropdown.querySelectorAll('div.country-dropdown div.focus') this.$refs.dropdown.querySelectorAll('div.country-dropdown div.focus')
); );
}, },
focusedItemIndex() { focusedItemIndex() {
if (!this.showDropdown) return -1;
return Array.from(this.dropdownItem()).indexOf(this.focusedItem()[0]); return Array.from(this.dropdownItem()).indexOf(this.focusedItem()[0]);
}, },
onKeyDownHandler(e) { moveUp() {
const { showDropdown, filteredCountriesBySearch, onSelectCountry } = this; if (!this.showDropdown) return;
const { selectedIndex } = this; this.selectedIndex = Math.max(this.selectedIndex - 1, 0);
this.$refs.dropdown.scrollTop = this.focusedItemIndex() * 28 - 56;
if (showDropdown) { },
if (hasPressedArrowDownKey(e)) { moveDown() {
e.preventDefault(); if (!this.showDropdown) return;
this.selectedIndex = Math.min( this.selectedIndex = Math.min(
selectedIndex + 1, this.selectedIndex + 1,
filteredCountriesBySearch.length - 1 this.filteredCountriesBySearch.length - 1
); );
this.$refs.dropdown.scrollTop = this.focusedItemIndex() * 28; this.$refs.dropdown.scrollTop = this.focusedItemIndex() * 28 - 56;
} else if (hasPressedArrowUpKey(e)) {
e.preventDefault();
this.selectedIndex = Math.max(selectedIndex - 1, 0);
this.$refs.dropdown.scrollTop = this.focusedItemIndex() * 28 - 56;
} else if (isEnter(e)) {
e.preventDefault();
onSelectCountry(filteredCountriesBySearch[selectedIndex]);
}
}
}, },
onSelectCountry(country) { onSelectCountry(country) {
this.activeCountryCode = country.id; this.activeCountryCode = country.id;
@@ -235,6 +224,33 @@ export default {
this.activeDialCode = number.countryCallingCode; this.activeDialCode = number.countryCallingCode;
} }
}, },
getKeyboardEvents() {
return {
ArrowUp: {
action: e => {
e.preventDefault();
this.moveUp();
},
allowOnFocusedInput: true,
},
ArrowDown: {
action: e => {
e.preventDefault();
this.moveDown();
},
allowOnFocusedInput: true,
},
Enter: {
action: e => {
e.preventDefault();
this.onSelectCountry(
this.filteredCountriesBySearch[this.selectedIndex]
);
},
allowOnFocusedInput: true,
},
};
},
toggleCountryDropdown() { toggleCountryDropdown() {
this.showDropdown = !this.showDropdown; this.showDropdown = !this.showDropdown;
this.selectedIndex = -1; this.selectedIndex = -1;
@@ -84,9 +84,7 @@ export default {
}, },
}, },
methods: { methods: {
handleKeyboardEvent(e) { adjustScroll() {},
this.processKeyDownEvent(e);
},
onHover(index) { onHover(index) {
this.selectedIndex = index; this.selectedIndex = index;
}, },
@@ -1,12 +1,7 @@
import { buildHotKeys } from 'shared/helpers/KeyboardHelpers'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
export default { export default {
mounted() { mixins: [keyboardEventListenerMixins],
document.addEventListener('keydown', this.handleKeyboardEvent);
},
beforeDestroy() {
document.removeEventListener('keydown', this.handleKeyboardEvent);
},
methods: { methods: {
moveSelectionUp() { moveSelectionUp() {
if (!this.selectedIndex) { if (!this.selectedIndex) {
@@ -14,6 +9,7 @@ export default {
} else { } else {
this.selectedIndex -= 1; this.selectedIndex -= 1;
} }
this.adjustScroll();
}, },
moveSelectionDown() { moveSelectionDown() {
if (this.selectedIndex === this.items.length - 1) { if (this.selectedIndex === this.items.length - 1) {
@@ -21,19 +17,46 @@ export default {
} else { } else {
this.selectedIndex += 1; this.selectedIndex += 1;
} }
this.adjustScroll();
}, },
processKeyDownEvent(e) { getKeyboardEvents() {
const keyPattern = buildHotKeys(e); return {
if (['arrowup', 'ctrl+p'].includes(keyPattern)) { ArrowUp: {
this.moveSelectionUp(); action: e => {
e.preventDefault(); this.moveSelectionUp();
} else if (['arrowdown', 'ctrl+n'].includes(keyPattern)) { e.preventDefault();
this.moveSelectionDown(); },
e.preventDefault(); allowOnFocusedInput: true,
} else if (keyPattern === 'enter') { },
this.onSelect(); 'Control+KeyP': {
e.preventDefault(); action: e => {
} this.moveSelectionUp();
e.preventDefault();
},
allowOnFocusedInput: true,
},
ArrowDown: {
action: e => {
this.moveSelectionDown();
e.preventDefault();
},
allowOnFocusedInput: true,
},
'Control+KeyN': {
action: e => {
this.moveSelectionDown();
e.preventDefault();
},
allowOnFocusedInput: true,
},
Enter: {
action: e => {
this.onSelect();
e.preventDefault();
},
allowOnFocusedInput: true,
},
};
}, },
}, },
}; };
@@ -1,64 +1,69 @@
import mentionSelectionKeyboardMixin from '../mentionSelectionKeyboardMixin'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import { shallowMount } from '@vue/test-utils'; import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
const localVue = createLocalVue();
const buildComponent = ({ data = {}, methods = {} }) => ({ const buildComponent = ({ data = {}, methods = {} }) => ({
render() {}, render() {},
data() { data() {
return data; return { ...data, selectedIndex: 0, items: [1, 2, 3] };
}, },
methods, methods: { ...methods, onSelect: jest.fn(), adjustScroll: jest.fn() },
mixins: [mentionSelectionKeyboardMixin], mixins: [keyboardEventListenerMixins],
}); });
describe('mentionSelectionKeyboardMixin', () => { describe('mentionSelectionKeyboardMixin', () => {
test('register listeners', () => { let wrapper;
jest.spyOn(document, 'addEventListener');
beforeEach(() => {
const Component = buildComponent({}); const Component = buildComponent({});
shallowMount(Component); wrapper = shallowMount(Component, { localVue });
// undefined expected as the method is not defined in the component
expect(document.addEventListener).toHaveBeenCalledWith(
'keydown',
undefined
);
}); });
test('processKeyDownEvent updates index on arrow up', () => { it('ArrowUp and Control+KeyP update selectedIndex correctly', () => {
const Component = buildComponent({ const preventDefault = jest.fn();
data: { selectedIndex: 0, items: [1, 2, 3] }, const keyboardEvents = wrapper.vm.getKeyboardEvents();
});
const wrapper = shallowMount(Component); if (keyboardEvents && keyboardEvents.ArrowUp) {
wrapper.vm.processKeyDownEvent({ keyboardEvents.ArrowUp.action({ preventDefault });
ctrlKey: true, expect(wrapper.vm.selectedIndex).toBe(2);
key: 'p', expect(preventDefault).toHaveBeenCalled();
preventDefault: jest.fn(), }
});
expect(wrapper.vm.selectedIndex).toBe(2); wrapper.setData({ selectedIndex: 1 });
if (keyboardEvents && keyboardEvents['Control+KeyP']) {
keyboardEvents['Control+KeyP'].action({ preventDefault });
expect(wrapper.vm.selectedIndex).toBe(0);
expect(preventDefault).toHaveBeenCalledTimes(2);
}
}); });
test('processKeyDownEvent updates index on arrow down', () => { it('ArrowDown and Control+KeyN update selectedIndex correctly', () => {
const Component = buildComponent({ const preventDefault = jest.fn();
data: { selectedIndex: 0, items: [1, 2, 3] }, const keyboardEvents = wrapper.vm.getKeyboardEvents();
});
const wrapper = shallowMount(Component); if (keyboardEvents && keyboardEvents.ArrowDown) {
wrapper.vm.processKeyDownEvent({ keyboardEvents.ArrowDown.action({ preventDefault });
key: 'ArrowDown', expect(wrapper.vm.selectedIndex).toBe(1);
preventDefault: jest.fn(), expect(preventDefault).toHaveBeenCalled();
}); }
expect(wrapper.vm.selectedIndex).toBe(1);
wrapper.setData({ selectedIndex: 1 });
if (keyboardEvents && keyboardEvents['Control+KeyN']) {
keyboardEvents['Control+KeyN'].action({ preventDefault });
expect(wrapper.vm.selectedIndex).toBe(2);
expect(preventDefault).toHaveBeenCalledTimes(2);
}
}); });
test('processKeyDownEvent calls select methods on Enter Key', () => { it('Enter key triggers onSelect method', () => {
const onSelectMockFn = jest.fn(); const preventDefault = jest.fn();
const Component = buildComponent({ const keyboardEvents = wrapper.vm.getKeyboardEvents();
data: { selectedIndex: 0, items: [1, 2, 3] },
methods: { onSelect: () => onSelectMockFn('enterKey pressed') }, if (keyboardEvents && keyboardEvents.Enter) {
}); keyboardEvents.Enter.action({ preventDefault });
const wrapper = shallowMount(Component); expect(wrapper.vm.onSelect).toHaveBeenCalled();
wrapper.vm.processKeyDownEvent({ expect(preventDefault).toHaveBeenCalled();
key: 'Enter', }
preventDefault: jest.fn(),
});
expect(onSelectMockFn).toHaveBeenCalledWith('enterKey pressed');
wrapper.vm.onSelect();
}); });
}); });
@@ -53,12 +53,6 @@ export const SHORTCUT_KEYS = [
firstKey: 'Alt / ⌥', firstKey: 'Alt / ⌥',
secondKey: 'S', secondKey: 'S',
}, },
{
id: 10,
label: 'SWITCH_CONVERSATION_STATUS',
firstKey: 'Alt / ⌥',
secondKey: 'B',
},
{ {
id: 11, id: 11,
label: 'SWITCH_TO_PRIVATE_NOTE', label: 'SWITCH_TO_PRIVATE_NOTE',
@@ -0,0 +1,32 @@
import { computed, getCurrentInstance } from 'vue';
import Vue from 'vue';
import VueI18n from 'vue-i18n';
let i18nInstance = VueI18n;
export function useI18n() {
if (!i18nInstance) throw new Error('vue-i18n not initialized');
const i18n = i18nInstance;
const instance = getCurrentInstance();
const vm = instance?.proxy || instance || new Vue({});
const locale = computed({
get() {
return i18n.locale;
},
set(v) {
i18n.locale = v;
},
});
return {
locale,
t: vm.$t.bind(vm),
tc: vm.$tc.bind(vm),
d: vm.$d.bind(vm),
te: vm.$te.bind(vm),
n: vm.$n.bind(vm),
};
}
@@ -1,5 +1,4 @@
import AnalyticsHelper from './AnalyticsHelper'; import AnalyticsHelper from './AnalyticsHelper';
import LogRocket from 'logrocket';
import DashboardAudioNotificationHelper from './AudioAlerts/DashboardAudioNotificationHelper'; import DashboardAudioNotificationHelper from './AudioAlerts/DashboardAudioNotificationHelper';
export const CHATWOOT_SET_USER = 'CHATWOOT_SET_USER'; export const CHATWOOT_SET_USER = 'CHATWOOT_SET_USER';
@@ -11,12 +10,6 @@ export const ANALYTICS_RESET = 'ANALYTICS_RESET';
export const initializeAnalyticsEvents = () => { export const initializeAnalyticsEvents = () => {
window.bus.$on(ANALYTICS_IDENTITY, ({ user }) => { window.bus.$on(ANALYTICS_IDENTITY, ({ user }) => {
AnalyticsHelper.identify(user); AnalyticsHelper.identify(user);
if (window.logRocketProjectId) {
LogRocket.identify(user.id, {
email: user.email,
name: user.name,
});
}
}); });
}; };
@@ -296,6 +296,8 @@
"BUTTON": "Add custom attribute", "BUTTON": "Add custom attribute",
"NOT_AVAILABLE": "There are no custom attributes available for this contact.", "NOT_AVAILABLE": "There are no custom attributes available for this contact.",
"COPY_SUCCESSFUL": "Copied to clipboard successfully", "COPY_SUCCESSFUL": "Copied to clipboard successfully",
"SHOW_MORE": "Show all attributes",
"SHOW_LESS": "Show less attributes",
"ACTIONS": { "ACTIONS": {
"COPY": "Copy attribute", "COPY": "Copy attribute",
"DELETE": "Delete attribute", "DELETE": "Delete attribute",
@@ -44,7 +44,8 @@
"CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox", "CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox",
"CREATED_AT": "Created At", "CREATED_AT": "Created At",
"LAST_ACTIVITY": "Last Activity", "LAST_ACTIVITY": "Last Activity",
"REFERER_LINK": "Referrer link" "REFERER_LINK": "Referrer link",
"BLOCKED": "Blocked"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "Standard Filters", "STANDARD_FILTERS": "Standard Filters",
@@ -64,7 +64,14 @@
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow", "SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow",
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week", "SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week",
"SNOOZED_UNTIL_NEXT_REPLY": "Snoozed until next reply" "SNOOZED_UNTIL_NEXT_REPLY": "Snoozed until next reply",
"SLA_STATUS": {
"FRT": "FRT {status}",
"NRT": "NRT {status}",
"RT": "RT {status}",
"MISSED": "missed",
"DUE": "due"
}
}, },
"RESOLVE_DROPDOWN": { "RESOLVE_DROPDOWN": {
"MARK_PENDING": "Mark as pending", "MARK_PENDING": "Mark as pending",
@@ -0,0 +1,5 @@
{
"GENERAL": {
"SHOWING_RESULTS": "Showing {firstIndex}-{lastIndex} of {totalCount} items"
}
}
@@ -87,7 +87,10 @@
"conversation_assignment": "Conversation Assigned", "conversation_assignment": "Conversation Assigned",
"assigned_conversation_new_message": "New Message", "assigned_conversation_new_message": "New Message",
"participating_conversation_new_message": "New Message", "participating_conversation_new_message": "New Message",
"conversation_mention": "Mention" "conversation_mention": "Mention",
"sla_missed_first_response": "SLA Missed",
"sla_missed_next_response": "SLA Missed",
"sla_missed_resolution": "SLA Missed"
} }
}, },
"NETWORK": { "NETWORK": {
@@ -4,24 +4,28 @@
"TITLE": "Inbox", "TITLE": "Inbox",
"DISPLAY_DROPDOWN": "Display", "DISPLAY_DROPDOWN": "Display",
"LOADING": "Fetching notifications", "LOADING": "Fetching notifications",
"EOF": "All notifications loaded 🎉",
"404": "There are no active notifications in this group.", "404": "There are no active notifications in this group.",
"NO_NOTIFICATIONS": "No notifications", "NO_NOTIFICATIONS": "No notifications",
"NOTE": "Notifications from all subscribed inboxes", "NOTE": "Notifications from all subscribed inboxes",
"NO_MESSAGES_AVAILABLE": "Oops! Not able to fetch messages",
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow", "SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow",
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week" "SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week"
}, },
"ACTION_HEADER": { "ACTION_HEADER": {
"SNOOZE": "Snooze notification", "SNOOZE": "Snooze notification",
"DELETE": "Delete notification" "DELETE": "Delete notification",
"BACK": "Back"
}, },
"TYPES": { "TYPES": {
"CONVERSATION_MENTION": "You have been mentioned in a conversation", "CONVERSATION_MENTION": "You have been mentioned in a conversation",
"CONVERSATION_CREATION": "New conversation created", "CONVERSATION_CREATION": "New conversation created",
"CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you", "CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in",
"SLA_MISSED_FIRST_RESPONSE": "SLA target first response missed for conversation",
"SLA_MISSED_NEXT_RESPONSE": "SLA target next response missed for conversation",
"SLA_MISSED_RESOLUTION": "SLA target resolution missed for conversation"
}, },
"MENU_ITEM": { "MENU_ITEM": {
"MARK_AS_READ": "Mark as read", "MARK_AS_READ": "Mark as read",
@@ -35,6 +35,14 @@
"NAME": "Resolution Count", "NAME": "Resolution Count",
"DESC": "( Total )" "DESC": "( Total )"
}, },
"BOT_RESOLUTION_COUNT": {
"NAME": "Resolution Count",
"DESC": "( Total )"
},
"BOT_HANDOFF_COUNT": {
"NAME": "Handoff Count",
"DESC": "( Total )"
},
"REPLY_TIME": { "REPLY_TIME": {
"NAME": "Customer waiting time", "NAME": "Customer waiting time",
"TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)" "TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)"
@@ -130,7 +138,11 @@
"groupBy": "Year" "groupBy": "Year"
} }
], ],
"BUSINESS_HOURS": "Business Hours" "BUSINESS_HOURS": "Business Hours",
"FILTER_ACTIONS": {
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "No results found"
}
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "Agents Overview", "HEADER": "Agents Overview",
@@ -433,6 +445,27 @@
} }
} }
}, },
"BOT_REPORTS": {
"HEADER": "Bot Reports",
"METRIC": {
"TOTAL_CONVERSATIONS": {
"LABEL": "No. of Conversations",
"TOOLTIP": "Total number of conversations handled by the bot"
},
"TOTAL_RESPONSES": {
"LABEL": "Total Responses",
"TOOLTIP": "Total number of responses sent by the bot"
},
"RESOLUTION_RATE": {
"LABEL": "Resolution Rate",
"TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100"
},
"HANDOFF_RATE": {
"LABEL": "Handoff Rate",
"TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100"
}
}
},
"OVERVIEW_REPORTS": { "OVERVIEW_REPORTS": {
"HEADER": "Overview", "HEADER": "Overview",
"LIVE": "Live", "LIVE": "Live",
@@ -476,5 +509,54 @@
"THURSDAY": "Thursday", "THURSDAY": "Thursday",
"FRIDAY": "Friday", "FRIDAY": "Friday",
"SATURDAY": "Saturday" "SATURDAY": "Saturday"
},
"SLA_REPORTS": {
"HEADER": "SLA Reports",
"NO_RECORDS": "SLA applied conversations are not available.",
"LOADING": "Loading SLA data...",
"DOWNLOAD_SLA_REPORTS": "Download SLA reports",
"DOWNLOAD_FAILED": "Failed to download SLA Reports",
"DROPDOWN": {
"ADD_FIlTER": "Add filter",
"CLEAR_ALL": "Clear all",
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "No results found",
"NO_FILTER": "No filters available",
"SEARCH": "Search filter",
"INPUT_PLACEHOLDER": {
"SLA": "SLA name",
"AGENTS": "Agent name",
"INBOXES": "Inbox name",
"LABELS": "Label name",
"TEAMS": "Team name"
},
"SLA": "SLA Policy",
"INBOXES": "Inbox",
"AGENTS": "Agent",
"LABELS": "Label",
"TEAMS": "Team"
},
"METRICS": {
"HIT_RATE": {
"LABEL": "Hit Rate",
"TOOLTIP": "Percentage of SLAs created were completed successfully"
},
"NO_OF_MISSES": {
"LABEL": "Number of Misses",
"TOOLTIP": "Total SLA misses in a certain period"
},
"NO_OF_CONVERSATIONS": {
"LABEL": "Number of Conversations",
"TOOLTIP": "Total number of conversations with SLA"
}
},
"TABLE": {
"HEADER": {
"POLICY": "Policy",
"CONVERSATION": "Conversation",
"AGENT": "Agent"
},
"VIEW_DETAILS": "View Details"
}
} }
} }
@@ -83,7 +83,10 @@
"CONVERSATION_CREATION": "Send email notifications when a new conversation is created", "CONVERSATION_CREATION": "Send email notifications when a new conversation is created",
"CONVERSATION_MENTION": "Send email notifications when you are mentioned in a conversation", "CONVERSATION_MENTION": "Send email notifications when you are mentioned in a conversation",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in a participating conversation" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in a participating conversation",
"SLA_MISSED_FIRST_RESPONSE": "Send email notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send email notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send email notifications when a conversation misses resolution SLA"
}, },
"API": { "API": {
"UPDATE_SUCCESS": "Your notification preferences are updated successfully", "UPDATE_SUCCESS": "Your notification preferences are updated successfully",
@@ -98,7 +101,10 @@
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in a participating conversation", "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in a participating conversation",
"HAS_ENABLED_PUSH": "You have enabled push for this browser.", "HAS_ENABLED_PUSH": "You have enabled push for this browser.",
"REQUEST_PUSH": "Enable push notifications" "REQUEST_PUSH": "Enable push notifications",
"SLA_MISSED_FIRST_RESPONSE": "Send push notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send push notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send push notifications when a conversation misses resolution SLA"
}, },
"PROFILE_IMAGE": { "PROFILE_IMAGE": {
"LABEL": "Profile Image" "LABEL": "Profile Image"
@@ -199,6 +205,7 @@
"SIDEBAR": { "SIDEBAR": {
"CURRENTLY_VIEWING_ACCOUNT": "Currently viewing:", "CURRENTLY_VIEWING_ACCOUNT": "Currently viewing:",
"SWITCH": "Switch", "SWITCH": "Switch",
"INBOX_VIEW": "Inbox View",
"CONVERSATIONS": "Conversations", "CONVERSATIONS": "Conversations",
"INBOX": "Inbox", "INBOX": "Inbox",
"ALL_CONVERSATIONS": "All Conversations", "ALL_CONVERSATIONS": "All Conversations",
@@ -237,6 +244,8 @@
"CAMPAIGNS": "Campaigns", "CAMPAIGNS": "Campaigns",
"ONGOING": "Ongoing", "ONGOING": "Ongoing",
"ONE_OFF": "One off", "ONE_OFF": "One off",
"REPORTS_SLA": "SLA",
"REPORTS_BOT": "Bot",
"REPORTS_AGENT": "Agents", "REPORTS_AGENT": "Agents",
"REPORTS_LABEL": "Labels", "REPORTS_LABEL": "Labels",
"REPORTS_INBOX": "Inbox", "REPORTS_INBOX": "Inbox",
@@ -1,22 +1,31 @@
{ {
"SLA": { "SLA": {
"HEADER": "SLA", "HEADER": "SLA",
"HEADER_BTN_TXT": "Add SLA", "ADD_ACTION": "Add SLA",
"ADD_ACTION_LONG": "Create a new SLA Policy",
"DESCRIPTION": "Service Level Agreements (SLAs) are contracts that define clear expectations between your team and customers. They establish standards for response and resolution times, creating a framework for accountability and ensures a consistent, high-quality experience.",
"LEARN_MORE": "Learn more about SLA",
"LOADING": "Fetching SLAs", "LOADING": "Fetching SLAs",
"SEARCH_404": "There are no items matching this query",
"SIDEBAR_TXT": "<p><b>SLA</b> <p>Think of Service Level Agreements (SLAs) like friendly promises between a service provider and a customer.</p> <p> These promises set clear expectations for things like how quickly the team will respond to issues, making sure you always get a reliable and top-notch experience!</p>",
"LIST": { "LIST": {
"404": "There are no SLAs available in this account.", "404": "There are no SLAs available in this account.",
"TITLE": "Manage SLA", "EMPTY": {
"DESC": "SLAs: Friendly promises for great service!", "TITLE_1": "Enterprise P0",
"TABLE_HEADER": [ "DESC_1": "Issues raised by enterprise customers, that require immediate attention.",
"Name", "TITLE_2": "Enterprise P1",
"Description", "DESC_2": "Issues raised by enterprise customers, that needs to be acknowledged quickly."
"FRT", },
"NRT", "BUSINESS_HOURS_ON": "Business hours on",
"RT", "BUSINESS_HOURS_OFF": "Business hours off",
"Business Hours" "RESPONSE_TYPES": {
] "FRT": "First response time threshold",
"NRT": "Next response time threshold",
"RT": "Resolution time threshold",
"SHORT_HAND": {
"FRT": "FRT",
"NRT": "NRT",
"RT": "RT"
}
}
}, },
"FORM": { "FORM": {
"NAME": { "NAME": {
@@ -56,18 +65,32 @@
}, },
"ADD": { "ADD": {
"TITLE": "Add SLA", "TITLE": "Add SLA",
"DESC": "SLAs: Friendly promises for great service!", "DESC": "Friendly promises for great service!",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA added successfully", "SUCCESS_MESSAGE": "SLA added successfully",
"ERROR_MESSAGE": "There was an error, please try again" "ERROR_MESSAGE": "There was an error, please try again"
} }
}, },
"EDIT": { "DELETE": {
"TITLE": "Edit SLA", "TITLE": "Delete SLA",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA updated successfully", "SUCCESS_MESSAGE": "SLA deleted successfully",
"ERROR_MESSAGE": "There was an error, please try again" "ERROR_MESSAGE": "There was an error, please try again"
},
"CONFIRM": {
"TITLE": "Confirm Deletion",
"MESSAGE": "Are you sure you want to delete ",
"YES": "Yes, Delete ",
"NO": "No, Keep "
} }
},
"EVENTS": {
"TITLE": "SLA Misses",
"FRT": "First response time",
"NRT": "Next response time",
"RT": "Resolution time",
"SHOW_MORE": "{count} more",
"HIDE": "Hide {count} rows"
} }
} }
} }
@@ -296,6 +296,8 @@
"BUTTON": "إضافة سمة خاصة", "BUTTON": "إضافة سمة خاصة",
"NOT_AVAILABLE": "لا توجد سمات مخصصة متاحة لجهة الاتصال هذه.", "NOT_AVAILABLE": "لا توجد سمات مخصصة متاحة لجهة الاتصال هذه.",
"COPY_SUCCESSFUL": "تم النسخ إلى الحافظة بنجاح", "COPY_SUCCESSFUL": "تم النسخ إلى الحافظة بنجاح",
"SHOW_MORE": "Show all attributes",
"SHOW_LESS": "Show less attributes",
"ACTIONS": { "ACTIONS": {
"COPY": "نسخ السمة", "COPY": "نسخ السمة",
"DELETE": "حذف السمة", "DELETE": "حذف السمة",
@@ -44,7 +44,8 @@
"CUSTOM_ATTRIBUTE_CHECKBOX": "مربع", "CUSTOM_ATTRIBUTE_CHECKBOX": "مربع",
"CREATED_AT": "تم إنشاؤها في", "CREATED_AT": "تم إنشاؤها في",
"LAST_ACTIVITY": "آخر نشاط", "LAST_ACTIVITY": "آخر نشاط",
"REFERER_LINK": "رابط المرجع" "REFERER_LINK": "رابط المرجع",
"BLOCKED": "Blocked"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "الفلاتر القياسية", "STANDARD_FILTERS": "الفلاتر القياسية",
@@ -64,7 +64,14 @@
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "غفوة حتى الغد", "SNOOZED_UNTIL_TOMORROW": "غفوة حتى الغد",
"SNOOZED_UNTIL_NEXT_WEEK": "غفوة حتى الأسبوع القادم", "SNOOZED_UNTIL_NEXT_WEEK": "غفوة حتى الأسبوع القادم",
"SNOOZED_UNTIL_NEXT_REPLY": "غفوة حتى الرد التالي" "SNOOZED_UNTIL_NEXT_REPLY": "غفوة حتى الرد التالي",
"SLA_STATUS": {
"FRT": "FRT {status}",
"NRT": "NRT {status}",
"RT": "RT {status}",
"MISSED": "missed",
"DUE": "due"
}
}, },
"RESOLVE_DROPDOWN": { "RESOLVE_DROPDOWN": {
"MARK_PENDING": "تحديد كمعلق", "MARK_PENDING": "تحديد كمعلق",
@@ -0,0 +1,5 @@
{
"GENERAL": {
"SHOWING_RESULTS": "Showing {firstIndex}-{lastIndex} of {totalCount} items"
}
}
@@ -87,7 +87,10 @@
"conversation_assignment": "تم تعيين المحادثة", "conversation_assignment": "تم تعيين المحادثة",
"assigned_conversation_new_message": "رسالة جديدة", "assigned_conversation_new_message": "رسالة جديدة",
"participating_conversation_new_message": "رسالة جديدة", "participating_conversation_new_message": "رسالة جديدة",
"conversation_mention": "إشارة" "conversation_mention": "إشارة",
"sla_missed_first_response": "SLA Missed",
"sla_missed_next_response": "SLA Missed",
"sla_missed_resolution": "SLA Missed"
} }
}, },
"NETWORK": { "NETWORK": {
@@ -4,24 +4,28 @@
"TITLE": "صندوق الوارد", "TITLE": "صندوق الوارد",
"DISPLAY_DROPDOWN": "Display", "DISPLAY_DROPDOWN": "Display",
"LOADING": "Fetching notifications", "LOADING": "Fetching notifications",
"EOF": "تم تحميل كافة الإشعارات 🎉",
"404": "There are no active notifications in this group.", "404": "There are no active notifications in this group.",
"NO_NOTIFICATIONS": "No notifications", "NO_NOTIFICATIONS": "No notifications",
"NOTE": "Notifications from all subscribed inboxes", "NOTE": "Notifications from all subscribed inboxes",
"NO_MESSAGES_AVAILABLE": "Oops! Not able to fetch messages",
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "غفوة حتى الغد", "SNOOZED_UNTIL_TOMORROW": "غفوة حتى الغد",
"SNOOZED_UNTIL_NEXT_WEEK": "غفوة حتى الأسبوع القادم" "SNOOZED_UNTIL_NEXT_WEEK": "غفوة حتى الأسبوع القادم"
}, },
"ACTION_HEADER": { "ACTION_HEADER": {
"SNOOZE": "Snooze notification", "SNOOZE": "Snooze notification",
"DELETE": "Delete notification" "DELETE": "Delete notification",
"BACK": "العودة"
}, },
"TYPES": { "TYPES": {
"CONVERSATION_MENTION": "You have been mentioned in a conversation", "CONVERSATION_MENTION": "You have been mentioned in a conversation",
"CONVERSATION_CREATION": "New conversation created", "CONVERSATION_CREATION": "New conversation created",
"CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you", "CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in",
"SLA_MISSED_FIRST_RESPONSE": "SLA target first response missed for conversation",
"SLA_MISSED_NEXT_RESPONSE": "SLA target next response missed for conversation",
"SLA_MISSED_RESOLUTION": "SLA target resolution missed for conversation"
}, },
"MENU_ITEM": { "MENU_ITEM": {
"MARK_AS_READ": "Mark as read", "MARK_AS_READ": "Mark as read",
@@ -35,6 +35,14 @@
"NAME": "عدد مرات الإغلاق", "NAME": "عدد مرات الإغلاق",
"DESC": "(الإجمالي)" "DESC": "(الإجمالي)"
}, },
"BOT_RESOLUTION_COUNT": {
"NAME": "عدد مرات الإغلاق",
"DESC": "(الإجمالي)"
},
"BOT_HANDOFF_COUNT": {
"NAME": "Handoff Count",
"DESC": "(الإجمالي)"
},
"REPLY_TIME": { "REPLY_TIME": {
"NAME": "Customer waiting time", "NAME": "Customer waiting time",
"TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)" "TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)"
@@ -130,7 +138,11 @@
"groupBy": "الشهر" "groupBy": "الشهر"
} }
], ],
"BUSINESS_HOURS": "ساعات العمل" "BUSINESS_HOURS": "ساعات العمل",
"FILTER_ACTIONS": {
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "لم يتم العثور على النتائج"
}
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "نظرة عامة للوكلاء", "HEADER": "نظرة عامة للوكلاء",
@@ -433,6 +445,27 @@
} }
} }
}, },
"BOT_REPORTS": {
"HEADER": "Bot Reports",
"METRIC": {
"TOTAL_CONVERSATIONS": {
"LABEL": "No. of Conversations",
"TOOLTIP": "Total number of conversations handled by the bot"
},
"TOTAL_RESPONSES": {
"LABEL": "Total Responses",
"TOOLTIP": "Total number of responses sent by the bot"
},
"RESOLUTION_RATE": {
"LABEL": "Resolution Rate",
"TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100"
},
"HANDOFF_RATE": {
"LABEL": "Handoff Rate",
"TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100"
}
}
},
"OVERVIEW_REPORTS": { "OVERVIEW_REPORTS": {
"HEADER": "نظرة عامة", "HEADER": "نظرة عامة",
"LIVE": "مباشر", "LIVE": "مباشر",
@@ -476,5 +509,54 @@
"THURSDAY": "Thursday", "THURSDAY": "Thursday",
"FRIDAY": "Friday", "FRIDAY": "Friday",
"SATURDAY": "Saturday" "SATURDAY": "Saturday"
},
"SLA_REPORTS": {
"HEADER": "SLA Reports",
"NO_RECORDS": "SLA applied conversations are not available.",
"LOADING": "Loading SLA data...",
"DOWNLOAD_SLA_REPORTS": "Download SLA reports",
"DOWNLOAD_FAILED": "Failed to download SLA Reports",
"DROPDOWN": {
"ADD_FIlTER": "Add filter",
"CLEAR_ALL": "Clear all",
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "لم يتم العثور على النتائج",
"NO_FILTER": "No filters available",
"SEARCH": "Search filter",
"INPUT_PLACEHOLDER": {
"SLA": "SLA name",
"AGENTS": "اسم الموظف",
"INBOXES": "اسم صندوق الوارد",
"LABELS": "اسم الوسم",
"TEAMS": "اسم الفريق"
},
"SLA": "SLA Policy",
"INBOXES": "صندوق الوارد",
"AGENTS": "موظف الدعم",
"LABELS": "الوسم",
"TEAMS": "الفريق"
},
"METRICS": {
"HIT_RATE": {
"LABEL": "Hit Rate",
"TOOLTIP": "Percentage of SLAs created were completed successfully"
},
"NO_OF_MISSES": {
"LABEL": "Number of Misses",
"TOOLTIP": "Total SLA misses in a certain period"
},
"NO_OF_CONVERSATIONS": {
"LABEL": "Number of Conversations",
"TOOLTIP": "Total number of conversations with SLA"
}
},
"TABLE": {
"HEADER": {
"POLICY": "Policy",
"CONVERSATION": "المحادثات",
"AGENT": "موظف الدعم"
},
"VIEW_DETAILS": "View Details"
}
} }
} }
@@ -83,7 +83,10 @@
"CONVERSATION_CREATION": "إرسال إشعارات للبريد الإلكتروني عند ورود محادثة جديدة", "CONVERSATION_CREATION": "إرسال إشعارات للبريد الإلكتروني عند ورود محادثة جديدة",
"CONVERSATION_MENTION": "إرسال إشعارات بالبريد الإلكتروني عندما يتم ذكرك في محادثة", "CONVERSATION_MENTION": "إرسال إشعارات بالبريد الإلكتروني عندما يتم ذكرك في محادثة",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "إرسال إشعارات البريد الإلكتروني عند إنشاء رسالة جديدة في محادثة موكلة", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "إرسال إشعارات البريد الإلكتروني عند إنشاء رسالة جديدة في محادثة موكلة",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "إرسال إشعارات التنية عند إنشاء رسالة جديدة في محادثة موكلة" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "إرسال إشعارات التنية عند إنشاء رسالة جديدة في محادثة موكلة",
"SLA_MISSED_FIRST_RESPONSE": "Send email notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send email notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send email notifications when a conversation misses resolution SLA"
}, },
"API": { "API": {
"UPDATE_SUCCESS": "يتم تحديث إعدادات الإشعارات بنجاح", "UPDATE_SUCCESS": "يتم تحديث إعدادات الإشعارات بنجاح",
@@ -98,7 +101,10 @@
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "إرسال إشعارات التنية عند إنشاء رسالة جديدة في محادثة موكلة", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "إرسال إشعارات التنية عند إنشاء رسالة جديدة في محادثة موكلة",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "إرسال إشعارات التنية عند إنشاء رسالة جديدة في محادثة موكلة", "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "إرسال إشعارات التنية عند إنشاء رسالة جديدة في محادثة موكلة",
"HAS_ENABLED_PUSH": "لقد قمت بتمكين الإشعارات لهذا المتصفح.", "HAS_ENABLED_PUSH": "لقد قمت بتمكين الإشعارات لهذا المتصفح.",
"REQUEST_PUSH": "تفعيل إشعارات المتصفح" "REQUEST_PUSH": "تفعيل إشعارات المتصفح",
"SLA_MISSED_FIRST_RESPONSE": "Send push notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send push notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send push notifications when a conversation misses resolution SLA"
}, },
"PROFILE_IMAGE": { "PROFILE_IMAGE": {
"LABEL": "صورة الملف الشخصي" "LABEL": "صورة الملف الشخصي"
@@ -199,6 +205,7 @@
"SIDEBAR": { "SIDEBAR": {
"CURRENTLY_VIEWING_ACCOUNT": "مشاهدة حاليا:", "CURRENTLY_VIEWING_ACCOUNT": "مشاهدة حاليا:",
"SWITCH": "تبديل", "SWITCH": "تبديل",
"INBOX_VIEW": "Inbox View",
"CONVERSATIONS": "المحادثات", "CONVERSATIONS": "المحادثات",
"INBOX": "صندوق الوارد", "INBOX": "صندوق الوارد",
"ALL_CONVERSATIONS": "كل المحادثات", "ALL_CONVERSATIONS": "كل المحادثات",
@@ -237,6 +244,8 @@
"CAMPAIGNS": "الحملات", "CAMPAIGNS": "الحملات",
"ONGOING": "جارية", "ONGOING": "جارية",
"ONE_OFF": "إيقاف واحد", "ONE_OFF": "إيقاف واحد",
"REPORTS_SLA": "SLA",
"REPORTS_BOT": "رد آلي",
"REPORTS_AGENT": "موظف الدعم", "REPORTS_AGENT": "موظف الدعم",
"REPORTS_LABEL": "الوسوم", "REPORTS_LABEL": "الوسوم",
"REPORTS_INBOX": "صندوق الوارد", "REPORTS_INBOX": "صندوق الوارد",
@@ -1,22 +1,31 @@
{ {
"SLA": { "SLA": {
"HEADER": "SLA", "HEADER": "SLA",
"HEADER_BTN_TXT": "Add SLA", "ADD_ACTION": "Add SLA",
"ADD_ACTION_LONG": "Create a new SLA Policy",
"DESCRIPTION": "Service Level Agreements (SLAs) are contracts that define clear expectations between your team and customers. They establish standards for response and resolution times, creating a framework for accountability and ensures a consistent, high-quality experience.",
"LEARN_MORE": "Learn more about SLA",
"LOADING": "Fetching SLAs", "LOADING": "Fetching SLAs",
"SEARCH_404": "لا توجد عناصر مطابقة لهذا الاستعلام",
"SIDEBAR_TXT": "<p><b>SLA</b> <p>Think of Service Level Agreements (SLAs) like friendly promises between a service provider and a customer.</p> <p> These promises set clear expectations for things like how quickly the team will respond to issues, making sure you always get a reliable and top-notch experience!</p>",
"LIST": { "LIST": {
"404": "There are no SLAs available in this account.", "404": "There are no SLAs available in this account.",
"TITLE": "Manage SLA", "EMPTY": {
"DESC": "SLAs: Friendly promises for great service!", "TITLE_1": "Enterprise P0",
"TABLE_HEADER": [ "DESC_1": "Issues raised by enterprise customers, that require immediate attention.",
"الاسم", "TITLE_2": "Enterprise P1",
"الوصف", "DESC_2": "Issues raised by enterprise customers, that needs to be acknowledged quickly."
"FRT", },
"NRT", "BUSINESS_HOURS_ON": "Business hours on",
"RT", "BUSINESS_HOURS_OFF": "Business hours off",
"ساعات العمل" "RESPONSE_TYPES": {
] "FRT": "First response time threshold",
"NRT": "Next response time threshold",
"RT": "Resolution time threshold",
"SHORT_HAND": {
"FRT": "FRT",
"NRT": "NRT",
"RT": "RT"
}
}
}, },
"FORM": { "FORM": {
"NAME": { "NAME": {
@@ -56,18 +65,32 @@
}, },
"ADD": { "ADD": {
"TITLE": "Add SLA", "TITLE": "Add SLA",
"DESC": "SLAs: Friendly promises for great service!", "DESC": "Friendly promises for great service!",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA added successfully", "SUCCESS_MESSAGE": "SLA added successfully",
"ERROR_MESSAGE": "حدث خطأ، الرجاء المحاولة مرة أخرى" "ERROR_MESSAGE": "حدث خطأ، الرجاء المحاولة مرة أخرى"
} }
}, },
"EDIT": { "DELETE": {
"TITLE": "Edit SLA", "TITLE": "Delete SLA",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA updated successfully", "SUCCESS_MESSAGE": "SLA deleted successfully",
"ERROR_MESSAGE": "حدث خطأ، الرجاء المحاولة مرة أخرى" "ERROR_MESSAGE": "حدث خطأ، الرجاء المحاولة مرة أخرى"
},
"CONFIRM": {
"TITLE": "تأكيد الحذف",
"MESSAGE": "Are you sure you want to delete ",
"YES": "نعم، احذف ",
"NO": "لا، احتفظ "
} }
},
"EVENTS": {
"TITLE": "SLA Misses",
"FRT": "وقت الاستجابة الأولى",
"NRT": "Next response time",
"RT": "Resolution time",
"SHOW_MORE": "{count} more",
"HIDE": "Hide {count} rows"
} }
} }
} }
@@ -83,7 +83,7 @@
"SELECT_ALL": "تحديد جميع الوكلاء", "SELECT_ALL": "تحديد جميع الوكلاء",
"SELECTED_COUNT": "تم تحديد %{selected} من أصل %{total} وكيل.", "SELECTED_COUNT": "تم تحديد %{selected} من أصل %{total} وكيل.",
"BUTTON_TEXT": "إضافة موظفين", "BUTTON_TEXT": "إضافة موظفين",
"AGENT_VALIDATION_ERROR": "اختيار وكيل واحد على الاقل." "AGENT_VALIDATION_ERROR": "اختيار وكيل واحد على الأقل."
}, },
"FINISH": { "FINISH": {
"TITLE": "أصبح فريقك جاهزة الآن!", "TITLE": "أصبح فريقك جاهزة الآن!",
@@ -296,6 +296,8 @@
"BUTTON": "Добавяне на персонализиран атрибут", "BUTTON": "Добавяне на персонализиран атрибут",
"NOT_AVAILABLE": "Няма персонализирани атрибути за този контакт.", "NOT_AVAILABLE": "Няма персонализирани атрибути за този контакт.",
"COPY_SUCCESSFUL": "Успешно копиране в клипборда", "COPY_SUCCESSFUL": "Успешно копиране в клипборда",
"SHOW_MORE": "Show all attributes",
"SHOW_LESS": "Show less attributes",
"ACTIONS": { "ACTIONS": {
"COPY": "Копиране на атрибут", "COPY": "Копиране на атрибут",
"DELETE": "Изтриване на атрибут", "DELETE": "Изтриване на атрибут",
@@ -44,7 +44,8 @@
"CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox", "CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox",
"CREATED_AT": "Created At", "CREATED_AT": "Created At",
"LAST_ACTIVITY": "Последна активност", "LAST_ACTIVITY": "Последна активност",
"REFERER_LINK": "Referrer link" "REFERER_LINK": "Referrer link",
"BLOCKED": "Blocked"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "Standard Filters", "STANDARD_FILTERS": "Standard Filters",
@@ -64,7 +64,14 @@
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow", "SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow",
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week", "SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week",
"SNOOZED_UNTIL_NEXT_REPLY": "Snoozed until next reply" "SNOOZED_UNTIL_NEXT_REPLY": "Snoozed until next reply",
"SLA_STATUS": {
"FRT": "FRT {status}",
"NRT": "NRT {status}",
"RT": "RT {status}",
"MISSED": "missed",
"DUE": "due"
}
}, },
"RESOLVE_DROPDOWN": { "RESOLVE_DROPDOWN": {
"MARK_PENDING": "Mark as pending", "MARK_PENDING": "Mark as pending",
@@ -0,0 +1,5 @@
{
"GENERAL": {
"SHOWING_RESULTS": "Showing {firstIndex}-{lastIndex} of {totalCount} items"
}
}
@@ -87,7 +87,10 @@
"conversation_assignment": "Conversation Assigned", "conversation_assignment": "Conversation Assigned",
"assigned_conversation_new_message": "New Message", "assigned_conversation_new_message": "New Message",
"participating_conversation_new_message": "New Message", "participating_conversation_new_message": "New Message",
"conversation_mention": "Mention" "conversation_mention": "Mention",
"sla_missed_first_response": "SLA Missed",
"sla_missed_next_response": "SLA Missed",
"sla_missed_resolution": "SLA Missed"
} }
}, },
"NETWORK": { "NETWORK": {
@@ -4,24 +4,28 @@
"TITLE": "Входяща кутия", "TITLE": "Входяща кутия",
"DISPLAY_DROPDOWN": "Display", "DISPLAY_DROPDOWN": "Display",
"LOADING": "Fetching notifications", "LOADING": "Fetching notifications",
"EOF": "All notifications loaded 🎉",
"404": "There are no active notifications in this group.", "404": "There are no active notifications in this group.",
"NO_NOTIFICATIONS": "No notifications", "NO_NOTIFICATIONS": "No notifications",
"NOTE": "Notifications from all subscribed inboxes", "NOTE": "Notifications from all subscribed inboxes",
"NO_MESSAGES_AVAILABLE": "Oops! Not able to fetch messages",
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow", "SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow",
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week" "SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week"
}, },
"ACTION_HEADER": { "ACTION_HEADER": {
"SNOOZE": "Snooze notification", "SNOOZE": "Snooze notification",
"DELETE": "Delete notification" "DELETE": "Delete notification",
"BACK": "Back"
}, },
"TYPES": { "TYPES": {
"CONVERSATION_MENTION": "You have been mentioned in a conversation", "CONVERSATION_MENTION": "You have been mentioned in a conversation",
"CONVERSATION_CREATION": "New conversation created", "CONVERSATION_CREATION": "New conversation created",
"CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you", "CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in",
"SLA_MISSED_FIRST_RESPONSE": "SLA target first response missed for conversation",
"SLA_MISSED_NEXT_RESPONSE": "SLA target next response missed for conversation",
"SLA_MISSED_RESOLUTION": "SLA target resolution missed for conversation"
}, },
"MENU_ITEM": { "MENU_ITEM": {
"MARK_AS_READ": "Mark as read", "MARK_AS_READ": "Mark as read",
@@ -35,6 +35,14 @@
"NAME": "Resolution Count", "NAME": "Resolution Count",
"DESC": "( Total )" "DESC": "( Total )"
}, },
"BOT_RESOLUTION_COUNT": {
"NAME": "Resolution Count",
"DESC": "( Total )"
},
"BOT_HANDOFF_COUNT": {
"NAME": "Handoff Count",
"DESC": "( Total )"
},
"REPLY_TIME": { "REPLY_TIME": {
"NAME": "Customer waiting time", "NAME": "Customer waiting time",
"TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)" "TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)"
@@ -130,7 +138,11 @@
"groupBy": "Month" "groupBy": "Month"
} }
], ],
"BUSINESS_HOURS": "Business Hours" "BUSINESS_HOURS": "Business Hours",
"FILTER_ACTIONS": {
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "Няма намерени резултати"
}
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "Agents Overview", "HEADER": "Agents Overview",
@@ -433,6 +445,27 @@
} }
} }
}, },
"BOT_REPORTS": {
"HEADER": "Bot Reports",
"METRIC": {
"TOTAL_CONVERSATIONS": {
"LABEL": "No. of Conversations",
"TOOLTIP": "Total number of conversations handled by the bot"
},
"TOTAL_RESPONSES": {
"LABEL": "Total Responses",
"TOOLTIP": "Total number of responses sent by the bot"
},
"RESOLUTION_RATE": {
"LABEL": "Resolution Rate",
"TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100"
},
"HANDOFF_RATE": {
"LABEL": "Handoff Rate",
"TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100"
}
}
},
"OVERVIEW_REPORTS": { "OVERVIEW_REPORTS": {
"HEADER": "Overview", "HEADER": "Overview",
"LIVE": "Live", "LIVE": "Live",
@@ -476,5 +509,54 @@
"THURSDAY": "Thursday", "THURSDAY": "Thursday",
"FRIDAY": "Friday", "FRIDAY": "Friday",
"SATURDAY": "Saturday" "SATURDAY": "Saturday"
},
"SLA_REPORTS": {
"HEADER": "SLA Reports",
"NO_RECORDS": "SLA applied conversations are not available.",
"LOADING": "Loading SLA data...",
"DOWNLOAD_SLA_REPORTS": "Download SLA reports",
"DOWNLOAD_FAILED": "Failed to download SLA Reports",
"DROPDOWN": {
"ADD_FIlTER": "Add filter",
"CLEAR_ALL": "Clear all",
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "Няма намерени резултати",
"NO_FILTER": "No filters available",
"SEARCH": "Search filter",
"INPUT_PLACEHOLDER": {
"SLA": "SLA name",
"AGENTS": "Agent name",
"INBOXES": "Inbox name",
"LABELS": "Label name",
"TEAMS": "Team name"
},
"SLA": "SLA Policy",
"INBOXES": "Входяща кутия",
"AGENTS": "Агент",
"LABELS": "Label",
"TEAMS": "Team"
},
"METRICS": {
"HIT_RATE": {
"LABEL": "Hit Rate",
"TOOLTIP": "Percentage of SLAs created were completed successfully"
},
"NO_OF_MISSES": {
"LABEL": "Number of Misses",
"TOOLTIP": "Total SLA misses in a certain period"
},
"NO_OF_CONVERSATIONS": {
"LABEL": "Number of Conversations",
"TOOLTIP": "Total number of conversations with SLA"
}
},
"TABLE": {
"HEADER": {
"POLICY": "Policy",
"CONVERSATION": "Разговор",
"AGENT": "Агент"
},
"VIEW_DETAILS": "View Details"
}
} }
} }
@@ -83,7 +83,10 @@
"CONVERSATION_CREATION": "Send email notifications when a new conversation is created", "CONVERSATION_CREATION": "Send email notifications when a new conversation is created",
"CONVERSATION_MENTION": "Send email notifications when you are mentioned in a conversation", "CONVERSATION_MENTION": "Send email notifications when you are mentioned in a conversation",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in a participating conversation" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in a participating conversation",
"SLA_MISSED_FIRST_RESPONSE": "Send email notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send email notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send email notifications when a conversation misses resolution SLA"
}, },
"API": { "API": {
"UPDATE_SUCCESS": "Your notification preferences are updated successfully", "UPDATE_SUCCESS": "Your notification preferences are updated successfully",
@@ -98,7 +101,10 @@
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in a participating conversation", "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in a participating conversation",
"HAS_ENABLED_PUSH": "You have enabled push for this browser.", "HAS_ENABLED_PUSH": "You have enabled push for this browser.",
"REQUEST_PUSH": "Enable push notifications" "REQUEST_PUSH": "Enable push notifications",
"SLA_MISSED_FIRST_RESPONSE": "Send push notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send push notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send push notifications when a conversation misses resolution SLA"
}, },
"PROFILE_IMAGE": { "PROFILE_IMAGE": {
"LABEL": "Profile Image" "LABEL": "Profile Image"
@@ -199,6 +205,7 @@
"SIDEBAR": { "SIDEBAR": {
"CURRENTLY_VIEWING_ACCOUNT": "Currently viewing:", "CURRENTLY_VIEWING_ACCOUNT": "Currently viewing:",
"SWITCH": "Switch", "SWITCH": "Switch",
"INBOX_VIEW": "Inbox View",
"CONVERSATIONS": "Разговори", "CONVERSATIONS": "Разговори",
"INBOX": "Входяща кутия", "INBOX": "Входяща кутия",
"ALL_CONVERSATIONS": "All Conversations", "ALL_CONVERSATIONS": "All Conversations",
@@ -237,6 +244,8 @@
"CAMPAIGNS": "Campaigns", "CAMPAIGNS": "Campaigns",
"ONGOING": "Ongoing", "ONGOING": "Ongoing",
"ONE_OFF": "One off", "ONE_OFF": "One off",
"REPORTS_SLA": "SLA",
"REPORTS_BOT": "Бот",
"REPORTS_AGENT": "Агенти", "REPORTS_AGENT": "Агенти",
"REPORTS_LABEL": "Labels", "REPORTS_LABEL": "Labels",
"REPORTS_INBOX": "Входяща кутия", "REPORTS_INBOX": "Входяща кутия",
@@ -1,22 +1,31 @@
{ {
"SLA": { "SLA": {
"HEADER": "SLA", "HEADER": "SLA",
"HEADER_BTN_TXT": "Add SLA", "ADD_ACTION": "Add SLA",
"ADD_ACTION_LONG": "Create a new SLA Policy",
"DESCRIPTION": "Service Level Agreements (SLAs) are contracts that define clear expectations between your team and customers. They establish standards for response and resolution times, creating a framework for accountability and ensures a consistent, high-quality experience.",
"LEARN_MORE": "Learn more about SLA",
"LOADING": "Fetching SLAs", "LOADING": "Fetching SLAs",
"SEARCH_404": "Няма резултати отговарящи на тази заявка",
"SIDEBAR_TXT": "<p><b>SLA</b> <p>Think of Service Level Agreements (SLAs) like friendly promises between a service provider and a customer.</p> <p> These promises set clear expectations for things like how quickly the team will respond to issues, making sure you always get a reliable and top-notch experience!</p>",
"LIST": { "LIST": {
"404": "There are no SLAs available in this account.", "404": "There are no SLAs available in this account.",
"TITLE": "Manage SLA", "EMPTY": {
"DESC": "SLAs: Friendly promises for great service!", "TITLE_1": "Enterprise P0",
"TABLE_HEADER": [ "DESC_1": "Issues raised by enterprise customers, that require immediate attention.",
"Име", "TITLE_2": "Enterprise P1",
"Описание", "DESC_2": "Issues raised by enterprise customers, that needs to be acknowledged quickly."
"FRT", },
"NRT", "BUSINESS_HOURS_ON": "Business hours on",
"RT", "BUSINESS_HOURS_OFF": "Business hours off",
"Business Hours" "RESPONSE_TYPES": {
] "FRT": "First response time threshold",
"NRT": "Next response time threshold",
"RT": "Resolution time threshold",
"SHORT_HAND": {
"FRT": "FRT",
"NRT": "NRT",
"RT": "RT"
}
}
}, },
"FORM": { "FORM": {
"NAME": { "NAME": {
@@ -56,18 +65,32 @@
}, },
"ADD": { "ADD": {
"TITLE": "Add SLA", "TITLE": "Add SLA",
"DESC": "SLAs: Friendly promises for great service!", "DESC": "Friendly promises for great service!",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA added successfully", "SUCCESS_MESSAGE": "SLA added successfully",
"ERROR_MESSAGE": "Възникна грешка, моля опитайте отново" "ERROR_MESSAGE": "Възникна грешка, моля опитайте отново"
} }
}, },
"EDIT": { "DELETE": {
"TITLE": "Edit SLA", "TITLE": "Delete SLA",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA updated successfully", "SUCCESS_MESSAGE": "SLA deleted successfully",
"ERROR_MESSAGE": "Възникна грешка, моля опитайте отново" "ERROR_MESSAGE": "Възникна грешка, моля опитайте отново"
},
"CONFIRM": {
"TITLE": "Потвърди изтриването",
"MESSAGE": "Are you sure you want to delete ",
"YES": "Да, изтрий ",
"NO": "Не, запази "
} }
},
"EVENTS": {
"TITLE": "SLA Misses",
"FRT": "First response time",
"NRT": "Next response time",
"RT": "Resolution time",
"SHOW_MORE": "{count} more",
"HIDE": "Hide {count} rows"
} }
} }
} }
@@ -296,6 +296,8 @@
"BUTTON": "Add custom attribute", "BUTTON": "Add custom attribute",
"NOT_AVAILABLE": "There are no custom attributes available for this contact.", "NOT_AVAILABLE": "There are no custom attributes available for this contact.",
"COPY_SUCCESSFUL": "S'ha copiat al porta-retalls amb èxit", "COPY_SUCCESSFUL": "S'ha copiat al porta-retalls amb èxit",
"SHOW_MORE": "Show all attributes",
"SHOW_LESS": "Show less attributes",
"ACTIONS": { "ACTIONS": {
"COPY": "Copy attribute", "COPY": "Copy attribute",
"DELETE": "Delete attribute", "DELETE": "Delete attribute",
@@ -44,7 +44,8 @@
"CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox", "CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox",
"CREATED_AT": "Created At", "CREATED_AT": "Created At",
"LAST_ACTIVITY": "Last Activity", "LAST_ACTIVITY": "Last Activity",
"REFERER_LINK": "Referrer link" "REFERER_LINK": "Referrer link",
"BLOCKED": "Blocked"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "Standard Filters", "STANDARD_FILTERS": "Standard Filters",
@@ -64,7 +64,14 @@
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow", "SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow",
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week", "SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week",
"SNOOZED_UNTIL_NEXT_REPLY": "Snoozed until next reply" "SNOOZED_UNTIL_NEXT_REPLY": "Snoozed until next reply",
"SLA_STATUS": {
"FRT": "FRT {status}",
"NRT": "NRT {status}",
"RT": "RT {status}",
"MISSED": "missed",
"DUE": "due"
}
}, },
"RESOLVE_DROPDOWN": { "RESOLVE_DROPDOWN": {
"MARK_PENDING": "Mark as pending", "MARK_PENDING": "Mark as pending",
@@ -0,0 +1,5 @@
{
"GENERAL": {
"SHOWING_RESULTS": "Showing {firstIndex}-{lastIndex} of {totalCount} items"
}
}
@@ -87,7 +87,10 @@
"conversation_assignment": "Conversació Assignada", "conversation_assignment": "Conversació Assignada",
"assigned_conversation_new_message": "Missatge Nou", "assigned_conversation_new_message": "Missatge Nou",
"participating_conversation_new_message": "Missatge Nou", "participating_conversation_new_message": "Missatge Nou",
"conversation_mention": "Menció" "conversation_mention": "Menció",
"sla_missed_first_response": "SLA Missed",
"sla_missed_next_response": "SLA Missed",
"sla_missed_resolution": "SLA Missed"
} }
}, },
"NETWORK": { "NETWORK": {
@@ -4,24 +4,28 @@
"TITLE": "Inbox", "TITLE": "Inbox",
"DISPLAY_DROPDOWN": "Display", "DISPLAY_DROPDOWN": "Display",
"LOADING": "Fetching notifications", "LOADING": "Fetching notifications",
"EOF": "S'han carregat totes les notificacions 🎉",
"404": "There are no active notifications in this group.", "404": "There are no active notifications in this group.",
"NO_NOTIFICATIONS": "No notifications", "NO_NOTIFICATIONS": "No notifications",
"NOTE": "Notifications from all subscribed inboxes", "NOTE": "Notifications from all subscribed inboxes",
"NO_MESSAGES_AVAILABLE": "Oops! Not able to fetch messages",
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow", "SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow",
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week" "SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week"
}, },
"ACTION_HEADER": { "ACTION_HEADER": {
"SNOOZE": "Snooze notification", "SNOOZE": "Snooze notification",
"DELETE": "Delete notification" "DELETE": "Delete notification",
"BACK": "Enrere"
}, },
"TYPES": { "TYPES": {
"CONVERSATION_MENTION": "You have been mentioned in a conversation", "CONVERSATION_MENTION": "You have been mentioned in a conversation",
"CONVERSATION_CREATION": "New conversation created", "CONVERSATION_CREATION": "New conversation created",
"CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you", "CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in",
"SLA_MISSED_FIRST_RESPONSE": "SLA target first response missed for conversation",
"SLA_MISSED_NEXT_RESPONSE": "SLA target next response missed for conversation",
"SLA_MISSED_RESOLUTION": "SLA target resolution missed for conversation"
}, },
"MENU_ITEM": { "MENU_ITEM": {
"MARK_AS_READ": "Mark as read", "MARK_AS_READ": "Mark as read",
@@ -35,6 +35,14 @@
"NAME": "Total de resolucions", "NAME": "Total de resolucions",
"DESC": "( Total )" "DESC": "( Total )"
}, },
"BOT_RESOLUTION_COUNT": {
"NAME": "Total de resolucions",
"DESC": "( Total )"
},
"BOT_HANDOFF_COUNT": {
"NAME": "Handoff Count",
"DESC": "( Total )"
},
"REPLY_TIME": { "REPLY_TIME": {
"NAME": "Customer waiting time", "NAME": "Customer waiting time",
"TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)" "TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)"
@@ -130,7 +138,11 @@
"groupBy": "Month" "groupBy": "Month"
} }
], ],
"BUSINESS_HOURS": "Business Hours" "BUSINESS_HOURS": "Business Hours",
"FILTER_ACTIONS": {
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "No s'ha trobat agents"
}
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "Agents Overview", "HEADER": "Agents Overview",
@@ -433,6 +445,27 @@
} }
} }
}, },
"BOT_REPORTS": {
"HEADER": "Bot Reports",
"METRIC": {
"TOTAL_CONVERSATIONS": {
"LABEL": "No. of Conversations",
"TOOLTIP": "Total number of conversations handled by the bot"
},
"TOTAL_RESPONSES": {
"LABEL": "Total Responses",
"TOOLTIP": "Total number of responses sent by the bot"
},
"RESOLUTION_RATE": {
"LABEL": "Resolution Rate",
"TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100"
},
"HANDOFF_RATE": {
"LABEL": "Handoff Rate",
"TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100"
}
}
},
"OVERVIEW_REPORTS": { "OVERVIEW_REPORTS": {
"HEADER": "Overview", "HEADER": "Overview",
"LIVE": "Live", "LIVE": "Live",
@@ -476,5 +509,54 @@
"THURSDAY": "Thursday", "THURSDAY": "Thursday",
"FRIDAY": "Friday", "FRIDAY": "Friday",
"SATURDAY": "Saturday" "SATURDAY": "Saturday"
},
"SLA_REPORTS": {
"HEADER": "SLA Reports",
"NO_RECORDS": "SLA applied conversations are not available.",
"LOADING": "Loading SLA data...",
"DOWNLOAD_SLA_REPORTS": "Download SLA reports",
"DOWNLOAD_FAILED": "Failed to download SLA Reports",
"DROPDOWN": {
"ADD_FIlTER": "Add filter",
"CLEAR_ALL": "Clear all",
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "No s'ha trobat agents",
"NO_FILTER": "No filters available",
"SEARCH": "Search filter",
"INPUT_PLACEHOLDER": {
"SLA": "SLA name",
"AGENTS": "Agent name",
"INBOXES": "Inbox name",
"LABELS": "Nom de l'etiqueta",
"TEAMS": "Team name"
},
"SLA": "SLA Policy",
"INBOXES": "Inbox",
"AGENTS": "Agent",
"LABELS": "Label",
"TEAMS": "Team"
},
"METRICS": {
"HIT_RATE": {
"LABEL": "Hit Rate",
"TOOLTIP": "Percentage of SLAs created were completed successfully"
},
"NO_OF_MISSES": {
"LABEL": "Number of Misses",
"TOOLTIP": "Total SLA misses in a certain period"
},
"NO_OF_CONVERSATIONS": {
"LABEL": "Number of Conversations",
"TOOLTIP": "Total number of conversations with SLA"
}
},
"TABLE": {
"HEADER": {
"POLICY": "Policy",
"CONVERSATION": "Conversation",
"AGENT": "Agent"
},
"VIEW_DETAILS": "View Details"
}
} }
} }
@@ -83,7 +83,10 @@
"CONVERSATION_CREATION": "Envieu notificacions per correu electrònic quan es crea una nova conversa", "CONVERSATION_CREATION": "Envieu notificacions per correu electrònic quan es crea una nova conversa",
"CONVERSATION_MENTION": "Enviar notificacions per mail quan siguis esmentat en una conversació", "CONVERSATION_MENTION": "Enviar notificacions per mail quan siguis esmentat en una conversació",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Envia notificacions per correu electrònic quan es creï un missatge nou en una conversa assignada", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Envia notificacions per correu electrònic quan es creï un missatge nou en una conversa assignada",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in a participating conversation" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in a participating conversation",
"SLA_MISSED_FIRST_RESPONSE": "Send email notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send email notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send email notifications when a conversation misses resolution SLA"
}, },
"API": { "API": {
"UPDATE_SUCCESS": "Les teves preferències de notificació s’han actualitzat correctament", "UPDATE_SUCCESS": "Les teves preferències de notificació s’han actualitzat correctament",
@@ -98,7 +101,10 @@
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Envia notificacions automàtiques quan es creï un missatge nou en una conversa assignada", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Envia notificacions automàtiques quan es creï un missatge nou en una conversa assignada",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in a participating conversation", "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in a participating conversation",
"HAS_ENABLED_PUSH": "Heu activat les notificacions per a aquest navegador.", "HAS_ENABLED_PUSH": "Heu activat les notificacions per a aquest navegador.",
"REQUEST_PUSH": "Activa les notificacions" "REQUEST_PUSH": "Activa les notificacions",
"SLA_MISSED_FIRST_RESPONSE": "Send push notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send push notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send push notifications when a conversation misses resolution SLA"
}, },
"PROFILE_IMAGE": { "PROFILE_IMAGE": {
"LABEL": "Imatge del Perfil" "LABEL": "Imatge del Perfil"
@@ -199,6 +205,7 @@
"SIDEBAR": { "SIDEBAR": {
"CURRENTLY_VIEWING_ACCOUNT": "Currently viewing:", "CURRENTLY_VIEWING_ACCOUNT": "Currently viewing:",
"SWITCH": "Switch", "SWITCH": "Switch",
"INBOX_VIEW": "Inbox View",
"CONVERSATIONS": "Converses", "CONVERSATIONS": "Converses",
"INBOX": "Inbox", "INBOX": "Inbox",
"ALL_CONVERSATIONS": "All Conversations", "ALL_CONVERSATIONS": "All Conversations",
@@ -237,6 +244,8 @@
"CAMPAIGNS": "Campaigns", "CAMPAIGNS": "Campaigns",
"ONGOING": "Ongoing", "ONGOING": "Ongoing",
"ONE_OFF": "One off", "ONE_OFF": "One off",
"REPORTS_SLA": "SLA",
"REPORTS_BOT": "Bot",
"REPORTS_AGENT": "Agents", "REPORTS_AGENT": "Agents",
"REPORTS_LABEL": "Etiquetes", "REPORTS_LABEL": "Etiquetes",
"REPORTS_INBOX": "Inbox", "REPORTS_INBOX": "Inbox",
@@ -1,22 +1,31 @@
{ {
"SLA": { "SLA": {
"HEADER": "SLA", "HEADER": "SLA",
"HEADER_BTN_TXT": "Add SLA", "ADD_ACTION": "Add SLA",
"ADD_ACTION_LONG": "Create a new SLA Policy",
"DESCRIPTION": "Service Level Agreements (SLAs) are contracts that define clear expectations between your team and customers. They establish standards for response and resolution times, creating a framework for accountability and ensures a consistent, high-quality experience.",
"LEARN_MORE": "Learn more about SLA",
"LOADING": "Fetching SLAs", "LOADING": "Fetching SLAs",
"SEARCH_404": "No hi ha articles que coincideixin amb aquesta consulta",
"SIDEBAR_TXT": "<p><b>SLA</b> <p>Think of Service Level Agreements (SLAs) like friendly promises between a service provider and a customer.</p> <p> These promises set clear expectations for things like how quickly the team will respond to issues, making sure you always get a reliable and top-notch experience!</p>",
"LIST": { "LIST": {
"404": "There are no SLAs available in this account.", "404": "There are no SLAs available in this account.",
"TITLE": "Manage SLA", "EMPTY": {
"DESC": "SLAs: Friendly promises for great service!", "TITLE_1": "Enterprise P0",
"TABLE_HEADER": [ "DESC_1": "Issues raised by enterprise customers, that require immediate attention.",
"Nom", "TITLE_2": "Enterprise P1",
"Descripció", "DESC_2": "Issues raised by enterprise customers, that needs to be acknowledged quickly."
"FRT", },
"NRT", "BUSINESS_HOURS_ON": "Business hours on",
"RT", "BUSINESS_HOURS_OFF": "Business hours off",
"Business Hours" "RESPONSE_TYPES": {
] "FRT": "First response time threshold",
"NRT": "Next response time threshold",
"RT": "Resolution time threshold",
"SHORT_HAND": {
"FRT": "FRT",
"NRT": "NRT",
"RT": "RT"
}
}
}, },
"FORM": { "FORM": {
"NAME": { "NAME": {
@@ -56,18 +65,32 @@
}, },
"ADD": { "ADD": {
"TITLE": "Add SLA", "TITLE": "Add SLA",
"DESC": "SLAs: Friendly promises for great service!", "DESC": "Friendly promises for great service!",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA added successfully", "SUCCESS_MESSAGE": "SLA added successfully",
"ERROR_MESSAGE": "S'ha produït un error; tornau-ho a provar" "ERROR_MESSAGE": "S'ha produït un error; tornau-ho a provar"
} }
}, },
"EDIT": { "DELETE": {
"TITLE": "Edit SLA", "TITLE": "Delete SLA",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA updated successfully", "SUCCESS_MESSAGE": "SLA deleted successfully",
"ERROR_MESSAGE": "S'ha produït un error; tornau-ho a provar" "ERROR_MESSAGE": "S'ha produït un error; tornau-ho a provar"
},
"CONFIRM": {
"TITLE": "Confirma l'esborrat",
"MESSAGE": "Are you sure you want to delete ",
"YES": "Si, esborra ",
"NO": "No, segueix "
} }
},
"EVENTS": {
"TITLE": "SLA Misses",
"FRT": "Primer temps de resposta",
"NRT": "Next response time",
"RT": "Resolution time",
"SHOW_MORE": "{count} more",
"HIDE": "Hide {count} rows"
} }
} }
} }
@@ -296,6 +296,8 @@
"BUTTON": "Add custom attribute", "BUTTON": "Add custom attribute",
"NOT_AVAILABLE": "There are no custom attributes available for this contact.", "NOT_AVAILABLE": "There are no custom attributes available for this contact.",
"COPY_SUCCESSFUL": "Úspěšně zkopírováno do schránky", "COPY_SUCCESSFUL": "Úspěšně zkopírováno do schránky",
"SHOW_MORE": "Show all attributes",
"SHOW_LESS": "Show less attributes",
"ACTIONS": { "ACTIONS": {
"COPY": "Copy attribute", "COPY": "Copy attribute",
"DELETE": "Delete attribute", "DELETE": "Delete attribute",
@@ -44,7 +44,8 @@
"CUSTOM_ATTRIBUTE_CHECKBOX": "Zaškrtávací pole", "CUSTOM_ATTRIBUTE_CHECKBOX": "Zaškrtávací pole",
"CREATED_AT": "Vytvořeno", "CREATED_AT": "Vytvořeno",
"LAST_ACTIVITY": "Poslední aktivita", "LAST_ACTIVITY": "Poslední aktivita",
"REFERER_LINK": "Odkazující odkaz" "REFERER_LINK": "Odkazující odkaz",
"BLOCKED": "Blocked"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "Standardní filtry", "STANDARD_FILTERS": "Standardní filtry",
@@ -64,7 +64,14 @@
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "Odloženo do zítřka", "SNOOZED_UNTIL_TOMORROW": "Odloženo do zítřka",
"SNOOZED_UNTIL_NEXT_WEEK": "Odloženo do příštího týdne", "SNOOZED_UNTIL_NEXT_WEEK": "Odloženo do příštího týdne",
"SNOOZED_UNTIL_NEXT_REPLY": "Odloženo do další odpovědi" "SNOOZED_UNTIL_NEXT_REPLY": "Odloženo do další odpovědi",
"SLA_STATUS": {
"FRT": "FRT {status}",
"NRT": "NRT {status}",
"RT": "RT {status}",
"MISSED": "missed",
"DUE": "due"
}
}, },
"RESOLVE_DROPDOWN": { "RESOLVE_DROPDOWN": {
"MARK_PENDING": "Označit jako nevyřízené", "MARK_PENDING": "Označit jako nevyřízené",
@@ -0,0 +1,5 @@
{
"GENERAL": {
"SHOWING_RESULTS": "Showing {firstIndex}-{lastIndex} of {totalCount} items"
}
}
@@ -87,7 +87,10 @@
"conversation_assignment": "Přiřazená konverzace", "conversation_assignment": "Přiřazená konverzace",
"assigned_conversation_new_message": "Nová zpráva", "assigned_conversation_new_message": "Nová zpráva",
"participating_conversation_new_message": "Nová zpráva", "participating_conversation_new_message": "Nová zpráva",
"conversation_mention": "Zmínka" "conversation_mention": "Zmínka",
"sla_missed_first_response": "SLA Missed",
"sla_missed_next_response": "SLA Missed",
"sla_missed_resolution": "SLA Missed"
} }
}, },
"NETWORK": { "NETWORK": {
@@ -4,24 +4,28 @@
"TITLE": "Inbox", "TITLE": "Inbox",
"DISPLAY_DROPDOWN": "Display", "DISPLAY_DROPDOWN": "Display",
"LOADING": "Fetching notifications", "LOADING": "Fetching notifications",
"EOF": "All notifications loaded 🎉",
"404": "There are no active notifications in this group.", "404": "There are no active notifications in this group.",
"NO_NOTIFICATIONS": "No notifications", "NO_NOTIFICATIONS": "No notifications",
"NOTE": "Notifications from all subscribed inboxes", "NOTE": "Notifications from all subscribed inboxes",
"NO_MESSAGES_AVAILABLE": "Oops! Not able to fetch messages",
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "Odloženo do zítřka", "SNOOZED_UNTIL_TOMORROW": "Odloženo do zítřka",
"SNOOZED_UNTIL_NEXT_WEEK": "Odloženo do příštího týdne" "SNOOZED_UNTIL_NEXT_WEEK": "Odloženo do příštího týdne"
}, },
"ACTION_HEADER": { "ACTION_HEADER": {
"SNOOZE": "Snooze notification", "SNOOZE": "Snooze notification",
"DELETE": "Delete notification" "DELETE": "Delete notification",
"BACK": "Zpět"
}, },
"TYPES": { "TYPES": {
"CONVERSATION_MENTION": "You have been mentioned in a conversation", "CONVERSATION_MENTION": "You have been mentioned in a conversation",
"CONVERSATION_CREATION": "New conversation created", "CONVERSATION_CREATION": "New conversation created",
"CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you", "CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in",
"SLA_MISSED_FIRST_RESPONSE": "SLA target first response missed for conversation",
"SLA_MISSED_NEXT_RESPONSE": "SLA target next response missed for conversation",
"SLA_MISSED_RESOLUTION": "SLA target resolution missed for conversation"
}, },
"MENU_ITEM": { "MENU_ITEM": {
"MARK_AS_READ": "Mark as read", "MARK_AS_READ": "Mark as read",
@@ -35,6 +35,14 @@
"NAME": "Počet rozlišení", "NAME": "Počet rozlišení",
"DESC": "( celkem)" "DESC": "( celkem)"
}, },
"BOT_RESOLUTION_COUNT": {
"NAME": "Počet rozlišení",
"DESC": "( celkem)"
},
"BOT_HANDOFF_COUNT": {
"NAME": "Handoff Count",
"DESC": "( celkem)"
},
"REPLY_TIME": { "REPLY_TIME": {
"NAME": "Customer waiting time", "NAME": "Customer waiting time",
"TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)" "TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)"
@@ -130,7 +138,11 @@
"groupBy": "Měsíc" "groupBy": "Měsíc"
} }
], ],
"BUSINESS_HOURS": "Pracovní doba" "BUSINESS_HOURS": "Pracovní doba",
"FILTER_ACTIONS": {
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "Žádné výsledky"
}
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "Agents Overview", "HEADER": "Agents Overview",
@@ -433,6 +445,27 @@
} }
} }
}, },
"BOT_REPORTS": {
"HEADER": "Bot Reports",
"METRIC": {
"TOTAL_CONVERSATIONS": {
"LABEL": "No. of Conversations",
"TOOLTIP": "Total number of conversations handled by the bot"
},
"TOTAL_RESPONSES": {
"LABEL": "Total Responses",
"TOOLTIP": "Total number of responses sent by the bot"
},
"RESOLUTION_RATE": {
"LABEL": "Resolution Rate",
"TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100"
},
"HANDOFF_RATE": {
"LABEL": "Handoff Rate",
"TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100"
}
}
},
"OVERVIEW_REPORTS": { "OVERVIEW_REPORTS": {
"HEADER": "Overview", "HEADER": "Overview",
"LIVE": "Live", "LIVE": "Live",
@@ -476,5 +509,54 @@
"THURSDAY": "Thursday", "THURSDAY": "Thursday",
"FRIDAY": "Friday", "FRIDAY": "Friday",
"SATURDAY": "Saturday" "SATURDAY": "Saturday"
},
"SLA_REPORTS": {
"HEADER": "SLA Reports",
"NO_RECORDS": "SLA applied conversations are not available.",
"LOADING": "Loading SLA data...",
"DOWNLOAD_SLA_REPORTS": "Download SLA reports",
"DOWNLOAD_FAILED": "Failed to download SLA Reports",
"DROPDOWN": {
"ADD_FIlTER": "Add filter",
"CLEAR_ALL": "Clear all",
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "Žádné výsledky",
"NO_FILTER": "No filters available",
"SEARCH": "Search filter",
"INPUT_PLACEHOLDER": {
"SLA": "SLA name",
"AGENTS": "Jméno agenta",
"INBOXES": "Inbox name",
"LABELS": "Label name",
"TEAMS": "Team name"
},
"SLA": "SLA Policy",
"INBOXES": "Inbox",
"AGENTS": "Agent",
"LABELS": "Label",
"TEAMS": "Team"
},
"METRICS": {
"HIT_RATE": {
"LABEL": "Hit Rate",
"TOOLTIP": "Percentage of SLAs created were completed successfully"
},
"NO_OF_MISSES": {
"LABEL": "Number of Misses",
"TOOLTIP": "Total SLA misses in a certain period"
},
"NO_OF_CONVERSATIONS": {
"LABEL": "Number of Conversations",
"TOOLTIP": "Total number of conversations with SLA"
}
},
"TABLE": {
"HEADER": {
"POLICY": "Policy",
"CONVERSATION": "Conversation",
"AGENT": "Agent"
},
"VIEW_DETAILS": "View Details"
}
} }
} }
@@ -83,7 +83,10 @@
"CONVERSATION_CREATION": "Odeslat oznámení e-mailem při vytváření nové konverzace", "CONVERSATION_CREATION": "Odeslat oznámení e-mailem při vytváření nové konverzace",
"CONVERSATION_MENTION": "Odeslat oznámení e-mailem, pokud jste zmíněni v konverzaci", "CONVERSATION_MENTION": "Odeslat oznámení e-mailem, pokud jste zmíněni v konverzaci",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Odeslat oznámení e-mailem, když je nová zpráva vytvořena v přiřazené konverzaci", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Odeslat oznámení e-mailem, když je nová zpráva vytvořena v přiřazené konverzaci",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in a participating conversation" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in a participating conversation",
"SLA_MISSED_FIRST_RESPONSE": "Send email notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send email notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send email notifications when a conversation misses resolution SLA"
}, },
"API": { "API": {
"UPDATE_SUCCESS": "Vaše předvolby oznámení byly úspěšně aktualizovány", "UPDATE_SUCCESS": "Vaše předvolby oznámení byly úspěšně aktualizovány",
@@ -98,7 +101,10 @@
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Odeslat push oznámení, když je nová zpráva vytvořena v přiřazené konverzaci", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Odeslat push oznámení, když je nová zpráva vytvořena v přiřazené konverzaci",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in a participating conversation", "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in a participating conversation",
"HAS_ENABLED_PUSH": "Povolili jste push pro tento prohlížeč.", "HAS_ENABLED_PUSH": "Povolili jste push pro tento prohlížeč.",
"REQUEST_PUSH": "Povolit push oznámení" "REQUEST_PUSH": "Povolit push oznámení",
"SLA_MISSED_FIRST_RESPONSE": "Send push notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send push notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send push notifications when a conversation misses resolution SLA"
}, },
"PROFILE_IMAGE": { "PROFILE_IMAGE": {
"LABEL": "Profil obrázek" "LABEL": "Profil obrázek"
@@ -199,6 +205,7 @@
"SIDEBAR": { "SIDEBAR": {
"CURRENTLY_VIEWING_ACCOUNT": "Currently viewing:", "CURRENTLY_VIEWING_ACCOUNT": "Currently viewing:",
"SWITCH": "Switch", "SWITCH": "Switch",
"INBOX_VIEW": "Inbox View",
"CONVERSATIONS": "Konverzace", "CONVERSATIONS": "Konverzace",
"INBOX": "Inbox", "INBOX": "Inbox",
"ALL_CONVERSATIONS": "All Conversations", "ALL_CONVERSATIONS": "All Conversations",
@@ -237,6 +244,8 @@
"CAMPAIGNS": "Kampaně", "CAMPAIGNS": "Kampaně",
"ONGOING": "Ongoing", "ONGOING": "Ongoing",
"ONE_OFF": "One off", "ONE_OFF": "One off",
"REPORTS_SLA": "SLA",
"REPORTS_BOT": "Bot",
"REPORTS_AGENT": "Agenti", "REPORTS_AGENT": "Agenti",
"REPORTS_LABEL": "Štítky", "REPORTS_LABEL": "Štítky",
"REPORTS_INBOX": "Inbox", "REPORTS_INBOX": "Inbox",
@@ -1,22 +1,31 @@
{ {
"SLA": { "SLA": {
"HEADER": "SLA", "HEADER": "SLA",
"HEADER_BTN_TXT": "Add SLA", "ADD_ACTION": "Add SLA",
"ADD_ACTION_LONG": "Create a new SLA Policy",
"DESCRIPTION": "Service Level Agreements (SLAs) are contracts that define clear expectations between your team and customers. They establish standards for response and resolution times, creating a framework for accountability and ensures a consistent, high-quality experience.",
"LEARN_MORE": "Learn more about SLA",
"LOADING": "Fetching SLAs", "LOADING": "Fetching SLAs",
"SEARCH_404": "Neexistují žádné položky odpovídající tomuto dotazu",
"SIDEBAR_TXT": "<p><b>SLA</b> <p>Think of Service Level Agreements (SLAs) like friendly promises between a service provider and a customer.</p> <p> These promises set clear expectations for things like how quickly the team will respond to issues, making sure you always get a reliable and top-notch experience!</p>",
"LIST": { "LIST": {
"404": "There are no SLAs available in this account.", "404": "There are no SLAs available in this account.",
"TITLE": "Manage SLA", "EMPTY": {
"DESC": "SLAs: Friendly promises for great service!", "TITLE_1": "Enterprise P0",
"TABLE_HEADER": [ "DESC_1": "Issues raised by enterprise customers, that require immediate attention.",
"Název", "TITLE_2": "Enterprise P1",
"Description", "DESC_2": "Issues raised by enterprise customers, that needs to be acknowledged quickly."
"FRT", },
"NRT", "BUSINESS_HOURS_ON": "Business hours on",
"RT", "BUSINESS_HOURS_OFF": "Business hours off",
"Pracovní doba" "RESPONSE_TYPES": {
] "FRT": "First response time threshold",
"NRT": "Next response time threshold",
"RT": "Resolution time threshold",
"SHORT_HAND": {
"FRT": "FRT",
"NRT": "NRT",
"RT": "RT"
}
}
}, },
"FORM": { "FORM": {
"NAME": { "NAME": {
@@ -56,18 +65,32 @@
}, },
"ADD": { "ADD": {
"TITLE": "Add SLA", "TITLE": "Add SLA",
"DESC": "SLAs: Friendly promises for great service!", "DESC": "Friendly promises for great service!",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA added successfully", "SUCCESS_MESSAGE": "SLA added successfully",
"ERROR_MESSAGE": "Došlo k chybě, zkuste to prosím znovu" "ERROR_MESSAGE": "Došlo k chybě, zkuste to prosím znovu"
} }
}, },
"EDIT": { "DELETE": {
"TITLE": "Edit SLA", "TITLE": "Delete SLA",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA updated successfully", "SUCCESS_MESSAGE": "SLA deleted successfully",
"ERROR_MESSAGE": "Došlo k chybě, zkuste to prosím znovu" "ERROR_MESSAGE": "Došlo k chybě, zkuste to prosím znovu"
},
"CONFIRM": {
"TITLE": "Potvrdit odstranění",
"MESSAGE": "Are you sure you want to delete ",
"YES": "Ano, odstranit ",
"NO": "Ne, zachovat "
} }
},
"EVENTS": {
"TITLE": "SLA Misses",
"FRT": "Čas první odpovědi",
"NRT": "Next response time",
"RT": "Resolution time",
"SHOW_MORE": "{count} more",
"HIDE": "Hide {count} rows"
} }
} }
} }
@@ -296,6 +296,8 @@
"BUTTON": "Tilføj brugerdefineret attribut", "BUTTON": "Tilføj brugerdefineret attribut",
"NOT_AVAILABLE": "Der er ingen brugerdefinerede attributter tilgængelige for denne kontakt.", "NOT_AVAILABLE": "Der er ingen brugerdefinerede attributter tilgængelige for denne kontakt.",
"COPY_SUCCESSFUL": "Kopiering til udklipsholder lykkedes", "COPY_SUCCESSFUL": "Kopiering til udklipsholder lykkedes",
"SHOW_MORE": "Show all attributes",
"SHOW_LESS": "Show less attributes",
"ACTIONS": { "ACTIONS": {
"COPY": "Kopier attribut", "COPY": "Kopier attribut",
"DELETE": "Slet egenskab", "DELETE": "Slet egenskab",
@@ -44,7 +44,8 @@
"CUSTOM_ATTRIBUTE_CHECKBOX": "Afkrydsningsfelt", "CUSTOM_ATTRIBUTE_CHECKBOX": "Afkrydsningsfelt",
"CREATED_AT": "Oprettet Den", "CREATED_AT": "Oprettet Den",
"LAST_ACTIVITY": "Sidste Aktivitet", "LAST_ACTIVITY": "Sidste Aktivitet",
"REFERER_LINK": "Link til reference" "REFERER_LINK": "Link til reference",
"BLOCKED": "Blocked"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "Standard Filtre", "STANDARD_FILTERS": "Standard Filtre",
@@ -64,7 +64,14 @@
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "Udsat til i morgen", "SNOOZED_UNTIL_TOMORROW": "Udsat til i morgen",
"SNOOZED_UNTIL_NEXT_WEEK": "Udsat indtil næste uge", "SNOOZED_UNTIL_NEXT_WEEK": "Udsat indtil næste uge",
"SNOOZED_UNTIL_NEXT_REPLY": "Udsat indtil næste svar" "SNOOZED_UNTIL_NEXT_REPLY": "Udsat indtil næste svar",
"SLA_STATUS": {
"FRT": "FRT {status}",
"NRT": "NRT {status}",
"RT": "RT {status}",
"MISSED": "missed",
"DUE": "due"
}
}, },
"RESOLVE_DROPDOWN": { "RESOLVE_DROPDOWN": {
"MARK_PENDING": "Markér som afventende", "MARK_PENDING": "Markér som afventende",
@@ -0,0 +1,5 @@
{
"GENERAL": {
"SHOWING_RESULTS": "Showing {firstIndex}-{lastIndex} of {totalCount} items"
}
}
@@ -87,7 +87,10 @@
"conversation_assignment": "Samtale Tildelt", "conversation_assignment": "Samtale Tildelt",
"assigned_conversation_new_message": "Ny Besked", "assigned_conversation_new_message": "Ny Besked",
"participating_conversation_new_message": "Ny Besked", "participating_conversation_new_message": "Ny Besked",
"conversation_mention": "Omtale" "conversation_mention": "Omtale",
"sla_missed_first_response": "SLA Missed",
"sla_missed_next_response": "SLA Missed",
"sla_missed_resolution": "SLA Missed"
} }
}, },
"NETWORK": { "NETWORK": {
@@ -4,24 +4,28 @@
"TITLE": "Indbakke", "TITLE": "Indbakke",
"DISPLAY_DROPDOWN": "Display", "DISPLAY_DROPDOWN": "Display",
"LOADING": "Fetching notifications", "LOADING": "Fetching notifications",
"EOF": "All notifications loaded 🎉",
"404": "There are no active notifications in this group.", "404": "There are no active notifications in this group.",
"NO_NOTIFICATIONS": "No notifications", "NO_NOTIFICATIONS": "No notifications",
"NOTE": "Notifications from all subscribed inboxes", "NOTE": "Notifications from all subscribed inboxes",
"NO_MESSAGES_AVAILABLE": "Oops! Not able to fetch messages",
"SNOOZED_UNTIL": "Snoozed until", "SNOOZED_UNTIL": "Snoozed until",
"SNOOZED_UNTIL_TOMORROW": "Udsat til i morgen", "SNOOZED_UNTIL_TOMORROW": "Udsat til i morgen",
"SNOOZED_UNTIL_NEXT_WEEK": "Udsat indtil næste uge" "SNOOZED_UNTIL_NEXT_WEEK": "Udsat indtil næste uge"
}, },
"ACTION_HEADER": { "ACTION_HEADER": {
"SNOOZE": "Snooze notification", "SNOOZE": "Snooze notification",
"DELETE": "Delete notification" "DELETE": "Delete notification",
"BACK": "Tilbage"
}, },
"TYPES": { "TYPES": {
"CONVERSATION_MENTION": "You have been mentioned in a conversation", "CONVERSATION_MENTION": "You have been mentioned in a conversation",
"CONVERSATION_CREATION": "New conversation created", "CONVERSATION_CREATION": "New conversation created",
"CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you", "CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in",
"SLA_MISSED_FIRST_RESPONSE": "SLA target first response missed for conversation",
"SLA_MISSED_NEXT_RESPONSE": "SLA target next response missed for conversation",
"SLA_MISSED_RESOLUTION": "SLA target resolution missed for conversation"
}, },
"MENU_ITEM": { "MENU_ITEM": {
"MARK_AS_READ": "Mark as read", "MARK_AS_READ": "Mark as read",
@@ -35,6 +35,14 @@
"NAME": "Antal Afsluttede", "NAME": "Antal Afsluttede",
"DESC": "( Total )" "DESC": "( Total )"
}, },
"BOT_RESOLUTION_COUNT": {
"NAME": "Antal Afsluttede",
"DESC": "( Total )"
},
"BOT_HANDOFF_COUNT": {
"NAME": "Handoff Count",
"DESC": "( Total )"
},
"REPLY_TIME": { "REPLY_TIME": {
"NAME": "Customer waiting time", "NAME": "Customer waiting time",
"TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)" "TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)"
@@ -130,7 +138,11 @@
"groupBy": "Måned" "groupBy": "Måned"
} }
], ],
"BUSINESS_HOURS": "Forretningstider" "BUSINESS_HOURS": "Forretningstider",
"FILTER_ACTIONS": {
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "Ingen resultater fundet"
}
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "Agenter Oversigt", "HEADER": "Agenter Oversigt",
@@ -433,6 +445,27 @@
} }
} }
}, },
"BOT_REPORTS": {
"HEADER": "Bot Reports",
"METRIC": {
"TOTAL_CONVERSATIONS": {
"LABEL": "No. of Conversations",
"TOOLTIP": "Total number of conversations handled by the bot"
},
"TOTAL_RESPONSES": {
"LABEL": "Total Responses",
"TOOLTIP": "Total number of responses sent by the bot"
},
"RESOLUTION_RATE": {
"LABEL": "Resolution Rate",
"TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100"
},
"HANDOFF_RATE": {
"LABEL": "Handoff Rate",
"TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100"
}
}
},
"OVERVIEW_REPORTS": { "OVERVIEW_REPORTS": {
"HEADER": "Oversigt", "HEADER": "Oversigt",
"LIVE": "Levende", "LIVE": "Levende",
@@ -476,5 +509,54 @@
"THURSDAY": "Thursday", "THURSDAY": "Thursday",
"FRIDAY": "Friday", "FRIDAY": "Friday",
"SATURDAY": "Saturday" "SATURDAY": "Saturday"
},
"SLA_REPORTS": {
"HEADER": "SLA Reports",
"NO_RECORDS": "SLA applied conversations are not available.",
"LOADING": "Loading SLA data...",
"DOWNLOAD_SLA_REPORTS": "Download SLA reports",
"DOWNLOAD_FAILED": "Failed to download SLA Reports",
"DROPDOWN": {
"ADD_FIlTER": "Add filter",
"CLEAR_ALL": "Clear all",
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "Ingen resultater fundet",
"NO_FILTER": "No filters available",
"SEARCH": "Search filter",
"INPUT_PLACEHOLDER": {
"SLA": "SLA name",
"AGENTS": "Agentens navn",
"INBOXES": "Indbakkens navn",
"LABELS": "Etiket Navn",
"TEAMS": "Team navn"
},
"SLA": "SLA Policy",
"INBOXES": "Indbakke",
"AGENTS": "Agent",
"LABELS": "Etiketter",
"TEAMS": "Team"
},
"METRICS": {
"HIT_RATE": {
"LABEL": "Hit Rate",
"TOOLTIP": "Percentage of SLAs created were completed successfully"
},
"NO_OF_MISSES": {
"LABEL": "Number of Misses",
"TOOLTIP": "Total SLA misses in a certain period"
},
"NO_OF_CONVERSATIONS": {
"LABEL": "Number of Conversations",
"TOOLTIP": "Total number of conversations with SLA"
}
},
"TABLE": {
"HEADER": {
"POLICY": "Policy",
"CONVERSATION": "Samtale",
"AGENT": "Agent"
},
"VIEW_DETAILS": "View Details"
}
} }
} }
@@ -83,7 +83,10 @@
"CONVERSATION_CREATION": "Send e-mail notifikationer når en ny samtale er oprettet", "CONVERSATION_CREATION": "Send e-mail notifikationer når en ny samtale er oprettet",
"CONVERSATION_MENTION": "Send e-mail notifikationer, når du er nævnt i en samtale", "CONVERSATION_MENTION": "Send e-mail notifikationer, når du er nævnt i en samtale",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send e-mail notifikationer når en ny besked er oprettet i en tildelt samtale", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send e-mail notifikationer når en ny besked er oprettet i en tildelt samtale",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in a participating conversation" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send email notifications when a new message is created in a participating conversation",
"SLA_MISSED_FIRST_RESPONSE": "Send email notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send email notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send email notifications when a conversation misses resolution SLA"
}, },
"API": { "API": {
"UPDATE_SUCCESS": "Dine notifikationsindstillinger er opdateret", "UPDATE_SUCCESS": "Dine notifikationsindstillinger er opdateret",
@@ -98,7 +101,10 @@
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send push-notifikationer, når en ny besked oprettes i en tildelt samtale", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Send push-notifikationer, når en ny besked oprettes i en tildelt samtale",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in a participating conversation", "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Send push notifications when a new message is created in a participating conversation",
"HAS_ENABLED_PUSH": "Du har aktiveret push for denne browser.", "HAS_ENABLED_PUSH": "Du har aktiveret push for denne browser.",
"REQUEST_PUSH": "Aktivér push-notifikationer" "REQUEST_PUSH": "Aktivér push-notifikationer",
"SLA_MISSED_FIRST_RESPONSE": "Send push notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send push notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send push notifications when a conversation misses resolution SLA"
}, },
"PROFILE_IMAGE": { "PROFILE_IMAGE": {
"LABEL": "Profilbillede" "LABEL": "Profilbillede"
@@ -199,6 +205,7 @@
"SIDEBAR": { "SIDEBAR": {
"CURRENTLY_VIEWING_ACCOUNT": "Vises nu:", "CURRENTLY_VIEWING_ACCOUNT": "Vises nu:",
"SWITCH": "Skift", "SWITCH": "Skift",
"INBOX_VIEW": "Inbox View",
"CONVERSATIONS": "Samtaler", "CONVERSATIONS": "Samtaler",
"INBOX": "Indbakke", "INBOX": "Indbakke",
"ALL_CONVERSATIONS": "Alle Samtaler", "ALL_CONVERSATIONS": "Alle Samtaler",
@@ -237,6 +244,8 @@
"CAMPAIGNS": "Kampagner", "CAMPAIGNS": "Kampagner",
"ONGOING": "Igangværende", "ONGOING": "Igangværende",
"ONE_OFF": "En rabat", "ONE_OFF": "En rabat",
"REPORTS_SLA": "SLA",
"REPORTS_BOT": "Bot",
"REPORTS_AGENT": "Agenter", "REPORTS_AGENT": "Agenter",
"REPORTS_LABEL": "Etiketter", "REPORTS_LABEL": "Etiketter",
"REPORTS_INBOX": "Indbakke", "REPORTS_INBOX": "Indbakke",
@@ -1,22 +1,31 @@
{ {
"SLA": { "SLA": {
"HEADER": "SLA", "HEADER": "SLA",
"HEADER_BTN_TXT": "Add SLA", "ADD_ACTION": "Add SLA",
"ADD_ACTION_LONG": "Create a new SLA Policy",
"DESCRIPTION": "Service Level Agreements (SLAs) are contracts that define clear expectations between your team and customers. They establish standards for response and resolution times, creating a framework for accountability and ensures a consistent, high-quality experience.",
"LEARN_MORE": "Learn more about SLA",
"LOADING": "Fetching SLAs", "LOADING": "Fetching SLAs",
"SEARCH_404": "Der er ingen elementer, der matcher denne forespørgsel",
"SIDEBAR_TXT": "<p><b>SLA</b> <p>Think of Service Level Agreements (SLAs) like friendly promises between a service provider and a customer.</p> <p> These promises set clear expectations for things like how quickly the team will respond to issues, making sure you always get a reliable and top-notch experience!</p>",
"LIST": { "LIST": {
"404": "There are no SLAs available in this account.", "404": "There are no SLAs available in this account.",
"TITLE": "Manage SLA", "EMPTY": {
"DESC": "SLAs: Friendly promises for great service!", "TITLE_1": "Enterprise P0",
"TABLE_HEADER": [ "DESC_1": "Issues raised by enterprise customers, that require immediate attention.",
"Navn", "TITLE_2": "Enterprise P1",
"Beskrivelse", "DESC_2": "Issues raised by enterprise customers, that needs to be acknowledged quickly."
"FRT", },
"NRT", "BUSINESS_HOURS_ON": "Business hours on",
"RT", "BUSINESS_HOURS_OFF": "Business hours off",
"Forretningstider" "RESPONSE_TYPES": {
] "FRT": "First response time threshold",
"NRT": "Next response time threshold",
"RT": "Resolution time threshold",
"SHORT_HAND": {
"FRT": "FRT",
"NRT": "NRT",
"RT": "RT"
}
}
}, },
"FORM": { "FORM": {
"NAME": { "NAME": {
@@ -56,18 +65,32 @@
}, },
"ADD": { "ADD": {
"TITLE": "Add SLA", "TITLE": "Add SLA",
"DESC": "SLAs: Friendly promises for great service!", "DESC": "Friendly promises for great service!",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA added successfully", "SUCCESS_MESSAGE": "SLA added successfully",
"ERROR_MESSAGE": "Der opstod en fejl. Prøv venligst igen" "ERROR_MESSAGE": "Der opstod en fejl. Prøv venligst igen"
} }
}, },
"EDIT": { "DELETE": {
"TITLE": "Edit SLA", "TITLE": "Delete SLA",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA updated successfully", "SUCCESS_MESSAGE": "SLA deleted successfully",
"ERROR_MESSAGE": "Der opstod en fejl. Prøv venligst igen" "ERROR_MESSAGE": "Der opstod en fejl. Prøv venligst igen"
},
"CONFIRM": {
"TITLE": "Bekræft Sletning",
"MESSAGE": "Are you sure you want to delete ",
"YES": "Ja, Slet ",
"NO": "Nej, Behold "
} }
},
"EVENTS": {
"TITLE": "SLA Misses",
"FRT": "Første svartid",
"NRT": "Next response time",
"RT": "Resolution time",
"SHOW_MORE": "{count} more",
"HIDE": "Hide {count} rows"
} }
} }
} }
@@ -296,6 +296,8 @@
"BUTTON": "Eigenes Attribut hinzufügen", "BUTTON": "Eigenes Attribut hinzufügen",
"NOT_AVAILABLE": "Für diesen Kontakt sind keine benutzerdefinierten Attribute verfügbar.", "NOT_AVAILABLE": "Für diesen Kontakt sind keine benutzerdefinierten Attribute verfügbar.",
"COPY_SUCCESSFUL": "Erfolgreich in die Zwischenablage kopiert", "COPY_SUCCESSFUL": "Erfolgreich in die Zwischenablage kopiert",
"SHOW_MORE": "Show all attributes",
"SHOW_LESS": "Show less attributes",
"ACTIONS": { "ACTIONS": {
"COPY": "Attribut kopieren", "COPY": "Attribut kopieren",
"DELETE": "Attribut löschen", "DELETE": "Attribut löschen",
@@ -44,7 +44,8 @@
"CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox", "CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox",
"CREATED_AT": "Erstellt am", "CREATED_AT": "Erstellt am",
"LAST_ACTIVITY": "Letzte Aktivität", "LAST_ACTIVITY": "Letzte Aktivität",
"REFERER_LINK": "Verweis-Link" "REFERER_LINK": "Verweis-Link",
"BLOCKED": "Blocked"
}, },
"GROUPS": { "GROUPS": {
"STANDARD_FILTERS": "Standardfilter", "STANDARD_FILTERS": "Standardfilter",
@@ -64,7 +64,14 @@
"SNOOZED_UNTIL": "Stummschalten bis", "SNOOZED_UNTIL": "Stummschalten bis",
"SNOOZED_UNTIL_TOMORROW": "Schlummern bis morgen", "SNOOZED_UNTIL_TOMORROW": "Schlummern bis morgen",
"SNOOZED_UNTIL_NEXT_WEEK": "Schlummern bis nächste Woche", "SNOOZED_UNTIL_NEXT_WEEK": "Schlummern bis nächste Woche",
"SNOOZED_UNTIL_NEXT_REPLY": "Schlummern bis zur nächsten Antwort" "SNOOZED_UNTIL_NEXT_REPLY": "Schlummern bis zur nächsten Antwort",
"SLA_STATUS": {
"FRT": "FRT {status}",
"NRT": "NRT {status}",
"RT": "RT {status}",
"MISSED": "missed",
"DUE": "due"
}
}, },
"RESOLVE_DROPDOWN": { "RESOLVE_DROPDOWN": {
"MARK_PENDING": "Als ausstehend markieren", "MARK_PENDING": "Als ausstehend markieren",
@@ -0,0 +1,5 @@
{
"GENERAL": {
"SHOWING_RESULTS": "Showing {firstIndex}-{lastIndex} of {totalCount} items"
}
}
@@ -87,7 +87,10 @@
"conversation_assignment": "Konversation zugewiesen", "conversation_assignment": "Konversation zugewiesen",
"assigned_conversation_new_message": "Neue Nachricht", "assigned_conversation_new_message": "Neue Nachricht",
"participating_conversation_new_message": "Neue Nachricht", "participating_conversation_new_message": "Neue Nachricht",
"conversation_mention": "Erwähnung" "conversation_mention": "Erwähnung",
"sla_missed_first_response": "SLA Missed",
"sla_missed_next_response": "SLA Missed",
"sla_missed_resolution": "SLA Missed"
} }
}, },
"NETWORK": { "NETWORK": {
@@ -4,24 +4,28 @@
"TITLE": "Posteingang", "TITLE": "Posteingang",
"DISPLAY_DROPDOWN": "Display", "DISPLAY_DROPDOWN": "Display",
"LOADING": "Fetching notifications", "LOADING": "Fetching notifications",
"EOF": "Alle Benachrichtigungen geladen 🎉",
"404": "There are no active notifications in this group.", "404": "There are no active notifications in this group.",
"NO_NOTIFICATIONS": "No notifications", "NO_NOTIFICATIONS": "No notifications",
"NOTE": "Notifications from all subscribed inboxes", "NOTE": "Notifications from all subscribed inboxes",
"NO_MESSAGES_AVAILABLE": "Oops! Not able to fetch messages",
"SNOOZED_UNTIL": "Stummschalten bis", "SNOOZED_UNTIL": "Stummschalten bis",
"SNOOZED_UNTIL_TOMORROW": "Schlummern bis morgen", "SNOOZED_UNTIL_TOMORROW": "Schlummern bis morgen",
"SNOOZED_UNTIL_NEXT_WEEK": "Schlummern bis nächste Woche" "SNOOZED_UNTIL_NEXT_WEEK": "Schlummern bis nächste Woche"
}, },
"ACTION_HEADER": { "ACTION_HEADER": {
"SNOOZE": "Snooze notification", "SNOOZE": "Snooze notification",
"DELETE": "Delete notification" "DELETE": "Delete notification",
"BACK": "Zurück"
}, },
"TYPES": { "TYPES": {
"CONVERSATION_MENTION": "You have been mentioned in a conversation", "CONVERSATION_MENTION": "You have been mentioned in a conversation",
"CONVERSATION_CREATION": "New conversation created", "CONVERSATION_CREATION": "New conversation created",
"CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you", "CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in",
"SLA_MISSED_FIRST_RESPONSE": "SLA target first response missed for conversation",
"SLA_MISSED_NEXT_RESPONSE": "SLA target next response missed for conversation",
"SLA_MISSED_RESOLUTION": "SLA target resolution missed for conversation"
}, },
"MENU_ITEM": { "MENU_ITEM": {
"MARK_AS_READ": "Mark as read", "MARK_AS_READ": "Mark as read",
@@ -35,6 +35,14 @@
"NAME": "Auflösungsanzahl", "NAME": "Auflösungsanzahl",
"DESC": "( Gesamt )" "DESC": "( Gesamt )"
}, },
"BOT_RESOLUTION_COUNT": {
"NAME": "Auflösungsanzahl",
"DESC": "( Gesamt )"
},
"BOT_HANDOFF_COUNT": {
"NAME": "Handoff Count",
"DESC": "( Gesamt )"
},
"REPLY_TIME": { "REPLY_TIME": {
"NAME": "Customer waiting time", "NAME": "Customer waiting time",
"TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)" "TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} replies)"
@@ -130,7 +138,11 @@
"groupBy": "Monat" "groupBy": "Monat"
} }
], ],
"BUSINESS_HOURS": "Öffnungszeiten" "BUSINESS_HOURS": "Öffnungszeiten",
"FILTER_ACTIONS": {
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "Keine Ergebnisse gefunden"
}
}, },
"AGENT_REPORTS": { "AGENT_REPORTS": {
"HEADER": "Agenten-Übersicht", "HEADER": "Agenten-Übersicht",
@@ -433,6 +445,27 @@
} }
} }
}, },
"BOT_REPORTS": {
"HEADER": "Bot Reports",
"METRIC": {
"TOTAL_CONVERSATIONS": {
"LABEL": "No. of Conversations",
"TOOLTIP": "Total number of conversations handled by the bot"
},
"TOTAL_RESPONSES": {
"LABEL": "Total Responses",
"TOOLTIP": "Total number of responses sent by the bot"
},
"RESOLUTION_RATE": {
"LABEL": "Resolution Rate",
"TOOLTIP": "Total number of conversations resolved by the bot / Total number of conversations handled by the bot * 100"
},
"HANDOFF_RATE": {
"LABEL": "Handoff Rate",
"TOOLTIP": "Total number of conversations handed off to agents / Total number of conversations handled by the bot * 100"
}
}
},
"OVERVIEW_REPORTS": { "OVERVIEW_REPORTS": {
"HEADER": "Übersicht", "HEADER": "Übersicht",
"LIVE": "Live", "LIVE": "Live",
@@ -476,5 +509,54 @@
"THURSDAY": "Thursday", "THURSDAY": "Thursday",
"FRIDAY": "Friday", "FRIDAY": "Friday",
"SATURDAY": "Saturday" "SATURDAY": "Saturday"
},
"SLA_REPORTS": {
"HEADER": "SLA Reports",
"NO_RECORDS": "SLA applied conversations are not available.",
"LOADING": "Loading SLA data...",
"DOWNLOAD_SLA_REPORTS": "Download SLA reports",
"DOWNLOAD_FAILED": "Failed to download SLA Reports",
"DROPDOWN": {
"ADD_FIlTER": "Add filter",
"CLEAR_ALL": "Clear all",
"CLEAR_FILTER": "Clear filter",
"EMPTY_LIST": "Keine Ergebnisse gefunden",
"NO_FILTER": "No filters available",
"SEARCH": "Search filter",
"INPUT_PLACEHOLDER": {
"SLA": "SLA name",
"AGENTS": "Agentenname",
"INBOXES": "Posteingangsname",
"LABELS": "Labelname",
"TEAMS": "Teamname"
},
"SLA": "SLA Policy",
"INBOXES": "Posteingang",
"AGENTS": "Agent",
"LABELS": "Label",
"TEAMS": "Team"
},
"METRICS": {
"HIT_RATE": {
"LABEL": "Hit Rate",
"TOOLTIP": "Percentage of SLAs created were completed successfully"
},
"NO_OF_MISSES": {
"LABEL": "Number of Misses",
"TOOLTIP": "Total SLA misses in a certain period"
},
"NO_OF_CONVERSATIONS": {
"LABEL": "Number of Conversations",
"TOOLTIP": "Total number of conversations with SLA"
}
},
"TABLE": {
"HEADER": {
"POLICY": "Policy",
"CONVERSATION": "Konversation",
"AGENT": "Agent"
},
"VIEW_DETAILS": "View Details"
}
} }
} }
@@ -83,7 +83,10 @@
"CONVERSATION_CREATION": "Senden Sie E-Mail-Benachrichtigungen, wenn eine neue Konversation erstellt wird", "CONVERSATION_CREATION": "Senden Sie E-Mail-Benachrichtigungen, wenn eine neue Konversation erstellt wird",
"CONVERSATION_MENTION": "Senden Sie E-Mail-Benachrichtigungen, wenn Sie in einer Konversation erwähnt werden", "CONVERSATION_MENTION": "Senden Sie E-Mail-Benachrichtigungen, wenn Sie in einer Konversation erwähnt werden",
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Senden Sie E-Mail-Benachrichtigungen, wenn eine neue Nachricht in einer zugewiesenen Konversation erstellt wird", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Senden Sie E-Mail-Benachrichtigungen, wenn eine neue Nachricht in einer zugewiesenen Konversation erstellt wird",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "E-Mail-Benachrichtigungen senden, wenn eine neue Nachricht in einer zugewiesenen Konversation erstellt wird" "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "E-Mail-Benachrichtigungen senden, wenn eine neue Nachricht in einer zugewiesenen Konversation erstellt wird",
"SLA_MISSED_FIRST_RESPONSE": "Send email notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send email notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send email notifications when a conversation misses resolution SLA"
}, },
"API": { "API": {
"UPDATE_SUCCESS": "Ihre Benachrichtigungseinstellungen wurden erfolgreich aktualisiert", "UPDATE_SUCCESS": "Ihre Benachrichtigungseinstellungen wurden erfolgreich aktualisiert",
@@ -98,7 +101,10 @@
"ASSIGNED_CONVERSATION_NEW_MESSAGE": "Senden Sie Push-Benachrichtigungen, wenn eine neue Nachricht in einer zugewiesenen Konversation erstellt wird", "ASSIGNED_CONVERSATION_NEW_MESSAGE": "Senden Sie Push-Benachrichtigungen, wenn eine neue Nachricht in einer zugewiesenen Konversation erstellt wird",
"PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Sende Push-Benachrichtigungen, wenn eine neue Nachricht in einer zugewiesenen Konversation erstellt wird", "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "Sende Push-Benachrichtigungen, wenn eine neue Nachricht in einer zugewiesenen Konversation erstellt wird",
"HAS_ENABLED_PUSH": "Sie haben die Push-Benachrichtigung für diesen Browser aktiviert.", "HAS_ENABLED_PUSH": "Sie haben die Push-Benachrichtigung für diesen Browser aktiviert.",
"REQUEST_PUSH": "Push-Benachrichtigungen aktivieren" "REQUEST_PUSH": "Push-Benachrichtigungen aktivieren",
"SLA_MISSED_FIRST_RESPONSE": "Send push notifications when a conversation misses first response SLA",
"SLA_MISSED_NEXT_RESPONSE": "Send push notifications when a conversation misses next response SLA",
"SLA_MISSED_RESOLUTION": "Send push notifications when a conversation misses resolution SLA"
}, },
"PROFILE_IMAGE": { "PROFILE_IMAGE": {
"LABEL": "Profilbild" "LABEL": "Profilbild"
@@ -199,6 +205,7 @@
"SIDEBAR": { "SIDEBAR": {
"CURRENTLY_VIEWING_ACCOUNT": "Wird gerade angezeigt:", "CURRENTLY_VIEWING_ACCOUNT": "Wird gerade angezeigt:",
"SWITCH": "Wechseln", "SWITCH": "Wechseln",
"INBOX_VIEW": "Inbox View",
"CONVERSATIONS": "Gespräche", "CONVERSATIONS": "Gespräche",
"INBOX": "Posteingang", "INBOX": "Posteingang",
"ALL_CONVERSATIONS": "Alle Konversationen", "ALL_CONVERSATIONS": "Alle Konversationen",
@@ -237,6 +244,8 @@
"CAMPAIGNS": "Kampagnen", "CAMPAIGNS": "Kampagnen",
"ONGOING": "Im Gange", "ONGOING": "Im Gange",
"ONE_OFF": "Einmalig", "ONE_OFF": "Einmalig",
"REPORTS_SLA": "SLA",
"REPORTS_BOT": "Bot",
"REPORTS_AGENT": "Agenten", "REPORTS_AGENT": "Agenten",
"REPORTS_LABEL": "Labels", "REPORTS_LABEL": "Labels",
"REPORTS_INBOX": "Posteingang", "REPORTS_INBOX": "Posteingang",
@@ -1,22 +1,31 @@
{ {
"SLA": { "SLA": {
"HEADER": "SLA", "HEADER": "SLA",
"HEADER_BTN_TXT": "Add SLA", "ADD_ACTION": "Add SLA",
"ADD_ACTION_LONG": "Create a new SLA Policy",
"DESCRIPTION": "Service Level Agreements (SLAs) are contracts that define clear expectations between your team and customers. They establish standards for response and resolution times, creating a framework for accountability and ensures a consistent, high-quality experience.",
"LEARN_MORE": "Learn more about SLA",
"LOADING": "Fetching SLAs", "LOADING": "Fetching SLAs",
"SEARCH_404": "Es gibt keine Elemente, die dieser Abfrage entsprechen",
"SIDEBAR_TXT": "<p><b>SLA</b> <p>Think of Service Level Agreements (SLAs) like friendly promises between a service provider and a customer.</p> <p> These promises set clear expectations for things like how quickly the team will respond to issues, making sure you always get a reliable and top-notch experience!</p>",
"LIST": { "LIST": {
"404": "There are no SLAs available in this account.", "404": "There are no SLAs available in this account.",
"TITLE": "Manage SLA", "EMPTY": {
"DESC": "SLAs: Friendly promises for great service!", "TITLE_1": "Enterprise P0",
"TABLE_HEADER": [ "DESC_1": "Issues raised by enterprise customers, that require immediate attention.",
"Name", "TITLE_2": "Enterprise P1",
"Beschreibung", "DESC_2": "Issues raised by enterprise customers, that needs to be acknowledged quickly."
"FRT", },
"NRT", "BUSINESS_HOURS_ON": "Business hours on",
"RT", "BUSINESS_HOURS_OFF": "Business hours off",
"Öffnungszeiten" "RESPONSE_TYPES": {
] "FRT": "First response time threshold",
"NRT": "Next response time threshold",
"RT": "Resolution time threshold",
"SHORT_HAND": {
"FRT": "FRT",
"NRT": "NRT",
"RT": "RT"
}
}
}, },
"FORM": { "FORM": {
"NAME": { "NAME": {
@@ -56,18 +65,32 @@
}, },
"ADD": { "ADD": {
"TITLE": "Add SLA", "TITLE": "Add SLA",
"DESC": "SLAs: Friendly promises for great service!", "DESC": "Friendly promises for great service!",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA added successfully", "SUCCESS_MESSAGE": "SLA added successfully",
"ERROR_MESSAGE": "Es ist ein Fehler aufgetreten, bitte versuchen Sie es erneut" "ERROR_MESSAGE": "Es ist ein Fehler aufgetreten, bitte versuchen Sie es erneut"
} }
}, },
"EDIT": { "DELETE": {
"TITLE": "Edit SLA", "TITLE": "Delete SLA",
"API": { "API": {
"SUCCESS_MESSAGE": "SLA updated successfully", "SUCCESS_MESSAGE": "SLA deleted successfully",
"ERROR_MESSAGE": "Es ist ein Fehler aufgetreten, bitte versuchen Sie es erneut" "ERROR_MESSAGE": "Es ist ein Fehler aufgetreten, bitte versuchen Sie es erneut"
},
"CONFIRM": {
"TITLE": "Löschung bestätigen",
"MESSAGE": "Are you sure you want to delete ",
"YES": "Ja, löschen ",
"NO": "Nein, behalten "
} }
},
"EVENTS": {
"TITLE": "SLA Misses",
"FRT": "Erste Antwortzeit",
"NRT": "Next response time",
"RT": "Resolution time",
"SHOW_MORE": "{count} more",
"HIDE": "Hide {count} rows"
} }
} }
} }

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