-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Categories UI/UX #26501
Categories UI/UX #26501
Changes from 46 commits
9de59bd
0de8fc9
a4e8623
ce8519c
4271f61
df09636
3136cba
8ab4fa4
16584e9
ed22582
9ec3adf
e84005d
b7a28e1
c1bedca
24b3f85
b8acd96
678b4c6
2b481b2
9064496
8ef7ad3
b2bd62e
30210f7
5212989
c6eaa66
46ef605
136db9d
323184b
e96b876
a83a539
b1c72c4
a688c13
d2cf77a
f89e2f3
1d1ee6d
75e808d
099c1fc
c2ad63e
b55359e
0e0f317
e49f2dd
d7e1560
c2980fe
278b103
d59ddb1
4cdf856
10a711a
c6f425f
90dd075
748dcfc
5acfae0
b5d1657
c3a77d1
0fbc6d1
1a7cb65
3d47748
305b6a2
b61d13a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -236,6 +236,9 @@ const ONYXKEYS = { | |
// Max width supported for HTML <canvas> element | ||
MAX_CANVAS_WIDTH: 'maxCanvasWidth', | ||
|
||
// A list of recently used categories of a policy | ||
RECENTLY_USED_POLICY_CATEGORIES: 'recentlyUsedPolicyCategories_', | ||
|
||
/** Collection Keys */ | ||
COLLECTION: { | ||
DOWNLOAD: 'download_', | ||
|
@@ -371,11 +374,12 @@ type OnyxValues = { | |
[ONYXKEYS.MAX_CANVAS_AREA]: number; | ||
[ONYXKEYS.MAX_CANVAS_HEIGHT]: number; | ||
[ONYXKEYS.MAX_CANVAS_WIDTH]: number; | ||
[ONYXKEYS.RECENTLY_USED_POLICY_CATEGORIES]: OnyxTypes.PolicyCategory[]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This collection is going to be an array of strings: https://github.com/Expensify/App/pull/26920/files#diff-03cc167466f0d1a888135cad7c8fbfd44d5d3385c7bd4409e2585b1feac20c7c, not policy category objects themselves. So we should change to reflect the type that will get added in that PR. |
||
|
||
// Collections | ||
[ONYXKEYS.COLLECTION.DOWNLOAD]: OnyxTypes.Download; | ||
[ONYXKEYS.COLLECTION.POLICY]: OnyxTypes.Policy; | ||
[ONYXKEYS.COLLECTION.POLICY_CATEGORIES]: unknown; | ||
[ONYXKEYS.COLLECTION.POLICY_CATEGORIES]: OnyxTypes.PolicyCategory; | ||
[ONYXKEYS.COLLECTION.POLICY_MEMBERS]: OnyxTypes.PolicyMember; | ||
[ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST]: OnyxTypes.PolicyMember; | ||
[ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT]: Record<string, number>; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,11 +14,23 @@ const propTypes = { | |
/* Onyx Props */ | ||
/** Collection of categories attached to a policy */ | ||
policyCategories: PropTypes.objectOf(categoryPropTypes), | ||
|
||
/* Onyx Props */ | ||
/** Collection of categories attached to a policy */ | ||
recentlyUsedPolicyCategories: PropTypes.arrayOf(categoryPropTypes), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be an array of strings. |
||
|
||
/* Onyx Props */ | ||
/** Holds data related to Money Request view state, rather than the underlying Money Request data. */ | ||
iou: PropTypes.shape({ | ||
category: PropTypes.string.isRequired, | ||
}), | ||
}; | ||
|
||
const defaultProps = { | ||
policyID: '', | ||
policyCategories: null, | ||
policyCategories: {}, | ||
recentlyUsedPolicyCategories: [], | ||
iou: {}, | ||
}; | ||
|
||
export {propTypes, defaultProps}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,94 @@ | ||
import React, {useMemo} from 'react'; | ||
import _ from 'underscore'; | ||
import React, {useMemo, useState} from 'react'; | ||
import {withOnyx} from 'react-native-onyx'; | ||
import _ from 'underscore'; | ||
import lodashGet from 'lodash/get'; | ||
import ONYXKEYS from '../../ONYXKEYS'; | ||
import {propTypes, defaultProps} from './categoryPickerPropTypes'; | ||
import OptionsList from '../OptionsList'; | ||
import styles from '../../styles/styles'; | ||
import ScreenWrapper from '../ScreenWrapper'; | ||
import Navigation from '../../libs/Navigation/Navigation'; | ||
import ROUTES from '../../ROUTES'; | ||
import CONST from '../../CONST'; | ||
import * as IOU from '../../libs/actions/IOU'; | ||
import * as OptionsListUtils from '../../libs/OptionsListUtils'; | ||
import OptionsSelector from '../OptionsSelector'; | ||
import useLocalize from '../../hooks/useLocalize'; | ||
|
||
function CategoryPicker({policyCategories, reportID, policyID, iouType, iou, recentlyUsedPolicyCategories}) { | ||
const {translate} = useLocalize(); | ||
const [searchValue, setSearchValue] = useState(''); | ||
|
||
const policyCategoriesAmount = _.size(policyCategories); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
function CategoryPicker({policyCategories, reportID, iouType}) { | ||
const sections = useMemo(() => { | ||
const categoryList = _.chain(policyCategories) | ||
.values() | ||
.map((category) => ({ | ||
text: category.name, | ||
keyForList: category.name, | ||
tooltipText: category.name, | ||
})) | ||
.value(); | ||
const selectedOptions = useMemo(() => { | ||
if (!iou.category) { | ||
return []; | ||
} | ||
|
||
return [ | ||
{ | ||
data: categoryList, | ||
name: iou.category, | ||
enabled: true, | ||
accountID: null, | ||
}, | ||
]; | ||
}, [policyCategories]); | ||
}, [iou.category]); | ||
|
||
const initialFocusedIndex = useMemo(() => { | ||
if (policyCategoriesAmount < CONST.CATEGORY_LIST_THRESHOLD && selectedOptions.length > 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NAB: You could make this a bit cleaner by assigning |
||
return _.chain(policyCategories) | ||
.values() | ||
.findIndex((category) => category.name === selectedOptions[0].name, true) | ||
.value(); | ||
} | ||
|
||
return 0; | ||
}, [policyCategories, policyCategoriesAmount, selectedOptions]); | ||
|
||
const sections = useMemo( | ||
() => OptionsListUtils.getNewChatOptions({}, {}, [], searchValue, selectedOptions, [], false, false, true, policyCategories, recentlyUsedPolicyCategories, false).categoryOptions, | ||
[policyCategories, recentlyUsedPolicyCategories, searchValue, selectedOptions], | ||
); | ||
|
||
const headerMessage = OptionsListUtils.getHeaderMessage(lodashGet(sections, '[0].data.length', 0) > 0, false, searchValue); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi, issue: #28078 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rushatgabhane, is it fixed already or I can work on it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's fixed in the linked issue |
||
const shouldShowTextInput = policyCategoriesAmount >= CONST.CATEGORY_LIST_THRESHOLD; | ||
|
||
const navigateBack = () => { | ||
Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID)); | ||
}; | ||
|
||
const updateCategory = (category) => { | ||
if (category.searchText === iou.category) { | ||
IOU.resetMoneyRequestCategory(); | ||
} else { | ||
IOU.setMoneyRequestCategory( | ||
{ | ||
name: category.searchText, | ||
enabled: true, | ||
}, | ||
policyID, | ||
recentlyUsedPolicyCategories, | ||
); | ||
} | ||
|
||
navigateBack(); | ||
}; | ||
|
||
return ( | ||
<ScreenWrapper includeSafeAreaPaddingBottom={false}> | ||
{({safeAreaPaddingBottomStyle}) => ( | ||
<OptionsList | ||
optionHoveredStyle={styles.hoveredComponentBG} | ||
contentContainerStyles={[safeAreaPaddingBottomStyle]} | ||
sections={sections} | ||
onSelectRow={navigateBack} | ||
/> | ||
)} | ||
</ScreenWrapper> | ||
<OptionsSelector | ||
optionHoveredStyle={styles.hoveredComponentBG} | ||
sections={sections} | ||
selectedOptions={selectedOptions} | ||
value={searchValue} | ||
initialFocusedIndex={initialFocusedIndex} | ||
headerMessage={headerMessage} | ||
shouldShowTextInput={shouldShowTextInput} | ||
textInputLabel={translate('common.search')} | ||
boldStyle | ||
highlightSelectedOptions | ||
isRowMultilineSupported | ||
onChangeText={setSearchValue} | ||
onSelectRow={updateCategory} | ||
/> | ||
); | ||
} | ||
|
||
|
@@ -53,4 +100,10 @@ export default withOnyx({ | |
policyCategories: { | ||
key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, | ||
}, | ||
recentlyUsedPolicyCategories: { | ||
key: ({policyID}) => `${ONYXKEYS.RECENTLY_USED_POLICY_CATEGORIES}${policyID}`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, we'll need to use the |
||
}, | ||
iou: { | ||
key: ONYXKEYS.IOU, | ||
}, | ||
})(CategoryPicker); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -171,7 +171,7 @@ function MoneyRequestConfirmationList(props) { | |
const {unit, rate, currency} = props.mileageRate; | ||
const distance = lodashGet(transaction, 'routes.route0.distance', 0); | ||
const shouldCalculateDistanceAmount = props.isDistanceRequest && props.iouAmount === 0; | ||
const shouldCategoryEditable = !_.isEmpty(props.policyCategories) && !props.isDistanceRequest; | ||
const shouldCategoryBeEditable = !_.isEmpty(props.policyCategories); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll need to check if someone is on the beta here as per my comment here: |
||
|
||
const formattedAmount = CurrencyUtils.convertToDisplayString( | ||
shouldCalculateDistanceAmount ? DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate) : props.iouAmount, | ||
|
@@ -484,7 +484,7 @@ function MoneyRequestConfirmationList(props) { | |
disabled={didConfirm || props.isReadOnly || !isTypeRequest} | ||
/> | ||
)} | ||
{shouldCategoryEditable && ( | ||
{shouldCategoryBeEditable && ( | ||
<MenuItemWithTopDescription | ||
shouldShowRightIcon={!props.isReadOnly} | ||
title={props.iouCategory} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be part of the collection keys down below. However, it's getting added in #26920
So you could merge that into your branch here and delete this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more details here btw: #24463 (comment)