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
5 changes: 5 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2239,6 +2239,11 @@ const ROUTES = {
getRoute: (policyID: string, cardID: string, feed: CompanyCardFeedWithDomainID) =>
`workspaces/${policyID}/company-cards/${encodeURIComponent(feed)}/${encodeURIComponent(cardID)}/edit/name` as const,
},
WORKSPACE_COMPANY_CARD_EDIT_TRANSACTION_START_DATE: {
route: 'workspaces/:policyID/company-cards/:feed/:cardID/edit/transaction-start-date',
getRoute: (policyID: string, cardID: string, feed: CompanyCardFeedWithDomainID) =>
`workspaces/${policyID}/company-cards/${encodeURIComponent(feed)}/${encodeURIComponent(cardID)}/edit/transaction-start-date` as const,
},
WORKSPACE_COMPANY_CARD_EXPORT: {
route: 'workspaces/:policyID/company-cards/:feed/:cardID/edit/export',
getRoute: (policyID: string, cardID: string, feed: CompanyCardFeedWithDomainID, backTo?: string) =>
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,7 @@ const SCREENS = {
COMPANY_CARDS_SETTINGS_STATEMENT_CLOSE_DATE: 'Workspace_CompanyCards_Settings_Statement_Close_Date',
COMPANY_CARD_DETAILS: 'Workspace_CompanyCard_Details',
COMPANY_CARD_EDIT_CARD_NAME: 'Workspace_CompanyCard_Edit_Card_Name',
COMPANY_CARD_EDIT_TRANSACTION_START_DATE: 'Workspace_CompanyCard_Edit_Transaction_Start_Date',
COMPANY_CARD_EXPORT: 'Workspace_CompanyCard_Export',
EXPENSIFY_CARD: 'Workspace_ExpensifyCard',
EXPENSIFY_CARD_DETAILS: 'Workspace_ExpensifyCard_Details',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type UpdateCardTransactionStartDateParams = {
authToken?: string | null;
cardID: number;
startDate: string;
};

export default UpdateCardTransactionStartDateParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ export type {default as AssignCompanyCardParams} from './AssignCompanyCardParams
export type {default as UnassignCompanyCard} from './UnassignCompanyCard';
export type {default as UpdateCompanyCard} from './UpdateCompanyCard';
export type {default as UpdateCompanyCardNameParams} from './UpdateCompanyCardNameParams';
export type {default as UpdateCardTransactionStartDateParams} from './UpdateCardTransactionStartDateParams';
export type {default as SetCompanyCardExportAccountParams} from './SetCompanyCardExportAccountParams';
export type {default as SetPersonalDetailsAndShipExpensifyCardsParams} from './SetPersonalDetailsAndShipExpensifyCardsParams';
export type {default as SetPersonalDetailsAndRevealExpensifyCardParams} from './SetPersonalDetailsAndRevealExpensifyCardParams';
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ const WRITE_COMMANDS = {
UNASSIGN_COMPANY_CARD: 'UnassignCard',
UPDATE_COMPANY_CARD: 'SyncCard',
UPDATE_COMPANY_CARD_NAME: 'SetCardName',
UPDATE_CARD_TRANSACTION_START_DATE: 'UpdateCardTransactionStartDate',
SET_CARD_EXPORT_ACCOUNT: 'SetCardExportAccount',
SET_PERSONAL_DETAILS_AND_SHIP_EXPENSIFY_CARDS: 'SetPersonalDetailsAndShipExpensifyCards',
SET_INVOICING_TRANSFER_BANK_ACCOUNT: 'SetInvoicingTransferBankAccount',
Expand Down Expand Up @@ -603,6 +604,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.UNASSIGN_COMPANY_CARD]: Parameters.UnassignCompanyCard;
[WRITE_COMMANDS.UPDATE_COMPANY_CARD]: Parameters.UpdateCompanyCard;
[WRITE_COMMANDS.UPDATE_COMPANY_CARD_NAME]: Parameters.UpdateCompanyCardNameParams;
[WRITE_COMMANDS.UPDATE_CARD_TRANSACTION_START_DATE]: Parameters.UpdateCardTransactionStartDateParams;
[WRITE_COMMANDS.SET_CARD_EXPORT_ACCOUNT]: Parameters.SetCompanyCardExportAccountParams;
[WRITE_COMMANDS.SET_COMPANY_CARD_TRANSACTION_LIABILITY]: Parameters.SetCompanyCardTransactionLiability;
[WRITE_COMMANDS.OPEN_POLICY_ADD_CARD_FEED_PAGE]: Parameters.OpenPolicyAddCardFeedPageParams;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,8 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.COMPANY_CARDS_ADD_NEW]: () => require<ReactComponentModule>('../../../../pages/workspace/companyCards/addNew/AddNewCardPage').default,
[SCREENS.WORKSPACE.COMPANY_CARD_DETAILS]: () => require<ReactComponentModule>('../../../../pages/workspace/companyCards/WorkspaceCompanyCardDetailsPage').default,
[SCREENS.WORKSPACE.COMPANY_CARD_EDIT_CARD_NAME]: () => require<ReactComponentModule>('../../../../pages/workspace/companyCards/WorkspaceCompanyCardEditCardNamePage').default,
[SCREENS.WORKSPACE.COMPANY_CARD_EDIT_TRANSACTION_START_DATE]: () =>
require<ReactComponentModule>('../../../../pages/workspace/companyCards/WorkspaceCompanyCardEditTransactionStartDatePage').default,
[SCREENS.WORKSPACE.COMPANY_CARD_EXPORT]: () => require<ReactComponentModule>('../../../../pages/workspace/companyCards/WorkspaceCompanyCardAccountSelectCardPage').default,
[SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW]: () => require<ReactComponentModule>('../../../../pages/workspace/expensifyCard/issueNew/IssueNewCardPage').default,
[SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW_CONFIRM_MAGIC_CODE]: () =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ const WORKSPACE_TO_RHP: Partial<Record<keyof WorkspaceSplitNavigatorParamList, s
SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD_INVITE_NEW_MEMBER,
SCREENS.WORKSPACE.COMPANY_CARD_DETAILS,
SCREENS.WORKSPACE.COMPANY_CARD_EDIT_CARD_NAME,
SCREENS.WORKSPACE.COMPANY_CARD_EDIT_TRANSACTION_START_DATE,
SCREENS.WORKSPACE.COMPANY_CARD_EXPORT,
],
[SCREENS.WORKSPACE.EXPENSIFY_CARD]: [
Expand Down
3 changes: 3 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,9 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
[SCREENS.WORKSPACE.COMPANY_CARD_EDIT_CARD_NAME]: {
path: ROUTES.WORKSPACE_COMPANY_CARD_EDIT_CARD_NAME.route,
},
[SCREENS.WORKSPACE.COMPANY_CARD_EDIT_TRANSACTION_START_DATE]: {
path: ROUTES.WORKSPACE_COMPANY_CARD_EDIT_TRANSACTION_START_DATE.route,
},
[SCREENS.WORKSPACE.COMPANY_CARD_EXPORT]: {
path: ROUTES.WORKSPACE_COMPANY_CARD_EXPORT.route,
},
Expand Down
5 changes: 5 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,11 @@ type SettingsNavigatorParamList = {
feed: CompanyCardFeedWithDomainID;
cardID: string;
};
[SCREENS.WORKSPACE.COMPANY_CARD_EDIT_TRANSACTION_START_DATE]: {
policyID: string;
feed: string;
cardID: string;
};
[SCREENS.WORKSPACE.COMPANY_CARD_EXPORT]: {
policyID: string;
cardID: string;
Expand Down
64 changes: 64 additions & 0 deletions src/libs/actions/CompanyCards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
RequestFeedSetupParams,
SetCompanyCardExportAccountParams,
SetFeedStatementPeriodEndDayParams,
UpdateCardTransactionStartDateParams,
UpdateCompanyCardNameParams,
} from '@libs/API/parameters';
import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
Expand Down Expand Up @@ -675,6 +676,68 @@ function updateCompanyCardName(domainOrWorkspaceAccountID: number, cardID: strin
API.write(WRITE_COMMANDS.UPDATE_COMPANY_CARD_NAME, parameters, {optimisticData, finallyData, failureData});
}

function updateCardTransactionStartDate(domainOrWorkspaceAccountID: number, cardID: string, newStartDate: string, bankName: CompanyCardFeed, oldStartDate?: string) {
const authToken = NetworkStore.getAuthToken();

const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${domainOrWorkspaceAccountID}_${bankName}`,
value: {
[cardID]: {
scrapeMinDate: newStartDate,
pendingFields: {
scrapeMinDate: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
errorFields: {
scrapeMinDate: null,
},
},
},
},
];

const finallyData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${domainOrWorkspaceAccountID}_${bankName}`,
value: {
[cardID]: {
pendingFields: {
scrapeMinDate: null,
},
},
},
},
];

