* feat(scheduled-messages): add recurring scheduled messages Implements the recurring scheduled messages feature allowing agents to configure recurrence rules when scheduling messages, with automatic creation of subsequent scheduled messages after each send. Backend: - RecurringScheduledMessage model with JSONB recurrence_rule validation - RecurrenceCalculatorService for next occurrence date calculation - RecurrenceDescriptionService for human-readable rule descriptions - CreateNextOccurrenceService for auto-creating child ScheduledMessages - RecurringScheduledMessagesController with CRUD operations - RecurringScheduledMessagePolicy for authorization - Modified SendScheduledMessageJob to handle recurrence after send - Updated due_for_sending scope to exclude resolved conversations - ActionCable events for real-time updates - Activity message i18n (en + pt-BR) Frontend: - RecurrenceDropdown.vue with contextual shortcut options - RecurrenceCustomModal.vue for custom recurrence configuration - RecurringScheduledMessageItem.vue for sidebar display - Integration into ScheduledMessageModal.vue - Updated ScheduledMessages.vue with recurrence section and filtering - Vuex store module for recurring scheduled messages - API client for CRUD operations - WebSocket handlers in actionCable.js - recurrenceHelpers.js utility functions - i18n keys for en and pt-BR Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): fix creation and edit visibility - Fix API payload key mismatch (snake_case vs camelCase) in modal submit - Add status: 'active' to recurring creation payload - Fix strong params to permit recurrence_rule array fields (week_days) - Cast string values from strong params to integers for JSONB validation - Show RecurrenceDropdown when editing (remove isEditing gate) - Populate recurrenceRule from scheduled message's recurring parent - Include recurring_scheduled_message_id and recurrence_rule in scheduled message jbuilder response Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): fix dropdown toggle and locale tag errors - Use DropdownItem :click prop instead of @click to use the injected closeMenu from DropdownContainer context (default slot doesn't expose toggle) - Normalize locale from pt_BR to pt-BR for Intl.DateTimeFormat compatibility in RecurringScheduledMessageItem Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(recurring-messages): add separator line and expandable history - Add border separator between recurring messages section and pending/draft messages, matching the history section separator - Replace static 'N enviadas' counter with clickable toggle that expands to show individual sent/failed child messages with status badges and formatted timestamps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(recurring-messages): add click-to-navigate on sent children Make sent child messages in recurring message history clickable. Clicking navigates to the actual message in the conversation using the messageId query param, same pattern as ScheduledMessageItem. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(recurring-messages): allow editing recurring messages - Add edit button to RecurringScheduledMessageItem (active only) - Transform recurring message into scheduledMessage-compatible shape with recurring_scheduled_message_id set, so the modal reuses the existing update path - Handle edge case of removing recurrence from a recurring message (cancels series without trying to update a non-existent standalone) - Sent history is preserved by the backend update action Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): show recurrence field without date selection Remove v-if="scheduledDate" gate so the recurrence dropdown is always visible in the modal. Falls back to today's date for contextual shortcut labels when no date is selected yet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): ensure recurrence visible on edit and add pending_scheduled_message to API - Add pending_scheduled_message to recurring_scheduled_message jbuilder so REST API data matches WebSocket push_event_data - Add fallback in openEditRecurringModal to find pending child from scheduled_messages array when pending_scheduled_message is absent - Add same fallback in nextSendLabel computed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(scheduled-messages): add sections for Drafts and Pending messages in the UI * refactor(scheduled-messages): merge RecurringScheduledMessageItem into ScheduledMessageItem Consolidate the recurring message card into the existing ScheduledMessageItem component instead of maintaining a separate component. The unified component detects recurring messages via recurrence_rule and conditionally shows: - Recurrence description header with repeat icon - Next send time label - Expandable sent/failed children history with click-to-navigate - Stop button (replaces delete) with confirmation modal - Active/completed/cancelled status badges Delete the now-unused RecurringScheduledMessageItem.vue. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(scheduled-messages): use blue badge for active, keep green for sent Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(scheduled-messages): remove draft and pending sections from UI and update recurrence title * fix(recurring-messages): use Teleport for recurrence dropdown Replace DropdownContainer with Teleport-based floating dropdown so options render outside the modal. Fixes: - Dropdown no longer enlarges the modal or causes scrolling - Dropdown closes before Custom modal opens (no overlap) - Auto-detects available space and opens above/below trigger Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): recalculate next date when recurrence rule changes When editing a recurring message and changing the recurrence rule, the pending occurrence date is now validated against the new rule. If the user-provided date doesn't match (e.g. Thursday removed from weekly days), the system computes the next valid date using RecurrenceCalculatorService instead of blindly using the old date. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(scheduled-messages): resolve deprecated onClose and disabled type warnings - Replace :on-close prop with @close event on woot-modal components - Cast hasTemplate computed to boolean to fix disabled prop type check Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(scheduled-messages): replace remaining deprecated on-close props - ScheduledMessages.vue delete confirm modal - RecurrenceCustomModal.vue modal Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): address review feedback on PR #240 - Fix v-if/v-else bug hiding message list behind resolved warning - Fix occurrences_sent incrementing on failed sends (skip_increment flag) - Fix compute_next_valid_date using .min instead of .max - Fix Vuex delete action to update state on cancel (not remove) - Use atomic update_counters for occurrences_sent increment - Add safe Date.iso8601 parsing with rescue in should_complete? - Add null: false to occurrences_sent migration column - Fix pt-BR accent: Recorrencia → Recorrências - Use I18n.with_locale(account.locale) for all activity messages - Fix N+1 in jbuilder partials (Ruby filtering + eager loading) - Add interval >= 1 validation to RecurrenceCustomModal isValid - Validate recurrence_rule presence when status is active - Add ISO8601 date format validation for end_date - Add unknown_agent i18n key for fallback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): wrap create/update in transactions, clean pending on deactivation - Wrap create and update flows in ActiveRecord transactions - Move attachment purge after save! to prevent data loss on validation failure - Destroy pending children when status transitions to non-active - Fixes critical bug where stopping recurrence could leave armed pending messages Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): prevent monthly/yearly day-of-month drift Store the original intended day in recurrence_rule JSONB as month_day (for monthly) and year_day/year_month (for yearly). The calculator now uses these stored values instead of @last_date.day, preventing drift after short months cap the day (e.g., Jan 31 → Feb 28 → all subsequent months stuck on 28). Backend: - RecurrenceCalculatorService: use rule[:month_day] for monthly and rule[:year_day]/rule[:year_month] for yearly calculations - Controller: permit and cast the new integer keys Frontend: - recurrenceHelpers: yearly shortcuts include year_day/year_month - RecurrenceCustomModal: emit month_day for monthly day_of_month rules and year_day/year_month for yearly rules Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): i18n description services, align due_for_sending scope Backend: - RecurrenceDescriptionService: replace hardcoded English with I18n.t() calls; accept locale parameter and use I18n.with_locale - RecurringScheduledMessage model: pass account locale to description service - ScheduledMessage: align due_for_sending? instance method with scope by checking conversation status (open/pending) Frontend: - buildRecurrenceDescription: use t() i18n function instead of manual isPt locale branching - Add DESCRIPTION i18n keys to en/conversation.json and pt_BR/conversation.json - Update RecurrenceDropdown and ScheduledMessageItem callers to pass t i18n: - Add recurring_scheduled_messages.description.* keys to en.yml and pt_BR.yml Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): keep pending child when deactivating recurrence When editing a recurring message to disable recurrence while setting a future send date, the pending child message is now preserved instead of being destroyed. This allows a 'final send' without creating new recurrences (the send job already guards with recurring&.active?). Backend: - Add update_pending_on_deactivation: updates pending child's scheduled_at or creates a final pending occurrence - Replace destroy_all in update's non-active branch Frontend: - activeRecurringMessages now includes non-active recurring messages that still have a pending child (pending_scheduled_message) - Stop button hidden for already-cancelled recurring messages - inactiveRecurringMessages excludes messages with pending children Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): prevent removing recurrence from existing recurring message Once a scheduled message has recurrence, the 'Does not repeat' option is hidden from the RecurrenceDropdown when editing. This avoids edge cases where deactivating recurrence leaves the message in an ambiguous display state. - RecurrenceDropdown: add hideNoRepeat prop, filter NO_REPEAT from shortcuts - ScheduledMessageModal: pass hideNoRepeat when isEditingRecurring - Revert update_pending_on_deactivation (no longer reachable from UI) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): address CodeRabbit review feedback - ScheduledMessage#push_event_data: expose recurring_scheduled_message_id in ActionCable payloads so frontend correctly classifies children - RecurringScheduledMessagePolicy: add agent_bot? check for parity with ScheduledMessagePolicy - RecurrenceCalculatorService: guard against nil/empty week_days - Factory: bind inbox and account to conversation to prevent cross-account flakiness in specs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(recurring-messages): update schema to enforce non-null constraint on occurrences_sent --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
647 lines
26 KiB
JSON
647 lines
26 KiB
JSON
{
|
||
"CONVERSATION": {
|
||
"SELECT_A_CONVERSATION": "Please select a conversation from left pane",
|
||
"CSAT_REPLY_MESSAGE": "Please rate the conversation",
|
||
"404": "Sorry, we cannot find the conversation. Please try again",
|
||
"SWITCH_VIEW_LAYOUT": "Switch the layout",
|
||
"DASHBOARD_APP_TAB_MESSAGES": "Messages",
|
||
"UNVERIFIED_SESSION": "The identity of this user is not verified",
|
||
"NO_MESSAGE_1": "Uh oh! Looks like there are no messages from customers in your inbox.",
|
||
"NO_MESSAGE_2": " to send a message to your page!",
|
||
"NO_INBOX_1": "Hola! Looks like you haven't added any inboxes yet.",
|
||
"NO_INBOX_2": " to get started",
|
||
"NO_INBOX_AGENT": "Uh Oh! Looks like you are not part of any inbox. Please contact your administrator",
|
||
"SEARCH_MESSAGES": "Search for messages in conversations",
|
||
"VIEW_ORIGINAL": "View original",
|
||
"VIEW_TRANSLATED": "View translated",
|
||
"EMPTY_STATE": {
|
||
"CMD_BAR": "to open command menu",
|
||
"KEYBOARD_SHORTCUTS": "to view keyboard shortcuts"
|
||
},
|
||
"SEARCH": {
|
||
"TITLE": "Search messages",
|
||
"RESULT_TITLE": "Search Results",
|
||
"LOADING_MESSAGE": "Crunching data...",
|
||
"PLACEHOLDER": "Type any text to search messages",
|
||
"NO_MATCHING_RESULTS": "No results found."
|
||
},
|
||
"UNREAD_MESSAGES": "Unread Messages",
|
||
"UNREAD_MESSAGE": "Unread Message",
|
||
"CLICK_HERE": "Click here",
|
||
"LOADING_INBOXES": "Loading inboxes",
|
||
"LOADING_CONVERSATIONS": "Loading Conversations",
|
||
"CANNOT_REPLY": "You cannot reply due to",
|
||
"24_HOURS_WINDOW": "24 hour message window restriction",
|
||
"48_HOURS_WINDOW": "48 hour message window restriction",
|
||
"API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours",
|
||
"NOT_ASSIGNED_TO_YOU": "This conversation is not assigned to you. Would you like to assign this conversation to yourself?",
|
||
"ASSIGN_TO_ME": "Assign to me",
|
||
"BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.",
|
||
"BOT_HANDOFF_ACTION": "Mark open and assign to you",
|
||
"BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
|
||
"BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
|
||
"BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
|
||
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
|
||
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hour message window restriction",
|
||
"ANNOUNCEMENT_MODE_BANNER": "Only administrators are allowed to send messages in this group",
|
||
"GROUP_LEFT_BANNER": "You are no longer part of this group and cannot send messages in it",
|
||
"GROUPS_DISABLED_BANNER": "Group messages are disabled. Enable full group support (free) to view and send messages.",
|
||
"GROUPS_DISABLED_CTA": "Learn how to enable (free)",
|
||
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You won’t be able to send messages from this conversation anymore.",
|
||
"REPLYING_TO": "You are replying to:",
|
||
"REMOVE_SELECTION": "Remove Selection",
|
||
"DOWNLOAD": "Download",
|
||
"UNKNOWN_FILE_TYPE": "Unknown File",
|
||
"SAVE_CONTACT": "Save Contact",
|
||
"NO_CONTENT": "No content to display",
|
||
"SHARED_ATTACHMENT": {
|
||
"CONTACT": "{sender} has shared a contact",
|
||
"LOCATION": "{sender} has shared a location",
|
||
"FILE": "{sender} has shared a file",
|
||
"MEETING": "{sender} has started a meeting"
|
||
},
|
||
"UPLOADING_ATTACHMENTS": "Uploading attachments...",
|
||
"REPLIED_TO_STORY": "Replied to your story",
|
||
"UNSUPPORTED_MESSAGE": "This message is unsupported. You can view this message on the app.",
|
||
"UNSUPPORTED_MESSAGE_WHATSAPP": "This message is unsupported. You can view this message on the WhatsApp app.",
|
||
"UNSUPPORTED_MESSAGE_FACEBOOK": "This message is unsupported. You can view this message on the Facebook Messenger app.",
|
||
"UNSUPPORTED_MESSAGE_INSTAGRAM": "This message is unsupported. You can view this message on the Instagram app.",
|
||
"UNSUPPORTED_MESSAGE_TIKTOK": "This message is unsupported. You can view this message on the TikTok app.",
|
||
"SUCCESS_DELETE_MESSAGE": "Message deleted successfully",
|
||
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again",
|
||
"NO_RESPONSE": "No response",
|
||
"RESPONSE": "Response",
|
||
"RATING_TITLE": "Rating",
|
||
"FEEDBACK_TITLE": "Feedback",
|
||
"REPLY_MESSAGE_NOT_FOUND": "Message not available",
|
||
"CARD": {
|
||
"SHOW_LABELS": "Show labels",
|
||
"HIDE_LABELS": "Hide labels"
|
||
},
|
||
"VOICE_CALL": {
|
||
"INCOMING_CALL": "Incoming call",
|
||
"OUTGOING_CALL": "Outgoing call",
|
||
"CALL_IN_PROGRESS": "Call in progress",
|
||
"NO_ANSWER": "No answer",
|
||
"MISSED_CALL": "Missed call",
|
||
"CALL_ENDED": "Call ended",
|
||
"NOT_ANSWERED_YET": "Not answered yet",
|
||
"THEY_ANSWERED": "They answered",
|
||
"YOU_ANSWERED": "You answered"
|
||
},
|
||
"HEADER": {
|
||
"RESOLVE_ACTION": "Resolve",
|
||
"REOPEN_ACTION": "Reopen",
|
||
"OPEN_ACTION": "Open",
|
||
"MORE_ACTIONS": "More actions",
|
||
"OPEN": "More",
|
||
"CLOSE": "Close",
|
||
"DETAILS": "details",
|
||
"SNOOZED_UNTIL": "Snoozed until",
|
||
"SNOOZED_UNTIL_TOMORROW": "Snoozed until tomorrow",
|
||
"SNOOZED_UNTIL_NEXT_WEEK": "Snoozed until next week",
|
||
"SNOOZED_UNTIL_NEXT_REPLY": "Snoozed until next reply",
|
||
"SLA_STATUS": {
|
||
"FRT": "FRT {status}",
|
||
"NRT": "NRT {status}",
|
||
"RT": "RT {status}",
|
||
"MISSED": "missed",
|
||
"DUE": "due"
|
||
}
|
||
},
|
||
"RESOLVE_DROPDOWN": {
|
||
"MARK_PENDING": "Mark as pending",
|
||
"SNOOZE_UNTIL": "Snooze",
|
||
"SNOOZE": {
|
||
"TITLE": "Snooze until",
|
||
"NEXT_REPLY": "Next reply",
|
||
"TOMORROW": "Tomorrow",
|
||
"NEXT_WEEK": "Next week"
|
||
}
|
||
},
|
||
"MENTION": {
|
||
"AGENTS": "Agents",
|
||
"TEAMS": "Teams"
|
||
},
|
||
"CUSTOM_SNOOZE": {
|
||
"TITLE": "Snooze until",
|
||
"APPLY": "Snooze",
|
||
"CANCEL": "Cancel"
|
||
},
|
||
"PRIORITY": {
|
||
"TITLE": "Priority",
|
||
"OPTIONS": {
|
||
"NONE": "None",
|
||
"URGENT": "Urgent",
|
||
"HIGH": "High",
|
||
"MEDIUM": "Medium",
|
||
"LOW": "Low"
|
||
},
|
||
"CHANGE_PRIORITY": {
|
||
"SELECT_PLACEHOLDER": "None",
|
||
"INPUT_PLACEHOLDER": "Select priority",
|
||
"NO_RESULTS": "No results found",
|
||
"SUCCESSFUL": "Changed priority of conversation id {conversationId} to {priority}",
|
||
"FAILED": "Couldn't change priority. Please try again."
|
||
}
|
||
},
|
||
"DELETE_CONVERSATION": {
|
||
"TITLE": "Delete conversation #{conversationId}",
|
||
"DESCRIPTION": "Are you sure you want to delete this conversation?",
|
||
"CONFIRM": "Delete"
|
||
},
|
||
"CARD_CONTEXT_MENU": {
|
||
"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",
|
||
"NEXT_REPLY": "Until next reply",
|
||
"TOMORROW": "Until tomorrow",
|
||
"NEXT_WEEK": "Until next week"
|
||
},
|
||
"ASSIGN_AGENT": "Assign agent",
|
||
"ASSIGN_LABEL": "Assign label",
|
||
"AGENTS_LOADING": "Loading agents...",
|
||
"ASSIGN_TEAM": "Assign team",
|
||
"DELETE": "Delete conversation",
|
||
"OPEN_IN_NEW_TAB": "Open in new tab",
|
||
"COPY_LINK": "Copy conversation link",
|
||
"COPY_LINK_SUCCESS": "Conversation link copied to clipboard",
|
||
"API": {
|
||
"AGENT_ASSIGNMENT": {
|
||
"SUCCESFUL": "Conversation id {conversationId} assigned to \"{agentName}\"",
|
||
"FAILED": "Couldn't assign agent. Please try again."
|
||
},
|
||
"LABEL_ASSIGNMENT": {
|
||
"SUCCESFUL": "Assigned label #{labelName} to conversation id {conversationId}",
|
||
"FAILED": "Couldn't assign label. Please try again."
|
||
},
|
||
"LABEL_REMOVAL": {
|
||
"SUCCESFUL": "Removed label #{labelName} from conversation id {conversationId}",
|
||
"FAILED": "Couldn't remove label. Please try again."
|
||
},
|
||
"TEAM_ASSIGNMENT": {
|
||
"SUCCESFUL": "Assigned team \"{team}\" to conversation id {conversationId}",
|
||
"FAILED": "Couldn't assign team. Please try again."
|
||
}
|
||
}
|
||
},
|
||
"FOOTER": {
|
||
"MESSAGE_SIGN_TOOLTIP": "Message signature",
|
||
"ENABLE_SIGN_TOOLTIP": "Enable signature",
|
||
"DISABLE_SIGN_TOOLTIP": "Disable signature",
|
||
"SIGNATURE_LABEL_TOP": "↓ Signature",
|
||
"SIGNATURE_LABEL_TOP_TOOLTIP": "The signature will be sent at the top of the message",
|
||
"SIGNATURE_LABEL_BOTTOM": "↑ Signature",
|
||
"SIGNATURE_LABEL_BOTTOM_TOOLTIP": "The signature will be sent at the bottom of the message",
|
||
"MSG_INPUT": "Shift + enter for new line. Start with '/' to select a Canned Response.",
|
||
"PRIVATE_MSG_INPUT": "Shift + enter for new line. This will be visible only to Agents",
|
||
"MESSAGING_RESTRICTED": "You cannot reply to this conversation",
|
||
"MESSAGING_RESTRICTED_WHATSAPP": "You can only reply using a template message due to 24-hour message window restriction",
|
||
"ANNOUNCEMENT_MODE_RESTRICTED": "Only administrators are allowed to send messages in this group",
|
||
"GROUP_LEFT_RESTRICTED": "You are no longer part of this group and cannot send messages in it",
|
||
"GROUPS_DISABLED_RESTRICTED": "Group messages are disabled — enable for free",
|
||
"MESSAGE_SIGNATURE_NOT_CONFIGURED": "Message signature is not configured, please configure it in profile settings.",
|
||
"COPILOT_MSG_INPUT": "Give copilot additional prompts, or ask anything else... Press enter to send follow-up",
|
||
"CLICK_HERE": "Click here to update",
|
||
"WHATSAPP_TEMPLATES": "Whatsapp Templates"
|
||
},
|
||
"REPLYBOX": {
|
||
"REPLY": "Reply",
|
||
"PRIVATE_NOTE": "Private Note",
|
||
"SEND": "Send",
|
||
"CREATE": "Add Note",
|
||
"INSERT_READ_MORE": "Read more",
|
||
"DISMISS_REPLY": "Dismiss reply",
|
||
"REPLYING_TO": "Replying to:",
|
||
"TIP_EMOJI_ICON": "Show emoji selector",
|
||
"TIP_ATTACH_ICON": "Attach files",
|
||
"TIP_AUDIORECORDER_ICON": "Record audio",
|
||
"TIP_AUDIORECORDER_PERMISSION": "Allow access to audio",
|
||
"TIP_AUDIORECORDER_ERROR": "Could not open the audio",
|
||
"AUDIO_CONVERSION_FAILED": "Audio conversion failed. Please try again.",
|
||
"DRAG_DROP": "Drag and drop here to attach",
|
||
"START_AUDIO_RECORDING": "Start audio recording",
|
||
"STOP_AUDIO_RECORDING": "Stop audio recording",
|
||
"COPILOT_THINKING": "Copilot is thinking",
|
||
"EMAIL_HEAD": {
|
||
"TO": "TO",
|
||
"ADD_BCC": "Add bcc",
|
||
"CC": {
|
||
"LABEL": "CC",
|
||
"PLACEHOLDER": "Emails separated by commas",
|
||
"ERROR": "Please enter valid email addresses"
|
||
},
|
||
"BCC": {
|
||
"LABEL": "BCC",
|
||
"PLACEHOLDER": "Emails separated by commas",
|
||
"ERROR": "Please enter valid email addresses"
|
||
}
|
||
},
|
||
"UNDEFINED_VARIABLES": {
|
||
"TITLE": "Undefined variables",
|
||
"MESSAGE": "You have {undefinedVariablesCount} undefined variables in your message: {undefinedVariables}. Would you like to send the message anyway?",
|
||
"CONFIRM": {
|
||
"YES": "Send",
|
||
"CANCEL": "Cancel"
|
||
}
|
||
},
|
||
"QUOTED_REPLY": {
|
||
"ENABLE_TOOLTIP": "Include quoted email thread",
|
||
"DISABLE_TOOLTIP": "Don't include quoted email thread",
|
||
"REMOVE_PREVIEW": "Remove quoted email thread",
|
||
"COLLAPSE": "Collapse preview",
|
||
"EXPAND": "Expand preview"
|
||
},
|
||
"SCHEDULE_SEND": "Schedule send"
|
||
},
|
||
"VISIBLE_TO_AGENTS": "Private Note: Only visible to you and your team",
|
||
"CHANGE_STATUS": "Conversation status changed",
|
||
"CHANGE_STATUS_FAILED": "Conversation status change failed",
|
||
"CHANGE_AGENT": "Conversation Assignee changed",
|
||
"CHANGE_AGENT_FAILED": "Assignee change failed",
|
||
"ASSIGN_LABEL_SUCCESFUL": "Label assigned successfully",
|
||
"ASSIGN_LABEL_FAILED": "Label assignment failed",
|
||
"CHANGE_TEAM": "Conversation team changed",
|
||
"SUCCESS_DELETE_CONVERSATION": "Conversation deleted successfully",
|
||
"FAIL_DELETE_CONVERSATION": "Couldn't delete conversation! Try again",
|
||
"FILE_SIZE_LIMIT": "File exceeds the {MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE} MB attachment limit",
|
||
"FILE_TYPE_NOT_SUPPORTED": "This {fileName} file type is not supported in this conversation",
|
||
"MESSAGE_ERROR": "Unable to send this message, please try again later",
|
||
"SENT_BY": "Sent by:",
|
||
"BOT": "Bot",
|
||
"NATIVE_APP": "Native app",
|
||
"NATIVE_APP_ADVISORY": "This message was sent from the native app. Reply from Chatwoot to maintain the message window.",
|
||
"WHATSAPP": "WhatsApp",
|
||
"SEND_FAILED": "Couldn't send message! Try again",
|
||
"TRY_AGAIN": "retry",
|
||
"ASSIGNMENT": {
|
||
"SELECT_AGENT": "Select Agent",
|
||
"REMOVE": "Remove",
|
||
"ASSIGN": "Assign"
|
||
},
|
||
"CONTEXT_MENU": {
|
||
"COPY": "Copy",
|
||
"REPLY_TO": "Reply to this message",
|
||
"DELETE": "Delete",
|
||
"CREATE_A_CANNED_RESPONSE": "Add to canned responses",
|
||
"TRANSLATE": "Translate",
|
||
"COPY_PERMALINK": "Copy link to the message",
|
||
"LINK_COPIED": "Message URL copied to the clipboard",
|
||
"DELETE_CONFIRMATION": {
|
||
"TITLE": "Are you sure you want to delete this message?",
|
||
"MESSAGE": "You cannot undo this action",
|
||
"DELETE": "Delete",
|
||
"CANCEL": "Cancel"
|
||
},
|
||
"EDIT": {
|
||
"LABEL": "Edit",
|
||
"TITLE": "Edit message",
|
||
"PLACEHOLDER": "Enter message content",
|
||
"SAVE": "Save",
|
||
"CANCEL": "Cancel",
|
||
"SUCCESS": "Message edited successfully",
|
||
"ERROR": "Failed to edit message",
|
||
"EMPTY_CONTENT": "Message content cannot be empty"
|
||
}
|
||
},
|
||
"SIDEBAR": {
|
||
"CONTACT": "Contact",
|
||
"COPILOT": "Copilot"
|
||
},
|
||
"VOICE_WIDGET": {
|
||
"INCOMING_CALL": "Incoming call",
|
||
"OUTGOING_CALL": "Outgoing call",
|
||
"CALL_IN_PROGRESS": "Call in progress",
|
||
"NOT_ANSWERED_YET": "Not answered yet",
|
||
"HANDLED_IN_ANOTHER_TAB": "Being handled in another tab",
|
||
"REJECT_CALL": "Reject",
|
||
"JOIN_CALL": "Join call",
|
||
"END_CALL": "End call"
|
||
},
|
||
"INBOX": {
|
||
"WHATSAPP_PROVIDER_CONNECTION": {
|
||
"NOT_CONNECTED": "WhatsApp is not connected. Please link your device again.",
|
||
"NOT_CONNECTED_CONTACT_ADMIN": "WhatsApp is not connected. Click this button to try to reconnect, or please contact your administrator to link your device again.",
|
||
"LINK_DEVICE": "Link device",
|
||
"RECONNECT_FAILED": "Failed to reconnect. Please contact your administrator to link your device again."
|
||
}
|
||
}
|
||
},
|
||
"EMAIL_TRANSCRIPT": {
|
||
"TITLE": "Send conversation transcript",
|
||
"DESC": "Send a copy of the conversation transcript to the specified email address",
|
||
"SUBMIT": "Submit",
|
||
"CANCEL": "Cancel",
|
||
"SEND_EMAIL_SUCCESS": "The chat transcript was sent successfully",
|
||
"SEND_EMAIL_ERROR": "There was an error, please try again",
|
||
"FORM": {
|
||
"SEND_TO_CONTACT": "Send the transcript to the customer",
|
||
"SEND_TO_AGENT": "Send the transcript to the assigned agent",
|
||
"SEND_TO_OTHER_EMAIL_ADDRESS": "Send the transcript to another email address",
|
||
"EMAIL": {
|
||
"PLACEHOLDER": "Enter an email address",
|
||
"ERROR": "Please enter a valid email address"
|
||
}
|
||
}
|
||
},
|
||
"ONBOARDING": {
|
||
"TITLE": "Hey 👋, Welcome to {installationName}!",
|
||
"DESCRIPTION": "Thanks for signing up. We want you to get the most out of {installationName}. Here are a few things you can do in {installationName} to make the experience delightful.",
|
||
"GREETING_MORNING": "👋 Good morning, {name}. Welcome to {installationName}.",
|
||
"GREETING_AFTERNOON": "👋 Good afternoon, {name}. Welcome to {installationName}.",
|
||
"GREETING_EVENING": "👋 Good evening, {name}. Welcome to {installationName}.",
|
||
"READ_LATEST_UPDATES": "Read our latest updates",
|
||
"ALL_CONVERSATION": {
|
||
"TITLE": "All your conversations in one place",
|
||
"DESCRIPTION": "View all the conversations from your customers in one single dashboard. You can filter the conversations by the incoming channel, label and status.",
|
||
"NEW_LINK": "Click here to create an inbox"
|
||
},
|
||
"TEAM_MEMBERS": {
|
||
"TITLE": "Invite your team members",
|
||
"DESCRIPTION": "Since you are getting ready to talk to your customer, bring in your teammates to assist you. You can invite your teammates by adding their email addresses to the agent list.",
|
||
"NEW_LINK": "Click here to invite a team member"
|
||
},
|
||
"LABELS": {
|
||
"TITLE": "Organize conversations with labels",
|
||
"DESCRIPTION": "Labels provide an easier way to categorize your conversation. Create some labels like #support-enquiry, #billing-question etc., so that you can use them in a conversation later.",
|
||
"NEW_LINK": "Click here to create tags"
|
||
},
|
||
"CANNED_RESPONSES": {
|
||
"TITLE": "Create canned responses",
|
||
"DESCRIPTION": "Pre-written quick reply templates help you quickly respond to a conversation. Agents can type the '/' character followed by the shortcode to insert a response.",
|
||
"NEW_LINK": "Click here to create a canned response"
|
||
}
|
||
},
|
||
"CONVERSATION_SIDEBAR": {
|
||
"ASSIGNEE_LABEL": "Assigned Agent",
|
||
"SELF_ASSIGN": "Assign to me",
|
||
"TEAM_LABEL": "Assigned Team",
|
||
"SELECT": {
|
||
"PLACEHOLDER": "None"
|
||
},
|
||
"ACCORDION": {
|
||
"CONTACT_DETAILS": "Contact Details",
|
||
"SCHEDULED_MESSAGES": "Scheduled Messages",
|
||
"CONVERSATION_ACTIONS": "Conversation Actions",
|
||
"CONVERSATION_LABELS": "Conversation Labels",
|
||
"CONVERSATION_INFO": "Conversation Information",
|
||
"CONTACT_NOTES": "Contact Notes",
|
||
"CONTACT_ATTRIBUTES": "Contact Attributes",
|
||
"PREVIOUS_CONVERSATION": "Previous Conversations",
|
||
"MACROS": "Macros",
|
||
"LINEAR_ISSUES": "Linked Linear Issues",
|
||
"SHOPIFY_ORDERS": "Shopify Orders"
|
||
},
|
||
"SHOPIFY": {
|
||
"ORDER_ID": "Order #{id}",
|
||
"ERROR": "Error loading orders",
|
||
"NO_SHOPIFY_ORDERS": "No orders found",
|
||
"FINANCIAL_STATUS": {
|
||
"PENDING": "Pending",
|
||
"AUTHORIZED": "Authorized",
|
||
"PARTIALLY_PAID": "Partially Paid",
|
||
"PAID": "Paid",
|
||
"PARTIALLY_REFUNDED": "Partially Refunded",
|
||
"REFUNDED": "Refunded",
|
||
"VOIDED": "Voided"
|
||
},
|
||
"FULFILLMENT_STATUS": {
|
||
"FULFILLED": "Fulfilled",
|
||
"PARTIALLY_FULFILLED": "Partially Fulfilled",
|
||
"UNFULFILLED": "Unfulfilled"
|
||
}
|
||
}
|
||
},
|
||
"SCHEDULED_MESSAGES": {
|
||
"NEW_BUTTON": "Schedule message",
|
||
"PAST_MESSAGES_SECTION": "Sent",
|
||
"EMPTY_STATE": "There are no scheduled messages yet.",
|
||
"STATUS": {
|
||
"DRAFT": "Draft",
|
||
"PENDING": "Pending",
|
||
"SENT": "Sent",
|
||
"FAILED": "Failed"
|
||
},
|
||
"ITEM": {
|
||
"SCHEDULED_FOR": "Scheduled for {time}",
|
||
"NO_SCHEDULE": "No schedule",
|
||
"TEMPLATE_PREVIEW": "Template: {name}",
|
||
"TEMPLATE_LABEL": "Template: {name}",
|
||
"ATTACHMENT_PREVIEW": "Attachment: {filename}",
|
||
"ATTACHMENT_LABEL": "Attachment: {filename}",
|
||
"EMPTY_PREVIEW": "No content",
|
||
"EXPAND": "Expand",
|
||
"COLLAPSE": "Collapse",
|
||
"GO_TO_MESSAGE": "Go to message",
|
||
"SEARCHING_MESSAGE": "Searching for message...",
|
||
"MESSAGE_NOT_FOUND": "The linked message was not found. It may have been deleted."
|
||
},
|
||
"MODAL": {
|
||
"TITLE_NEW": "Schedule a message",
|
||
"TITLE_EDIT": "Edit scheduled message",
|
||
"MESSAGE_LABEL": "Message",
|
||
"MESSAGE_PLACEHOLDER": "Write your message...",
|
||
"DATETIME_LABEL": "Date and time to send",
|
||
"ATTACHMENT_LABEL": "Attachment",
|
||
"ATTACHMENT_ADD": "Attach file",
|
||
"ATTACHMENT_CURRENT": "Current attachment: {filename}",
|
||
"TEMPLATE_SELECT": "Use template",
|
||
"TEMPLATE_SELECTED": "Template: {name}",
|
||
"TEMPLATE_ACTION": "Schedule message",
|
||
"CANCEL": "Cancel",
|
||
"SAVE_DRAFT": "Save as draft",
|
||
"SCHEDULE": "Schedule",
|
||
"SHORTCUTS": {
|
||
"TOMORROW_MORNING": "Tomorrow morning",
|
||
"TOMORROW_AFTERNOON": "Tomorrow afternoon",
|
||
"MONDAY_MORNING": "Monday morning",
|
||
"CUSTOM": "Type a date and time"
|
||
},
|
||
"CUSTOM_INPUT_PLACEHOLDER": "e.g. tomorrow at 2pm, next friday morning",
|
||
"CUSTOM_INPUT_HINT": "Try: tomorrow at 3pm, next monday, in 2 hours",
|
||
"PARSED_DATE_IN_PAST": "This date is in the past",
|
||
"DATEPICKER_TOOLTIP": "Pick from calendar",
|
||
"SCHEDULE_LABEL": "Schedule send"
|
||
},
|
||
"CONFIRM_CLOSE": {
|
||
"TITLE": "Unsaved changes",
|
||
"MESSAGE": "You have unsaved content. Would you like to discard your changes?",
|
||
"CONTINUE_EDITING": "Continue editing",
|
||
"DISCARD": "Discard",
|
||
"CANCEL": "Cancel"
|
||
},
|
||
"CONFIRM_DELETE": {
|
||
"TITLE": "Delete scheduled message",
|
||
"MESSAGE": "Are you sure you want to delete this scheduled message? This action cannot be undone.",
|
||
"CANCEL": "Cancel",
|
||
"DELETE": "Delete"
|
||
},
|
||
"META": {
|
||
"TOOLTIP": "Scheduled at {time} by {author}",
|
||
"YOU": "You",
|
||
"AUTHOR_YOU": "{name} (You)",
|
||
"AUTOMATION": "Automation",
|
||
"UNKNOWN_AUTHOR": "Unknown"
|
||
},
|
||
"ERRORS": {
|
||
"CONTENT_REQUIRED": "Add a message, template, or attachment before saving.",
|
||
"CONTENT_TOO_LONG": "Message is too long. Maximum {maxLength} characters allowed.",
|
||
"DATETIME_REQUIRED": "Select a date and time to schedule the message.",
|
||
"SCHEDULE_IN_PAST": "Scheduled time must be in the future.",
|
||
"SAVE_FAILED": "Unable to save scheduled message. Please try again.",
|
||
"DELETE_FAILED": "Unable to delete scheduled message. Please try again."
|
||
},
|
||
"RECURRENCE": {
|
||
"SECTION_TITLE": "Recurrences",
|
||
"NO_REPEAT": "Does not repeat",
|
||
"DAILY": "Every day",
|
||
"WEEKLY": "Weekly on {day}",
|
||
"MONTHLY_NTH": "Monthly on the {nth} {day}",
|
||
"MONTHLY_LAST": "Monthly on the last {day}",
|
||
"YEARLY": "Yearly on {month} {dayNum}",
|
||
"WEEKDAYS": "Every weekday (Mon-Fri)",
|
||
"CUSTOM": "Custom...",
|
||
"CUSTOM_MODAL": {
|
||
"TITLE": "Custom recurrence",
|
||
"REPEAT_EVERY": "Repeat every",
|
||
"FREQ_DAILY": "day(s)",
|
||
"FREQ_WEEKLY": "week(s)",
|
||
"FREQ_MONTHLY": "month(s)",
|
||
"FREQ_YEARLY": "year(s)",
|
||
"UNIT_DAY": "day | days",
|
||
"UNIT_WEEK": "week | weeks",
|
||
"UNIT_MONTH": "month | months",
|
||
"UNIT_YEAR": "year | years",
|
||
"REPEAT_ON": "Repeat on",
|
||
"MONTHLY_ON_DAY": "Day of month",
|
||
"MONTHLY_ON_WEEKDAY": "Day of week",
|
||
"ENDS": "Ends",
|
||
"ENDS_NEVER": "Never",
|
||
"ENDS_ON_DATE": "On date",
|
||
"ENDS_AFTER": "After",
|
||
"ENDS_OCCURRENCES": "occurrences",
|
||
"DONE": "Done",
|
||
"CANCEL": "Cancel"
|
||
},
|
||
"STATUS_ACTIVE": "Active",
|
||
"STATUS_DRAFT": "Draft",
|
||
"STATUS_COMPLETED": "Completed",
|
||
"STATUS_CANCELLED": "Cancelled",
|
||
"OCCURRENCES_SENT": "{count} sent",
|
||
"NEXT_SEND": "Next: {time}",
|
||
"EXPAND": "Expand history",
|
||
"COLLAPSE": "Collapse history",
|
||
"STOP": "Stop recurrence",
|
||
"STOP_CONFIRM": {
|
||
"TITLE": "Stop recurrence",
|
||
"MESSAGE": "The pending message will be removed and the recurrence will be permanently stopped.",
|
||
"CONFIRM": "Stop",
|
||
"CANCEL": "Cancel"
|
||
},
|
||
"EDIT": "Edit recurrence",
|
||
"EDIT_WARNING": "Next send: {oldDate} → {newDate}",
|
||
"WEEKDAYS_SHORT": {
|
||
"SUN": "S",
|
||
"MON": "M",
|
||
"TUE": "T",
|
||
"WED": "W",
|
||
"THU": "T",
|
||
"FRI": "F",
|
||
"SAT": "S"
|
||
},
|
||
"ORDINALS": {
|
||
"FIRST": "first",
|
||
"SECOND": "second",
|
||
"THIRD": "third",
|
||
"FOURTH": "fourth",
|
||
"FIFTH": "fifth",
|
||
"LAST": "last"
|
||
},
|
||
"DESCRIPTION": {
|
||
"DAILY_ONE": "Every day",
|
||
"DAILY_OTHER": "Every {count} days",
|
||
"WEEKLY_ONE": "Every week",
|
||
"WEEKLY_OTHER": "Every {count} weeks",
|
||
"WEEKLY_ON": "{prefix}: {days}",
|
||
"MONTHLY_ONE": "Monthly",
|
||
"MONTHLY_OTHER": "Every {count} months",
|
||
"MONTHLY_ON_WEEKDAY": "{prefix} on the {ordinal} {weekday}",
|
||
"YEARLY_ONE": "Every year",
|
||
"YEARLY_OTHER": "Every {count} years",
|
||
"UNTIL_DATE": "until {date}",
|
||
"AFTER_COUNT": "{count} occurrences"
|
||
},
|
||
"RESOLVED_WARNING": "Scheduled messages will not be sent while the conversation is resolved. Reopen the conversation to resume sending."
|
||
}
|
||
},
|
||
"CONVERSATION_CUSTOM_ATTRIBUTES": {
|
||
"ADD_BUTTON_TEXT": "Create attribute",
|
||
"NO_RECORDS_FOUND": "No attributes found",
|
||
"UPDATE": {
|
||
"SUCCESS": "Attribute updated successfully",
|
||
"ERROR": "Unable to update attribute. Please try again later"
|
||
},
|
||
"ADD": {
|
||
"TITLE": "Add",
|
||
"SUCCESS": "Attribute added successfully",
|
||
"ERROR": "Unable to add attribute. Please try again later"
|
||
},
|
||
"DELETE": {
|
||
"SUCCESS": "Attribute deleted successfully",
|
||
"ERROR": "Unable to delete attribute. Please try again later"
|
||
},
|
||
"ATTRIBUTE_SELECT": {
|
||
"TITLE": "Add attributes",
|
||
"PLACEHOLDER": "Search attributes",
|
||
"NO_RESULT": "No attributes found"
|
||
}
|
||
},
|
||
"EMAIL_HEADER": {
|
||
"FROM": "From",
|
||
"TO": "To",
|
||
"BCC": "Bcc",
|
||
"CC": "Cc",
|
||
"SUBJECT": "Subject",
|
||
"EXPAND": "Expand email"
|
||
},
|
||
"CONVERSATION_PARTICIPANTS": {
|
||
"SIDEBAR_MENU_TITLE": "Participating",
|
||
"SIDEBAR_TITLE": "Conversation participants",
|
||
"NO_RECORDS_FOUND": "No results found",
|
||
"ADD_PARTICIPANTS": "Select participants",
|
||
"REMANING_PARTICIPANTS_TEXT": "+{count} others",
|
||
"REMANING_PARTICIPANT_TEXT": "+{count} other",
|
||
"TOTAL_PARTICIPANTS_TEXT": "{count} people are participating.",
|
||
"TOTAL_PARTICIPANT_TEXT": "{count} person is participating.",
|
||
"NO_PARTICIPANTS_TEXT": "No one is participating!.",
|
||
"WATCH_CONVERSATION": "Join conversation",
|
||
"YOU_ARE_WATCHING": "You are participating",
|
||
"API": {
|
||
"ERROR_MESSAGE": "Could not update, try again!",
|
||
"SUCCESS_MESSAGE": "Participants updated!"
|
||
}
|
||
},
|
||
"TRANSLATE_MODAL": {
|
||
"TITLE": "View translated content",
|
||
"DESC": "You can view the translated content in each langauge.",
|
||
"ORIGINAL_CONTENT": "Original Content",
|
||
"TRANSLATED_CONTENT": "Translated Content",
|
||
"NO_TRANSLATIONS_AVAILABLE": "No translations are available for this content"
|
||
},
|
||
"TYPING": {
|
||
"ONE": "{user} is typing",
|
||
"TWO": "{user} and {secondUser} are typing",
|
||
"MULTIPLE": "{user} and {count} others are typing"
|
||
},
|
||
"COPILOT": {
|
||
"TRY_THESE_PROMPTS": "Try these prompts"
|
||
},
|
||
"GALLERY_VIEW": {
|
||
"ERROR_DOWNLOADING": "Unable to download attachment. Please try again"
|
||
}
|
||
}
|