From 2f4d561ffbedd7ed4273baa30c109814f99fcf99 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Sun, 5 May 2024 04:32:26 +0530 Subject: [PATCH 001/482] fix: [Violations] Distance - Incorrect error message when distance amount is changed to smaller amount. Signed-off-by: Krishna Gupta --- src/CONST.ts | 4 ++-- src/components/ReceiptAudit.tsx | 13 ++++++++++--- .../ReportActionItem/MoneyRequestView.tsx | 11 ++++++----- src/hooks/useViolations.ts | 16 +++++++++++----- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 566d5179f86a..e0dd65fb2ef1 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3619,9 +3619,9 @@ const CONST = { SMARTSCAN_FAILED: 'smartscanFailed', SOME_TAG_LEVELS_REQUIRED: 'someTagLevelsRequired', TAG_OUT_OF_POLICY: 'tagOutOfPolicy', - TAX_AMOUNT_CHANGED: 'taxAmountChanged', + // TAX_AMOUNT_CHANGED: 'taxAmountChanged', + // TAX_RATE_CHANGED: 'taxRateChanged', TAX_OUT_OF_POLICY: 'taxOutOfPolicy', - TAX_RATE_CHANGED: 'taxRateChanged', TAX_REQUIRED: 'taxRequired', }, diff --git a/src/components/ReceiptAudit.tsx b/src/components/ReceiptAudit.tsx index ac1b36c6bf32..2adf3c2601d5 100644 --- a/src/components/ReceiptAudit.tsx +++ b/src/components/ReceiptAudit.tsx @@ -7,17 +7,24 @@ import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import Text from './Text'; -function ReceiptAuditHeader({notes, shouldShowAuditMessage}: {notes: string[]; shouldShowAuditMessage: boolean}) { +function ReceiptAuditHeader({notes, shouldShowAuditSuccess, shouldShowAuditFailure}: {notes: string[]; shouldShowAuditSuccess?: boolean; shouldShowAuditFailure?: boolean}) { const styles = useThemeStyles(); const theme = useTheme(); const {translate} = useLocalize(); - const auditText = notes.length > 0 ? translate('iou.receiptIssuesFound', notes.length) : translate('common.verified'); + let auditText = ''; + + if (notes.length > 0 && shouldShowAuditFailure) { + auditText = translate('iou.receiptIssuesFound', notes.length); + } else if (!notes.length && shouldShowAuditSuccess) { + auditText = translate('common.verified'); + } + return ( {translate('common.receipt')} - {shouldShowAuditMessage && ( + {auditText && ( <> {` • ${auditText}`} !!canUseViolations && getViolationsForField(field, data).length > 0, [canUseViolations, getViolationsForField], @@ -330,7 +330,7 @@ function MoneyRequestView({ const shouldShowMapOrReceipt = showMapAsImage || hasReceipt; const shouldShowReceiptEmptyState = !hasReceipt && !isInvoice && (canEditReceipt || isAdmin || isApprover); const noticeTypeViolations = transactionViolations?.filter((violation) => violation.type === 'notice').map((v) => ViolationsUtils.getViolationTranslation(v, translate)) ?? []; - const shouldShowNotesViolations = !isReceiptBeingScanned && canUseViolations && ReportUtils.isPaidGroupPolicy(report); + const shouldShowAuditMessage = !isReceiptBeingScanned && canUseViolations && ReportUtils.isPaidGroupPolicy(report); return ( @@ -339,7 +339,8 @@ function MoneyRequestView({ {!isInvoice && ( )} {shouldShowMapOrReceipt && ( @@ -393,7 +394,7 @@ function MoneyRequestView({ /> )} {!shouldShowReceiptEmptyState && !shouldShowMapOrReceipt && } - {shouldShowNotesViolations && } + {/* {shouldShowNotesViolations && } */} {canUseViolations && } = { smartscanFailed: 'receipt', someTagLevelsRequired: 'tag', tagOutOfPolicy: 'tag', - taxAmountChanged: 'tax', + // taxAmountChanged: 'tax', + // taxRateChanged: 'tax', taxOutOfPolicy: 'tax', - taxRateChanged: 'tax', taxRequired: 'tax', }; type ViolationsMap = Map; -function useViolations(violations: TransactionViolation[]) { +function useViolations(violations: TransactionViolation[], shouldIncludeNoticeViolations?: boolean) { const violationsByField = useMemo((): ViolationsMap => { - const filteredViolations = violations.filter((violation) => violation.type === CONST.VIOLATION_TYPES.VIOLATION); + const filteredViolations = violations.filter((violation) => { + if (!shouldIncludeNoticeViolations) { + return violation.type === CONST.VIOLATION_TYPES.VIOLATION; + } + return violation.type === CONST.VIOLATION_TYPES.VIOLATION || violation.type === CONST.VIOLATION_TYPES.NOTICE; + }); + const violationGroups = new Map(); for (const violation of filteredViolations) { const field = violationFields[violation.name]; @@ -58,7 +64,7 @@ function useViolations(violations: TransactionViolation[]) { violationGroups.set(field, [...existingViolations, violation]); } return violationGroups ?? new Map(); - }, [violations]); + }, [violations, shouldIncludeNoticeViolations]); const getViolationsForField = useCallback( (field: ViolationField, data?: TransactionViolation['data']) => { From bac54f14cff9ca95447ea7c4ac5aa17b5925721a Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Sun, 5 May 2024 04:41:51 +0530 Subject: [PATCH 002/482] remove tax rate changed violation. Signed-off-by: Krishna Gupta --- src/CONST.ts | 3 +-- src/hooks/useViolations.ts | 3 +-- src/libs/Violations/ViolationsUtils.ts | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index e0dd65fb2ef1..97a7c551da5a 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3619,8 +3619,7 @@ const CONST = { SMARTSCAN_FAILED: 'smartscanFailed', SOME_TAG_LEVELS_REQUIRED: 'someTagLevelsRequired', TAG_OUT_OF_POLICY: 'tagOutOfPolicy', - // TAX_AMOUNT_CHANGED: 'taxAmountChanged', - // TAX_RATE_CHANGED: 'taxRateChanged', + TAX_AMOUNT_CHANGED: 'taxAmountChanged', TAX_OUT_OF_POLICY: 'taxOutOfPolicy', TAX_REQUIRED: 'taxRequired', }, diff --git a/src/hooks/useViolations.ts b/src/hooks/useViolations.ts index bf2e8315194a..125a38e48220 100644 --- a/src/hooks/useViolations.ts +++ b/src/hooks/useViolations.ts @@ -40,8 +40,7 @@ const violationFields: Record = { smartscanFailed: 'receipt', someTagLevelsRequired: 'tag', tagOutOfPolicy: 'tag', - // taxAmountChanged: 'tax', - // taxRateChanged: 'tax', + taxAmountChanged: 'tax', taxOutOfPolicy: 'tax', taxRequired: 'tax', }; diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index 42f58be1d699..5e38d213edaa 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -276,8 +276,6 @@ const ViolationsUtils = { return translate('violations.taxAmountChanged'); case 'taxOutOfPolicy': return translate('violations.taxOutOfPolicy', {taxName}); - case 'taxRateChanged': - return translate('violations.taxRateChanged'); case 'taxRequired': return translate('violations.taxRequired'); default: From d3994531be44330e015fd1d43c628b8f0ba0643f Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Sun, 5 May 2024 04:43:44 +0530 Subject: [PATCH 003/482] remove ReceiptAuditHeader. Signed-off-by: Krishna Gupta --- src/components/ReceiptAudit.tsx | 9 ++------- src/components/ReportActionItem/MoneyRequestView.tsx | 5 ++--- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/components/ReceiptAudit.tsx b/src/components/ReceiptAudit.tsx index 2adf3c2601d5..a5ccf543e0b7 100644 --- a/src/components/ReceiptAudit.tsx +++ b/src/components/ReceiptAudit.tsx @@ -7,7 +7,7 @@ import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import Text from './Text'; -function ReceiptAuditHeader({notes, shouldShowAuditSuccess, shouldShowAuditFailure}: {notes: string[]; shouldShowAuditSuccess?: boolean; shouldShowAuditFailure?: boolean}) { +function ReceiptAudit({notes, shouldShowAuditSuccess, shouldShowAuditFailure}: {notes: string[]; shouldShowAuditSuccess?: boolean; shouldShowAuditFailure?: boolean}) { const styles = useThemeStyles(); const theme = useTheme(); const {translate} = useLocalize(); @@ -41,9 +41,4 @@ function ReceiptAuditHeader({notes, shouldShowAuditSuccess, shouldShowAuditFailu ); } -function ReceiptAuditMessages({notes = []}: {notes?: string[]}) { - const styles = useThemeStyles(); - return {notes.length > 0 && notes.map((message) => {message})}; -} - -export {ReceiptAuditHeader, ReceiptAuditMessages}; +export default ReceiptAudit; diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 0f9ffc2d2485..2b91b41e8cdc 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -7,7 +7,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {useSession} from '@components/OnyxProvider'; -import {ReceiptAuditHeader} from '@components/ReceiptAudit'; +import ReceiptAudit from '@components/ReceiptAudit'; import ReceiptEmptyState from '@components/ReceiptEmptyState'; import Switch from '@components/Switch'; import Text from '@components/Text'; @@ -337,7 +337,7 @@ function MoneyRequestView({ {shouldShowAnimatedBackground && } {!isInvoice && ( - )} {!shouldShowReceiptEmptyState && !shouldShowMapOrReceipt && } - {/* {shouldShowNotesViolations && } */} {canUseViolations && } Date: Fri, 10 May 2024 15:28:23 +0530 Subject: [PATCH 004/482] updated amountModified translation. Signed-off-by: Krishna Gupta --- src/CONST.ts | 1 + src/hooks/useViolations.ts | 4 ++++ src/languages/en.ts | 15 ++++++++++++++- src/languages/es.ts | 15 ++++++++++++++- src/languages/types.ts | 3 +++ src/libs/Violations/ViolationsUtils.ts | 2 +- 6 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index ce8e0dc8aeca..efb0463457b1 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3651,6 +3651,7 @@ const CONST = { TAG_OUT_OF_POLICY: 'tagOutOfPolicy', TAX_AMOUNT_CHANGED: 'taxAmountChanged', TAX_OUT_OF_POLICY: 'taxOutOfPolicy', + TAX_RATE_CHANGED: 'taxRateChanged', TAX_REQUIRED: 'taxRequired', }, diff --git a/src/hooks/useViolations.ts b/src/hooks/useViolations.ts index 125a38e48220..4f35c6d27a73 100644 --- a/src/hooks/useViolations.ts +++ b/src/hooks/useViolations.ts @@ -40,6 +40,7 @@ const violationFields: Record = { smartscanFailed: 'receipt', someTagLevelsRequired: 'tag', tagOutOfPolicy: 'tag', + taxRateChanged: 'tax', taxAmountChanged: 'tax', taxOutOfPolicy: 'tax', taxRequired: 'tax', @@ -50,6 +51,9 @@ type ViolationsMap = Map; function useViolations(violations: TransactionViolation[], shouldIncludeNoticeViolations?: boolean) { const violationsByField = useMemo((): ViolationsMap => { const filteredViolations = violations.filter((violation) => { + if (violation.name === 'taxRateChanged' || violation.name === 'taxAmountChanged') { + return false; + } if (!shouldIncludeNoticeViolations) { return violation.type === CONST.VIOLATION_TYPES.VIOLATION; } diff --git a/src/languages/en.ts b/src/languages/en.ts index 75ef134a6175..7faa4ed1804c 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -88,6 +88,7 @@ import type { ViolationsInvoiceMarkupParams, ViolationsMaxAgeParams, ViolationsMissingTagParams, + ViolationsModifiedAmountParams, ViolationsOverCategoryLimitParams, ViolationsOverLimitParams, ViolationsPerDayLimitParams, @@ -2959,7 +2960,19 @@ export default { missingCategory: 'Missing category', missingComment: 'Description required for selected category', missingTag: ({tagName}: ViolationsMissingTagParams) => `Missing ${tagName ?? 'tag'}`, - modifiedAmount: 'Amount greater than scanned receipt', + modifiedAmount: ({type, displayPercentVariance}: ViolationsModifiedAmountParams): string => { + if (type === 'card' && displayPercentVariance) { + return `Amount ${displayPercentVariance}% greater than scanned receipt`; + } + switch (type) { + case 'distance': + return 'Amount differs from calculated distance'; + case 'card': + return 'Amount greater than card transaction'; + default: + return 'Amount greater than scanned receipt'; + } + }, modifiedDate: 'Date differs from scanned receipt', nonExpensiworksExpense: 'Non-Expensiworks expense', overAutoApprovalLimit: ({formattedLimit}: ViolationsOverLimitParams) => `Expense exceeds auto approval limit of ${formattedLimit}`, diff --git a/src/languages/es.ts b/src/languages/es.ts index 55203ef32749..041160f9e0e5 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -86,6 +86,7 @@ import type { ViolationsInvoiceMarkupParams, ViolationsMaxAgeParams, ViolationsMissingTagParams, + ViolationsModifiedAmountParams, ViolationsOverAutoApprovalLimitParams, ViolationsOverCategoryLimitParams, ViolationsOverLimitParams, @@ -3460,7 +3461,19 @@ export default { missingCategory: 'Falta categoría', missingComment: 'Descripción obligatoria para la categoría seleccionada', missingTag: ({tagName}: ViolationsMissingTagParams) => `Falta ${tagName ?? 'etiqueta'}`, - modifiedAmount: 'Importe superior al del recibo escaneado', + modifiedAmount: ({type, displayPercentVariance}: ViolationsModifiedAmountParams) => { + if (type === 'card' && displayPercentVariance) { + return `Importe ${displayPercentVariance}% mayor al del recibo escaneado`; + } + switch (type) { + case 'distance': + return 'Importe difiere del calculado basado en distancia'; + case 'card': + return 'Importe mayor al de la transacción de la tarjeta'; + default: + return 'Importe mayor al del recibo escaneado'; + } + }, modifiedDate: 'Fecha difiere del recibo escaneado', nonExpensiworksExpense: 'Gasto no proviene de Expensiworks', overAutoApprovalLimit: ({formattedLimit}: ViolationsOverAutoApprovalLimitParams) => diff --git a/src/languages/types.ts b/src/languages/types.ts index e2e7e26e696b..665857c2efa5 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -222,6 +222,8 @@ type ViolationsMaxAgeParams = {maxAge: number}; type ViolationsMissingTagParams = {tagName?: string}; +type ViolationsModifiedAmountParams = {type: string; displayPercentVariance?: string}; + type ViolationsOverAutoApprovalLimitParams = {formattedLimit?: string}; type ViolationsOverCategoryLimitParams = {formattedLimit?: string}; @@ -382,6 +384,7 @@ export type { ViolationsInvoiceMarkupParams, ViolationsMaxAgeParams, ViolationsMissingTagParams, + ViolationsModifiedAmountParams, ViolationsOverAutoApprovalLimitParams, ViolationsOverCategoryLimitParams, ViolationsOverLimitParams, diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index 5e38d213edaa..c864747847d4 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -239,7 +239,7 @@ const ViolationsUtils = { case 'missingTag': return translate('violations.missingTag', {tagName}); case 'modifiedAmount': - return translate('violations.modifiedAmount'); + return translate('violations.modifiedAmount', {type: 'card'}); case 'modifiedDate': return translate('violations.modifiedDate'); case 'nonExpensiworksExpense': From 0549056529c2a89b7f765167eac237e107bf082b Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Fri, 10 May 2024 15:30:51 +0530 Subject: [PATCH 005/482] minor update. Signed-off-by: Krishna Gupta --- src/languages/en.ts | 6 +++--- src/languages/es.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 7faa4ed1804c..57082f98799e 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2961,13 +2961,13 @@ export default { missingComment: 'Description required for selected category', missingTag: ({tagName}: ViolationsMissingTagParams) => `Missing ${tagName ?? 'tag'}`, modifiedAmount: ({type, displayPercentVariance}: ViolationsModifiedAmountParams): string => { - if (type === 'card' && displayPercentVariance) { - return `Amount ${displayPercentVariance}% greater than scanned receipt`; - } switch (type) { case 'distance': return 'Amount differs from calculated distance'; case 'card': + if (displayPercentVariance) { + return `Amount ${displayPercentVariance}% greater than scanned receipt`; + } return 'Amount greater than card transaction'; default: return 'Amount greater than scanned receipt'; diff --git a/src/languages/es.ts b/src/languages/es.ts index 041160f9e0e5..1eee82369f1a 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3462,13 +3462,13 @@ export default { missingComment: 'Descripción obligatoria para la categoría seleccionada', missingTag: ({tagName}: ViolationsMissingTagParams) => `Falta ${tagName ?? 'etiqueta'}`, modifiedAmount: ({type, displayPercentVariance}: ViolationsModifiedAmountParams) => { - if (type === 'card' && displayPercentVariance) { - return `Importe ${displayPercentVariance}% mayor al del recibo escaneado`; - } switch (type) { case 'distance': return 'Importe difiere del calculado basado en distancia'; case 'card': + if (displayPercentVariance) { + return `Importe ${displayPercentVariance}% mayor al del recibo escaneado`; + } return 'Importe mayor al de la transacción de la tarjeta'; default: return 'Importe mayor al del recibo escaneado'; From f0390382c4788a3b1754caf32c28bd21d03bcab8 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Fri, 17 May 2024 13:43:59 +0530 Subject: [PATCH 006/482] remove taxAmountChanged & taxRateChanged notice violations. Signed-off-by: Krishna Gupta --- src/hooks/useViolations.ts | 5 ++++- src/languages/types.ts | 2 +- src/libs/Violations/ViolationsUtils.ts | 4 +++- src/types/onyx/TransactionViolation.ts | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/hooks/useViolations.ts b/src/hooks/useViolations.ts index 4f35c6d27a73..f5e53a06fb10 100644 --- a/src/hooks/useViolations.ts +++ b/src/hooks/useViolations.ts @@ -48,10 +48,13 @@ const violationFields: Record = { type ViolationsMap = Map; +// We don't want to show these violations on NewDot +const excludedViolationsName = ['taxAmountChanged', 'taxRateChanged']; + function useViolations(violations: TransactionViolation[], shouldIncludeNoticeViolations?: boolean) { const violationsByField = useMemo((): ViolationsMap => { const filteredViolations = violations.filter((violation) => { - if (violation.name === 'taxRateChanged' || violation.name === 'taxAmountChanged') { + if (excludedViolationsName.includes(violation.name)) { return false; } if (!shouldIncludeNoticeViolations) { diff --git a/src/languages/types.ts b/src/languages/types.ts index 665857c2efa5..c95e1043930d 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -222,7 +222,7 @@ type ViolationsMaxAgeParams = {maxAge: number}; type ViolationsMissingTagParams = {tagName?: string}; -type ViolationsModifiedAmountParams = {type: string; displayPercentVariance?: string}; +type ViolationsModifiedAmountParams = {type: string; displayPercentVariance?: number}; type ViolationsOverAutoApprovalLimitParams = {formattedLimit?: string}; diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index c864747847d4..edb351e8e155 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -239,7 +239,7 @@ const ViolationsUtils = { case 'missingTag': return translate('violations.missingTag', {tagName}); case 'modifiedAmount': - return translate('violations.modifiedAmount', {type: 'card'}); + return translate('violations.modifiedAmount', {type: violation.type, displayPercentVariance: violation.displayPercentVariance}); case 'modifiedDate': return translate('violations.modifiedDate'); case 'nonExpensiworksExpense': @@ -276,6 +276,8 @@ const ViolationsUtils = { return translate('violations.taxAmountChanged'); case 'taxOutOfPolicy': return translate('violations.taxOutOfPolicy', {taxName}); + case 'taxRateChanged': + return translate('violations.taxRateChanged'); case 'taxRequired': return translate('violations.taxRequired'); default: diff --git a/src/types/onyx/TransactionViolation.ts b/src/types/onyx/TransactionViolation.ts index ab2037ff336a..edb08b798683 100644 --- a/src/types/onyx/TransactionViolation.ts +++ b/src/types/onyx/TransactionViolation.ts @@ -31,6 +31,7 @@ type TransactionViolation = { errorIndexes?: number[]; pendingPattern?: boolean; }; + displayPercentVariance?: number; }; type TransactionViolations = TransactionViolation[]; From be4f9be6cf63214d701cb623463f2ef8ece6005e Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Mon, 3 Jun 2024 02:26:35 +0530 Subject: [PATCH 007/482] fix conflicts. Signed-off-by: Krishna Gupta --- .../ReportActionItem/MoneyRequestView.tsx | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 7f47b504b481..f01fb049e943 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -7,7 +7,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {useSession} from '@components/OnyxProvider'; -import ReceiptAudit from '@components/ReceiptAudit'; +import {ReceiptAuditHeader, ReceiptAuditMessages} from '@components/ReceiptAudit'; import ReceiptEmptyState from '@components/ReceiptEmptyState'; import Switch from '@components/Switch'; import Text from '@components/Text'; @@ -15,12 +15,10 @@ import ViolationMessages from '@components/ViolationMessages'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; 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 * as CurrencyUtils from '@libs/CurrencyUtils'; import type {MileageRate} from '@libs/DistanceRequestUtils'; @@ -29,6 +27,7 @@ import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import {isTaxTrackingEnabled} from '@libs/PolicyUtils'; 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 ViolationsUtils from '@libs/Violations/ViolationsUtils'; @@ -97,9 +96,7 @@ function MoneyRequestView({ const theme = useTheme(); const styles = useThemeStyles(); const session = useSession(); - const StyleUtils = useStyleUtils(); const {isOffline} = useNetwork(); - const {isSmallScreenWidth} = useWindowDimensions(); const {translate, toLocaleDigit} = useLocalize(); const parentReportAction = parentReportActions?.[report.parentReportActionID ?? ''] ?? null; const isTrackExpense = ReportUtils.isTrackExpenseReport(report); @@ -129,6 +126,7 @@ function MoneyRequestView({ const cardProgramName = isCardTransaction && transactionCardID !== undefined ? CardUtils.getCardDescription(transactionCardID) : ''; const isApproved = ReportUtils.isReportApproved(moneyRequestReport); const isInvoice = ReportUtils.isInvoiceReport(moneyRequestReport); + const isPaidReport = ReportActionsUtils.isPayAction(parentReportAction); const taxRates = policy?.taxRates; const formattedTaxAmount = CurrencyUtils.convertToDisplayString(transactionTaxAmount, transactionCurrency); @@ -141,6 +139,8 @@ function MoneyRequestView({ // Used for non-restricted fields such as: description, category, tag, billable, etc. const canEdit = ReportUtils.canEditMoneyRequest(parentReportAction); + const canEditTaxFields = canEdit && !isDistanceRequest; + const canEditAmount = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.AMOUNT); const canEditMerchant = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.MERCHANT); const canEditDate = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.DATE); @@ -148,8 +148,7 @@ function MoneyRequestView({ const hasReceipt = TransactionUtils.hasReceipt(transaction); const isReceiptBeingScanned = hasReceipt && TransactionUtils.isReceiptBeingScanned(transaction); const didRceiptScanSucceed = hasReceipt && TransactionUtils.didRceiptScanSucceed(transaction); - // TODO: remove the !isTrackExpense from this condition after this fix: https://github.com/Expensify/Expensify/issues/382786 - const canEditDistance = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.DISTANCE) && !isTrackExpense; + const canEditDistance = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.DISTANCE); const isAdmin = policy?.role === 'admin'; const isApprover = ReportUtils.isMoneyRequestReport(moneyRequestReport) && moneyRequestReport?.managerID !== null && session?.accountID === moneyRequestReport?.managerID; @@ -170,10 +169,9 @@ function MoneyRequestView({ const shouldShowTag = isPolicyExpenseChat && (transactionTag || OptionsListUtils.hasEnabledTags(policyTagLists)); const shouldShowBillable = isPolicyExpenseChat && (!!transactionBillable || !(policy?.disabledFields?.defaultBillable ?? true)); - // A flag for showing tax rate - const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat, policy); + const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat, policy, isDistanceRequest); - const {getViolationsForField} = useViolations(transactionViolations ?? [], !isReceiptBeingScanned && ReportUtils.isPaidGroupPolicy(report)); + const {getViolationsForField} = useViolations(transactionViolations ?? []); const hasViolations = useCallback( (field: ViolationField, data?: OnyxTypes.TransactionViolation['data']): boolean => !!canUseViolations && getViolationsForField(field, data).length > 0, [canUseViolations, getViolationsForField], @@ -318,19 +316,29 @@ function MoneyRequestView({ ); const shouldShowMapOrReceipt = showMapAsImage || hasReceipt; - const shouldShowReceiptEmptyState = !hasReceipt && !isInvoice && (canEditReceipt || isAdmin || isApprover); - const noticeTypeViolations = transactionViolations?.filter((violation) => violation.type === 'notice').map((v) => ViolationsUtils.getViolationTranslation(v, translate)) ?? []; - const shouldShowAuditMessage = !isReceiptBeingScanned && canUseViolations && ReportUtils.isPaidGroupPolicy(report); + const isReceiptAllowed = !isPaidReport && !isInvoice; + const shouldShowReceiptEmptyState = + isReceiptAllowed && !hasReceipt && !isApproved && !isSettled && (canEditReceipt || isAdmin || isApprover) && (canEditReceipt || ReportUtils.isPaidGroupPolicy(report)); + const receiptViolationNames: OnyxTypes.ViolationName[] = [ + CONST.VIOLATIONS.RECEIPT_REQUIRED, + CONST.VIOLATIONS.RECEIPT_NOT_SMART_SCANNED, + CONST.VIOLATIONS.MODIFIED_DATE, + CONST.VIOLATIONS.CASH_EXPENSE_WITH_NO_RECEIPT, + CONST.VIOLATIONS.SMARTSCAN_FAILED, + ]; + const receiptViolations = + transactionViolations?.filter((violation) => receiptViolationNames.includes(violation.name)).map((violation) => ViolationsUtils.getViolationTranslation(violation, translate)) ?? []; + const shouldShowNotesViolations = !isReceiptBeingScanned && canUseViolations && ReportUtils.isPaidGroupPolicy(report); + const shouldShowReceiptHeader = isReceiptAllowed && (shouldShowReceiptEmptyState || shouldShowMapOrReceipt) && canUseViolations && ReportUtils.isPaidGroupPolicy(report); return ( - + {shouldShowAnimatedBackground && } - - {!isInvoice && ( - + {shouldShowReceiptHeader && ( + )} {shouldShowMapOrReceipt && ( @@ -384,7 +392,7 @@ function MoneyRequestView({ /> )} {!shouldShowReceiptEmptyState && !shouldShowMapOrReceipt && } - {canUseViolations && } + {shouldShowNotesViolations && } Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '', report.reportID)) } + wrapperStyle={[styles.taskDescriptionMenuItem]} brickRoadIndicator={getErrorForField('merchant') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} errorText={getErrorForField('merchant')} + numberOfLinesTitle={0} /> )} @@ -504,8 +514,8 @@ function MoneyRequestView({ Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_RATE.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '', report.reportID)) @@ -521,8 +531,8 @@ function MoneyRequestView({ Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '', report.reportID)) @@ -551,7 +561,7 @@ function MoneyRequestView({ /> )} - + ); } From c9fd9aaff77b11e6f72ee14ad1472955b810fdbd Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Mon, 3 Jun 2024 02:29:07 +0530 Subject: [PATCH 008/482] fix conflicts. Signed-off-by: Krishna Gupta --- src/components/ReportActionItem/MoneyRequestView.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index f01fb049e943..014fd3c97096 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -7,7 +7,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {useSession} from '@components/OnyxProvider'; -import {ReceiptAuditHeader, ReceiptAuditMessages} from '@components/ReceiptAudit'; +import ReceiptAudit from '@components/ReceiptAudit'; import ReceiptEmptyState from '@components/ReceiptEmptyState'; import Switch from '@components/Switch'; import Text from '@components/Text'; @@ -171,7 +171,7 @@ function MoneyRequestView({ const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat, policy, isDistanceRequest); - const {getViolationsForField} = useViolations(transactionViolations ?? []); + const {getViolationsForField} = useViolations(transactionViolations ?? [], !isReceiptBeingScanned && ReportUtils.isPaidGroupPolicy(report)); const hasViolations = useCallback( (field: ViolationField, data?: OnyxTypes.TransactionViolation['data']): boolean => !!canUseViolations && getViolationsForField(field, data).length > 0, [canUseViolations, getViolationsForField], @@ -328,7 +328,7 @@ function MoneyRequestView({ ]; const receiptViolations = transactionViolations?.filter((violation) => receiptViolationNames.includes(violation.name)).map((violation) => ViolationsUtils.getViolationTranslation(violation, translate)) ?? []; - const shouldShowNotesViolations = !isReceiptBeingScanned && canUseViolations && ReportUtils.isPaidGroupPolicy(report); + const shouldShowAuditMessage = !isReceiptBeingScanned && canUseViolations && ReportUtils.isPaidGroupPolicy(report); const shouldShowReceiptHeader = isReceiptAllowed && (shouldShowReceiptEmptyState || shouldShowMapOrReceipt) && canUseViolations && ReportUtils.isPaidGroupPolicy(report); return ( @@ -336,9 +336,10 @@ function MoneyRequestView({ {shouldShowAnimatedBackground && } <> {shouldShowReceiptHeader && ( - )} {shouldShowMapOrReceipt && ( @@ -392,7 +393,6 @@ function MoneyRequestView({ /> )} {!shouldShowReceiptEmptyState && !shouldShowMapOrReceipt && } - {shouldShowNotesViolations && } Date: Thu, 6 Jun 2024 09:52:39 +0530 Subject: [PATCH 009/482] use violation data type from backend. Signed-off-by: Krishna Gupta --- src/CONST.ts | 9 +++++++++ src/languages/types.ts | 3 ++- src/libs/Violations/ViolationsUtils.ts | 3 ++- src/types/onyx/TransactionViolation.ts | 4 +++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index a4c330b36cc6..a4fc07751c87 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3656,6 +3656,15 @@ const CONST = { WARNING: 'warning', }, + /** + * Constants for types of violation data. + */ + VIOLATION_DATA_TYPES: { + DISTANCE: 'distance', + CARD: 'card', + SMARTSCAN: 'smartscan', + }, + /** * Constants for types of violation names. * Defined here because they need to be referenced by the type system to generate the diff --git a/src/languages/types.ts b/src/languages/types.ts index c95e1043930d..7555fceba611 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -1,5 +1,6 @@ import type {ReportAction} from '@src/types/onyx'; import type {Unit} from '@src/types/onyx/Policy'; +import type {ViolationDataType} from '@src/types/onyx/TransactionViolation'; import type en from './en'; type AddressLineParams = { @@ -222,7 +223,7 @@ type ViolationsMaxAgeParams = {maxAge: number}; type ViolationsMissingTagParams = {tagName?: string}; -type ViolationsModifiedAmountParams = {type: string; displayPercentVariance?: number}; +type ViolationsModifiedAmountParams = {type?: ViolationDataType; displayPercentVariance?: number}; type ViolationsOverAutoApprovalLimitParams = {formattedLimit?: string}; diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index 13e6b52f56b4..9fc9ae93879b 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -202,6 +202,7 @@ const ViolationsUtils = { maxAge = 0, tagName, taxName, + type, } = violation.data ?? {}; switch (violation.name) { @@ -239,7 +240,7 @@ const ViolationsUtils = { case 'missingTag': return translate('violations.missingTag', {tagName}); case 'modifiedAmount': - return translate('violations.modifiedAmount', {type: violation.type, displayPercentVariance: violation.displayPercentVariance}); + return translate('violations.modifiedAmount', {type, displayPercentVariance: violation.displayPercentVariance}); case 'modifiedDate': return translate('violations.modifiedDate'); case 'nonExpensiworksExpense': diff --git a/src/types/onyx/TransactionViolation.ts b/src/types/onyx/TransactionViolation.ts index edb08b798683..6b905c17067a 100644 --- a/src/types/onyx/TransactionViolation.ts +++ b/src/types/onyx/TransactionViolation.ts @@ -5,6 +5,7 @@ import type CONST from '@src/CONST'; * Derived from `CONST.VIOLATIONS` to maintain a single source of truth. */ type ViolationName = (typeof CONST.VIOLATIONS)[keyof typeof CONST.VIOLATIONS]; +type ViolationDataType = (typeof CONST.VIOLATION_DATA_TYPES)[keyof typeof CONST.VIOLATION_DATA_TYPES]; type TransactionViolation = { type: string; @@ -30,11 +31,12 @@ type TransactionViolation = { tagListName?: string; errorIndexes?: number[]; pendingPattern?: boolean; + type?: ViolationDataType; }; displayPercentVariance?: number; }; type TransactionViolations = TransactionViolation[]; -export type {TransactionViolation, ViolationName}; +export type {TransactionViolation, ViolationName, ViolationDataType}; export default TransactionViolations; From cc7cf3827a2b4a7d5ff566639e3beee63358f75b Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 6 Jun 2024 18:49:06 +0700 Subject: [PATCH 010/482] fix: 42117 --- src/components/MoneyRequestAmountInput.tsx | 2 ++ .../MoneyRequestConfirmationList.tsx | 6 ++-- .../TextInput/BaseTextInput/index.native.tsx | 35 +++++++++++++++++-- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/components/MoneyRequestAmountInput.tsx b/src/components/MoneyRequestAmountInput.tsx index 1cccfdc720b3..a6c1689cb726 100644 --- a/src/components/MoneyRequestAmountInput.tsx +++ b/src/components/MoneyRequestAmountInput.tsx @@ -121,6 +121,7 @@ function MoneyRequestAmountInput( hideFocusedState = true, shouldKeepUserInput = false, autoGrow = true, + contentWidth = undefined, ...props }: MoneyRequestAmountInputProps, forwardedRef: ForwardedRef, @@ -315,6 +316,7 @@ function MoneyRequestAmountInput( hideFocusedState={hideFocusedState} onMouseDown={handleMouseDown} onMouseUp={handleMouseUp} + contentWidth={contentWidth} /> ); } diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 40647e33849c..bf8393f8f357 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -491,7 +491,6 @@ function MoneyRequestConfirmationList({ const currencySymbol = currencyList?.[iouCurrencyCode ?? '']?.symbol ?? iouCurrencyCode; const prefixPadding = StyleUtils.getCharacterPadding(currencySymbol ?? ''); const formattedTotalAmount = CurrencyUtils.convertToDisplayStringWithoutCurrency(iouAmount, iouCurrencyCode); - const amountWidth = StyleUtils.getWidthStyle(formattedTotalAmount.length * 9 + prefixPadding); return [payeeOption, ...selectedParticipants].map((participantOption: Participant) => ({ ...participantOption, @@ -509,12 +508,13 @@ function MoneyRequestConfirmationList({ hideCurrencySymbol formatAmountOnBlur prefixContainerStyle={[styles.pv0]} - inputStyle={[styles.optionRowAmountInput, amountWidth] as TextStyle[]} - containerStyle={[styles.textInputContainer, amountWidth]} + inputStyle={[styles.optionRowAmountInput] as TextStyle[]} + containerStyle={[styles.textInputContainer]} touchableInputWrapperStyle={[styles.ml3]} onFormatAmount={CurrencyUtils.convertToDisplayStringWithoutCurrency} onAmountChange={(value: string) => onSplitShareChange(participantOption.accountID ?? 0, Number(value))} maxLength={formattedTotalAmount.length} + contentWidth={formattedTotalAmount.length * 9} /> ), })); diff --git a/src/components/TextInput/BaseTextInput/index.native.tsx b/src/components/TextInput/BaseTextInput/index.native.tsx index 809544d2c5ed..b01a48b09f62 100644 --- a/src/components/TextInput/BaseTextInput/index.native.tsx +++ b/src/components/TextInput/BaseTextInput/index.native.tsx @@ -64,6 +64,7 @@ function BaseTextInput( shouldShowClearButton = false, prefixContainerStyle = [], prefixStyle = [], + contentWidth = undefined, ...props }: BaseTextInputProps, ref: ForwardedRef, @@ -251,12 +252,14 @@ function BaseTextInput( const newTextInputContainerStyles: StyleProp = StyleSheet.flatten([ styles.textInputContainer, textInputContainerStyles, - autoGrow && StyleUtils.getWidthStyle(textInputWidth), + (autoGrow || contentWidth) && StyleUtils.getWidthStyle(textInputWidth), !hideFocusedState && isFocused && styles.borderColorFocus, (!!hasError || !!errorText) && styles.borderColorDanger, autoGrowHeight && {scrollPaddingTop: typeof maxAutoGrowHeight === 'number' ? 2 * maxAutoGrowHeight : undefined}, ]); + const inputPaddingLeft = !!prefixCharacter && StyleUtils.getPaddingLeft(StyleUtils.getCharacterPadding(prefixCharacter) + styles.pl1.paddingLeft); + return ( <> @@ -341,7 +344,7 @@ function BaseTextInput( styles.w100, inputStyle, (!hasLabel || isMultiline) && styles.pv0, - !!prefixCharacter && StyleUtils.getPaddingLeft(StyleUtils.getCharacterPadding(prefixCharacter) + styles.pl1.paddingLeft), + inputPaddingLeft, inputProps.secureTextEntry && styles.secureInput, !isMultiline && {height, lineHeight: undefined}, @@ -411,6 +414,34 @@ function BaseTextInput( /> )} + {contentWidth && + { + if (e.nativeEvent.layout.width === 0 && e.nativeEvent.layout.height === 0) { + return; + } + setTextInputWidth(e.nativeEvent.layout.width); + setTextInputHeight(e.nativeEvent.layout.height); + }} + > + + {/* \u200B added to solve the issue of not expanding the text input enough when the value ends with '\n' (https://github.com/Expensify/App/issues/21271) */} + {value ? `${value}${value.endsWith('\n') ? '\u200B' : ''}` : placeholder} + + + } {/* Text input component doesn't support auto grow by default. We're using a hidden text input to achieve that. From 12f0433b475dab211725e4ce36202b67d8f17447 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Fri, 7 Jun 2024 11:14:48 +0530 Subject: [PATCH 011/482] add ViolationMessages for receipt. Signed-off-by: Krishna Gupta --- src/components/ReportActionItem/MoneyRequestView.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index d4aae74cc9b3..0512acb2eaff 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -402,6 +402,7 @@ function MoneyRequestView({ /> )} {!shouldShowReceiptEmptyState && !shouldShowMapOrReceipt && } + {canUseViolations && } Date: Fri, 7 Jun 2024 11:19:39 +0530 Subject: [PATCH 012/482] return all type of violations for paid policies. Signed-off-by: Krishna Gupta --- src/hooks/useViolations.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hooks/useViolations.ts b/src/hooks/useViolations.ts index e5a9824eaed6..938244f09eef 100644 --- a/src/hooks/useViolations.ts +++ b/src/hooks/useViolations.ts @@ -52,16 +52,16 @@ type ViolationsMap = Map; // We don't want to show these violations on NewDot const excludedViolationsName = ['taxAmountChanged', 'taxRateChanged']; -function useViolations(violations: TransactionViolation[], shouldIncludeNoticeViolations?: boolean) { +function useViolations(violations: TransactionViolation[], isPaidGroupPolicy?: boolean) { const violationsByField = useMemo((): ViolationsMap => { const filteredViolations = violations.filter((violation) => { if (excludedViolationsName.includes(violation.name)) { return false; } - if (!shouldIncludeNoticeViolations) { + if (!isPaidGroupPolicy) { return violation.type === CONST.VIOLATION_TYPES.VIOLATION; } - return violation.type === CONST.VIOLATION_TYPES.VIOLATION || violation.type === CONST.VIOLATION_TYPES.NOTICE; + return true; }); const violationGroups = new Map(); @@ -71,7 +71,7 @@ function useViolations(violations: TransactionViolation[], shouldIncludeNoticeVi violationGroups.set(field, [...existingViolations, violation]); } return violationGroups ?? new Map(); - }, [violations, shouldIncludeNoticeViolations]); + }, [violations, isPaidGroupPolicy]); const getViolationsForField = useCallback( (field: ViolationField, data?: TransactionViolation['data']) => { From 03a9345a1c1bcba1b5118f45cecfacf26b4ecefb Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Wed, 12 Jun 2024 15:28:39 +0530 Subject: [PATCH 013/482] add changes back in MoneyRequestView. Signed-off-by: Krishna Gupta --- .../ReportActionItem/MoneyRequestView.tsx | 14 +++++++------- src/types/onyx/TransactionViolation.ts | 11 ++++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index cc99a3f6e108..3029fa36da21 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -6,7 +6,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {useSession} from '@components/OnyxProvider'; -import {ReceiptAuditHeader, ReceiptAuditMessages} from '@components/ReceiptAudit'; +import ReceiptAudit from '@components/ReceiptAudit'; import ReceiptEmptyState from '@components/ReceiptEmptyState'; import Switch from '@components/Switch'; import Text from '@components/Text'; @@ -169,7 +169,7 @@ function MoneyRequestView({ const shouldShowTax = isTaxTrackingEnabled(isPolicyExpenseChat, policy, isDistanceRequest); - const {getViolationsForField} = useViolations(transactionViolations ?? []); + const {getViolationsForField} = useViolations(transactionViolations ?? [], !isReceiptBeingScanned && ReportUtils.isPaidGroupPolicy(report)); const hasViolations = useCallback( (field: ViolationField, data?: OnyxTypes.TransactionViolation['data'], policyHasDependentTags = false, tagValue?: string): boolean => !!canUseViolations && getViolationsForField(field, data, policyHasDependentTags, tagValue).length > 0, @@ -326,7 +326,7 @@ function MoneyRequestView({ ]; const receiptViolations = transactionViolations?.filter((violation) => receiptViolationNames.includes(violation.name)).map((violation) => ViolationsUtils.getViolationTranslation(violation, translate)) ?? []; - const shouldShowNotesViolations = !isReceiptBeingScanned && canUseViolations && ReportUtils.isPaidGroupPolicy(report); + const shouldShowAuditMessage = !isReceiptBeingScanned && canUseViolations && ReportUtils.isPaidGroupPolicy(report); const shouldShowReceiptHeader = isReceiptAllowed && (shouldShowReceiptEmptyState || hasReceipt) && canUseViolations && ReportUtils.isPaidGroupPolicy(report); const errors = { @@ -370,9 +370,10 @@ function MoneyRequestView({ {shouldShowAnimatedBackground && } <> {shouldShowReceiptHeader && ( - )} {(hasReceipt || errors) && ( @@ -422,7 +423,7 @@ function MoneyRequestView({ /> )} {!shouldShowReceiptEmptyState && !hasReceipt && } - {shouldShowNotesViolations && } + {canUseViolations && }{' '} )} - {shouldShowTax && ( ; +/** + * Types of violation data. + * Derived from ONST.VIOLATION_DATA_TYPES` to maintain a single source of truth. + */ +type ViolationDataType = ValueOf; + /** Model of transaction violation data */ type TransactionViolationData = { /** Who rejected the transaction */ @@ -62,6 +68,9 @@ type TransactionViolationData = { /** Whether the current violation is `pending RTER` */ pendingPattern?: boolean; + + /** Violation data type */ + type?: ViolationDataType; }; /** Model of a transaction violation */ @@ -79,5 +88,5 @@ type TransactionViolation = { /** Collection of transaction violations */ type TransactionViolations = TransactionViolation[]; -export type {TransactionViolation, ViolationName}; +export type {TransactionViolation, ViolationName, ViolationDataType}; export default TransactionViolations; From 245d667e53a0fdd7046ec98efdcaa8dfe19ed366 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Wed, 12 Jun 2024 16:08:01 +0530 Subject: [PATCH 014/482] updated receiptViolationNames. Signed-off-by: Krishna Gupta --- src/components/ReportActionItem/MoneyRequestView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 3029fa36da21..791e18d2af71 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -321,6 +321,7 @@ function MoneyRequestView({ CONST.VIOLATIONS.RECEIPT_REQUIRED, CONST.VIOLATIONS.RECEIPT_NOT_SMART_SCANNED, CONST.VIOLATIONS.MODIFIED_DATE, + CONST.VIOLATIONS.MODIFIED_AMOUNT, CONST.VIOLATIONS.CASH_EXPENSE_WITH_NO_RECEIPT, CONST.VIOLATIONS.SMARTSCAN_FAILED, ]; @@ -423,7 +424,7 @@ function MoneyRequestView({ /> )} {!shouldShowReceiptEmptyState && !hasReceipt && } - {canUseViolations && }{' '} + {canUseViolations && } Date: Thu, 13 Jun 2024 13:16:48 +0530 Subject: [PATCH 015/482] fix type check. Signed-off-by: Krishna Gupta --- src/types/onyx/TransactionViolation.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/onyx/TransactionViolation.ts b/src/types/onyx/TransactionViolation.ts index d77178104b72..0d8b94909631 100644 --- a/src/types/onyx/TransactionViolation.ts +++ b/src/types/onyx/TransactionViolation.ts @@ -83,6 +83,9 @@ type TransactionViolation = { /** Additional violation information to provide the user */ data?: TransactionViolationData; + + /** Percent Variance for modified amount violations */ + displayPercentVariance?: number; }; /** Collection of transaction violations */ From caeb8298bbb0c806136e8deab9766039de11b634 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 13 Jun 2024 18:42:05 +0700 Subject: [PATCH 016/482] fix lint --- src/components/MoneyRequestAmountInput.tsx | 3 +++ src/components/MoneyRequestConfirmationList.tsx | 4 ---- .../TextInput/BaseTextInput/index.native.tsx | 15 +++++---------- src/components/TextInput/BaseTextInput/types.ts | 3 +++ .../TextInputWithCurrencySymbol/types.ts | 2 +- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/components/MoneyRequestAmountInput.tsx b/src/components/MoneyRequestAmountInput.tsx index cbe9c1beb4cc..ab0ded0d0a52 100644 --- a/src/components/MoneyRequestAmountInput.tsx +++ b/src/components/MoneyRequestAmountInput.tsx @@ -88,6 +88,9 @@ type MoneyRequestAmountInputProps = { * Autogrow input container length based on the entered text. */ autoGrow?: boolean; + + /** The width of inner content */ + contentWidth?: number; }; type Selection = { diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 637ad3db6438..1f1d8e0443be 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -13,7 +13,6 @@ import {MouseProvider} from '@hooks/useMouseContext'; import useNetwork from '@hooks/useNetwork'; import usePermissions from '@hooks/usePermissions'; import usePrevious from '@hooks/usePrevious'; -import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as CurrencyUtils from '@libs/CurrencyUtils'; @@ -227,7 +226,6 @@ function MoneyRequestConfirmationList({ const policyCategories = policyCategoriesReal ?? policyCategoriesDraft; const theme = useTheme(); const styles = useThemeStyles(); - const StyleUtils = useStyleUtils(); const {translate, toLocaleDigit} = useLocalize(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const {canUseP2PDistanceRequests, canUseViolations} = usePermissions(iouType); @@ -499,7 +497,6 @@ function MoneyRequestConfirmationList({ } const currencySymbol = currencyList?.[iouCurrencyCode ?? '']?.symbol ?? iouCurrencyCode; - const prefixPadding = StyleUtils.getCharacterPadding(currencySymbol ?? ''); const formattedTotalAmount = CurrencyUtils.convertToDisplayStringWithoutCurrency(iouAmount, iouCurrencyCode); return [payeeOption, ...selectedParticipants].map((participantOption: Participant) => ({ @@ -534,7 +531,6 @@ function MoneyRequestConfirmationList({ shouldShowReadOnlySplits, currencyList, iouCurrencyCode, - StyleUtils, iouAmount, selectedParticipants, styles.flexWrap, diff --git a/src/components/TextInput/BaseTextInput/index.native.tsx b/src/components/TextInput/BaseTextInput/index.native.tsx index 0efe7ed05d08..256a7c98ceac 100644 --- a/src/components/TextInput/BaseTextInput/index.native.tsx +++ b/src/components/TextInput/BaseTextInput/index.native.tsx @@ -252,7 +252,7 @@ function BaseTextInput( const newTextInputContainerStyles: StyleProp = StyleSheet.flatten([ styles.textInputContainer, textInputContainerStyles, - (autoGrow || contentWidth) && StyleUtils.getWidthStyle(textInputWidth), + (autoGrow || !!contentWidth) && StyleUtils.getWidthStyle(textInputWidth), !hideFocusedState && isFocused && styles.borderColorFocus, (!!hasError || !!errorText) && styles.borderColorDanger, autoGrowHeight && {scrollPaddingTop: typeof maxAutoGrowHeight === 'number' ? 2 * maxAutoGrowHeight : undefined}, @@ -414,14 +414,9 @@ function BaseTextInput( /> )} - {contentWidth && + {contentWidth && ( { if (e.nativeEvent.layout.width === 0 && e.nativeEvent.layout.height === 0) { return; @@ -434,14 +429,14 @@ function BaseTextInput( style={[ inputStyle, autoGrowHeight && styles.autoGrowHeightHiddenInput(width ?? 0, typeof maxAutoGrowHeight === 'number' ? maxAutoGrowHeight : undefined), - {width: contentWidth} + {width: contentWidth}, ]} > {/* \u200B added to solve the issue of not expanding the text input enough when the value ends with '\n' (https://github.com/Expensify/App/issues/21271) */} {value ? `${value}${value.endsWith('\n') ? '\u200B' : ''}` : placeholder} - } + )} {/* Text input component doesn't support auto grow by default. We're using a hidden text input to achieve that. diff --git a/src/components/TextInput/BaseTextInput/types.ts b/src/components/TextInput/BaseTextInput/types.ts index e8e2d5ab352d..cac7b68f0d17 100644 --- a/src/components/TextInput/BaseTextInput/types.ts +++ b/src/components/TextInput/BaseTextInput/types.ts @@ -121,6 +121,9 @@ type CustomBaseTextInputProps = { /** Style for the prefix container */ prefixContainerStyle?: StyleProp; + + /** The width of inner content */ + contentWidth?: number; }; type BaseTextInputRef = HTMLFormElement | AnimatedTextInputRef; diff --git a/src/components/TextInputWithCurrencySymbol/types.ts b/src/components/TextInputWithCurrencySymbol/types.ts index c83a7b9579ab..619ed0fd84e6 100644 --- a/src/components/TextInputWithCurrencySymbol/types.ts +++ b/src/components/TextInputWithCurrencySymbol/types.ts @@ -77,6 +77,6 @@ type TextInputWithCurrencySymbolProps = { /** Hide the focus styles on TextInput */ hideFocusedState?: boolean; -} & Pick; +} & Pick; export default TextInputWithCurrencySymbolProps; From 46a068b5b48a97d3ed852b91cd4dec4382e1ec30 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 14 Jun 2024 17:32:05 +0700 Subject: [PATCH 017/482] apply changes for web --- .../TextInput/BaseTextInput/index.tsx | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/components/TextInput/BaseTextInput/index.tsx b/src/components/TextInput/BaseTextInput/index.tsx index 3a1032ff7a43..5759474fc659 100644 --- a/src/components/TextInput/BaseTextInput/index.tsx +++ b/src/components/TextInput/BaseTextInput/index.tsx @@ -66,6 +66,7 @@ function BaseTextInput( shouldShowClearButton = false, prefixContainerStyle = [], prefixStyle = [], + contentWidth = undefined, ...inputProps }: BaseTextInputProps, ref: ForwardedRef, @@ -248,7 +249,7 @@ function BaseTextInput( const newTextInputContainerStyles: StyleProp = StyleSheet.flatten([ styles.textInputContainer, textInputContainerStyles, - autoGrow && StyleUtils.getWidthStyle(textInputWidth), + (autoGrow || !!contentWidth) && StyleUtils.getWidthStyle(textInputWidth), !hideFocusedState && isFocused && styles.borderColorFocus, (!!hasError || !!errorText) && styles.borderColorDanger, autoGrowHeight && {scrollPaddingTop: typeof maxAutoGrowHeight === 'number' ? 2 * maxAutoGrowHeight : undefined}, @@ -274,6 +275,8 @@ function BaseTextInput( return undefined; }, [inputStyle]); + const inputPaddingLeft = !!prefixCharacter && StyleUtils.getPaddingLeft(StyleUtils.getCharacterPadding(prefixCharacter) + styles.pl1.paddingLeft); + return ( <> )} + {contentWidth && ( + { + if (e.nativeEvent.layout.width === 0 && e.nativeEvent.layout.height === 0) { + return; + } + setTextInputWidth(e.nativeEvent.layout.width); + setTextInputHeight(e.nativeEvent.layout.height); + }} + > + + {/* \u200B added to solve the issue of not expanding the text input enough when the value ends with '\n' (https://github.com/Expensify/App/issues/21271) */} + {value ? `${value}${value.endsWith('\n') ? '\u200B' : ''}` : placeholder} + + + )} {/* Text input component doesn't support auto grow by default. We're using a hidden text input to achieve that. From 9e452c4a13352c96de2641229f38eaab02049b8a Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Fri, 14 Jun 2024 16:10:19 +0530 Subject: [PATCH 018/482] minor fixes. Signed-off-by: Krishna Gupta --- src/components/ReceiptAudit.tsx | 2 +- src/languages/en.ts | 4 ++-- src/languages/es.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/ReceiptAudit.tsx b/src/components/ReceiptAudit.tsx index a5ccf543e0b7..b950e75c7b38 100644 --- a/src/components/ReceiptAudit.tsx +++ b/src/components/ReceiptAudit.tsx @@ -24,7 +24,7 @@ function ReceiptAudit({notes, shouldShowAuditSuccess, shouldShowAuditFailure}: { {translate('common.receipt')} - {auditText && ( + {!!auditText && ( <> {` • ${auditText}`} Date: Sun, 16 Jun 2024 16:29:35 +0530 Subject: [PATCH 019/482] fix: QBO - Required remains enabled when all tags are disabled Signed-off-by: Krishna Gupta --- src/libs/actions/Policy/Tag.ts | 37 ++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index 7e2fb68ab125..b814faabc377 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -6,6 +6,7 @@ import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; import * as ErrorUtils from '@libs/ErrorUtils'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import Log from '@libs/Log'; +import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import {navigateWhenEnableFeature} from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -181,6 +182,23 @@ function createPolicyTag(policyID: string, tagName: string) { function setWorkspaceTagEnabled(policyID: string, tagsToUpdate: Record, tagListIndex: number) { const policyTag = PolicyUtils.getTagLists(allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {})?.[tagListIndex] ?? {}; + const optimisticPolicyTagsData = { + ...Object.keys(tagsToUpdate).reduce((acc, key) => { + acc[key] = { + ...policyTag.tags[key], + ...tagsToUpdate[key], + errors: null, + pendingFields: { + enabled: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }; + + return acc; + }, {}), + }; + const shouldDisableRequiredTag = !OptionsListUtils.hasEnabledOptions({...policyTag.tags, ...optimisticPolicyTagsData}); + const onyxData: OnyxData = { optimisticData: [ { @@ -188,21 +206,8 @@ function setWorkspaceTagEnabled(policyID: string, tagsToUpdate: Record((acc, key) => { - acc[key] = { - ...policyTag.tags[key], - ...tagsToUpdate[key], - errors: null, - pendingFields: { - enabled: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, - }, - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, - }; - - return acc; - }, {}), - }, + ...(shouldDisableRequiredTag ? {required: false, pendingFields: {required: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}} : {}), + tags: optimisticPolicyTagsData, }, }, }, @@ -213,6 +218,7 @@ function setWorkspaceTagEnabled(policyID: string, tagsToUpdate: Record((acc, key) => { acc[key] = { @@ -238,6 +244,7 @@ function setWorkspaceTagEnabled(policyID: string, tagsToUpdate: Record((acc, key) => { acc[key] = { From d164b7ac3ebb6e9e5dc28f38a0bc5d1ef3600624 Mon Sep 17 00:00:00 2001 From: daledah Date: Wed, 19 Jun 2024 11:46:37 +0700 Subject: [PATCH 020/482] Workspace member has option to edit categories, which leads to not here page --- src/languages/en.ts | 4 ++ src/languages/es.ts | 4 ++ .../request/step/IOURequestStepCategory.tsx | 61 ++++++++++++++----- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index e3eaafc54bd3..96d037128474 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2193,7 +2193,11 @@ export default { subtitle: 'Get a better overview of where money is being spent. Use our default categories or add your own.', emptyCategories: { title: "You haven't created any categories", + memberTitle: (workspaceName: string) => `${workspaceName} doesn' have any categories enabled.`, subtitle: 'Add a category to organize your spend.', + otherWorkspace: 'Categorize this expense by choosing a different workspace, or ', + askYourAdmin: 'ask your admin', + enableForThisWorkspace: ' to enable categories for this workspace.', }, updateFailureMessage: 'An error occurred while updating the category, please try again.', createFailureMessage: 'An error occurred while creating the category, please try again.', diff --git a/src/languages/es.ts b/src/languages/es.ts index ece0f7f70cdb..1136b827ec45 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2230,6 +2230,10 @@ export default { emptyCategories: { title: 'No has creado ninguna categoría', subtitle: 'Añade una categoría para organizar tu gasto.', + memberTitle: (workspaceName: string) => `${workspaceName} no tiene ninguna categoría activada.`, + otherWorkspace: 'Categorice este gasto eligiendo un espacio de trabajo diferente, o ', + askYourAdmin: 'pida a su administrador', + enableForThisWorkspace: ' que habilite categorías para este espacio de trabajo.', }, updateFailureMessage: 'Se ha producido un error al intentar eliminar la categoría. Por favor, inténtalo más tarde.', createFailureMessage: 'Se ha producido un error al intentar crear la categoría. Por favor, inténtalo más tarde.', diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index 18ddc19644ef..12032b07fd65 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -1,17 +1,20 @@ import lodashIsEmpty from 'lodash/isEmpty'; import React, {useEffect} from 'react'; +import type {ReactNode} from 'react'; import {ActivityIndicator, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import CategoryPicker from '@components/CategoryPicker'; import FixedFooter from '@components/FixedFooter'; +import Icon from '@components/Icon'; import * as Illustrations from '@components/Icon/Illustrations'; import type {ListItem} from '@components/SelectionList/types'; import Text from '@components/Text'; -import WorkspaceEmptyStateSection from '@components/WorkspaceEmptyStateSection'; +import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; @@ -85,6 +88,8 @@ function IOURequestStepCategory({ const {translate} = useLocalize(); const isEditing = action === CONST.IOU.ACTION.EDIT; const isEditingSplitBill = isEditing && iouType === CONST.IOU.TYPE.SPLIT; + const isAdmin = policy?.role === CONST.POLICY.ROLE.ADMIN; + const {shouldUseNarrowLayout} = useResponsiveLayout(); const transactionCategory = ReportUtils.getTransactionDetails(isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction)?.category; // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -151,6 +156,36 @@ function IOURequestStepCategory({ navigateBack(); }; + const renderCategoriesEmptyStateSection = (): ReactNode => ( + + + + + + + {isAdmin ? translate('workspace.categories.emptyCategories.title') : translate('workspace.categories.emptyCategories.memberTitle', policy?.name ?? '')} + + + + + {isAdmin ? ( + {translate('workspace.categories.emptyCategories.subtitle')} + ) : ( + + {translate('workspace.categories.emptyCategories.otherWorkspace')} + {}}>{translate('workspace.categories.emptyCategories.askYourAdmin')} + {translate('workspace.categories.emptyCategories.enableForThisWorkspace')} + + )} + + + + ); + return ( - + {renderCategoriesEmptyStateSection()}