diff --git a/apps/ui/public/locales/en.json b/apps/ui/public/locales/en.json index 05ac6e01..a110c787 100644 --- a/apps/ui/public/locales/en.json +++ b/apps/ui/public/locales/en.json @@ -98,6 +98,7 @@ "email": "Email", "ended_at": "Ended At", "endpoint": "Endpoint", + "engagement": "Engagement", "enter_email": "Enter email...", "entrance": "Entrance", "entrance_add_everyone_from": "Add everyone from", diff --git a/apps/ui/public/locales/es.json b/apps/ui/public/locales/es.json index 1183bab3..65aab92c 100644 --- a/apps/ui/public/locales/es.json +++ b/apps/ui/public/locales/es.json @@ -98,6 +98,7 @@ "email": "Email", "ended_at": "Terminó en", "endpoint": "Punto de conexión", + "engagement": "Participación", "enter_email": "Introducir email...", "entrance": "Entrada", "entrance_add_everyone_from": "Añade a todos los de", diff --git a/apps/ui/src/ui/DataTable.css b/apps/ui/src/ui/DataTable.css index aae41bd0..12de4b19 100644 --- a/apps/ui/src/ui/DataTable.css +++ b/apps/ui/src/ui/DataTable.css @@ -94,6 +94,10 @@ column-gap: 10px; } +.ui-table .table-cell .multi-cell.no-image { + grid-template-areas: "text text"; +} + .ui-table .table-cell .multi-cell .text { grid-area: text; } diff --git a/apps/ui/src/ui/DataTable.tsx b/apps/ui/src/ui/DataTable.tsx index d9d4d778..55cac170 100644 --- a/apps/ui/src/ui/DataTable.tsx +++ b/apps/ui/src/ui/DataTable.tsx @@ -124,7 +124,7 @@ export function DataTable({ if (!col.cell) { if ((col.key.endsWith('_at') || col.key.endsWith('_until')) && (typeof value === 'string' || typeof value === 'number')) { - value = formatDate(preferences, value, 'Ppp') + value = formatDate(preferences, value, 'Pp') } if (typeof value === 'boolean') { value = value ? : diff --git a/apps/ui/src/views/campaign/Campaigns.tsx b/apps/ui/src/views/campaign/Campaigns.tsx index 47505dea..a6db5fea 100644 --- a/apps/ui/src/views/campaign/Campaigns.tsx +++ b/apps/ui/src/views/campaign/Campaigns.tsx @@ -33,12 +33,15 @@ export const CampaignTag = ({ state }: { state: CampaignState }) => { } export const DeliveryRatio = ({ delivery }: { delivery: CampaignDelivery }) => { - const sent = (delivery?.sent ?? 0).toLocaleString() - const total = (delivery?.total ?? 0).toLocaleString() - return `${sent} / ${total}` + const sent = (delivery?.sent ?? 0) + const total = (delivery?.total ?? 0) + const ratio = sent > 0 ? sent / total : 0 + const sentStr = sent.toLocaleString() + const ratioStr = ratio.toLocaleString(undefined, { style: 'percent', minimumFractionDigits: 0 }) + return `${sentStr} (${ratioStr})` } -export const OpenRatio = ({ delivery }: { delivery: CampaignDelivery }) => { +export const OpenRate = ({ delivery }: { delivery: CampaignDelivery }) => { const opens = (delivery?.opens ?? 0) const sent = (delivery?.sent ?? 0) const ratio = sent > 0 ? opens / sent : 0 @@ -47,7 +50,7 @@ export const OpenRatio = ({ delivery }: { delivery: CampaignDelivery }) => { return `${opensStr} (${ratioStr})` } -export const ClickRatio = ({ delivery }: { delivery: CampaignDelivery }) => { +export const ClickRate = ({ delivery }: { delivery: CampaignDelivery }) => { const clicks = (delivery?.clicks ?? 0) const sent = (delivery?.sent ?? 0) const ratio = sent > 0 ? clicks / sent : 0 @@ -135,14 +138,22 @@ export default function Campaigns() { cell: ({ item: { delivery } }) => DeliveryRatio({ delivery }), }, { - key: 'open_rate', - title: t('open_rate'), - cell: ({ item: { delivery } }) => OpenRatio({ delivery }), - }, - { - key: 'click_rate', - title: t('click_rate'), - cell: ({ item: { delivery } }) => ClickRatio({ delivery }), + key: 'engagement', + title: t('engagement'), + cell: ({ item: { channel, delivery } }) => delivery.opens > 0 + ? ( +
+
+
+ {OpenRate({ delivery })} {t('open_rate')} +
+ {channel === 'email' &&
+ {ClickRate({ delivery })} {t('click_rate')} +
} +
+
+ ) + : null, }, { key: 'send_at', @@ -150,7 +161,7 @@ export default function Campaigns() { title: t('launched_at'), cell: ({ item: { send_at, type } }) => { return send_at != null - ? formatDate(preferences, send_at, 'Ppp') + ? formatDate(preferences, send_at, 'Pp') : type === 'trigger' ? t('api_triggered') : <>–