Skip to content

Commit

Permalink
feat(debug mode): add ability to pick multi-level transaction tags
Browse files Browse the repository at this point in the history
  • Loading branch information
pac-guerreiro committed Nov 5, 2024
1 parent 54da244 commit 9100196
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 23 deletions.
35 changes: 21 additions & 14 deletions src/components/TagPicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@ type TagPickerProps = {
/** Should show the selected option that is disabled? */
shouldShowDisabledAndSelectedOption?: boolean;

shouldOrderListByTagName?: boolean;

/** Indicates which tag list index was selected */
tagListIndex: number;
};

function TagPicker({selectedTag, tagListName, policyID, tagListIndex, shouldShowDisabledAndSelectedOption = false, onSubmit}: TagPickerProps) {
function TagPicker({selectedTag, tagListName, policyID, tagListIndex, shouldShowDisabledAndSelectedOption = false, shouldOrderListByTagName = false, onSubmit}: TagPickerProps) {
const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`);
const [policyRecentlyUsedTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`);
const styles = useThemeStyles();
Expand Down Expand Up @@ -79,19 +81,24 @@ function TagPicker({selectedTag, tagListName, policyID, tagListIndex, shouldShow
return [...selectedOptions, ...Object.values(policyTagList.tags).filter((policyTag) => policyTag.enabled && !selectedNames.includes(policyTag.name))];
}, [selectedOptions, policyTagList, shouldShowDisabledAndSelectedOption]);

const sections = useMemo(
() =>
OptionsListUtils.getFilteredOptions({
searchValue,
selectedOptions,
includeP2P: false,
includeTags: true,
tags: enabledTags,
recentlyUsedTags: policyRecentlyUsedTagsList,
canInviteUser: false,
}).tagOptions,
[searchValue, enabledTags, selectedOptions, policyRecentlyUsedTagsList],
);
const sections = useMemo(() => {
const options = OptionsListUtils.getFilteredOptions({
searchValue,
selectedOptions,
includeP2P: false,
includeTags: true,
tags: enabledTags,
recentlyUsedTags: policyRecentlyUsedTagsList,
canInviteUser: false,
}).tagOptions;

return shouldOrderListByTagName
? options.map((option) => ({
...option,
data: option.data.sort((a, b) => a.text?.localeCompare(b.text ?? '') ?? 0),
}))
: options;
}, [searchValue, selectedOptions, enabledTags, policyRecentlyUsedTagsList, shouldOrderListByTagName]);

const headerMessage = OptionsListUtils.getHeaderMessageForNonUserList((sections?.at(0)?.data?.length ?? 0) > 0, searchValue);

Expand Down
9 changes: 4 additions & 5 deletions src/pages/Debug/DebugDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import type {ObjectType, OnyxDataType} from '@libs/DebugUtils';
import DebugUtils from '@libs/DebugUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import Debug from '@userActions/Debug';
import type CONST from '@src/CONST';
Expand Down Expand Up @@ -53,6 +54,7 @@ function DebugDetails({formType, data, children, onSave, onDelete, validate}: De
const [formDraftData] = useOnyx(ONYXKEYS.FORMS.DEBUG_DETAILS_FORM_DRAFT);
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${(data as OnyxEntry<Transaction>)?.reportID ?? ''}`);
const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID}`);
const policyTagLists = useMemo(() => PolicyUtils.getTagLists(policyTags), [policyTags]);
const booleanFields = useMemo(
() =>
Object.entries(data ?? {})
Expand All @@ -65,16 +67,13 @@ function DebugDetails({formType, data, children, onSave, onDelete, validate}: De
Object.entries(data ?? {})
.filter((entry): entry is [string, string] => {
// Tag picker needs to be hidden when the policy has no tags available to pick
if (
entry[0] === TRANSACTION_FORM_INPUT_IDS.TAG &&
!Object.values(policyTags ?? {}).some((policyTagList) => PolicyUtils.getCountOfEnabledTagsOfList(policyTagList.tags))
) {
if (entry[0] === TRANSACTION_FORM_INPUT_IDS.TAG && !OptionsListUtils.hasEnabledTags(policyTagLists)) {
return false;
}
return DETAILS_CONSTANT_FIELDS[formType].some(({fieldName}) => fieldName === entry[0]);
})
.sort((a, b) => a[0].localeCompare(b[0])),
[data, formType, policyTags],
[data, formType, policyTagLists],
);
const numberFields = useMemo(
() =>
Expand Down
7 changes: 3 additions & 4 deletions src/pages/Debug/DebugDetailsConstantPickerPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import CONST from '@src/CONST';
import type SCREENS from '@src/SCREENS';
import TRANSACTION_FORM_INPUT_IDS from '@src/types/form/DebugTransactionForm';
import ConstantPicker from './ConstantPicker';
import DebugTagPicker from './DebugTagPicker';

type DebugDetailsConstantPickerPageProps = StackScreenProps<DebugParamList, typeof SCREENS.DEBUG.DETAILS_CONSTANT_PICKER_PAGE>;

Expand Down Expand Up @@ -55,12 +56,10 @@ function DebugDetailsConstantPickerPage({
}
if (fieldName === TRANSACTION_FORM_INPUT_IDS.TAG) {
return (
<TagPicker
<DebugTagPicker
policyID={policyID}
selectedTag={fieldValue ?? ''}
tagListName=""
tagName={fieldValue}
onSubmit={onSubmit}
tagListIndex={0}
/>
);
}
Expand Down
71 changes: 71 additions & 0 deletions src/pages/Debug/DebugTagPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, {useCallback, useMemo, useState} from 'react';
import {View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
import type {ListItem} from '@components/SelectionList/types';
import TagPicker from '@components/TagPicker';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as IOUUtils from '@libs/IOUUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import ONYXKEYS from '@src/ONYXKEYS';

type DebugTagPickerProps = {
policyID: string;
tagName?: string;
onSubmit: (item: ListItem) => void;
};

function DebugTagPicker({policyID, tagName = '', onSubmit}: DebugTagPickerProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const [newTagName, setNewTagName] = useState(tagName);
const selectedTags = useMemo(() => TransactionUtils.getTagArrayFromName(newTagName), [newTagName]);
const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`);
const policyTagLists = useMemo(() => PolicyUtils.getTagLists(policyTags), [policyTags]);

const updateTagName = useCallback(
(index: number) =>
({text}: ListItem) => {
const newTag = text === selectedTags.at(index) ? undefined : text;
setNewTagName(IOUUtils.insertTagIntoTransactionTagsString(newTagName, newTag ?? '', index));
},
[newTagName, selectedTags],
);

const submitTag = useCallback(() => {
onSubmit({text: newTagName});
}, [newTagName, onSubmit]);

return (
<View style={styles.gap5}>
<View style={styles.gap5}>
{policyTagLists.map(({name}, index) => (
<View>
{policyTagLists.length > 1 && <Text style={[styles.textLabelSupportingNormal, styles.ph5, styles.mb3]}>{name}</Text>}
<TagPicker
policyID={policyID}
selectedTag={selectedTags.at(index) ?? ''}
tagListName={name}
tagListIndex={index}
shouldOrderListByTagName
onSubmit={updateTagName(index)}
/>
</View>
))}
</View>
<View style={styles.ph5}>
<Button
success
large
text={translate('common.save')}
onPress={submitTag}
/>
</View>
</View>
);
}

export default DebugTagPicker;

0 comments on commit 9100196

Please sign in to comment.