Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thomas/list alerts #485

Merged
merged 2 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/app-builder/public/locales/en/navigation.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
"settings.case_manager": "Case Manager",
"settings.inboxes": "Inboxes",
"settings.tags": "Tags",
"transfercheck.transfers": "Transfers"
"transfercheck.transfers": "Transfers",
"transfercheck.alerts": "Alerts"
}
22 changes: 21 additions & 1 deletion packages/app-builder/public/locales/en/transfercheck.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@
"transfer_detail.status.suspected_fraud": "Suspected fraud",
"transfer_detail.status.confirmed_fraud": "Confirmed fraud",
"transfer_detail.title": "Transfer details",
"transfer_detail.transfer_status.title": "Transfer status",
"transfer_detail.transfer_data.title": "Transfer data",
"transfer_detail.transfer_data.description": "Here is the transfer id associated to the source information system <TransferIdLabel>transfer_id</TransferIdLabel>: <TransferIdValue>{{transferId}}</TransferIdValue>"
"transfer_detail.transfer_data.description": "Here is the transfer id associated to the source information system <TransferIdLabel>transfer_id</TransferIdLabel>: <TransferIdValue>{{transferId}}</TransferIdValue>",
"transfer_detail.transfer_data.sender": "Sender",
"transfer_detail.transfer_data.beneficiary": "Beneficiary",
"transfer_detail.transfer_data.label": "Label",
"transfer_detail.transfer_data.currency": "Currency",
"transfer_detail.transfer_data.value": "Value",
"transfer_detail.transfer_data.requested_at": "Requested at",
"transfer_detail.transfer_data.created_at": "Created at",
"transfer_detail.transfer_data.updated_at": "Updated at",
"transfer_detail.transfer_data.account_id": "Account id",
"transfer_detail.transfer_data.account_type": "Account type",
"transfer_detail.transfer_data.bic": "BIC",
"transfer_detail.transfer_data.device": "Device",
"transfer_detail.transfer_data.ip": "IP",
"transfer_detail.transfer_data.name": "Name",
"alerts.empty": "You have no alerts",
"alerts.search.empty": "No alert found",
"alert_detail.title": "Alert details",
"alert_detail.alert_data.title": "Alert data",
"alert_detail.alert_data.transfer_id": "Here is the transfer id associated to this alert <TransferIdLabel>transfer_id</TransferIdLabel>: <TransferIdValue>{{transferId}}</TransferIdValue>"
}
2 changes: 1 addition & 1 deletion packages/app-builder/src/components/HelpCenter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ export function useMarbleCoreResources() {
return t('navigation:scenarios');
if (location.pathname.startsWith(getRoute('/lists/')))
return t('navigation:lists');
if (location.pathname.startsWith(getRoute('/workflows/')))
if (location.pathname.startsWith(getRoute('/workflows')))
return t('navigation:workflows');
if (location.pathname.startsWith(getRoute('/data')))
return t('navigation:data');
Expand Down
1 change: 1 addition & 0 deletions packages/app-builder/src/components/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { type IconProps } from 'packages/ui-icons/src/Icon';
import * as React from 'react';
import { useTranslation } from 'react-i18next';

//TODO(split apps): refactor this to be translation agnostic: directly pass the translated string (it will help separate the navigation.json file per "app")
export const navigationI18n = ['navigation'] satisfies Namespace;

export interface SidebarLinkProps {
Expand Down
148 changes: 148 additions & 0 deletions packages/app-builder/src/components/TransferAlerts/AlertData.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { type TransferAlert } from '@app-builder/models/transfer-alert';
import {
formatDateRelative,
formatDateTime,
useFormatLanguage,
} from '@app-builder/utils/format';
import { useGetCopyToClipboard } from '@app-builder/utils/use-get-copy-to-clipboard';
import { Trans, useTranslation } from 'react-i18next';
import { Tooltip } from 'ui-design-system';

import { Callout } from '../Callout';
import { alertsI18n } from './alerts-i18n';

interface AlertDataProps {
alert: TransferAlert;
}

export function AlertData({ alert }: AlertDataProps) {
const { t } = useTranslation(alertsI18n);
const language = useFormatLanguage();
const getCopyToClipboardProps = useGetCopyToClipboard();

return (
<div className="grid grid-cols-2 gap-8">
<Callout className="col-span-2" variant="outlined" color="red">
<div className="flex flex-col gap-2">
<Tooltip.Default
content={
<span className="text-grey-100 text-s">
{formatDateTime(alert.createdAt, {
language,
})}
</span>
}
>
<span className="text-grey-50 text-s w-fit first-letter:capitalize">
{formatDateRelative(alert.createdAt, {
language,
})}
</span>
</Tooltip.Default>

<span className="whitespace-pre-wrap">{alert.message}</span>
</div>
</Callout>

<table className="border-grey-10 h-fit w-full table-auto border-separate border-spacing-0 overflow-hidden rounded-lg border">
<thead>
<tr>
<th className="bg-grey-02 h-12 px-4" colSpan={2}>
Sender
</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-grey-50 text-s border-grey-10 border-t p-4">
IBAN
</td>
<td className="text-grey-100 text-s border-grey-10 border-t p-4">
{alert.beneficiaryIban}
</td>
</tr>
</tbody>
</table>

<table className="border-grey-10 h-fit w-full table-auto border-separate border-spacing-0 overflow-hidden rounded-lg border">
<thead>
<tr>
<th className="bg-grey-02 h-12 px-4" colSpan={2}>
Beneficiary
</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-grey-50 text-s border-grey-10 border-t p-4">
IBAN
</td>
<td className="text-grey-100 text-s border-grey-10 border-t p-4">
{alert.beneficiaryIban}
</td>
</tr>
</tbody>
</table>

<p className="col-span-2 whitespace-pre-wrap">
<Trans
t={t}
i18nKey="transfercheck:alert_detail.alert_data.transfer_id"
components={{
TransferIdLabel: <code className="select-none" />,
TransferIdValue: (
<code
className="border-grey-10 cursor-pointer select-none rounded-sm border px-1"
{...getCopyToClipboardProps(alert.transferEndToEndId)}
/>
),
}}
values={{
transferId: alert.transferEndToEndId,
}}
/>
</p>
</div>
);
}

export function AlertData2({ alert }: AlertDataProps) {
const language = useFormatLanguage();

return (
<div className="flex flex-col gap-8">
<Callout variant="outlined" color="red">
<div className="flex flex-col gap-2">
<Tooltip.Default
content={
<span className="text-grey-100 text-s">
{formatDateTime(alert.createdAt, {
language,
})}
</span>
}
>
<span className="text-grey-50 text-s w-fit first-letter:capitalize">
{formatDateRelative(alert.createdAt, {
language,
})}
</span>
</Tooltip.Default>

<span className="whitespace-pre-wrap">{alert.message}</span>
</div>
</Callout>

<div className="grid w-full grid-cols-[max-content_1fr] gap-x-8 gap-y-2">
<span className="text-grey-50 text-s">Transfer ID</span>
<span className="text-grey-100 text-s">{alert.transferEndToEndId}</span>

<span className="text-grey-50 text-s">Sender IBAN</span>
<span className="text-grey-100 text-s">{alert.senderIban}</span>

<span className="text-grey-50 text-s">Beneficiary IBAN</span>
<span className="text-grey-100 text-s">{alert.beneficiaryIban}</span>
</div>
</div>
);
}
105 changes: 105 additions & 0 deletions packages/app-builder/src/components/TransferAlerts/AlertsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { type TransferAlert } from '@app-builder/models/transfer-alert';
import { formatDateTime, useFormatLanguage } from '@app-builder/utils/format';
import { getRoute } from '@app-builder/utils/routes';
import { fromUUID } from '@app-builder/utils/short-uuid';
import { Link } from '@remix-run/react';
import { createColumnHelper, getCoreRowModel } from '@tanstack/react-table';
import clsx from 'clsx';
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { Table, useTable } from 'ui-design-system';

import { alertsI18n } from './alerts-i18n';

interface AlertsListProps {
alerts: TransferAlert[];
}

const columnHelper = createColumnHelper<TransferAlert>();

export function AlertsList({ alerts }: AlertsListProps) {
const { t } = useTranslation(alertsI18n);
const language = useFormatLanguage();

const columns = React.useMemo(
() => [
columnHelper.accessor((row) => row.status, {
id: 'status',
header: 'Status',
size: 50,
}),
columnHelper.accessor((row) => row.message, {
id: 'message',
header: 'Message',
size: 200,
cell: ({ getValue }) => {
const message = getValue();
return <div className="py-2">{message}</div>;
},
}),
columnHelper.accessor((row) => row.createdAt, {
id: 'createdAt',
header: 'Created At',
size: 100,
cell: ({ getValue }) => {
const dateTime = getValue();
return (
<time dateTime={dateTime}>
{formatDateTime(dateTime, { language, timeStyle: undefined })}
</time>
);
},
}),
],
[language],
);

const { rows, table, getBodyProps, getContainerProps } = useTable({
data: alerts,
columns,
columnResizeMode: 'onChange',
getCoreRowModel: getCoreRowModel(),
rowLink: (alert) => (
<Link
to={getRoute('/transfercheck/alerts/:alertId', {
alertId: fromUUID(alert.id),
})}
/>
),
});

if (rows.length === 0 || alerts.length === 0) {
const emptyMessage =
alerts.length === 0
? t('transfercheck:alerts.empty')
: t('transfercheck:alerts.search.empty');
return (
<div className="bg-grey-00 border-grey-10 flex h-28 max-w-3xl flex-col items-center justify-center rounded-lg border border-solid p-4">
<p className="text-s font-medium">{emptyMessage}</p>
</div>
);
}

return (
<Table.Container {...getContainerProps()}>
<Table.Header headerGroups={table.getHeaderGroups()} />
<Table.Body {...getBodyProps()}>
{rows.map((row) => {
const bgClassName =
row.original.status === 'unread' ? 'bg-grey-00' : 'transparent';
return (
<Table.Row
key={row.id}
tabIndex={0}
className={clsx(
'hover:bg-grey-02 relative cursor-pointer',
bgClassName,
)}
row={row}
/>
);
})}
</Table.Body>
</Table.Container>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { type Namespace } from 'i18next';

export const alertsI18n = ['common', 'transfercheck'] satisfies Namespace;
Loading
Loading