Merge branch 'develop' into live-agent-reports-controller
This commit is contained in:
@@ -14,6 +14,7 @@ import WootSnackbarBox from './components/SnackbarContainer.vue';
|
||||
import { setColorTheme } from './helper/themeHelper';
|
||||
import { isOnOnboardingView } from 'v3/helpers/RouteHelper';
|
||||
import { useAccount } from 'dashboard/composables/useAccount';
|
||||
import { useFontSize } from 'dashboard/composables/useFontSize';
|
||||
import {
|
||||
registerSubscription,
|
||||
verifyServiceWorkerExistence,
|
||||
@@ -37,8 +38,15 @@ export default {
|
||||
const router = useRouter();
|
||||
const store = useStore();
|
||||
const { accountId } = useAccount();
|
||||
// Use the font size composable (it automatically sets up the watcher)
|
||||
const { currentFontSize } = useFontSize();
|
||||
|
||||
return { router, store, currentAccountId: accountId };
|
||||
return {
|
||||
router,
|
||||
store,
|
||||
currentAccountId: accountId,
|
||||
currentFontSize,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -82,7 +82,7 @@ input[type='url']:not(.reset-base) {
|
||||
}
|
||||
|
||||
input[type='file'] {
|
||||
@apply bg-white dark:bg-slate-800 leading-[1.15] mb-4;
|
||||
@apply bg-white dark:bg-n-solid-1 leading-[1.15] mb-4;
|
||||
}
|
||||
|
||||
// Select
|
||||
@@ -141,11 +141,16 @@ code {
|
||||
@apply text-xs border-0;
|
||||
|
||||
&.hljs {
|
||||
@apply bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-50 rounded-lg p-5;
|
||||
@apply bg-n-slate-3 dark:bg-n-solid-3 text-slate-800 dark:text-slate-50 rounded-lg p-5;
|
||||
|
||||
.hljs-number,
|
||||
.hljs-string {
|
||||
@apply text-red-800 dark:text-red-400;
|
||||
}
|
||||
|
||||
.hljs-name,
|
||||
.hljs-tag {
|
||||
@apply text-n-slate-11;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ const handleButtonClick = () => {
|
||||
<template>
|
||||
<section class="flex flex-col w-full h-full overflow-hidden bg-n-background">
|
||||
<header class="sticky top-0 z-10 px-6 lg:px-0">
|
||||
<div class="w-full max-w-[960px] mx-auto">
|
||||
<div class="w-full max-w-[60rem] mx-auto">
|
||||
<div class="flex items-center justify-between w-full h-20 gap-2">
|
||||
<span class="text-xl font-medium text-n-slate-12">
|
||||
{{ headerTitle }}
|
||||
@@ -44,7 +44,7 @@ const handleButtonClick = () => {
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex-1 px-6 overflow-y-auto lg:px-0">
|
||||
<div class="w-full max-w-[960px] mx-auto py-4">
|
||||
<div class="w-full max-w-[60rem] mx-auto py-4">
|
||||
<slot name="default" />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ const handleSubmit = campaignDetails => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-[400px] z-50 min-w-0 absolute top-10 ltr:right-0 rtl:left-0 bg-n-alpha-3 backdrop-blur-[100px] p-6 rounded-xl border border-slate-50 dark:border-slate-900 shadow-md flex flex-col gap-6 max-h-[85vh] overflow-y-auto"
|
||||
class="w-[25rem] z-50 min-w-0 absolute top-10 ltr:right-0 rtl:left-0 bg-n-alpha-3 backdrop-blur-[100px] p-6 rounded-xl border border-slate-50 dark:border-slate-900 shadow-md flex flex-col gap-6 max-h-[85vh] overflow-y-auto"
|
||||
>
|
||||
<h3 class="text-base font-medium text-slate-900 dark:text-slate-50">
|
||||
{{ t(`CAMPAIGN.LIVE_CHAT.CREATE.TITLE`) }}
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ const handleClose = () => emit('close');
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-[400px] z-50 min-w-0 absolute top-10 ltr:right-0 rtl:left-0 bg-n-alpha-3 backdrop-blur-[100px] p-6 rounded-xl border border-slate-50 dark:border-slate-900 shadow-md flex flex-col gap-6"
|
||||
class="w-[25rem] z-50 min-w-0 absolute top-10 ltr:right-0 rtl:left-0 bg-n-alpha-3 backdrop-blur-[100px] p-6 rounded-xl border border-slate-50 dark:border-slate-900 shadow-md flex flex-col gap-6"
|
||||
>
|
||||
<h3 class="text-base font-medium text-slate-900 dark:text-slate-50">
|
||||
{{ t(`CAMPAIGN.SMS.CREATE.TITLE`) }}
|
||||
|
||||
@@ -65,8 +65,8 @@ const toggleBlock = () => {
|
||||
<div
|
||||
class="flex flex-col w-full h-full transition-all duration-300 ltr:2xl:ml-56 rtl:2xl:mr-56"
|
||||
>
|
||||
<header class="sticky top-0 z-10 px-6 xl:px-0">
|
||||
<div class="w-full mx-auto max-w-[650px]">
|
||||
<header class="sticky top-0 z-10 px-6 3xl:px-0">
|
||||
<div class="w-full mx-auto max-w-[40.625rem]">
|
||||
<div class="flex items-center justify-between w-full h-20 gap-2">
|
||||
<Breadcrumb
|
||||
:items="breadcrumbItems"
|
||||
@@ -98,8 +98,8 @@ const toggleBlock = () => {
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex-1 px-6 overflow-y-auto xl:px-px">
|
||||
<div class="w-full py-4 mx-auto max-w-[650px]">
|
||||
<main class="flex-1 px-6 overflow-y-auto 3xl:px-px">
|
||||
<div class="w-full py-4 mx-auto max-w-[40.625rem]">
|
||||
<slot name="default" />
|
||||
</div>
|
||||
</main>
|
||||
@@ -107,7 +107,7 @@ const toggleBlock = () => {
|
||||
|
||||
<div
|
||||
v-if="slots.sidebar"
|
||||
class="overflow-y-auto justify-end min-w-[200px] w-full py-6 max-w-[440px] border-l border-n-weak bg-n-solid-2"
|
||||
class="overflow-y-auto justify-end min-w-52 w-full py-6 max-w-md border-l border-n-weak bg-n-solid-2"
|
||||
>
|
||||
<slot name="sidebar" />
|
||||
</div>
|
||||
|
||||
@@ -60,7 +60,7 @@ const emit = defineEmits([
|
||||
<template>
|
||||
<header class="sticky top-0 z-10">
|
||||
<div
|
||||
class="flex items-center justify-between w-full h-20 px-6 gap-2 mx-auto max-w-[960px]"
|
||||
class="flex items-center justify-between w-full h-20 px-6 gap-2 mx-auto max-w-[60rem]"
|
||||
>
|
||||
<span class="text-xl font-medium truncate text-n-slate-12">
|
||||
{{ headerTitle }}
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ const activeFilterQueryData = computed(() => {
|
||||
t('CONTACTS_LAYOUT.FILTER.ACTIVE_FILTERS.CLEAR_FILTERS')
|
||||
"
|
||||
:show-clear-button="!hasActiveSegments"
|
||||
class="max-w-[960px] px-6"
|
||||
class="max-w-[60rem] px-6"
|
||||
@open-filter="emit('openFilter')"
|
||||
@clear-filters="emit('clearFilters')"
|
||||
/>
|
||||
|
||||
@@ -72,7 +72,7 @@ const openFilter = () => {
|
||||
@clear-filters="emit('clearFilters')"
|
||||
/>
|
||||
<main class="flex-1 overflow-y-auto">
|
||||
<div class="w-full mx-auto max-w-[960px]">
|
||||
<div class="w-full mx-auto max-w-[60rem]">
|
||||
<ContactsActiveFiltersPreview
|
||||
v-if="
|
||||
(hasAppliedFilters || !isNotSegmentView) &&
|
||||
|
||||
@@ -22,7 +22,7 @@ defineProps({
|
||||
class="relative flex flex-col items-center justify-center w-full h-full overflow-hidden"
|
||||
>
|
||||
<div
|
||||
class="relative w-full max-w-[960px] mx-auto overflow-hidden h-full max-h-[448px]"
|
||||
class="relative w-full max-w-[60rem] mx-auto overflow-hidden h-full max-h-[28rem]"
|
||||
>
|
||||
<div
|
||||
class="w-full h-full space-y-4 overflow-y-hidden opacity-50 pointer-events-none"
|
||||
|
||||
@@ -60,7 +60,7 @@ const togglePortalSwitcher = () => {
|
||||
<template>
|
||||
<section class="flex flex-col w-full h-full overflow-hidden bg-n-background">
|
||||
<header class="sticky top-0 z-10 px-6 pb-3 lg:px-0">
|
||||
<div class="w-full max-w-[960px] mx-auto lg:px-6">
|
||||
<div class="w-full max-w-[60rem] mx-auto lg:px-6">
|
||||
<div
|
||||
v-if="showHeaderTitle"
|
||||
class="flex items-center justify-start h-20 gap-2"
|
||||
@@ -96,7 +96,7 @@ const togglePortalSwitcher = () => {
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex-1 px-6 overflow-y-auto lg:px-0">
|
||||
<div class="w-full max-w-[960px] mx-auto py-3 lg:px-6">
|
||||
<div class="w-full max-w-[60rem] mx-auto py-3 lg:px-6">
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
+7
-7
@@ -52,7 +52,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col absolute w-[400px] bg-n-alpha-3 outline outline-1 outline-n-container backdrop-blur-[100px] shadow-lg gap-6 rounded-xl p-6"
|
||||
class="flex flex-col absolute w-[25rem] bg-n-alpha-3 outline outline-1 outline-n-container backdrop-blur-[100px] shadow-lg gap-6 rounded-xl p-6"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3>
|
||||
@@ -75,7 +75,7 @@ onMounted(() => {
|
||||
<div>
|
||||
<div class="flex justify-between w-full gap-4 py-2">
|
||||
<label
|
||||
class="text-sm font-medium whitespace-nowrap min-w-[100px] text-slate-900 dark:text-slate-50"
|
||||
class="text-sm font-medium whitespace-nowrap min-w-[6.25rem] text-slate-900 dark:text-slate-50"
|
||||
>
|
||||
{{
|
||||
t(
|
||||
@@ -90,9 +90,9 @@ onMounted(() => {
|
||||
'HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.META_DESCRIPTION_PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
class="w-[220px]"
|
||||
class="w-[13.75rem]"
|
||||
custom-text-area-wrapper-class="!p-0 !border-0 !rounded-none !bg-transparent transition-none"
|
||||
custom-text-area-class="max-h-[150px]"
|
||||
custom-text-area-class="max-h-[9.375rem]"
|
||||
auto-height
|
||||
min-height="3rem"
|
||||
/>
|
||||
@@ -108,12 +108,12 @@ onMounted(() => {
|
||||
:label="
|
||||
t('HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.META_TITLE')
|
||||
"
|
||||
custom-label-class="min-w-[120px]"
|
||||
custom-label-class="min-w-[7.5rem]"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-between w-full gap-3 py-2">
|
||||
<label
|
||||
class="text-sm font-medium whitespace-nowrap min-w-[120px] text-slate-900 dark:text-slate-50"
|
||||
class="text-sm font-medium whitespace-nowrap min-w-[7.5rem] text-slate-900 dark:text-slate-50"
|
||||
>
|
||||
{{
|
||||
t('HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.META_TAGS')
|
||||
@@ -126,7 +126,7 @@ onMounted(() => {
|
||||
'HELP_CENTER.EDIT_ARTICLE_PAGE.ARTICLE_PROPERTIES.META_TAGS_PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
class="w-[224px]"
|
||||
class="w-[14rem]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ const handleCategory = async formData => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-[400px] absolute top-10 ltr:right-0 rtl:left-0 bg-n-alpha-3 backdrop-blur-[100px] p-6 rounded-xl border border-slate-50 dark:border-slate-900 shadow-md flex flex-col gap-6"
|
||||
class="w-[25rem] absolute top-10 ltr:right-0 rtl:left-0 bg-n-alpha-3 backdrop-blur-[100px] p-6 rounded-xl border border-slate-50 dark:border-slate-900 shadow-md flex flex-col gap-6"
|
||||
>
|
||||
<h3 class="text-base font-medium text-slate-900 dark:text-slate-50">
|
||||
{{
|
||||
|
||||
+1
-1
@@ -201,7 +201,7 @@ defineExpose({ state, isSubmitDisabled });
|
||||
color="slate"
|
||||
size="sm"
|
||||
:icon="!state.icon ? 'i-lucide-smile-plus' : ''"
|
||||
class="!h-[38px] !w-[38px] absolute top-[31px] !outline-none !rounded-[7px] border-0 ltr:left-px rtl:right-px ltr:!rounded-r-none rtl:!rounded-l-none"
|
||||
class="!h-[2.4rem] !w-[2.375rem] absolute top-[1.94rem] !outline-none !rounded-[0.438rem] border-0 ltr:left-px rtl:right-px ltr:!rounded-r-none rtl:!rounded-l-none"
|
||||
@click="isEmojiPickerOpen = !isEmojiPickerOpen"
|
||||
/>
|
||||
<EmojiInput
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ const handleDeletePortal = () => {
|
||||
</div>
|
||||
<div
|
||||
v-else-if="activePortal"
|
||||
class="flex flex-col w-full gap-4 max-w-[640px] pb-8"
|
||||
class="flex flex-col w-full gap-4 max-w-[40rem] pb-8"
|
||||
>
|
||||
<PortalBaseSettings
|
||||
:active-portal="activePortal"
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ const redirectToPortalHomePage = () => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="pt-5 pb-3 bg-n-alpha-3 backdrop-blur-[100px] outline outline-n-container outline-1 z-50 absolute w-[440px] rounded-xl shadow-md flex flex-col gap-4"
|
||||
class="pt-5 pb-3 bg-n-alpha-3 backdrop-blur-[100px] outline outline-n-container outline-1 z-50 absolute w-[27.5rem] rounded-xl shadow-md flex flex-col gap-4"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-between gap-4 px-6 pb-3 border-b border-n-alpha-2"
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
createNewContact,
|
||||
fetchContactableInboxes,
|
||||
processContactableInboxes,
|
||||
mergeInboxDetails,
|
||||
} from 'dashboard/components-next/NewConversation/helpers/composeConversationHelper';
|
||||
|
||||
import ComposeNewConversationForm from 'dashboard/components-next/NewConversation/components/ComposeNewConversationForm.vue';
|
||||
@@ -47,6 +48,7 @@ const currentUser = useMapGetter('getCurrentUser');
|
||||
const globalConfig = useMapGetter('globalConfig/get');
|
||||
const uiFlags = useMapGetter('contactConversations/getUIFlags');
|
||||
const messageSignature = useMapGetter('getMessageSignature');
|
||||
const inboxesList = useMapGetter('inboxes/getInboxes');
|
||||
|
||||
const sendWithSignature = computed(() =>
|
||||
fetchSignatureFlagFromUISettings(targetInbox.value?.channelType)
|
||||
@@ -104,7 +106,12 @@ const handleSelectedContact = async ({ value, action, ...rest }) => {
|
||||
isFetchingInboxes.value = true;
|
||||
try {
|
||||
const contactableInboxes = await fetchContactableInboxes(contact.id);
|
||||
selectedContact.value.contactInboxes = contactableInboxes;
|
||||
// Merge the processed contactableInboxes with the inboxesList
|
||||
selectedContact.value.contactInboxes = mergeInboxDetails(
|
||||
contactableInboxes,
|
||||
inboxesList.value
|
||||
);
|
||||
|
||||
isFetchingInboxes.value = false;
|
||||
} catch (error) {
|
||||
isFetchingInboxes.value = false;
|
||||
@@ -162,9 +169,12 @@ watch(
|
||||
() => {
|
||||
if (activeContact.value && props.contactId) {
|
||||
const contactInboxes = activeContact.value?.contactInboxes || [];
|
||||
// First process the contactable inboxes to get the right structure
|
||||
const processedInboxes = processContactableInboxes(contactInboxes);
|
||||
// Then Merge processedInboxes with the inboxes list
|
||||
selectedContact.value = {
|
||||
...activeContact.value,
|
||||
contactInboxes: processContactableInboxes(contactInboxes),
|
||||
contactInboxes: mergeInboxDetails(processedInboxes, inboxesList.value),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
+1
-1
@@ -148,7 +148,7 @@ useKeyboardEvents(keyboardEvents);
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center justify-between w-full h-[52px] gap-2 px-4 py-3"
|
||||
class="flex items-center justify-between w-full h-[3.25rem] gap-2 px-4 py-3"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<WhatsAppOptions
|
||||
|
||||
+3
-3
@@ -47,10 +47,10 @@ const removeAttachment = id => {
|
||||
<div
|
||||
v-for="attachment in filteredImageAttachments"
|
||||
:key="attachment.id"
|
||||
class="relative group/image w-[72px] h-[72px]"
|
||||
class="relative group/image w-[4.5rem] h-[4.5rem]"
|
||||
>
|
||||
<img
|
||||
class="object-cover w-[72px] h-[72px] rounded-lg"
|
||||
class="object-cover w-[4.5rem] h-[4.5rem] rounded-lg"
|
||||
:src="attachment.thumb"
|
||||
/>
|
||||
<Button
|
||||
@@ -69,7 +69,7 @@ const removeAttachment = id => {
|
||||
<div
|
||||
v-for="attachment in filteredNonImageAttachments"
|
||||
:key="attachment.id"
|
||||
class="max-w-[300px] inline-flex items-center h-8 min-w-0 bg-n-alpha-2 dark:bg-n-solid-3 rounded-lg gap-3 ltr:pl-3 rtl:pr-3 ltr:pr-2 rtl:pl-2"
|
||||
class="max-w-[18.75rem] inline-flex items-center h-8 min-w-0 bg-n-alpha-2 dark:bg-n-solid-3 rounded-lg gap-3 ltr:pl-3 rtl:pr-3 ltr:pr-2 rtl:pl-2"
|
||||
>
|
||||
<span class="text-sm font-medium text-n-slate-11">
|
||||
{{ fileNameWithEllipsis(attachment.resource) }}
|
||||
|
||||
+1
-1
@@ -265,7 +265,7 @@ const handleSendWhatsappMessage = async ({ message, templateParams }) => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-[670px] mt-2 divide-y divide-n-strong overflow-visible transition-all duration-300 ease-in-out top-full justify-between flex flex-col bg-n-alpha-3 border border-n-strong shadow-sm backdrop-blur-[100px] rounded-xl"
|
||||
class="w-[42rem] mt-2 divide-y divide-n-strong overflow-visible transition-all duration-300 ease-in-out top-full justify-between flex flex-col bg-n-alpha-3 border border-n-strong shadow-sm backdrop-blur-[100px] rounded-xl"
|
||||
>
|
||||
<ContactSelector
|
||||
:contacts="contacts"
|
||||
|
||||
+15
@@ -87,6 +87,21 @@ export const processContactableInboxes = inboxes => {
|
||||
}));
|
||||
};
|
||||
|
||||
export const mergeInboxDetails = (inboxesData, inboxesList = []) => {
|
||||
if (!inboxesData || !inboxesData.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return inboxesData.map(inboxData => {
|
||||
const matchingInbox =
|
||||
inboxesList.find(inbox => inbox.id === inboxData.id) || {};
|
||||
return {
|
||||
...camelcaseKeys(matchingInbox, { deep: true }),
|
||||
...inboxData,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const prepareAttachmentPayload = (
|
||||
attachedFiles,
|
||||
directUploadsEnabled
|
||||
|
||||
+147
@@ -110,6 +110,153 @@ describe('composeConversationHelper', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('mergeInboxDetails', () => {
|
||||
it('returns empty array if inboxesData is empty or null', () => {
|
||||
expect(helpers.mergeInboxDetails(null)).toEqual([]);
|
||||
expect(helpers.mergeInboxDetails([])).toEqual([]);
|
||||
expect(helpers.mergeInboxDetails(undefined)).toEqual([]);
|
||||
});
|
||||
|
||||
it('merges inbox data with matching inboxes from the list', () => {
|
||||
const inboxesData = [
|
||||
{ id: 1, sourceId: 'source1' },
|
||||
{ id: 2, sourceId: 'source2' },
|
||||
];
|
||||
|
||||
const inboxesList = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Inbox 1',
|
||||
channel_type: 'Channel::Email',
|
||||
channel_id: 10,
|
||||
phone_number: null,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Inbox 2',
|
||||
channel_type: 'Channel::Whatsapp',
|
||||
channel_id: 20,
|
||||
phone_number: '+1234567890',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Inbox 3',
|
||||
channel_type: 'Channel::Api',
|
||||
channel_id: 30,
|
||||
phone_number: null,
|
||||
},
|
||||
];
|
||||
|
||||
const result = helpers.mergeInboxDetails(inboxesData, inboxesList);
|
||||
|
||||
expect(result.length).toBe(2);
|
||||
expect(result[0]).toMatchObject({
|
||||
id: 1,
|
||||
sourceId: 'source1',
|
||||
name: 'Inbox 1',
|
||||
channelType: 'Channel::Email',
|
||||
channelId: 10,
|
||||
phoneNumber: null,
|
||||
});
|
||||
|
||||
expect(result[1]).toMatchObject({
|
||||
id: 2,
|
||||
sourceId: 'source2',
|
||||
name: 'Inbox 2',
|
||||
channelType: 'Channel::Whatsapp',
|
||||
channelId: 20,
|
||||
phoneNumber: '+1234567890',
|
||||
});
|
||||
});
|
||||
|
||||
it('handles inboxes not found in the list', () => {
|
||||
const inboxesData = [
|
||||
{ id: 1, sourceId: 'source1' },
|
||||
{ id: 99, sourceId: 'source99' }, // This doesn't exist in inboxesList
|
||||
];
|
||||
|
||||
const inboxesList = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Inbox 1',
|
||||
channel_type: 'Channel::Email',
|
||||
},
|
||||
];
|
||||
|
||||
const result = helpers.mergeInboxDetails(inboxesData, inboxesList);
|
||||
|
||||
expect(result.length).toBe(2);
|
||||
|
||||
expect(result[0]).toMatchObject({
|
||||
id: 1,
|
||||
sourceId: 'source1',
|
||||
name: 'Inbox 1',
|
||||
channelType: 'Channel::Email',
|
||||
});
|
||||
|
||||
expect(result[1]).toMatchObject({
|
||||
id: 99,
|
||||
sourceId: 'source99',
|
||||
});
|
||||
|
||||
expect(result[1].name).toBeUndefined();
|
||||
expect(result[1].channelType).toBeUndefined();
|
||||
});
|
||||
|
||||
it('camelcases properties from inboxesList', () => {
|
||||
const inboxesData = [{ id: 1, sourceId: 'source1' }];
|
||||
|
||||
const inboxesList = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Inbox 1',
|
||||
channel_type: 'Channel::Email',
|
||||
avatar_url: 'https://example.com/avatar.png',
|
||||
working_hours: [
|
||||
{
|
||||
day_of_week: 1,
|
||||
closed_all_day: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const result = helpers.mergeInboxDetails(inboxesData, inboxesList);
|
||||
|
||||
expect(result[0]).toMatchObject({
|
||||
id: 1,
|
||||
sourceId: 'source1',
|
||||
name: 'Inbox 1',
|
||||
channelType: 'Channel::Email',
|
||||
avatarUrl: 'https://example.com/avatar.png',
|
||||
});
|
||||
|
||||
expect(result[0].workingHours[0]).toMatchObject({
|
||||
dayOfWeek: 1,
|
||||
closedAllDay: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('preserves original properties when they conflict with inboxesList', () => {
|
||||
const inboxesData = [
|
||||
{ id: 1, sourceId: 'source1', name: 'Original Name' },
|
||||
];
|
||||
|
||||
const inboxesList = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'List Name',
|
||||
channel_type: 'Channel::Email',
|
||||
},
|
||||
];
|
||||
|
||||
const result = helpers.mergeInboxDetails(inboxesData, inboxesList);
|
||||
|
||||
expect(result[0].name).toBe('Original Name');
|
||||
expect(result[0].channelType).toBe('Channel::Email');
|
||||
});
|
||||
});
|
||||
|
||||
describe('prepareAttachmentPayload', () => {
|
||||
it('prepares direct upload files', () => {
|
||||
const files = [{ blobSignedId: 'signed1' }];
|
||||
|
||||
@@ -99,45 +99,50 @@ const computedJustify = computed(() => {
|
||||
const STYLE_CONFIG = {
|
||||
colors: {
|
||||
blue: {
|
||||
solid: 'bg-n-brand text-white hover:brightness-110 outline-transparent',
|
||||
solid:
|
||||
'bg-n-brand text-white hover:enabled:brightness-110 outline-transparent',
|
||||
faded:
|
||||
'bg-n-brand/10 text-n-blue-text hover:bg-n-brand/20 outline-transparent',
|
||||
'bg-n-brand/10 text-n-blue-text hover:enabled:bg-n-brand/20 outline-transparent',
|
||||
outline: 'text-n-blue-text outline-n-blue-border',
|
||||
ghost: 'text-n-blue-text hover:bg-n-alpha-2 outline-transparent',
|
||||
link: 'text-n-blue-text hover:underline outline-transparent',
|
||||
ghost: 'text-n-blue-text hover:enabled:bg-n-alpha-2 outline-transparent',
|
||||
link: 'text-n-blue-text hover:enabled:underline outline-transparent',
|
||||
},
|
||||
ruby: {
|
||||
solid: 'bg-n-ruby-9 text-white hover:bg-n-ruby-10 outline-transparent',
|
||||
solid:
|
||||
'bg-n-ruby-9 text-white hover:enabled:bg-n-ruby-10 outline-transparent',
|
||||
faded:
|
||||
'bg-n-ruby-9/10 text-n-ruby-11 hover:bg-n-ruby-9/20 outline-transparent',
|
||||
outline: 'text-n-ruby-11 hover:bg-n-ruby-9/10 outline-n-ruby-8',
|
||||
ghost: 'text-n-ruby-11 hover:bg-n-alpha-2 outline-transparent',
|
||||
link: 'text-n-ruby-9 hover:underline outline-transparent',
|
||||
'bg-n-ruby-9/10 text-n-ruby-11 hover:enabled:bg-n-ruby-9/20 outline-transparent',
|
||||
outline: 'text-n-ruby-11 hover:enabled:bg-n-ruby-9/10 outline-n-ruby-8',
|
||||
ghost: 'text-n-ruby-11 hover:enabled:bg-n-alpha-2 outline-transparent',
|
||||
link: 'text-n-ruby-9 hover:enabled:underline outline-transparent',
|
||||
},
|
||||
amber: {
|
||||
solid: 'bg-n-amber-9 text-white hover:bg-n-amber-10 outline-transparent',
|
||||
solid:
|
||||
'bg-n-amber-9 text-white hover:enabled:bg-n-amber-10 outline-transparent',
|
||||
faded:
|
||||
'bg-n-amber-9/10 text-n-slate-12 hover:bg-n-amber-9/20 outline-transparent',
|
||||
outline: 'text-n-amber-11 hover:bg-n-amber-9/10 outline-n-amber-9',
|
||||
link: 'text-n-amber-9 hover:underline outline-transparent',
|
||||
ghost: 'text-n-amber-9 hover:bg-n-alpha-2 outline-transparent',
|
||||
'bg-n-amber-9/10 text-n-slate-12 hover:enabled:bg-n-amber-9/20 outline-transparent',
|
||||
outline:
|
||||
'text-n-amber-11 hover:enabled:bg-n-amber-9/10 outline-n-amber-9',
|
||||
link: 'text-n-amber-9 hover:enabled:underline outline-transparent',
|
||||
ghost: 'text-n-amber-9 hover:enabled:bg-n-alpha-2 outline-transparent',
|
||||
},
|
||||
slate: {
|
||||
solid:
|
||||
'bg-n-solid-3 dark:hover:bg-n-solid-2 hover:bg-n-alpha-2 text-n-slate-12 outline-n-container',
|
||||
'bg-n-solid-3 dark:hover:enabled:bg-n-solid-2 hover:enabled:bg-n-alpha-2 text-n-slate-12 outline-n-container',
|
||||
faded:
|
||||
'bg-n-slate-9/10 text-n-slate-12 hover:bg-n-slate-9/20 outline-transparent',
|
||||
outline: 'text-n-slate-11 outline-n-strong hover:bg-n-slate-9/10',
|
||||
link: 'text-n-slate-11 hover:text-n-slate-12 hover:underline outline-transparent',
|
||||
ghost: 'text-n-slate-12 hover:bg-n-alpha-2 outline-transparent',
|
||||
'bg-n-slate-9/10 text-n-slate-12 hover:enabled:bg-n-slate-9/20 outline-transparent',
|
||||
outline: 'text-n-slate-11 outline-n-strong hover:enabled:bg-n-slate-9/10',
|
||||
link: 'text-n-slate-11 hover:enabled:text-n-slate-12 hover:enabled:underline outline-transparent',
|
||||
ghost: 'text-n-slate-12 hover:enabled:bg-n-alpha-2 outline-transparent',
|
||||
},
|
||||
teal: {
|
||||
solid: 'bg-n-teal-9 text-white hover:bg-n-teal-10 outline-transparent',
|
||||
solid:
|
||||
'bg-n-teal-9 text-white hover:enabled:bg-n-teal-10 outline-transparent',
|
||||
faded:
|
||||
'bg-n-teal-9/10 text-n-slate-12 hover:bg-n-teal-9/20 outline-transparent',
|
||||
outline: 'text-n-teal-11 hover:bg-n-teal-9/10 outline-n-teal-9',
|
||||
link: 'text-n-teal-9 hover:underline outline-transparent',
|
||||
ghost: 'text-n-teal-9 hover:bg-n-alpha-2 outline-transparent',
|
||||
'bg-n-teal-9/10 text-n-slate-12 hover:enabled:bg-n-teal-9/20 outline-transparent',
|
||||
outline: 'text-n-teal-11 hover:enabled:bg-n-teal-9/10 outline-n-teal-9',
|
||||
link: 'text-n-teal-9 hover:enabled:underline outline-transparent',
|
||||
ghost: 'text-n-teal-9 hover:enabled:bg-n-alpha-2 outline-transparent',
|
||||
},
|
||||
},
|
||||
sizes: {
|
||||
@@ -171,7 +176,7 @@ const STYLE_CONFIG = {
|
||||
center: 'justify-center',
|
||||
end: 'justify-end',
|
||||
},
|
||||
base: 'inline-flex items-center min-w-0 gap-2 transition-all duration-200 ease-in-out border-0 rounded-lg outline-1 outline disabled:cursor-not-allowed disabled:pointer-events-none disabled:opacity-50',
|
||||
base: 'inline-flex items-center min-w-0 gap-2 transition-all duration-200 ease-in-out border-0 rounded-lg outline-1 outline disabled:opacity-50',
|
||||
};
|
||||
|
||||
const variantClasses = computed(() => {
|
||||
|
||||
@@ -68,7 +68,7 @@ const handlePageChange = event => {
|
||||
<template>
|
||||
<section class="flex flex-col w-full h-full overflow-hidden bg-n-background">
|
||||
<header class="sticky top-0 z-10 px-6 xl:px-0">
|
||||
<div class="w-full max-w-[960px] mx-auto">
|
||||
<div class="w-full max-w-[60rem] mx-auto">
|
||||
<div
|
||||
class="flex items-start lg:items-center justify-between w-full py-6 lg:py-0 lg:h-20 gap-4 lg:gap-2 flex-col lg:flex-row"
|
||||
>
|
||||
@@ -96,7 +96,7 @@ const handlePageChange = event => {
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex-1 px-6 overflow-y-auto xl:px-0">
|
||||
<div class="w-full max-w-[960px] mx-auto py-4">
|
||||
<div class="w-full max-w-[60rem] mx-auto py-4">
|
||||
<slot v-if="!showPaywall" name="controls" />
|
||||
<div
|
||||
v-if="isFetching"
|
||||
|
||||
@@ -27,7 +27,7 @@ const openBilling = () => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-full max-w-[960px] mx-auto h-full max-h-[448px] grid place-content-center"
|
||||
class="w-full max-w-[60rem] mx-auto h-full max-h-[448px] grid place-content-center"
|
||||
>
|
||||
<BasePaywallModal
|
||||
class="mx-auto"
|
||||
|
||||
@@ -63,7 +63,7 @@ const pageInfo = computed(() => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex justify-between h-12 w-full max-w-[957px] outline outline-n-container outline-1 -outline-offset-1 mx-auto bg-n-solid-2 rounded-xl py-2 ltr:pl-4 rtl:pr-4 ltr:pr-3 rtl:pl-3 items-center before:absolute before:inset-x-0 before:-top-4 before:bg-gradient-to-t before:from-n-background before:from-10% before:dark:from-0% before:to-transparent before:h-4 before:pointer-events-none"
|
||||
class="flex justify-between h-12 w-full max-w-[calc(60rem-3px)] outline outline-n-container outline-1 -outline-offset-1 mx-auto bg-n-solid-2 rounded-xl py-2 ltr:pl-4 rtl:pr-4 ltr:pr-3 rtl:pl-3 items-center before:absolute before:inset-x-0 before:-top-4 before:bg-gradient-to-t before:from-n-background before:from-10% before:dark:from-0% before:to-transparent before:h-4 before:pointer-events-none"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="min-w-0 text-sm font-normal line-clamp-1 text-n-slate-11">
|
||||
|
||||
@@ -185,7 +185,7 @@ watch(
|
||||
"
|
||||
trailing-icon
|
||||
:disabled="disabled"
|
||||
class="!h-[30px] top-1 !px-2 outline-0 !outline-none !rounded-lg border-0 ltr:!rounded-r-none rtl:!rounded-l-none"
|
||||
class="!h-[1.875rem] top-1 !px-2 outline-0 !outline-none !rounded-lg border-0 ltr:!rounded-r-none rtl:!rounded-l-none"
|
||||
@click="toggleCountryDropdown"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -515,7 +515,7 @@ const menuItems = computed(() => {
|
||||
|
||||
<template>
|
||||
<aside
|
||||
class="w-[200px] bg-n-solid-2 rtl:border-l ltr:border-r border-n-weak h-screen flex flex-col text-sm pb-1"
|
||||
class="w-[12.5rem] bg-n-solid-2 rtl:border-l ltr:border-r border-n-weak h-screen flex flex-col text-sm pb-1"
|
||||
>
|
||||
<section class="grid gap-2 mt-2 mb-4">
|
||||
<div class="flex items-center min-w-0 gap-2 px-2">
|
||||
|
||||
@@ -31,7 +31,7 @@ const shouldRenderComponent = computed(() => {
|
||||
:is="to ? 'router-link' : 'div'"
|
||||
:to="to"
|
||||
:title="label"
|
||||
class="flex h-8 items-center gap-2 px-2 py-1 rounded-lg max-w-[151px] hover:bg-gradient-to-r from-transparent via-n-slate-3/70 to-n-slate-3/70 group"
|
||||
class="flex h-8 items-center gap-2 px-2 py-1 rounded-lg max-w-[9.438rem] hover:bg-gradient-to-r from-transparent via-n-slate-3/70 to-n-slate-3/70 group"
|
||||
:class="{
|
||||
'n-blue-text bg-n-alpha-2 active': active,
|
||||
}"
|
||||
|
||||
@@ -27,7 +27,7 @@ const updateValue = () => {
|
||||
>
|
||||
<span class="sr-only">{{ t('SWITCH.TOGGLE') }}</span>
|
||||
<span
|
||||
class="absolute top-px left-0.5 h-3 w-3 transform rounded-full shadow-sm transition-transform duration-200 ease-in-out"
|
||||
class="absolute top-[0.07rem] left-0.5 h-3 w-3 transform rounded-full shadow-sm transition-transform duration-200 ease-in-out"
|
||||
:class="
|
||||
modelValue
|
||||
? 'translate-x-2.5 bg-white'
|
||||
|
||||
@@ -23,33 +23,34 @@ export default {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="ml-0 mr-0 flex py-8 w-full xl:w-3/4 flex-col xl:flex-row"
|
||||
class="ml-0 mr-0 py-8 w-full"
|
||||
:class="{
|
||||
'border-b border-solid border-slate-50 dark:border-slate-700/30':
|
||||
showBorder,
|
||||
'border-b border-solid border-n-weak/60 dark:border-n-weak': showBorder,
|
||||
}"
|
||||
>
|
||||
<div class="w-full xl:w-1/4 min-w-0 xl:max-w-[30%] pr-12">
|
||||
<p
|
||||
v-if="title"
|
||||
class="text-base text-woot-500 dark:text-woot-500 mb-0 font-medium"
|
||||
>
|
||||
{{ title }}
|
||||
</p>
|
||||
<p
|
||||
class="text-sm mb-2 text-slate-700 dark:text-slate-300 leading-5 tracking-normal mt-2"
|
||||
>
|
||||
<slot v-if="subTitle" name="subTitle">
|
||||
{{ subTitle }}
|
||||
</slot>
|
||||
</p>
|
||||
<p v-if="note">
|
||||
<span class="font-semibold">{{ $t('INBOX_MGMT.NOTE') }}</span>
|
||||
{{ note }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-full xl:w-1/2 min-w-0 xl:max-w-[50%]">
|
||||
<slot />
|
||||
<div class="grid grid-cols-1 lg:grid-cols-6 gap-6">
|
||||
<div class="col-span-2 xl:col-span-1">
|
||||
<p
|
||||
v-if="title"
|
||||
class="text-base text-woot-500 dark:text-woot-500 mb-0 font-medium"
|
||||
>
|
||||
{{ title }}
|
||||
</p>
|
||||
<p
|
||||
class="text-sm mb-2 text-slate-700 dark:text-slate-300 leading-5 tracking-normal mt-2"
|
||||
>
|
||||
<slot v-if="subTitle" name="subTitle">
|
||||
{{ subTitle }}
|
||||
</slot>
|
||||
</p>
|
||||
<p v-if="note">
|
||||
<span class="font-semibold">{{ $t('INBOX_MGMT.NOTE') }}</span>
|
||||
{{ note }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-span-4 lg:col-span-4 2xl:col-span-3">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -23,17 +23,16 @@ export default {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col min-w-[15rem] max-h-[21.25rem] max-w-[23.75rem] rounded-md border border-solid border-slate-75 dark:border-slate-600"
|
||||
class="flex flex-col min-w-[15rem] max-h-[21.25rem] max-w-[23.75rem] rounded-md border border-solid border-n-strong"
|
||||
:class="{
|
||||
'bg-woot-25 dark:bg-slate-700 border border-solid border-woot-300 dark:border-woot-400':
|
||||
'bg-woot-25 dark:bg-n-solid-2 border border-solid border-n-blue-border':
|
||||
active,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="flex justify-between items-center px-2 w-full h-10 bg-slate-50 dark:bg-slate-900 rounded-t-[5px] border-b border-solid border-slate-50 dark:border-slate-600"
|
||||
class="flex justify-between items-center rounded-t-md px-2 w-full h-10 bg-slate-50 dark:bg-slate-900 border-b border-solid border-n-strong"
|
||||
:class="{
|
||||
'bg-woot-50 border-b border-solid border-woot-75 dark:border-woot-700':
|
||||
active,
|
||||
'bg-woot-50 border-b border-solid border-n-blue-border': active,
|
||||
}"
|
||||
>
|
||||
<div class="flex items-center p-1 text-sm font-medium">{{ heading }}</div>
|
||||
|
||||
@@ -38,20 +38,20 @@ export default {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
height: 19px;
|
||||
height: 1.188rem;
|
||||
position: relative;
|
||||
transition-duration: 200ms;
|
||||
transition-property: background-color;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
width: 34px;
|
||||
width: 2.125rem;
|
||||
|
||||
&.active {
|
||||
background-color: var(--w-500);
|
||||
}
|
||||
|
||||
&.small {
|
||||
width: 22px;
|
||||
height: 14px;
|
||||
width: 1.375rem;
|
||||
height: 0.875rem;
|
||||
|
||||
span {
|
||||
height: var(--space-one);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { ref, provide, onMounted, computed } from 'vue';
|
||||
import { useEventListener } from '@vueuse/core';
|
||||
import { ref, useTemplateRef, provide, computed, watch } from 'vue';
|
||||
import { useElementSize } from '@vueuse/core';
|
||||
|
||||
const props = defineProps({
|
||||
index: {
|
||||
@@ -19,6 +19,12 @@ const props = defineProps({
|
||||
|
||||
const emit = defineEmits(['change']);
|
||||
|
||||
const tabsContainer = useTemplateRef('tabsContainer');
|
||||
const tabsList = useTemplateRef('tabsList');
|
||||
|
||||
const { width: containerWidth } = useElementSize(tabsContainer);
|
||||
const { width: listWidth } = useElementSize(tabsList);
|
||||
|
||||
const hasScroll = ref(false);
|
||||
|
||||
const activeIndex = computed({
|
||||
@@ -34,20 +40,16 @@ provide('updateActiveIndex', index => {
|
||||
});
|
||||
|
||||
const computeScrollWidth = () => {
|
||||
// TODO: use useElementSize from vueuse
|
||||
const tabElement = document.querySelector('.tabs');
|
||||
if (tabElement) {
|
||||
hasScroll.value = tabElement.scrollWidth > tabElement.clientWidth;
|
||||
if (tabsContainer.value && tabsList.value) {
|
||||
hasScroll.value = tabsList.value.scrollWidth > tabsList.value.clientWidth;
|
||||
}
|
||||
};
|
||||
|
||||
const onScrollClick = direction => {
|
||||
// TODO: use useElementSize from vueuse
|
||||
const tabElement = document.querySelector('.tabs');
|
||||
if (tabElement) {
|
||||
let scrollPosition = tabElement.scrollLeft;
|
||||
if (tabsContainer.value && tabsList.value) {
|
||||
let scrollPosition = tabsList.value.scrollLeft;
|
||||
scrollPosition += direction === 'left' ? -100 : 100;
|
||||
tabElement.scrollTo({
|
||||
tabsList.value.scrollTo({
|
||||
top: 0,
|
||||
left: scrollPosition,
|
||||
behavior: 'smooth',
|
||||
@@ -55,14 +57,19 @@ const onScrollClick = direction => {
|
||||
}
|
||||
};
|
||||
|
||||
useEventListener(window, 'resize', computeScrollWidth);
|
||||
onMounted(() => {
|
||||
computeScrollWidth();
|
||||
});
|
||||
// Watch for changes in element sizes with immediate execution
|
||||
watch(
|
||||
[containerWidth, listWidth],
|
||||
() => {
|
||||
computeScrollWidth();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
ref="tabsContainer"
|
||||
:class="{
|
||||
'tabs--container--with-border': border,
|
||||
'tabs--container--compact': isCompact,
|
||||
@@ -76,7 +83,7 @@ onMounted(() => {
|
||||
>
|
||||
<fluent-icon icon="chevron-left" :size="16" />
|
||||
</button>
|
||||
<ul :class="{ 'tabs--with-scroll': hasScroll }" class="tabs">
|
||||
<ul ref="tabsList" :class="{ 'tabs--with-scroll': hasScroll }" class="tabs">
|
||||
<slot />
|
||||
</ul>
|
||||
<button
|
||||
|
||||
@@ -72,26 +72,26 @@ export default {
|
||||
|
||||
&.active {
|
||||
h3 {
|
||||
@apply text-woot-500 dark:text-woot-500;
|
||||
@apply text-n-blue-text dark:text-n-blue-text;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
@apply bg-n-brand dark:bg-n-brand;
|
||||
}
|
||||
}
|
||||
|
||||
&.over {
|
||||
&::after {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
@apply bg-n-brand dark:bg-n-brand;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
@apply bg-n-brand dark:bg-n-brand;
|
||||
}
|
||||
|
||||
& + .item {
|
||||
&::before {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
@apply bg-n-brand dark:bg-n-brand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,10 +201,10 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.filter {
|
||||
@apply bg-slate-50 dark:bg-slate-800 p-2 border border-solid border-slate-75 dark:border-slate-600 rounded-md mb-2;
|
||||
@apply bg-n-slate-3 dark:bg-n-solid-3 p-2 border border-solid border-n-strong dark:border-n-strong rounded-md mb-2;
|
||||
|
||||
&.is-a-macro {
|
||||
@apply mb-0 bg-white dark:bg-slate-700 p-0 border-0 rounded-none;
|
||||
@apply mb-0 bg-n-slate-2 dark:bg-n-solid-3 p-0 border-0 rounded-none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ export default {
|
||||
getInputErrorClass(errorMessage) {
|
||||
return errorMessage
|
||||
? 'bg-red-50 dark:bg-red-800/50 border-red-100 dark:border-red-700/50'
|
||||
: 'bg-slate-50 dark:bg-slate-800 border-slate-75 dark:border-slate-700/50';
|
||||
: 'bg-n-slate-3 dark:bg-n-solid-3 border-n-strong dark:border-n-strong';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="pt-4 pb-0 px-8 border-b border-solid border-n-weak">
|
||||
<div class="pt-4 pb-0 px-8 border-b border-solid border-n-weak/60">
|
||||
<h2 class="text-2xl text-slate-800 dark:text-slate-100 mb-1 font-medium">
|
||||
{{ headerTitle }}
|
||||
</h2>
|
||||
|
||||
@@ -85,7 +85,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-between h-[52px] gap-2 ltr:pl-3 rtl:pr-3">
|
||||
<div class="flex justify-between h-[3.25rem] gap-2 ltr:pl-3 rtl:pr-3">
|
||||
<EditorModeToggle
|
||||
:mode="mode"
|
||||
class="mt-3"
|
||||
|
||||
@@ -411,7 +411,7 @@ export default {
|
||||
}
|
||||
|
||||
.checkbox-wrapper {
|
||||
@apply h-10 w-10 flex items-center justify-center rounded-full cursor-pointer mt-4;
|
||||
@apply flex items-center justify-center rounded-full cursor-pointer mt-4;
|
||||
|
||||
input[type='checkbox'] {
|
||||
@apply m-0 cursor-pointer;
|
||||
|
||||
@@ -53,7 +53,7 @@ const showCopilotTab = computed(() =>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="ltr:border-l rtl:border-r border-n-weak h-full overflow-hidden z-10 min-w-[320px] w-[320px] 2xl:min-w-96 2xl:w-96 flex flex-col bg-n-background"
|
||||
class="ltr:border-l rtl:border-r border-n-weak h-full overflow-hidden z-10 w-80 min-w-80 2xl:min-w-96 2xl:w-96 flex flex-col bg-n-background"
|
||||
>
|
||||
<div v-if="showCopilotTab" class="p-2">
|
||||
<TabBar
|
||||
|
||||
@@ -45,7 +45,7 @@ const statusDesiredOrder = [
|
||||
];
|
||||
|
||||
const isCreating = ref(false);
|
||||
const inputStyles = { borderRadius: '12px', fontSize: '14px' };
|
||||
const inputStyles = { borderRadius: '0.75rem', fontSize: '0.875rem' };
|
||||
|
||||
const formState = reactive({
|
||||
title: '',
|
||||
@@ -209,7 +209,7 @@ onMounted(getTeams);
|
||||
v-model="formState.title"
|
||||
:class="{ error: v$.title.$error }"
|
||||
class="w-full"
|
||||
:styles="{ ...inputStyles, padding: '6px 12px' }"
|
||||
:styles="{ ...inputStyles, padding: '0.375rem 0.75rem' }"
|
||||
:label="$t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.FORM.TITLE.LABEL')"
|
||||
:placeholder="
|
||||
$t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.FORM.TITLE.PLACEHOLDER')
|
||||
@@ -221,7 +221,7 @@ onMounted(getTeams);
|
||||
{{ $t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.FORM.DESCRIPTION.LABEL') }}
|
||||
<textarea
|
||||
v-model="formState.description"
|
||||
:style="{ ...inputStyles, padding: '8px 12px' }"
|
||||
:style="{ ...inputStyles, padding: '0.5rem 0.75rem' }"
|
||||
rows="3"
|
||||
class="text-sm"
|
||||
:placeholder="
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
import { ref } from 'vue';
|
||||
import { useFontSize } from '../useFontSize';
|
||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('dashboard/composables/useUISettings');
|
||||
vi.mock('dashboard/composables', () => ({
|
||||
useAlert: vi.fn(message => message),
|
||||
}));
|
||||
vi.mock('vue-i18n');
|
||||
|
||||
// Mock requestAnimationFrame
|
||||
global.requestAnimationFrame = vi.fn(cb => cb());
|
||||
|
||||
describe('useFontSize', () => {
|
||||
const mockUISettings = ref({
|
||||
font_size: '16px',
|
||||
});
|
||||
const mockUpdateUISettings = vi.fn().mockResolvedValue(undefined);
|
||||
const mockTranslate = vi.fn(key => key);
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Setup mocks
|
||||
useUISettings.mockReturnValue({
|
||||
uiSettings: mockUISettings,
|
||||
updateUISettings: mockUpdateUISettings,
|
||||
});
|
||||
|
||||
useI18n.mockReturnValue({
|
||||
t: mockTranslate,
|
||||
});
|
||||
|
||||
// Reset DOM state
|
||||
document.documentElement.style.removeProperty('font-size');
|
||||
|
||||
// Reset mockUISettings to default
|
||||
mockUISettings.value = { font_size: '16px' };
|
||||
});
|
||||
|
||||
it('returns fontSizeOptions with correct structure', () => {
|
||||
const { fontSizeOptions } = useFontSize();
|
||||
expect(fontSizeOptions).toHaveLength(6);
|
||||
expect(fontSizeOptions[0]).toHaveProperty('value');
|
||||
expect(fontSizeOptions[0]).toHaveProperty('label');
|
||||
|
||||
// Check specific options
|
||||
expect(fontSizeOptions.find(option => option.value === '16px')).toEqual({
|
||||
value: '16px',
|
||||
label:
|
||||
'PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.OPTIONS.DEFAULT',
|
||||
});
|
||||
|
||||
expect(fontSizeOptions.find(option => option.value === '14px')).toEqual({
|
||||
value: '14px',
|
||||
label:
|
||||
'PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.OPTIONS.SMALLER',
|
||||
});
|
||||
|
||||
expect(fontSizeOptions.find(option => option.value === '22px')).toEqual({
|
||||
value: '22px',
|
||||
label:
|
||||
'PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.OPTIONS.EXTRA_LARGE',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns currentFontSize from UI settings', () => {
|
||||
const { currentFontSize } = useFontSize();
|
||||
expect(currentFontSize.value).toBe('16px');
|
||||
|
||||
mockUISettings.value.font_size = '18px';
|
||||
expect(currentFontSize.value).toBe('18px');
|
||||
});
|
||||
|
||||
it('applies font size to document root correctly based on pixel values', () => {
|
||||
const { applyFontSize } = useFontSize();
|
||||
|
||||
applyFontSize('18px');
|
||||
expect(document.documentElement.style.fontSize).toBe('18px');
|
||||
|
||||
applyFontSize('14px');
|
||||
expect(document.documentElement.style.fontSize).toBe('14px');
|
||||
|
||||
applyFontSize('22px');
|
||||
expect(document.documentElement.style.fontSize).toBe('22px');
|
||||
|
||||
applyFontSize('16px');
|
||||
expect(document.documentElement.style.fontSize).toBe('16px');
|
||||
});
|
||||
|
||||
it('updates UI settings and applies font size', async () => {
|
||||
const { updateFontSize } = useFontSize();
|
||||
|
||||
await updateFontSize('20px');
|
||||
|
||||
expect(mockUpdateUISettings).toHaveBeenCalledWith({ font_size: '20px' });
|
||||
expect(document.documentElement.style.fontSize).toBe('20px');
|
||||
expect(useAlert).toHaveBeenCalledWith(
|
||||
'PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.UPDATE_SUCCESS'
|
||||
);
|
||||
});
|
||||
|
||||
it('shows error alert when update fails', async () => {
|
||||
mockUpdateUISettings.mockRejectedValueOnce(new Error('Update failed'));
|
||||
|
||||
const { updateFontSize } = useFontSize();
|
||||
await updateFontSize('20px');
|
||||
|
||||
expect(useAlert).toHaveBeenCalledWith(
|
||||
'PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.UPDATE_ERROR'
|
||||
);
|
||||
});
|
||||
|
||||
it('handles unknown font size values gracefully', () => {
|
||||
const { applyFontSize } = useFontSize();
|
||||
|
||||
// Should not throw an error and should apply the default font size
|
||||
applyFontSize('unknown-size');
|
||||
expect(document.documentElement.style.fontSize).toBe('16px');
|
||||
});
|
||||
|
||||
it('watches for UI settings changes and applies font size', async () => {
|
||||
useFontSize();
|
||||
|
||||
// Initial font size should now be 16px instead of empty
|
||||
expect(document.documentElement.style.fontSize).toBe('16px');
|
||||
|
||||
// Update UI settings
|
||||
mockUISettings.value = { font_size: '18px' };
|
||||
|
||||
// Wait for next tick to let watchers fire
|
||||
await Promise.resolve();
|
||||
|
||||
expect(document.documentElement.style.fontSize).toBe('18px');
|
||||
});
|
||||
|
||||
it('translates font size option labels correctly', () => {
|
||||
// Set up specific translation mapping
|
||||
mockTranslate.mockImplementation(key => {
|
||||
const translations = {
|
||||
'PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.OPTIONS.SMALLER':
|
||||
'Smaller',
|
||||
'PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.OPTIONS.DEFAULT':
|
||||
'Default',
|
||||
'PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.OPTIONS.EXTRA_LARGE':
|
||||
'Extra Large',
|
||||
};
|
||||
return translations[key] || key;
|
||||
});
|
||||
|
||||
const { fontSizeOptions } = useFontSize();
|
||||
|
||||
// Check that translation is applied
|
||||
expect(fontSizeOptions.find(option => option.value === '14px').label).toBe(
|
||||
'Smaller'
|
||||
);
|
||||
expect(fontSizeOptions.find(option => option.value === '16px').label).toBe(
|
||||
'Default'
|
||||
);
|
||||
expect(fontSizeOptions.find(option => option.value === '22px').label).toBe(
|
||||
'Extra Large'
|
||||
);
|
||||
|
||||
// Verify translation function was called with correct keys
|
||||
expect(mockTranslate).toHaveBeenCalledWith(
|
||||
'PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.OPTIONS.SMALLER'
|
||||
);
|
||||
expect(mockTranslate).toHaveBeenCalledWith(
|
||||
'PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.OPTIONS.DEFAULT'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* @file useFontSize.js
|
||||
* @description A composable for managing font size settings throughout the application.
|
||||
* This handles font size selection, application to the DOM, and persistence in user settings.
|
||||
*/
|
||||
|
||||
import { computed, watch } from 'vue';
|
||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
/**
|
||||
* Font size options with their pixel values
|
||||
* @type {Object}
|
||||
*/
|
||||
const FONT_SIZE_OPTIONS = {
|
||||
SMALLER: '14px',
|
||||
SMALL: '15px',
|
||||
DEFAULT: '16px',
|
||||
LARGE: '18px',
|
||||
LARGER: '20px',
|
||||
EXTRA_LARGE: '22px',
|
||||
};
|
||||
|
||||
/**
|
||||
* Array of font size option keys
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
const FONT_SIZE_NAMES = Object.keys(FONT_SIZE_OPTIONS);
|
||||
|
||||
/**
|
||||
* Get font size label translation key
|
||||
*
|
||||
* @param {string} name - Font size name
|
||||
* @returns {string} Translation key
|
||||
*/
|
||||
const getFontSizeLabelKey = name =>
|
||||
`PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.OPTIONS.${name}`;
|
||||
|
||||
/**
|
||||
* Create font size option object
|
||||
*
|
||||
* @param {Function} t - Translation function
|
||||
* @param {string} name - Font size name
|
||||
* @returns {Object} Font size option with value and label
|
||||
*/
|
||||
const createFontSizeOption = (t, name) => ({
|
||||
value: FONT_SIZE_OPTIONS[name],
|
||||
label: t(getFontSizeLabelKey(name)),
|
||||
});
|
||||
|
||||
/**
|
||||
* Apply font size value to document root
|
||||
*
|
||||
* @param {string} pixelValue - Font size value in pixels
|
||||
*/
|
||||
const applyFontSizeToDOM = pixelValue => {
|
||||
document.documentElement.style.setProperty(
|
||||
'font-size',
|
||||
pixelValue ?? FONT_SIZE_OPTIONS.DEFAULT
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Font size management composable
|
||||
*
|
||||
* @returns {Object} Font size utilities and state
|
||||
* @property {Array} fontSizeOptions - Array of font size options for select components
|
||||
* @property {import('vue').ComputedRef<string>} currentFontSize - Current font size from UI settings
|
||||
* @property {Function} applyFontSize - Function to apply font size to document
|
||||
* @property {Function} updateFontSize - Function to update font size in settings with alert feedback
|
||||
*/
|
||||
export const useFontSize = () => {
|
||||
const { uiSettings, updateUISettings } = useUISettings();
|
||||
const { t } = useI18n();
|
||||
|
||||
/**
|
||||
* Font size options for select dropdown
|
||||
* @type {Array<{value: string, label: string}>}
|
||||
*/
|
||||
const fontSizeOptions = FONT_SIZE_NAMES.map(name =>
|
||||
createFontSizeOption(t, name)
|
||||
);
|
||||
|
||||
/**
|
||||
* Current font size from UI settings
|
||||
* @type {import('vue').ComputedRef<string>}
|
||||
*/
|
||||
const currentFontSize = computed(
|
||||
() => uiSettings.value.font_size || FONT_SIZE_OPTIONS.DEFAULT
|
||||
);
|
||||
|
||||
/**
|
||||
* Apply font size to document root
|
||||
* @param {string} pixelValue - Font size in pixels (e.g., '16px')
|
||||
* @returns {void}
|
||||
*/
|
||||
const applyFontSize = pixelValue => {
|
||||
// Use requestAnimationFrame for better performance
|
||||
requestAnimationFrame(() => applyFontSizeToDOM(pixelValue));
|
||||
};
|
||||
|
||||
/**
|
||||
* Update font size in settings and apply to document
|
||||
* Shows success/error alerts
|
||||
* @param {string} pixelValue - Font size in pixels (e.g., '16px')
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const updateFontSize = async pixelValue => {
|
||||
try {
|
||||
await updateUISettings({ font_size: pixelValue });
|
||||
applyFontSize(pixelValue);
|
||||
useAlert(
|
||||
t('PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.UPDATE_SUCCESS')
|
||||
);
|
||||
} catch (error) {
|
||||
useAlert(
|
||||
t('PROFILE_SETTINGS.FORM.INTERFACE_SECTION.FONT_SIZE.UPDATE_ERROR')
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Watch for changes to the font size in UI settings
|
||||
watch(
|
||||
() => uiSettings.value.font_size,
|
||||
newSize => {
|
||||
applyFontSize(newSize);
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
return {
|
||||
fontSizeOptions,
|
||||
currentFontSize,
|
||||
applyFontSize,
|
||||
updateFontSize,
|
||||
};
|
||||
};
|
||||
|
||||
export default useFontSize;
|
||||
@@ -9,9 +9,9 @@ export const setColorTheme = isOSOnDarkMode => {
|
||||
selectedColorScheme === 'dark'
|
||||
) {
|
||||
document.body.classList.add('dark');
|
||||
document.documentElement.setAttribute('style', 'color-scheme: dark;');
|
||||
document.documentElement.style.setProperty('color-scheme', 'dark');
|
||||
} else {
|
||||
document.body.classList.remove('dark');
|
||||
document.documentElement.setAttribute('style', 'color-scheme: light;');
|
||||
document.documentElement.style.setProperty('color-scheme', 'light');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Contact details of <strong>{primaryContactName}</strong> will be copied to <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Merge contacts",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Message",
|
||||
"SEND_MESSAGE": "Send message",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Contacts"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Contact saved successfully",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Import contacts through a CSV file.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Mark as pending",
|
||||
"RESOLVED": "Mark as resolved",
|
||||
"MARK_AS_UNREAD": "Mark as unread",
|
||||
"MARK_AS_READ": "Mark as read",
|
||||
"REOPEN": "Reopen conversation",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Snooze",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Switch to Private Note",
|
||||
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "سيتم نسخ تفاصيل الاتصال من <strong>{primaryContactName}</strong> إلى <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "رسالة_خطأ"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " دمج جهات الاتصال",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "رسالة",
|
||||
"SEND_MESSAGE": "إرسال الرسالة",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "جهات الاتصال"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "تم حفظ جهة الاتصال بنجاح",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "تم إلغاء حجب جهة الاتصال بنجاح",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "استيراد جهات الاتصال من خلال ملف CSV.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "تحديد كمعلق",
|
||||
"RESOLVED": "تحديد كمحلولة",
|
||||
"MARK_AS_UNREAD": "وضع علامة كغير مقروء",
|
||||
"MARK_AS_READ": "تحديد كمقروء",
|
||||
"REOPEN": "إعادة فتح المحادثة",
|
||||
"SNOOZE": {
|
||||
"TITLE": "تأجيل",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "التبديل إلى الملاحظة الخاصة",
|
||||
"SWITCH_TO_REPLY": "التبديل إلى الرد",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "تبديل القائمة المنسدلة"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘\n",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Contact details of <strong>{primaryContactName}</strong> will be copied to <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Merge contacts",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Message",
|
||||
"SEND_MESSAGE": "Send message",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Contacts"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Contact saved successfully",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Import contacts through a CSV file.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Mark as pending",
|
||||
"RESOLVED": "Mark as resolved",
|
||||
"MARK_AS_UNREAD": "Mark as unread",
|
||||
"MARK_AS_READ": "Mark as read",
|
||||
"REOPEN": "Reopen conversation",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Snooze",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Switch to Private Note",
|
||||
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Детайлите на контакт <strong>{primaryContactName}</strong> ще бъдат копирани в <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ГРЕШКА"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Обединяване на контакти",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Съобщение",
|
||||
"SEND_MESSAGE": "Изпрати съобщение",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Контакти"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Успешно запазване на контакта",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Внасяне на контакти чрез CSV файл.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Mark as pending",
|
||||
"RESOLVED": "Mark as resolved",
|
||||
"MARK_AS_UNREAD": "Mark as unread",
|
||||
"MARK_AS_READ": "Mark as read",
|
||||
"REOPEN": "Reopen conversation",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Snooze",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Switch to Private Note",
|
||||
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Les dades de contacte de <strong>{primaryContactName}</strong> es copiaran a <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Fusiona contactes",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Missatge",
|
||||
"SEND_MESSAGE": "Envia missatge",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Contactes"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Contacte guardat correctament",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "Aquest contacte s'ha desbloquejat correctament",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Importa contactes a través d'un fitxer CSV.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Marca com a pendent",
|
||||
"RESOLVED": "Marca com a resolt",
|
||||
"MARK_AS_UNREAD": "Marca com a no llegit",
|
||||
"MARK_AS_READ": "Marca com a llegit",
|
||||
"REOPEN": "Torna a obrir la conversa",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Posposat",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Canvia a la nota privada",
|
||||
"SWITCH_TO_REPLY": "Canvia a Respon",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Commuta el menú desplegable de posposar"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Contact details of <strong>{primaryContactName}</strong> will be copied to <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Merge contacts",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Zpráva",
|
||||
"SEND_MESSAGE": "Send message",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Kontakty"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Kontakt byl úspěšně uložen",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Import contacts through a CSV file.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Označit jako nevyřízené",
|
||||
"RESOLVED": "Označit jako vyřešené",
|
||||
"MARK_AS_UNREAD": "Mark as unread",
|
||||
"MARK_AS_READ": "Mark as read",
|
||||
"REOPEN": "Znovu otevřít konverzaci",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Odložit",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Switch to Private Note",
|
||||
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Canned response added successfully.",
|
||||
"ERROR_MESSAGE": "Kunne ikke oprette forbindelse til Woot Server, Prøv igen senere."
|
||||
"ERROR_MESSAGE": "Kunne ikke oprette forbindelse til Woot server, Prøv igen senere."
|
||||
}
|
||||
},
|
||||
"EDIT": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"FAILED_TO_SEND": "Failed to send",
|
||||
"TAB_HEADING": "Samtaler",
|
||||
"MENTION_HEADING": "Omtaler",
|
||||
"UNATTENDED_HEADING": "Unattet",
|
||||
"UNATTENDED_HEADING": "Ubehandlet",
|
||||
"SEARCH": {
|
||||
"INPUT": "Søg efter Mennesker, Chats, Gemte svar .."
|
||||
},
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Kontaktoplysninger på <strong>{primaryContactName}</strong> vil blive kopieret til <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "FEJL_MEDDELELSE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Sammenflet kontakter",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Besked",
|
||||
"SEND_MESSAGE": "Send besked",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Kontakter"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Kontakt gemt med succes",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Importér kontakter via en CSV-fil.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Markér som afventende",
|
||||
"RESOLVED": "Marker som løst",
|
||||
"MARK_AS_UNREAD": "Marker som ulæst",
|
||||
"MARK_AS_READ": "Mark as read",
|
||||
"REOPEN": "Genåbn samtale",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Udsæt",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Skift til privat note",
|
||||
"SWITCH_TO_REPLY": "Skift til svar",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Skift snooze dropdown"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Vind / ¤",
|
||||
"ALT_OR_OPTION_KEY": "Alt. / ¤",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Details von Kontakt <strong>{primaryContactName}</strong> wird zu <strong>{parentContactName}</strong> kopiert."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Kontakte zusammenführen",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Nachricht",
|
||||
"SEND_MESSAGE": "Nachricht senden",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Kontakte"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Kontakt erfolgreich gespeichert",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "Dieser Kontakt wurde erfolgreich entsperrt",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Kontakte über CSV-Datei importieren.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Als ausstehend markieren",
|
||||
"RESOLVED": "Als gelöst markieren",
|
||||
"MARK_AS_UNREAD": "Als ungelesen markieren",
|
||||
"MARK_AS_READ": "Als gelesen markieren",
|
||||
"REOPEN": "Konversation wieder öffnen",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Erinnern",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Zu privaten Notizen wechseln",
|
||||
"SWITCH_TO_REPLY": "Zur Antwort wechseln",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Schlummer-Dropdown ein-/ausblenden"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Τα στοιχεία επικοινωνίας του <strong>{primaryContactName}</strong> θα αντιγραφούν στο <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Συγχώνευση επαφών",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Μήνυμα",
|
||||
"SEND_MESSAGE": "Αποστολή μηνύματος",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Επαφές"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Η επαφή αποθηκεύτηκε με επιτυχία",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Εισαγωγή επαφών μέσω αρχείου CSV.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Σήμανση ως εκκρεμής",
|
||||
"RESOLVED": "Σήμανση ως επιλυμένου",
|
||||
"MARK_AS_UNREAD": "Σήμανση ως μη αναγνωσμένο",
|
||||
"MARK_AS_READ": "Mark as read",
|
||||
"REOPEN": "Άνοιγμα συνομιλίας",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Αναβολή",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Αλλαγή σε Ιδιωτική Σημείωση",
|
||||
"SWITCH_TO_REPLY": "Εναλλαγή σε απάντηση",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Εναλλαγή αναβολής dropdown"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / °C.",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,6 +297,12 @@
|
||||
"TITLE": "Unlink",
|
||||
"SUCCESS": "Issue unlinked successfully",
|
||||
"ERROR": "There was an error unlinking the issue, please try again"
|
||||
},
|
||||
"DELETE": {
|
||||
"TITLE": "Are you sure you want to delete the integration?",
|
||||
"MESSAGE": "Are you sure you want to delete the integration?",
|
||||
"CONFIRM": "Yes, delete",
|
||||
"CANCEL": "Cancel"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -35,6 +35,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"INTERFACE_SECTION": {
|
||||
"TITLE": "Interface",
|
||||
"NOTE": "Customize the look and feel of your Chatwoot dashboard.",
|
||||
"FONT_SIZE": {
|
||||
"TITLE": "Font size",
|
||||
"NOTE": "Adjust the text size across the dashboard based on your preference.",
|
||||
"UPDATE_SUCCESS": "Your font settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the font settings, please try again",
|
||||
"OPTIONS": {
|
||||
"SMALLER": "Smaller",
|
||||
"SMALL": "Small",
|
||||
"DEFAULT": "Default",
|
||||
"LARGE": "Large",
|
||||
"LARGER": "Larger",
|
||||
"EXTRA_LARGE": "Extra Large"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
"TITLE": "Personal message signature",
|
||||
"NOTE": "Create a unique message signature to appear at the end of every message you send from any inbox. You can also include an inline image, which is supported in live-chat, email, and API inboxes.",
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
"CONTENT": "ha compartido una url"
|
||||
},
|
||||
"contact": {
|
||||
"CONTENT": "Shared contact"
|
||||
"CONTENT": "Contacto compartido"
|
||||
}
|
||||
},
|
||||
"CHAT_SORT_BY_FILTER": {
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Los datos de contacto de <strong>{primaryContactName}</strong> se copiarán en <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Combinar contactos",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Buscar...",
|
||||
"MESSAGE_BUTTON": "Mensaje",
|
||||
"SEND_MESSAGE": "Enviar mensaje",
|
||||
"BLOCK_CONTACT": "Bloquear contacto",
|
||||
"UNBLOCK_CONTACT": "Desbloquear contacto",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Contactos"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Contacto guardado correctamente",
|
||||
"ERROR_MESSAGE": "No se pudo guardar el contacto. Inténtalo de nuevo más tarde."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "Este contacto se ha bloqueado correctamente",
|
||||
"BLOCK_ERROR_MESSAGE": "No se pudo bloquear el contacto. Inténtalo de nuevo más tarde.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "Este contacto está desbloqueado correctamente",
|
||||
"UNBLOCK_ERROR_MESSAGE": "No se pudo desbloquear el contacto. Inténtalo de nuevo más tarde.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Importar contactos",
|
||||
"DESCRIPTION": "Importar contactos a través de un archivo CSV.",
|
||||
@@ -346,10 +352,10 @@
|
||||
"TITLE": "¿Desea guardar este filtro?",
|
||||
"CONFIRM": "Guardar filtro",
|
||||
"LABEL": "Nombre",
|
||||
"PLACEHOLDER": "Introduzca el nombre del filtro",
|
||||
"ERROR": "Introduzca un nombre válido",
|
||||
"PLACEHOLDER": "Ingrese el nombre del filtro",
|
||||
"ERROR": "Ingrese un nombre válido",
|
||||
"SUCCESS_MESSAGE": "Filtro guardado correctamente",
|
||||
"ERROR_MESSAGE": "No se puede guardar el filtro. Inténtalo de nuevo más tarde."
|
||||
"ERROR_MESSAGE": "No se pudo guardar el filtro. Inténtalo de nuevo más tarde."
|
||||
},
|
||||
"DELETE_SEGMENT": {
|
||||
"TITLE": "Confirmar eliminación",
|
||||
@@ -357,13 +363,13 @@
|
||||
"CONFIRM": "Sí, eliminar",
|
||||
"CANCEL": "No, cancelar",
|
||||
"SUCCESS_MESSAGE": "Filtro eliminado correctamente",
|
||||
"ERROR_MESSAGE": "No se puede eliminar el filtro. Inténtalo de nuevo más tarde."
|
||||
"ERROR_MESSAGE": "No se pudo eliminar el filtro. Inténtalo de nuevo más tarde."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PAGINATION_FOOTER": {
|
||||
"SHOWING": "Mostrando {startItem} - {endItem} de contactos {totalItems}"
|
||||
"SHOWING": "Mostrando {startItem} - {endItem} de {totalItems} contactos"
|
||||
},
|
||||
"FILTER": {
|
||||
"NAME": "Nombre",
|
||||
@@ -402,27 +408,27 @@
|
||||
"TITLE": "Editar detalles del contacto",
|
||||
"FORM": {
|
||||
"FIRST_NAME": {
|
||||
"PLACEHOLDER": "Introduzca el primer nombre"
|
||||
"PLACEHOLDER": "Ingrese el nombre"
|
||||
},
|
||||
"LAST_NAME": {
|
||||
"PLACEHOLDER": "Introduzca el apellido"
|
||||
"PLACEHOLDER": "Ingrese el apellido"
|
||||
},
|
||||
"EMAIL_ADDRESS": {
|
||||
"PLACEHOLDER": "Introduzca la dirección de correo electrónico",
|
||||
"PLACEHOLDER": "Ingrese el correo electrónico",
|
||||
"DUPLICATE": "Ésta dirección de correo está siendo utilizada por otro contacto."
|
||||
},
|
||||
"PHONE_NUMBER": {
|
||||
"PLACEHOLDER": "Introduzca el número de teléfono",
|
||||
"PLACEHOLDER": "Ingrese el número de teléfono",
|
||||
"DUPLICATE": "Este número de teléfono está en uso para otro contacto."
|
||||
},
|
||||
"CITY": {
|
||||
"PLACEHOLDER": "Introduzca el nombre de la ciudad"
|
||||
},
|
||||
"COUNTRY": {
|
||||
"PLACEHOLDER": "Seleccionar país"
|
||||
"PLACEHOLDER": "Seleccione el país"
|
||||
},
|
||||
"BIO": {
|
||||
"PLACEHOLDER": "Introduzca la biografía"
|
||||
"PLACEHOLDER": "Ingrese la biografía"
|
||||
},
|
||||
"COMPANY_NAME": {
|
||||
"PLACEHOLDER": "Escriba el nombre de la empresa"
|
||||
@@ -430,25 +436,25 @@
|
||||
},
|
||||
"UPDATE_BUTTON": "Actualizar contacto",
|
||||
"SUCCESS_MESSAGE": "Contacto actualizado correctamente",
|
||||
"ERROR_MESSAGE": "No se puede actualizar el contacto. Inténtalo de nuevo más tarde."
|
||||
"ERROR_MESSAGE": "No se pudo actualizar el contacto. Inténtalo de nuevo más tarde."
|
||||
},
|
||||
"SOCIAL_MEDIA": {
|
||||
"TITLE": "Editar enlaces de redes sociales",
|
||||
"FORM": {
|
||||
"FACEBOOK": {
|
||||
"PLACEHOLDER": "Añadir Facebook"
|
||||
"PLACEHOLDER": "Agregar Facebook"
|
||||
},
|
||||
"GITHUB": {
|
||||
"PLACEHOLDER": "Añadir Github"
|
||||
"PLACEHOLDER": "Agregar Github"
|
||||
},
|
||||
"INSTAGRAM": {
|
||||
"PLACEHOLDER": "Añadir Instagram"
|
||||
"PLACEHOLDER": "Agregar Instagram"
|
||||
},
|
||||
"LINKEDIN": {
|
||||
"PLACEHOLDER": "Añadir LinkedIn"
|
||||
"PLACEHOLDER": "Agregar LinkedIn"
|
||||
},
|
||||
"TWITTER": {
|
||||
"PLACEHOLDER": "Añadir Twitter/X"
|
||||
"PLACEHOLDER": "Agregar Twitter/X"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Marcar como pendiente",
|
||||
"RESOLVED": "Marcar como resuelto",
|
||||
"MARK_AS_UNREAD": "Marcar como no leído",
|
||||
"MARK_AS_READ": "Marcar como leído",
|
||||
"REOPEN": "Resolver conversación",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Posponer",
|
||||
@@ -134,7 +135,7 @@
|
||||
"FAILED": "No se pudo asignar el agente. Por favor, inténtelo de nuevo."
|
||||
},
|
||||
"LABEL_ASSIGNMENT": {
|
||||
"SUCCESFUL": "Etiqueta asignada #{labelName} a la conversación con id {conversationId}",
|
||||
"SUCCESFUL": "Etiqueta #{labelName} asignada a la conversación con id {conversationId}",
|
||||
"FAILED": "No se pudo asignar el agente. Por favor, inténtelo de nuevo."
|
||||
},
|
||||
"TEAM_ASSIGNMENT": {
|
||||
@@ -358,6 +359,6 @@
|
||||
"TRY_THESE_PROMPTS": "Prueba estas sugerencias"
|
||||
},
|
||||
"GALLERY_VIEW": {
|
||||
"ERROR_DOWNLOADING": "No se puede descargar el archivo adjunto. Por favor, inténtelo de nuevo"
|
||||
"ERROR_DOWNLOADING": "No se pudo descargar el archivo adjunto. Por favor, inténtelo de nuevo"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"BUTTON_TEXT": "Desconectar"
|
||||
},
|
||||
"SIDEBAR_DESCRIPTION": {
|
||||
"DIALOGFLOW": "Dialogflow is a natural language understanding platform that makes it easy to design and integrate a conversational user interface into your mobile app, web application, device, bot, interactive voice response system, and so on. <br /> <br /> Dialogflow integration with {installationName} allows you to configure a Dialogflow bot with your inboxes which lets the bot handle the queries initially and hand them over to an agent when needed. Dialogflow can be used to qualifying the leads, reduce the workload of agents by providing frequently asked questions etc. <br /> <br /> To add Dialogflow, you need to create a Service Account in your Google project console and share the credentials. Please refer to the Dialogflow docs for more information."
|
||||
"DIALOGFLOW": "Dialogflow es una plataforma de comprensión del lenguaje natural que facilita el diseño e integración de una interfaz de usuario conversacional en su aplicación móvil, aplicación web, dispositivo, bot, sistema interactivo de respuesta de voz, etc. <br /> <br /> La integración de Dialogflow con {installationName} le permite configurar un bot de Dialogflow con sus bandejas de entrada que permite al bot manejar las consultas inicialmente y entregarlas a un agente cuando sea necesario. Dialogflow se puede utilizar para calificar a los clientes potenciales, reducir la carga de trabajo de los agentes proporcionando preguntas frecuentes, etc. <br /> <br /> Para añadir Dialogflow, necesita crear una cuenta de servicio en la consola del proyecto de Google y compartir las credenciales. Consulte la documentación de Dialogflow para obtener más información."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"INTEGRATION_SETTINGS": {
|
||||
"HEADER": "Integraciones",
|
||||
"DESCRIPTION": "Chatwoot integrates with multiple tools and services to improve your team's efficiency. Explore the list below to configure your favorite apps.",
|
||||
"DESCRIPTION": "Chatwoot se integra con múltiples herramientas y servicios para mejorar la eficiencia de tu equipo. Explora la lista de abajo para configurar tus aplicaciones favoritas.",
|
||||
"LEARN_MORE": "Más información acerca de integraciones",
|
||||
"LOADING": "Obteniendo integraciones",
|
||||
"CAPTAIN": {
|
||||
@@ -12,7 +12,7 @@
|
||||
},
|
||||
"WEBHOOK": {
|
||||
"SUBSCRIBED_EVENTS": "Eventos suscritos",
|
||||
"LEARN_MORE": "Learn more about webhooks",
|
||||
"LEARN_MORE": "Aprenda más sobre webhooks",
|
||||
"FORM": {
|
||||
"CANCEL": "Cancelar",
|
||||
"DESC": "Los eventos Webhook te proporcionan la información en tiempo real sobre lo que está sucediendo en tu cuenta de Chatwoot. Por favor, introduce una URL válida para configurar un callback.",
|
||||
@@ -31,7 +31,7 @@
|
||||
},
|
||||
"END_POINT": {
|
||||
"LABEL": "URL de Webhook",
|
||||
"PLACEHOLDER": "Example: {webhookExampleURL}",
|
||||
"PLACEHOLDER": "Ejemplo: {webhookExampleURL}",
|
||||
"ERROR": "Por favor, introduzca una URL válida"
|
||||
},
|
||||
"EDIT_SUBMIT": "Actualizar webhook",
|
||||
@@ -90,7 +90,7 @@
|
||||
},
|
||||
"HELP_TEXT": {
|
||||
"TITLE": "¿Cómo utilizar la Integración Slack?",
|
||||
"BODY": "With this integration, all of your incoming conversations will be synced to the ***{selectedChannelName}*** channel in your Slack workspace. You can manage all your customer conversations right within the channel and never miss a message.\n\nHere are the main features of the integration:\n\n**Respond to conversations from within Slack:** To respond to a conversation in the ***{selectedChannelName}*** Slack channel, simply type out your message and send it as a thread. This will create a response back to the customer through Chatwoot. It's that simple!\n\n **Create private notes:** If you want to create private notes instead of replies, start your message with ***`note:`***. This ensures that your message is kept private and won't be visible to the customer.\n\n**Associate an agent profile:** If the person who replied on Slack has an agent profile in Chatwoot under the same email, the replies will be associated with that agent profile automatically. This means you can easily track who said what and when. On the other hand, when the replier doesn't have an associated agent profile, the replies will appear from the bot profile to the customer.",
|
||||
"BODY": "Con esta integración, todas tus conversaciones entrantes serán sincronizadas con el canal ***{selectedChannelName}*** en tu espacio de trabajo en Slack. Puedes administrar todas tus conversaciones con los clientes directamente en tu canal y nunca perder un mensaje.\n\nEstas son las principales características de la integración:\n\n**Responda a conversaciones desde Slack:** Para responder a una conversación en el canal Slack ***{selectedChannelName}***, simplemente escriba el mensaje y envíalo como un hilo. Esto creará una respuesta que se enviará al cliente mediante Chatwoot. ¡Es así de simple!\n\n**Crea notas privadas:** Si quieres crear una nota privada en lugar de una respuesta, comience su mensaje con ***`note:`***. Esto asegurará que tu mensaje se mantenga privado y no será visible al cliente.\n\n**Asociar un perfil de agente:** Si la persona que responde en Slack tiene un agente de perfil en Chatwoot bajo el mismo correo electrónico, las respuestas serán asociadas con ese perfil de agente automáticamente. Esto quiere decir que puedes fácilmente estar al tanto de quién dijo qué y cuándo. Por el otro lado, cuando la persona que responde no tiene un perfil de agente, las respuestas aparecerán desde el perfil de bot al cliente.",
|
||||
"SELECTED": "seleccionado"
|
||||
},
|
||||
"SELECT_CHANNEL": {
|
||||
@@ -114,7 +114,7 @@
|
||||
},
|
||||
"OPEN_AI": {
|
||||
"AI_ASSIST": "Asistencia AI",
|
||||
"WITH_AI": " {option} with AI ",
|
||||
"WITH_AI": " {option} con IA ",
|
||||
"OPTIONS": {
|
||||
"REPLY_SUGGESTION": "Responder sugerencia",
|
||||
"SUMMARIZE": "Resumir",
|
||||
@@ -233,13 +233,13 @@
|
||||
"EMPTY_LIST": "No se encontraron problemas lineales",
|
||||
"LOADING": "Cargando",
|
||||
"ERROR": "Hubo un error al recuperar los problemas lineales, por favor inténtalo de nuevo",
|
||||
"LINK_SUCCESS": "Issue linked successfully",
|
||||
"LINK_ERROR": "There was an error linking the issue, please try again",
|
||||
"LINK_TITLE": "Conversation (#{conversationId}) with {name}"
|
||||
"LINK_SUCCESS": "Incidencia enlazada correctamente",
|
||||
"LINK_ERROR": "Ocurrió un error al enlazar la incidencia. Inténtelo de nuevo",
|
||||
"LINK_TITLE": "Conversación (#{conversationId}) con {name}"
|
||||
},
|
||||
"ADD_OR_LINK": {
|
||||
"TITLE": "Create/link linear issue",
|
||||
"DESCRIPTION": "Create Linear issues from conversations, or link existing ones for seamless tracking.",
|
||||
"TITLE": "Crear/enlazar incidencia con Linear",
|
||||
"DESCRIPTION": "Crear incidencias en Linear desde conversaciones, o enlazar existentes para un seguimiento fluido.",
|
||||
"FORM": {
|
||||
"TITLE": {
|
||||
"LABEL": "Título",
|
||||
@@ -284,17 +284,17 @@
|
||||
},
|
||||
"CREATE": "Crear",
|
||||
"CANCEL": "Cancelar",
|
||||
"CREATE_SUCCESS": "Issue created successfully",
|
||||
"CREATE_ERROR": "There was an error creating the issue, please try again",
|
||||
"LOADING_TEAM_ERROR": "There was an error fetching the teams, please try again",
|
||||
"LOADING_TEAM_ENTITIES_ERROR": "There was an error fetching the team entities, please try again"
|
||||
"CREATE_SUCCESS": "Incidencia creada correctamente",
|
||||
"CREATE_ERROR": "Hubo un error creando la incidencia. Inténtalo de nuevo",
|
||||
"LOADING_TEAM_ERROR": "Hubo un error al coger los equipos. Inténtalo de nuevo",
|
||||
"LOADING_TEAM_ENTITIES_ERROR": "Hubo un error al coger las entidades del equipo. Inténtalo de nuevo"
|
||||
},
|
||||
"ISSUE": {
|
||||
"STATUS": "Estado",
|
||||
"PRIORITY": "Prioridad",
|
||||
"ASSIGNEE": "Cesionario",
|
||||
"LABELS": "Etiquetas",
|
||||
"CREATED_AT": "Created at {createdAt}"
|
||||
"CREATED_AT": "Creado en {createdAt}"
|
||||
},
|
||||
"UNLINK": {
|
||||
"TITLE": "Desenlazar",
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
"CONVERSATIONS": "Conversaciones",
|
||||
"MESSAGES": "Mensajes"
|
||||
},
|
||||
"VIEW_MORE": "View more",
|
||||
"LOAD_MORE": "Load more",
|
||||
"VIEW_MORE": "Ver más",
|
||||
"LOAD_MORE": "Cargar más",
|
||||
"SEARCHING_DATA": "Buscando",
|
||||
"LOADING_DATA": "Cargando",
|
||||
"EMPTY_STATE": "Ningún {item} encontrado para la consulta '{query}'",
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
"CHANGE_AVAILABILITY_STATUS": "Cambiar",
|
||||
"CHANGE_ACCOUNTS": "Cambiar de cuenta",
|
||||
"SWITCH_ACCOUNT": "Cambiar de cuenta",
|
||||
"CONTACT_SUPPORT": "Contactar al soporte",
|
||||
"CONTACT_SUPPORT": "Contactar a soporte",
|
||||
"SELECTOR_SUBTITLE": "Seleccione una cuenta de la siguiente lista",
|
||||
"PROFILE_SETTINGS": "Ajustes del perfil",
|
||||
"KEYBOARD_SHORTCUTS": "Atajos de teclado",
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Cambiar a nota privada",
|
||||
"SWITCH_TO_REPLY": "Cambiar a respuesta",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Cambiar el menú desplegable"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Windows / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt \\ ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "اطلاعات مخاطب <strong>{primaryContactName}</strong> کپی شود به <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " ادغام مخاطبین",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "پیام",
|
||||
"SEND_MESSAGE": "ارسال پیام",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "مخاطبین"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "مخاطب با موفقیت ذخیره شد",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "مخاطب با موفقیت رفع نسداد شد",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "مخاطبین را از طریق یک فایل CSV وارد کنید.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "علامت گذاری به عنوان در انتظار",
|
||||
"RESOLVED": "علامت زدن به عنوان حل شده",
|
||||
"MARK_AS_UNREAD": "علامت گذاری به عنوان خوانده نشده",
|
||||
"MARK_AS_READ": "ثبت به عنوان خوانده شده",
|
||||
"REOPEN": "مکالمه را دوباره باز کنید",
|
||||
"SNOOZE": {
|
||||
"TITLE": "به تعویق انداختن",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "رفتن به یادداشت خصوصی",
|
||||
"SWITCH_TO_REPLY": "رفتن به پاسخ",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "تغییر حالت بازکردن تعویق"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Contact details of <strong>{primaryContactName}</strong> will be copied to <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Yhdistä yhteystiedot",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Viesti",
|
||||
"SEND_MESSAGE": "Lähetä viesti",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Yhteystiedot"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Kontakti tallennettu onnistuneesti",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Import contacts through a CSV file.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Mark as pending",
|
||||
"RESOLVED": "Mark as resolved",
|
||||
"MARK_AS_UNREAD": "Mark as unread",
|
||||
"MARK_AS_READ": "Mark as read",
|
||||
"REOPEN": "Avaa keskustelu uudelleen",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Snooze",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Switch to Private Note",
|
||||
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Les coordonnées de <strong>{primaryContactName}</strong> seront copiées vers <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Fusionner les contacts",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Message",
|
||||
"SEND_MESSAGE": "Envoyer un message",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Contacts"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Contact enregistré avec succès",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Importer des contacts via un fichier CSV.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Marquer comme en attente",
|
||||
"RESOLVED": "Marquer comme résolu",
|
||||
"MARK_AS_UNREAD": "Marquer comme non lu",
|
||||
"MARK_AS_READ": "Marquer comme lu",
|
||||
"REOPEN": "Reprendre la conversation",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Reporter",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Basculer vers une note privée",
|
||||
"SWITCH_TO_REPLY": "Basculer vers la réponse",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Activer/désactiver la liste déroulante de répétition"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "פרטי הקשר של <strong>{primaryContactName}</strong> יועתקו אל <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "הודעת שגיאה"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " מזג אנשי קשר",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "הודעה",
|
||||
"SEND_MESSAGE": "שלח הודעה",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "איש קשר"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "איש הקשר נשמר בהצלחה",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "ייבא אנשי קשר באמצעות קובץ CSV.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "סמן כממתין",
|
||||
"RESOLVED": "סמן כפתור",
|
||||
"MARK_AS_UNREAD": "סמן כלא נקרא",
|
||||
"MARK_AS_READ": "Mark as read",
|
||||
"REOPEN": "פתח מחדש את השיחה",
|
||||
"SNOOZE": {
|
||||
"TITLE": "נודניק",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "עבור להערה פרטית",
|
||||
"SWITCH_TO_REPLY": "עבור לתשובה",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "החלפת תפריט נודניק"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "נצח / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Contact details of <strong>{primaryContactName}</strong> will be copied to <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Merge contacts",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Message",
|
||||
"SEND_MESSAGE": "Send message",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Contacts"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Contact saved successfully",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Import contacts through a CSV file.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Mark as pending",
|
||||
"RESOLVED": "Mark as resolved",
|
||||
"MARK_AS_UNREAD": "Mark as unread",
|
||||
"MARK_AS_READ": "Mark as read",
|
||||
"REOPEN": "Reopen conversation",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Snooze",
|
||||
|
||||
@@ -389,11 +389,6 @@
|
||||
"SWITCH_TO_PRIVATE_NOTE": "Switch to Private Note",
|
||||
"SWITCH_TO_REPLY": "Switch to Reply",
|
||||
"TOGGLE_SNOOZE_DROPDOWN": "Toggle snooze dropdown"
|
||||
},
|
||||
"KEYS": {
|
||||
"WINDOWS_KEY_AND_COMMAND_KEY": "Win / ⌘",
|
||||
"ALT_OR_OPTION_KEY": "Alt / ⌥",
|
||||
"FORWARD_SLASH_KEY": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
"ATTRIBUTE_WARNING": "Contact details of <strong>{primaryContactName}</strong> will be copied to <strong>{parentContactName}</strong>."
|
||||
},
|
||||
"SEARCH": {
|
||||
"ERROR": "ERROR_MESSAGE"
|
||||
"ERROR_MESSAGE": "Something went wrong. Please try again later."
|
||||
},
|
||||
"FORM": {
|
||||
"SUBMIT": " Merge contacts",
|
||||
@@ -288,6 +288,8 @@
|
||||
"SEARCH_PLACEHOLDER": "Search...",
|
||||
"MESSAGE_BUTTON": "Poruka",
|
||||
"SEND_MESSAGE": "Send message",
|
||||
"BLOCK_CONTACT": "Block contact",
|
||||
"UNBLOCK_CONTACT": "Unblock contact",
|
||||
"BREADCRUMB": {
|
||||
"CONTACTS": "Kontakti"
|
||||
},
|
||||
@@ -302,6 +304,10 @@
|
||||
"SUCCESS_MESSAGE": "Contact saved successfully",
|
||||
"ERROR_MESSAGE": "Unable to save contact. Please try again later."
|
||||
},
|
||||
"BLOCK_SUCCESS_MESSAGE": "This contact is blocked successfully",
|
||||
"BLOCK_ERROR_MESSAGE": "Unable to block contact. Please try again later.",
|
||||
"UNBLOCK_SUCCESS_MESSAGE": "This contact is unblocked successfully",
|
||||
"UNBLOCK_ERROR_MESSAGE": "Unable to unblock contact. Please try again later.",
|
||||
"IMPORT_CONTACT": {
|
||||
"TITLE": "Import contacts",
|
||||
"DESCRIPTION": "Import contacts through a CSV file.",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"PENDING": "Mark as pending",
|
||||
"RESOLVED": "Mark as resolved",
|
||||
"MARK_AS_UNREAD": "Mark as unread",
|
||||
"MARK_AS_READ": "Mark as read",
|
||||
"REOPEN": "Reopen conversation",
|
||||
"SNOOZE": {
|
||||
"TITLE": "Snooze",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user