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: 3 additions & 0 deletions src/components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ function Search({query, policyIDs, sortBy, sortOrder}: SearchProps) {

const isSortingAllowed = sortableSearchTabs.includes(query);

const shouldShowYear = SearchUtils.shouldShowYear(searchResults?.data);

return (
<SelectionList<ReportListItemType | TransactionListItemType>
customListHeader={
Expand All @@ -131,6 +133,7 @@ function Search({query, policyIDs, sortBy, sortOrder}: SearchProps) {
sortOrder={sortOrder}
isSortingAllowed={isSortingAllowed}
sortBy={sortBy}
shouldShowYear={shouldShowYear}
/>
}
// To enhance the smoothness of scrolling and minimize the risk of encountering blank spaces during scrolling,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import DateUtils from '@libs/DateUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
import variables from '@styles/variables';
Expand Down Expand Up @@ -87,7 +88,9 @@ function ReceiptCell({transactionItem}: TransactionCellProps) {

function DateCell({transactionItem, showTooltip, isLargeScreenWidth}: TransactionCellProps) {
const styles = useThemeStyles();
const date = TransactionUtils.getCreated(transactionItem, CONST.DATE.MONTH_DAY_ABBR_FORMAT);

const created = TransactionUtils.getCreated(transactionItem);
const date = DateUtils.formatWithUTCTimeZone(created, DateUtils.doesDateBelongToAPastYear(created) ? CONST.DATE.MONTH_DAY_YEAR_ABBR_FORMAT : CONST.DATE.MONTH_DAY_ABBR_FORMAT);

return (
<TextWithTooltip
Expand Down Expand Up @@ -283,7 +286,7 @@ function TransactionListItemRow({item, showTooltip, onButtonPress, showItemHeade
showTooltip={false}
/>
</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.DATE)]}>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.DATE, item.shouldShowYear)]}>
<DateCell
transactionItem={item}
showTooltip={showTooltip}
Expand Down
5 changes: 3 additions & 2 deletions src/components/SelectionList/SearchTableHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,10 @@ type SearchTableHeaderProps = {
sortOrder?: SortOrder;
isSortingAllowed: boolean;
onSortPress: (column: SearchColumnType, order: SortOrder) => void;
shouldShowYear: boolean;
};

function SearchTableHeader({data, sortBy, sortOrder, isSortingAllowed, onSortPress}: SearchTableHeaderProps) {
function SearchTableHeader({data, sortBy, sortOrder, isSortingAllowed, onSortPress, shouldShowYear}: SearchTableHeaderProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {isSmallScreenWidth, isMediumScreenWidth} = useWindowDimensions();
Expand Down Expand Up @@ -123,7 +124,7 @@ function SearchTableHeader({data, sortBy, sortOrder, isSortingAllowed, onSortPre
textStyle={textStyle}
sortOrder={sortOrder ?? CONST.SORT_ORDER.ASC}
isActive={isActive}
containerStyle={[StyleUtils.getSearchTableColumnStyles(columnName)]}
containerStyle={[StyleUtils.getSearchTableColumnStyles(columnName, shouldShowYear)]}
isSortable={isSortable}
onPress={(order: SortOrder) => onSortPress(columnName, order)}
/>
Expand Down
5 changes: 5 additions & 0 deletions src/components/SelectionList/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ type TransactionListItemType = ListItem &

/** Whether we should show the tax column */
shouldShowTax: boolean;

/** Whether we should show the transaction year.
* This is true if at least one transaction in the dataset was created in past years
*/
shouldShowYear: boolean;
};

type ReportListItemType = ListItem &
Expand Down
6 changes: 6 additions & 0 deletions src/libs/DateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,11 @@ function getFormattedTransportDate(date: Date): string {
return `${translateLocal('travel.departs')} ${format(date, 'EEEE, MMM d, yyyy')} ${translateLocal('common.conjunctionAt')} ${format(date, 'HH:MM')}`;
}

function doesDateBelongToAPastYear(date: string): boolean {
const transactionYear = new Date(date).getFullYear();
return transactionYear !== new Date().getFullYear();
}

const DateUtils = {
formatToDayOfWeek,
formatToLongDateWithWeekday,
Expand Down Expand Up @@ -831,6 +836,7 @@ const DateUtils = {
getFormattedDateRange,
getFormattedReservationRangeDate,
getFormattedTransportDate,
doesDateBelongToAPastYear,
};

export default DateUtils;
4 changes: 2 additions & 2 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2567,7 +2567,7 @@ function getTransactionDetails(transaction: OnyxInputOrEntry<Transaction>, creat
}
const report = getReport(transaction?.reportID);
return {
created: TransactionUtils.getCreated(transaction, createdDateFormat),
created: TransactionUtils.getFormattedCreated(transaction, createdDateFormat),
amount: TransactionUtils.getAmount(transaction, !isEmptyObject(report) && isExpenseReport(report)),
taxAmount: TransactionUtils.getTaxAmount(transaction, !isEmptyObject(report) && isExpenseReport(report)),
taxCode: TransactionUtils.getTaxCode(transaction),
Expand Down Expand Up @@ -3085,7 +3085,7 @@ function getModifiedExpenseOriginalMessage(
originalMessage.newComment = transactionChanges?.comment;
}
if ('created' in transactionChanges) {
originalMessage.oldCreated = TransactionUtils.getCreated(oldTransaction);
originalMessage.oldCreated = TransactionUtils.getFormattedCreated(oldTransaction);
originalMessage.created = transactionChanges?.created;
}
if ('merchant' in transactionChanges) {
Expand Down
44 changes: 43 additions & 1 deletion src/libs/SearchUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type * as OnyxTypes from '@src/types/onyx';
import type {SearchAccountDetails, SearchDataTypes, SearchPersonalDetails, SearchTransaction, SearchTypeToItemMap, SectionsType} from '@src/types/onyx/SearchResults';
import DateUtils from './DateUtils';
import getTopmostCentralPaneRoute from './Navigation/getTopmostCentralPaneRoute';
import navigationRef from './Navigation/navigationRef';
import type {CentralPaneNavigatorParamList, RootStackParamList, State} from './Navigation/types';
Expand Down Expand Up @@ -76,9 +77,46 @@ function getShouldShowMerchant(data: OnyxTypes.SearchResults['data']): boolean {
});
}

const currentYear = new Date().getFullYear();

function isReportListItemType(item: TransactionListItemType | ReportListItemType): item is ReportListItemType {
return 'transactions' in item;
}

function shouldShowYear(data: TransactionListItemType[] | ReportListItemType[] | OnyxTypes.SearchResults['data']): boolean {
if (Array.isArray(data)) {
return data.some((item: TransactionListItemType | ReportListItemType) => {
if (isReportListItemType(item)) {
// If the item is a ReportListItemType, iterate over its transactions and check them
return item.transactions.some((transaction) => {
const transactionYear = new Date(TransactionUtils.getCreated(transaction)).getFullYear();
return transactionYear !== currentYear;
});
}

const createdYear = new Date(item?.modifiedCreated ? item.modifiedCreated : item?.created || '').getFullYear();
return createdYear !== currentYear;
});
}

for (const [key, transactionItem] of Object.entries(data)) {
if (key.startsWith(ONYXKEYS.COLLECTION.TRANSACTION)) {
const item = transactionItem as SearchTransaction;
const date = TransactionUtils.getCreated(item);

if (DateUtils.doesDateBelongToAPastYear(date)) {
return true;
}
}
}
return false;
}

function getTransactionsSections(data: OnyxTypes.SearchResults['data']): TransactionListItemType[] {
const shouldShowMerchant = getShouldShowMerchant(data);

const doesDataContainAPastYearTransaction = shouldShowYear(data);

return Object.entries(data)
.filter(([key]) => key.startsWith(ONYXKEYS.COLLECTION.TRANSACTION))
.map(([, transactionItem]) => {
Expand All @@ -104,13 +142,16 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data']): Transac
shouldShowTag: true,
shouldShowTax: true,
keyForList: transactionItem.transactionID,
shouldShowYear: doesDataContainAPastYearTransaction,
};
});
}

function getReportSections(data: OnyxTypes.SearchResults['data']): ReportListItemType[] {
const shouldShowMerchant = getShouldShowMerchant(data);

const doesDataContainAPastYearTransaction = shouldShowYear(data);

const reportIDToTransactions: Record<string, ReportListItemType> = {};
for (const key in data) {
if (key.startsWith(ONYXKEYS.COLLECTION.REPORT)) {
Expand Down Expand Up @@ -146,6 +187,7 @@ function getReportSections(data: OnyxTypes.SearchResults['data']): ReportListIte
shouldShowTag: true,
shouldShowTax: true,
keyForList: transactionItem.transactionID,
shouldShowYear: doesDataContainAPastYearTransaction,
};
if (reportIDToTransactions[reportKey]?.transactions) {
reportIDToTransactions[reportKey].transactions.push(transaction);
Expand Down Expand Up @@ -230,5 +272,5 @@ function getSearchParams() {
return topmostCentralPaneRoute?.params as CentralPaneNavigatorParamList['Search_Central_Pane'];
}

export {getListItem, getQueryHash, getSections, getSortedSections, getShouldShowMerchant, getSearchType, getSearchParams};
export {getListItem, getQueryHash, getSections, getSortedSections, getShouldShowMerchant, getSearchType, getSearchParams, shouldShowYear};
export type {SearchColumnType, SortOrder};
12 changes: 8 additions & 4 deletions src/libs/TransactionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,13 +459,16 @@ function getTagForDisplay(transaction: OnyxEntry<Transaction>, tagIndex?: number
return getCleanedTagName(getTag(transaction, tagIndex));
}

function getCreated(transaction: OnyxInputOrEntry<Transaction>): string {
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
return transaction?.modifiedCreated ? transaction.modifiedCreated : transaction?.created || '';
}

/**
* Return the created field from the transaction, return the modifiedCreated if present.
*/
function getCreated(transaction: OnyxInputOrEntry<Transaction>, dateFormat: string = CONST.DATE.FNS_FORMAT_STRING): string {
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const created = transaction?.modifiedCreated ? transaction.modifiedCreated : transaction?.created || '';

function getFormattedCreated(transaction: OnyxInputOrEntry<Transaction>, dateFormat: string = CONST.DATE.FNS_FORMAT_STRING): string {
const created = getCreated(transaction);
return DateUtils.formatWithUTCTimeZone(created, dateFormat);
}

Expand Down Expand Up @@ -813,6 +816,7 @@ export {
getMerchant,
getMCCGroup,
getCreated,
getFormattedCreated,
getCategory,
getBillable,
getTag,
Expand Down
3 changes: 2 additions & 1 deletion src/pages/iou/request/step/IOURequestStepDate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ function IOURequestStepDate({
const isEditing = action === CONST.IOU.ACTION.EDIT;
// In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value
const isEditingSplitBill = iouType === CONST.IOU.TYPE.SPLIT && isEditing;
const currentCreated = isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? TransactionUtils.getCreated(splitDraftTransaction) : TransactionUtils.getCreated(transaction);
const currentCreated =
isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? TransactionUtils.getFormattedCreated(splitDraftTransaction) : TransactionUtils.getFormattedCreated(transaction);
const parentReportAction = reportActions?.[(isEditingSplitBill ? reportActionID : report?.parentReportActionID) ?? -1];
const canEditingSplitBill =
isEditingSplitBill && session && parentReportAction && session.accountID === parentReportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction);
Expand Down
4 changes: 2 additions & 2 deletions src/styles/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1556,14 +1556,14 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({
return isDragging ? styles.cursorGrabbing : styles.cursorZoomOut;
},

getSearchTableColumnStyles: (columnName: string): ViewStyle => {
getSearchTableColumnStyles: (columnName: string, shouldExtendDateColumn = false): ViewStyle => {
let columnWidth;
switch (columnName) {
case CONST.SEARCH_TABLE_COLUMNS.RECEIPT:
columnWidth = {...getWidthStyle(variables.w36), ...styles.alignItemsCenter};
break;
case CONST.SEARCH_TABLE_COLUMNS.DATE:
columnWidth = getWidthStyle(variables.w44);
columnWidth = getWidthStyle(shouldExtendDateColumn ? variables.w80 : variables.w44);
break;
case CONST.SEARCH_TABLE_COLUMNS.MERCHANT:
case CONST.SEARCH_TABLE_COLUMNS.FROM:
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/TransactionUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('TransactionUtils', () => {
it('returns the "modifiedCreated" date with the correct format', () => {
const expectedResult = '2023-10-25';

const result = TransactionUtils.getCreated(transaction);
const result = TransactionUtils.getFormattedCreated(transaction);

expect(result).toEqual(expectedResult);
});
Expand All @@ -39,7 +39,7 @@ describe('TransactionUtils', () => {
it('returns the "created" date with the correct format', () => {
const expectedResult = '2023-10-01';

const result = TransactionUtils.getCreated(transaction);
const result = TransactionUtils.getFormattedCreated(transaction);

expect(result).toEqual(expectedResult);
});
Expand All @@ -54,7 +54,7 @@ describe('TransactionUtils', () => {
it('returns an empty string', () => {
const expectedResult = '';

const result = TransactionUtils.getCreated(transaction);
const result = TransactionUtils.getFormattedCreated(transaction);

expect(result).toEqual(expectedResult);
});
Expand Down