Skip to content

Commit

Permalink
Merge branch 'main' into Bump-eslint-config-expensify
Browse files Browse the repository at this point in the history
  • Loading branch information
rayane-djouah authored Oct 30, 2024
2 parents ab40264 + 6b85457 commit 65f493a
Show file tree
Hide file tree
Showing 14 changed files with 85 additions and 67 deletions.
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2930,6 +2930,7 @@ const CONST = {

// Character Limits
FORM_CHARACTER_LIMIT: 50,
STANDARD_LENGTH_LIMIT: 100,
LEGAL_NAMES_CHARACTER_LIMIT: 150,
LOGIN_CHARACTER_LIMIT: 254,
CATEGORY_NAME_LIMIT: 256,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ type ValidateCodeFormProps = {
/** Function to clear error of the form */
clearError: () => void;

/** Function is called when validate code modal is mounted and on magic code resend */
sendValidateCode: () => void;
};

Expand Down Expand Up @@ -90,6 +91,10 @@ function BaseValidateCodeForm({
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- nullish coalescing doesn't achieve the same result in this case
const shouldDisableResendValidateCode = !!isOffline || account?.isLoading;
const focusTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const [timeRemaining, setTimeRemaining] = useState(CONST.REQUEST_CODE_DELAY as number);
const [isResent, setIsResent] = useState(false);

const timerRef = useRef<NodeJS.Timeout>();

useImperativeHandle(innerRef, () => ({
focus() {
Expand Down Expand Up @@ -135,12 +140,28 @@ function BaseValidateCodeForm({
inputValidateCodeRef.current?.clear();
}, [hasMagicCodeBeenSent]);

useEffect(() => {
if (timeRemaining > 0) {
timerRef.current = setTimeout(() => {
setTimeRemaining(timeRemaining - 1);
}, 1000);
}
return () => {
clearTimeout(timerRef.current);
};
}, [timeRemaining]);

/**
* Request a validate code / magic code be sent to verify this contact method
*/
const resendValidateCode = () => {
if (hasMagicCodeBeenSent && !isResent) {
return;
}

sendValidateCode();
inputValidateCodeRef.current?.clear();
setTimeRemaining(CONST.REQUEST_CODE_DELAY);
};

/**
Expand Down Expand Up @@ -177,6 +198,7 @@ function BaseValidateCodeForm({
handleSubmitForm(validateCode);
}, [validateCode, handleSubmitForm]);

const shouldShowTimer = timeRemaining > 0 && !isOffline;
return (
<>
<MagicCodeInput
Expand All @@ -190,35 +212,46 @@ function BaseValidateCodeForm({
onFulfill={validateAndSubmitForm}
autoFocus
/>
{shouldShowTimer && (
<Text style={[styles.mt5]}>
{translate('validateCodeForm.requestNewCode')}
<Text style={[styles.textBlue]}>00:{String(timeRemaining).padStart(2, '0')}</Text>
</Text>
)}
<OfflineWithFeedback
pendingAction={validateCodeAction?.pendingFields?.validateCodeSent}
errors={ErrorUtils.getLatestErrorField(validateCodeAction, 'actionVerified')}
errorRowStyles={[styles.mt2]}
onClose={() => User.clearValidateCodeActionError('actionVerified')}
>
<View style={[styles.mt5, styles.dFlex, styles.flexColumn, styles.alignItemsStart]}>
<PressableWithFeedback
disabled={shouldDisableResendValidateCode}
style={[styles.mr1]}
onPress={resendValidateCode}
underlayColor={theme.componentBG}
hoverDimmingValue={1}
pressDimmingValue={0.2}
role={CONST.ROLE.BUTTON}
accessibilityLabel={translate('validateCodeForm.magicCodeNotReceived')}
>
<Text style={[StyleUtils.getDisabledLinkStyles(shouldDisableResendValidateCode)]}>{translate('validateCodeForm.magicCodeNotReceived')}</Text>
</PressableWithFeedback>
{!!hasMagicCodeBeenSent && (
<DotIndicatorMessage
type="success"
style={[styles.mt6, styles.flex0]}
// eslint-disable-next-line @typescript-eslint/naming-convention
messages={{0: translate('validateCodeModal.successfulNewCodeRequest')}}
/>
)}
</View>
{!shouldShowTimer && (
<View style={[styles.mt5, styles.dFlex, styles.flexColumn, styles.alignItemsStart]}>
<PressableWithFeedback
disabled={shouldDisableResendValidateCode}
style={[styles.mr1]}
onPress={() => {
resendValidateCode();
setIsResent(true);
}}
underlayColor={theme.componentBG}
hoverDimmingValue={1}
pressDimmingValue={0.2}
role={CONST.ROLE.BUTTON}
accessibilityLabel={translate('validateCodeForm.magicCodeNotReceived')}
>
<Text style={[StyleUtils.getDisabledLinkStyles(shouldDisableResendValidateCode)]}>{translate('validateCodeForm.magicCodeNotReceived')}</Text>
</PressableWithFeedback>
</View>
)}
</OfflineWithFeedback>
{!!hasMagicCodeBeenSent && (
<DotIndicatorMessage
type="success"
style={[styles.mt6, styles.flex0]}
// eslint-disable-next-line @typescript-eslint/naming-convention
messages={{0: translate('validateCodeModal.successfulNewCodeRequest')}}
/>
)}
<OfflineWithFeedback
pendingAction={validatePendingAction}
errors={validateError}
Expand Down
4 changes: 2 additions & 2 deletions src/components/ValidateCodeActionModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ function ValidateCodeActionModal({
}, [onClose, clearError]);

useEffect(() => {
if (!firstRenderRef.current || !isVisible) {
if (!firstRenderRef.current || !isVisible || hasMagicCodeBeenSent) {
return;
}
firstRenderRef.current = false;

sendValidateCode();
}, [isVisible, sendValidateCode]);
}, [isVisible, sendValidateCode, hasMagicCodeBeenSent]);

return (
<Modal
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3127,6 +3127,7 @@ const translations = {
assignCard: 'Assign card',
cardNumber: 'Card number',
customFeed: 'Custom feed',
feedName: ({feedName}: CompanyCardFeedNameParams) => `${feedName} cards`,
directFeed: 'Direct feed',
whoNeedsCardAssigned: 'Who needs a card assigned?',
chooseCard: 'Choose a card',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3166,6 +3166,7 @@ const translations = {
assignCard: 'Asignar tarjeta',
cardNumber: 'Número de la tarjeta',
customFeed: 'Fuente personalizada',
feedName: ({feedName}: CompanyCardFeedNameParams) => `Tarjetas ${feedName}`,
directFeed: 'Fuente directa',
whoNeedsCardAssigned: '¿Quién necesita una tarjeta?',
chooseCard: 'Elige una tarjeta',
Expand Down
5 changes: 4 additions & 1 deletion src/pages/Search/SearchTypeMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {SearchQueryJSON} from '@components/Search/types';
import Text from '@components/Text';
import useDeleteSavedSearch from '@hooks/useDeleteSavedSearch';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useSingleExecution from '@hooks/useSingleExecution';
import useThemeStyles from '@hooks/useThemeStyles';
Expand Down Expand Up @@ -67,6 +68,7 @@ function SearchTypeMenu({queryJSON, searchName}: SearchTypeMenuProps) {
const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
const taxRates = getAllTaxRates();
const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST);
const {isOffline} = useNetwork();

const typeMenuItems: SearchTypeMenuItem[] = [
{
Expand Down Expand Up @@ -234,6 +236,7 @@ function SearchTypeMenu({queryJSON, searchName}: SearchTypeMenuProps) {
/>
);
}
const shouldShowSavedSearchesMenuItemTitle = Object.values(savedSearches ?? {}).filter((s) => s.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || isOffline).length > 0;

return (
<>
Expand Down Expand Up @@ -261,7 +264,7 @@ function SearchTypeMenu({queryJSON, searchName}: SearchTypeMenuProps) {
);
})}
</View>
{!!savedSearches && Object.keys(savedSearches).length > 0 && (
{shouldShowSavedSearchesMenuItemTitle && (
<>
<Text style={[styles.sectionTitle, styles.pb1, styles.mh3, styles.mt3]}>{translate('search.savedSearchesMenuItemTitle')}</Text>
<ScrollView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,6 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) {
User.deleteContactMethod(contactMethod, loginList ?? {}, backTo);
}, [contactMethod, loginList, toggleDeleteModal, backTo]);

const sendValidateCode = () => {
if (loginData?.validateCodeSent) {
return;
}

User.requestContactMethodValidateCode(contactMethod);
};

const prevValidatedDate = usePrevious(loginData?.validatedDate);
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
Expand Down Expand Up @@ -276,7 +268,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) {
Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo));
setIsValidateCodeActionModalVisible(false);
}}
sendValidateCode={sendValidateCode}
sendValidateCode={() => User.requestContactMethodValidateCode(contactMethod)}
description={translate('contacts.enterMagicCode', {contactMethod})}
footer={() => getMenuItems()}
/>
Expand Down
13 changes: 3 additions & 10 deletions src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,6 @@ function NewContactMethodPage({route}: NewContactMethodPageProps) {
Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(navigateBackTo));
}, [navigateBackTo]);

const sendValidateCode = () => {
if (loginData?.validateCodeSent) {
return;
}

User.requestValidateCodeAction();
};

return (
<AccessOrNotFoundWrapper shouldBeBlocked={isActingAsDelegate}>
<ScreenWrapper
Expand Down Expand Up @@ -176,8 +168,9 @@ function NewContactMethodPage({route}: NewContactMethodPageProps) {
setIsValidateCodeActionModalVisible(false);
}}
isVisible={isValidateCodeActionModalVisible}
title={contactMethod}
sendValidateCode={sendValidateCode}
hasMagicCodeBeenSent={!!loginData?.validateCodeSent}
title={translate('delegate.makeSureItIsYou')}
sendValidateCode={() => User.requestValidateCodeAction()}
description={translate('contacts.enterMagicCode', {contactMethod})}
/>
</ScreenWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,15 @@ function DelegateMagicCodeModal({login, role, onClose}: DelegateMagicCodeModalPr
Delegate.clearAddDelegateErrors(currentDelegate?.email ?? '', 'addDelegate');
};

const sendValidateCode = () => {
if (currentDelegate?.validateCodeSent) {
return;
}

User.requestValidateCodeAction();
};

return (
<ValidateCodeActionModal
clearError={clearError}
onClose={onBackButtonPress}
validateError={validateLoginError}
isVisible={isValidateCodeActionModalVisible}
title={translate('delegate.makeSureItIsYou')}
sendValidateCode={sendValidateCode}
sendValidateCode={() => User.requestValidateCodeAction()}
hasMagicCodeBeenSent={!!currentDelegate?.validateCodeSent}
handleSubmitForm={(validateCode) => Delegate.addDelegate(login, role, validateCode)}
description={translate('delegate.enterMagicCode', {contactMethod: account?.primaryLogin ?? ''})}
/>
Expand Down
17 changes: 5 additions & 12 deletions src/pages/settings/Wallet/ExpensifyCardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ function ExpensifyCardPage({
const formattedAvailableSpendAmount = CurrencyUtils.convertToDisplayString(cardsToShow?.at(0)?.availableSpend);
const {limitNameKey, limitTitleKey} = getLimitTypeTranslationKeys(cardsToShow?.at(0)?.nameValuePairs?.limitType);

const primaryLogin = account?.primaryLogin ?? '';
const loginData = loginList?.[primaryLogin];

const goToGetPhysicalCardFlow = () => {
let updatedDraftValues = draftValues;
if (!draftValues) {
Expand All @@ -146,17 +149,6 @@ function ExpensifyCardPage({
GetPhysicalCardUtils.goToNextPhysicalCardRoute(domain, GetPhysicalCardUtils.getUpdatedPrivatePersonalDetails(updatedDraftValues, privatePersonalDetails));
};

const sendValidateCode = () => {
const primaryLogin = account?.primaryLogin ?? '';
const loginData = loginList?.[primaryLogin];

if (loginData?.validateCodeSent) {
return;
}

requestValidateCodeAction();
};

if (isNotFound) {
return <NotFoundPage onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_WALLET)} />;
}
Expand Down Expand Up @@ -310,9 +302,10 @@ function ExpensifyCardPage({
<ValidateCodeActionModal
handleSubmitForm={handleRevealDetails}
clearError={() => {}}
sendValidateCode={sendValidateCode}
sendValidateCode={() => requestValidateCodeAction()}
onClose={() => setIsValidateCodeActionModalVisible(false)}
isVisible={isValidateCodeActionModalVisible}
hasMagicCodeBeenSent={!!loginData?.validateCodeSent}
title={translate('cardPage.validateCardTitle')}
description={translate('cardPage.enterMagicCode', {contactMethod: account?.primaryLogin ?? ''})}
/>
Expand Down
1 change: 1 addition & 0 deletions src/pages/settings/Wallet/VerifyAccountPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ function VerifyAccountPage({route}: VerifyAccountPageProps) {
sendValidateCode={() => User.requestValidateCodeAction()}
handleSubmitForm={handleSubmitForm}
validateError={validateLoginError}
hasMagicCodeBeenSent={!!loginData?.validateCodeSent}
isVisible={isValidateCodeActionModalVisible}
title={translate('contacts.validateAccount')}
description={translate('contacts.featureRequiresValidate')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ function WorkspaceCompanyCardsListHeaderButtons({policyID, selectedFeed}: Worksp
const [cardFeeds] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`);
const shouldChangeLayout = isMediumScreenWidth || shouldUseNarrowLayout;
const feedName = cardFeeds?.settings?.companyCardNicknames?.[selectedFeed] ?? CardUtils.getCardFeedName(selectedFeed);
const formattedFeedName = translate('workspace.companyCards.feedName', {feedName});
const isCustomFeed =
CONST.COMPANY_CARD.FEED_BANK_NAME.MASTER_CARD === selectedFeed || CONST.COMPANY_CARD.FEED_BANK_NAME.VISA === selectedFeed || CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX === selectedFeed;

Expand All @@ -51,7 +52,7 @@ function WorkspaceCompanyCardsListHeaderButtons({policyID, selectedFeed}: Worksp
<PressableWithFeedback
onPress={() => Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_SELECT_FEED.getRoute(policyID))}
style={[styles.flexRow, styles.alignItemsCenter, styles.gap3, shouldChangeLayout && styles.mb3]}
accessibilityLabel={feedName}
accessibilityLabel={formattedFeedName}
>
<Icon
src={CardUtils.getCardFeedIcon(selectedFeed)}
Expand All @@ -61,7 +62,7 @@ function WorkspaceCompanyCardsListHeaderButtons({policyID, selectedFeed}: Worksp
<View>
<View style={[styles.flexRow, styles.gap1]}>
<CaretWrapper>
<Text style={styles.textStrong}>{feedName}</Text>
<Text style={styles.textStrong}>{formattedFeedName}</Text>
</CaretWrapper>
{PolicyUtils.hasPolicyFeedsError(cardFeeds?.settings?.companyCards ?? {}, selectedFeed) && (
<Icon
Expand Down
1 change: 1 addition & 0 deletions src/pages/workspace/companyCards/addNew/CardNameStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ function CardNameStep() {
role={CONST.ROLE.PRESENTATION}
defaultValue={addNewCard?.data?.bankName}
containerStyles={[styles.mb6]}
maxLength={CONST.STANDARD_LENGTH_LIMIT}
ref={inputCallbackRef}
/>
</FormProvider>
Expand Down
5 changes: 5 additions & 0 deletions src/pages/workspace/companyCards/addNew/DetailsStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ function DetailsStep({policyID}: DetailsStepProps) {
inputID={INPUT_IDS.PROCESSOR_ID}
label={translate('workspace.companyCards.addNewCard.feedDetails.vcf.processorLabel')}
role={CONST.ROLE.PRESENTATION}
maxLength={CONST.STANDARD_LENGTH_LIMIT}
containerStyles={[styles.mb6]}
ref={inputCallbackRef}
/>
Expand All @@ -112,13 +113,15 @@ function DetailsStep({policyID}: DetailsStepProps) {
inputID={INPUT_IDS.BANK_ID}
label={translate('workspace.companyCards.addNewCard.feedDetails.vcf.bankLabel')}
role={CONST.ROLE.PRESENTATION}
maxLength={CONST.STANDARD_LENGTH_LIMIT}
containerStyles={[styles.mb6]}
/>
<InputWrapper
InputComponent={TextInput}
inputID={INPUT_IDS.COMPANY_ID}
label={translate('workspace.companyCards.addNewCard.feedDetails.vcf.companyLabel')}
role={CONST.ROLE.PRESENTATION}
maxLength={CONST.STANDARD_LENGTH_LIMIT}
containerStyles={[styles.mb6]}
/>
</>
Expand All @@ -130,6 +133,7 @@ function DetailsStep({policyID}: DetailsStepProps) {
inputID={INPUT_IDS.DISTRIBUTION_ID}
label={translate('workspace.companyCards.addNewCard.feedDetails.cdf.distributionLabel')}
role={CONST.ROLE.PRESENTATION}
maxLength={CONST.STANDARD_LENGTH_LIMIT}
containerStyles={[styles.mb6]}
ref={inputCallbackRef}
/>
Expand All @@ -141,6 +145,7 @@ function DetailsStep({policyID}: DetailsStepProps) {
inputID={INPUT_IDS.DELIVERY_FILE_NAME}
label={translate('workspace.companyCards.addNewCard.feedDetails.gl1025.fileNameLabel')}
role={CONST.ROLE.PRESENTATION}
maxLength={CONST.STANDARD_LENGTH_LIMIT}
containerStyles={[styles.mb6]}
ref={inputCallbackRef}
/>
Expand Down

0 comments on commit 65f493a

Please sign in to comment.