Skip to content
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 src/components/Table/TableHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {StyleSheet, View} from 'react-native';

import type {TableColumn, TableData} from './types';

import getGridTemplateColumns from './getGridTemplateColumns';
import {getColumnHeaderAccessibilityProps, getRowAccessibilityProps, shouldUseTableSemantics} from './tableAccessibility';
import {useTableContext} from './TableContext';

Expand Down Expand Up @@ -79,7 +80,7 @@ function TableHeader<DataType extends TableData, ColumnKey extends string = stri
return null;
}

const gridTemplateColumns = columns.map((column) => (column.width ? `${column.width}px` : '1fr'));
const gridTemplateColumns = getGridTemplateColumns(columns);

if (isSelectionCheckboxVisible) {
gridTemplateColumns.unshift(`${variables.tableCheckboxColumnWidth}px`);
Expand Down
3 changes: 2 additions & 1 deletion src/components/Table/TableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import React from 'react';
import {View} from 'react-native';
import Animated from 'react-native-reanimated';

import getGridTemplateColumns from './getGridTemplateColumns';
import {assignCellColumnIndexes, getCellAccessibilityProps, getRowAccessibilityProps, shouldUseTableSemantics} from './tableAccessibility';
import {useTableContext} from './TableContext';

Expand Down Expand Up @@ -82,7 +83,7 @@ export default function TableRow({
const item = processedData.at(rowIndex);
const rowCount = processedData.length;
const isTableSemanticsEnabled = shouldUseTableSemantics(shouldUseNarrowTableLayout);
const gridTemplateColumns = columns.map((column) => (column.width ? `${column.width}px` : '1fr'));
const gridTemplateColumns = getGridTemplateColumns(columns);
const isSelectionCheckboxVisible = selectionEnabled && (isMobileSelectionEnabled || !selectionUsesNarrowLayout);

const isDisabled = !!disabled;
Expand Down
13 changes: 13 additions & 0 deletions src/components/Table/getGridTemplateColumns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type {TableColumn} from './types';

/**
* Builds the CSS grid track list that lays out a table's columns on wide layouts.
*
* A column with a fixed `width` gets a `px` track. Every other column gets an `fr` track sized by its
* `styling.flex`, so a column can claim a larger share of the leftover space than its siblings.
*/
function getGridTemplateColumns<ColumnKey extends string = string>(columns: Array<TableColumn<ColumnKey>>): string[] {
return columns.map((column) => (column.width ? `${column.width}px` : `${column.styling?.flex ?? 1}fr`));
}

export default getGridTemplateColumns;
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default function WorkspaceExpensifyCardsTableRow({item, rowIndex, shouldU
const statusTranslationKey = getTranslationKeyForCardStatus(item.card.state, item.isVirtual);
const statusLabel = statusTranslationKey ? translate(statusTranslationKey) : '';
const formattedLimit = convertToShortDisplayString(item.limit, item.currency);
const formattedRemainingLimit = convertToShortDisplayString(item.remainingLimit, item.currency);
const formattedFrozenDate = item.frozenDate ? DateUtils.formatWithUTCTimeZone(item.frozenDate, CONST.DATE.MONTH_DAY_YEAR_ABBR_FORMAT) : '';
let frozenByText: string | undefined;
if (formattedFrozenDate) {
Expand All @@ -65,7 +66,9 @@ export default function WorkspaceExpensifyCardsTableRow({item, rowIndex, shouldU
}
}

const accessibilityLabel = [cardholderName, item.name, cardType, limitTypeLabel, item.lastFourPAN, statusLabel, formattedLimit, frozenByText].filter(Boolean).join(', ');
const accessibilityLabel = [cardholderName, item.name, cardType, limitTypeLabel, item.lastFourPAN, statusLabel, formattedLimit, formattedRemainingLimit, frozenByText]
.filter(Boolean)
.join(', ');

const frozenByRowFooter = !!frozenByText && (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mt1]}>
Expand Down Expand Up @@ -138,7 +141,7 @@ export default function WorkspaceExpensifyCardsTableRow({item, rowIndex, shouldU

{!shouldUseNarrowTableLayout && (
<View
style={[styles.flex1, styles.flexRow, styles.alignItemsCenter]}
style={[styles.flex1, styles.mnw0, styles.flexRow, styles.alignItemsCenter]}
{...getCellAccessibilityProps(isTableSemanticsEnabled)}
>
<TextWithTooltip
Expand Down Expand Up @@ -212,6 +215,19 @@ export default function WorkspaceExpensifyCardsTableRow({item, rowIndex, shouldU
)}
</View>

{!shouldUseNarrowTableLayout && (
<View
style={[styles.flex1, styles.flexRow, styles.alignItemsCenter, styles.justifyContentEnd]}
{...getCellAccessibilityProps(isTableSemanticsEnabled)}
>
<TextWithTooltip
shouldShowTooltip
numberOfLines={1}
text={formattedRemainingLimit}
/>
</View>
)}

<View
style={[styles.flexRow, styles.alignItemsCenter, styles.justifyContentEnd, styles.gap3]}
{...getCellAccessibilityProps(isTableSemanticsEnabled)}
Expand Down
29 changes: 27 additions & 2 deletions src/components/Tables/WorkspaceExpensifyCardsTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {View} from 'react-native';

import WorkspaceExpensifyCardsTableRow from './WorkspaceExpensifyCardsTableRow';

type WorkspaceExpensifyCardTableColumnKey = 'name' | 'type' | 'limitType' | 'lastFour' | 'status' | 'limit' | 'actions';
type WorkspaceExpensifyCardTableColumnKey = 'name' | 'type' | 'limitType' | 'lastFour' | 'status' | 'limit' | 'remainingLimit' | 'actions';

type WorkspaceExpensifyCardTableRowData = TableData & {
cardID: number;
Expand All @@ -37,6 +37,7 @@ type WorkspaceExpensifyCardTableRowData = TableData & {
name: string;
cardholder?: PersonalDetails | null;
limit: number;
remainingLimit: number;
currency?: string;
isVirtual: boolean;
limitType: CardLimitType | undefined;
Expand Down Expand Up @@ -109,31 +110,43 @@ export default function WorkspaceExpensifyCardsTable({
key: 'name',
label: translate('workspace.expensifyCard.name'),
sortable: true,
styling: {
// Cardholder names and card titles are the longest values in the table, so this column takes the
// space freed up by giving Type, Last 4 and Status fixed widths. Limit type still needs a full share
// to fit its longest value, so this stops at double rather than taking everything.
flex: 2,
},
},
{
key: 'type',
label: translate('common.type'),
sortable: true,
width: variables.tableTypeColumnWidth,
styling: {
containerStyles: [styles.mnw0],
},
},
{
key: 'limitType',
label: translate('workspace.card.issueNewCard.limitType'),
sortable: true,
styling: {
// minWidth: 0 lets the grid track size purely from its 1fr share instead of the cell content,
// so the Limit type and Status columns always render at the same width.
// so a long limit type value truncates instead of widening the column.
containerStyles: [styles.mnw0],
},
},
{
key: 'lastFour',
label: translate('workspace.expensifyCard.lastFour'),
sortable: true,
width: variables.tableLastFourColumnWidth,
},
{
key: 'status',
label: translate('common.status'),
sortable: true,
width: variables.tableCardStatusColumnWidth,
styling: {
containerStyles: [styles.mnw0],
},
Expand All @@ -146,6 +159,14 @@ export default function WorkspaceExpensifyCardsTable({
containerStyles: [styles.justifyContentEnd],
},
},
{
key: 'remainingLimit',
label: translate('workspace.expensifyCard.remaining'),
sortable: true,
styling: {
containerStyles: [styles.justifyContentEnd],
},
},
{
key: 'actions',
label: '',
Expand Down Expand Up @@ -185,6 +206,10 @@ export default function WorkspaceExpensifyCardsTable({
return (item1.limit - item2.limit) * orderMultiplier;
}

if (activeSorting.columnKey === 'remainingLimit') {
return (item1.remainingLimit - item2.remainingLimit) * orderMultiplier;
}

const cardholderName1 = item1.cardholder?.displayName ?? item1.cardholder?.login ?? '';
const cardholderName2 = item2.cardholder?.displayName ?? item2.cardholder?.login ?? '';
return localeCompare(cardholderName1, cardholderName2) * orderMultiplier;
Expand Down
1 change: 1 addition & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5943,6 +5943,7 @@ _Für ausführlichere Anweisungen [besuchen Sie unsere Hilfeseite](${CONST.NETSU
balanceWillBeSettledOn: (settlementDate: string) => `Der Saldo wird am ${settlementDate} ausgeglichen.`,
settleBalance: 'Saldo ausgleichen',
cardLimit: 'Kartenlimit',
remaining: 'Verbleibend',
remainingLimit: 'Verbleibendes Limit',
requestLimitIncrease: 'Anhebung des Anfragelimits',
remainingLimitDescription:
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6032,6 +6032,7 @@ const translations = {
balanceWillBeSettledOn: (settlementDate: string) => `Balance will be settled on ${settlementDate}`,
settleBalance: 'Settle balance',
cardLimit: 'Card limit',
remaining: 'Remaining',
remainingLimit: 'Remaining limit',
requestLimitIncrease: 'Request limit increase',
remainingLimitDescription:
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5780,6 +5780,7 @@ ${amount} para ${merchant} - ${date}`,
balanceWillBeSettledOn: (settlementDate) => `El saldo se liquidará el ${settlementDate}.`,
settleBalance: 'Liquidar saldo',
cardLimit: 'Límite de la tarjeta',
remaining: 'Restante',
remainingLimit: 'Límite restante',
requestLimitIncrease: 'Solicitar aumento de límite',
remainingLimitDescription:
Expand Down
1 change: 1 addition & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5955,6 +5955,7 @@ _Pour des instructions plus détaillées, [visitez notre site d’aide](${CONST.
balanceWillBeSettledOn: (settlementDate: string) => `Le solde sera réglé le ${settlementDate}`,
settleBalance: 'Régler le solde',
cardLimit: 'Plafond de carte',
remaining: 'Restant',
remainingLimit: 'Plafond restant',
requestLimitIncrease: 'Demander une augmentation de la limite',
remainingLimitDescription:
Expand Down
1 change: 1 addition & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5912,6 +5912,7 @@ _Per istruzioni più dettagliate, [visita il nostro sito di assistenza](${CONST.
balanceWillBeSettledOn: (settlementDate: string) => `Il saldo sarà regolato il ${settlementDate}`,
settleBalance: 'Saldo da saldare',
cardLimit: 'Limite carta',
remaining: 'Rimanente',
remainingLimit: 'Limite rimanente',
requestLimitIncrease: 'Richiedi aumento limite',
remainingLimitDescription:
Expand Down
1 change: 1 addition & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5851,6 +5851,7 @@ _詳しい手順については、[ヘルプサイトをご覧ください](${CO
balanceWillBeSettledOn: (settlementDate: string) => `残高は${settlementDate}に精算されます`,
settleBalance: '残高を清算',
cardLimit: 'カード上限',
remaining: '残り',
remainingLimit: '残りの上限',
requestLimitIncrease: 'リクエスト上限の引き上げ',
remainingLimitDescription:
Expand Down
1 change: 1 addition & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5906,6 +5906,7 @@ _Voor meer gedetailleerde instructies, [bezoek onze help-site](${CONST.NETSUITE_
balanceWillBeSettledOn: (settlementDate: string) => `Saldo wordt vereffend op ${settlementDate}`,
settleBalance: 'Saldo vereffenen',
cardLimit: 'Kaartlimiet',
remaining: 'Resterend',
remainingLimit: 'Resterende limiet',
requestLimitIncrease: 'Verhoging van limiet aanvragen',
remainingLimitDescription:
Expand Down
1 change: 1 addition & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5886,6 +5886,7 @@ _Aby uzyskać bardziej szczegółowe instrukcje, [odwiedź naszą stronę pomocy
balanceWillBeSettledOn: (settlementDate: string) => `Saldo zostanie rozliczone w dniu ${settlementDate}`,
settleBalance: 'Ureguluj saldo',
cardLimit: 'Limit karty',
remaining: 'Pozostało',
remainingLimit: 'Pozostały limit',
requestLimitIncrease: 'Zwiększ limit żądań',
remainingLimitDescription:
Expand Down
1 change: 1 addition & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5900,6 +5900,7 @@ _Para instruções mais detalhadas, [visite nossa central de ajuda](${CONST.NETS
balanceWillBeSettledOn: (settlementDate: string) => `O saldo será liquidado em ${settlementDate}`,
settleBalance: 'Quitar saldo',
cardLimit: 'Limite do cartão',
remaining: 'Restante',
remainingLimit: 'Limite restante',
requestLimitIncrease: 'Solicitar aumento de limite',
remainingLimitDescription:
Expand Down
1 change: 1 addition & 0 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5728,6 +5728,7 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM
balanceWillBeSettledOn: (settlementDate: string) => `余额将于 ${settlementDate} 结清`,
settleBalance: '结清余额',
cardLimit: '卡片限额',
remaining: '剩余',
remainingLimit: '剩余额度',
requestLimitIncrease: '请求提高限额',
remainingLimitDescription:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ function WorkspaceExpensifyCardListPage({route, cardsList, fundID}: WorkspaceExp
name: card.nameValuePairs?.cardTitle ?? '',
cardholder: personalDetails?.[card.accountID ?? CONST.DEFAULT_NUMBER_ID],
limit: card.nameValuePairs?.unapprovedExpenseLimit ?? 0,
remainingLimit: card.availableSpend ?? 0,
currency: settlementCurrency,
isVirtual: !!card.nameValuePairs?.isVirtual,
limitType: card.nameValuePairs?.limitType,
Expand Down
2 changes: 2 additions & 0 deletions src/styles/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ export default {
tableRequireFieldsTypeColumnWidth: 112,
tableSwitchColumnWidth: 58,
tableCaretColumnWidth: 20,
tableLastFourColumnWidth: 72,
tableCardStatusColumnWidth: 128,
workspaceTagsTableCountColumnWidth: 100,
domainTableActionColumnWidth: 64,
domainAdminsTableActionColumnWidth: 140,
Expand Down
Loading