diff --git a/public/locales_0.1.5/en/translation.json b/public/locales_0.1.5/en/translation.json index 4f9ce8c..1a63627 100644 --- a/public/locales_0.1.5/en/translation.json +++ b/public/locales_0.1.5/en/translation.json @@ -272,5 +272,6 @@ "STATUS_VIDEO_FALLBACK": "Video status", "STATUS_AUDIO_FALLBACK": "Audio status", "STATUS_QUOTE_EXCEEDED": "The tariff quota has been exceeded. The status has not been sent", - "STATUS_BULK_NOT_SENT": "Failed to send {failed} of {total} statuses" + "STATUS_BULK_NOT_SENT": "Failed to send {failed} of {total} statuses", + "AD_MSG_TITLE": "Message via advertisement" } diff --git a/public/locales_0.1.5/he/translation.json b/public/locales_0.1.5/he/translation.json index 286d038..94ba2f1 100644 --- a/public/locales_0.1.5/he/translation.json +++ b/public/locales_0.1.5/he/translation.json @@ -270,5 +270,6 @@ "STATUS_VIDEO_FALLBACK": "סטטוס וידאו", "STATUS_AUDIO_FALLBACK": "סטטוס אודיו", "STATUS_QUOTE_EXCEEDED": "חריגה ממכסת התעריף. הסטטוס לא נשלח", - "STATUS_BULK_NOT_SENT": "לא נשלחו {failed} מתוך {total} סטטוסים" + "STATUS_BULK_NOT_SENT": "לא נשלחו {failed} מתוך {total} סטטוסים", + "AD_MSG_TITLE": "הודעה באמצעות פרסומת" } diff --git a/public/locales_0.1.5/ru/translation.json b/public/locales_0.1.5/ru/translation.json index ab42d2d..62c2c85 100644 --- a/public/locales_0.1.5/ru/translation.json +++ b/public/locales_0.1.5/ru/translation.json @@ -288,5 +288,6 @@ "STATUS_VIDEO_FALLBACK": "Видео-статус", "STATUS_AUDIO_FALLBACK": "Аудио-статус", "STATUS_QUOTE_EXCEEDED": "Превышена квота тарифа. Статус не отправлен", - "STATUS_BULK_NOT_SENT": "Не отправлено {failed} из {total} статусов" + "STATUS_BULK_NOT_SENT": "Не отправлено {failed} из {total} статусов", + "AD_MSG_TITLE": "Сообщение через рекламу" } diff --git a/public/locales_0.1.5/tr/translation.json b/public/locales_0.1.5/tr/translation.json index 7fa8ea4..8562ab1 100644 --- a/public/locales_0.1.5/tr/translation.json +++ b/public/locales_0.1.5/tr/translation.json @@ -272,5 +272,6 @@ "STATUS_VIDEO_FALLBACK": "Video durumu", "STATUS_AUDIO_FALLBACK": "Ses durumu", "STATUS_QUOTE_EXCEEDED": "Tarife kotası aşıldı. Durum gönderilmedi", - "STATUS_BULK_NOT_SENT": "{total} durumdan {failed} tanesi gönderilemedi" + "STATUS_BULK_NOT_SENT": "{total} durumdan {failed} tanesi gönderilemedi", + "AD_MSG_TITLE": "Reklam yoluyla mesaj" } diff --git a/src/components/shared/chat-list/chat-list-item.component.tsx b/src/components/shared/chat-list/chat-list-item.component.tsx index 32a2ba8..b7e971a 100644 --- a/src/components/shared/chat-list/chat-list-item.component.tsx +++ b/src/components/shared/chat-list/chat-list-item.component.tsx @@ -233,13 +233,7 @@ const ChatListItem: FC = ({ height: 20, })} {getMessageTypeIcon(lastMessage.typeMessage)} - {lastMessage.isDeleted ? ( - {t('DELETED_MESSAGE')} - ) : ( - - {formattedPreviewMessage} - - )} + {lastMessage.isDeleted ? {t('DELETED_MESSAGE')} : formattedPreviewMessage} ) } diff --git a/src/components/shared/chat-view.component.tsx b/src/components/shared/chat-view.component.tsx index e8f7aad..10acaae 100644 --- a/src/components/shared/chat-view.component.tsx +++ b/src/components/shared/chat-view.component.tsx @@ -219,9 +219,7 @@ const ChatView: FC = () => { const selectedOptions = msg.pollMessageData?.votes ?.filter((vote) => - vote.optionVoters.some( - (voter) => getPhoneNumberFromChatId(voter) === senderPhone - ) + vote.optionVoters.some((voter) => getPhoneNumberFromChatId(voter) === senderPhone) ) .map((vote) => vote.optionName) ?? []; @@ -469,6 +467,7 @@ const ChatView: FC = () => { statusMessage: message.statusMessage, quotedMessage: message.quotedMessage, templateMessage: templateMessage, + extendedTextMessage: message.extendedTextMessage, interactiveButtonsMessage: interactiveButtonsMessage, caption: message.caption, fileName: message.fileName, diff --git a/src/components/shared/message/ad-message.component.tsx b/src/components/shared/message/ad-message.component.tsx new file mode 100644 index 0000000..ececdae --- /dev/null +++ b/src/components/shared/message/ad-message.component.tsx @@ -0,0 +1,40 @@ +import { FC } from 'react'; + +import { Image, Space } from 'antd'; +import { useTranslation } from 'react-i18next'; + +import { ExtendedTextMessage } from 'types'; +import { getAdMsgUrlHostname, IMAGE_FALLBACK } from 'utils'; + +type AdMessageProps = Pick; + +const AdMessage: FC = ({ sourceUrl, thumbnailUrl, description }) => { + const { t } = useTranslation(); + const adUrlHostname = getAdMsgUrlHostname(sourceUrl); + + return ( + + + {t('AD_MSG_TITLE')} + image + + {description} + + {adUrlHostname && ( + + {adUrlHostname} + + )} + + + ); +}; + +export default AdMessage; diff --git a/src/components/shared/message/file-message.component.tsx b/src/components/shared/message/file-message.component.tsx index f064fc3..4f081ad 100644 --- a/src/components/shared/message/file-message.component.tsx +++ b/src/components/shared/message/file-message.component.tsx @@ -3,20 +3,13 @@ import { FC } from 'react'; import { Image, Space, Typography } from 'antd'; import { MessageProps } from './message.component'; -import { getMessageTypeIcon } from 'utils'; +import { getMessageTypeIcon, IMAGE_FALLBACK } from 'utils'; const FileMessage: FC< Pick > = ({ downloadUrl, typeMessage, fileName, type }) => { if (typeMessage === 'imageMessage') { - return ( - image - ); + return image; } return ( diff --git a/src/components/shared/message/message.component.tsx b/src/components/shared/message/message.component.tsx index d28bba3..1fc56f2 100644 --- a/src/components/shared/message/message.component.tsx +++ b/src/components/shared/message/message.component.tsx @@ -4,6 +4,7 @@ import { Space } from 'antd'; import clsx from 'clsx'; import { useTranslation } from 'react-i18next'; +import AdMessage from './ad-message.component'; import AudioMessage from './audio-message.component'; import FileMessage from './file-message.component'; import MessageErrorBoundary from './message-error-boundary.component'; @@ -40,6 +41,7 @@ const Message: FC = ({ messageDataForRender, preview }) => { quotedMessage, templateMessage, interactiveButtonsMessage, + extendedTextMessage, caption, fileName, isDeleted, @@ -134,6 +136,8 @@ const Message: FC = ({ messageDataForRender, preview }) => { ); } + const isAdMsg = extendedTextMessage && extendedTextMessage.sourceType === 'ad'; + return (
= ({ messageDataForRender, preview }) => { /> )} + {isAdMsg && ( + + )} + {isDeleted && !showDeletedMessage ? ( {t('DELETED_MESSAGE')} diff --git a/src/styles/components/shared/message.scss b/src/styles/components/shared/message.scss index dbf3ece..00d4790 100644 --- a/src/styles/components/shared/message.scss +++ b/src/styles/components/shared/message.scss @@ -217,3 +217,10 @@ color: var(--primary-color); } } + +.ad-message { + background-color: var(--qouted-message-outgoing-bg-color); + border-radius: 10px; + padding: 10px; + color: var(--icon-color); +} \ No newline at end of file diff --git a/src/styles/index.scss b/src/styles/index.scss index 64c4d6b..512473c 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -196,6 +196,7 @@ html { .text-overflow { display: -webkit-box; overflow: hidden; + text-overflow: ellipsis; -webkit-box-orient: vertical; -webkit-line-clamp: 1; } diff --git a/src/types/api.types.ts b/src/types/api.types.ts index 2fab901..13221b0 100644 --- a/src/types/api.types.ts +++ b/src/types/api.types.ts @@ -146,6 +146,12 @@ export interface ExtendedTextMessage { title: string; previewType: string; jpegThumbnail: string; + mediaType?: 'IMAGE' | 'VIDEO'; + showAdAttribution?: boolean; + sourceId?: string; + sourceType?: string; + sourceUrl?: string; + thumbnailUrl?: string; } export interface ExtendedTextMessageData { diff --git a/src/types/index.ts b/src/types/index.ts index 523a808..c3ee476 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -6,6 +6,7 @@ import { Color } from 'antd/es/color-picker'; import { Button, ExpandedInstanceInterface, + ExtendedTextMessage, FontType, GetContactInfoResponseInterface, GetGroupDataSuccessResponseInterface, @@ -371,6 +372,7 @@ export interface MessageDataForRender { quotedMessage?: QuotedMessageInterface; templateMessage?: ParsedWabaTemplateInterface; interactiveButtonsMessage?: ParsedWabaTemplateInterface; + extendedTextMessage?: ExtendedTextMessage; caption?: string; fileName?: string; isDeleted?: boolean; diff --git a/src/utils/component.utils.tsx b/src/utils/component.utils.tsx index 5fd33b9..72d0acd 100644 --- a/src/utils/component.utils.tsx +++ b/src/utils/component.utils.tsx @@ -107,7 +107,11 @@ export function getFormattedMessage( if (!formattedText) { return textMessage; } - return {parse(formattedText)}; + return ( + + {parse(formattedText)} + + ); } export function fillString(string: string, data: string[]) { diff --git a/src/utils/message.utils.ts b/src/utils/message.utils.ts index 7882e9a..47efbd4 100644 --- a/src/utils/message.utils.ts +++ b/src/utils/message.utils.ts @@ -2,6 +2,9 @@ import { MessageInterface } from 'types'; type MessageLike = Partial & Pick; +export const IMAGE_FALLBACK = + 'data:image/png;base64,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'; + export function getTextMessage(message: MessageLike) { if (message.typeMessage === 'reactionMessage') { return ( @@ -75,3 +78,13 @@ export function getJSONMessage(message: Partial): string { } } } + +export function getAdMsgUrlHostname(url?: string) { + if (!url) return null; + + try { + return new URL(url).hostname; + } catch { + return url; + } +}