Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,7 @@ const CONST = {
REMOVE_HOLD: 'removeHold',
REVIEW_DUPLICATES: 'reviewDuplicates',
MARK_AS_CASH: 'markAsCash',
ADD_EXPENSE: 'addExpense',
},
TRANSACTION_PRIMARY_ACTIONS: {
REMOVE_HOLD: 'removeHold',
Expand Down
38 changes: 13 additions & 25 deletions src/components/EmptyStateComponent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import isEmpty from 'lodash/isEmpty';
import React, {useMemo, useState} from 'react';
import {View} from 'react-native';
import Button from '@components/Button';
import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu';
import ImageSVG from '@components/ImageSVG';
import Lottie from '@components/Lottie';
import Text from '@components/Text';
Expand Down Expand Up @@ -104,30 +103,19 @@ function EmptyStateComponent({
{subtitleText ?? <Text style={[styles.textAlignCenter, styles.textSupporting, styles.textNormal]}>{subtitle}</Text>}
{children}
{!isEmpty(buttons) && (
<View style={[styles.gap2, styles.mt5, !shouldUseNarrowLayout ? styles.flexRow : styles.flexColumn, styles.justifyContentCenter]}>
{buttons?.map(({buttonText, buttonAction, success, icon, isDisabled, style, dropDownOptions}) =>
dropDownOptions ? (
<ButtonWithDropdownMenu
onPress={() => {}}
shouldAlwaysShowDropdownMenu
customText={buttonText}
options={dropDownOptions}
isSplitButton={false}
style={[styles.flex1, style]}
/>
) : (
<Button
key={buttonText}
success={success}
onPress={buttonAction}
text={buttonText}
icon={icon}
large
isDisabled={isDisabled}
style={[styles.flex1, style]}
/>
),
)}
<View style={[styles.gap2, styles.mt5, !shouldUseNarrowLayout ? styles.flexRow : styles.flexColumn]}>
{buttons?.map(({buttonText, buttonAction, success, icon, isDisabled, style}) => (
<Button
key={buttonText}
success={success}
onPress={buttonAction}
text={buttonText}
icon={icon}
large
isDisabled={isDisabled}
style={[styles.flex1, style]}
/>
))}
</View>
)}
</View>
Expand Down
11 changes: 1 addition & 10 deletions src/components/EmptyStateComponent/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type {ImageStyle} from 'expo-image';
import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
import type {ValueOf} from 'type-fest';
import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types';
import type DotLottieAnimation from '@components/LottieAnimations/types';
import type SearchRowSkeleton from '@components/Skeletons/SearchRowSkeleton';
import type TableRowSkeleton from '@components/Skeletons/TableRowSkeleton';
Expand All @@ -10,15 +9,7 @@ import type IconAsset from '@src/types/utils/IconAsset';

type ValidSkeletons = typeof SearchRowSkeleton | typeof TableRowSkeleton;
type MediaTypes = ValueOf<typeof CONST.EMPTY_STATE_MEDIA>;
type EmptyStateButton = {
buttonText?: string;
buttonAction?: () => void;
success?: boolean;
icon?: IconAsset;
isDisabled?: boolean;
style?: StyleProp<ViewStyle>;
dropDownOptions?: Array<DropdownOption<ValueOf<{readonly CREATE_NEW_EXPENSE: 'createNewExpense'; readonly ADD_UNREPORTED_EXPENSE: 'addUnreportedExpense'}>>>;
};
type EmptyStateButton = {buttonText?: string; buttonAction?: () => void; success?: boolean; icon?: IconAsset; isDisabled?: boolean; style?: StyleProp<ViewStyle>};

type SharedProps<T> = {
SkeletonComponent?: ValidSkeletons;
Expand Down
9 changes: 9 additions & 0 deletions src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,15 @@ function MoneyReportHeader({
}}
/>
),
[CONST.REPORT.PRIMARY_ACTIONS.ADD_EXPENSE]: (
<ButtonWithDropdownMenu
onPress={() => {}}
shouldAlwaysShowDropdownMenu
customText={translate('iou.addExpense')}
options={addExpenseDropdownOptions}
isSplitButton={false}
/>
),
};

const [offlineModalVisible, setOfflineModalVisible] = useState(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import DecisionModal from '@components/DecisionModal';
import FlatList from '@components/FlatList';
import {AUTOSCROLL_TO_TOP_THRESHOLD} from '@components/InvertedFlatList/BaseInvertedFlatList';
import {PressableWithFeedback} from '@components/Pressable';
import ScrollView from '@components/ScrollView';
import {useSearchContext} from '@components/Search/SearchContext';
import Text from '@components/Text';
import useLoadReportActions from '@hooks/useLoadReportActions';
Expand Down Expand Up @@ -617,16 +616,13 @@ function MoneyRequestReportActionsList({
onClick={scrollToBottomAndMarkReportAsRead}
/>
{isEmpty(visibleReportActions) && isEmpty(transactions) && !showReportActionsLoadingState ? (
<ScrollView>
<>
<MoneyRequestViewReportFields
report={report}
policy={policy}
/>
<SearchMoneyRequestReportEmptyState
reportId={report.reportID}
policy={policy}
/>
</ScrollView>
<SearchMoneyRequestReportEmptyState />
</>
) : (
<FlatList
initialNumToRender={INITIAL_NUM_TO_RENDER}
Expand Down Expand Up @@ -655,7 +651,6 @@ function MoneyRequestReportActionsList({
hasComments={reportHasComments}
isLoadingInitialReportActions={showReportActionsLoadingState}
scrollToNewTransaction={scrollToNewTransaction}
policy={policy}
/>
</>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ import SearchMoneyRequestReportEmptyState from './SearchMoneyRequestReportEmptyS
type MoneyRequestReportTransactionListProps = {
report: OnyxTypes.Report;

policy?: OnyxTypes.Policy;

/** List of transactions belonging to one report */
transactions: OnyxTypes.Transaction[];

Expand Down Expand Up @@ -113,7 +111,6 @@ function MoneyRequestReportTransactionList({
hasComments,
isLoadingInitialReportActions: isLoadingReportActions,
scrollToNewTransaction,
policy,
}: MoneyRequestReportTransactionListProps) {
useCopySelectionHelper();
const styles = useThemeStyles();
Expand Down Expand Up @@ -368,10 +365,7 @@ function MoneyRequestReportTransactionList({
</Modal>
</>
) : (
<SearchMoneyRequestReportEmptyState
reportId={report.reportID}
policy={policy}
/>
<SearchMoneyRequestReportEmptyState />
)}
<View style={[styles.dFlex, styles.flexRow, listHorizontalPadding, styles.justifyContentBetween, styles.mb2]}>
<Animated.Text
Expand Down
Original file line number Diff line number Diff line change
@@ -1,54 +1,17 @@
import React from 'react';
import {View} from 'react-native';
import EmptyStateComponent from '@components/EmptyStateComponent';
import * as Expensicons from '@components/Icon/Expensicons';
import LottieAnimations from '@components/LottieAnimations';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
import Navigation from '@navigation/Navigation';
import {startMoneyRequest} from '@userActions/IOU';
import {openUnreportedExpense} from '@userActions/Report';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import type {Policy} from '@src/types/onyx';

const minModalHeight = 380;

function SearchMoneyRequestReportEmptyState({reportId, policy}: {reportId?: string; policy?: Policy}) {
function SearchMoneyRequestReportEmptyState() {
const {translate} = useLocalize();
const styles = useThemeStyles();

const addExpenseDropdownOptions = [
{
value: CONST.REPORT.ADD_EXPENSE_OPTIONS.CREATE_NEW_EXPENSE,
text: translate('iou.createNewExpense'),
icon: Expensicons.Plus,
onSelected: () => {
if (!reportId) {
return;
}
if (policy && shouldRestrictUserBillableActions(policy.id)) {
Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(policy.id));
return;
}
startMoneyRequest(CONST.IOU.TYPE.SUBMIT, reportId);
},
},
{
value: CONST.REPORT.ADD_EXPENSE_OPTIONS.ADD_UNREPORTED_EXPENSE,
text: translate('iou.addUnreportedExpense'),
icon: Expensicons.ReceiptPlus,
onSelected: () => {
if (policy && shouldRestrictUserBillableActions(policy.id)) {
Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(policy.id));
return;
}
openUnreportedExpense(reportId);
},
},
];

return (
<View style={styles.flex1}>
<EmptyStateComponent
Expand All @@ -62,7 +25,6 @@ function SearchMoneyRequestReportEmptyState({reportId, policy}: {reportId?: stri
lottieWebViewStyles={styles.emptyStateFolderWebStyles}
headerContentStyles={styles.emptyStateFolderWebStyles}
minModalHeight={minModalHeight}
buttons={[{buttonText: translate('iou.addExpense'), buttonAction: () => {}, success: true, isDisabled: false, dropDownOptions: addExpenseDropdownOptions}]}
/>
</View>
);
Expand Down
3 changes: 1 addition & 2 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5983,8 +5983,7 @@ const translations = {
groupBy: 'Gruppe nach',
moneyRequestReport: {
emptyStateTitle: 'Dieser Bericht enthält keine Ausgaben.',
emptyStateSubtitle:
'Sie können diesem Bericht Ausgaben hinzufügen,\n indem Sie auf die Schaltfläche unten klicken oder die Option „Ausgabe hinzufügen“ im Menü „Mehr“ oben verwenden.',
emptyStateSubtitle: 'Sie können Ausgaben zu diesem Bericht hinzufügen, indem Sie die Schaltfläche oben verwenden.',
},
noCategory: 'Keine Kategorie',
noTag: 'Kein Tag',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5954,7 +5954,7 @@ const translations = {
groupBy: 'Group by',
moneyRequestReport: {
emptyStateTitle: 'This report has no expenses.',
emptyStateSubtitle: 'You can add expenses to this report \n using the button below or the "Add expense" option in the More menu above.',
emptyStateSubtitle: 'You can add expenses to this report \n using the button above.',
},
noCategory: 'No category',
noTag: 'No tag',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5976,7 +5976,7 @@ const translations = {
groupBy: 'Agrupar por',
moneyRequestReport: {
emptyStateTitle: 'Este informe no tiene gastos.',
emptyStateSubtitle: 'Puedes agregar gastos a este informe\n usando el botón de abajo o la opción "Agregar gasto" en el menú Más de arriba.',
emptyStateSubtitle: 'Puedes añadir gastos a este informe usando el botón de arriba.',
},
noCategory: 'Sin categoría',
noTag: 'Sin etiqueta',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5993,7 +5993,7 @@ const translations = {
groupBy: 'Groupe par',
moneyRequestReport: {
emptyStateTitle: "Ce rapport n'a pas de dépenses.",
emptyStateSubtitle: "Vous pouvez ajouter des dépenses à ce rapport\n en utilisant le bouton ci-dessous ou l'option « Ajouter une dépense » dans le menu Plus ci-dessus.",
emptyStateSubtitle: 'Vous pouvez ajouter des dépenses à ce rapport en utilisant le bouton ci-dessus.',
},
noCategory: 'Aucune catégorie',
noTag: 'Aucun tag',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5996,7 +5996,7 @@ const translations = {
groupBy: 'Gruppo per',
moneyRequestReport: {
emptyStateTitle: 'Questo report non ha spese.',
emptyStateSubtitle: 'Puoi aggiungere spese a questo report\n utilizzando il pulsante in basso o l\'opzione "Aggiungi spesa" nel menu Altro sopra.',
emptyStateSubtitle: 'Puoi aggiungere spese a questo rapporto utilizzando il pulsante sopra.',
},
noCategory: 'Nessuna categoria',
noTag: 'Nessun tag',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5957,7 +5957,7 @@ const translations = {
groupBy: 'グループ',
moneyRequestReport: {
emptyStateTitle: 'このレポートには経費がありません。',
emptyStateSubtitle: 'このレポートに経費を追加するには、\n 下のボタンを使用するか、上の「その他」メニューから「経費を追加」を選択してください。',
emptyStateSubtitle: 'このレポートに経費を追加するには、上のボタンを使用してください。',
},
noCategory: 'カテゴリなし',
noTag: 'タグなし',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5988,7 +5988,7 @@ const translations = {
groupBy: 'Groep per',
moneyRequestReport: {
emptyStateTitle: 'Dit rapport heeft geen uitgaven.',
emptyStateSubtitle: 'U kunt uitgaven aan dit rapport toevoegen\n via de knop hieronder of de optie "Uitgave toevoegen" in het menu Meer hierboven.',
emptyStateSubtitle: 'Je kunt uitgaven aan dit rapport toevoegen met de knop hierboven.',
},
noCategory: 'Geen categorie',
noTag: 'Geen tag',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5973,7 +5973,7 @@ const translations = {
groupBy: 'Grupa według',
moneyRequestReport: {
emptyStateTitle: 'Ten raport nie zawiera wydatków.',
emptyStateSubtitle: 'Możesz dodać wydatki do tego raportu\n za pomocą przycisku poniżej lub opcji „Dodaj wydatek” w menu Więcej powyżej.',
emptyStateSubtitle: 'Możesz dodać wydatki do tego raportu, używając przycisku powyżej.',
},
noCategory: 'Brak kategorii',
noTag: 'Brak tagu',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5986,7 +5986,7 @@ const translations = {
groupBy: 'Agrupar por',
moneyRequestReport: {
emptyStateTitle: 'Este relatório não possui despesas.',
emptyStateSubtitle: 'Você pode adicionar despesas a este relatório\n usando o botão abaixo ou a opção "Adicionar despesa" no menu Mais acima.',
emptyStateSubtitle: 'Você pode adicionar despesas a este relatório usando o botão acima.',
},
noCategory: 'Sem categoria',
noTag: 'Sem etiqueta',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5883,7 +5883,7 @@ const translations = {
groupBy: '组别',
moneyRequestReport: {
emptyStateTitle: '此报告没有费用。',
emptyStateSubtitle: '您可以使用下方按钮,或上方“更多”菜单中的“添加费用”选项,将费用添加到此报告中。',
emptyStateSubtitle: '您可以使用上面的按钮将费用添加到此报告中。',
},
noCategory: '无类别',
noTag: '无标签',
Expand Down
4 changes: 4 additions & 0 deletions src/libs/ReportPrimaryActionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,10 @@ function getReportPrimaryAction(params: GetReportPrimaryActionParams): ValueOf<t

const isPayActionWithAllExpensesHeld = isPrimaryPayAction(report, policy, reportNameValuePairs, isChatReportArchived) && hasOnlyHeldExpenses(report?.reportID);

if (isAddExpenseAction(report, reportTransactions, isChatReportArchived)) {
return CONST.REPORT.PRIMARY_ACTIONS.ADD_EXPENSE;
}

if (isMarkAsCashAction(report, reportTransactions, violations, policy)) {
return CONST.REPORT.PRIMARY_ACTIONS.MARK_AS_CASH;
}
Expand Down
2 changes: 1 addition & 1 deletion src/libs/ReportSecondaryActionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import {
function isAddExpenseAction(report: Report, reportTransactions: Transaction[], isReportArchived = false) {
const isReportSubmitter = isCurrentUserSubmitter(report.reportID);

if (!isReportSubmitter) {
if (!isReportSubmitter || reportTransactions.length === 0) {
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions tests/unit/ReportPrimaryActionUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('getPrimaryAction', () => {
await Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, {[CURRENT_USER_ACCOUNT_ID]: PERSONAL_DETAILS});
});

it('should return empty string for expense report with no transactions', async () => {
it('should return ADD_EXPENSE for expense report with no transactions', async () => {
const report = {
reportID: REPORT_ID,
type: CONST.REPORT.TYPE.EXPENSE,
Expand All @@ -54,7 +54,7 @@ describe('getPrimaryAction', () => {
} as unknown as Report;
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, report);

expect(getReportPrimaryAction({report, chatReport, reportTransactions: [], violations: {}, policy: {} as Policy})).toBe('');
expect(getReportPrimaryAction({report, chatReport, reportTransactions: [], violations: {}, policy: {} as Policy})).toBe(CONST.REPORT.PRIMARY_ACTIONS.ADD_EXPENSE);
});

it('should return SUBMIT for expense report with manual submit', async () => {
Expand Down
Loading