Skip to content

Commit b63917a

Browse files
committed
add field visibility helper
1 parent 08b5d3e commit b63917a

5 files changed

Lines changed: 246 additions & 128 deletions

File tree

src/components/MoneyRequestConfirmationListFooter/ConfirmationFieldList.tsx

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type * as OnyxTypes from '@src/types/onyx';
1616
import type {Participant} from '@src/types/onyx/IOU';
1717
import type {Unit} from '@src/types/onyx/Policy';
1818
import ClassificationFields from './fieldGroups/ClassificationFields';
19+
import computeFieldVisibility, {hasBelowShowMore} from './fieldGroups/fieldVisibility';
1920
import SettingsFields from './fieldGroups/SettingsFields';
2021
import TransactionDetailsFields from './fieldGroups/TransactionDetailsFields';
2122

@@ -251,23 +252,24 @@ function ConfirmationFieldList({
251252
const {translate} = useLocalize();
252253
const icons = useMemoizedLazyExpensifyIcons(['Sparkles', 'DownArrow']);
253254

254-
const showAmount = shouldShowSmartScanFields && shouldShowAmountField;
255-
const showCategoryBelowShowMore = shouldShowCategories && !isCategoryRequired;
256-
const hasOptionalTags = tagVisibility.some((entry) => entry.shouldShow && !entry.isTagRequired);
257-
258-
const hasBelowShowMore =
259-
showAmount ||
260-
isDistanceRequest ||
261-
shouldShowMerchant ||
262-
shouldShowTimeRequestFields ||
263-
showCategoryBelowShowMore ||
264-
shouldShowDate ||
265-
hasOptionalTags ||
266-
shouldShowTax ||
267-
shouldShowAttendees ||
268-
shouldShowReimbursable ||
269-
shouldShowBillable ||
270-
isPolicyExpenseChat;
255+
const fieldVisibility = computeFieldVisibility({
256+
shouldShowSmartScanFields,
257+
shouldShowAmountField,
258+
isDistanceRequest,
259+
shouldShowMerchant,
260+
shouldShowTimeRequestFields,
261+
shouldShowCategories,
262+
isCategoryRequired,
263+
shouldShowDate,
264+
tagVisibility,
265+
policyTagLists,
266+
shouldShowTax,
267+
shouldShowAttendees,
268+
shouldShowReimbursable,
269+
shouldShowBillable,
270+
isPolicyExpenseChat,
271+
});
272+
const shouldShowMoreButton = hasBelowShowMore(fieldVisibility);
271273

272274
return (
273275
<View style={[styles.mb5, styles.mt2]}>
@@ -296,15 +298,10 @@ function ConfirmationFieldList({
296298
isNewManualExpenseFlowEnabled={isNewManualExpenseFlowEnabled}
297299
isEditingSplitBill={isEditingSplitBill}
298300
isPolicyExpenseChat={isPolicyExpenseChat}
299-
isDistanceRequest={isDistanceRequest}
300301
isManualDistanceRequest={isManualDistanceRequest}
301302
isOdometerDistanceRequest={isOdometerDistanceRequest}
302303
isGPSDistanceRequest={isGPSDistanceRequest}
303-
shouldShowAmountField={shouldShowAmountField}
304-
shouldShowSmartScanFields={shouldShowSmartScanFields}
305-
shouldShowMerchant={shouldShowMerchant}
306304
isMerchantRequired={isMerchantRequired}
307-
shouldShowTimeRequestFields={shouldShowTimeRequestFields}
308305
isDescriptionRequired={isDescriptionRequired}
309306
shouldDisplayFieldError={shouldDisplayFieldError}
310307
formError={formError}
@@ -320,6 +317,7 @@ function ConfirmationFieldList({
320317
distanceRateName={distanceRateName}
321318
distanceRateCurrency={distanceRateCurrency}
322319
isCompactMode={isCompactMode}
320+
fieldVisibility={fieldVisibility}
323321
/>
324322

325323
<ClassificationFields
@@ -332,23 +330,19 @@ function ConfirmationFieldList({
332330
policy={policy}
333331
policyForMovingExpenses={policyForMovingExpenses}
334332
policyTagLists={policyTagLists}
335-
tagVisibility={tagVisibility}
336333
previousTagsVisibility={previousTagsVisibility}
337334
isReadOnly={isReadOnly}
338335
didConfirm={didConfirm}
339-
shouldShowCategories={shouldShowCategories}
340336
isCategoryRequired={isCategoryRequired}
341-
shouldShowDate={shouldShowDate}
342-
shouldShowTax={shouldShowTax}
343337
canModifyTaxFields={canModifyTaxFields}
344-
shouldShowAttendees={shouldShowAttendees}
345338
shouldDisplayFieldError={shouldDisplayFieldError}
346339
shouldNavigateToUpgradePath={shouldNavigateToUpgradePath}
347340
shouldSelectPolicy={shouldSelectPolicy}
348341
iouCurrencyCode={iouCurrencyCode}
349342
formattedAmountPerAttendee={formattedAmountPerAttendee}
350343
formError={formError}
351344
isCompactMode={isCompactMode}
345+
fieldVisibility={fieldVisibility}
352346
/>
353347

354348
<SettingsFields
@@ -367,9 +361,10 @@ function ConfirmationFieldList({
367361
onToggleReimbursable={onToggleReimbursable}
368362
onToggleBillable={onToggleBillable}
369363
isCompactMode={isCompactMode}
364+
fieldVisibility={fieldVisibility}
370365
/>
371366

372-
{isCompactMode && hasBelowShowMore && (
367+
{isCompactMode && shouldShowMoreButton && (
373368
<View style={[styles.mt3, styles.alignItemsCenter, styles.pRelative, styles.mh5]}>
374369
<View style={[styles.dividerLine, styles.pAbsolute, styles.w100, styles.justifyContentCenter, {transform: [{translateY: -0.5}]}]} />
375370
<Button

src/components/MoneyRequestConfirmationListFooter/fieldGroups/ClassificationFields.tsx

Lines changed: 39 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@ import TaxFields from '@components/MoneyRequestConfirmationList/sections/TaxFiel
99
import type CONST from '@src/CONST';
1010
import type {IOUAction, IOUType} from '@src/CONST';
1111
import type * as OnyxTypes from '@src/types/onyx';
12-
13-
type TagVisibilityEntry = {
14-
/** Whether this tag list should be displayed */
15-
shouldShow: boolean;
16-
/** Whether the tag for this list is required to submit */
17-
isTagRequired: boolean;
18-
};
12+
import type {FieldVisibility, TagEntry} from './fieldVisibility';
1913

2014
type ClassificationFieldsProps = {
2115
/** Action being performed (drives section navigation targets) */
@@ -42,12 +36,9 @@ type ClassificationFieldsProps = {
4236
/** Resolved policy used when moving an expense off track-expense (drives tax fallback) */
4337
policyForMovingExpenses: OnyxEntry<OnyxTypes.Policy> | undefined;
4438

45-
/** Tag lists configured on the policy */
39+
/** Tag lists configured on the policy (used to look up the list at each tag entry's index) */
4640
policyTagLists: Array<ValueOf<OnyxTypes.PolicyTagLists>>;
4741

48-
/** Per-tag-list visibility (parallel to `policyTagLists` order) */
49-
tagVisibility: TagVisibilityEntry[];
50-
5142
/** Previous render's per-tag-list `shouldShow` projection (drives `TagFields` transitions) */
5243
previousTagsVisibility: boolean[];
5344

@@ -57,24 +48,12 @@ type ClassificationFieldsProps = {
5748
/** Whether the user has confirmed (locks editable controls) */
5849
didConfirm: boolean;
5950

60-
/** Whether the categories field should be displayed */
61-
shouldShowCategories: boolean;
62-
6351
/** Whether the categories field is required (drives above-show-more placement) */
6452
isCategoryRequired: boolean;
6553

66-
/** Whether the date field should be displayed */
67-
shouldShowDate: boolean;
68-
69-
/** Whether the tax field should be displayed */
70-
shouldShowTax: boolean;
71-
7254
/** Whether tax field modifications are allowed */
7355
canModifyTaxFields: boolean;
7456

75-
/** Whether the attendees field should be displayed */
76-
shouldShowAttendees: boolean;
77-
7857
/** Whether to display per-field validation errors */
7958
shouldDisplayFieldError: boolean;
8059

@@ -95,6 +74,9 @@ type ClassificationFieldsProps = {
9574

9675
/** When true, suppresses optional fields (only required Category + required Tags render) */
9776
isCompactMode: boolean;
77+
78+
/** Per-field visibility decisions resolved by `computeFieldVisibility` */
79+
fieldVisibility: Pick<FieldVisibility, 'categoryRequired' | 'categoryOptional' | 'date' | 'tagsRequired' | 'tagsOptional' | 'tax' | 'attendees'>;
9880
};
9981

10082
function ClassificationFields({
@@ -107,41 +89,49 @@ function ClassificationFields({
10789
policy,
10890
policyForMovingExpenses,
10991
policyTagLists,
110-
tagVisibility,
11192
previousTagsVisibility,
11293
isReadOnly,
11394
didConfirm,
114-
shouldShowCategories,
11595
isCategoryRequired,
116-
shouldShowDate,
117-
shouldShowTax,
11896
canModifyTaxFields,
119-
shouldShowAttendees,
12097
shouldDisplayFieldError,
12198
shouldNavigateToUpgradePath,
12299
shouldSelectPolicy,
123100
iouCurrencyCode,
124101
formattedAmountPerAttendee,
125102
formError,
126103
isCompactMode,
104+
fieldVisibility,
127105
}: ClassificationFieldsProps) {
128-
const showCategory = shouldShowCategories && (isCompactMode ? isCategoryRequired : true);
129-
130-
const visibleTagEntries = policyTagLists
131-
.map(({name}, index) => {
132-
const tagVisibilityItem = tagVisibility.at(index);
133-
return {
134-
name,
135-
index,
136-
isTagRequired: tagVisibilityItem?.isTagRequired ?? false,
137-
tagShouldShow: tagVisibilityItem?.shouldShow ?? false,
138-
};
139-
})
140-
.filter(({tagShouldShow, isTagRequired}) => tagShouldShow && (isCompactMode ? isTagRequired : true));
106+
const renderTagFields = (entries: TagEntry[]) =>
107+
entries.map(({name, index, isTagRequired}) => {
108+
const policyTagList = policyTagLists.at(index);
109+
if (!policyTagList) {
110+
return null;
111+
}
112+
return (
113+
<TagFields
114+
key={`tag_${name}`}
115+
tagIndex={index}
116+
policyTagList={policyTagList}
117+
isTagRequired={isTagRequired}
118+
previousShouldShow={previousTagsVisibility.at(index) ?? false}
119+
didConfirm={didConfirm}
120+
isReadOnly={isReadOnly}
121+
transactionID={transactionID}
122+
action={action}
123+
iouType={iouType}
124+
reportID={reportID}
125+
reportActionID={reportActionID}
126+
transaction={transaction}
127+
formError={formError}
128+
/>
129+
);
130+
});
141131

142132
return (
143133
<>
144-
{showCategory && (
134+
{(fieldVisibility.categoryRequired || (!isCompactMode && fieldVisibility.categoryOptional)) && (
145135
<CategoryField
146136
isCategoryRequired={isCategoryRequired}
147137
didConfirm={didConfirm}
@@ -159,7 +149,7 @@ function ClassificationFields({
159149
/>
160150
)}
161151

162-
{!isCompactMode && shouldShowDate && (
152+
{!isCompactMode && fieldVisibility.date && (
163153
<DateField
164154
shouldDisplayFieldError={shouldDisplayFieldError}
165155
didConfirm={didConfirm}
@@ -173,32 +163,11 @@ function ClassificationFields({
173163
/>
174164
)}
175165

176-
{visibleTagEntries.map(({name, index, isTagRequired}) => {
177-
const policyTagList = policyTagLists.at(index);
178-
if (!policyTagList) {
179-
return null;
180-
}
181-
return (
182-
<TagFields
183-
key={`tag_${name}`}
184-
tagIndex={index}
185-
policyTagList={policyTagList}
186-
isTagRequired={isTagRequired}
187-
previousShouldShow={previousTagsVisibility.at(index) ?? false}
188-
didConfirm={didConfirm}
189-
isReadOnly={isReadOnly}
190-
transactionID={transactionID}
191-
action={action}
192-
iouType={iouType}
193-
reportID={reportID}
194-
reportActionID={reportActionID}
195-
transaction={transaction}
196-
formError={formError}
197-
/>
198-
);
199-
})}
200-
201-
{!isCompactMode && shouldShowTax && (
166+
{renderTagFields(fieldVisibility.tagsRequired)}
167+
168+
{!isCompactMode && renderTagFields(fieldVisibility.tagsOptional)}
169+
170+
{!isCompactMode && fieldVisibility.tax && (
202171
<TaxFields
203172
policy={policy}
204173
policyForMovingExpenses={policyForMovingExpenses}
@@ -214,7 +183,7 @@ function ClassificationFields({
214183
/>
215184
)}
216185

217-
{!isCompactMode && shouldShowAttendees && (
186+
{!isCompactMode && fieldVisibility.attendees && (
218187
<AttendeeField
219188
formattedAmountPerAttendee={formattedAmountPerAttendee}
220189
isReadOnly={isReadOnly}

src/components/MoneyRequestConfirmationListFooter/fieldGroups/SettingsFields.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type CONST from '@src/CONST';
66
import type {IOUAction, IOUType} from '@src/CONST';
77
import type * as OnyxTypes from '@src/types/onyx';
88
import type {Participant} from '@src/types/onyx/IOU';
9+
import type {FieldVisibility} from './fieldVisibility';
910

1011
type SettingsFieldsProps = {
1112
/** Action being performed (drives section navigation targets) */
@@ -52,6 +53,9 @@ type SettingsFieldsProps = {
5253

5354
/** When true, suppresses all fields in this group (all are below show-more) */
5455
isCompactMode: boolean;
56+
57+
/** Per-field visibility decisions resolved by `computeFieldVisibility` */
58+
fieldVisibility: Pick<FieldVisibility, 'toggles' | 'report'>;
5559
};
5660

5761
/**
@@ -75,14 +79,14 @@ function SettingsFields({
7579
onToggleReimbursable,
7680
onToggleBillable,
7781
isCompactMode,
82+
fieldVisibility,
7883
}: SettingsFieldsProps) {
7984
if (isCompactMode) {
8085
return null;
8186
}
82-
const showToggles = shouldShowReimbursable || shouldShowBillable;
8387
return (
8488
<>
85-
{showToggles && (
89+
{fieldVisibility.toggles && (
8690
<ToggleFields
8791
isReadOnly={isReadOnly}
8892
shouldShowReimbursable={shouldShowReimbursable}
@@ -92,7 +96,7 @@ function SettingsFields({
9296
transaction={transaction}
9397
/>
9498
)}
95-
{isPolicyExpenseChat && (
99+
{fieldVisibility.report && (
96100
<ReportField
97101
selectedParticipants={selectedParticipants}
98102
isPolicyExpenseChat={isPolicyExpenseChat}

0 commit comments

Comments
 (0)