From a56bce1cd7715499377d77dc02ad26755f314fd4 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 15 Jan 2024 12:11:19 +0100 Subject: [PATCH 01/72] Migrate MoneyRequestAction to TypeScript --- ...equestAction.js => MoneyRequestAction.tsx} | 129 ++++++++---------- .../ContextMenu/ReportActionContextMenu.ts | 7 +- 2 files changed, 59 insertions(+), 77 deletions(-) rename src/components/ReportActionItem/{MoneyRequestAction.js => MoneyRequestAction.tsx} (58%) diff --git a/src/components/ReportActionItem/MoneyRequestAction.js b/src/components/ReportActionItem/MoneyRequestAction.tsx similarity index 58% rename from src/components/ReportActionItem/MoneyRequestAction.js rename to src/components/ReportActionItem/MoneyRequestAction.tsx index e0a3152a41b4..e0c44dfc65b9 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.js +++ b/src/components/ReportActionItem/MoneyRequestAction.tsx @@ -1,80 +1,63 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React from 'react'; +import type {StyleProp, ViewStyle} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import networkPropTypes from '@components/networkPropTypes'; -import {withNetwork} from '@components/OnyxProvider'; -import refPropTypes from '@components/refPropTypes'; +import type {OnyxEntry} from 'react-native-onyx/lib/types'; import RenderHTML from '@components/RenderHTML'; import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as IOUUtils from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; -import iouReportPropTypes from '@pages/iouReportPropTypes'; -import reportPropTypes from '@pages/reportPropTypes'; +import type {ContextMenuAnchor} from '@pages/home/report/ContextMenu/ReportActionContextMenu'; import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type * as OnyxTypes from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import MoneyRequestPreview from './MoneyRequestPreview'; -const propTypes = { +type MoneyRequestActionOnyxProps = { + /** Chat report associated with iouReport */ + chatReport: OnyxEntry; + + /** IOU report data object */ + iouReport: OnyxEntry; + + /** Report actions for this report */ + reportActions: OnyxEntry; +}; + +type MoneyRequestActionProps = MoneyRequestActionOnyxProps & { /** All the data of the action */ - action: PropTypes.shape(reportActionPropTypes).isRequired, + action: OnyxTypes.ReportAction; /** The ID of the associated chatReport */ - chatReportID: PropTypes.string.isRequired, + chatReportID: string; /** The ID of the associated request report */ - requestReportID: PropTypes.string.isRequired, + requestReportID: string; /** Is this IOUACTION the most recent? */ - isMostRecentIOUReportAction: PropTypes.bool.isRequired, + isMostRecentIOUReportAction: boolean; /** Popover context menu anchor, used for showing context menu */ - contextMenuAnchor: refPropTypes, + contextMenuAnchor?: ContextMenuAnchor; /** Callback for updating context menu active state, used for showing context menu */ - checkIfContextMenuActive: PropTypes.func, - - /* Onyx Props */ - /** chatReport associated with iouReport */ - chatReport: reportPropTypes, - - /** IOU report data object */ - iouReport: iouReportPropTypes, - - /** Array of report actions for this report */ - reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + checkIfContextMenuActive?: () => void; /** Whether the IOU is hovered so we can modify its style */ - isHovered: PropTypes.bool, - - network: networkPropTypes.isRequired, + isHovered?: boolean; /** Whether a message is a whisper */ - isWhisper: PropTypes.bool, + isWhisper?: boolean; /** Styles to be assigned to Container */ - // eslint-disable-next-line react/forbid-prop-types - style: PropTypes.arrayOf(PropTypes.object), -}; - -const defaultProps = { - contextMenuAnchor: undefined, - checkIfContextMenuActive: () => {}, - chatReport: {}, - iouReport: {}, - reportActions: {}, - isHovered: false, - style: [], - isWhisper: false, + style?: StyleProp; }; function MoneyRequestAction({ @@ -83,31 +66,32 @@ function MoneyRequestAction({ requestReportID, isMostRecentIOUReportAction, contextMenuAnchor, - checkIfContextMenuActive, + checkIfContextMenuActive = () => {}, chatReport, iouReport, reportActions, - isHovered, - network, + isHovered = false, style, - isWhisper, -}) { + isWhisper = false, +}: MoneyRequestActionProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const isSplitBillAction = lodashGet(action, 'originalMessage.type', '') === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; + const {isOffline} = useNetwork(); + + const isSplitBillAction = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; const onMoneyRequestPreviewPressed = () => { if (isSplitBillAction) { - const reportActionID = lodashGet(action, 'reportActionID', '0'); + const reportActionID = action.reportActionID ?? '0'; Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(chatReportID, reportActionID)); return; } // If the childReportID is not present, we need to create a new thread - const childReportID = lodashGet(action, 'childReportID', 0); + const childReportID = action?.childReportID ?? '0'; if (!childReportID) { const thread = ReportUtils.buildTransactionThread(action, requestReportID); - const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(thread.participantAccountIDs); + const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(thread.participantAccountIDs ?? []); Report.openReport(thread.reportID, userLogins, thread, action.reportActionID); Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(thread.reportID)); return; @@ -120,12 +104,12 @@ function MoneyRequestAction({ const isDeletedParentAction = ReportActionsUtils.isDeletedParentAction(action); const isReversedTransaction = ReportActionsUtils.isReversedTransaction(action); if ( - !_.isEmpty(iouReport) && - !_.isEmpty(reportActions) && - chatReport.iouReportID && + !isEmptyObject(iouReport) && + !isEmptyObject(reportActions) && + chatReport?.iouReportID && isMostRecentIOUReportAction && action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && - network.isOffline + isOffline ) { shouldShowPendingConversionMessage = IOUUtils.isIOUReportPendingCurrencyConversion(iouReport); } @@ -142,29 +126,24 @@ function MoneyRequestAction({ checkIfContextMenuActive={checkIfContextMenuActive} shouldShowPendingConversionMessage={shouldShowPendingConversionMessage} onPreviewPressed={onMoneyRequestPreviewPressed} - containerStyles={[styles.cursorPointer, isHovered ? styles.reportPreviewBoxHoverBorder : undefined, ...style]} + containerStyles={[styles.cursorPointer, isHovered ? styles.reportPreviewBoxHoverBorder : undefined, style]} isHovered={isHovered} isWhisper={isWhisper} /> ); } -MoneyRequestAction.propTypes = propTypes; -MoneyRequestAction.defaultProps = defaultProps; MoneyRequestAction.displayName = 'MoneyRequestAction'; -export default compose( - withOnyx({ - chatReport: { - key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, - }, - iouReport: { - key: ({requestReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`, - }, - reportActions: { - key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, - canEvict: false, - }, - }), - withNetwork(), -)(MoneyRequestAction); +export default withOnyx({ + chatReport: { + key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, + }, + iouReport: { + key: ({requestReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`, + }, + reportActions: { + key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, + canEvict: false, + }, +})(MoneyRequestAction); diff --git a/src/pages/home/report/ContextMenu/ReportActionContextMenu.ts b/src/pages/home/report/ContextMenu/ReportActionContextMenu.ts index 5b64d90da5da..9553d8207a2f 100644 --- a/src/pages/home/report/ContextMenu/ReportActionContextMenu.ts +++ b/src/pages/home/report/ContextMenu/ReportActionContextMenu.ts @@ -14,11 +14,13 @@ type OnCancel = () => void; type ContextMenuType = ValueOf; +type ContextMenuAnchor = View | RNText | null; + type ShowContextMenu = ( type: ContextMenuType, event: GestureResponderEvent | MouseEvent, selection: string, - contextMenuAnchor: View | RNText | null, + contextMenuAnchor: ContextMenuAnchor, reportID?: string, reportActionID?: string, originalReportID?: string, @@ -96,7 +98,7 @@ function showContextMenu( type: ContextMenuType, event: GestureResponderEvent | MouseEvent, selection: string, - contextMenuAnchor: View | RNText | null, + contextMenuAnchor: ContextMenuAnchor, reportID = '0', reportActionID = '0', originalReportID = '0', @@ -175,3 +177,4 @@ function clearActiveReportAction() { } export {contextMenuRef, showContextMenu, hideContextMenu, isActiveReportAction, clearActiveReportAction, showDeleteModal, hideDeleteModal}; +export type {ContextMenuAnchor}; From 0f627bab72b127aeca7969b2b8633f49a064e38d Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 16 Jan 2024 09:36:03 +0100 Subject: [PATCH 02/72] Migrate MoneyRequestPreview to TypeScript --- .../Pressable/GenericPressable/types.ts | 2 +- .../Pressable/PressableWithDelayToggle.tsx | 2 +- .../Pressable/PressableWithoutFocus.tsx | 2 +- ...uestPreview.js => MoneyRequestPreview.tsx} | 252 +++++++++--------- src/languages/types.ts | 2 +- src/libs/ReceiptUtils.ts | 3 +- src/libs/TransactionUtils.ts | 14 +- 7 files changed, 132 insertions(+), 145 deletions(-) rename src/components/ReportActionItem/{MoneyRequestPreview.js => MoneyRequestPreview.tsx} (63%) diff --git a/src/components/Pressable/GenericPressable/types.ts b/src/components/Pressable/GenericPressable/types.ts index dc04b6fcf329..03cdb30c67fc 100644 --- a/src/components/Pressable/GenericPressable/types.ts +++ b/src/components/Pressable/GenericPressable/types.ts @@ -40,7 +40,7 @@ type PressableProps = RNPressableProps & /** * onPress callback */ - onPress: (event?: GestureResponderEvent | KeyboardEvent) => void | Promise; + onPress: ((event?: GestureResponderEvent | KeyboardEvent) => void | Promise) | undefined; /** * Specifies keyboard shortcut to trigger onPressHandler diff --git a/src/components/Pressable/PressableWithDelayToggle.tsx b/src/components/Pressable/PressableWithDelayToggle.tsx index ab1fa95efeb5..86f6c9d8aff8 100644 --- a/src/components/Pressable/PressableWithDelayToggle.tsx +++ b/src/components/Pressable/PressableWithDelayToggle.tsx @@ -78,7 +78,7 @@ function PressableWithDelayToggle( return; } temporarilyDisableInteractions(); - onPress(); + onPress?.(); }; // Due to limitations in RN regarding the vertical text alignment of non-Text elements, diff --git a/src/components/Pressable/PressableWithoutFocus.tsx b/src/components/Pressable/PressableWithoutFocus.tsx index f887b0ea9b7d..240ef4a9873a 100644 --- a/src/components/Pressable/PressableWithoutFocus.tsx +++ b/src/components/Pressable/PressableWithoutFocus.tsx @@ -15,7 +15,7 @@ function PressableWithoutFocus({children, onPress, onLongPress, ...rest}: Pressa const pressAndBlur = () => { ref?.current?.blur(); - onPress(); + onPress?.(); }; return ( diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.tsx similarity index 63% rename from src/components/ReportActionItem/MoneyRequestPreview.js rename to src/components/ReportActionItem/MoneyRequestPreview.tsx index 96c9e1b364d6..a6df98973670 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.tsx @@ -1,20 +1,18 @@ import {truncate} from 'lodash'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; +import lodashSortBy from 'lodash/sortBy'; import React from 'react'; import {View} from 'react-native'; +import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; +import type {OnyxEntry} from 'react-native-onyx/lib/types'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import MoneyRequestSkeletonView from '@components/MoneyRequestSkeletonView'; import MultipleAvatars from '@components/MultipleAvatars'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import PressableWithFeedback from '@components/Pressable/PressableWithoutFeedback'; -import refPropTypes from '@components/refPropTypes'; import {showContextMenuForReport} from '@components/ShowContextMenuContext'; import Text from '@components/Text'; -import transactionPropTypes from '@components/transactionPropTypes'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; @@ -29,144 +27,135 @@ import * as ReceiptUtils from '@libs/ReceiptUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; -import walletTermsPropTypes from '@pages/EnablePayments/walletTermsPropTypes'; -import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; -import iouReportPropTypes from '@pages/iouReportPropTypes'; -import reportPropTypes from '@pages/reportPropTypes'; +import type {ContextMenuAnchor} from '@pages/home/report/ContextMenu/ReportActionContextMenu'; import * as PaymentMethods from '@userActions/PaymentMethods'; import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import * as Localize from '@src/libs/Localize'; import ONYXKEYS from '@src/ONYXKEYS'; +import type * as OnyxTypes from '@src/types/onyx'; +import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import ReportActionItemImages from './ReportActionItemImages'; -const propTypes = { +type MoneyRequestPreviewOnyxProps = { + /** All of the personal details for everyone */ + personalDetails: OnyxEntry; + + /** Chat report associated with iouReport */ + chatReport: OnyxEntry; + + /** IOU report data object */ + iouReport: OnyxEntry; + + /** Session info for the currently logged in user. */ + session: OnyxEntry; + + /** The transaction attached to the action.message.iouTransactionID */ + transaction: OnyxEntry; + + /** Information about the user accepting the terms for payments */ + walletTerms: OnyxEntry; +}; + +type MoneyRequestPreviewProps = MoneyRequestPreviewOnyxProps & { /** The active IOUReport, used for Onyx subscription */ + // The iouReportID is used inside withOnyx HOC // eslint-disable-next-line react/no-unused-prop-types - iouReportID: PropTypes.string.isRequired, + iouReportID: string; /** The associated chatReport */ - chatReportID: PropTypes.string.isRequired, + chatReportID: string; /** Callback for the preview pressed */ - onPreviewPressed: PropTypes.func, + onPreviewPressed: (event?: GestureResponderEvent | KeyboardEvent) => void; /** All the data of the action, used for showing context menu */ - action: PropTypes.shape(reportActionPropTypes), + action: OnyxTypes.ReportAction; /** Popover context menu anchor, used for showing context menu */ - contextMenuAnchor: refPropTypes, + contextMenuAnchor?: ContextMenuAnchor; /** Callback for updating context menu active state, used for showing context menu */ - checkIfContextMenuActive: PropTypes.func, + checkIfContextMenuActive?: () => void; /** Extra styles to pass to View wrapper */ - // eslint-disable-next-line react/forbid-prop-types - containerStyles: PropTypes.arrayOf(PropTypes.object), - - /* Onyx Props */ - - /** chatReport associated with iouReport */ - chatReport: reportPropTypes, - - /** IOU report data object */ - iouReport: iouReportPropTypes, + containerStyles: StyleProp; /** True if this is this IOU is a split instead of a 1:1 request */ - isBillSplit: PropTypes.bool.isRequired, + isBillSplit: boolean; /** True if the IOU Preview card is hovered */ - isHovered: PropTypes.bool, - - /** All of the personal details for everyone */ - personalDetails: PropTypes.objectOf( - PropTypes.shape({ - /** This is either the user's full name, or their login if full name is an empty string */ - displayName: PropTypes.string, - }), - ), - - /** The transaction attached to the action.message.iouTransactionID */ - transaction: transactionPropTypes, - - /** Session info for the currently logged in user. */ - session: PropTypes.shape({ - /** Currently logged in user email */ - email: PropTypes.string, - }), - - /** Information about the user accepting the terms for payments */ - walletTerms: walletTermsPropTypes, + isHovered?: boolean; /** Whether or not an IOU report contains money requests in a different currency * that are either created or cancelled offline, and thus haven't been converted to the report's currency yet */ - shouldShowPendingConversionMessage: PropTypes.bool, + shouldShowPendingConversionMessage?: boolean; /** Whether a message is a whisper */ - isWhisper: PropTypes.bool, + isWhisper?: boolean; }; -const defaultProps = { - iouReport: {}, - onPreviewPressed: null, - action: undefined, - contextMenuAnchor: undefined, - checkIfContextMenuActive: () => {}, - containerStyles: [], - walletTerms: {}, - chatReport: {}, - isHovered: false, - personalDetails: {}, - session: { - email: null, - }, - transaction: {}, - shouldShowPendingConversionMessage: false, - isWhisper: false, -}; - -function MoneyRequestPreview(props) { +function MoneyRequestPreview({ + iouReport, + isBillSplit, + session, + action, + personalDetails, + chatReport, + transaction, + contextMenuAnchor, + chatReportID, + onPreviewPressed, + containerStyles, + walletTerms, + checkIfContextMenuActive = () => {}, + shouldShowPendingConversionMessage = false, + isHovered = false, + isWhisper = false, +}: MoneyRequestPreviewProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); const {isSmallScreenWidth, windowWidth} = useWindowDimensions(); - if (_.isEmpty(props.iouReport) && !props.isBillSplit) { + if (isEmptyObject(iouReport) && !isBillSplit) { return null; } - const sessionAccountID = lodashGet(props.session, 'accountID', null); - const managerID = props.iouReport.managerID || ''; - const ownerAccountID = props.iouReport.ownerAccountID || ''; - const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.chatReport); - - const participantAccountIDs = props.isBillSplit ? lodashGet(props.action, 'originalMessage.participantAccountIDs', []) : [managerID, ownerAccountID]; - const participantAvatars = OptionsListUtils.getAvatarsForAccountIDs(participantAccountIDs, props.personalDetails); - const sortedParticipantAvatars = _.sortBy(participantAvatars, (avatar) => avatar.id); - if (isPolicyExpenseChat && props.isBillSplit) { - sortedParticipantAvatars.push(ReportUtils.getWorkspaceIcon(props.chatReport)); + const sessionAccountID = session?.accountID; + const managerID = iouReport?.managerID ?? -1; + const ownerAccountID = iouReport?.ownerAccountID ?? -1; + const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport); + + const participantAccountIDs = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && isBillSplit ? action.originalMessage.participantAccountIDs ?? [] : [managerID, ownerAccountID]; + // TODO: Remove the assertion once OptionsListUtils (https://github.com/Expensify/App/issues/24921) is migrated to TypeScript. + const participantAvatars = OptionsListUtils.getAvatarsForAccountIDs(participantAccountIDs, personalDetails ?? {}) as OnyxCommon.Icon[]; + const sortedParticipantAvatars = lodashSortBy(participantAvatars, (avatar) => avatar.id); + if (isPolicyExpenseChat && isBillSplit) { + sortedParticipantAvatars.push(ReportUtils.getWorkspaceIcon(chatReport)); } // Pay button should only be visible to the manager of the report. const isCurrentUserManager = managerID === sessionAccountID; - const {amount: requestAmount, currency: requestCurrency, comment: requestComment, merchant} = ReportUtils.getTransactionDetails(props.transaction); + const {amount: requestAmount, currency: requestCurrency, comment: requestComment, merchant} = ReportUtils.getTransactionDetails(transaction) ?? {}; const description = truncate(requestComment, {length: CONST.REQUEST_PREVIEW.MAX_LENGTH}); const requestMerchant = truncate(merchant, {length: CONST.REQUEST_PREVIEW.MAX_LENGTH}); - const hasReceipt = TransactionUtils.hasReceipt(props.transaction); - const isScanning = hasReceipt && TransactionUtils.isReceiptBeingScanned(props.transaction); - const hasFieldErrors = TransactionUtils.hasMissingSmartscanFields(props.transaction); - const isDistanceRequest = TransactionUtils.isDistanceRequest(props.transaction); - const isExpensifyCardTransaction = TransactionUtils.isExpensifyCardTransaction(props.transaction); - const isSettled = ReportUtils.isSettled(props.iouReport.reportID); - const isDeleted = lodashGet(props.action, 'pendingAction', null) === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; + const hasReceipt = TransactionUtils.hasReceipt(transaction); + const isScanning = hasReceipt && TransactionUtils.isReceiptBeingScanned(transaction); + const hasFieldErrors = TransactionUtils.hasMissingSmartscanFields(transaction); + const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction); + const isExpensifyCardTransaction = TransactionUtils.isExpensifyCardTransaction(transaction); + const isSettled = ReportUtils.isSettled(iouReport?.reportID); + const isDeleted = action?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; // Show the merchant for IOUs and expenses only if they are custom or not related to scanning smartscan - const shouldShowMerchant = !_.isEmpty(requestMerchant) && requestMerchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT && requestMerchant !== CONST.TRANSACTION.DEFAULT_MERCHANT; - const shouldShowDescription = !_.isEmpty(description) && !shouldShowMerchant && !isScanning; - const hasPendingWaypoints = lodashGet(props.transaction, 'pendingFields.waypoints', null); + const shouldShowMerchant = !!requestMerchant && requestMerchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT && requestMerchant !== CONST.TRANSACTION.DEFAULT_MERCHANT; + const shouldShowDescription = !!description && !shouldShowMerchant && !isScanning; + const hasPendingWaypoints = transaction?.pendingFields?.waypoints; let merchantOrDescription = requestMerchant; if (!shouldShowMerchant) { @@ -175,20 +164,21 @@ function MoneyRequestPreview(props) { merchantOrDescription = requestMerchant.replace(CONST.REGEX.FIRST_SPACE, translate('common.tbd')); } - const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(props.transaction)] : []; + const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(transaction)] : []; - const getSettledMessage = () => { + const getSettledMessage = (): string => { if (isExpensifyCardTransaction) { return translate('common.done'); } return translate('iou.settledExpensify'); }; - const showContextMenu = (event) => { - showContextMenuForReport(event, props.contextMenuAnchor, props.chatReportID, props.action, props.checkIfContextMenuActive); + const showContextMenu = (event: GestureResponderEvent) => { + // @ts-expect-error TODO: Remove this once ShowContextMenuContext (https://github.com/Expensify/App/issues/24980) is migrated to TypeScript. + showContextMenuForReport(event, contextMenuAnchor, chatReportID, action, checkIfContextMenuActive); }; - const getPreviewHeaderText = () => { + const getPreviewHeaderText = (): string => { if (isDistanceRequest) { return translate('common.distance'); } @@ -197,30 +187,30 @@ function MoneyRequestPreview(props) { return translate('common.receipt'); } - if (props.isBillSplit) { + if (isBillSplit) { return translate('iou.split'); } if (isExpensifyCardTransaction) { let message = translate('iou.card'); - if (TransactionUtils.isPending(props.transaction)) { + if (TransactionUtils.isPending(transaction)) { message += ` • ${translate('iou.pending')}`; } return message; } let message = translate('iou.cash'); - if (ReportUtils.isPaidGroupPolicyExpenseReport(props.iouReport) && ReportUtils.isReportApproved(props.iouReport) && !ReportUtils.isSettled(props.iouReport)) { + if (ReportUtils.isPaidGroupPolicyExpenseReport(iouReport) && ReportUtils.isReportApproved(iouReport) && !ReportUtils.isSettled(iouReport?.reportID)) { message += ` • ${translate('iou.approved')}`; - } else if (props.iouReport.isWaitingOnBankAccount) { + } else if (iouReport?.isWaitingOnBankAccount) { message += ` • ${translate('iou.pending')}`; - } else if (props.iouReport.isCancelledIOU) { + } else if (iouReport?.isCancelledIOU) { message += ` • ${translate('iou.canceled')}`; } return message; }; - const getDisplayAmountText = () => { + const getDisplayAmountText = (): string => { if (isDistanceRequest) { return requestAmount && !hasPendingWaypoints ? CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency) : translate('common.tbd'); } @@ -229,18 +219,18 @@ function MoneyRequestPreview(props) { return translate('iou.receiptScanning'); } - if (TransactionUtils.hasMissingSmartscanFields(props.transaction)) { + if (TransactionUtils.hasMissingSmartscanFields(transaction)) { return Localize.translateLocal('iou.receiptMissingDetails'); } return CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency); }; - const getDisplayDeleteAmountText = () => { - const {amount, currency} = ReportUtils.getTransactionDetails(props.action.originalMessage); + const getDisplayDeleteAmountText = (): string => { + const {amount, currency} = ReportUtils.getTransactionDetails(action.originalMessage as OnyxTypes.Transaction) ?? {}; if (isDistanceRequest) { - return CurrencyUtils.convertToDisplayString(TransactionUtils.getAmount(props.action.originalMessage), currency); + return CurrencyUtils.convertToDisplayString(TransactionUtils.getAmount(action.originalMessage as OnyxTypes.Transaction), currency); } return CurrencyUtils.convertToDisplayString(amount, currency); @@ -251,36 +241,35 @@ function MoneyRequestPreview(props) { const childContainer = ( { PaymentMethods.clearWalletTermsError(); - Report.clearIOUError(props.chatReportID); + Report.clearIOUError(chatReportID); }} errorRowStyles={[styles.mbn1]} needsOffscreenAlphaCompositing > {hasReceipt && ( )} - {_.isEmpty(props.transaction) && - !ReportActionsUtils.isMessageDeleted(props.action) && - lodashGet(props.action, 'pendingAction') !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ? ( + {isEmptyObject(transaction) && !ReportActionsUtils.isMessageDeleted(action) && action.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ? ( ) : ( - {getPreviewHeaderText() + (isSettled && !props.iouReport.isCancelledIOU ? ` • ${getSettledMessage()}` : '')} + {getPreviewHeaderText() + (isSettled && !iouReport?.isCancelledIOU ? ` • ${getSettledMessage()}` : '')} {!isSettled && hasFieldErrors && ( {displayAmount} - {ReportUtils.isSettled(props.iouReport.reportID) && !props.isBillSplit && ( + {ReportUtils.isSettled(iouReport?.reportID) && !isBillSplit && ( )} - {props.isBillSplit && ( + {isBillSplit && ( @@ -325,16 +313,16 @@ function MoneyRequestPreview(props) { - {!isCurrentUserManager && props.shouldShowPendingConversionMessage && ( + {!isCurrentUserManager && shouldShowPendingConversionMessage && ( {translate('iou.pendingConversionMessage')} )} {(shouldShowDescription || shouldShowMerchant) && {merchantOrDescription}} - {props.isBillSplit && !_.isEmpty(participantAccountIDs) && requestAmount > 0 && ( + {isBillSplit && participantAccountIDs.length > 0 && requestAmount && requestAmount > 0 && ( {translate('iou.amountEach', { amount: CurrencyUtils.convertToDisplayString( - IOUUtils.calculateAmount(isPolicyExpenseChat ? 1 : participantAccountIDs.length - 1, requestAmount, requestCurrency), + IOUUtils.calculateAmount(isPolicyExpenseChat ? 1 : participantAccountIDs.length - 1, requestAmount, requestCurrency ?? ''), requestCurrency, ), })} @@ -348,32 +336,30 @@ function MoneyRequestPreview(props) { ); - if (!props.onPreviewPressed) { + if (!onPreviewPressed) { return childContainer; } - const shouldDisableOnPress = props.isBillSplit && _.isEmpty(props.transaction); + const shouldDisableOnPress = isBillSplit && isEmptyObject(transaction); return ( DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} onPressOut={() => ControlSelection.unblock()} onLongPress={showContextMenu} - accessibilityLabel={props.isBillSplit ? translate('iou.split') : translate('iou.cash')} + accessibilityLabel={isBillSplit ? translate('iou.split') : translate('iou.cash')} accessibilityHint={CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency)} - style={[styles.moneyRequestPreviewBox, ...props.containerStyles, shouldDisableOnPress && styles.cursorDefault]} + style={[styles.moneyRequestPreviewBox, containerStyles, shouldDisableOnPress && styles.cursorDefault]} > {childContainer} ); } -MoneyRequestPreview.propTypes = propTypes; -MoneyRequestPreview.defaultProps = defaultProps; MoneyRequestPreview.displayName = 'MoneyRequestPreview'; -export default withOnyx({ +export default withOnyx({ personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, @@ -387,7 +373,7 @@ export default withOnyx({ key: ONYXKEYS.SESSION, }, transaction: { - key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${(action && action.originalMessage && action.originalMessage.IOUTransactionID) || 0}`, + key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${(action?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && action?.originalMessage?.IOUTransactionID) || 0}`, }, walletTerms: { key: ONYXKEYS.WALLET_TERMS, diff --git a/src/languages/types.ts b/src/languages/types.ts index 3185b7a8f6f1..7fd9794e01c3 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -113,7 +113,7 @@ type SplitAmountParams = {amount: number}; type DidSplitAmountMessageParams = {formattedAmount: string; comment: string}; -type AmountEachParams = {amount: number}; +type AmountEachParams = {amount: string}; type PayerOwesAmountParams = {payer: string; amount: number | string}; diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index bcba68a3a0bd..72d37abc1b4e 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -1,5 +1,6 @@ import Str from 'expensify-common/lib/str'; import type {ImageSourcePropType} from 'react-native'; +import {OnyxEntry} from 'react-native-onyx'; import ReceiptDoc from '@assets/images/receipt-doc.png'; import ReceiptGeneric from '@assets/images/receipt-generic.png'; import ReceiptHTML from '@assets/images/receipt-html.png'; @@ -28,7 +29,7 @@ type FileNameAndExtension = { * @param receiptPath * @param receiptFileName */ -function getThumbnailAndImageURIs(transaction: Transaction, receiptPath: string | null = null, receiptFileName: string | null = null): ThumbnailAndImageURI { +function getThumbnailAndImageURIs(transaction: OnyxEntry, receiptPath: string | null = null, receiptFileName: string | null = null): ThumbnailAndImageURI { // URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg const path = transaction?.receipt?.source ?? receiptPath ?? ''; // filename of uploaded image or last part of remote URI diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index c34a6753c1d5..061ce683b33c 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -37,10 +37,10 @@ Onyx.connect({ callback: (value) => (allReports = value), }); -function isDistanceRequest(transaction: Transaction): boolean { +function isDistanceRequest(transaction: OnyxEntry): boolean { // This is used during the request creation flow before the transaction has been saved to the server if (lodashHas(transaction, 'iouRequestType')) { - return transaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE; + return transaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE; } // This is the case for transaction objects once they have been saved to the server @@ -258,7 +258,7 @@ function getDescription(transaction: OnyxEntry): string { /** * Return the amount field from the transaction, return the modifiedAmount if present. */ -function getAmount(transaction: OnyxEntry, isFromExpenseReport: boolean): number { +function getAmount(transaction: OnyxEntry, isFromExpenseReport?: boolean): number { // IOU requests cannot have negative values but they can be stored as negative values, let's return absolute value if (!isFromExpenseReport) { const amount = transaction?.modifiedAmount ?? 0; @@ -385,8 +385,8 @@ function getHeaderTitleTranslationKey(transaction: Transaction): string { /** * Determine whether a transaction is made with an Expensify card. */ -function isExpensifyCardTransaction(transaction: Transaction): boolean { - if (!transaction.cardID) { +function isExpensifyCardTransaction(transaction: OnyxEntry): boolean { + if (!transaction?.cardID) { return false; } return isExpensifyCard(transaction.cardID); @@ -403,8 +403,8 @@ function isCardTransaction(transaction: Transaction): boolean { /** * Check if the transaction status is set to Pending. */ -function isPending(transaction: Transaction): boolean { - if (!transaction.status) { +function isPending(transaction: OnyxEntry): boolean { + if (!transaction?.status) { return false; } return transaction.status === CONST.TRANSACTION.STATUS.PENDING; From 02296e884a636fa8772b27013ec52878ea059af7 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 16 Jan 2024 12:42:24 +0100 Subject: [PATCH 03/72] Migrate MoneyRequestView to TypeScript --- src/ONYXKEYS.ts | 3 +- src/components/MenuItem.tsx | 2 +- ...neyRequestView.js => MoneyRequestView.tsx} | 257 ++++++++---------- src/libs/TransactionUtils.ts | 2 +- src/libs/actions/IOU.js | 4 +- src/types/onyx/Policy.ts | 3 + src/types/onyx/PolicyTag.ts | 3 + src/types/onyx/Transaction.ts | 6 +- src/types/onyx/TransactionViolation.ts | 4 +- src/types/onyx/index.ts | 3 +- 10 files changed, 132 insertions(+), 155 deletions(-) rename src/components/ReportActionItem/{MoneyRequestView.js => MoneyRequestView.tsx} (70%) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 98e3856f4544..909ec9f8f50d 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -437,7 +437,7 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.DOWNLOAD]: OnyxTypes.Download; [ONYXKEYS.COLLECTION.POLICY]: OnyxTypes.Policy; [ONYXKEYS.COLLECTION.POLICY_DRAFTS]: OnyxTypes.Policy; - [ONYXKEYS.COLLECTION.POLICY_CATEGORIES]: OnyxTypes.PolicyCategory; + [ONYXKEYS.COLLECTION.POLICY_CATEGORIES]: OnyxTypes.PolicyCategories; [ONYXKEYS.COLLECTION.POLICY_TAGS]: OnyxTypes.PolicyTags; [ONYXKEYS.COLLECTION.POLICY_MEMBERS]: OnyxTypes.PolicyMembers; [ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS]: OnyxTypes.PolicyMember; @@ -459,6 +459,7 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.SECURITY_GROUP]: OnyxTypes.SecurityGroup; [ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.Transaction; + [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolations; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; [ONYXKEYS.COLLECTION.SELECTED_TAB]: string; [ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string; diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 334fa9895205..5f82e1da94ed 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -204,7 +204,7 @@ type MenuItemProps = (IconProps | AvatarProps | NoIcon) & { shouldBlockSelection?: boolean; /** Whether should render title as HTML or as Text */ - shouldParseTitle?: false; + shouldParseTitle?: boolean; /** Should check anonymous user in onPress function */ shouldCheckActionAllowedOnPress?: boolean; diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.tsx similarity index 70% rename from src/components/ReportActionItem/MoneyRequestView.js rename to src/components/ReportActionItem/MoneyRequestView.tsx index 036b64af1e4b..124a6ab4c9d3 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -1,30 +1,24 @@ -import lodashGet from 'lodash/get'; -import lodashValues from 'lodash/values'; -import PropTypes from 'prop-types'; import React, {useCallback} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import categoryPropTypes from '@components/categoryPropTypes'; +import type {OnyxEntry} from 'react-native-onyx'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ReceiptEmptyState from '@components/ReceiptEmptyState'; import SpacerView from '@components/SpacerView'; import Switch from '@components/Switch'; -import tagPropTypes from '@components/tagPropTypes'; import Text from '@components/Text'; -import transactionPropTypes from '@components/transactionPropTypes'; import ViolationMessages from '@components/ViolationMessages'; -import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useViolations from '@hooks/useViolations'; +import type {ViolationField} from '@hooks/useViolations'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as CardUtils from '@libs/CardUtils'; -import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; @@ -34,96 +28,67 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateBackground'; -import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; -import iouReportPropTypes from '@pages/iouReportPropTypes'; -import reportPropTypes from '@pages/reportPropTypes'; -import {policyDefaultProps, policyPropTypes} from '@pages/workspace/withPolicy'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type * as OnyxTypes from '@src/types/onyx'; +import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction'; import ReportActionItemImage from './ReportActionItemImage'; -const violationNames = lodashValues(CONST.VIOLATIONS); +type MoneyRequestViewTransactionOnyxProps = { + /** The transaction associated with the transactionThread */ + transaction: OnyxEntry; +}; -const transactionViolationPropType = PropTypes.shape({ - type: PropTypes.string.isRequired, - name: PropTypes.oneOf(violationNames).isRequired, - data: PropTypes.shape({ - rejectedBy: PropTypes.string, - rejectReason: PropTypes.string, - amount: PropTypes.string, - surcharge: PropTypes.number, - invoiceMarkup: PropTypes.number, - maxAge: PropTypes.number, - tagName: PropTypes.string, - formattedLimitAmount: PropTypes.string, - categoryLimit: PropTypes.string, - limit: PropTypes.string, - category: PropTypes.string, - brokenBankConnection: PropTypes.bool, - isAdmin: PropTypes.bool, - email: PropTypes.string, - isTransactionOlderThan7Days: PropTypes.bool, - member: PropTypes.string, - taxName: PropTypes.string, - }), -}); +type MoneyRequestViewOnyxPropsWithoutTransaction = { + /** The policy object for the current route */ + policy: OnyxEntry; -const propTypes = { - /** The report currently being looked at */ - report: reportPropTypes.isRequired, + /** Collection of categories attached to a policy */ + policyCategories: OnyxEntry; - /** Whether we should display the horizontal rule below the component */ - shouldShowHorizontalRule: PropTypes.bool.isRequired, + /** Collection of tags attached to a policy */ + policyTags: OnyxEntry; - /* Onyx Props */ /** The expense report or iou report (only will have a value if this is a transaction thread) */ - parentReport: iouReportPropTypes, + parentReport: OnyxEntry; /** The actions from the parent report */ - parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), - - /** The policy the report is tied to */ - ...policyPropTypes, - - /** Collection of categories attached to a policy */ - policyCategories: PropTypes.objectOf(categoryPropTypes), - - /** The transaction associated with the transactionThread */ - transaction: transactionPropTypes, + parentReportActions: OnyxEntry; /** Violations detected in this transaction */ - transactionViolations: PropTypes.arrayOf(transactionViolationPropType), + transactionViolations: OnyxEntry; +}; - /** Collection of tags attached to a policy */ - policyTags: tagPropTypes, +type MoneyRequestViewPropsWithoutTransaction = MoneyRequestViewOnyxPropsWithoutTransaction & { + /** The report currently being looked at */ + report: OnyxTypes.Report; - ...withCurrentUserPersonalDetailsPropTypes, + /** Whether we should display the horizontal rule below the component */ + shouldShowHorizontalRule: boolean; }; -const defaultProps = { - parentReport: {}, - parentReportActions: {}, - transaction: { - amount: 0, - currency: CONST.CURRENCY.USD, - comment: {comment: ''}, - }, - transactionViolations: [], - policyCategories: {}, - policyTags: {}, - ...policyDefaultProps, -}; +type MoneyRequestViewProps = MoneyRequestViewTransactionOnyxProps & MoneyRequestViewPropsWithoutTransaction; -function MoneyRequestView({report, parentReport, parentReportActions, policyCategories, shouldShowHorizontalRule, transaction, policyTags, policy, transactionViolations}) { +function MoneyRequestView({ + report, + parentReport, + parentReportActions, + policyCategories, + shouldShowHorizontalRule, + transaction, + policyTags, + policy, + transactionViolations, +}: MoneyRequestViewProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); const {canUseViolations} = usePermissions(); - const parentReportAction = parentReportActions[report.parentReportActionID] || {}; + const parentReportAction = parentReportActions?.[report.parentReportActionID ?? ''] ?? null; const moneyRequestReport = parentReport; const { created: transactionDate, @@ -137,20 +102,20 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate originalAmount: transactionOriginalAmount, originalCurrency: transactionOriginalCurrency, cardID: transactionCardID, - } = ReportUtils.getTransactionDetails(transaction); + } = ReportUtils.getTransactionDetails(transaction) ?? {}; const isEmptyMerchant = transactionMerchant === '' || transactionMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction); let formattedTransactionAmount = transactionAmount ? CurrencyUtils.convertToDisplayString(transactionAmount, transactionCurrency) : ''; - const hasPendingWaypoints = lodashGet(transaction, 'pendingFields.waypoints', null); + const hasPendingWaypoints = transaction?.pendingFields?.waypoints; if (isDistanceRequest && (!formattedTransactionAmount || hasPendingWaypoints)) { formattedTransactionAmount = translate('common.tbd'); } const formattedOriginalAmount = transactionOriginalAmount && transactionOriginalCurrency && CurrencyUtils.convertToDisplayString(transactionOriginalAmount, transactionOriginalCurrency); const isCardTransaction = TransactionUtils.isCardTransaction(transaction); - const cardProgramName = isCardTransaction ? CardUtils.getCardDescription(transactionCardID) : ''; + const cardProgramName = isCardTransaction && transactionCardID !== undefined ? CardUtils.getCardDescription(transactionCardID) : ''; // Flags for allowing or disallowing editing a money request - const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); + const isSettled = ReportUtils.isSettled(moneyRequestReport?.reportID); const isCancelled = moneyRequestReport && moneyRequestReport.isCancelledIOU; // Used for non-restricted fields such as: description, category, tag, billable, etc. @@ -167,26 +132,30 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate // Fetches only the first tag, for now const policyTag = PolicyUtils.getTag(policyTags); - const policyTagsList = lodashGet(policyTag, 'tags', {}); + const policyTagsList = policyTag?.tags ?? {}; // Flags for showing categories and tags - const shouldShowCategory = isPolicyExpenseChat && (transactionCategory || OptionsListUtils.hasEnabledOptions(lodashValues(policyCategories))); - const shouldShowTag = isPolicyExpenseChat && (transactionTag || OptionsListUtils.hasEnabledOptions(lodashValues(policyTagsList))); - const shouldShowBillable = isPolicyExpenseChat && (transactionBillable || !lodashGet(policy, 'disabledFields.defaultBillable', true)); + // transactionCategory can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const shouldShowCategory = isPolicyExpenseChat && (transactionCategory || OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); + // transactionTag can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const shouldShowTag = isPolicyExpenseChat && (transactionTag || OptionsListUtils.hasEnabledOptions(Object.values(policyTagsList))); + const shouldShowBillable = isPolicyExpenseChat && (!!transactionBillable || !(policy?.disabledFields?.defaultBillable ?? true)); - const {getViolationsForField} = useViolations(transactionViolations); - const hasViolations = useCallback((field) => canUseViolations && getViolationsForField(field).length > 0, [canUseViolations, getViolationsForField]); + const {getViolationsForField} = useViolations(transactionViolations ?? []); + const hasViolations = useCallback((field: ViolationField): boolean => !!canUseViolations && getViolationsForField(field).length > 0, [canUseViolations, getViolationsForField]); let amountDescription = `${translate('iou.amount')}`; const saveBillable = useCallback( - (newBillable) => { + (newBillable: boolean) => { // If the value hasn't changed, don't request to save changes on the server and just close the modal if (newBillable === TransactionUtils.getBillable(transaction)) { Navigation.dismissModal(); return; } - IOU.updateMoneyRequestBillable(transaction.transactionID, report.reportID, newBillable); + IOU.updateMoneyRequestBillable(transaction?.transactionID ?? '', report?.reportID, newBillable); Navigation.dismissModal(); }, [transaction, report], @@ -225,8 +194,8 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate hasErrors = canEdit && TransactionUtils.hasMissingSmartscanFields(transaction); } - const pendingAction = lodashGet(transaction, 'pendingAction'); - const getPendingFieldAction = (fieldPath) => lodashGet(transaction, fieldPath) || pendingAction; + const pendingAction = transaction?.pendingAction; + const getPendingFieldAction = (fieldPath: TransactionPendingFieldsKey) => transaction?.pendingFields?.[fieldPath] ?? pendingAction; return ( @@ -236,9 +205,11 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate )} {canUseViolations && } - + Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.AMOUNT))} - brickRoadIndicator={hasViolations('amount') || (hasErrors && transactionAmount === 0) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={hasViolations('amount') || (hasErrors && transactionAmount === 0) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={hasErrors && transactionAmount === 0 ? translate('common.error.enterAmount') : ''} /> {canUseViolations && } - + Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.DESCRIPTION))} wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]} - brickRoadIndicator={hasViolations('comment') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={hasViolations('comment') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} numberOfLinesTitle={0} /> {canUseViolations && } {isDistanceRequest ? ( - + ) : ( - + // Merchant can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.MERCHANT))} - brickRoadIndicator={hasViolations('merchant') || (hasErrors && isEmptyMerchant) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={hasViolations('merchant') || (hasErrors && isEmptyMerchant) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={hasErrors && isEmptyMerchant ? translate('common.error.enterMerchant') : ''} /> {canUseViolations && } )} - + Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.DATE))} - brickRoadIndicator={hasViolations('date') || (hasErrors && transactionDate === '') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={hasViolations('date') || (hasErrors && transactionDate === '') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={hasErrors && transactionDate === '' ? translate('common.error.enterDate') : ''} /> {canUseViolations && } {shouldShowCategory && ( - + Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.CATEGORY))} - brickRoadIndicator={hasViolations('category') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={hasViolations('category') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} /> {canUseViolations && } )} {shouldShowTag && ( - + Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.TAG))} - brickRoadIndicator={hasViolations('tag') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={hasViolations('tag') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} /> {canUseViolations && } )} {isCardTransaction && ( - + {translate('common.billable')} @@ -397,50 +370,42 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate ); } -MoneyRequestView.propTypes = propTypes; -MoneyRequestView.defaultProps = defaultProps; MoneyRequestView.displayName = 'MoneyRequestView'; -export default compose( - withCurrentUserPersonalDetails, - withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, - }, - policyCategories: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report.policyID}`, - }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report.policyID}`, - }, - parentReport: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, - }, - parentReportActions: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`, - canEvict: false, +export default withOnyx({ + policy: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, + }, + policyCategories: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report.policyID}`, + }, + policyTags: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report.policyID}`, + }, + parentReport: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, + }, + parentReportActions: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`, + canEvict: false, + }, + transactionViolations: { + key: ({report}) => { + const parentReportAction = ReportActionsUtils.getParentReportAction(report); + const originalMessage = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction.originalMessage : undefined; + const transactionID = originalMessage?.IOUTransactionID ?? 0; + return `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`; }, - }), - withOnyx({ + }, +})( + withOnyx({ transaction: { key: ({report, parentReportActions}) => { - const parentReportAction = parentReportActions[report.parentReportActionID]; - const transactionID = lodashGet(parentReportAction, ['originalMessage', 'IOUTransactionID'], 0); + const parentReportAction = parentReportActions?.[report.parentReportActionID ?? '']; + const originalMessage = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction.originalMessage : undefined; + const transactionID = originalMessage?.IOUTransactionID ?? 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, - transactionViolation: { - key: ({report}) => { - const parentReportAction = ReportActionsUtils.getParentReportAction(report); - const transactionID = lodashGet(parentReportAction, ['originalMessage', 'IOUTransactionID'], 0); - return `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`; - }, - }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report.policyID}`, - }, - }), -)(MoneyRequestView); + })(MoneyRequestView), +); diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 061ce683b33c..d92c2b9b3293 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -395,7 +395,7 @@ function isExpensifyCardTransaction(transaction: OnyxEntry): boolea /** * Determine whether a transaction is made with a card (Expensify or Company Card). */ -function isCardTransaction(transaction: Transaction): boolean { +function isCardTransaction(transaction: OnyxEntry): boolean { const cardID = transaction?.cardID ?? 0; return isCorporateCard(cardID); } diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 9aa7c52b1ea0..53cc81ef96a5 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1117,8 +1117,8 @@ function updateMoneyRequestDate(transactionID, transactionThreadReportID, val) { * Updates the billable field of a money request * * @param {String} transactionID - * @param {Number} transactionThreadReportID - * @param {String} val + * @param {String} transactionThreadReportID + * @param {Boolean} val */ function updateMoneyRequestBillable(transactionID, transactionThreadReportID, val) { const transactionChanges = { diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index da4522487a7a..e58e8b56b92e 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -82,6 +82,9 @@ type Policy = { /** The employee list of the policy */ employeeList?: []; + + /** A list of disabled fields */ + disabledFields?: Record; }; export default Policy; diff --git a/src/types/onyx/PolicyTag.ts b/src/types/onyx/PolicyTag.ts index 58a21dcf4df5..c14ede73b622 100644 --- a/src/types/onyx/PolicyTag.ts +++ b/src/types/onyx/PolicyTag.ts @@ -8,6 +8,9 @@ type PolicyTag = { /** "General Ledger code" that corresponds to this tag in an accounting system. Similar to an ID. */ // eslint-disable-next-line @typescript-eslint/naming-convention 'GL Code': string; + + /** Nested tags */ + tags: PolicyTags; }; type PolicyTags = Record; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 8b7e26280305..3a652ba0ef8c 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -49,6 +49,8 @@ type Route = { type Routes = Record; +type TransactionPendingFieldsKey = keyof Transaction | keyof Comment; + type Transaction = { amount: number; billable: boolean; @@ -76,7 +78,7 @@ type Transaction = { routes?: Routes; transactionID: string; tag: string; - pendingFields?: Partial<{[K in keyof Transaction | keyof Comment]: ValueOf}>; + pendingFields?: Partial<{[K in TransactionPendingFieldsKey]: ValueOf}>; /** Card Transactions */ @@ -97,4 +99,4 @@ type Transaction = { }; export default Transaction; -export type {WaypointCollection, Comment, Receipt, Waypoint}; +export type {WaypointCollection, Comment, Receipt, Waypoint, TransactionPendingFieldsKey}; diff --git a/src/types/onyx/TransactionViolation.ts b/src/types/onyx/TransactionViolation.ts index dd7a9ef65746..6b5882cfc73d 100644 --- a/src/types/onyx/TransactionViolation.ts +++ b/src/types/onyx/TransactionViolation.ts @@ -31,4 +31,6 @@ type TransactionViolation = { }; }; -export type {TransactionViolation, ViolationName}; +type TransactionViolations = TransactionViolation[]; + +export type {TransactionViolation, TransactionViolations, ViolationName}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 8cba351d0f45..d613d8c5d2da 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -55,7 +55,7 @@ import type SecurityGroup from './SecurityGroup'; import type Session from './Session'; import type Task from './Task'; import type Transaction from './Transaction'; -import type {TransactionViolation, ViolationName} from './TransactionViolation'; +import type {TransactionViolation, TransactionViolations, ViolationName} from './TransactionViolation'; import type User from './User'; import type UserLocation from './UserLocation'; import type UserWallet from './UserWallet'; @@ -126,6 +126,7 @@ export type { Task, Transaction, TransactionViolation, + TransactionViolations, User, UserLocation, UserWallet, From 03a0c4cdc55ab72b61987e9e3d2e10b68cf3c69f Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 16 Jan 2024 13:03:16 +0100 Subject: [PATCH 04/72] Fix lint errors --- src/components/ReportActionItem/MoneyRequestPreview.tsx | 5 ++++- src/libs/ReceiptUtils.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.tsx b/src/components/ReportActionItem/MoneyRequestPreview.tsx index a6df98973670..f997cd7273a9 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview.tsx @@ -373,7 +373,10 @@ export default withOnyx( key: ONYXKEYS.SESSION, }, transaction: { - key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${(action?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && action?.originalMessage?.IOUTransactionID) || 0}`, + key: ({action}) => { + const originalMessage = action?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? action.originalMessage : undefined; + return `${ONYXKEYS.COLLECTION.TRANSACTION}${originalMessage?.IOUTransactionID ?? 0}`; + }, }, walletTerms: { key: ONYXKEYS.WALLET_TERMS, diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index 72d37abc1b4e..29535e2a07aa 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -1,6 +1,6 @@ import Str from 'expensify-common/lib/str'; import type {ImageSourcePropType} from 'react-native'; -import {OnyxEntry} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import ReceiptDoc from '@assets/images/receipt-doc.png'; import ReceiptGeneric from '@assets/images/receipt-generic.png'; import ReceiptHTML from '@assets/images/receipt-html.png'; From 663758370fbf00a38bad24a58fa99c9cc604c49e Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 17 Jan 2024 08:47:08 +0100 Subject: [PATCH 05/72] Use ContextMenuAnchor type for anchor typing --- src/components/ReportActionItem/MoneyRequestPreview.tsx | 1 - src/components/ShowContextMenuContext.ts | 7 ++++--- .../report/ContextMenu/PopoverReportActionContextMenu.tsx | 6 +----- .../home/report/ContextMenu/ReportActionContextMenu.ts | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.tsx b/src/components/ReportActionItem/MoneyRequestPreview.tsx index 8677b7e5cbb8..b40773302695 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview.tsx @@ -177,7 +177,6 @@ function MoneyRequestPreview({ }; const showContextMenu = (event: GestureResponderEvent) => { - // @ts-expect-error TODO: Remove this once ShowContextMenuContext (https://github.com/Expensify/App/issues/24980) is migrated to TypeScript. showContextMenuForReport(event, contextMenuAnchor, chatReportID, action, checkIfContextMenuActive); }; diff --git a/src/components/ShowContextMenuContext.ts b/src/components/ShowContextMenuContext.ts index 17557051bef9..374ca8a2f1e5 100644 --- a/src/components/ShowContextMenuContext.ts +++ b/src/components/ShowContextMenuContext.ts @@ -1,15 +1,16 @@ import {createContext} from 'react'; // eslint-disable-next-line no-restricted-imports -import type {GestureResponderEvent, Text as RNText} from 'react-native'; +import type {GestureResponderEvent} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as ReportUtils from '@libs/ReportUtils'; import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu'; +import type {ContextMenuAnchor} from '@pages/home/report/ContextMenu/ReportActionContextMenu'; import CONST from '@src/CONST'; import type {Report, ReportAction} from '@src/types/onyx'; type ShowContextMenuContextProps = { - anchor: RNText | null; + anchor: ContextMenuAnchor; report: OnyxEntry; action: OnyxEntry; checkIfContextMenuActive: () => void; @@ -36,7 +37,7 @@ ShowContextMenuContext.displayName = 'ShowContextMenuContext'; */ function showContextMenuForReport( event: GestureResponderEvent | MouseEvent, - anchor: RNText | null, + anchor: ContextMenuAnchor, reportID: string, action: OnyxEntry, checkIfContextMenuActive: () => void, diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx index 46b783bca3f9..bbd048b0d82c 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx @@ -12,11 +12,7 @@ import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import type {ReportAction} from '@src/types/onyx'; import BaseReportActionContextMenu from './BaseReportActionContextMenu'; -import type {ContextMenuType, ReportActionContextMenu} from './ReportActionContextMenu'; - -type ContextMenuAnchorCallback = (x: number, y: number) => void; - -type ContextMenuAnchor = {measureInWindow: (callback: ContextMenuAnchorCallback) => void}; +import type {ContextMenuAnchor, ContextMenuType, ReportActionContextMenu} from './ReportActionContextMenu'; type Location = { x: number; diff --git a/src/pages/home/report/ContextMenu/ReportActionContextMenu.ts b/src/pages/home/report/ContextMenu/ReportActionContextMenu.ts index 19d46c1fdc4a..7080c02775ce 100644 --- a/src/pages/home/report/ContextMenu/ReportActionContextMenu.ts +++ b/src/pages/home/report/ContextMenu/ReportActionContextMenu.ts @@ -15,7 +15,7 @@ type OnCancel = () => void; type ContextMenuType = ValueOf; -type ContextMenuAnchor = View | RNText | null; +type ContextMenuAnchor = View | RNText | null | undefined; type ShowContextMenu = ( type: ContextMenuType, From e1e39e130489d4a801161dcb25399bcae380870c Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 17 Jan 2024 11:48:28 +0100 Subject: [PATCH 06/72] Code improvements --- src/components/Pressable/GenericPressable/types.ts | 2 +- .../ReportActionItem/MoneyRequestPreview.tsx | 2 +- src/components/ReportActionItem/MoneyRequestView.tsx | 10 ++++------ 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/components/Pressable/GenericPressable/types.ts b/src/components/Pressable/GenericPressable/types.ts index 03cdb30c67fc..2dd2e17e0454 100644 --- a/src/components/Pressable/GenericPressable/types.ts +++ b/src/components/Pressable/GenericPressable/types.ts @@ -40,7 +40,7 @@ type PressableProps = RNPressableProps & /** * onPress callback */ - onPress: ((event?: GestureResponderEvent | KeyboardEvent) => void | Promise) | undefined; + onPress?: (event?: GestureResponderEvent | KeyboardEvent) => void | Promise; /** * Specifies keyboard shortcut to trigger onPressHandler diff --git a/src/components/ReportActionItem/MoneyRequestPreview.tsx b/src/components/ReportActionItem/MoneyRequestPreview.tsx index b40773302695..1a685b85bf11 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview.tsx @@ -82,7 +82,7 @@ type MoneyRequestPreviewProps = MoneyRequestPreviewOnyxProps & { checkIfContextMenuActive?: () => void; /** Extra styles to pass to View wrapper */ - containerStyles: StyleProp; + containerStyles?: StyleProp; /** True if this is this IOU is a split instead of a 1:1 request */ isBillSplit: boolean; diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 28a7e1593dab..30ebce9f566c 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -265,7 +265,7 @@ function MoneyRequestView({ {canUseViolations && } {isDistanceRequest ? ( - + ) : ( - // Merchant can be an empty string - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - + } {shouldShowCategory && ( - + )} {shouldShowTag && ( - + Date: Thu, 18 Jan 2024 17:54:53 +0100 Subject: [PATCH 07/72] Update getDisplayDeleteAmountText function, move transactionViolations back to the second hoc --- .../ReportActionItem/MoneyRequestPreview.tsx | 9 ++++---- .../ReportActionItem/MoneyRequestView.tsx | 22 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.tsx b/src/components/ReportActionItem/MoneyRequestPreview.tsx index 1a685b85bf11..d2792c3964e4 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview.tsx @@ -37,7 +37,9 @@ import * as Localize from '@src/libs/Localize'; import ONYXKEYS from '@src/ONYXKEYS'; import type * as OnyxTypes from '@src/types/onyx'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; +import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; import ReportActionItemImages from './ReportActionItemImages'; type MoneyRequestPreviewOnyxProps = { @@ -229,11 +231,8 @@ function MoneyRequestPreview({ }; const getDisplayDeleteAmountText = (): string => { - const {amount, currency} = ReportUtils.getTransactionDetails(action.originalMessage as OnyxTypes.Transaction) ?? {}; - - if (isDistanceRequest) { - return CurrencyUtils.convertToDisplayString(TransactionUtils.getAmount(action.originalMessage as OnyxTypes.Transaction), currency); - } + const iouOriginalMessage: IOUMessage | EmptyObject = action?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? action.originalMessage : {}; + const {amount = 0, currency = CONST.CURRENCY.USD} = iouOriginalMessage; return CurrencyUtils.convertToDisplayString(amount, currency); }; diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 30ebce9f566c..7aeb86a3d23e 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -39,6 +39,9 @@ import ReportActionItemImage from './ReportActionItemImage'; type MoneyRequestViewTransactionOnyxProps = { /** The transaction associated with the transactionThread */ transaction: OnyxEntry; + + /** Violations detected in this transaction */ + transactionViolations: OnyxEntry; }; type MoneyRequestViewOnyxPropsWithoutTransaction = { @@ -56,9 +59,6 @@ type MoneyRequestViewOnyxPropsWithoutTransaction = { /** The actions from the parent report */ parentReportActions: OnyxEntry; - - /** Violations detected in this transaction */ - transactionViolations: OnyxEntry; }; type MoneyRequestViewPropsWithoutTransaction = MoneyRequestViewOnyxPropsWithoutTransaction & { @@ -387,14 +387,6 @@ export default withOnyx `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`, canEvict: false, }, - transactionViolations: { - key: ({report}) => { - const parentReportAction = ReportActionsUtils.getParentReportAction(report); - const originalMessage = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction.originalMessage : undefined; - const transactionID = originalMessage?.IOUTransactionID ?? 0; - return `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`; - }, - }, })( withOnyx({ transaction: { @@ -405,5 +397,13 @@ export default withOnyx { + const parentReportAction = ReportActionsUtils.getParentReportAction(report); + const originalMessage = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction.originalMessage : undefined; + const transactionID = originalMessage?.IOUTransactionID ?? 0; + return `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`; + }, + }, })(MoneyRequestView), ); From be3755861d75e8bc7e2dfc3e2eecdbfa99dcdd5e Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 22 Jan 2024 10:02:33 +0100 Subject: [PATCH 08/72] TS fixes after merging main --- .../ReportActionItem/MoneyRequestPreview.tsx | 1 - src/components/ReportActionItem/MoneyRequestView.tsx | 2 -- .../ReportActionItem/ReportActionItemImage.tsx | 7 ++++--- .../ReportActionItem/ReportActionItemImages.tsx | 11 ++--------- src/libs/ReceiptUtils.ts | 8 ++++---- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.tsx b/src/components/ReportActionItem/MoneyRequestPreview.tsx index 3ac97d4552af..2d566ca36cda 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview.tsx @@ -258,7 +258,6 @@ function MoneyRequestPreview({ > {hasReceipt && ( ; /** whether thumbnail is refer the local file or not */ isLocalFile?: boolean; diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index c24defb8ac08..06edea95fb89 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -6,20 +6,13 @@ import Text from '@components/Text'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import type {ThumbnailAndImageURI} from '@libs/ReceiptUtils'; import variables from '@styles/variables'; -import type {Transaction} from '@src/types/onyx'; import ReportActionItemImage from './ReportActionItemImage'; -type Image = { - thumbnail: string | number; - image: string | number; - transaction: Transaction; - isLocalFile: boolean; -}; - type ReportActionItemImagesProps = { /** array of image and thumbnail URIs */ - images: Image[]; + images: ThumbnailAndImageURI[]; // We're not providing default values for size and total and disabling the ESLint rule // because we want them to default to the length of images, but we can't set default props diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index 29535e2a07aa..305720eb8067 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -1,5 +1,4 @@ import Str from 'expensify-common/lib/str'; -import type {ImageSourcePropType} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import ReceiptDoc from '@assets/images/receipt-doc.png'; import ReceiptGeneric from '@assets/images/receipt-generic.png'; @@ -11,8 +10,8 @@ import type {Transaction} from '@src/types/onyx'; import * as FileUtils from './fileDownload/FileUtils'; type ThumbnailAndImageURI = { - image: ImageSourcePropType | string; - thumbnail: ImageSourcePropType | string | null; + image: number | string; + thumbnail: number | string | null; transaction?: Transaction; isLocalFile?: boolean; }; @@ -68,8 +67,9 @@ function getThumbnailAndImageURIs(transaction: OnyxEntry, receiptPa } const isLocalFile = typeof path === 'number' || path.startsWith('blob:') || path.startsWith('file:') || path.startsWith('/'); - return {thumbnail: image, image: path, isLocalFile}; + return {thumbnail: image as string | number, image: path, isLocalFile}; } // eslint-disable-next-line import/prefer-default-export export {getThumbnailAndImageURIs}; +export type {ThumbnailAndImageURI}; From 01fa10442b48b2f13bb2de632e328344703ebbd3 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 23 Jan 2024 10:00:52 +0100 Subject: [PATCH 09/72] Fix TS issues --- src/components/ReportActionItem/MoneyRequestView.tsx | 2 +- src/libs/ReceiptUtils.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 17748ca20789..877094ca509a 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -319,7 +319,7 @@ function MoneyRequestView({ , receiptPath: string | null = null, receiptFileName: string | null = null): ThumbnailAndImageURI { if (Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints')) { - return {thumbnail: null, image: ReceiptGeneric, isLocalFile: true}; + return {thumbnail: null, image: ReceiptGeneric as string | number, isLocalFile: true}; } // URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg const path = transaction?.receipt?.source ?? receiptPath ?? ''; From f65fbe0f2fa83701041d9dccf742890107d9dd48 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 23 Jan 2024 13:46:50 +0100 Subject: [PATCH 10/72] Update image typing --- src/components/ImageWithSizeCalculation.tsx | 4 ++-- .../ReportActionItem/ReportActionItemImage.tsx | 5 +++-- .../ReportActionItem/ReportActionItemImages.tsx | 2 +- src/components/ThumbnailImage.tsx | 4 ++-- src/libs/ReceiptUtils.ts | 9 +++++---- src/libs/tryResolveUrlFromApiRoot.ts | 9 +++++---- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/components/ImageWithSizeCalculation.tsx b/src/components/ImageWithSizeCalculation.tsx index c65faef53748..d0559327274a 100644 --- a/src/components/ImageWithSizeCalculation.tsx +++ b/src/components/ImageWithSizeCalculation.tsx @@ -1,6 +1,6 @@ import delay from 'lodash/delay'; import React, {useEffect, useRef, useState} from 'react'; -import type {StyleProp, ViewStyle} from 'react-native'; +import type {ImageSourcePropType, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; import Log from '@libs/Log'; @@ -19,7 +19,7 @@ type OnLoadNativeEvent = { type ImageWithSizeCalculationProps = { /** Url for image to display */ - url: string | number; + url: string | ImageSourcePropType; /** Any additional styles to apply */ style?: StyleProp; diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index fa47f3c7f316..c014a71a4789 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -2,6 +2,7 @@ import Str from 'expensify-common/lib/str'; import React from 'react'; import type {ReactElement} from 'react'; import {View} from 'react-native'; +import type {ImageSourcePropType} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx/lib/types'; import AttachmentModal from '@components/AttachmentModal'; import EReceiptThumbnail from '@components/EReceiptThumbnail'; @@ -18,10 +19,10 @@ import type {Transaction} from '@src/types/onyx'; type ReportActionItemImageProps = { /** thumbnail URI for the image */ - thumbnail?: string | number | null; + thumbnail?: string | ImageSourcePropType | null; /** URI for the image or local numeric reference for the image */ - image?: string | number; + image?: string | ImageSourcePropType; /** whether or not to enable the image preview modal */ enablePreviewModal?: boolean; diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index 06edea95fb89..00b91bf4f862 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -72,7 +72,7 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report const borderStyle = shouldShowBorder ? styles.reportActionItemImageBorder : {}; return ( ; diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index f523632cd8b6..76887fe71107 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -1,4 +1,5 @@ import Str from 'expensify-common/lib/str'; +import type {ImageSourcePropType} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import ReceiptDoc from '@assets/images/receipt-doc.png'; import ReceiptGeneric from '@assets/images/receipt-generic.png'; @@ -10,8 +11,8 @@ import type {Transaction} from '@src/types/onyx'; import * as FileUtils from './fileDownload/FileUtils'; type ThumbnailAndImageURI = { - image: number | string; - thumbnail: number | string | null; + image: ImageSourcePropType | string; + thumbnail: ImageSourcePropType | string | null; transaction?: Transaction; isLocalFile?: boolean; }; @@ -30,7 +31,7 @@ type FileNameAndExtension = { */ function getThumbnailAndImageURIs(transaction: OnyxEntry, receiptPath: string | null = null, receiptFileName: string | null = null): ThumbnailAndImageURI { if (Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints')) { - return {thumbnail: null, image: ReceiptGeneric as string | number, isLocalFile: true}; + return {thumbnail: null, image: ReceiptGeneric, isLocalFile: true}; } // URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg const path = transaction?.receipt?.source ?? receiptPath ?? ''; @@ -67,7 +68,7 @@ function getThumbnailAndImageURIs(transaction: OnyxEntry, receiptPa } const isLocalFile = typeof path === 'number' || path.startsWith('blob:') || path.startsWith('file:') || path.startsWith('/'); - return {thumbnail: image as string | number, image: path, isLocalFile}; + return {thumbnail: image, image: path, isLocalFile}; } // eslint-disable-next-line import/prefer-default-export diff --git a/src/libs/tryResolveUrlFromApiRoot.ts b/src/libs/tryResolveUrlFromApiRoot.ts index adf717d500be..df80211ff6f1 100644 --- a/src/libs/tryResolveUrlFromApiRoot.ts +++ b/src/libs/tryResolveUrlFromApiRoot.ts @@ -1,3 +1,4 @@ +import type {ImageSourcePropType} from 'react-native'; import Config from '@src/CONFIG'; import type {Request} from '@src/types/onyx'; import * as ApiUtils from './ApiUtils'; @@ -18,12 +19,12 @@ const ORIGIN_PATTERN = new RegExp(`^(${ORIGINS_TO_REPLACE.join('|')})`); * - Unmatched URLs (non expensify) are returned with no modifications */ function tryResolveUrlFromApiRoot(url: string): string; -function tryResolveUrlFromApiRoot(url: number): number; -function tryResolveUrlFromApiRoot(url: string | number): string | number; -function tryResolveUrlFromApiRoot(url: string | number): string | number { +function tryResolveUrlFromApiRoot(url: ImageSourcePropType): ImageSourcePropType; +function tryResolveUrlFromApiRoot(url: string | ImageSourcePropType): string | ImageSourcePropType; +function tryResolveUrlFromApiRoot(url: string | ImageSourcePropType): string | ImageSourcePropType { // in native, when we import an image asset, it will have a number representation which can be used in `source` of Image // in this case we can skip the url resolving - if (typeof url === 'number') { + if (typeof url !== 'string') { return url; } const apiRoot = ApiUtils.getApiRoot({shouldUseSecure: false} as Request); From e3afca1a5fae2ede960201ac031ff70ec05b7934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Wed, 24 Jan 2024 17:23:50 +0100 Subject: [PATCH 11/72] header fix --- .../MoneyTemporaryForRefactorRequestParticipantsSelector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js index 0949081435c4..34048e4dd7bc 100644 --- a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js +++ b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js @@ -229,7 +229,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ const headerMessage = useMemo( () => OptionsListUtils.getHeaderMessage( - _.get(newChatOptions, 'personalDetails.length', 0) + _.get(newChatOptions, 'recentReports.length', 0) !== 0, + _.get(newChatOptions, 'personalDetails', []).length + _.get(newChatOptions, 'recentReports', []).length !== 0, Boolean(newChatOptions.userToInvite), searchTerm.trim(), maxParticipantsReached, From 7e7f40335ef2b90bcede320b5680d88965c35df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Wed, 24 Jan 2024 17:30:01 +0100 Subject: [PATCH 12/72] header fix on second component --- .../MoneyRequestParticipantsSelector.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js index 9567b17ecdf5..12dd2df5c784 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js @@ -249,13 +249,13 @@ function MoneyRequestParticipantsSelector({ const headerMessage = useMemo( () => OptionsListUtils.getHeaderMessage( - newChatOptions.personalDetails.length + newChatOptions.recentReports.length !== 0, + _.get(newChatOptions, 'personalDetails', []).length + _.get(newChatOptions, 'recentReports', []).length !== 0, Boolean(newChatOptions.userToInvite), searchTerm.trim(), maxParticipantsReached, _.some(participants, (participant) => participant.searchText.toLowerCase().includes(searchTerm.trim().toLowerCase())), ), - [maxParticipantsReached, newChatOptions.personalDetails.length, newChatOptions.recentReports.length, newChatOptions.userToInvite, participants, searchTerm], + [maxParticipantsReached, newChatOptions, participants, searchTerm], ); // When search term updates we will fetch any reports From 41bc02b041f2047db87d055199bf4382cb625903 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 25 Jan 2024 14:46:50 +0700 Subject: [PATCH 13/72] remove MoneyRequestTagPae --- src/ROUTES.ts | 10 +- src/SCREENS.ts | 1 - ...oraryForRefactorRequestConfirmationList.js | 39 +++--- .../ReportActionItem/MoneyRequestView.js | 4 +- .../AppNavigator/ModalStackNavigators.tsx | 1 - src/libs/Navigation/linkingConfig.ts | 1 - src/libs/Navigation/types.ts | 9 +- src/pages/iou/MoneyRequestTagPage.js | 127 ------------------ .../iou/request/step/IOURequestStepTag.js | 15 ++- 9 files changed, 48 insertions(+), 159 deletions(-) delete mode 100644 src/pages/iou/MoneyRequestTagPage.js diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 9c4375b84ab6..eb2c1728d596 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -287,10 +287,6 @@ const ROUTES = { route: ':iouType/new/category/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/category/${reportID}` as const, }, - MONEY_REQUEST_TAG: { - route: ':iouType/new/tag/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/tag/${reportID}` as const, - }, MONEY_REQUEST_MERCHANT: { route: ':iouType/new/merchant/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/merchant/${reportID}` as const, @@ -374,9 +370,9 @@ const ROUTES = { getUrlWithBackToParam(`${action}/${iouType}/scan/${transactionID}/${reportID}`, backTo), }, MONEY_REQUEST_STEP_TAG: { - route: 'create/:iouType/tag/:transactionID/:reportID', - getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => - getUrlWithBackToParam(`create/${iouType}/tag/${transactionID}/${reportID}`, backTo), + route: ':action/:iouType/tag/:transactionID/:reportID', + getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`${action}/${iouType}/tag/${transactionID}/${reportID}`, backTo), }, MONEY_REQUEST_STEP_WAYPOINT: { route: ':action/:iouType/waypoint/:transactionID/:reportID/:pageIndex', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 2bf40caede57..ded041b0f5b3 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -146,7 +146,6 @@ const SCREENS = { DATE: 'Money_Request_Date', DESCRIPTION: 'Money_Request_Description', CATEGORY: 'Money_Request_Category', - TAG: 'Money_Request_Tag', MERCHANT: 'Money_Request_Merchant', WAYPOINT: 'Money_Request_Waypoint', EDIT_WAYPOINT: 'Money_Request_Edit_Waypoint', diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 2aff0444a59e..bdd3fa98672f 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -810,21 +810,30 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ rightLabel={canUseViolations && Boolean(policy.requiresCategory) ? translate('common.required') : ''} /> )} - {shouldShowTags && ( - - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams())) - } - style={[styles.moneyRequestMenuItem]} - disabled={didConfirm} - interactive={!isReadOnly} - rightLabel={canUseViolations && Boolean(policy.requiresTag) ? translate('common.required') : ''} - /> - )} + {shouldShowTags || + (true && ( + + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + transaction.transactionID, + reportID, + Navigation.getActiveRouteWithoutParams(), + ), + ) + } + style={[styles.moneyRequestMenuItem]} + disabled={didConfirm} + interactive={!isReadOnly} + rightLabel={canUseViolations && Boolean(policy.requiresTag) ? translate('common.required') : ''} + /> + ))} {shouldShowTax && ( Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.TAG))} + onPress={() => + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction.transactionID, report.reportID)) + } brickRoadIndicator={hasViolations('tag') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} /> {canUseViolations && } diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index c9325206e5b2..b9a3deb5f702 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -98,7 +98,6 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../pages/iou/MoneyRequestDatePage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.DESCRIPTION]: () => require('../../../pages/iou/MoneyRequestDescriptionPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.CATEGORY]: () => require('../../../pages/iou/MoneyRequestCategoryPage').default as React.ComponentType, - [SCREENS.MONEY_REQUEST.TAG]: () => require('../../../pages/iou/MoneyRequestTagPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.MERCHANT]: () => require('../../../pages/iou/MoneyRequestMerchantPage').default as React.ComponentType, [SCREENS.IOU_SEND.ADD_BANK_ACCOUNT]: () => require('../../../pages/AddPersonalBankAccountPage').default as React.ComponentType, [SCREENS.IOU_SEND.ADD_DEBIT_CARD]: () => require('../../../pages/settings/Wallet/AddDebitCardPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts index 5df2bcf0e57b..6f184168b9f1 100644 --- a/src/libs/Navigation/linkingConfig.ts +++ b/src/libs/Navigation/linkingConfig.ts @@ -433,7 +433,6 @@ const linkingConfig: LinkingOptions = { [SCREENS.MONEY_REQUEST.CURRENCY]: ROUTES.MONEY_REQUEST_CURRENCY.route, [SCREENS.MONEY_REQUEST.DESCRIPTION]: ROUTES.MONEY_REQUEST_DESCRIPTION.route, [SCREENS.MONEY_REQUEST.CATEGORY]: ROUTES.MONEY_REQUEST_CATEGORY.route, - [SCREENS.MONEY_REQUEST.TAG]: ROUTES.MONEY_REQUEST_TAG.route, [SCREENS.MONEY_REQUEST.MERCHANT]: ROUTES.MONEY_REQUEST_MERCHANT.route, [SCREENS.MONEY_REQUEST.RECEIPT]: ROUTES.MONEY_REQUEST_RECEIPT.route, [SCREENS.MONEY_REQUEST.DISTANCE]: ROUTES.MONEY_REQUEST_DISTANCE.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 2371c764f42a..60bc0b54e41e 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -211,12 +211,15 @@ type MoneyRequestNavigatorParamList = { iouType: string; reportID: string; }; - [SCREENS.MONEY_REQUEST.TAG]: { + [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: { iouType: string; + transactionID: string; reportID: string; + backTo: string; }; - [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: { - iouType: string; + [SCREENS.MONEY_REQUEST.STEP_TAG]: { + action: ValueOf; + iouType: ValueOf; transactionID: string; reportID: string; backTo: string; diff --git a/src/pages/iou/MoneyRequestTagPage.js b/src/pages/iou/MoneyRequestTagPage.js deleted file mode 100644 index 60e40d665580..000000000000 --- a/src/pages/iou/MoneyRequestTagPage.js +++ /dev/null @@ -1,127 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React from 'react'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import TagPicker from '@components/TagPicker'; -import tagPropTypes from '@components/tagPropTypes'; -import Text from '@components/Text'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; -import Navigation from '@libs/Navigation/Navigation'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import reportPropTypes from '@pages/reportPropTypes'; -import * as IOU from '@userActions/IOU'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import {iouDefaultProps, iouPropTypes} from './propTypes'; - -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: PropTypes.shape({ - /** Route specific parameters used on this screen via route :iouType/new/tag/:reportID? */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report ID of the IOU */ - reportID: PropTypes.string, - }), - }).isRequired, - - /* Onyx props */ - /** The report currently being used */ - report: reportPropTypes, - - /** Collection of tags attached to a policy */ - policyTags: tagPropTypes, - - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: iouPropTypes, -}; - -const defaultProps = { - report: {}, - policyTags: {}, - iou: iouDefaultProps, -}; - -function MoneyRequestTagPage({route, report, policyTags, iou}) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - - const iouType = lodashGet(route, 'params.iouType', ''); - - // Fetches the first tag list of the policy - const tagListKey = _.first(_.keys(policyTags)); - const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); - - const navigateBack = () => { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); - }; - - const updateTag = (selectedTag) => { - if (selectedTag.searchText === iou.tag) { - IOU.resetMoneyRequestTag(); - } else { - IOU.setMoneyRequestTag(selectedTag.searchText); - } - navigateBack(); - }; - - return ( - - {({insets}) => ( - <> - - {translate('iou.tagSelection', {tagName: policyTagListName})} - - - )} - - ); -} - -MoneyRequestTagPage.displayName = 'MoneyRequestTagPage'; -MoneyRequestTagPage.propTypes = propTypes; -MoneyRequestTagPage.defaultProps = defaultProps; - -export default compose( - withOnyx({ - iou: { - key: ONYXKEYS.IOU, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - report: { - key: ({route, iou}) => { - const reportID = IOU.getIOUReportID(iou, route); - - return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; - }, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, - }, - }), -)(MoneyRequestTagPage); diff --git a/src/pages/iou/request/step/IOURequestStepTag.js b/src/pages/iou/request/step/IOURequestStepTag.js index 7e2ccbe1a9dd..51bda8e232ce 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.js +++ b/src/pages/iou/request/step/IOURequestStepTag.js @@ -12,6 +12,7 @@ import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import reportPropTypes from '@pages/reportPropTypes'; import * as IOU from '@userActions/IOU'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; @@ -44,7 +45,7 @@ function IOURequestStepTag({ policyTags, report, route: { - params: {transactionID, backTo}, + params: {action, transactionID, backTo}, }, transaction: {tag}, }) { @@ -54,6 +55,7 @@ function IOURequestStepTag({ // Fetches the first tag list of the policy const tagListKey = _.first(_.keys(policyTags)); const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); + const isEditting = action === CONST.IOU.ACTION.EDIT; const navigateBack = () => { Navigation.goBack(backTo || ROUTES.HOME); @@ -64,10 +66,17 @@ function IOURequestStepTag({ * @param {String} selectedTag.searchText */ const updateTag = (selectedTag) => { - if (selectedTag.searchText === tag) { + const isSelectedTag = selectedTag.searchText === tag; + const updatedTag = !isSelectedTag ? selectedTag.searchText : ''; + if (isEditting) { + IOU.updateMoneyRequestTag(transactionID, report.reportID, updatedTag); + Navigation.dismissModal(); + return; + } + if (isSelectedTag) { IOU.resetMoneyRequestTag_temporaryForRefactor(transactionID); } else { - IOU.setMoneyRequestTag_temporaryForRefactor(transactionID, selectedTag.searchText); + IOU.setMoneyRequestTag_temporaryForRefactor(transactionID, updatedTag); } navigateBack(); }; From c07a39eff58ee3093ebf2a5436fd340b94d8ec4e Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 26 Jan 2024 14:54:09 +0100 Subject: [PATCH 14/72] TS fixes after merging OptionsListUtils migration --- .../ReportActionItem/MoneyRequestPreview.tsx | 4 +--- src/libs/OptionsListUtils.ts | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.tsx b/src/components/ReportActionItem/MoneyRequestPreview.tsx index 2d566ca36cda..83a287d68c55 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview.tsx @@ -36,7 +36,6 @@ import CONST from '@src/CONST'; import * as Localize from '@src/libs/Localize'; import ONYXKEYS from '@src/ONYXKEYS'; import type * as OnyxTypes from '@src/types/onyx'; -import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; import type {IOUMessage} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; @@ -136,8 +135,7 @@ function MoneyRequestPreview({ const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport); const participantAccountIDs = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && isBillSplit ? action.originalMessage.participantAccountIDs ?? [] : [managerID, ownerAccountID]; - // TODO: Remove the assertion once OptionsListUtils (https://github.com/Expensify/App/issues/24921) is migrated to TypeScript. - const participantAvatars = OptionsListUtils.getAvatarsForAccountIDs(participantAccountIDs, personalDetails ?? {}) as OnyxCommon.Icon[]; + const participantAvatars = OptionsListUtils.getAvatarsForAccountIDs(participantAccountIDs, personalDetails ?? {}); const sortedParticipantAvatars = lodashSortBy(participantAvatars, (avatar) => avatar.id); if (isPolicyExpenseChat && isBillSplit) { sortedParticipantAvatars.push(ReportUtils.getWorkspaceIcon(chatReport)); diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 2621e4d7f12b..463c3e7d5ee8 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -10,7 +10,21 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Beta, Login, PersonalDetails, PersonalDetailsList, Policy, PolicyCategories, Report, ReportAction, ReportActions, Transaction, TransactionViolation} from '@src/types/onyx'; +import type { + Beta, + Login, + PersonalDetails, + PersonalDetailsList, + Policy, + PolicyCategories, + PolicyCategory, + PolicyTag, + Report, + ReportAction, + ReportActions, + Transaction, + TransactionViolation, +} from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; import type {PolicyTaxRate, PolicyTaxRates} from '@src/types/onyx/PolicyTaxRates'; @@ -767,8 +781,8 @@ function getEnabledCategoriesCount(options: PolicyCategories): number { /** * Verifies that there is at least one enabled option */ -function hasEnabledOptions(options: PolicyCategories): boolean { - return Object.values(options).some((option) => option.enabled); +function hasEnabledOptions(options: PolicyCategory[] | PolicyTag[]): boolean { + return options.some((option) => option.enabled); } /** From eb4631e30198957d678326b9dd0f37d7156a442e Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 26 Jan 2024 15:00:17 +0100 Subject: [PATCH 15/72] TS fixes after merging main --- .../report/ContextMenu/PopoverReportActionContextMenu.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx index b28374fae04a..f37eabaa7c1d 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx @@ -2,7 +2,7 @@ import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; /* eslint-disable no-restricted-imports */ -import type {EmitterSubscription, GestureResponderEvent, NativeTouchEvent, Text as RNText, View} from 'react-native'; +import type {EmitterSubscription, GestureResponderEvent, NativeTouchEvent, View} from 'react-native'; import {Dimensions} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import ConfirmModal from '@components/ConfirmModal'; @@ -16,7 +16,7 @@ import CONST from '@src/CONST'; import type {ReportAction} from '@src/types/onyx'; import BaseReportActionContextMenu from './BaseReportActionContextMenu'; import type {ContextMenuAction} from './ContextMenuActions'; -import type {ContextMenuType, ReportActionContextMenu} from './ReportActionContextMenu'; +import type {ContextMenuAnchor, ContextMenuType, ReportActionContextMenu} from './ReportActionContextMenu'; type Location = { x: number; @@ -67,7 +67,7 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef(null); const anchorRef = useRef(null); const dimensionsEventListener = useRef(null); - const contextMenuAnchorRef = useRef(null); + const contextMenuAnchorRef = useRef(null); const contextMenuTargetNode = useRef(null); const onPopoverShow = useRef(() => {}); From abb17dbd7a355b7a9b74b0354d41b6be8b1905a2 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 29 Jan 2024 03:14:06 +0530 Subject: [PATCH 16/72] add tabs --- docs/Gemfile | 1 + docs/Gemfile.lock | 3 ++ docs/_config.yml | 2 + docs/_layouts/default.html | 1 + docs/_sass/_main.scss | 50 +++++++++++++++++++ .../getting-started/Using-The-App.md | 46 ++++++++++++++++- docs/assets/js/tabs.js | 7 +++ 7 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 docs/assets/js/tabs.js diff --git a/docs/Gemfile b/docs/Gemfile index 91971b594b4f..3616112f183a 100644 --- a/docs/Gemfile +++ b/docs/Gemfile @@ -13,6 +13,7 @@ gem "github-pages", group: :jekyll_plugins # If you have any plugins, put them here! group :jekyll_plugins do gem "jekyll-feed", "~> 0.12" + gem "jekyll-tabs" end # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index de99bbcb48ef..567f66d9c468 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -149,6 +149,8 @@ GEM jekyll-sitemap (1.4.0) jekyll (>= 3.7, < 5.0) jekyll-swiss (1.0.0) + jekyll-tabs (1.2.1) + jekyll (>= 3.0, < 5.0) jekyll-theme-architect (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) @@ -266,6 +268,7 @@ DEPENDENCIES jekyll-feed (~> 0.12) jekyll-redirect-from jekyll-seo-tag + jekyll-tabs liquid (~> 4.0.4) tzinfo (~> 1.2) tzinfo-data diff --git a/docs/_config.yml b/docs/_config.yml index 888f0b24a91e..12aaed805e1d 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -19,6 +19,8 @@ exclude: [README.md, TEMPLATE.md, vendor] plugins: - jekyll-seo-tag - jekyll-redirect-from + - jekyll-tabs + whitelist: - jekyll-redirect-from diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 7d98500ecf32..edb4a88d525e 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -12,6 +12,7 @@ + diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index cfdf4ff3a2bc..8a5ecddb64e1 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -842,3 +842,53 @@ button { } } } + + +.tab { + display: flex; + flex-wrap: wrap; + margin-left: -20px; + padding: 0; + list-style: none; + position: relative; +} + +.tab > * { + flex: none; + padding-left: 20px; + position: relative; +} + +.tab > * > a { + display: block; + text-align: center; + padding: 9px 20px; + color: #999; + border-bottom: 2px solid transparent; + border-bottom-color: transparent; + font-size: 12px; + text-transform: uppercase; + transition: color .1s ease-in-out; + line-height: 20px; +} + +.tab > .active > a { + color:#fff; + border-color: #00d47c; +} + +.tab > li > a { + text-decoration: none; + cursor: pointer; +} + +.tab-content { + padding: 0; +} + +.tab-content > li { + display: none; +} +.tab-content > li.active { + display: block; +} diff --git a/docs/articles/expensify-classic/getting-started/Using-The-App.md b/docs/articles/expensify-classic/getting-started/Using-The-App.md index 9b8bc530e12e..80c149a26944 100644 --- a/docs/articles/expensify-classic/getting-started/Using-The-App.md +++ b/docs/articles/expensify-classic/getting-started/Using-The-App.md @@ -4,11 +4,52 @@ description: Streamline expense management effortlessly with the Expensify mobil --- # Overview The Expensify mobile app is the ultimate expense management solution that makes it effortless to track and submit your receipts and expenses. Use the app to snap a picture of your receipts, categorize and submit expenses, and even review and approve expense reports. -# How to install the Expensify app + +# How to download the Expensify app + +{% tabs log %} + +{% tab log iOS %} To get started with Expensify on your mobile device, you need to download the app: -1. Visit the App Store (iOS) or Google Play Store (Android). +1. Visit the App Store (iOS). 2. Search for "Expensify" and select the official Expensify app. 3. Tap "Download" or "Install." + +{% endtab %} + +{% tab log android %} +To get started with Expensify on your mobile device, you need to download the app: +1. Visit the Google Play Store (Android). +2. Search for "Expensify" and select the official Expensify app. +3. Tap "Download" or "Install." +{% endtab %} + +{% endtabs %} + + +# How to smart scan + +{% tabs log %} +{% tab log iOS %} +To get started with Smartscan: +1. Open the app. +2. Click request money. +3. Allow permissions. +4. Take a photo of a receipt. + +{% endtab %} + +{% tab log android %} +To get started with Smartscan: +1. Open system settings. +2. Go to camera settings and allow permissions for Expensify. +3. Open the app. +4. Click request money. +5. Take a photo of a receipt. +{% endtab %} + +{% endtabs %} + Once the app is installed, open it and log in with your Expensify credentials. If you don't have an Expensify account, you can create one during the sign-up process. # How to enable on push notifications @@ -54,3 +95,4 @@ Expensify takes security seriously and employs encryption and other security mea Yes, you can use the mobile app offline to capture receipts and create expenses. The app will sync your data once you have an internet connection. {% include faq-end.md %} + diff --git a/docs/assets/js/tabs.js b/docs/assets/js/tabs.js new file mode 100644 index 000000000000..2607f4aeb2f9 --- /dev/null +++ b/docs/assets/js/tabs.js @@ -0,0 +1,7 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.jekyllTabs=e():t.jekyllTabs=e()}(self,(()=>{return t={918:t=>{t.exports={getChildPosition:t=>{const e=t.parentNode;for(let o=0;o{const o=document.querySelectorAll(t),a=[];for(let t=0;t{const e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild},addClass:(t,e,o)=>{t.className=t.className?`${t.className} ${e}`:e,setTimeout((()=>{t.className=t.className.replace(e,"").trim()}),o)}}},613:(t,e,o)=>{const{activateTabFromUrl:a,updateUrlWithActiveTab:n,handleTabClicked:s,addCopyToClipboardButtons:r,syncTabsWithSameLabels:l,appendToastMessageHTML:i}=o(925);t.exports={init:(t={})=>{const e={syncTabsWithSameLabels:!1,activateTabFromUrl:!1,addCopyToClipboardButtons:!1,copyToClipboardSettings:{buttonHTML:"",showToastMessageOnCopy:!1,toastMessage:"Code copied to clipboard",toastDuration:3e3}},o={...e,...t,copyToClipboardSettings:{...e.copyToClipboardSettings,...t.copyToClipboardSettings}},c=document.querySelectorAll("ul.tab > li > a");if(Array.prototype.forEach.call(c,(t=>{t.addEventListener("click",(e=>{e.preventDefault(),s(t),o.activateTabFromUrl&&n(t),o.syncTabsWithSameLabels&&l(t)}),!1)})),o.addCopyToClipboardButtons){const t=o.copyToClipboardSettings;r(t),t.showToastMessageOnCopy&&i(t.toastMessage)}o.activateTabFromUrl&&a()}}},925:(t,e,o)=>{const{getChildPosition:a,createElementFromHTML:n,findElementsWithTextContent:s,addClass:r}=o(918),l=t=>{const e=t.querySelectorAll("ul > li");Array.prototype.forEach.call(e,(t=>{t.classList.remove("active")}))},i=t=>{const e=t.parentNode,o=e.parentNode,n=a(e);if(e.className.includes("active"))return;const s=o.getAttribute("data-tab");if(!s)return;const r=document.getElementById(s);l(o),l(r),r.querySelectorAll("ul.tab-content > li")[n].classList.add("active"),e.classList.add("active")},c=(t,e)=>{if(navigator.clipboard&&window.isSecureContext)navigator.clipboard.writeText(t);else{const e=document.createElement("textarea");e.value=t,e.style.position="absolute",e.style.left="-999999px",document.body.prepend(e),e.select();try{document.execCommand("copy")}catch(t){console.error(t)}finally{e.remove()}}"function"==typeof e&&e()},d=t=>{r(document.getElementById("jekyll-tabs-copy-to-clipboard-message"),"show",t)};t.exports={removeActiveClasses:l,handleTabClicked:i,copyToClipboard:c,addCopyToClipboardButtons:({buttonHTML:t,showToastMessageOnCopy:e,toastDuration:o})=>{const a=document.querySelectorAll("ul.tab-content > li pre");for(let s=0;s{d(o)}),i.addEventListener("click",(()=>{c(r.innerText,p)}))}},activateTabFromUrl:()=>{const t=window.location.hash?.substring(1);if(!t)return;const e=document.getElementById(t);if(!e)return;const o=new URLSearchParams(window.location.search).get("active_tab");if(!o)return;const a=e.querySelector("li#"+o+" > a");a&&i(a)},updateUrlWithActiveTab:t=>{const e=t.parentNode,o=e.parentNode,a=new URLSearchParams(window.location.search);a.set("active_tab",e.id);const n=window.location.pathname+"?"+a.toString()+"#"+o.id;history.replaceState(null,"",n)},syncTabsWithSameLabels:t=>{const e=s("a",t.textContent);for(let o=0;o{const e=document.createElement("div");e.id="jekyll-tabs-copy-to-clipboard-message",e.textContent=t,document.getElementsByTagName("body")[0].appendChild(e)}}}},e={},function o(a){var n=e[a];if(void 0!==n)return n.exports;var s=e[a]={exports:{}};return t[a](s,s.exports,o),s.exports}(613);var t,e})); + +window.addEventListener('load', function () { + jekyllTabs.init({ + syncTabsWithSameLabels: true, + }); +}); From 13358a9ad6d4d332c92e1aa501526eabb0cf4414 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Mon, 29 Jan 2024 03:50:26 +0530 Subject: [PATCH 17/72] add tab style --- docs/_sass/_main.scss | 19 ++++++++----------- .../getting-started/Using-The-App.md | 9 ++++----- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 8a5ecddb64e1..3f5aa45b3c18 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -847,39 +847,36 @@ button { .tab { display: flex; flex-wrap: wrap; + align-items: center; margin-left: -20px; padding: 0; list-style: none; - position: relative; + // position: relative; } .tab > * { flex: none; - padding-left: 20px; position: relative; } .tab > * > a { display: block; + color: #AFBBB0; + font-size: 13px; text-align: center; - padding: 9px 20px; - color: #999; - border-bottom: 2px solid transparent; - border-bottom-color: transparent; - font-size: 12px; - text-transform: uppercase; - transition: color .1s ease-in-out; - line-height: 20px; + font-weight: 700; } .tab > .active > a { color:#fff; - border-color: #00d47c; + background-color: #1A3D32; } .tab > li > a { text-decoration: none; cursor: pointer; + border-radius: 20px; + padding: 10px 20px; } .tab-content { diff --git a/docs/articles/expensify-classic/getting-started/Using-The-App.md b/docs/articles/expensify-classic/getting-started/Using-The-App.md index 80c149a26944..efc5802007fb 100644 --- a/docs/articles/expensify-classic/getting-started/Using-The-App.md +++ b/docs/articles/expensify-classic/getting-started/Using-The-App.md @@ -2,14 +2,13 @@ title: Using the app description: Streamline expense management effortlessly with the Expensify mobile app. Learn how to install, enable push notifications, and use SmartScan to capture, categorize, and track expenses. Versatile for personal and business use, Expensify is a secure and automated solution for managing your finances on the go. --- +{% tabs log %} +{% tab log iOS %} # Overview The Expensify mobile app is the ultimate expense management solution that makes it effortless to track and submit your receipts and expenses. Use the app to snap a picture of your receipts, categorize and submit expenses, and even review and approve expense reports. # How to download the Expensify app -{% tabs log %} - -{% tab log iOS %} To get started with Expensify on your mobile device, you need to download the app: 1. Visit the App Store (iOS). 2. Search for "Expensify" and select the official Expensify app. @@ -17,7 +16,7 @@ To get started with Expensify on your mobile device, you need to download the ap {% endtab %} -{% tab log android %} +{% tab log Android %} To get started with Expensify on your mobile device, you need to download the app: 1. Visit the Google Play Store (Android). 2. Search for "Expensify" and select the official Expensify app. @@ -39,7 +38,7 @@ To get started with Smartscan: {% endtab %} -{% tab log android %} +{% tab log Android %} To get started with Smartscan: 1. Open system settings. 2. Go to camera settings and allow permissions for Expensify. From 7192beb7ef62201a33e4ee415c30ff8b6650f9df Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 01:20:07 +0530 Subject: [PATCH 18/72] add platforms tabs --- docs/_layouts/default.html | 12 ++- docs/_sass/_main.scss | 51 ++++------ .../deposit-accounts/Deposit-Accounts-AUD.md | 8 ++ .../deposit-accounts/Deposit-Accounts-USD.md | 3 + .../getting-started/Using-The-App.md | 50 +++------- docs/assets/js/main.js | 99 ++++++++++++++----- docs/assets/js/platform-tabs.js | 26 +++++ 7 files changed, 150 insertions(+), 99 deletions(-) create mode 100644 docs/assets/js/platform-tabs.js diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index edb4a88d525e..4803a53e3960 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -13,6 +13,7 @@ + @@ -65,10 +66,13 @@
{% if page.url contains "/articles/" %} -

- {{ page.name | remove: '.md' | split: "-" | join: " " }} -

- +
+

+ {{ page.name | remove: '.md' | split: "-" | join: " " }} +

+
+
+
{{ content }}
diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 3f5aa45b3c18..dea12a04f3c7 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -354,6 +354,9 @@ button { } .article { + .hidden { + display: none; + } img { display: block; margin: 20px auto; @@ -843,49 +846,31 @@ button { } } +.title-platform-tabs { + display: flex; + justify-content: space-between; + padding-bottom: 12px; + h1 { + padding: 0; + } +} -.tab { +#platform-tabs { display: flex; flex-wrap: wrap; align-items: center; - margin-left: -20px; - padding: 0; - list-style: none; - // position: relative; -} - -.tab > * { - flex: none; - position: relative; -} - -.tab > * > a { - display: block; - color: #AFBBB0; - font-size: 13px; text-align: center; font-weight: 700; + font-size: 13px; } -.tab > .active > a { - color:#fff; - background-color: #1A3D32; -} - -.tab > li > a { - text-decoration: none; +#platform-tabs > * { cursor: pointer; border-radius: 20px; padding: 10px 20px; } -.tab-content { - padding: 0; -} - -.tab-content > li { - display: none; -} -.tab-content > li.active { - display: block; -} +#platform-tabs > .active { + color:#fff; + background-color: #1A3D32; +} \ No newline at end of file diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md index 6114e98883e0..1863c767c40a 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md @@ -3,6 +3,8 @@ title: Deposit Accounts (AUD) description: Expensify allows you to add a personal bank account to receive reimbursements for your expenses. We never take money out of this account — it is only a place for us to deposit funds from your employer. This article covers deposit accounts for Australian banks. --- +
+ ## How-to add your Australian personal deposit account information 1. Confirm with your Policy Admin that they’ve set up Global Reimbursment 2. Set your default policy (by selecting the correct policy after clicking on your profile picture) before adding your deposit account. @@ -20,3 +22,9 @@ Bank accounts are easy to delete! Simply click the red **Delete** button in the You can complete this process on a computer or on the mobile app. +
+ +
+## How-to add your Australian personal deposit account information + +
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md index 0bc5cb0ad955..61a0fe539194 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md @@ -2,6 +2,8 @@ title: Deposit Accounts - USD description: How to add a deposit account to receive payments for yourself or your business (US) --- +
+ # Overview There are two types of deposit-only accounts: @@ -75,3 +77,4 @@ There are a few reasons a reimbursement may be unsuccessful. The first step is t If you aren’t sure, please reach out to Concierge and we can assist! {% include faq-end.md %} +
\ No newline at end of file diff --git a/docs/articles/expensify-classic/getting-started/Using-The-App.md b/docs/articles/expensify-classic/getting-started/Using-The-App.md index efc5802007fb..3172aab3b69a 100644 --- a/docs/articles/expensify-classic/getting-started/Using-The-App.md +++ b/docs/articles/expensify-classic/getting-started/Using-The-App.md @@ -2,53 +2,21 @@ title: Using the app description: Streamline expense management effortlessly with the Expensify mobile app. Learn how to install, enable push notifications, and use SmartScan to capture, categorize, and track expenses. Versatile for personal and business use, Expensify is a secure and automated solution for managing your finances on the go. --- -{% tabs log %} -{% tab log iOS %} + +
# Overview The Expensify mobile app is the ultimate expense management solution that makes it effortless to track and submit your receipts and expenses. Use the app to snap a picture of your receipts, categorize and submit expenses, and even review and approve expense reports. -# How to download the Expensify app - -To get started with Expensify on your mobile device, you need to download the app: -1. Visit the App Store (iOS). -2. Search for "Expensify" and select the official Expensify app. -3. Tap "Download" or "Install." - -{% endtab %} - -{% tab log Android %} -To get started with Expensify on your mobile device, you need to download the app: -1. Visit the Google Play Store (Android). -2. Search for "Expensify" and select the official Expensify app. -3. Tap "Download" or "Install." -{% endtab %} - -{% endtabs %} - # How to smart scan -{% tabs log %} -{% tab log iOS %} + To get started with Smartscan: 1. Open the app. 2. Click request money. 3. Allow permissions. 4. Take a photo of a receipt. -{% endtab %} - -{% tab log Android %} -To get started with Smartscan: -1. Open system settings. -2. Go to camera settings and allow permissions for Expensify. -3. Open the app. -4. Click request money. -5. Take a photo of a receipt. -{% endtab %} - -{% endtabs %} - Once the app is installed, open it and log in with your Expensify credentials. If you don't have an Expensify account, you can create one during the sign-up process. # How to enable on push notifications @@ -94,4 +62,16 @@ Expensify takes security seriously and employs encryption and other security mea Yes, you can use the mobile app offline to capture receipts and create expenses. The app will sync your data once you have an internet connection. {% include faq-end.md %} +
+
+ +# How to smart scan + + +To get started with Smartscan: +1. Open the app. +2. Click request money. +3. Allow permissions. +4. Take a photo of a receipt. +
\ No newline at end of file diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index 6e154bb09a44..af1c798e2601 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -165,6 +165,37 @@ window.addEventListener('load', () => { insertElementAfter(searchInput, searchLabel); }); +const tocbotOptions = { + // Where to render the table of contents. + tocSelector: '.article-toc', + + // Where to grab the headings to build the table of contents. + contentSelector: '', + + // Disable the collapsible functionality of the library by + // setting the maximum number of heading levels (6) + collapseDepth: 6, + headingSelector: 'h1, h2, h3, summary', + + // Main class to add to lists. + listClass: 'lhn-items', + + // Main class to add to links. + linkClass: 'link', + + // Class to add to active links, + // the link corresponding to the top most heading on the page. + activeLinkClass: 'selected-article', + + // Headings offset between the headings and the top of the document (requires scrollSmooth enabled) + headingsOffset: 80, + scrollSmoothOffset: -80, + scrollSmooth: true, + + // If there is a fixed article scroll container, set to calculate titles' offset + scrollContainer: 'content-area', +} + window.addEventListener('DOMContentLoaded', () => { injectFooterCopywrite(); @@ -179,36 +210,50 @@ window.addEventListener('DOMContentLoaded', () => { buttonCloseSidebar.addEventListener('click', closeSidebar); } - if (window.tocbot) { - window.tocbot.init({ - // Where to render the table of contents. - tocSelector: '.article-toc', - - // Where to grab the headings to build the table of contents. - contentSelector: '.article-toc-content', - - // Disable the collapsible functionality of the library by - // setting the maximum number of heading levels (6) - collapseDepth: 6, - headingSelector: 'h1, h2, h3, summary', - - // Main class to add to lists. - listClass: 'lhn-items', - - // Main class to add to links. - linkClass: 'link', + const expensifyClassic = document.getElementById('platform-expensify-classic'); + const newExpensify = document.getElementById('platform-new-expensify'); + + const expensifyClassicContent = document.getElementById('expensify-classic'); + const newExpensifyContent = document.getElementById('new-expensify'); + + let defaultPlatform; + if (expensifyClassicContent) { + defaultPlatform = '#expensify-classic'; + } else if(newExpensifyContent) { + defaultPlatform = '#new-expensify'; + } else { + defaultPlatform = '.article-toc-content'; + } - // Class to add to active links, - // the link corresponding to the top most heading on the page. - activeLinkClass: 'selected-article', + expensifyClassic?.addEventListener('click', (e) => { + expensifyClassic.classList.add('active'); + expensifyClassicContent.classList.remove('hidden'); + + newExpensify.classList.remove('active'); + newExpensifyContent.classList.add('hidden'); + window.tocbot.refresh({ + ...tocbotOptions, + contentSelector: '#expensify-classic' + }); + }); - // Headings offset between the headings and the top of the document (requires scrollSmooth enabled) - headingsOffset: 80, - scrollSmoothOffset: -80, - scrollSmooth: true, + newExpensify?.addEventListener('click', (e) => { + newExpensify.classList.add('active'); + newExpensifyContent.classList.remove('hidden'); + + expensifyClassic.classList.remove('active'); + expensifyClassicContent.classList.add('hidden'); + active = '#new-expensify'; + window.tocbot.refresh({ + ...tocbotOptions, + contentSelector: '#new-expensify' + }); + }); - // If there is a fixed article scroll container, set to calculate titles' offset - scrollContainer: 'content-area', + if (window.tocbot) { + window.tocbot.init({ + ...tocbotOptions, + contentSelector: defaultPlatform, }); } diff --git a/docs/assets/js/platform-tabs.js b/docs/assets/js/platform-tabs.js new file mode 100644 index 000000000000..25d426af7b53 --- /dev/null +++ b/docs/assets/js/platform-tabs.js @@ -0,0 +1,26 @@ +const expensifyClassic = document.getElementById('platform-expensify-classic'); +const newExpensify = document.getElementById('platform-new-expensify'); + + +const expensifyClassicContent = document.getElementById('expensify-classic'); +const newExpensifyContent = document.getElementById('new-expensify'); + +const platformTabs = document.getElementById('platform-tabs'); +if (expensifyClassicContent) { + const tab = document.createElement('div'); + tab.innerHTML = 'Expensify classic'; + tab.id = 'platform-expensify-classic'; + tab.classList.add('active'); + platformTabs.appendChild(tab); +} + +if (newExpensifyContent) { + const tab = document.createElement('div'); + tab.innerHTML = 'New expensify'; + tab.id = 'platform-new-expensify'; + + if (!expensifyClassicContent) { + tab.classList.add('active'); + } + platformTabs.appendChild(tab); +} From 9ae293ee8b707e8b591545c28b5cd046ea91019c Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 01:25:51 +0530 Subject: [PATCH 19/72] cleanup --- docs/assets/js/main.js | 30 +++++++++++++++--------------- docs/assets/js/platform-tabs.js | 8 ++++---- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index af1c798e2601..1de88432edbd 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -210,22 +210,29 @@ window.addEventListener('DOMContentLoaded', () => { buttonCloseSidebar.addEventListener('click', closeSidebar); } - const expensifyClassic = document.getElementById('platform-expensify-classic'); - const newExpensify = document.getElementById('platform-new-expensify'); + const expensifyClassicTab = document.getElementById('platform-tab-expensify-classic'); + const newExpensifyTab = document.getElementById('platform-tab-new-expensify'); const expensifyClassicContent = document.getElementById('expensify-classic'); const newExpensifyContent = document.getElementById('new-expensify'); - let defaultPlatform; + let contentSelector; if (expensifyClassicContent) { - defaultPlatform = '#expensify-classic'; + contentSelector = '#expensify-classic'; } else if(newExpensifyContent) { - defaultPlatform = '#new-expensify'; + contentSelector = '#new-expensify'; } else { - defaultPlatform = '.article-toc-content'; + contentSelector = '.article-toc-content'; } - expensifyClassic?.addEventListener('click', (e) => { + if (window.tocbot) { + window.tocbot.init({ + ...tocbotOptions, + contentSelector, + }); + } + + expensifyClassicTab?.addEventListener('click', () => { expensifyClassic.classList.add('active'); expensifyClassicContent.classList.remove('hidden'); @@ -237,7 +244,7 @@ window.addEventListener('DOMContentLoaded', () => { }); }); - newExpensify?.addEventListener('click', (e) => { + newExpensifyTab?.addEventListener('click', () => { newExpensify.classList.add('active'); newExpensifyContent.classList.remove('hidden'); @@ -250,13 +257,6 @@ window.addEventListener('DOMContentLoaded', () => { }); }); - if (window.tocbot) { - window.tocbot.init({ - ...tocbotOptions, - contentSelector: defaultPlatform, - }); - } - document.getElementById('header-button').addEventListener('click', toggleHeaderMenu); // Back button doesn't exist on all the pages diff --git a/docs/assets/js/platform-tabs.js b/docs/assets/js/platform-tabs.js index 25d426af7b53..caf547e1d2e9 100644 --- a/docs/assets/js/platform-tabs.js +++ b/docs/assets/js/platform-tabs.js @@ -1,5 +1,5 @@ -const expensifyClassic = document.getElementById('platform-expensify-classic'); -const newExpensify = document.getElementById('platform-new-expensify'); +const expensifyClassic = document.getElementById('platform-tab-expensify-classic'); +const newExpensify = document.getElementById('platform-tab-new-expensify'); const expensifyClassicContent = document.getElementById('expensify-classic'); @@ -9,7 +9,7 @@ const platformTabs = document.getElementById('platform-tabs'); if (expensifyClassicContent) { const tab = document.createElement('div'); tab.innerHTML = 'Expensify classic'; - tab.id = 'platform-expensify-classic'; + tab.id = 'platform-tab-expensify-classic'; tab.classList.add('active'); platformTabs.appendChild(tab); } @@ -17,7 +17,7 @@ if (expensifyClassicContent) { if (newExpensifyContent) { const tab = document.createElement('div'); tab.innerHTML = 'New expensify'; - tab.id = 'platform-new-expensify'; + tab.id = 'platform-tab-new-expensify'; if (!expensifyClassicContent) { tab.classList.add('active'); From 55e75b836d8e5bc8d9dfe3b32709fd664450c3a2 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 01:33:54 +0530 Subject: [PATCH 20/72] cleanup --- .../getting-started/Using-The-App.md | 24 +++++-------------- docs/assets/js/platform-tabs.js | 4 ++-- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/docs/articles/expensify-classic/getting-started/Using-The-App.md b/docs/articles/expensify-classic/getting-started/Using-The-App.md index 3172aab3b69a..f1bc31793ba8 100644 --- a/docs/articles/expensify-classic/getting-started/Using-The-App.md +++ b/docs/articles/expensify-classic/getting-started/Using-The-App.md @@ -6,18 +6,12 @@ description: Streamline expense management effortlessly with the Expensify mobil
# Overview The Expensify mobile app is the ultimate expense management solution that makes it effortless to track and submit your receipts and expenses. Use the app to snap a picture of your receipts, categorize and submit expenses, and even review and approve expense reports. +# How to install the Expensify app +To get started with Expensify on your mobile device, you need to download the app: +1. Visit the App Store (iOS) or Google Play Store (Android). +2. Search for "Expensify" and select the official Expensify app. +3. Tap "Download" or "Install." - -# How to smart scan - - -To get started with Smartscan: -1. Open the app. -2. Click request money. -3. Allow permissions. -4. Take a photo of a receipt. - - Once the app is installed, open it and log in with your Expensify credentials. If you don't have an Expensify account, you can create one during the sign-up process. # How to enable on push notifications Push notifications keep you informed about expense approvals, reimbursements, and more. To enable push notifications: @@ -65,13 +59,7 @@ Yes, you can use the mobile app offline to capture receipts and create expenses.
-# How to smart scan - +# Coming soon -To get started with Smartscan: -1. Open the app. -2. Click request money. -3. Allow permissions. -4. Take a photo of a receipt.
\ No newline at end of file diff --git a/docs/assets/js/platform-tabs.js b/docs/assets/js/platform-tabs.js index caf547e1d2e9..d49d898517c4 100644 --- a/docs/assets/js/platform-tabs.js +++ b/docs/assets/js/platform-tabs.js @@ -1,16 +1,16 @@ const expensifyClassic = document.getElementById('platform-tab-expensify-classic'); const newExpensify = document.getElementById('platform-tab-new-expensify'); - const expensifyClassicContent = document.getElementById('expensify-classic'); const newExpensifyContent = document.getElementById('new-expensify'); const platformTabs = document.getElementById('platform-tabs'); + if (expensifyClassicContent) { const tab = document.createElement('div'); tab.innerHTML = 'Expensify classic'; tab.id = 'platform-tab-expensify-classic'; - tab.classList.add('active'); + tab.classList.add('active'); platformTabs.appendChild(tab); } From 6acdd897acd6c4b2395a665871913d5338aa747d Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 01:34:38 +0530 Subject: [PATCH 21/72] cleanup --- .../deposit-accounts/Deposit-Accounts-AUD.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md index 1863c767c40a..c1082a211443 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md @@ -3,8 +3,6 @@ title: Deposit Accounts (AUD) description: Expensify allows you to add a personal bank account to receive reimbursements for your expenses. We never take money out of this account — it is only a place for us to deposit funds from your employer. This article covers deposit accounts for Australian banks. --- -
- ## How-to add your Australian personal deposit account information 1. Confirm with your Policy Admin that they’ve set up Global Reimbursment 2. Set your default policy (by selecting the correct policy after clicking on your profile picture) before adding your deposit account. @@ -22,9 +20,4 @@ Bank accounts are easy to delete! Simply click the red **Delete** button in the You can complete this process on a computer or on the mobile app. -
- -
-## How-to add your Australian personal deposit account information -
From e07c1001cfd84c682a6a81af75e87c2d392759db Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 01:35:03 +0530 Subject: [PATCH 22/72] cleanup --- .../deposit-accounts/Deposit-Accounts-AUD.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md index c1082a211443..6114e98883e0 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-AUD.md @@ -20,4 +20,3 @@ Bank accounts are easy to delete! Simply click the red **Delete** button in the You can complete this process on a computer or on the mobile app. - From 29a2e31acf9e6721f03e7d56d99e09035eda50e8 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 01:36:37 +0530 Subject: [PATCH 23/72] cleanup --- .../deposit-accounts/Deposit-Accounts-USD.md | 4 +--- .../workspace-and-domain-settings/Domain-Settings-Overview.md | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md index 61a0fe539194..8880e923ce3b 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md @@ -2,7 +2,6 @@ title: Deposit Accounts - USD description: How to add a deposit account to receive payments for yourself or your business (US) --- -
# Overview @@ -76,5 +75,4 @@ There are a few reasons a reimbursement may be unsuccessful. The first step is t If you aren’t sure, please reach out to Concierge and we can assist! -{% include faq-end.md %} -
\ No newline at end of file +{% include faq-end.md %} \ No newline at end of file diff --git a/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md b/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md index 40d759479390..730d696d97f4 100644 --- a/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md +++ b/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md @@ -2,7 +2,7 @@ title: Domains description: Want to gain greater control over your company settings in Expensify? Read on to find out more about our Domains feature and how it can help you save time and effort when managing your company expenses. --- - +
# Overview Domains is a feature in Expensify that allows admins to have more nuanced control over a specific Expensify activity, as well as providing a bird’s eye view of company card expenditure. Think of it as your command center for things like managing user account access, enforcing stricter Workspace rules for certain groups, or issuing cards and reconciling statements. There are several settings within Domains that you can configure so that you have more control and visibility into your organization’s settings. Those features are: @@ -140,3 +140,4 @@ You can manage multiple domains by adding them through **Settings > Domains > Ne Claiming a domain is limited to users with matching email domains, and allows Workspace Admins with a company email to manage bills, company cards, and reconciliation. Verifying a domain offers extra features and security. {% include faq-end.md %} +
\ No newline at end of file From e4c4aab3dc86fff0c48f439a7fb180d77a3c43dd Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 01:39:01 +0530 Subject: [PATCH 24/72] rename to tab --- docs/assets/js/main.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index 1de88432edbd..14f455247dd0 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -233,10 +233,10 @@ window.addEventListener('DOMContentLoaded', () => { } expensifyClassicTab?.addEventListener('click', () => { - expensifyClassic.classList.add('active'); + expensifyClassicTab.classList.add('active'); expensifyClassicContent.classList.remove('hidden'); - newExpensify.classList.remove('active'); + newExpensifyTab.classList.remove('active'); newExpensifyContent.classList.add('hidden'); window.tocbot.refresh({ ...tocbotOptions, @@ -245,10 +245,10 @@ window.addEventListener('DOMContentLoaded', () => { }); newExpensifyTab?.addEventListener('click', () => { - newExpensify.classList.add('active'); + newExpensifyTab.classList.add('active'); newExpensifyContent.classList.remove('hidden'); - expensifyClassic.classList.remove('active'); + expensifyClassicTab.classList.remove('active'); expensifyClassicContent.classList.add('hidden'); active = '#new-expensify'; window.tocbot.refresh({ From 5bb3a5b9749e76268c41b49c86b33e67ad945a2c Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 01:42:23 +0530 Subject: [PATCH 25/72] remove jekyll tabs --- docs/Gemfile | 1 - docs/Gemfile.lock | 3 --- docs/_config.yml | 1 - docs/_layouts/default.html | 1 - docs/_sass/_main.scss | 2 +- docs/assets/js/tabs.js | 7 ------- 6 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 docs/assets/js/tabs.js diff --git a/docs/Gemfile b/docs/Gemfile index 3616112f183a..91971b594b4f 100644 --- a/docs/Gemfile +++ b/docs/Gemfile @@ -13,7 +13,6 @@ gem "github-pages", group: :jekyll_plugins # If you have any plugins, put them here! group :jekyll_plugins do gem "jekyll-feed", "~> 0.12" - gem "jekyll-tabs" end # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 567f66d9c468..de99bbcb48ef 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -149,8 +149,6 @@ GEM jekyll-sitemap (1.4.0) jekyll (>= 3.7, < 5.0) jekyll-swiss (1.0.0) - jekyll-tabs (1.2.1) - jekyll (>= 3.0, < 5.0) jekyll-theme-architect (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) @@ -268,7 +266,6 @@ DEPENDENCIES jekyll-feed (~> 0.12) jekyll-redirect-from jekyll-seo-tag - jekyll-tabs liquid (~> 4.0.4) tzinfo (~> 1.2) tzinfo-data diff --git a/docs/_config.yml b/docs/_config.yml index 12aaed805e1d..b68bcdf8a1f3 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -19,7 +19,6 @@ exclude: [README.md, TEMPLATE.md, vendor] plugins: - jekyll-seo-tag - jekyll-redirect-from - - jekyll-tabs whitelist: diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 4803a53e3960..9c474286797f 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -12,7 +12,6 @@ - diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index dea12a04f3c7..1c0728b152ea 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -873,4 +873,4 @@ button { #platform-tabs > .active { color:#fff; background-color: #1A3D32; -} \ No newline at end of file +} diff --git a/docs/assets/js/tabs.js b/docs/assets/js/tabs.js deleted file mode 100644 index 2607f4aeb2f9..000000000000 --- a/docs/assets/js/tabs.js +++ /dev/null @@ -1,7 +0,0 @@ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.jekyllTabs=e():t.jekyllTabs=e()}(self,(()=>{return t={918:t=>{t.exports={getChildPosition:t=>{const e=t.parentNode;for(let o=0;o{const o=document.querySelectorAll(t),a=[];for(let t=0;t{const e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild},addClass:(t,e,o)=>{t.className=t.className?`${t.className} ${e}`:e,setTimeout((()=>{t.className=t.className.replace(e,"").trim()}),o)}}},613:(t,e,o)=>{const{activateTabFromUrl:a,updateUrlWithActiveTab:n,handleTabClicked:s,addCopyToClipboardButtons:r,syncTabsWithSameLabels:l,appendToastMessageHTML:i}=o(925);t.exports={init:(t={})=>{const e={syncTabsWithSameLabels:!1,activateTabFromUrl:!1,addCopyToClipboardButtons:!1,copyToClipboardSettings:{buttonHTML:"",showToastMessageOnCopy:!1,toastMessage:"Code copied to clipboard",toastDuration:3e3}},o={...e,...t,copyToClipboardSettings:{...e.copyToClipboardSettings,...t.copyToClipboardSettings}},c=document.querySelectorAll("ul.tab > li > a");if(Array.prototype.forEach.call(c,(t=>{t.addEventListener("click",(e=>{e.preventDefault(),s(t),o.activateTabFromUrl&&n(t),o.syncTabsWithSameLabels&&l(t)}),!1)})),o.addCopyToClipboardButtons){const t=o.copyToClipboardSettings;r(t),t.showToastMessageOnCopy&&i(t.toastMessage)}o.activateTabFromUrl&&a()}}},925:(t,e,o)=>{const{getChildPosition:a,createElementFromHTML:n,findElementsWithTextContent:s,addClass:r}=o(918),l=t=>{const e=t.querySelectorAll("ul > li");Array.prototype.forEach.call(e,(t=>{t.classList.remove("active")}))},i=t=>{const e=t.parentNode,o=e.parentNode,n=a(e);if(e.className.includes("active"))return;const s=o.getAttribute("data-tab");if(!s)return;const r=document.getElementById(s);l(o),l(r),r.querySelectorAll("ul.tab-content > li")[n].classList.add("active"),e.classList.add("active")},c=(t,e)=>{if(navigator.clipboard&&window.isSecureContext)navigator.clipboard.writeText(t);else{const e=document.createElement("textarea");e.value=t,e.style.position="absolute",e.style.left="-999999px",document.body.prepend(e),e.select();try{document.execCommand("copy")}catch(t){console.error(t)}finally{e.remove()}}"function"==typeof e&&e()},d=t=>{r(document.getElementById("jekyll-tabs-copy-to-clipboard-message"),"show",t)};t.exports={removeActiveClasses:l,handleTabClicked:i,copyToClipboard:c,addCopyToClipboardButtons:({buttonHTML:t,showToastMessageOnCopy:e,toastDuration:o})=>{const a=document.querySelectorAll("ul.tab-content > li pre");for(let s=0;s{d(o)}),i.addEventListener("click",(()=>{c(r.innerText,p)}))}},activateTabFromUrl:()=>{const t=window.location.hash?.substring(1);if(!t)return;const e=document.getElementById(t);if(!e)return;const o=new URLSearchParams(window.location.search).get("active_tab");if(!o)return;const a=e.querySelector("li#"+o+" > a");a&&i(a)},updateUrlWithActiveTab:t=>{const e=t.parentNode,o=e.parentNode,a=new URLSearchParams(window.location.search);a.set("active_tab",e.id);const n=window.location.pathname+"?"+a.toString()+"#"+o.id;history.replaceState(null,"",n)},syncTabsWithSameLabels:t=>{const e=s("a",t.textContent);for(let o=0;o{const e=document.createElement("div");e.id="jekyll-tabs-copy-to-clipboard-message",e.textContent=t,document.getElementsByTagName("body")[0].appendChild(e)}}}},e={},function o(a){var n=e[a];if(void 0!==n)return n.exports;var s=e[a]={exports:{}};return t[a](s,s.exports,o),s.exports}(613);var t,e})); - -window.addEventListener('load', function () { - jekyllTabs.init({ - syncTabsWithSameLabels: true, - }); -}); From 1891c00f10b734f45dbbeb0ad652c73a6bd9e9dd Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 01:44:48 +0530 Subject: [PATCH 26/72] rm whitespace --- docs/_config.yml | 1 - .../deposit-accounts/Deposit-Accounts-USD.md | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/_config.yml b/docs/_config.yml index b68bcdf8a1f3..888f0b24a91e 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -20,6 +20,5 @@ plugins: - jekyll-seo-tag - jekyll-redirect-from - whitelist: - jekyll-redirect-from diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md index 8880e923ce3b..0bc5cb0ad955 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md @@ -2,7 +2,6 @@ title: Deposit Accounts - USD description: How to add a deposit account to receive payments for yourself or your business (US) --- - # Overview There are two types of deposit-only accounts: @@ -75,4 +74,4 @@ There are a few reasons a reimbursement may be unsuccessful. The first step is t If you aren’t sure, please reach out to Concierge and we can assist! -{% include faq-end.md %} \ No newline at end of file +{% include faq-end.md %} From f3e572665d7f48ade61db8f8bfdb59318134241f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 02:15:23 +0530 Subject: [PATCH 27/72] fix lint --- docs/assets/js/main.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index 14f455247dd0..69252be6d33c 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -232,6 +232,7 @@ window.addEventListener('DOMContentLoaded', () => { }); } + // eslint-disable-line es/no-optional-chaining expensifyClassicTab?.addEventListener('click', () => { expensifyClassicTab.classList.add('active'); expensifyClassicContent.classList.remove('hidden'); @@ -244,13 +245,13 @@ window.addEventListener('DOMContentLoaded', () => { }); }); + // eslint-disable-line es/no-optional-chaining newExpensifyTab?.addEventListener('click', () => { newExpensifyTab.classList.add('active'); newExpensifyContent.classList.remove('hidden'); expensifyClassicTab.classList.remove('active'); expensifyClassicContent.classList.add('hidden'); - active = '#new-expensify'; window.tocbot.refresh({ ...tocbotOptions, contentSelector: '#new-expensify' From 8c4c1766d971a9c1a343a7904155c52c68e2d5eb Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 02:16:29 +0530 Subject: [PATCH 28/72] fix lint --- docs/assets/js/platform-tabs.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/assets/js/platform-tabs.js b/docs/assets/js/platform-tabs.js index d49d898517c4..97e6efc554e2 100644 --- a/docs/assets/js/platform-tabs.js +++ b/docs/assets/js/platform-tabs.js @@ -1,6 +1,3 @@ -const expensifyClassic = document.getElementById('platform-tab-expensify-classic'); -const newExpensify = document.getElementById('platform-tab-new-expensify'); - const expensifyClassicContent = document.getElementById('expensify-classic'); const newExpensifyContent = document.getElementById('new-expensify'); From 889c4bbbd1539c3470ccc50f3608fa1934a8b060 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 02:22:31 +0530 Subject: [PATCH 29/72] fix lint --- docs/assets/js/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index 69252be6d33c..caafd0ac1c67 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -232,7 +232,7 @@ window.addEventListener('DOMContentLoaded', () => { }); } - // eslint-disable-line es/no-optional-chaining + // eslint-disable-next-line es/no-optional-chaining expensifyClassicTab?.addEventListener('click', () => { expensifyClassicTab.classList.add('active'); expensifyClassicContent.classList.remove('hidden'); @@ -245,7 +245,7 @@ window.addEventListener('DOMContentLoaded', () => { }); }); - // eslint-disable-line es/no-optional-chaining + // eslint-disable-next-line es/no-optional-chaining newExpensifyTab?.addEventListener('click', () => { newExpensifyTab.classList.add('active'); newExpensifyContent.classList.remove('hidden'); From 5771cf87191d3edfa2c9161210a3cfe56e5e7cb8 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 02:31:59 +0530 Subject: [PATCH 30/72] add breakpoint for mobile --- docs/_sass/_main.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 1c0728b152ea..a238b3d0f7f3 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -853,6 +853,11 @@ button { h1 { padding: 0; } + + @include maxBreakpoint($breakpoint-tablet) { + flex-direction: column; + gap: 20px; + } } #platform-tabs { From 97a7a4c01269ccf331ef479dbd4124a2bde93343 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 02:41:39 +0530 Subject: [PATCH 31/72] fix lint --- docs/assets/js/main.js | 46 ++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index caafd0ac1c67..31c480bb8aaf 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -232,31 +232,33 @@ window.addEventListener('DOMContentLoaded', () => { }); } - // eslint-disable-next-line es/no-optional-chaining - expensifyClassicTab?.addEventListener('click', () => { - expensifyClassicTab.classList.add('active'); - expensifyClassicContent.classList.remove('hidden'); - - newExpensifyTab.classList.remove('active'); - newExpensifyContent.classList.add('hidden'); - window.tocbot.refresh({ - ...tocbotOptions, - contentSelector: '#expensify-classic' + if (expensifyClassicTab) { + expensifyClassicTab.addEventListener('click', () => { + expensifyClassicTab.classList.add('active'); + expensifyClassicContent.classList.remove('hidden'); + + newExpensifyTab.classList.remove('active'); + newExpensifyContent.classList.add('hidden'); + window.tocbot.refresh({ + ...tocbotOptions, + contentSelector: '#expensify-classic' + }); }); - }); + } - // eslint-disable-next-line es/no-optional-chaining - newExpensifyTab?.addEventListener('click', () => { - newExpensifyTab.classList.add('active'); - newExpensifyContent.classList.remove('hidden'); - - expensifyClassicTab.classList.remove('active'); - expensifyClassicContent.classList.add('hidden'); - window.tocbot.refresh({ - ...tocbotOptions, - contentSelector: '#new-expensify' + if (newExpensifyTab) { + newExpensifyTab.addEventListener('click', () => { + newExpensifyTab.classList.add('active'); + newExpensifyContent.classList.remove('hidden'); + + expensifyClassicTab.classList.remove('active'); + expensifyClassicContent.classList.add('hidden'); + window.tocbot.refresh({ + ...tocbotOptions, + contentSelector: '#new-expensify' + }); }); - }); + } document.getElementById('header-button').addEventListener('click', toggleHeaderMenu); From b914b57684e3c40d67f19656e27c0b46287fa07b Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 02:43:02 +0530 Subject: [PATCH 32/72] Revert "fix lint" This reverts commit 97a7a4c01269ccf331ef479dbd4124a2bde93343. --- docs/assets/js/main.js | 46 ++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index 31c480bb8aaf..caafd0ac1c67 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -232,33 +232,31 @@ window.addEventListener('DOMContentLoaded', () => { }); } - if (expensifyClassicTab) { - expensifyClassicTab.addEventListener('click', () => { - expensifyClassicTab.classList.add('active'); - expensifyClassicContent.classList.remove('hidden'); - - newExpensifyTab.classList.remove('active'); - newExpensifyContent.classList.add('hidden'); - window.tocbot.refresh({ - ...tocbotOptions, - contentSelector: '#expensify-classic' - }); + // eslint-disable-next-line es/no-optional-chaining + expensifyClassicTab?.addEventListener('click', () => { + expensifyClassicTab.classList.add('active'); + expensifyClassicContent.classList.remove('hidden'); + + newExpensifyTab.classList.remove('active'); + newExpensifyContent.classList.add('hidden'); + window.tocbot.refresh({ + ...tocbotOptions, + contentSelector: '#expensify-classic' }); - } + }); - if (newExpensifyTab) { - newExpensifyTab.addEventListener('click', () => { - newExpensifyTab.classList.add('active'); - newExpensifyContent.classList.remove('hidden'); - - expensifyClassicTab.classList.remove('active'); - expensifyClassicContent.classList.add('hidden'); - window.tocbot.refresh({ - ...tocbotOptions, - contentSelector: '#new-expensify' - }); + // eslint-disable-next-line es/no-optional-chaining + newExpensifyTab?.addEventListener('click', () => { + newExpensifyTab.classList.add('active'); + newExpensifyContent.classList.remove('hidden'); + + expensifyClassicTab.classList.remove('active'); + expensifyClassicContent.classList.add('hidden'); + window.tocbot.refresh({ + ...tocbotOptions, + contentSelector: '#new-expensify' }); - } + }); document.getElementById('header-button').addEventListener('click', toggleHeaderMenu); From bee81409c5f996f08af54285db5b336d2bd18567 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 02:43:42 +0530 Subject: [PATCH 33/72] run prettier --- docs/assets/js/main.js | 14 +++++++------- docs/assets/js/platform-tabs.js | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index caafd0ac1c67..473bd544c7b8 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -194,7 +194,7 @@ const tocbotOptions = { // If there is a fixed article scroll container, set to calculate titles' offset scrollContainer: 'content-area', -} +}; window.addEventListener('DOMContentLoaded', () => { injectFooterCopywrite(); @@ -212,14 +212,14 @@ window.addEventListener('DOMContentLoaded', () => { const expensifyClassicTab = document.getElementById('platform-tab-expensify-classic'); const newExpensifyTab = document.getElementById('platform-tab-new-expensify'); - + const expensifyClassicContent = document.getElementById('expensify-classic'); const newExpensifyContent = document.getElementById('new-expensify'); let contentSelector; if (expensifyClassicContent) { contentSelector = '#expensify-classic'; - } else if(newExpensifyContent) { + } else if (newExpensifyContent) { contentSelector = '#new-expensify'; } else { contentSelector = '.article-toc-content'; @@ -236,12 +236,12 @@ window.addEventListener('DOMContentLoaded', () => { expensifyClassicTab?.addEventListener('click', () => { expensifyClassicTab.classList.add('active'); expensifyClassicContent.classList.remove('hidden'); - + newExpensifyTab.classList.remove('active'); newExpensifyContent.classList.add('hidden'); window.tocbot.refresh({ ...tocbotOptions, - contentSelector: '#expensify-classic' + contentSelector: '#expensify-classic', }); }); @@ -249,12 +249,12 @@ window.addEventListener('DOMContentLoaded', () => { newExpensifyTab?.addEventListener('click', () => { newExpensifyTab.classList.add('active'); newExpensifyContent.classList.remove('hidden'); - + expensifyClassicTab.classList.remove('active'); expensifyClassicContent.classList.add('hidden'); window.tocbot.refresh({ ...tocbotOptions, - contentSelector: '#new-expensify' + contentSelector: '#new-expensify', }); }); diff --git a/docs/assets/js/platform-tabs.js b/docs/assets/js/platform-tabs.js index 97e6efc554e2..d9890fde9d25 100644 --- a/docs/assets/js/platform-tabs.js +++ b/docs/assets/js/platform-tabs.js @@ -17,7 +17,7 @@ if (newExpensifyContent) { tab.id = 'platform-tab-new-expensify'; if (!expensifyClassicContent) { - tab.classList.add('active'); + tab.classList.add('active'); } platformTabs.appendChild(tab); } From aaeefdcf3f53a53dbe6bcbab100b631a0bfec577 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 05:02:00 +0530 Subject: [PATCH 34/72] add gap b/w buttons --- docs/_sass/_main.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index a238b3d0f7f3..0689c1b39b56 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -867,6 +867,7 @@ button { text-align: center; font-weight: 700; font-size: 13px; + gap: 4px; } #platform-tabs > * { From 687ae7a6813b3053c06a11bcf865ed2f7e3874f5 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 05:03:56 +0530 Subject: [PATCH 35/72] fix case --- docs/assets/js/platform-tabs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/assets/js/platform-tabs.js b/docs/assets/js/platform-tabs.js index d9890fde9d25..18746efc5a84 100644 --- a/docs/assets/js/platform-tabs.js +++ b/docs/assets/js/platform-tabs.js @@ -5,7 +5,7 @@ const platformTabs = document.getElementById('platform-tabs'); if (expensifyClassicContent) { const tab = document.createElement('div'); - tab.innerHTML = 'Expensify classic'; + tab.innerHTML = 'Expensify Classic'; tab.id = 'platform-tab-expensify-classic'; tab.classList.add('active'); platformTabs.appendChild(tab); @@ -13,7 +13,7 @@ if (expensifyClassicContent) { if (newExpensifyContent) { const tab = document.createElement('div'); - tab.innerHTML = 'New expensify'; + tab.innerHTML = 'New Expensify'; tab.id = 'platform-tab-new-expensify'; if (!expensifyClassicContent) { From 72ead7ba41d8a2c74d9a3302fc68baa6783d1338 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 06:07:39 +0530 Subject: [PATCH 36/72] handle long titles --- docs/_sass/_main.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 0689c1b39b56..f0713796b68e 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -350,6 +350,7 @@ button { h1 { &.title { font-size: 2.25em; + flex: 1; } } @@ -873,7 +874,7 @@ button { #platform-tabs > * { cursor: pointer; border-radius: 20px; - padding: 10px 20px; + padding: 9px 20px; } #platform-tabs > .active { From 47c20b94928ba2ebf58f3d47d5cb66e50f6dc495 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 06:11:28 +0530 Subject: [PATCH 37/72] fix color --- docs/_sass/_main.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index f0713796b68e..d4ab85a2fa41 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -878,6 +878,6 @@ button { } #platform-tabs > .active { - color:#fff; - background-color: #1A3D32; + color: $color-text; + background-color: $color-button-background; } From a8468c7568fdf60dcbf5211f74d2ab12ae91965a Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Tue, 30 Jan 2024 06:24:13 +0530 Subject: [PATCH 38/72] fix button size --- docs/_sass/_main.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index d4ab85a2fa41..fc95a9cce7f0 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -874,7 +874,10 @@ button { #platform-tabs > * { cursor: pointer; border-radius: 20px; - padding: 9px 20px; + padding: 10px 20px; + box-sizing: border-box; + height: 36px; + line-height: 16px; } #platform-tabs > .active { From 15cffe2c5e3d97036d855bbd8237a092cd3b29f5 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 30 Jan 2024 11:41:30 +0100 Subject: [PATCH 39/72] Fix Onyx types import --- src/components/ReportActionItem/MoneyRequestAction.tsx | 2 +- src/components/ReportActionItem/MoneyRequestPreview.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestAction.tsx b/src/components/ReportActionItem/MoneyRequestAction.tsx index 51c814c1b2c6..ff29bf5b0ee8 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.tsx +++ b/src/components/ReportActionItem/MoneyRequestAction.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx/lib/types'; +import type {OnyxEntry} from 'react-native-onyx'; import RenderHTML from '@components/RenderHTML'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; diff --git a/src/components/ReportActionItem/MoneyRequestPreview.tsx b/src/components/ReportActionItem/MoneyRequestPreview.tsx index c17c5ecd4129..bde8063690b6 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview.tsx @@ -5,7 +5,7 @@ import React from 'react'; import {View} from 'react-native'; import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx/lib/types'; +import type {OnyxEntry} from 'react-native-onyx'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import MoneyRequestSkeletonView from '@components/MoneyRequestSkeletonView'; From e63e68c1f9945355a078dbc594395b90dbed3329 Mon Sep 17 00:00:00 2001 From: mkhutornyi Date: Tue, 30 Jan 2024 14:53:17 +0100 Subject: [PATCH 40/72] remove unused popover ref callbacks --- src/components/PopoverProvider/index.tsx | 6 ------ src/components/PopoverProvider/types.ts | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/components/PopoverProvider/index.tsx b/src/components/PopoverProvider/index.tsx index a738d1f9798a..69728d7be126 100644 --- a/src/components/PopoverProvider/index.tsx +++ b/src/components/PopoverProvider/index.tsx @@ -27,9 +27,6 @@ function PopoverContextProvider(props: PopoverContextProps) { } activePopoverRef.current.close(); - if (activePopoverRef.current.onCloseCallback) { - activePopoverRef.current.onCloseCallback(); - } activePopoverRef.current = null; setIsOpen(false); }, []); @@ -107,9 +104,6 @@ function PopoverContextProvider(props: PopoverContextProps) { closePopover(activePopoverRef.current.anchorRef); } activePopoverRef.current = popoverParams; - if (popoverParams?.onOpenCallback) { - popoverParams.onOpenCallback(); - } setIsOpen(true); }, [closePopover], diff --git a/src/components/PopoverProvider/types.ts b/src/components/PopoverProvider/types.ts index 49705d7ea7a8..2a366ae2a712 100644 --- a/src/components/PopoverProvider/types.ts +++ b/src/components/PopoverProvider/types.ts @@ -16,8 +16,6 @@ type AnchorRef = { ref: RefObject; close: (anchorRef?: RefObject) => void; anchorRef: RefObject; - onOpenCallback?: () => void; - onCloseCallback?: () => void; }; export type {PopoverContextProps, PopoverContextValue, AnchorRef}; From 414136a8d9e7299b3cc6217893bc98e37307f2a5 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 31 Jan 2024 11:15:51 +0700 Subject: [PATCH 41/72] 34612 --- ...oraryForRefactorRequestConfirmationList.js | 47 +++++++++---------- .../iou/request/step/IOURequestStepTag.js | 4 +- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index bdd3fa98672f..98be34c41bf9 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -810,30 +810,29 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ rightLabel={canUseViolations && Boolean(policy.requiresCategory) ? translate('common.required') : ''} /> )} - {shouldShowTags || - (true && ( - - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( - CONST.IOU.ACTION.CREATE, - iouType, - transaction.transactionID, - reportID, - Navigation.getActiveRouteWithoutParams(), - ), - ) - } - style={[styles.moneyRequestMenuItem]} - disabled={didConfirm} - interactive={!isReadOnly} - rightLabel={canUseViolations && Boolean(policy.requiresTag) ? translate('common.required') : ''} - /> - ))} + {shouldShowTags && ( + + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + transaction.transactionID, + reportID, + Navigation.getActiveRouteWithoutParams(), + ), + ) + } + style={[styles.moneyRequestMenuItem]} + disabled={didConfirm} + interactive={!isReadOnly} + rightLabel={canUseViolations && lodashGet(policy, 'requiresTag', false) ? translate('common.required') : ''} + /> + )} {shouldShowTax && ( { Navigation.goBack(backTo || ROUTES.HOME); @@ -68,7 +68,7 @@ function IOURequestStepTag({ const updateTag = (selectedTag) => { const isSelectedTag = selectedTag.searchText === tag; const updatedTag = !isSelectedTag ? selectedTag.searchText : ''; - if (isEditting) { + if (isEditing) { IOU.updateMoneyRequestTag(transactionID, report.reportID, updatedTag); Navigation.dismissModal(); return; From a0763958c623991b8ac85531e1bcb26f1551352f Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Wed, 31 Jan 2024 07:20:04 +0100 Subject: [PATCH 42/72] prevent crash on Backspace press when magic input is not focused --- src/components/MagicCodeInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MagicCodeInput.tsx b/src/components/MagicCodeInput.tsx index 4a6d87b48e38..9af07bef6af1 100644 --- a/src/components/MagicCodeInput.tsx +++ b/src/components/MagicCodeInput.tsx @@ -278,7 +278,7 @@ function MagicCodeInput( const indexToFocus = numbers[editIndex] === CONST.MAGIC_CODE_EMPTY_CHAR ? indexBeforeLastEditIndex : editIndex; const formElement = inputRefs.current as HTMLFormElement | null; - (formElement?.[indexToFocus] as HTMLInputElement).focus(); + (formElement?.[indexToFocus] as HTMLInputElement)?.focus(); onChangeTextProp(value.substring(0, indexToFocus)); return; From 17f3d4844c2db4ca8a52d8e8bc990be39aaba1e1 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 31 Jan 2024 14:21:08 +0700 Subject: [PATCH 43/72] fix lint --- .../MoneyTemporaryForRefactorRequestConfirmationList.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 98be34c41bf9..122001861827 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -818,13 +818,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ numberOfLinesTitle={2} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( - CONST.IOU.ACTION.CREATE, - iouType, - transaction.transactionID, - reportID, - Navigation.getActiveRouteWithoutParams(), - ), + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), ) } style={[styles.moneyRequestMenuItem]} From e7ff2176847948ce3c0a5d5121393c08bbabd5e0 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 31 Jan 2024 12:39:06 +0100 Subject: [PATCH 44/72] Fix TS issues after merging main --- src/components/DotIndicatorMessage.tsx | 5 ++--- src/components/MessagesRow.tsx | 3 ++- src/components/OfflineWithFeedback.tsx | 5 +++-- src/components/ReportActionItem/MoneyRequestView.tsx | 6 +++++- src/libs/Localize/index.ts | 6 +++++- src/libs/ReceiptUtils.ts | 2 +- src/types/onyx/Transaction.ts | 2 +- 7 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/components/DotIndicatorMessage.tsx b/src/components/DotIndicatorMessage.tsx index d18704fdfb05..d2143f5b48da 100644 --- a/src/components/DotIndicatorMessage.tsx +++ b/src/components/DotIndicatorMessage.tsx @@ -8,13 +8,12 @@ import useThemeStyles from '@hooks/useThemeStyles'; import fileDownload from '@libs/fileDownload'; import * as Localize from '@libs/Localize'; import CONST from '@src/CONST'; +import type {ReceiptError} from '@src/types/onyx/Transaction'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import {PressableWithoutFeedback} from './Pressable'; import Text from './Text'; -type ReceiptError = {error?: string; source: string; filename: string}; - type DotIndicatorMessageProps = { /** * In most cases this should just be errors from onxyData @@ -23,7 +22,7 @@ type DotIndicatorMessageProps = { * timestamp: 'message', * } */ - messages: Record; + messages: Record; /** The type of message, 'error' shows a red dot, 'success' shows a green dot */ type: 'error' | 'success'; diff --git a/src/components/MessagesRow.tsx b/src/components/MessagesRow.tsx index cfec6fd292e9..7c764ec94fcd 100644 --- a/src/components/MessagesRow.tsx +++ b/src/components/MessagesRow.tsx @@ -6,6 +6,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import type * as Localize from '@libs/Localize'; import CONST from '@src/CONST'; +import type {ReceiptError} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import DotIndicatorMessage from './DotIndicatorMessage'; import Icon from './Icon'; @@ -15,7 +16,7 @@ import Tooltip from './Tooltip'; type MessagesRowProps = { /** The messages to display */ - messages: Record; + messages: Record; /** The type of message, 'error' shows a red dot, 'success' shows a green dot */ type: 'error' | 'success'; diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index 1a8f313af267..2fad21fb54ef 100644 --- a/src/components/OfflineWithFeedback.tsx +++ b/src/components/OfflineWithFeedback.tsx @@ -8,6 +8,7 @@ import mapChildrenFlat from '@libs/mapChildrenFlat'; import shouldRenderOffscreen from '@libs/shouldRenderOffscreen'; import CONST from '@src/CONST'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; +import type {ReceiptError, ReceiptErrors} from '@src/types/onyx/Transaction'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import MessagesRow from './MessagesRow'; @@ -26,7 +27,7 @@ type OfflineWithFeedbackProps = ChildrenProps & { shouldHideOnDelete?: boolean; /** The errors to display */ - errors?: OnyxCommon.Errors | null; + errors?: OnyxCommon.Errors | ReceiptErrors | null; /** Whether we should show the error messages */ shouldShowErrorMessages?: boolean; @@ -84,7 +85,7 @@ function OfflineWithFeedback({ const hasErrors = !isEmptyObject(errors ?? {}); // Some errors have a null message. This is used to apply opacity only and to avoid showing redundant messages. - const errorMessages = omitBy(errors, (e) => e === null); + const errorMessages = omitBy(errors, (e: string | ReceiptError) => e === null); const hasErrorMessages = !isEmptyObject(errorMessages); const isOfflinePendingAction = !!isOffline && !!pendingAction; const isUpdateOrDeleteError = hasErrors && (pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 6e814811f858..ee727ad81518 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -205,9 +205,13 @@ function MoneyRequestView({ {hasReceipt && ( { + if (!transaction?.transactionID) { + return; + } + Transaction.clearError(transaction.transactionID); }} > diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index bc40f93dd13b..46ca550eaa1a 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -7,6 +7,7 @@ import CONST from '@src/CONST'; import translations from '@src/languages/translations'; import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {ReceiptError} from '@src/types/onyx/Transaction'; import LocaleListener from './LocaleListener'; import BaseLocaleListener from './LocaleListener/BaseLocaleListener'; @@ -102,7 +103,10 @@ type MaybePhraseKey = string | [string, Record & {isTranslated? /** * Return translated string for given error. */ -function translateIfPhraseKey(message: MaybePhraseKey): string { +function translateIfPhraseKey(message: MaybePhraseKey): string; +function translateIfPhraseKey(message: ReceiptError): ReceiptError; +function translateIfPhraseKey(message: MaybePhraseKey | ReceiptError): string | ReceiptError; +function translateIfPhraseKey(message: MaybePhraseKey | ReceiptError): string | ReceiptError { if (!message || (Array.isArray(message) && message.length === 0)) { return ''; } diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index cbffb5b454b3..444b9b0f3954 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -37,7 +37,7 @@ function getThumbnailAndImageURIs(transaction: OnyxEntry, receiptPa } // URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg // If there're errors, we need to display them in preview. We can store many files in errors, but we just need to get the last one - const errors = _.findLast(transaction.errors) as ReceiptError | undefined; + const errors = _.findLast(transaction?.errors) as ReceiptError | undefined; const path = errors?.source ?? transaction?.receipt?.source ?? receiptPath ?? ''; // filename of uploaded image or last part of remote URI const filename = errors?.filename ?? transaction?.filename ?? receiptFileName ?? ''; diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 8f2b9d03dc9e..fe7ca7436a81 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -103,4 +103,4 @@ type Transaction = { }; export default Transaction; -export type {WaypointCollection, Comment, Receipt, Waypoint, ReceiptError, TransactionPendingFieldsKey}; +export type {WaypointCollection, Comment, Receipt, Waypoint, ReceiptError, ReceiptErrors, TransactionPendingFieldsKey}; From 88d27a0e312ee856f54adb4d28a6acfbcbeaad6c Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 31 Jan 2024 17:32:20 +0300 Subject: [PATCH 45/72] Update docs/assets/js/main.js Co-authored-by: Nikki Wines --- docs/assets/js/main.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index 473bd544c7b8..6b3390148ff0 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -216,13 +216,11 @@ window.addEventListener('DOMContentLoaded', () => { const expensifyClassicContent = document.getElementById('expensify-classic'); const newExpensifyContent = document.getElementById('new-expensify'); - let contentSelector; + let contentSelector = '.article-toc-content'; if (expensifyClassicContent) { contentSelector = '#expensify-classic'; } else if (newExpensifyContent) { contentSelector = '#new-expensify'; - } else { - contentSelector = '.article-toc-content'; } if (window.tocbot) { From db2937ae9fd931949aaa5e8ddbecc6bb571bba43 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Wed, 31 Jan 2024 20:03:10 +0530 Subject: [PATCH 46/72] rm breaker --- docs/assets/js/platform-tabs.js | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/assets/js/platform-tabs.js b/docs/assets/js/platform-tabs.js index 18746efc5a84..e677e58b1e97 100644 --- a/docs/assets/js/platform-tabs.js +++ b/docs/assets/js/platform-tabs.js @@ -1,6 +1,5 @@ const expensifyClassicContent = document.getElementById('expensify-classic'); const newExpensifyContent = document.getElementById('new-expensify'); - const platformTabs = document.getElementById('platform-tabs'); if (expensifyClassicContent) { From 292b1fe75c65e8ea31c84e88320221783d543dc6 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 01:48:42 +0530 Subject: [PATCH 47/72] add selectors --- docs/_includes/endselect.html | 1 + docs/_includes/endselector.html | 1 + docs/_includes/select.html | 1 + docs/_includes/selector.html | 8 ++++++++ 4 files changed, 11 insertions(+) create mode 100644 docs/_includes/endselect.html create mode 100644 docs/_includes/endselector.html create mode 100644 docs/_includes/select.html create mode 100644 docs/_includes/selector.html diff --git a/docs/_includes/endselect.html b/docs/_includes/endselect.html new file mode 100644 index 000000000000..7f5eaa32ef17 --- /dev/null +++ b/docs/_includes/endselect.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/docs/_includes/endselector.html b/docs/_includes/endselector.html new file mode 100644 index 000000000000..7f5eaa32ef17 --- /dev/null +++ b/docs/_includes/endselector.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/_includes/select.html b/docs/_includes/select.html new file mode 100644 index 000000000000..510f724e46f5 --- /dev/null +++ b/docs/_includes/select.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/docs/_includes/selector.html b/docs/_includes/selector.html new file mode 100644 index 000000000000..ea9a91a1696e --- /dev/null +++ b/docs/_includes/selector.html @@ -0,0 +1,8 @@ +{% assign values = include.values | split: "," %} + +
+ From 0e39061e41bb2ceeeb9a3dd964feb2c80094bd40 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 02:13:27 +0530 Subject: [PATCH 48/72] hide menu on selction --- docs/_includes/select.html | 2 +- docs/_includes/selector.html | 4 ++-- docs/_layouts/default.html | 1 + docs/_sass/_main.scss | 4 ++++ docs/assets/js/selector.js | 26 ++++++++++++++++++++++++++ 5 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 docs/assets/js/selector.js diff --git a/docs/_includes/select.html b/docs/_includes/select.html index 510f724e46f5..6b34d87152b7 100644 --- a/docs/_includes/select.html +++ b/docs/_includes/select.html @@ -1 +1 @@ -
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/_includes/selector.html b/docs/_includes/selector.html index ea9a91a1696e..c52e5bfcae30 100644 --- a/docs/_includes/selector.html +++ b/docs/_includes/selector.html @@ -1,8 +1,8 @@ {% assign values = include.values | split: "," %}
- {% for value in values %} - + {% endfor %} diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 7d98500ecf32..3d89708794e5 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -12,6 +12,7 @@ + diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index cfdf4ff3a2bc..961606239127 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -842,3 +842,7 @@ button { } } } + +.hidden { + display: none; +} \ No newline at end of file diff --git a/docs/assets/js/selector.js b/docs/assets/js/selector.js new file mode 100644 index 000000000000..4d190f308ba3 --- /dev/null +++ b/docs/assets/js/selector.js @@ -0,0 +1,26 @@ +/** + * 1. The selector can have any name + * 2. The selector should be in sync in all pages + * 3. Minimal code in article + * + * + +This can be derived from class name . + + */ + + + + +const selectors = document.getElementsByClassName('selector'); +for (let selector of selectors) { + // selector.addEventListener('onchange') +} + +function select(e) { + const selectedValue = e.options[e.selectedIndex].value; + const toHide = document.getElementsByClassName(selectedValue); + for (element of toHide) { + element.classList.add('hidden'); + } +} \ No newline at end of file From f087f23e63c2985871f918f6e489bbae4cb433f8 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 02:53:31 +0530 Subject: [PATCH 49/72] show and hide selection on load --- docs/_includes/selector.html | 2 +- docs/assets/js/selector.js | 32 ++++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/_includes/selector.html b/docs/_includes/selector.html index c52e5bfcae30..3331eb4d17d1 100644 --- a/docs/_includes/selector.html +++ b/docs/_includes/selector.html @@ -1,7 +1,7 @@ {% assign values = include.values | split: "," %}
- {% for value in values %} {% endfor %} diff --git a/docs/assets/js/selector.js b/docs/assets/js/selector.js index 4d190f308ba3..a4a9d83e5af3 100644 --- a/docs/assets/js/selector.js +++ b/docs/assets/js/selector.js @@ -11,16 +11,28 @@ This can be derived from class name . +function selectOption(s) { + if (!s) { + return; + } -const selectors = document.getElementsByClassName('selector'); -for (let selector of selectors) { - // selector.addEventListener('onchange') + const allOptions = Array.from(s.options); + const selectedValue = s.options[s.selectedIndex].value; + + allOptions.forEach(option => { + if (option.value === selectedValue) { + const toShow = document.getElementsByClassName(option.value); + for (e of toShow) { + e.classList.remove('hidden'); + } + return; + } + + const toHide = document.getElementsByClassName(option.value); + for (e of toHide) { + e.classList.add('hidden'); + } + }); } -function select(e) { - const selectedValue = e.options[e.selectedIndex].value; - const toHide = document.getElementsByClassName(selectedValue); - for (element of toHide) { - element.classList.add('hidden'); - } -} \ No newline at end of file +window.onload = selectOption(document.getElementsByClassName('platform')[0]); \ No newline at end of file From d387b2f5a34ca50ef28781c880e5747d12da5a40 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 02:56:36 +0530 Subject: [PATCH 50/72] style background --- docs/_sass/_main.scss | 8 +++++++- docs/assets/js/selector.js | 5 +---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 961606239127..385e26acb0ee 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -845,4 +845,10 @@ button { .hidden { display: none; -} \ No newline at end of file +} + +.selector { + background-color: $color-highlightBG; + border-radius: 12px; + padding: 20px; +} diff --git a/docs/assets/js/selector.js b/docs/assets/js/selector.js index a4a9d83e5af3..210c787b6887 100644 --- a/docs/assets/js/selector.js +++ b/docs/assets/js/selector.js @@ -8,9 +8,6 @@ This can be derived from class name . */ - - - function selectOption(s) { if (!s) { return; @@ -35,4 +32,4 @@ function selectOption(s) { }); } -window.onload = selectOption(document.getElementsByClassName('platform')[0]); \ No newline at end of file +window.onload = selectOption(document.getElementsByClassName('platform')[0]); From 9fda267aa8ad2b35fed149ff39a89225c5de7c83 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 03:09:56 +0530 Subject: [PATCH 51/72] style background --- docs/_sass/_main.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 385e26acb0ee..b61028fc53a3 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -851,4 +851,5 @@ button { background-color: $color-highlightBG; border-radius: 12px; padding: 20px; + margin-bottom: 20px; } From 6a51f2184398eb76925f83ffc16db10ddbe2b4a4 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 03:10:12 +0530 Subject: [PATCH 52/72] keep all selectors on page in sync --- docs/assets/js/selector.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/assets/js/selector.js b/docs/assets/js/selector.js index 210c787b6887..f0d1756b8fe2 100644 --- a/docs/assets/js/selector.js +++ b/docs/assets/js/selector.js @@ -2,20 +2,22 @@ * 1. The selector can have any name * 2. The selector should be in sync in all pages * 3. Minimal code in article - * - * - -This can be derived from class name . - */ function selectOption(s) { if (!s) { return; } + // Keep all selects on the page in sync + const allSelects = document.querySelectorAll('select'); + for (e of allSelects) { + e.selectedIndex = s.selectedIndex; + } + const allOptions = Array.from(s.options); const selectedValue = s.options[s.selectedIndex].value; - + + // Hide section that isn't selected, and show section that is selected. allOptions.forEach(option => { if (option.value === selectedValue) { const toShow = document.getElementsByClassName(option.value); From aafbdda012561f65c3756d6b3ae71691bc1aef4e Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 03:20:10 +0530 Subject: [PATCH 53/72] add basic style to select --- docs/_sass/_main.scss | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index b61028fc53a3..def9726b1376 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -853,3 +853,13 @@ button { padding: 20px; margin-bottom: 20px; } + +select { + height: 28px; + border-radius: 20px; + padding: 0px 12px; + background-color: $color-button-background; + font-size: 11px; + font-weight: 700; + align-items: center; +} \ No newline at end of file From c78b434b5da6f1ba7e2f7f35d0a4967b2c9fb8fc Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 1 Feb 2024 11:32:12 +0700 Subject: [PATCH 54/72] refactor logic to update tag and implement for split flow --- .../MoneyRequestConfirmationList.js | 10 +++++++- ...oraryForRefactorRequestConfirmationList.js | 2 +- src/libs/actions/IOU.js | 24 +------------------ .../step/IOURequestStepParticipants.js | 2 +- .../iou/request/step/IOURequestStepTag.js | 14 ++++++----- .../MoneyRequestParticipantsPage.js | 1 - 6 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index afabb40fd9f4..7508943d4769 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -769,7 +769,15 @@ function MoneyRequestConfirmationList(props) { numberOfLinesTitle={2} onPress={() => { if (props.isEditingSplitBill) { - Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.TAG)); + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( + CONST.IOU.ACTION.EDIT, + CONST.IOU.TYPE.SPLIT, + props.transaction.transactionID, + props.reportID, + Navigation.getActiveRouteWithoutParams(), + ), + ); return; } Navigation.navigate(ROUTES.MONEY_REQUEST_TAG.getRoute(props.iouType, props.reportID)); diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 122001861827..8dc9d3e419c0 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -258,7 +258,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const shouldCalculateDistanceAmount = isDistanceRequest && iouAmount === 0; // A flag for showing the categories field - const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories))); + const shouldShowCategories = iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories)); // A flag and a toggler for showing the rest of the form fields const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 5b503e4a5046..8c771149c5f3 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -234,17 +234,10 @@ function resetMoneyRequestCategory_temporaryForRefactor(transactionID) { * @param {String} transactionID * @param {String} tag */ -function setMoneyRequestTag_temporaryForRefactor(transactionID, tag) { +function setMoneyRequestTag(transactionID, tag) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {tag}); } -/* - * @param {String} transactionID - */ -function resetMoneyRequestTag_temporaryForRefactor(transactionID) { - Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {tag: null}); -} - /** * @param {String} transactionID * @param {Boolean} billable @@ -3635,17 +3628,6 @@ function resetMoneyRequestCategory() { Onyx.merge(ONYXKEYS.IOU, {category: ''}); } -/* - * @param {String} tag - */ -function setMoneyRequestTag(tag) { - Onyx.merge(ONYXKEYS.IOU, {tag}); -} - -function resetMoneyRequestTag() { - Onyx.merge(ONYXKEYS.IOU, {tag: ''}); -} - /** * @param {String} transactionID * @param {Object} taxRate @@ -3726,7 +3708,6 @@ function navigateToNextPage(iou, iouType, report, path = '') { .value(); setMoneyRequestParticipants(participants); resetMoneyRequestCategory(); - resetMoneyRequestTag(); } Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); return; @@ -3795,8 +3776,6 @@ export { resetMoneyRequestCategory, resetMoneyRequestCategory_temporaryForRefactor, resetMoneyRequestInfo, - resetMoneyRequestTag, - resetMoneyRequestTag_temporaryForRefactor, clearMoneyRequest, setMoneyRequestAmount_temporaryForRefactor, setMoneyRequestBillable_temporaryForRefactor, @@ -3807,7 +3786,6 @@ export { setMoneyRequestMerchant_temporaryForRefactor, setMoneyRequestParticipants_temporaryForRefactor, setMoneyRequestReceipt, - setMoneyRequestTag_temporaryForRefactor, setMoneyRequestAmount, setMoneyRequestBillable, setMoneyRequestCategory, diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.js b/src/pages/iou/request/step/IOURequestStepParticipants.js index 0d1177e231c4..5f1b22cab128 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.js +++ b/src/pages/iou/request/step/IOURequestStepParticipants.js @@ -70,7 +70,7 @@ function IOURequestStepParticipants({ const goToNextStep = useCallback(() => { const nextStepIOUType = numberOfParticipants.current === 1 ? iouType : CONST.IOU.TYPE.SPLIT; - IOU.resetMoneyRequestTag_temporaryForRefactor(transactionID); + IOU.setMoneyRequestTag(transactionID, ''); IOU.resetMoneyRequestCategory_temporaryForRefactor(transactionID); Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(nextStepIOUType, transactionID, selectedReportID.current || reportID)); }, [iouType, transactionID, reportID]); diff --git a/src/pages/iou/request/step/IOURequestStepTag.js b/src/pages/iou/request/step/IOURequestStepTag.js index 31dadf624f61..e4390c5abbde 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.js +++ b/src/pages/iou/request/step/IOURequestStepTag.js @@ -45,7 +45,7 @@ function IOURequestStepTag({ policyTags, report, route: { - params: {action, transactionID, backTo}, + params: {action, transactionID, backTo, iouType}, }, transaction: {tag}, }) { @@ -56,6 +56,7 @@ function IOURequestStepTag({ const tagListKey = _.first(_.keys(policyTags)); const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); const isEditing = action === CONST.IOU.ACTION.EDIT; + const isBillSplit = iouType === CONST.IOU.TYPE.SPLIT; const navigateBack = () => { Navigation.goBack(backTo || ROUTES.HOME); @@ -68,16 +69,17 @@ function IOURequestStepTag({ const updateTag = (selectedTag) => { const isSelectedTag = selectedTag.searchText === tag; const updatedTag = !isSelectedTag ? selectedTag.searchText : ''; + if (isBillSplit) { + IOU.setDraftSplitTransaction(transactionID, {tag: selectedTag.searchText}); + navigateBack(); + return; + } if (isEditing) { IOU.updateMoneyRequestTag(transactionID, report.reportID, updatedTag); Navigation.dismissModal(); return; } - if (isSelectedTag) { - IOU.resetMoneyRequestTag_temporaryForRefactor(transactionID); - } else { - IOU.setMoneyRequestTag_temporaryForRefactor(transactionID, updatedTag); - } + IOU.setMoneyRequestTag(transactionID, updatedTag); navigateBack(); }; diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index 216154be9cd4..ea57d88579ae 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -88,7 +88,6 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route, transaction}) { const navigateToConfirmationStep = (moneyRequestType) => { IOU.setMoneyRequestId(moneyRequestType); IOU.resetMoneyRequestCategory(); - IOU.resetMoneyRequestTag(); Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(moneyRequestType, reportID)); }; From 4e83c6fae2bfd9539b9edebd9ac8ac5d2772ed2f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 13:55:52 +0530 Subject: [PATCH 55/72] position selector --- docs/_sass/_main.scss | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index def9726b1376..eda9f5ef3387 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -458,6 +458,26 @@ button { opacity: 0.8; } } + + .selector { + background-color: $color-highlightBG; + display: flex; + flex-direction: row-reverse; + gap: 20px; + border-radius: 12px; + padding: 20px; + margin-bottom: 20px; + } + + select { + height: 28px; + border-radius: 20px; + padding: 0px 12px; + background-color: $color-button-background; + color: $color-text; + font-size: 11px; + font-weight: 700; + } } } @@ -846,20 +866,3 @@ button { .hidden { display: none; } - -.selector { - background-color: $color-highlightBG; - border-radius: 12px; - padding: 20px; - margin-bottom: 20px; -} - -select { - height: 28px; - border-radius: 20px; - padding: 0px 12px; - background-color: $color-button-background; - font-size: 11px; - font-weight: 700; - align-items: center; -} \ No newline at end of file From 03249e02e77482f0f61dd5ce4df79d2b68df312c Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 14:05:48 +0530 Subject: [PATCH 56/72] rm padding for ol in selector --- docs/_sass/_main.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index eda9f5ef3387..304242066bef 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -467,6 +467,9 @@ button { border-radius: 12px; padding: 20px; margin-bottom: 20px; + * > ol { + padding: 0; + } } select { From 6cca2910212c19265d755cd93eda1f1c8d5cc4b0 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 19:18:44 +0530 Subject: [PATCH 57/72] rm padding for ul in selector --- docs/_includes/{endselect.html => end-option.html} | 0 docs/_includes/{endselector.html => end-selector.html} | 0 docs/_includes/option.html | 1 + docs/_includes/select.html | 1 - docs/_includes/selector.html | 2 +- docs/_sass/_main.scss | 2 +- 6 files changed, 3 insertions(+), 3 deletions(-) rename docs/_includes/{endselect.html => end-option.html} (100%) rename docs/_includes/{endselector.html => end-selector.html} (100%) create mode 100644 docs/_includes/option.html delete mode 100644 docs/_includes/select.html diff --git a/docs/_includes/endselect.html b/docs/_includes/end-option.html similarity index 100% rename from docs/_includes/endselect.html rename to docs/_includes/end-option.html diff --git a/docs/_includes/endselector.html b/docs/_includes/end-selector.html similarity index 100% rename from docs/_includes/endselector.html rename to docs/_includes/end-selector.html diff --git a/docs/_includes/option.html b/docs/_includes/option.html new file mode 100644 index 000000000000..0168c15dc97e --- /dev/null +++ b/docs/_includes/option.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/docs/_includes/select.html b/docs/_includes/select.html deleted file mode 100644 index 6b34d87152b7..000000000000 --- a/docs/_includes/select.html +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/docs/_includes/selector.html b/docs/_includes/selector.html index 3331eb4d17d1..e43c32cfe5bb 100644 --- a/docs/_includes/selector.html +++ b/docs/_includes/selector.html @@ -3,6 +3,6 @@
diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 304242066bef..0db0ad07a759 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -467,7 +467,7 @@ button { border-radius: 12px; padding: 20px; margin-bottom: 20px; - * > ol { + * > ol, ul { padding: 0; } } From a2bd84bde71b71b67271a4042b6d97c97728daaf Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 19:23:19 +0530 Subject: [PATCH 58/72] space between content --- docs/_sass/_main.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 0db0ad07a759..cc8b24c8f24e 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -467,6 +467,7 @@ button { border-radius: 12px; padding: 20px; margin-bottom: 20px; + justify-content: space-between; * > ol, ul { padding: 0; } From 68bd5830e1916c77db0f91f7478c6cc17dda6a6c Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 20:08:16 +0530 Subject: [PATCH 59/72] pixel perfect selector arrow --- docs/_includes/selector.html | 5 +++-- docs/_sass/_main.scss | 17 ++++++++++++++--- docs/assets/js/selector.js | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/_includes/selector.html b/docs/_includes/selector.html index e43c32cfe5bb..be27578a519a 100644 --- a/docs/_includes/selector.html +++ b/docs/_includes/selector.html @@ -1,7 +1,8 @@ {% assign values = include.values | split: "," %} -
- {% for value in values %} {% endfor %} diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index cc8b24c8f24e..4fab45188eb8 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -459,7 +459,7 @@ button { } } - .selector { + .selector-container { background-color: $color-highlightBG; display: flex; flex-direction: row-reverse; @@ -476,11 +476,22 @@ button { select { height: 28px; border-radius: 20px; - padding: 0px 12px; - background-color: $color-button-background; + padding: 0px 26px 0px 12px; color: $color-text; font-size: 11px; font-weight: 700; + text-align: center; + cursor: pointer; + + appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + } + + select { + background: url("/assets/images/down.svg") no-repeat right $color-button-background; + background-size: 12px; + background-position-x: 85%; } } diff --git a/docs/assets/js/selector.js b/docs/assets/js/selector.js index f0d1756b8fe2..1292f50d1b32 100644 --- a/docs/assets/js/selector.js +++ b/docs/assets/js/selector.js @@ -34,4 +34,4 @@ function selectOption(s) { }); } -window.onload = selectOption(document.getElementsByClassName('platform')[0]); +window.onload = selectOption(document.getElementsByClassName('selector')[0]); From 1a7a4bcc3a79bb02973953e9bbdf1360153772ed Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 20:08:56 +0530 Subject: [PATCH 60/72] refac --- docs/_sass/_main.scss | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 4fab45188eb8..290a7ce25f80 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -482,16 +482,15 @@ button { font-weight: 700; text-align: center; cursor: pointer; - - appearance: none; - -moz-appearance: none; - -webkit-appearance: none; } select { background: url("/assets/images/down.svg") no-repeat right $color-button-background; background-size: 12px; background-position-x: 85%; + appearance: none !important; + -moz-appearance: none !important; + -webkit-appearance: none !important; } } From 6f13838aeccbfad57859966070c4e6724b458192 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 20:26:04 +0530 Subject: [PATCH 61/72] add sample article - join your company's workspace --- .../Join-your-company's-workspace.md | 258 ++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md diff --git a/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md b/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md new file mode 100644 index 000000000000..099f381e6010 --- /dev/null +++ b/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md @@ -0,0 +1,258 @@ +--- +title: Join your company's workspace +description: Get started with Expensify as an employee or other company member +--- +
+ +# Overview + +Welcome to Expensify! If you received an invitation to join your company’s Expensify workspace, follow the steps below to get started. + +# 1. Download the mobile app + +Upload your expenses and check your reports right from your phone by downloading the Expensify mobile app. You can search for “Expensify” in the app store, or tap one of the links below. + +[iOS](https://apps.apple.com/us/app/expensify-expense-tracker/id471713959) +| [Android](https://play.google.com/store/apps/details?id=org.me.mobiexpensifyg&hl=en_US&gl=US) + +# 2. Add your name and photo + +{% include selector.html values="desktop, mobile" %} +{% include option.html value="desktop" %} +
    +
  1. Click the profile image at the top of the main menu.
  2. +
  3. Hover over the profile picture and click Change.
  4. +
  5. Update your profile picture and name. +
      +
    • Name: Enter your first and last name into the fields and click Update. Note that this name will be visible to anyone in your company workspace.
    • +
    • Photo: Click Add Photo.
    • +
    +
  6. +
+ +{% include end-option.html %} + +{% include option.html value="mobile" %} + +
    +
  1. Tap the ☰ menu icon in the top left.
  2. +
  3. Tap the profile picture icon.
  4. +
  5. Tap the Edit icon next to your name and update your name or photo. +
      +
    • Name: Enter your first and/or last name into the fields and tap Update. Note that this name will be visible to anyone in your company workspace.
    • +
    • Photo: Tap Upload Photo and either:
    • +
        +
      • Tap the capture button to take a new photo.
      • +
      • Tap the photo icon on the left to select a saved photo.
      • +
      +
    +
  6. +
+ +{% include end-option.html %} +{% include end-selector.html %} + + +# 3. Meet Concierge +Your personal assistant, Concierge, lives on your Expensify Home page on both desktop and the mobile app. + +Concierge will walk you through setting up your account and also provide: +
    +
  • Reminders to do things like submit your expenses
  • +
  • Alerts when more information is needed on an expense report
  • +
  • Updates on new and improved account features
  • +
+ +You can also get support at any time by clicking the green chat bubble in the right corner. This will open a chat with Concierge where you can ask questions and receive direct support. + +# 4. Learn how to add an expense +As an employee, you may need to document reimbursable expenses (like business travel paid for with personal funds) or non-reimbursable expenses (like a lunch paid for with a company card). You can create an expense automatically by SmartScanning a receipt, or you can enter them manually. + +## SmartScan a receipt + +You can upload pictures of your receipts to Expensify and SmartScan will automatically capture the receipt details including the merchant, date, total, and currency. + +{% include selector.html values="desktop, mobile" %} +{% include option.html value="desktop" %} +
    +
  1. Click the Expenses tab.
  2. +
  3. Click the + icon in the top right and select Scan Receipt.
  4. +
  5. Upload a saved image of a receipt.
  6. +
+ +{% include end-option.html %} + +{% include option.html value="mobile" %} +
    +
  1. Open the mobile app and tap the camera icon in the bottom right corner.
  2. +
  3. Upload or take a photo of your receipt.
  4. +
      +
    • Upload a photo: Click the photo icon in the left corner and select the image from your device.
    • +
    • Take a photo: Click the camera icon in the right corner to select the mode, make sure all of the transaction details are clearly visible, and then take the photo.
    • +
    +
  5. Normal Mode: Upload one receipt.
  6. +
  7. Rapid Fire Mode: Upload multiple receipts at once.
  8. +
+{% include end-option.html %} +{% include end-selector.html %} + +You can open any receipt and select **Fill out details myself** to add or edit the merchant, date, total, description, category, or add attendees who took part in the expense. You can also check that the expense is correctly labeled as reimbursable or non-reimbursable, and split the expense if multiple expenses are included on one receipt. + +*Note: You can also email receipts to SmartScan by sending them to receipts@expensify.com from an email address tied to your Expensify account (either a primary or secondary email). SmartScan will automatically pull all of the details from the receipt, fill them in for you, and add the receipt to the Expenses tab on your account.* + +## Manually enter an expense + +{% include selector.html values="desktop, mobile" %} + +{% include option.html value="desktop" %} +
    +
  1. Click the Expenses tab.
  2. +
  3. Click the + icon in the top right.
  4. +
  5. Select the type of expense and enter the expense details.
  6. +
      +
    • Manually create: Manually enter receipt details.
    • +
    • Scan receipt: Upload a saved image of a receipt.
    • +
    • Create multiple: Upload expenses in bulk.
    • +
    • Time: Create an expense based on hours.
    • +
    • Distance: Create an expense based on distance.
    • +
        +
      • Manually Create: Manually enter the distance details for the expense.
      • +
      • Create from Map: Enter the start and end destination and Expensify will help you create a receipt for the trip.
      • +
      +
    +
  7. Click Save.
  8. +
+{% include end-option.html %} + +{% include option.html value="mobile" %} +
    +
  1. Tap the ☰ menu icon in the top left.
  2. +
  3. Tap Expenses.
  4. +
  5. Tap the + icon in the top right.
  6. +
  7. Tap the correct expense type and enter the expense details.
  8. +
      +
    • Manually create: Manually enter receipt details.
    • +
    • Time: Enter work time and rate.
    • +
    • Manually create (Distance): Manually enter trip details by total distance.
    • +
    • Odometer: Manually enter trip details by start and end odometer readings.
    • +
    • Start GPS: Track distance while using the Expensify app to automatically calculate the distance in real time during the trip.
    • +
    +
  9. Tap Save.
  10. +
+{% include end-option.html %} + +{% include end-selector.html %} + +# 5. Learn how to create & submit an expense report + +Once you’ve created your expenses, they may be automatically added to an expense report if your company has this feature enabled. If not, your next step will be to add your expenses to a report and submit them for payment. + +{% include selector.html values="Desktop, Mobile" %} + +{% include option.html value="desktop" %} + +
    +
  1. Click the Reports tab.
  2. +
      +
    • If a report has been automatically created for your most recently submitted expense, then you don’t have to do anything else—your report is already created and will also be automatically submitted.
    • +
    • If a report has not been automatically created, follow the steps below.
    • +
    +
  3. Click New Report, or click the New Report dropdown and select Expense Report.
  4. +
  5. Click Add Expenses.
  6. +
  7. Click an expense to add it to the report.
  8. +
      +
    • If an expense you already added does not appear in the list, use the filter on the left to search by the merchant name or change the date range. Note: Only expenses that are not already on a report will appear.
    • +
    +
  9. Once all your expenses are added to the report, click the X to close the pop-up.
  10. +
  11. (Optional) Make any desired changes to the report and/or expenses.
  12. +
      +
    • Click the Edit icon next to the report name to change it. If this icon is not visible, the option has been disabled by your workspace.
    • +
    • Click the X icon next to an expense to remove it from the report.
    • +
    • Click the Expense Details icon to review or edit the expense details.
    • +
    • At the bottom of the report, add comments to include more information.
    • +
    • Click the Attachments icon to add additional attachments.
    • +
    +
  13. When the report is ready to send for approval, click Submit.
  14. +
  15. Enter the details for who will receive a notification email about your report and what they will receive.
  16. +
      +
    • To: Enter the name(s) who will be approving your report (if they are not already listed).
    • +
    • CC: Enter the email address of anyone else who should be notified that your expense report has been submitted. Add a comma between each email address if adding more than one.
    • +
    • Memo: Enter any relevant notes.
    • +
    • Attach PDF: Select this checkbox to attach a copy of your report to the email.
    • +
    +
  17. Click Send.
  18. +
+ +{% include end-option.html %} + +{% include option.html value="mobile" %} +
    +
  1. Tap the ☰ menu icon in the top left.
  2. +
  3. Tap Reports.
  4. +
      +
    • If a report has been automatically created for your most recently submitted expense, then you don’t have to do anything else—your report is already created and will also be automatically submitted.
    • +
    • If a report has not been automatically created, follow the steps below.
    • +
    +
  5. Tap the + icon and tap Expense Report.
  6. +
  7. Tap Add Expenses, then tap an expense to add it to the report. Repeat this step until all desired expenses are added. Note: Only expenses that are not already on a report will appear.
  8. +
  9. (Optional) Make any desired changes to the report and/or expenses.
  10. +
      +
    • Tap the report name to change it.
    • +
    • Tap an expense to review or edit the expense details.
    • +
    • At the bottom of the report, add comments to include more information.
    • +
    • Tap the Attachments icon to add additional attachments.
    • +
    +
  11. When the report is ready to send for approval, tap Submit Report.
  12. +
  13. Add any additional sending details and tap Submit.
  14. +
  15. Enter the details for who will receive a notification email about your report and what they will receive.
  16. +
      +
    • To: Enter the name(s) who will be approving your report (if they are not already listed).
    • +
    • CC: Enter the email address of anyone else who should be notified that your expense report has been submitted. Add a comma between each email address if adding more than one.
    • +
    • Memo: Enter any relevant notes.
    • +
    • Attach PDF: Select this checkbox to attach a copy of your report to the email.
    • +
    +
  17. Tap Submit.
  18. + +
+{% include end-option.html %} + +{% include end-selector.html %} + +# 6. Add a secondary login + +Connect your personal email address as a secondary login so you always have access to your Expensify account, even if your employer changes. + +*Note: This process is currently not available from the mobile app and must be completed from the Expensify website.* + +
    +
  1. Hover over Settings, then click Account.
  2. +
  3. Under the Account Details tab, scroll down to the Secondary Logins section and click Add Secondary Login.
  4. +
  5. Enter the email address or phone number you wish to use as a secondary login. For phone numbers, be sure to include the international code, if applicable.
  6. +
  7. Find the email or text message from Expensify containing the Magic Code and enter it into the field to add the secondary login.
  8. +
+ +# 7. Secure your account + +Add an extra layer of security to help keep your financial data safe and secure by enabling two-factor authentication. This will require you to enter a code generated by your preferred authenticator app (like Google Authenticator or Microsoft Authenticator) when you log in. + +*Note: This process is currently not available from the mobile app and must be completed from the Expensify website.* + +
    +
  1. Hover over Settings, then click Account.
  2. +
  3. Under the Account Details tab, scroll down to the Two Factor Authentication section and enable the toggle.
  4. +
  5. Save a copy of your backup codes. This step is critical—You will lose access to your account if you cannot use your authenticator app and do not have your recovery codes.
  6. +
      +
    • Click Download to save a copy of your backup codes to your computer.
    • +
    • Click Copy to paste the codes into a document or other secure location.
    • +
    +
  7. Click Continue.
  8. +
  9. Download or open your authenticator app and either:
  10. +
      +
    • Scan the QR code shown on your computer screen.
    • +
    • Enter the 6-digit code from your authenticator app into Expensify and click Verify.
    • +
    +
+ +When you log in to Expensify in the future, you’ll open your authenticator app to get the code and enter it into Expensify. A new code regenerates every few seconds, so the code is always different. If the code time runs out, you can generate a new code as needed. + +
\ No newline at end of file From 30aa95641534dd317fe289bee8f7523c09fd5068 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 20:42:40 +0530 Subject: [PATCH 62/72] mobile styling --- docs/_sass/_main.scss | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss index 290a7ce25f80..666649b84d3d 100644 --- a/docs/_sass/_main.scss +++ b/docs/_sass/_main.scss @@ -471,6 +471,10 @@ button { * > ol, ul { padding: 0; } + + @include maxBreakpoint($breakpoint-tablet) { + flex-direction: column; + } } select { @@ -482,6 +486,11 @@ button { font-weight: 700; text-align: center; cursor: pointer; + + @include maxBreakpoint($breakpoint-tablet) { + width: 100px; + } + } select { From 37fde26a56071462c46219f3b5a1caa523fc6528 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 20:46:26 +0530 Subject: [PATCH 63/72] run prettier --- docs/assets/js/selector.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/assets/js/selector.js b/docs/assets/js/selector.js index 1292f50d1b32..9fa77afff2f4 100644 --- a/docs/assets/js/selector.js +++ b/docs/assets/js/selector.js @@ -18,7 +18,7 @@ function selectOption(s) { const selectedValue = s.options[s.selectedIndex].value; // Hide section that isn't selected, and show section that is selected. - allOptions.forEach(option => { + allOptions.forEach((option) => { if (option.value === selectedValue) { const toShow = document.getElementsByClassName(option.value); for (e of toShow) { @@ -26,7 +26,7 @@ function selectOption(s) { } return; } - + const toHide = document.getElementsByClassName(option.value); for (e of toHide) { e.classList.add('hidden'); From 896ca65a5725992be201a275596e467ad23793b6 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 20:49:00 +0530 Subject: [PATCH 64/72] cleanup --- docs/assets/js/selector.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/assets/js/selector.js b/docs/assets/js/selector.js index 9fa77afff2f4..a3ce49bcfc6e 100644 --- a/docs/assets/js/selector.js +++ b/docs/assets/js/selector.js @@ -1,8 +1,3 @@ -/** - * 1. The selector can have any name - * 2. The selector should be in sync in all pages - * 3. Minimal code in article - */ function selectOption(s) { if (!s) { return; From 1189848c0fa4c8101ecb689068c42a7023176d06 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 1 Feb 2024 21:15:24 +0530 Subject: [PATCH 65/72] fix lint --- docs/assets/js/selector.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/assets/js/selector.js b/docs/assets/js/selector.js index a3ce49bcfc6e..f045c59afb61 100644 --- a/docs/assets/js/selector.js +++ b/docs/assets/js/selector.js @@ -5,8 +5,8 @@ function selectOption(s) { // Keep all selects on the page in sync const allSelects = document.querySelectorAll('select'); - for (e of allSelects) { - e.selectedIndex = s.selectedIndex; + for (let i = 0; i < allSelects.length; i++) { + allSelects[i].selectedIndex = s.selectedIndex; } const allOptions = Array.from(s.options); @@ -16,15 +16,15 @@ function selectOption(s) { allOptions.forEach((option) => { if (option.value === selectedValue) { const toShow = document.getElementsByClassName(option.value); - for (e of toShow) { - e.classList.remove('hidden'); + for (let i = 0; i < toShow.length; i++) { + toShow[i].classList.remove('hidden'); } return; } const toHide = document.getElementsByClassName(option.value); - for (e of toHide) { - e.classList.add('hidden'); + for (let i = 0; i < toHide.length; i++) { + toHide[i].classList.add('hidden'); } }); } From 53e3ae8bc685cf29314872422732bada5f2e17bb Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 2 Feb 2024 10:28:33 +0700 Subject: [PATCH 66/72] revert hard code and rename variable --- ...oraryForRefactorRequestConfirmationList.js | 2 +- .../iou/request/step/IOURequestStepTag.js | 23 +++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 8dc9d3e419c0..122001861827 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -258,7 +258,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const shouldCalculateDistanceAmount = isDistanceRequest && iouAmount === 0; // A flag for showing the categories field - const shouldShowCategories = iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories)); + const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories))); // A flag and a toggler for showing the rest of the form fields const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); diff --git a/src/pages/iou/request/step/IOURequestStepTag.js b/src/pages/iou/request/step/IOURequestStepTag.js index e4390c5abbde..1297b98a0814 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.js +++ b/src/pages/iou/request/step/IOURequestStepTag.js @@ -56,7 +56,7 @@ function IOURequestStepTag({ const tagListKey = _.first(_.keys(policyTags)); const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); const isEditing = action === CONST.IOU.ACTION.EDIT; - const isBillSplit = iouType === CONST.IOU.TYPE.SPLIT; + const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const navigateBack = () => { Navigation.goBack(backTo || ROUTES.HOME); @@ -69,7 +69,7 @@ function IOURequestStepTag({ const updateTag = (selectedTag) => { const isSelectedTag = selectedTag.searchText === tag; const updatedTag = !isSelectedTag ? selectedTag.searchText : ''; - if (isBillSplit) { + if (isSplitBill) { IOU.setDraftSplitTransaction(transactionID, {tag: selectedTag.searchText}); navigateBack(); return; @@ -90,13 +90,18 @@ function IOURequestStepTag({ shouldShowWrapper testID={IOURequestStepTag.displayName} > - {translate('iou.tagSelection', {tagName: policyTagListName})} - + {({insets}) => ( + <> + {translate('iou.tagSelection', {tagName: policyTagListName})} + + + )} ); } From 1a4717aa879275223a0ff82630ef232bb5f424a7 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 2 Feb 2024 15:10:49 +0100 Subject: [PATCH 67/72] Fix type error in linkTo --- src/libs/Navigation/linkTo.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 3767e1ea010c..49dcee71eda4 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -216,16 +216,18 @@ export default function linkTo(navigation: NavigationContainerRef Date: Fri, 2 Feb 2024 22:48:18 +0530 Subject: [PATCH 68/72] improve readability --- docs/assets/js/selector.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/assets/js/selector.js b/docs/assets/js/selector.js index f045c59afb61..6cc94d266f01 100644 --- a/docs/assets/js/selector.js +++ b/docs/assets/js/selector.js @@ -1,16 +1,12 @@ -function selectOption(s) { - if (!s) { +function selectOption(select) { + if (!select) { return; } - // Keep all selects on the page in sync - const allSelects = document.querySelectorAll('select'); - for (let i = 0; i < allSelects.length; i++) { - allSelects[i].selectedIndex = s.selectedIndex; - } + syncSelectors(select.selectedIndex); - const allOptions = Array.from(s.options); - const selectedValue = s.options[s.selectedIndex].value; + const allOptions = Array.from(select.options); + const selectedValue = select.options[select.selectedIndex].value; // Hide section that isn't selected, and show section that is selected. allOptions.forEach((option) => { @@ -29,4 +25,11 @@ function selectOption(s) { }); } +function syncSelectors(selectedIndex) { + const allSelects = document.querySelectorAll('select'); + for (let i = 0; i < allSelects.length; i++) { + allSelects[i].selectedIndex = selectedIndex; + } +} + window.onload = selectOption(document.getElementsByClassName('selector')[0]); From db1c8a91cf8320e8f855052b6565047eeec9629f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Sat, 3 Feb 2024 01:03:47 +0530 Subject: [PATCH 69/72] fix lint --- docs/assets/js/selector.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/assets/js/selector.js b/docs/assets/js/selector.js index 6cc94d266f01..7373c7892767 100644 --- a/docs/assets/js/selector.js +++ b/docs/assets/js/selector.js @@ -1,3 +1,10 @@ +function syncSelectors(selectedIndex) { + const allSelects = document.querySelectorAll('select'); + for (let i = 0; i < allSelects.length; i++) { + allSelects[i].selectedIndex = selectedIndex; + } +} + function selectOption(select) { if (!select) { return; @@ -25,11 +32,4 @@ function selectOption(select) { }); } -function syncSelectors(selectedIndex) { - const allSelects = document.querySelectorAll('select'); - for (let i = 0; i < allSelects.length; i++) { - allSelects[i].selectedIndex = selectedIndex; - } -} - window.onload = selectOption(document.getElementsByClassName('selector')[0]); From d3f64c9c932c5ae6fdcb06ffd8a2722c4b67d28a Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 2 Feb 2024 21:18:16 +0100 Subject: [PATCH 70/72] Retry performance test From c90b7675cd6341c1515fa93364c120a0a719e59a Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Sun, 4 Feb 2024 11:47:45 +0100 Subject: [PATCH 71/72] Use keyForList in OptionsSelector's isSelected logic --- src/components/OptionsList/BaseOptionsList.tsx | 10 +--------- src/libs/OptionsListUtils.ts | 2 ++ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/components/OptionsList/BaseOptionsList.tsx b/src/components/OptionsList/BaseOptionsList.tsx index 1975c0f1a88e..6f265bfb8440 100644 --- a/src/components/OptionsList/BaseOptionsList.tsx +++ b/src/components/OptionsList/BaseOptionsList.tsx @@ -175,15 +175,7 @@ function BaseOptionsList( const renderItem: SectionListRenderItem = ({item, index, section}) => { const isItemDisabled = isDisabled || !!section.isDisabled || !!item.isDisabled; const isSelected = selectedOptions?.some((option) => { - if (option.accountID && option.accountID === item.accountID) { - return true; - } - - if (option.reportID && option.reportID === item.reportID) { - return true; - } - - if (option.policyID && option.policyID === item.policyID) { + if (option.keyForList && option.keyForList === item.keyForList) { return true; } diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 8cbe5bfa2d23..b6518b361381 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -66,6 +66,7 @@ type PayeePersonalDetails = { descriptiveText: string; login: string; accountID: number; + keyForList: string; }; type CategorySection = { @@ -1737,6 +1738,7 @@ function getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetail: Person descriptiveText: amountText, login: personalDetail.login ?? '', accountID: personalDetail.accountID, + keyForList: String(personalDetail.accountID), }; } From 0251342e888a9dc1e5c9da73fa63200c590b44de Mon Sep 17 00:00:00 2001 From: OSBotify Date: Mon, 5 Feb 2024 10:45:36 +0000 Subject: [PATCH 72/72] Update version to 1.4.36-1 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index a53c6dfb62af..829f980431a4 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001043600 - versionName "1.4.36-0" + versionCode 1001043601 + versionName "1.4.36-1" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 6a6a54e58c49..d4ee691ab6da 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.36.0 + 1.4.36.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 763896fd45f1..b40af313f3e5 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.36.0 + 1.4.36.1 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index a4bef0847c95..b5da9f0caaa4 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.36 CFBundleVersion - 1.4.36.0 + 1.4.36.1 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 674325508da5..e9ba0d44e663 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.36-0", + "version": "1.4.36-1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.36-0", + "version": "1.4.36-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 0c1105f978c6..68c815ad328a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.36-0", + "version": "1.4.36-1", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",