Feature: Ability to set an account name (#667)

* Ability to change the account name 
* Ability to set a language to the account

Addresses: #667  #307  

Co-authored-by: Pranav Raj Sreepuram <pranavrajs@gmail.com>
This commit is contained in:
Nithin David Thomas 2020-04-06 22:17:07 +05:30 committed by GitHub
parent a1a81e3799
commit 99eaf59509
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 1385 additions and 67 deletions

View file

@ -28,4 +28,5 @@ exclude_patterns:
- "app/test-matchers.js"
- "docs/*"
- "**/*.md"
- "**/*.yml"
- "**/*.yml"
- "app/javascript/dashboard/i18n/locale"

View file

@ -8,7 +8,10 @@
</template>
<script>
import Vue from 'vue';
import { mapGetters } from 'vuex';
import WootSnackbarBox from './components/SnackbarContainer';
import { accountIdFromPathname } from './helper/URLHelper';
export default {
name: 'App',
@ -17,8 +20,28 @@ export default {
WootSnackbarBox,
},
computed: {
...mapGetters({
getAccount: 'accounts/getAccount',
}),
},
mounted() {
this.$store.dispatch('setUser');
this.initializeAccount();
},
methods: {
async initializeAccount() {
const { pathname } = window.location;
const accountId = accountIdFromPathname(pathname);
if (accountId) {
await this.$store.dispatch('accounts/get');
const { locale } = this.getAccount(accountId);
Vue.config.lang = locale;
}
},
},
};
</script>

View file

@ -0,0 +1,9 @@
import ApiClient from './ApiClient';
class AccountAPI extends ApiClient {
constructor() {
super('', { accountScoped: true });
}
}
export default new AccountAPI();

View file

@ -3,8 +3,8 @@
}
.flex-center {
display: flex;
@include flex-align(center, middle);
display: flex;
}
.bottom-space-fix {
@ -17,42 +17,43 @@
.spinner {
@include color-spinner();
position: relative;
display: inline-block;
width: $space-medium;
height: $space-medium;
padding: $zero $space-medium;
position: relative;
vertical-align: middle;
width: $space-medium;
&.message {
padding: $space-normal;
top: 0;
left: 0;
margin: 0 auto;
margin-top: $space-slab;
@include elegent-shadow;
background: $color-white;
border-radius: $space-large;
@include elegent-shadow;
left: 0;
margin: $space-slab 0 auto;
padding: $space-normal;
top: 0;
&:before {
margin-top: -$space-slab;
&::before {
margin-left: -$space-slab;
margin-top: -$space-slab;
}
}
&.small {
width: $space-normal;
height: $space-normal;
width: $space-normal;
&:before {
width: $space-normal;
&::before {
height: $space-normal;
margin-top: -$space-small;
width: $space-normal;
}
}
}
input, textarea {
input,
textarea,
select {
border-radius: 4px !important;
}

View file

@ -44,12 +44,12 @@
<ul class="vertical dropdown menu">
<li>
<router-link :to="`/app/accounts/${accountId}/profile/settings`">
{{ $t('SIDEBAR.PROFILE_SETTINGS') }}
{{ $t('SIDEBAR_ITEMS.PROFILE_SETTINGS') }}
</router-link>
</li>
<li>
<a href="#" @click.prevent="logout()">
{{ $t('SIDEBAR.LOGOUT') }}
{{ $t('SIDEBAR_ITEMS.LOGOUT') }}
</a>
</li>
</ul>
@ -139,7 +139,7 @@ export default {
inboxSection() {
return {
icon: 'ion-folder',
label: 'Inboxes',
label: 'INBOXES',
hasSubMenu: true,
newLink: true,
key: 'inbox',

View file

@ -14,7 +14,7 @@
>
<div class="wrap">
<i :class="menuItem.icon" />
{{ menuItem.label }}
{{ $t(`SIDEBAR.${menuItem.label}`) }}
</div>
<span
v-if="showItem(menuItem)"

View file

@ -29,12 +29,6 @@
/* eslint no-console: 0 */
export default {
props: {
items: {
type: Array,
default() {
return [];
},
},
isFullwidth: Boolean,
},
@ -45,6 +39,9 @@ export default {
activeIndex() {
return this.items.findIndex(i => i.route === this.$route.name);
},
items() {
return this.$t('INBOX_MGMT.CREATE_FLOW');
},
},
methods: {
isActive(item) {

View file

@ -11,3 +11,12 @@ export const conversationUrl = (accountId, activeInbox, id) => {
: `accounts/${accountId}/conversations/${id}`;
return path;
};
export const accountIdFromPathname = pathname => {
const isInsideAccountScopedURLs = pathname.includes('/app/accounts');
const urlParam = pathname.split('/')[3];
// eslint-disable-next-line no-restricted-globals
const isScoped = isInsideAccountScopedURLs && !isNaN(urlParam);
const accountId = isScoped ? Number(urlParam) : '';
return accountId;
};

View file

@ -1,4 +1,8 @@
import { frontendURL, conversationUrl } from '../URLHelper';
import {
frontendURL,
conversationUrl,
accountIdFromPathname,
} from '../URLHelper';
describe('#URL Helpers', () => {
describe('conversationUrl', () => {
@ -22,4 +26,26 @@ describe('#URL Helpers', () => {
expect(frontendURL('main', { ping: 'pong' })).toBe('/app/main?ping=pong');
});
});
/*
export const accountIdFromPathname = pathname => {
const isInsideAccountScopedURLs = pathname.includes('/app/accounts');
const accountId = isInsideAccountScopedURLs ? pathname.split('/')[3] : '';
return Number(accountId);
};
*/
describe('accountIdFromPathname', () => {
it('should return account id if accont scoped url is passed', () => {
expect(accountIdFromPathname('/app/accounts/1/settings/general')).toBe(1);
});
it('should return empty string if accont scoped url not is passed', () => {
expect(accountIdFromPathname('/app/accounts/settings/general')).toBe('');
});
it('should return empty string if empty string is passed', () => {
expect(accountIdFromPathname('')).toBe('');
});
});
});

View file

@ -0,0 +1,37 @@
import de from './locale/de';
export default {
...de,
APP_GLOBAL: {
TRIAL_MESSAGE: 'verbleibende Tage Probezeit.',
TRAIL_BUTTON: 'Kaufe jetzt',
},
COMPONENTS: {
CODE: {
BUTTON_TEXT: 'Kopieren',
COPY_SUCCESSFUL: 'Code erfolgreich in die Zwischenablage kopiert',
},
FILE_BUBBLE: {
DOWNLOAD: 'Herunterladen',
UPLOADING: 'Hochladen...',
},
},
CONFIRM_EMAIL: 'Überprüfen...',
SETTINGS: {
INBOXES: {
NEW_INBOX: 'Posteingang hinzufügen',
},
},
SIDEBAR: {
CONVERSATIONS: 'Gespräche',
REPORTS: 'Berichte',
SETTINGS: 'Die Einstellungen',
HOME: 'Zuhause',
AGENTS: 'Agenten',
INBOXES: 'Posteingänge',
CANNED_RESPONSES: 'Vorgefertigte Antworten',
BILLING: 'Abrechnung',
INTEGRATIONS: 'Integrationen',
ACCOUNT_SETTINGS: 'Kontoeinstellungen',
},
};

View file

@ -19,7 +19,7 @@ export default {
menuItems: {
assignedToMe: {
icon: 'ion-chatbox-working',
label: 'Conversations',
label: 'CONVERSATIONS',
hasSubMenu: false,
key: '',
toState: frontendURL(`accounts/${accountId}/dashboard`),
@ -28,14 +28,14 @@ export default {
},
report: {
icon: 'ion-arrow-graph-up-right',
label: 'Reports',
label: 'REPORTS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/reports`),
toStateName: 'settings_account_reports',
},
settings: {
icon: 'ion-settings',
label: 'Settings',
label: 'SETTINGS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings`),
toStateName: 'settings_home',
@ -58,32 +58,34 @@ export default {
'billing',
'settings_integrations',
'settings_integrations_webhook',
'general_settings',
'general_settings_index',
],
menuItems: {
back: {
icon: 'ion-ios-arrow-back',
label: 'Home',
label: 'HOME',
hasSubMenu: false,
toStateName: 'home',
toState: frontendURL(`accounts/${accountId}/dashboard`),
},
agents: {
icon: 'ion-person-stalker',
label: 'Agents',
label: 'AGENTS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/agents/list`),
toStateName: 'agent_list',
},
inboxes: {
icon: 'ion-archive',
label: 'Inboxes',
label: 'INBOXES',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/inboxes/list`),
toStateName: 'settings_inbox_list',
},
cannedResponses: {
icon: 'ion-chatbox-working',
label: 'Canned Responses',
label: 'CANNED_RESPONSES',
hasSubMenu: false,
toState: frontendURL(
`accounts/${accountId}/settings/canned-response/list`
@ -92,18 +94,25 @@ export default {
},
billing: {
icon: 'ion-card',
label: 'Billing',
label: 'BILLING',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/billing`),
toStateName: 'billing',
},
settings_integrations: {
icon: 'ion-flash',
label: 'Integrations',
label: 'INTEGRATIONS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/integrations`),
toStateName: 'settings_integrations',
},
general_settings: {
icon: 'ion-gear-a',
label: 'ACCOUNT_SETTINGS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/general`),
toStateName: 'general_settings',
},
},
},
};

View file

@ -22,4 +22,16 @@ export default {
NEW_INBOX: 'Add Inbox',
},
},
SIDEBAR: {
CONVERSATIONS: 'Conversations',
REPORTS: 'Reports',
SETTINGS: 'Settings',
HOME: 'Home',
AGENTS: 'Agents',
INBOXES: 'Inboxes',
CANNED_RESPONSES: 'Canned Responses',
BILLING: 'Billing',
INTEGRATIONS: 'Integrations',
ACCOUNT_SETTINGS: 'Account Settings',
},
};

View file

@ -1,5 +1,7 @@
import en from './en';
import de from './de';
export default {
de,
en,
};

View file

@ -0,0 +1,100 @@
{
"AGENT_MGMT": {
"HEADER": "Agenten",
"HEADER_BTN_TXT": "Agent hinzufügen",
"LOADING": "Agentenliste abrufen",
"SIDEBAR_TXT": "<p> <b> Agenten </b> </p> <p> Ein <b> Agent </b> ist Mitglied Ihres Kundensupportteams. </p> <p> Agenten können Nachrichten Ihrer Benutzer anzeigen und beantworten. In der Liste werden alle Agenten angezeigt, die sich derzeit in Ihrem Konto befinden. </p> <p> Klicken Sie auf <b> Agent hinzufügen </b>, um einen neuen Agenten hinzuzufügen. Der von Ihnen hinzugefügte Agent erhält eine E-Mail mit einem Bestätigungslink zur Aktivierung seines Kontos. Anschließend kann er auf Chatwoot zugreifen und auf Nachrichten antworten. </p> <p> Der Zugriff auf die Funktionen von Chatwoot basiert auf den folgenden Rollen. </p> <p> <b> Agent </b> - Agenten mit dieser Rolle können nur auf Posteingänge, Berichte und Konversationen zugreifen. Sie können Konversationen anderen Agenten oder sich selbst zuweisen und Konversationen auflösen. </p> <p> <b> Administrator </b> - Der Administrator hat Zugriff auf alle für Ihr Konto aktivierten Chatwoot-Funktionen, einschließlich Einstellungen und Abrechnung, sowie auf alle der Berechtigungen eines normalen Agenten. </p>",
"AGENT_TYPES": [
{
"name": "administrator",
"label": "Administrator"
}, {
"name": "agent",
"label": "Agent"
}
],
"LIST": {
"404": "Diesem Konto sind keine Agenten zugeordnet",
"TITLE": "Verwalten Sie Agenten in Ihrem Team",
"DESC": "Sie können Agenten zu / in Ihrem Team hinzufügen / entfernen.",
"NAME": "Name",
"EMAIL": "EMAIL",
"STATUS": "Status",
"ACTIONS": "Aktionen",
"VERIFIED": "Verifiziert",
"VERIFICATION_PENDING": "Überprüfung ausstehend"
},
"ADD": {
"TITLE": "Fügen Sie Ihrem Team einen Agenten hinzu",
"DESC": "Sie können Personen hinzufügen, die die Unterstützung für Ihre Posteingänge übernehmen können.",
"FORM": {
"NAME" : {
"LABEL": "Agentenname",
"PLACEHOLDER": "Bitte geben Sie einen Namen des Agenten ein"
},
"AGENT_TYPE" : {
"LABEL": "Agententyp",
"PLACEHOLDER": "Bitte wählen Sie einen Typ",
"ERROR": "Agententyp ist erforderlich"
},
"EMAIL" : {
"LABEL": "E-Mail-Addresse",
"PLACEHOLDER": "Bitte geben Sie eine E-Mail-Adresse des Agenten ein"
},
"SUBMIT": "Agent hinzufügen"
},
"API": {
"SUCCESS_MESSAGE": "Agent erfolgreich hinzugefügt",
"EXIST_MESSAGE": "Agent-E-Mail bereits verwendet. Bitte versuchen Sie es mit einer anderen E-Mail-Adresse",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
}
},
"DELETE": {
"BUTTON_TEXT": "Löschen",
"API": {
"SUCCESS_MESSAGE": "Agent erfolgreich gelöscht",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
},
"CONFIRM": {
"TITLE": "Löschung bestätigen",
"MESSAGE": "Bist du sicher, das du das löschen möchtest?",
"YES": "Ja, löschen ",
"NO": "Nein, behalte es "
}
},
"EDIT": {
"TITLE": "Agent bearbeiten",
"FORM": {
"NAME" : {
"LABEL": "Agentenname",
"PLACEHOLDER": "Bitte geben Sie einen Namen des Agenten ein"
},
"AGENT_TYPE" : {
"LABEL": "Agententyp",
"PLACEHOLDER": "Bitte wählen Sie einen Typ",
"ERROR": "Agententyp ist erforderlich"
},
"EMAIL" : {
"LABEL": "E-Mail-Addresse",
"PLACEHOLDER": "Bitte geben Sie eine E-Mail-Adresse des Agenten ein"
},
"SUBMIT": "Agent bearbeiten"
},
"BUTTON_TEXT": "Bearbeiten",
"CANCEL_BUTTON_TEXT": "Stornieren",
"API": {
"SUCCESS_MESSAGE": "Agent erfolgreich aktualisiert",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
},
"PASSWORD_RESET": {
"ADMIN_RESET_BUTTON": "Passwort zurücksetzen",
"ADMIN_SUCCESS_MESSAGE": "Eine E-Mail mit Anweisungen zum Zurücksetzen des Passworts wurde an den Agenten gesendet",
"SUCCESS_MESSAGE": "Agent-Passwort erfolgreich zurückgesetzt",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
}
},
"SEARCH": {
"NO_RESULTS": "Keine Agenten gefunden."
}
}
}

View file

@ -0,0 +1,19 @@
{
"BILLING": {
"HEADER": "Abrechnung",
"LOADING": "Abonnements abrufen",
"ACCOUNT_STATE": "Kontostatus",
"AGENT_COUNT": "Anzahl der Agenten",
"PER_AGENT_COST": "Kosten pro Agent",
"TOTAL_COST": "Gesamtkosten",
"BUTTON": {
"ADD": "Zahlungsmethode hinzufügen",
"EDIT": "Zahlungsmethode BEARBEITEN"
},
"TRIAL": {
"TITLE": "Ihre Probezeit ist vorbei",
"MESSAGE": "Fügen Sie eine Zahlungsmethode hinzu, um Chatwoot weiterhin zu verwenden."
},
"ACCOUNT_LOCKED": "Ihr Konto ist derzeit nicht verfügbar. <br> Bitte wenden Sie sich zur Reaktivierung an Ihren Administrator."
}
}

View file

@ -0,0 +1,74 @@
{
"CANNED_MGMT": {
"HEADER": "Vorgefertigte Antworten",
"HEADER_BTN_TXT": "Eingemachte Antwort hinzufügen",
"LOADING": "Eingemachte Antworten abrufen",
"SEARCH_404": "Es gibt keine Elemente, die dieser Abfrage entsprechen",
"SIDEBAR_TXT": "<p> <b> Eingemachte Antworten </b> </p> <p> Eingemachte Antworten sind gespeicherte Antwortvorlagen, mit denen schnell eine Antwort auf eine Konversation gesendet werden kann. </p> <p> Um eine vordefinierte Antwort zu erstellen, klicken Sie einfach auf <b> vordefinierte Antwort hinzufügen </b>. Sie können eine vorhandene gespeicherte Antwort auch bearbeiten oder löschen, indem Sie auf die Schaltfläche Bearbeiten oder Löschen klicken. </p> <p> Gespeicherte Antworten werden mithilfe von <b> Funktionscodes </b> verwendet. Agenten können während eines Chats auf vordefinierte Antworten zugreifen, indem sie <b> '/' </b> gefolgt vom Funktionscode eingeben. </p>",
"LIST": {
"404": "In diesem Konto sind keine gespeicherten Antworten verfügbar.",
"TITLE": "Verwalten Sie vordefinierte Antworten",
"DESC": "Eingemachte Antworten sind vordefinierte Antwortvorlagen, mit denen schnell Antworten auf Tickets gesendet werden können.",
"TABLE_HEADER": [
"Funktionscode",
"Inhalt",
"Aktionen"
]
},
"ADD": {
"TITLE": "Eingemachte Antwort hinzufügen",
"DESC": "Gespeicherte Antworten sind gespeicherte Antwortvorlagen, mit denen schnell Antworten auf Konversationen gesendet werden können.",
"FORM": {
"SHORT_CODE" : {
"LABEL": "Funktionscode",
"PLACEHOLDER": "Bitte geben Sie einen Shortcode ein",
"ERROR": "Funktionscode ist erforderlich"
},
"CONTENT" : {
"LABEL": "Inhalt",
"PLACEHOLDER": "Bitte geben Sie einen Inhalt ein",
"ERROR": "Inhalt ist erforderlich"
},
"SUBMIT": "Einreichen"
},
"API": {
"SUCCESS_MESSAGE": "Eingemachte Antwort erfolgreich hinzugefügt",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
}
},
"EDIT": {
"TITLE": "Eingemachte Antwort bearbeiten",
"FORM": {
"SHORT_CODE" : {
"LABEL": "Funktionscode",
"PLACEHOLDER": "Bitte geben Sie einen Shortcode ein",
"ERROR": "Funktionscode ist erforderlich"
},
"CONTENT" : {
"LABEL": "Inhalt",
"PLACEHOLDER": "Bitte geben Sie einen Inhalt ein",
"ERROR": "Inhalt ist erforderlich"
},
"SUBMIT": "Einreichen"
},
"BUTTON_TEXT": "Bearbeiten",
"API": {
"SUCCESS_MESSAGE": "Eingemachte Antwort erfolgreich aktualisiert",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
}
},
"DELETE": {
"BUTTON_TEXT": "Löschen",
"API": {
"SUCCESS_MESSAGE": "Eingemachte Antwort erfolgreich gelöscht",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
},
"CONFIRM": {
"TITLE": "Löschung bestätigen",
"MESSAGE": "Bist du sicher, das du das löschen möchtest",
"YES": "Ja, löschen",
"NO": "Nein, behalte es"
}
}
}
}

View file

@ -0,0 +1,77 @@
{
"CHAT_LIST": {
"LOADING": "Gespräche abrufen",
"LOAD_MORE_CONVERSATIONS": "Laden Sie weitere Gespräche",
"EOF": "Alle Gespräche geladen 🎉",
"LIST": {
"404": "In dieser Gruppe gibt es keine aktiven Gespräche."
},
"TAB_HEADING": "Gespräche",
"SEARCH": {
"INPUT": "Suche nach Personen, Chats, gespeicherten Antworten .."
},
"STATUS_TABS": [{
"NAME": "Öffnen",
"KEY": "openCount"
},
{
"NAME": "Aufgelöst",
"KEY": "allConvCount"
}
],
"ASSIGNEE_TYPE_TABS": [{
"NAME": "Bergwerk",
"KEY": "me",
"COUNT_KEY": "mineCount"
},
{
"NAME": "Nicht zugewiesen",
"KEY": "unassigned",
"COUNT_KEY": "unAssignedCount"
},
{
"NAME": "Alle",
"KEY": "all",
"COUNT_KEY": "allCount"
}
],
"CHAT_STATUS_ITEMS": [{
"TEXT": "Öffnen",
"VALUE": "open"
},
{
"TEXT": "Aufgelöst",
"VALUE": "resolved"
}
],
"ATTACHMENTS": {
"image": {
"ICON": "ion-image",
"CONTENT": "Bildnachricht"
},
"audio": {
"ICON": "ion-volume-high",
"CONTENT": "Audio-Nachricht"
},
"video": {
"ICON": "ion-ios-videocam",
"CONTENT": "Videonachricht"
},
"file": {
"ICON": "ion-document",
"CONTENT": "Dateianhang"
},
"location": {
"ICON": "ion-ios-location",
"CONTENT": "Ort"
},
"fallback": {
"ICON": "ion-link",
"CONTENT": "hat eine URL geteilt"
}
}
}
}

View file

@ -0,0 +1,20 @@
{
"CONTACT_PANEL": {
"CONVERSATION_TITLE": "Unterhaltungsdetails",
"BROWSER": "Browser",
"OS": "Betriebssystem",
"INITIATED_FROM": "Initiiert von",
"INITIATED_AT": "Initiiert bei",
"CONVERSATIONS": {
"NO_RECORDS_FOUND": "Es sind keine vorherigen Gespräche mit diesem Kontakt verbunden.",
"TITLE": "Vorherige Gespräche"
},
"LABELS": {
"TITLE": "Konversationsetiketten",
"UPDATE_BUTTON": "Etiketten aktualisieren",
"UPDATE_ERROR": "Etiketten konnten nicht aktualisiert werden. Versuchen Sie es erneut.",
"TAG_PLACEHOLDER": "Neues Etikett hinzufügen",
"PLACEHOLDER": "Suchen oder fügen Sie ein Etikett hinzu"
}
}
}

View file

@ -0,0 +1,35 @@
{
"CONVERSATION": {
"404": "Bitte wählen Sie eine Konversation aus dem linken Bereich",
"NO_MESSAGE_1": "Oh oh! Anscheinend befinden sich keine Nachrichten von Kunden in Ihrem Posteingang.",
"NO_MESSAGE_2": "um eine Nachricht an Ihre Seite zu senden!",
"NO_INBOX_1": "Hallo! Sieht so aus, als hätten Sie noch keine Posteingänge hinzugefügt.",
"NO_INBOX_2": " um loszulegen",
"NO_INBOX_AGENT": "Oh oh! Sieht so aus, als wären Sie nicht Teil eines Posteingangs. Bitte wenden Sie sich an Ihren Administrator",
"CLICK_HERE": "Hier klicken",
"LOADING_INBOXES": "Posteingänge laden",
"LOADING_CONVERSATIONS": "Gespräche laden",
"DOWNLOAD": "Herunterladen",
"HEADER": {
"RESOLVE_ACTION": "Entschlossenheit",
"REOPEN_ACTION": "Wieder öffnen",
"OPEN": "Mehr",
"CLOSE": "Schließen",
"DETAILS": "Einzelheiten"
},
"FOOTER": {
"MSG_INPUT": "Umschalt + Eingabetaste für neue Zeile. Beginnen Sie mit '/', um eine vordefinierte Antwort auszuwählen.",
"PRIVATE_MSG_INPUT": "Umschalt + Eingabetaste für neue Zeile. Dies ist nur für Agenten sichtbar"
},
"REPLYBOX": {
"REPLY": "Antworten",
"PRIVATE_NOTE": "Private Notiz",
"SEND": "Senden",
"CREATE": "Notiz hinzufügen",
"TWEET": "Tweet"
},
"VISIBLE_TO_AGENTS": "Privater Hinweis: Nur für Sie und Ihr Team sichtbar",
"CHANGE_STATUS": "Gesprächsstatus geändert",
"CHANGE_AGENT": "Konversationsempfänger geändert"
}
}

View file

@ -0,0 +1,27 @@
{
"GENERAL_SETTINGS": {
"TITLE": "Kontoeinstellungen",
"SUBMIT": "Update Einstellungen",
"UPDATE": {
"ERROR": "Einstellungen konnten nicht aktualisiert werden, versuchen Sie es erneut!",
"SUCCESS": "Kontoeinstellungen erfolgreich aktualisiert"
},
"FORM": {
"ERROR": "Bitte korrigieren Sie Formularfehler",
"GENERAL_SECTION": {
"TITLE": "Allgemeine Einstellungen",
"NOTE": ""
},
"NAME": {
"LABEL": "Kontobezeichnung",
"PLACEHOLDER": "Ihr Kontoname",
"ERROR": "Bitte geben Sie einen gültigen Kontonamen ein"
},
"LANGUAGE": {
"LABEL": "Site-Sprache (Beta)",
"PLACEHOLDER": "Your account name",
"ERROR": ""
}
}
}
}

View file

@ -0,0 +1,138 @@
{
"INBOX_MGMT": {
"HEADER": "Posteingänge",
"SIDEBAR_TXT": "<p> <b> Posteingang </b> </p> <p> Wenn Sie eine Website oder eine Facebook-Seite mit Chatwoot verbinden, wird dies als <b> Posteingang </b> bezeichnet. Sie können unbegrenzt Posteingänge in Ihrem Chatwoot-Konto haben. </p> <p> Klicken Sie auf <b> Posteingang hinzufügen </b>, um eine Website oder eine Facebook-Seite zu verbinden. </p> <p> Im <a href=\"/app/dashboard\"> Dashboard </a> können Sie alle Konversationen aus all Ihren Posteingängen an einem einzigen Ort anzeigen und unter 'Konversationen' darauf antworten `tab. </p> <p> Sie können Konversationen auch für einen Posteingang anzeigen, indem Sie auf den Namen des Posteingangs im linken Bereich des Dashboards klicken. </p>",
"LIST": {
"404": "Diesem Konto sind keine Posteingänge zugeordnet."
},
"CREATE_FLOW": [
{ "title": "Wählen Sie Kanal", "route": "settings_inbox_new", "body": "Wählen Sie den Anbieter, den Sie in Chatwoot integrieren möchten." },
{ "title": "Posteingang erstellen", "route": "settings_inboxes_page_channel", "body": "Authentifizieren Sie Ihr Konto und erstellen Sie einen Posteingang." },
{ "title": "Agenten hinzufügen", "route": "settings_inboxes_add_agents", "body": "Fügen Sie dem erstellten Posteingang Agenten hinzu." },
{ "title": "Voila!", "route": "settings_inbox_finish", "body": "Sie sind bereit zu gehen!" }
],
"ADD": {
"FB": {
"HELP": "PS: Durch die Anmeldung erhalten wir nur Zugriff auf die Nachrichten Ihrer Seite. Auf Ihre privaten Nachrichten kann Chatwoot niemals zugreifen."
},
"TWITTER": {
"HELP": "Um Ihr Twitter-Profil als Kanal hinzuzufügen, müssen Sie Ihr Twitter-Profil authentifizieren, indem Sie auf 'Mit Twitter anmelden' klicken."
},
"WEBSITE_CHANNEL": {
"TITLE": "Website-Kanal",
"DESC": "Erstellen Sie einen Kanal für Ihre Website und unterstützen Sie Ihre Kunden über unser Website-Widget.",
"CHANNEL_NAME": {
"LABEL": "Webseiten-Name",
"PLACEHOLDER": "Geben Sie den Namen Ihrer Website ein (eg: Acme Inc)"
},
"CHANNEL_DOMAIN": {
"LABEL": "Website Domain",
"PLACEHOLDER": "Geben Sie Ihre Website-Domain ein (eg: acme.com)"
},
"WIDGET_COLOR": {
"LABEL": "Widget Farbe",
"PLACEHOLDER": "Aktualisieren Sie die im Widget verwendete Widget-Farbe"
},
"SUBMIT_BUTTON":"Posteingang erstellen"
},
"TWILIO": {
"TITLE": "Twilio SMS Channel",
"DESC": "Integrieren Sie Twilio und unterstützen Sie Ihre Kunden per SMS.",
"ACCOUNT_SID": {
"LABEL": "Account SID",
"PLACEHOLDER": "Bitte geben Sie Ihre Twilio Account SID ein",
"ERROR": "Dieses Feld wird benötigt"
},
"AUTH_TOKEN": {
"LABEL": "Auth Token",
"PLACEHOLDER": "Bitte geben Sie Ihr Twilio Auth Token ein",
"ERROR": "Dieses Feld wird benötigt"
},
"CHANNEL_NAME": {
"LABEL": "Kanal Name",
"PLACEHOLDER": "Bitte geben Sie einen Kanalnamen ein",
"ERROR": "Dieses Feld wird benötigt"
},
"PHONE_NUMBER": {
"LABEL": "Telefonnummer",
"PLACEHOLDER": "Bitte geben Sie die Telefonnummer ein, von der die Nachricht gesendet wird.",
"ERROR": "Bitte geben sie einen gültigen Wert ein. Die Telefonnummer sollte mit dem Pluszeichen beginnen."
},
"SUBMIT_BUTTON": "Erstellen Sie Twilio Channel",
"API": {
"ERROR_MESSAGE": "Wir konnten die Twilio-Anmeldeinformationen nicht authentifizieren. Bitte versuchen Sie es erneut"
}
},
"AUTH": {
"TITLE": "Kanäle",
"DESC": "Derzeit unterstützen wir Website-Live-Chat-Widgets, Facebook-Seiten und Twitter-Profile als Plattformen. Wir haben weitere Plattformen wie WhatsApp, Email, Telegram und Line in Arbeit, die bald veröffentlicht werden."
},
"AGENTS": {
"TITLE": "Agenten",
"DESC": "Hier können Sie Agenten hinzufügen, um Ihren neu erstellten Posteingang zu verwalten. Nur diese ausgewählten Agenten haben Zugriff auf Ihren Posteingang. Agenten, die nicht Teil dieses Posteingangs sind, können bei der Anmeldung keine Nachrichten in diesem Posteingang sehen oder darauf antworten. <br> <b> PS: </b> Wenn Sie als Administrator Zugriff auf alle Posteingänge benötigen, sollten Sie sich als Agent zu allen von Ihnen erstellten Posteingängen hinzufügen."
},
"DETAILS": {
"TITLE": "Posteingangsdetails",
"DESC": "Wählen Sie aus der Dropdown-Liste die Facebook-Seite aus, zu der Sie eine Verbindung zu Chatwoot herstellen möchten. Sie können Ihrem Posteingang auch einen benutzerdefinierten Namen geben, um ihn besser identifizieren zu können."
},
"FINISH":{
"TITLE": "Geschafft!",
"DESC": "Sie haben die Integration Ihrer Facebook-Seite in Chatwoot erfolgreich abgeschlossen. Wenn ein Kunde das nächste Mal eine Nachricht an Ihre Seite sendet, wird die Konversation automatisch in Ihrem Posteingang angezeigt. <br> Wir stellen Ihnen außerdem ein Widget-Skript zur Verfügung, das Sie ganz einfach zu Ihrer Website hinzufügen können. Sobald dies auf Ihrer Website live ist, können Kunden Ihnen ohne Hilfe eines externen Tools direkt von Ihrer Website aus eine Nachricht senden, und die Konversation wird direkt hier auf Chatwoot angezeigt. <br> Cool, oder? Nun, wir versuchen es auf jeden Fall :)"
}
},
"DETAILS": {
"LOADING_FB": "Authentifizierung mit Facebook ...",
"ERROR_FB_AUTH": "Es ist ein Fehler aufgetreten. Bitte Seite aktualisieren ...",
"CREATING_CHANNEL": "Erstellen Sie Ihren Posteingang ...",
"TITLE": "Posteingangsdetails konfigurieren",
"DESC": ""
},
"AGENTS": {
"BUTTON_TEXT": "Agenten hinzufügen",
"ADD_AGENTS": "Adding Agents to your Inbox...Hinzufügen von Agenten zu Ihrem Posteingang ..."
},
"FINISH": {
"TITLE": "Ihr Posteingang ist fertig!",
"MESSAGE": "Sie können jetzt über Ihren neuen Kanal mit Ihren Kunden in Kontakt treten. Viel Spaß beim Unterstützen",
"BUTTON_TEXT": "Bring mich dahin",
"WEBSITE_SUCCESS": "Sie haben die Erstellung eines Website-Kanals erfolgreich abgeschlossen. Kopieren Sie den unten gezeigten Code und fügen Sie ihn in Ihre Website ein. Wenn ein Kunde das nächste Mal den Live-Chat verwendet, wird die Konversation automatisch in Ihrem Posteingang angezeigt."
},
"REAUTH": "Neu autorisieren",
"VIEW": "Aussicht",
"EDIT": {
"API": {
"SUCCESS_MESSAGE": "Widget-Farbe erfolgreich aktualisiert",
"AUTO_ASSIGNMENT_SUCCESS_MESSAGE": "Automatische Zuordnung erfolgreich aktualisiert",
"ERROR_MESSAGE": "Widget-Farbe konnte nicht aktualisiert werden. Bitte versuchen Sie es später noch einmal."
},
"AUTO_ASSIGNMENT": {
"ENABLED": "Aktiviert",
"DISABLED": "Behindert"
}
},
"DELETE": {
"BUTTON_TEXT": "Löschen",
"CONFIRM": {
"TITLE": "Löschung bestätigen",
"MESSAGE": "Bist du sicher, das du das löschen möchtest ",
"YES": "Ja, löschen",
"NO": "Nein, behalte es "
},
"API": {
"SUCCESS_MESSAGE": "Posteingang erfolgreich gelöscht",
"ERROR_MESSAGE": "Posteingang konnte nicht gelöscht werden. Bitte versuchen Sie es später noch einmal."
}
},
"SETTINGS": "die Einstellungen",
"SETTINGS_POPUP": {
"MESSENGER_HEADING": "Messenger-Skript",
"MESSENGER_SUB_HEAD": "Platzieren Sie diese Schaltfläche in Ihrem Body-Tag",
"INBOX_AGENTS": "Agenten",
"INBOX_AGENTS_SUB_TEXT": "Hinzufügen oder Entfernen von Agenten zu diesem Posteingang",
"UPDATE": "Aktualisieren",
"AUTO_ASSIGNMENT": "Aktivieren Sie die automatische Zuweisung",
"AUTO_ASSIGNMENT_SUB_TEXT": "Aktivieren oder deaktivieren Sie die automatische Zuweisung verfügbarer Agenten für neue Konversationen"
}
}
}

View file

@ -0,0 +1,34 @@
/* eslint-disable */
import { default as _agentMgmt } from './agentMgmt.json';
import { default as _billing } from './billing.json';
import { default as _cannedMgmt } from './cannedMgmt.json';
import { default as _chatlist } from './chatlist.json';
import { default as _contact } from './contact.json';
import { default as _conversation } from './conversation.json';
import { default as _inboxMgmt } from './inboxMgmt.json';
import { default as _login } from './login.json';
import { default as _report } from './report.json';
import { default as _resetPassword } from './resetPassword.json';
import { default as _setNewPassword } from './setNewPassword.json';
import { default as _settings } from './settings.json';
import { default as _signup } from './signup.json';
import { default as _integrations } from './integrations.json';
import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
..._billing,
..._cannedMgmt,
..._chatlist,
..._contact,
..._conversation,
..._inboxMgmt,
..._login,
..._report,
..._resetPassword,
..._setNewPassword,
..._settings,
..._signup,
..._integrations,
..._generalSettings,
};

View file

@ -0,0 +1,54 @@
{
"INTEGRATION_SETTINGS": {
"HEADER": "Integrationen",
"WEBHOOK": {
"TITLE": "Webhook",
"CONFIGURE": "Konfigurieren",
"HEADER": "Webhook-Einstellungen",
"HEADER_BTN_TXT": "Neuen Webhook hinzufügen",
"INTEGRATION_TXT": "Webhook-Ereignisse bieten Ihnen Echtzeitinformationen darüber, was in Ihrem Chatwoot-Konto passiert. Sie können die Webhooks verwenden, um die Ereignisse an Ihre Lieblings-Apps wie Slack oder Github zu kommunizieren. Klicken Sie auf Konfigurieren, um Ihre Webhooks einzurichten.",
"LOADING": "Angehängte Webhooks abrufen",
"SEARCH_404": "Es gibt keine Elemente, die dieser Abfrage entsprechen",
"SIDEBAR_TXT": "<p> <b> Webhooks </b> </p> <p> Webhooks sind HTTP-Rückrufe, die für jedes Konto definiert werden können. Sie werden durch Ereignisse wie die Erstellung von Nachrichten in Chatwoot ausgelöst. Sie können mehr als einen Webhook für dieses Konto erstellen. <br /> <br /> Um einen <b> Webhook </b> zu erstellen, klicken Sie auf die Schaltfläche <b> Neuen Webhook hinzufügen </b>. Sie können auch vorhandene Webhooks entfernen, indem Sie auf die Schaltfläche Löschen klicken. </p>",
"LIST": {
"404": "Für dieses Konto sind keine Webhooks konfiguriert.",
"TITLE": "Webhooks verwalten",
"DESC": "Webhooks sind vordefinierte Antwortvorlagen, mit denen schnell Antworten auf Tickets gesendet werden können.",
"TABLE_HEADER": [
"Webhook-Endpunkt",
"Aktionen"
]
},
"ADD": {
"CANCEL": "Stornieren",
"TITLE": "Neuen Webhook hinzufügen",
"DESC": "Webhook-Ereignisse bieten Ihnen Echtzeitinformationen darüber, was in Ihrem Chatwoot-Konto passiert. Bitte geben Sie eine gültige URL ein, um einen Rückruf zu konfigurieren.",
"FORM": {
"END_POINT": {
"LABEL": "Webhook-URL",
"PLACEHOLDER": "Example: https://example/api/webhook",
"ERROR": "Bitte geben Sie eine gültige URL ein"
},
"SUBMIT": "Webhook erstellen"
},
"API": {
"SUCCESS_MESSAGE": "Webhook erfolgreich hinzugefügt",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
}
},
"DELETE": {
"BUTTON_TEXT": "Löschen",
"API": {
"SUCCESS_MESSAGE": "Webhook erfolgreich gelöscht",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
},
"CONFIRM": {
"TITLE": "Löschung bestätigen",
"MESSAGE": "Bist du sicher, das du das löschen möchtest",
"YES": "Ja, löschen ",
"NO": "Nein, behalte es "
}
}
}
}
}

View file

@ -0,0 +1,21 @@
{
"LOGIN": {
"TITLE": "Melden Sie sich bei Chatwoot an",
"EMAIL": {
"LABEL": "Email",
"PLACEHOLDER": "Email eg: someone@example.com"
},
"PASSWORD": {
"LABEL": "Passwort",
"PLACEHOLDER": "Passwort"
},
"API": {
"SUCCESS_MESSAGE": "Anmeldung erfolgreich",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut",
"UNAUTH": "Benutzername / Passwort falsch. Bitte versuche es erneut"
},
"FORGOT_PASSWORD": "Haben Sie Ihr Passwort vergessen?",
"CREATE_NEW_ACCOUNT": "Neuen Account erstellen",
"SUBMIT": "Einloggen"
}
}

View file

@ -0,0 +1,19 @@
{
"REPORT": {
"HEADER": "Berichte",
"LOADING_CHART": "Diagrammdaten laden ...",
"NO_ENOUGH_DATA": "Wir haben nicht genügend Datenpunkte erhalten, um einen Bericht zu erstellen. Bitte versuchen Sie es später erneut.",
"METRICS": [
{ "NAME": "Gespräche", "KEY": "conversations_count", "DESC": "( Total )" },
{ "NAME": "Eingehende Nachrichten", "KEY": "incoming_messages_count", "DESC": "( Total )" },
{ "NAME": "Ausgehende Nachrichten", "KEY": "outgoing_messages_count", "DESC": "( Total )" },
{ "NAME": "Erste Antwortzeit", "KEY": "avg_first_response_time", "DESC": "( Avg )" },
{ "NAME": "Lösungszeit", "KEY": "avg_resolution_time", "DESC": "( Avg )" },
{ "NAME": "Auflösungsanzahl", "KEY": "resolutions_count", "DESC": "( Total )" }
],
"DATE_RANGE": [
{ "id": 0, "name": "Letzten 7 Tage" },
{ "id": 1, "name": "Letzte 30 Tage" }
]
}
}

View file

@ -0,0 +1,15 @@
{
"RESET_PASSWORD": {
"TITLE": "Passwort zurücksetzen",
"EMAIL": {
"LABEL": "Email",
"PLACEHOLDER": "Bitte geben Sie ihre E-Mail-Adresse ein",
"ERROR": "Bitte geben Sie eine gültige Email-Adresse ein"
},
"API": {
"SUCCESS_MESSAGE": "Der Link zum Zurücksetzen des Passworts wurde an Ihre E-Mail gesendet",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
},
"SUBMIT": "Einreichen"
}
}

View file

@ -0,0 +1,20 @@
{
"SET_NEW_PASSWORD": {
"TITLE": "Neues Passwort festlegen",
"PASSWORD": {
"LABEL": "Passwort",
"PLACEHOLDER": "Passwort",
"ERROR": "Das Passwort ist zu kurz"
},
"CONFIRM_PASSWORD": {
"LABEL": "Bestätige das Passwort",
"PLACEHOLDER": "Bestätige das Passwort",
"ERROR": "Passwörter stimmen nicht überein"
},
"API": {
"SUCCESS_MESSAGE": "Das Passwort wurde erfolgreich geändert",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
},
"SUBMIT": "Einreichen"
}
}

View file

@ -0,0 +1,62 @@
{
"PROFILE_SETTINGS": {
"LINK": "Profileinstellungen",
"TITLE": "Profileinstellungen",
"BTN_TEXT": "Profil aktualisieren",
"AFTER_EMAIL_CHANGED": "Ihr Profil wurde erfolgreich aktualisiert. Melden Sie sich erneut an, wenn Ihre Anmeldeinformationen geändert werden",
"FORM": {
"AVATAR": "Profilbild",
"ERROR": "Bitte korrigieren Sie Formularfehler",
"REMOVE_IMAGE": "Entfernen",
"UPLOAD_IMAGE": "Bild hochladen",
"UPDATE_IMAGE": "Bild aktualisieren",
"PROFILE_SECTION" : {
"TITLE": "Profil",
"NOTE": "Ihre E-Mail-Adresse ist Ihre Identität und wird zum Anmelden verwendet."
},
"PASSWORD_SECTION" : {
"TITLE": "Passwort",
"NOTE": "Durch das Aktualisieren Ihres Kennworts werden Ihre Anmeldungen auf mehreren Geräten zurückgesetzt."
},
"ACCESS_TOKEN": {
"TITLE": "Zugangstoken",
"NOTE": "Dieses Token kann verwendet werden, wenn Sie eine API-basierte Integration erstellen"
},
"EMAIL_NOTIFICATIONS_SECTION" : {
"TITLE": "E-Mail Benachrichtigungen",
"NOTE": "Aktualisieren Sie hier Ihre E-Mail-Benachrichtigungseinstellungen",
"CONVERSATION_ASSIGNMENT": "Senden Sie E-Mail-Benachrichtigungen, wenn mir ein Gespräch zugewiesen wurde",
"CONVERSATION_CREATION": "Senden Sie E-Mail-Benachrichtigungen, wenn eine neue Konversation erstellt wird",
"UPDATE_SUCCESS": "Ihre E-Mail-Benachrichtigungseinstellungen wurden erfolgreich aktualisiert",
"UPDATE_ERROR": "Beim Aktualisieren der Einstellungen ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut"
},
"PROFILE_IMAGE":{
"LABEL": "Profilbild"
},
"NAME": {
"LABEL": "Dein Name",
"ERROR": "Bitte geben Sie einen gültigen Namen ein",
"PLACEHOLDER": "Bitte geben Sie Ihren Namen ein, dies wird in Gesprächen angezeigt"
},
"EMAIL": {
"LABEL": "Deine Emailadresse",
"ERROR": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
"PLACEHOLDER": "Bitte geben Sie Ihre E-Mail-Adresse ein, diese wird in Gesprächen angezeigt"
},
"PASSWORD": {
"LABEL": "Passwort",
"ERROR": "Bitte geben Sie ein Passwort mit einer Länge von 6 oder mehr ein",
"PLACEHOLDER": "Bitte geben Sie ein neues Passwort ein"
},
"PASSWORD_CONFIRMATION": {
"LABEL": "Bestätige neues Passwort",
"ERROR": "Bestätigen Sie, dass das Passwort mit dem Passwort übereinstimmen sollte",
"PLACEHOLDER": "Bitte geben Sie Ihr Passwort erneut ein"
}
}
},
"SIDEBAR_ITEMS": {
"PROFILE_SETTINGS": "Profileinstellungen",
"LOGOUT": "Ausloggen"
}
}

View file

@ -0,0 +1,32 @@
{
"REGISTER": {
"TRY_WOOT": "Einen Account registrieren",
"TITLE": "Registrieren",
"TERMS_ACCEPT": "Mit Ihrer Anmeldung stimmen Sie unseren <a href=\"https://www.chatwoot.com/terms\"> AGB </a> und <a href=\"https://www.chatwoot.com/privacy-policy\"> Datenschutzrichtlinie </a>",
"ACCOUNT_NAME": {
"LABEL": "Kontobezeichnung",
"PLACEHOLDER": "Wayne Enterprises",
"ERROR": "Der Kontoname ist zu klein"
},
"EMAIL": {
"LABEL": "Email",
"PLACEHOLDER": "bruce@wayne.enterprises",
"ERROR": "E-Mail ist ungültig"
},
"PASSWORD": {
"LABEL": "Passwort",
"PLACEHOLDER": "Password",
"ERROR": "Das Passwort ist zu kurz"
},
"CONFIRM_PASSWORD": {
"LABEL": "Bestätige das Passwort",
"PLACEHOLDER": "Bestätige das Passwort",
"ERROR": "Passwort stimmt nicht überein"
},
"API": {
"SUCCESS_MESSAGE": "Registrierung erfolgreich",
"ERROR_MESSAGE": "Es konnte keine Verbindung zum Woot Server hergestellt werden. Bitte versuchen Sie es später erneut"
},
"SUBMIT": "Einreichen"
}
}

View file

@ -0,0 +1,5 @@
{
"WEBHOOKS_SETTINGS": {
"HEADER": "Webhook-Einstellungen"
}
}

View file

@ -0,0 +1,27 @@
{
"GENERAL_SETTINGS": {
"TITLE": "Account settings",
"SUBMIT": "Update settings",
"UPDATE": {
"ERROR": "Could not update settings, try again!",
"SUCCESS": "Successfully updated account settings"
},
"FORM": {
"ERROR": "Please fix form errors",
"GENERAL_SECTION": {
"TITLE": "General settings",
"NOTE": ""
},
"NAME": {
"LABEL": "Account name",
"PLACEHOLDER": "Your account name",
"ERROR": "Please enter a valid account name"
},
"LANGUAGE": {
"LABEL": "Site language (Beta)",
"PLACEHOLDER": "Your account name",
"ERROR": ""
}
}
}
}

View file

@ -13,6 +13,7 @@ import { default as _setNewPassword } from './setNewPassword.json';
import { default as _settings } from './settings.json';
import { default as _signup } from './signup.json';
import { default as _integrations } from './integrations.json';
import { default as _generalSettings } from './generalSettings.json';
export default {
..._agentMgmt,
@ -29,4 +30,5 @@ export default {
..._settings,
..._signup,
..._integrations,
..._generalSettings,
};

View file

@ -55,7 +55,7 @@
}
}
},
"SIDEBAR": {
"SIDEBAR_ITEMS": {
"PROFILE_SETTINGS": "Profile Settings",
"LOGOUT": "Logout"
}

View file

@ -0,0 +1,141 @@
<template>
<div class="columns profile--settings ">
<form @submit.prevent="updateAccount()">
<div class="small-12 row profile--settings--row">
<div class="columns small-3 ">
<h4 class="block-title">
{{ $t('GENERAL_SETTINGS.FORM.GENERAL_SECTION.TITLE') }}
</h4>
<p>{{ $t('GENERAL_SETTINGS.FORM.GENERAL_SECTION.NOTE') }}</p>
</div>
<div class="columns small-9 medium-5">
<label :class="{ error: $v.name.$error }">
{{ $t('GENERAL_SETTINGS.FORM.NAME.LABEL') }}
<input
v-model="name"
type="text"
:placeholder="$t('GENERAL_SETTINGS.FORM.NAME.PLACEHOLDER')"
@blur="$v.name.$touch"
/>
<span v-if="$v.name.$error" class="message">
{{ $t('GENERAL_SETTINGS.FORM.NAME.ERROR') }}
</span>
</label>
<label :class="{ error: $v.locale.$error }">
{{ $t('GENERAL_SETTINGS.FORM.LANGUAGE.LABEL') }}
<select v-model="locale">
<option value="en">English</option>
<option value="de">German</option>
</select>
<span v-if="$v.locale.$error" class="message">
{{ $t('GENERAL_SETTINGS.FORM.LANGUAGE.ERROR') }}
</span>
</label>
</div>
</div>
<woot-submit-button
class="button nice success button--fixed-right-top"
:button-text="$t('GENERAL_SETTINGS.SUBMIT')"
:loading="isUpdating"
>
</woot-submit-button>
</form>
</div>
</template>
<script>
import Vue from 'vue';
import { required } from 'vuelidate/lib/validators';
import { mapGetters } from 'vuex';
import { accountIdFromPathname } from 'dashboard/helper/URLHelper';
import alertMixin from 'shared/mixins/alertMixin';
export default {
mixins: [alertMixin],
data() {
return {
id: '',
name: '',
locale: 'en',
};
},
validations: {
name: {
required,
},
locale: {
required,
},
},
computed: {
...mapGetters({
getAccount: 'accounts/getAccount',
uiFlags: 'accounts/getUIFlags',
}),
isUpdating() {
return this.uiFlags.isUpdating;
},
},
mounted() {
if (!this.id) {
this.initializeAccount();
}
},
methods: {
async initializeAccount() {
const { pathname } = window.location;
const accountId = accountIdFromPathname(pathname);
if (accountId) {
await this.$store.dispatch('accounts/get');
const { name, locale, id } = this.getAccount(accountId);
Vue.config.lang = locale;
this.name = name;
this.locale = locale;
this.id = id;
}
},
async updateAccount() {
this.$v.$touch();
if (this.$v.$invalid) {
this.showAlert(this.$t('GENERAL_SETTINGS.FORM.ERROR'));
return;
}
try {
await this.$store.dispatch('accounts/update', {
locale: this.locale,
name: this.name,
});
Vue.config.lang = this.locale;
this.showAlert(this.$t('GENERAL_SETTINGS.UPDATE.SUCCESS'));
} catch (error) {
this.showAlert(this.$t('GENERAL_SETTINGS.UPDATE.ERROR'));
}
},
},
};
</script>
<style lang="scss">
@import '~dashboard/assets/scss/variables.scss';
@import '~dashboard/assets/scss/mixins.scss';
.profile--settings {
padding: 24px;
overflow: auto;
}
.profile--settings--row {
@include border-normal-bottom;
padding: $space-normal;
.small-3 {
padding: $space-normal $space-medium $space-normal 0;
}
.small-9 {
padding: $space-normal;
}
}
</style>

View file

@ -0,0 +1,27 @@
import SettingsContent from '../Wrapper';
import Index from './Index.vue';
import { frontendURL } from '../../../../helper/URLHelper';
export default {
routes: [
{
path: frontendURL('accounts/:accountId/settings/general'),
name: 'general_settings',
roles: ['administrator'],
component: SettingsContent,
props: {
headerTitle: 'GENERAL_SETTINGS.TITLE',
icon: 'ion-gear-a',
showNewButton: false,
},
children: [
{
path: '',
name: 'general_settings_index',
component: Index,
roles: ['administrator'],
},
],
},
],
};

View file

@ -1,18 +1,6 @@
<template>
<div class="row content-box full-height">
<woot-wizard class="small-3 columns" :items="wizardItems"></woot-wizard>
<woot-wizard class="small-3 columns"></woot-wizard>
<router-view></router-view>
</div>
</template>
<script>
/* eslint no-console: 0 */
/* eslint-env browser */
export default {
data() {
return {
wizardItems: this.$t('INBOX_MGMT.CREATE_FLOW'),
};
},
};
</script>

View file

@ -10,14 +10,14 @@ export default {
roles: ['administrator', 'agent'],
component: SettingsContent,
props: {
headerTitle: 'PROFILE_SETTINGS.TITLE',
headerTitle: 'GENERAL_SETTINGS.TITLE',
icon: 'ion-compose',
showNewButton: false,
},
children: [
{
path: 'settings',
name: 'profile_settings_index',
name: 'general_settings_index',
component: Index,
roles: ['administrator', 'agent'],
},

View file

@ -7,6 +7,7 @@ import inbox from './inbox/inbox.routes';
import profile from './profile/profile.routes';
import reports from './reports/reports.routes';
import integrations from './integrations/integrations.routes';
import account from './account/account.routes';
export default {
routes: [
@ -28,5 +29,6 @@ export default {
...profile.routes,
...reports.routes,
...integrations.routes,
...account.routes,
],
};

View file

@ -17,6 +17,7 @@ import inboxMembers from './modules/inboxMembers';
import reports from './modules/reports';
import userNotificationSettings from './modules/userNotificationSettings';
import webhooks from './modules/webhooks';
import accounts from './modules/accounts';
Vue.use(Vuex);
export default new Vuex.Store({
@ -37,5 +38,6 @@ export default new Vuex.Store({
reports,
userNotificationSettings,
webhooks,
accounts,
},
});

View file

@ -0,0 +1,70 @@
/* eslint no-console: 0 */
/* eslint no-param-reassign: 0 */
/* eslint no-shadow: 0 */
import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers';
import * as types from '../mutation-types';
import AccountAPI from '../../api/account';
const state = {
records: [],
uiFlags: {
isFetching: false,
isFetchingItem: false,
isUpdating: false,
},
};
export const getters = {
getAccount: $state => id => {
return $state.records.find(record => record.id === Number(id));
},
getUIFlags($state) {
return $state.uiFlags;
},
};
export const actions = {
get: async ({ commit }) => {
commit(types.default.SET_ACCOUNT_UI_FLAG, { isFetchingItem: true });
try {
const response = await AccountAPI.get();
commit(types.default.ADD_ACCOUNT, response.data);
commit(types.default.SET_ACCOUNT_UI_FLAG, {
isFetchingItem: false,
});
} catch (error) {
commit(types.default.SET_ACCOUNT_UI_FLAG, {
isFetchingItem: false,
});
}
},
update: async ({ commit }, updateObj) => {
commit(types.default.SET_ACCOUNT_UI_FLAG, { isUpdating: true });
try {
await AccountAPI.update('', updateObj);
commit(types.default.SET_ACCOUNT_UI_FLAG, { isUpdating: false });
} catch (error) {
commit(types.default.SET_ACCOUNT_UI_FLAG, { isUpdating: false });
throw new Error(error);
}
},
};
export const mutations = {
[types.default.SET_ACCOUNT_UI_FLAG]($state, data) {
$state.uiFlags = {
...$state.uiFlags,
...data,
};
},
[types.default.ADD_ACCOUNT]: MutationHelpers.create,
[types.default.EDIT_ACCOUNT]: MutationHelpers.update,
};
export default {
namespaced: true,
state,
getters,
actions,
mutations,
};

View file

@ -0,0 +1,56 @@
import axios from 'axios';
import { actions, getters } from '../../accounts';
import * as types from '../../../mutation-types';
const accountData = {
id: 1,
name: 'Company one',
locale: 'en',
};
const commit = jest.fn();
global.axios = axios;
jest.mock('axios');
describe('#actions', () => {
describe('#get', () => {
it('sends correct actions if API is success', async () => {
axios.get.mockResolvedValue({ data: accountData });
await actions.get({ commit });
expect(commit.mock.calls).toEqual([
[types.default.SET_ACCOUNT_UI_FLAG, { isFetchingItem: true }],
[types.default.ADD_ACCOUNT, accountData],
[types.default.SET_ACCOUNT_UI_FLAG, { isFetchingItem: false }],
]);
});
it('sends correct actions if API is error', async () => {
axios.get.mockRejectedValue({ message: 'Incorrect header' });
await actions.get({ commit });
expect(commit.mock.calls).toEqual([
[types.default.SET_ACCOUNT_UI_FLAG, { isFetchingItem: true }],
[types.default.SET_ACCOUNT_UI_FLAG, { isFetchingItem: false }],
]);
});
});
describe('#update', () => {
it('sends correct actions if API is success', async () => {
axios.patch.mockResolvedValue();
await actions.update({ commit, getters }, accountData);
expect(commit.mock.calls).toEqual([
[types.default.SET_ACCOUNT_UI_FLAG, { isUpdating: true }],
[types.default.SET_ACCOUNT_UI_FLAG, { isUpdating: false }],
]);
});
it('sends correct actions if API is error', async () => {
axios.patch.mockRejectedValue({ message: 'Incorrect header' });
await expect(
actions.update({ commit, getters }, accountData)
).rejects.toThrow(Error);
expect(commit.mock.calls).toEqual([
[types.default.SET_ACCOUNT_UI_FLAG, { isUpdating: true }],
[types.default.SET_ACCOUNT_UI_FLAG, { isUpdating: false }],
]);
});
});
});

View file

@ -0,0 +1,32 @@
import { getters } from '../../accounts';
const accountData = {
id: 1,
name: 'Company one',
locale: 'en',
};
describe('#getters', () => {
it('getAccount', () => {
const state = {
records: [accountData],
};
expect(getters.getAccount(state)(1)).toEqual(accountData);
});
it('getUIFlags', () => {
const state = {
uiFlags: {
isFetching: true,
isCreating: false,
isUpdating: false,
isDeleting: false,
},
};
expect(getters.getUIFlags(state)).toEqual({
isFetching: true,
isCreating: false,
isUpdating: false,
isDeleting: false,
});
});
});

View file

@ -0,0 +1,30 @@
import * as types from '../../../mutation-types';
import { mutations } from '../../accounts';
const accountData = {
id: 1,
name: 'Company one',
locale: 'en',
};
describe('#mutations', () => {
describe('#ADD_ACCOUNT', () => {
it('push contact data to the store', () => {
const state = {
records: [],
};
mutations[types.default.ADD_ACCOUNT](state, accountData);
expect(state.records).toEqual([accountData]);
});
});
describe('#EDIT_ACCOUNT', () => {
it('update contact', () => {
const state = {
records: [{ ...accountData, locale: 'fr' }],
};
mutations[types.default.EDIT_ACCOUNT](state, accountData);
expect(state.records).toEqual([accountData]);
});
});
});

View file

@ -39,6 +39,13 @@ export default {
EDIT_INBOXES: 'EDIT_INBOXES',
DELETE_INBOXES: 'DELETE_INBOXES',
// Agent
SET_ACCOUNT_UI_FLAG: 'SET_ACCOUNT_UI_FLAG',
SET_ACCOUNTS: 'SET_ACCOUNTS',
ADD_ACCOUNT: 'ADD_ACCOUNT',
EDIT_ACCOUNT: 'EDIT_ACCOUNT',
DELETE_ACCOUNT: 'DELETE_AGENT',
// Agent
SET_AGENT_FETCHING_STATUS: 'SET_AGENT_FETCHING_STATUS',
SET_AGENT_CREATING_STATUS: 'SET_AGENT_CREATING_STATUS',

View file

@ -32,7 +32,7 @@ class Account < ApplicationRecord
has_one :subscription, dependent: :destroy
has_many :notification_settings, dependent: :destroy
enum locale: LANGUAGES_CONFIG.map { |key, val| [val[:iso_639_3_code], key] }.to_h
enum locale: LANGUAGES_CONFIG.map { |key, val| [val[:iso_639_1_code], key] }.to_h
after_create :create_subscription
after_create :notify_creation

View file

@ -2,17 +2,17 @@
# This Hash is used in account model, so do not change the index for existing languages
LANGUAGES_CONFIG = {
0 => { name: 'English', iso_639_3_code: 'eng' },
1 => { name: 'Arabic', iso_639_3_code: 'ara' },
2 => { name: 'Dutch', iso_639_3_code: 'nld' },
3 => { name: 'French', iso_639_3_code: 'fra' },
4 => { name: 'German', iso_639_3_code: 'deu' },
5 => { name: 'Hindi', iso_639_3_code: 'hin' },
6 => { name: 'Italian', iso_639_3_code: 'ita' },
7 => { name: 'Japanese', iso_639_3_code: 'jpn' },
8 => { name: 'Korean', iso_639_3_code: 'kor' },
9 => { name: 'Portugues', iso_639_3_code: 'por' },
10 => { name: 'Russian', iso_639_3_code: 'rus' },
11 => { name: 'Chinese', iso_639_3_code: 'zho' },
12 => { name: 'Spanish', iso_639_3_code: 'spa' }
0 => { name: 'English', iso_639_3_code: 'eng', iso_639_1_code: 'en' },
1 => { name: 'Arabic', iso_639_3_code: 'ara', iso_639_1_code: 'ar' },
2 => { name: 'Dutch', iso_639_3_code: 'nld', iso_639_1_code: 'nl' },
3 => { name: 'French', iso_639_3_code: 'fra', iso_639_1_code: 'fr' },
4 => { name: 'German', iso_639_3_code: 'deu', iso_639_1_code: 'de' },
5 => { name: 'Hindi', iso_639_3_code: 'hin', iso_639_1_code: 'hi' },
6 => { name: 'Italian', iso_639_3_code: 'ita', iso_639_1_code: 'it' },
7 => { name: 'Japanese', iso_639_3_code: 'jpn', iso_639_1_code: 'ja' },
8 => { name: 'Korean', iso_639_3_code: 'kor', iso_639_1_code: 'ko' },
9 => { name: 'Portugues', iso_639_3_code: 'por', iso_639_1_code: 'pt' },
10 => { name: 'Russian', iso_639_3_code: 'rus', iso_639_1_code: 'ru' },
11 => { name: 'Chinese', iso_639_3_code: 'zho', iso_639_1_code: 'zh' },
12 => { name: 'Spanish', iso_639_3_code: 'spa', iso_639_1_code: 'es' }
}.freeze

56
config/locales/de.yml Normal file
View file

@ -0,0 +1,56 @@
# Files in the config/locales directory are used for internationalization
# and are automatically loaded by Rails. If you want to use locales other
# than English, add the necessary files in this directory.
#
# To use the locales, use `I18n.t`:
#
# I18n.t 'hello'
#
# In views, this is aliased to just `t`:
#
# <%= t('hello') %>
#
# To use a different locale, set it with `I18n.locale`:
#
# I18n.locale = :es
#
# This would use the information in config/locales/es.yml.
#
# The following keys must be escaped otherwise they will not be retrieved by
# the default I18n backend:
#
# true, false, on, off, yes, no
#
# Instead, surround them with single quotes.
#
# en:
# 'true': 'foo'
#
# To learn more, please read the Rails Internationalization guide
# available at https://guides.rubyonrails.org/i18n.html.
de:
hello: "Hello world"
messages:
reset_password_success: Woot! Die Anforderung zum Zurücksetzen des Passworts ist erfolgreich. Überprüfen Sie Ihre E-Mails auf Anweisungen.
reset_password_failure: Uh ho! Wir konnten keinen Benutzer mit der angegebenen E-Mail-Adresse finden.
errors:
signup:
disposable_email: Wir erlauben keine Einweg-E-Mails
invalid_email: Sie haben eine ungültige E-Mail-Adresse eingegeben
email_already_exists: "Sie haben sich bereits für ein Konto bei %{email} angemeldet."
failed: Anmeldung gescheitert
conversations:
activity:
status:
resolved: "Das Gespräch wurde von gelöst gelöst %{user_name}"
open: "Das Gespräch wurde von wieder eröffnet %{user_name}"
assignee:
assigned: "%{user_name} von %{assignee_name} zugewiesen"
removed: "Gespräch nicht zugewiesen von %{user_name}"
templates:
typical_reply_message_body: "%{account_name} Antworten in der Regel in wenigen Stunden."
ways_to_reach_you_message_body: "Geben Sie dem Team einen Weg, Sie zu erreichen."
email_input_box_message_body: "Lassen Sie sich per E-Mail benachrichtigen"

View file

@ -132,7 +132,7 @@ RSpec.describe 'Accounts API', type: :request do
end
context 'when it is an authenticated user' do
params = { name: 'New Name', locale: 'ara' }
params = { name: 'New Name', locale: 'ar' }
it 'modifies an account' do
put "/api/v1/accounts/#{account.id}",