const failureData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${domainOrWorkspaceAccountID}_${bankName}`,
value: {
[cardID]: {
scrapeMinDate: oldStartDate,
pendingFields: {
scrapeMinDate: null,
},
errorFields: {
scrapeMinDate: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'),
},
},
},
},
];

const parameters: UpdateCardTransactionStartDateParams = {
authToken,
cardID: Number(cardID),
startDate: newStartDate,
};

API.write(WRITE_COMMANDS.UPDATE_CARD_TRANSACTION_START_DATE, parameters, {optimisticData, finallyData, failureData});
}

function setCompanyCardExportAccount(policyID: string, domainOrWorkspaceAccountID: number, cardID: string, accountKey: string, newAccount: string, bank: CompanyCardFeed) {
const authToken = NetworkStore.getAuthToken();

Expand Down Expand Up @@ -980,6 +1043,7 @@ export {
resetFailedWorkspaceCompanyCardAssignment,
updateWorkspaceCompanyCard,
updateCompanyCardName,
updateCardTransactionStartDate,
setCompanyCardExportAccount,
clearCompanyCardErrorField,
setAddNewCompanyCardStepAndData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,20 @@ function WorkspaceCompanyCardDetailsPage({route}: WorkspaceCompanyCardDetailsPag
title={card?.isLoadingLastUpdated ? translate('workspace.moreFeatures.companyCards.updating') : lastScrape}
interactive={false}
/>
<MenuItemWithTopDescription
description={translate('workspace.moreFeatures.companyCards.transactionStartDate')}
title={card?.scrapeMinDate ? format(parseISO(card.scrapeMinDate), CONST.DATE.FNS_FORMAT_STRING) : ''}
interactive={false}
/>
<OfflineWithFeedback
pendingAction={card?.pendingFields?.scrapeMinDate}
errorRowStyles={[styles.ph5, styles.mb3]}
errors={getLatestErrorField(card ?? {}, 'scrapeMinDate')}
onClose={() => clearCompanyCardErrorField(domainOrWorkspaceAccountID, cardID, bank, 'scrapeMinDate', true)}
Comment thread
ikevin127 marked this conversation as resolved.
>
<MenuItemWithTopDescription
description={translate('workspace.moreFeatures.companyCards.transactionStartDate')}
title={card?.scrapeMinDate ? format(parseISO(card.scrapeMinDate), CONST.DATE.FNS_FORMAT_STRING) : ''}
shouldShowRightIcon
brickRoadIndicator={card?.errorFields?.scrapeMinDate ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
onPress={() => Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARD_EDIT_TRANSACTION_START_DATE.getRoute(policyID, cardID, feedName))}
Comment thread
ikevin127 marked this conversation as resolved.
/>
</OfflineWithFeedback>
<MenuItem
icon={expensifyIcons.MoneySearch}
title={translate('workspace.common.viewTransactions')}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import {format, parseISO, subDays} from 'date-fns';
import React, {useState} from 'react';
import {View} from 'react-native';
import type {ValueOf} from 'type-fest';
import Button from '@components/Button';
import DatePicker from '@components/DatePicker';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import SingleSelectListItem from '@components/SelectionListWithSections/SingleSelectListItem';
import Text from '@components/Text';
import useCardFeeds from '@hooks/useCardFeeds';
import useCardsList from '@hooks/useCardsList';
import useLocalize from '@hooks/useLocalize';
import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import {getCompanyCardFeed, getCompanyFeeds, getDomainOrWorkspaceAccountID} from '@libs/CardUtils';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import {isRequiredFulfilled} from '@libs/ValidationUtils';
import Navigation from '@navigation/Navigation';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import {updateCardTransactionStartDate} from '@userActions/CompanyCards';
import CONST from '@src/CONST';
import type SCREENS from '@src/SCREENS';
import type {CompanyCardFeedWithDomainID} from '@src/types/onyx';

type DateOption = ValueOf<typeof CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS>;
type WorkspaceCompanyCardEditTransactionStartDatePageProps = PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.COMPANY_CARD_EDIT_TRANSACTION_START_DATE>;

function WorkspaceCompanyCardEditTransactionStartDatePage({route}: WorkspaceCompanyCardEditTransactionStartDatePageProps) {
const {policyID, cardID} = route.params;
const feedName = decodeURIComponent(route.params.feed) as CompanyCardFeedWithDomainID;
const bank = getCompanyCardFeed(feedName);

const {translate} = useLocalize();
const styles = useThemeStyles();
const policy = usePolicy(policyID);
const workspaceAccountID = policy?.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID;

const [cardFeeds] = useCardFeeds(policyID);
const companyFeeds = getCompanyFeeds(cardFeeds);
const domainOrWorkspaceAccountID = getDomainOrWorkspaceAccountID(workspaceAccountID, companyFeeds[feedName]);

const [allBankCards] = useCardsList(feedName);
const card = allBankCards?.[cardID];
const currentStartDate = card?.scrapeMinDate;

const [dateOptionSelected, setDateOptionSelected] = useState<DateOption>(CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.CUSTOM);

const [startDate, setStartDate] = useState(() => {
if (currentStartDate) {
return format(parseISO(currentStartDate), CONST.DATE.FNS_FORMAT_STRING);
}
return format(new Date(), CONST.DATE.FNS_FORMAT_STRING);
});

const [errorText, setErrorText] = useState('');

Comment thread
ikevin127 marked this conversation as resolved.
const handleSelectDateOption = (dateOption: DateOption) => {
setErrorText('');
setDateOptionSelected(dateOption);
if (dateOption === CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.FROM_BEGINNING) {
return;
}
// Reset to current date when switching to custom
if (!currentStartDate) {
setStartDate(format(new Date(), CONST.DATE.FNS_FORMAT_STRING));
}
};

Comment thread
ikevin127 marked this conversation as resolved.
const submit = () => {
if (dateOptionSelected === CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.CUSTOM && !isRequiredFulfilled(startDate)) {
setErrorText(translate('common.error.fieldRequired'));
return;
}

const date90DaysBack = format(subDays(new Date(), 90), CONST.DATE.FNS_FORMAT_STRING);
const newStartDate = dateOptionSelected === CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.FROM_BEGINNING ? date90DaysBack : startDate;

updateCardTransactionStartDate(domainOrWorkspaceAccountID, cardID, newStartDate, bank, currentStartDate);
Navigation.goBack();
};

Comment thread
ikevin127 marked this conversation as resolved.
const dateOptions = [
{
value: CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.FROM_BEGINNING,
text: translate('workspace.companyCards.fromTheBeginning'),
keyForList: CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.FROM_BEGINNING,
isSelected: dateOptionSelected === CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.FROM_BEGINNING,
},
{
value: CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.CUSTOM,
text: translate('workspace.companyCards.customStartDate'),
keyForList: CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.CUSTOM,
isSelected: dateOptionSelected === CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.CUSTOM,
},
];

return (
<AccessOrNotFoundWrapper
policyID={policyID}
featureName={CONST.POLICY.MORE_FEATURES.ARE_COMPANY_CARDS_ENABLED}
>
<ScreenWrapper
testID="WorkspaceCompanyCardEditTransactionStartDatePage"
enableEdgeToEdgeBottomSafeAreaPadding
>
<HeaderWithBackButton
title={translate('workspace.moreFeatures.companyCards.transactionStartDate')}
onBackButtonPress={Navigation.goBack}
/>
<Text style={[styles.textSupporting, styles.ph5, styles.mv3]}>{translate('workspace.companyCards.startDateDescription')}</Text>
<View style={styles.flex1}>
<SelectionList
ListItem={SingleSelectListItem}
Comment thread
ikevin127 marked this conversation as resolved.
onSelectRow={({value}) => handleSelectDateOption(value)}
data={dateOptions}
shouldSingleExecuteRowSelect
initiallyFocusedItemKey={dateOptionSelected}
shouldUpdateFocusedIndex
addBottomSafeAreaPadding
shouldHighlightSelectedItem={false}
footerContent={
<Button
success
large
pressOnEnter
text={translate('common.save')}
onPress={submit}
/>
}
listFooterContent={
dateOptionSelected === CONST.COMPANY_CARD.TRANSACTION_START_DATE_OPTIONS.CUSTOM ? (
<View style={[styles.ph5]}>
<DatePicker
inputID=""
value={startDate}
Comment thread
ikevin127 marked this conversation as resolved.
label={translate('iou.startDate')}
onInputChange={(value) => {
if (!isRequiredFulfilled(value)) {
setErrorText(translate('common.error.fieldRequired'));
} else {
setErrorText('');
}
setStartDate(value);
}}
minDate={CONST.CALENDAR_PICKER.MIN_DATE}
maxDate={new Date()}
errorText={errorText}
/>
</View>
) : null
}
/>
</View>
</ScreenWrapper>
</AccessOrNotFoundWrapper>
);
}

export default WorkspaceCompanyCardEditTransactionStartDatePage;
Loading