From 9718b3a4516a5c97521dd0a11c68d140f2d73b04 Mon Sep 17 00:00:00 2001 From: Aditya Khatri <aditya.khatri@togglecorp.com> Date: Thu, 25 Jun 2020 16:08:26 +0545 Subject: [PATCH 1/4] Add lead assignee information in entries listing page * Set entry creator as default assignee in all entry comments --- .../general/EntryCommentModal/index.js | 7 ++- src/entities/editEntries.js | 2 + src/redux/initial-state/dev-lang.json | 12 +++-- src/schema/entries.js | 15 ++++++ .../List/WidgetFaramContainer/index.js | 1 + src/views/EditEntries/Overview/index.js | 2 +- .../Entries/FilterEntriesForm/GeoFilter.js | 2 +- .../Entries/LeadGroupedEntries/Entry/index.js | 2 + src/views/Entries/LeadGroupedEntries/index.js | 46 +++++++++++++++---- .../Entries/LeadGroupedEntries/styles.scss | 28 +++++++---- src/views/LeadAdd/LeadDetail/index.js | 2 +- 11 files changed, 93 insertions(+), 26 deletions(-) diff --git a/src/components/general/EntryCommentModal/index.js b/src/components/general/EntryCommentModal/index.js index fc1ef26cc4..9a592124cc 100644 --- a/src/components/general/EntryCommentModal/index.js +++ b/src/components/general/EntryCommentModal/index.js @@ -43,6 +43,7 @@ const propTypes = { projectId: PropTypes.number, // eslint-disable-line react/no-unused-prop-types entryServerId: PropTypes.number, onCommentsCountChange: PropTypes.func.isRequired, + defaultAssignee: PropTypes.number, requests: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types }; @@ -51,6 +52,7 @@ const defaultProps = { projectId: undefined, entryServerId: undefined, closeModal: undefined, + defaultAssignee: undefined, }; const RESOLVED = 'resolved'; @@ -150,6 +152,7 @@ export default class EntryCommentModal extends React.PureComponent { requests: { entryCommentsGet, }, + defaultAssignee, } = this.props; entryCommentsGet.setDefaultParams({ @@ -160,7 +163,9 @@ export default class EntryCommentModal extends React.PureComponent { activeTabKey: UNRESOLVED, comments: [], currentEdit: undefined, - faramValues: {}, + faramValues: { + assignee: defaultAssignee, + }, faramErrors: {}, globalPristine: true, pristine: true, diff --git a/src/entities/editEntries.js b/src/entities/editEntries.js index 026552acb6..8bd9049704 100644 --- a/src/entities/editEntries.js +++ b/src/entities/editEntries.js @@ -46,6 +46,7 @@ export const entryAccessor = { tabularField: entry => getDataSafe(entry).tabularField, order: entry => getDataSafe(entry).order, serverId: entry => getDataSafe(entry).id, + createdBy: entry => getDataSafe(entry).createdBy, unresolvedCommentCount: entry => getServerDataSafe(entry).unresolvedCommentCount || 0, versionId: entry => getServerDataSafe(entry).versionId, @@ -179,6 +180,7 @@ export const createEntry = ({ 'exportData', 'filterData', 'createdAt', + 'createdBy', ]; const pickedData = pick(data, keysToPick); diff --git a/src/redux/initial-state/dev-lang.json b/src/redux/initial-state/dev-lang.json index 7a33f401d3..019603ca21 100644 --- a/src/redux/initial-state/dev-lang.json +++ b/src/redux/initial-state/dev-lang.json @@ -1128,7 +1128,8 @@ "-72546396": "{privateProjects} Private Projects", "-59460837": "This framework is used by private projects you are not a part of.", "-61550815": "Widgets Preview", - "-40186961": "View Details" + "-40186961": "View Details", + "-91728706": "Extract lead information from attached document\t" }, "links": { "browserExtension": { @@ -1585,7 +1586,9 @@ "entryGroupsFilterPlaceholder": 14, "entryLabelsFilterPlaceholder": 14, "entryLabelsFilterLabel": -80269151, - "entryGroupsHeaderTooltip": -47675119 + "entryGroupsHeaderTooltip": -47675119, + "assigneeIconTitle": 6, + "calendarIconTitle": 163 }, "export": { "headerExport": 600, @@ -1864,7 +1867,8 @@ "searchInputEmptyText": -24511724, "authorPlaceholder": -4332303, "formatButtonTitle": -50025578, - "suggestionsLabel": -75552913 + "suggestionsLabel": -75552913, + "extractLeadFromDocument": -91728706 }, "addLeads.actions": { "deleteLeadConfirmText": 133, @@ -3242,4 +3246,4 @@ "importQuestionnaireFromXLSFormButtonLabel": -37971354 } } -} +} \ No newline at end of file diff --git a/src/schema/entries.js b/src/schema/entries.js index 0211b71192..462cc01e3a 100644 --- a/src/schema/entries.js +++ b/src/schema/entries.js @@ -144,6 +144,21 @@ const entrySchema = []; createdAt: { type: 'string', required: true }, // date // createdBy: { type: 'uint' }, id: { type: 'uint', required: true }, + assignee: { type: 'array.uint' }, + assigneeDetails: { + type: { + doc: { + name: 'assigneeDetails', + description: 'Assignee details of lead', + }, + fields: { + id: { type: 'uint' }, + displayName: { type: 'string' }, + displayPicture: { type: 'uint' }, + email: { type: 'string' }, + }, + }, + }, // source: { type: 'string' }, title: { type: 'string' }, url: { type: 'string' }, diff --git a/src/views/EditEntries/List/WidgetFaramContainer/index.js b/src/views/EditEntries/List/WidgetFaramContainer/index.js index 594c67cec7..161cae8cf4 100644 --- a/src/views/EditEntries/List/WidgetFaramContainer/index.js +++ b/src/views/EditEntries/List/WidgetFaramContainer/index.js @@ -228,6 +228,7 @@ export default class WidgetFaramContainer extends React.PureComponent { <EntryCommentModal entryServerId={entryServerId} onCommentsCountChange={this.handleCommentsCountChange} + defaultAssignee={entryAccessor.createdBy(entry)} /> } iconName="chat" diff --git a/src/views/EditEntries/Overview/index.js b/src/views/EditEntries/Overview/index.js index 483a4d5c53..e9e2cfd775 100644 --- a/src/views/EditEntries/Overview/index.js +++ b/src/views/EditEntries/Overview/index.js @@ -235,7 +235,6 @@ export default class Overview extends React.PureComponent { const { entry, leadId, - entries, lead, analysisFramework, statuses, @@ -335,6 +334,7 @@ export default class Overview extends React.PureComponent { onCommentsCountChange={ this.handleCommentsCountChange } + defaultAssignee={entryAccessor.createdBy(entry)} /> } iconName="chat" diff --git a/src/views/Entries/FilterEntriesForm/GeoFilter.js b/src/views/Entries/FilterEntriesForm/GeoFilter.js index b1af82820f..dcd8e2d492 100644 --- a/src/views/Entries/FilterEntriesForm/GeoFilter.js +++ b/src/views/Entries/FilterEntriesForm/GeoFilter.js @@ -22,7 +22,7 @@ const defaultProps = { label: '', disabled: false, value: { - includeSubRegions: false, + includeSubRegions: true, areas: [], }, }; diff --git a/src/views/Entries/LeadGroupedEntries/Entry/index.js b/src/views/Entries/LeadGroupedEntries/Entry/index.js index b4a759635f..7183872d14 100644 --- a/src/views/Entries/LeadGroupedEntries/Entry/index.js +++ b/src/views/Entries/LeadGroupedEntries/Entry/index.js @@ -189,6 +189,7 @@ export default class Entry extends React.PureComponent { widgets, entry: { id: entryId, + createdBy, attributes, unresolvedCommentCount: commentCount, projectLabels, @@ -221,6 +222,7 @@ export default class Entry extends React.PureComponent { <EntryCommentModal entryServerId={entryId} onCommentsCountChange={this.handleCommentsCountChange} + defaultAssignee={createdBy} /> } iconName="chat" diff --git a/src/views/Entries/LeadGroupedEntries/index.js b/src/views/Entries/LeadGroupedEntries/index.js index 53f16c715b..951267e32b 100644 --- a/src/views/Entries/LeadGroupedEntries/index.js +++ b/src/views/Entries/LeadGroupedEntries/index.js @@ -83,6 +83,8 @@ export default class LeadGroupedEntries extends React.PureComponent { entries, url: leadUrlFromProps, attachment, + assignee, + assigneeDetails, } = lead; const route = reverseRoute(pathNames.editEntries, { @@ -96,11 +98,11 @@ export default class LeadGroupedEntries extends React.PureComponent { return ( <div className={_cs(classNameFromProps, styles.leadGroupedEntries)}> <header className={_cs(headerClassNameFromProps, styles.header)}> - <h3 - title={leadTitle} - className={styles.heading} - > - <div className={styles.title}> + <h3 className={styles.heading}> + <div + title={leadTitle} + className={styles.title} + > {leadUrl ? ( <ModalButton className={styles.leadTitleButton} @@ -115,11 +117,35 @@ export default class LeadGroupedEntries extends React.PureComponent { leadTitle )} </div> - <FormattedDate - className={styles.date} - date={leadCreatedAt} - mode="dd-MM-yyyy" - /> + <div className={styles.leadDetails}> + <Icon + title={_ts('entries', 'calendarIconTitle')} + name="calendar" + /> + <FormattedDate + className={styles.date} + date={leadCreatedAt} + mode="dd-MM-yyyy" + /> + {assignee && assignee[0] && ( + <> + <Icon + title={_ts('entries', 'assigneeIconTitle')} + name="user" + /> + <Link + key={assignee} + className={styles.assigneeLink} + to={reverseRoute( + pathNames.userProfile, + { userId: assignee }, + )} + > + {assigneeDetails.displayName} + </Link> + </> + )} + </div> </h3> <div title={_ts('entries', 'numberOfEntriesTooltip')} diff --git a/src/views/Entries/LeadGroupedEntries/styles.scss b/src/views/Entries/LeadGroupedEntries/styles.scss index b3b8082882..8eab8aba7d 100644 --- a/src/views/Entries/LeadGroupedEntries/styles.scss +++ b/src/views/Entries/LeadGroupedEntries/styles.scss @@ -12,13 +12,11 @@ color: var(--color-text-on-background-header); .heading { - display: flex; - align-items: baseline; flex-grow: 1; overflow: hidden; .title { - padding: var(--spacing-small-alt) var(--spacing-small-alt) var(--spacing-small-alt) var(--spacing-medium); + padding: var(--spacing-small-alt) var(--spacing-small-alt) 0 var(--spacing-medium); overflow: hidden; text-transform: none; text-overflow: ellipsis; @@ -35,11 +33,25 @@ } } - .date { - flex-shrink: 0; - padding: var(--spacing-small); - color: var(--color-text-label); - font-size: var(--font-size-medium); + .lead-details { + display: flex; + align-items: center; + padding: 0 var(--spacing-small-alt); + color: var(--color-text); + + .date { + flex-shrink: 0; + margin-right: var(--spacing-small); + padding: var(--spacing-small); + color: var(--color-text-label); + font-size: var(--font-size-medium); + } + + .assignee-link { + @extend %accent-color-link; + padding: var(--spacing-small); + font-size: var(--font-size-medium); + } } } diff --git a/src/views/LeadAdd/LeadDetail/index.js b/src/views/LeadAdd/LeadDetail/index.js index bb6450ad31..3954896edd 100644 --- a/src/views/LeadAdd/LeadDetail/index.js +++ b/src/views/LeadAdd/LeadDetail/index.js @@ -909,7 +909,7 @@ class LeadDetail extends React.PureComponent { <AccentButton transparent className={styles.extractButton} - title={_ts('addLeads', 'extractLead')} + title={_ts('addLeads', 'extractLeadFromDocument')} disabled={formDisabled || extractionForFileDisabled} onClick={this.handleExtractClickForFiles} tabIndex="-1" From 932d590d5136ab3fc52037bdeea8db08243b326e Mon Sep 17 00:00:00 2001 From: Aditya Khatri <aditya.khatri@togglecorp.com> Date: Thu, 25 Jun 2020 16:22:05 +0545 Subject: [PATCH 2/4] Use links for owners instead of badge * Remove conditional visibility of polygons based on feature access --- .../GeoInput/GeoModal/GeoInputList/index.js | 4 +-- src/components/input/GeoInput/index.js | 26 +--------------- src/components/viewer/EntityLink/index.tsx | 30 +++++++++++++++++++ src/components/viewer/EntityLink/styles.scss | 6 ++++ src/constants/features.js | 1 - src/views/Entries/LeadGroupedEntries/index.js | 11 ++++--- .../Entries/LeadGroupedEntries/styles.scss | 2 -- .../Frameworks/FrameworkDetail/index.js | 9 +++--- .../Frameworks/FrameworkDetail/styles.scss | 15 ++++++++++ 9 files changed, 64 insertions(+), 40 deletions(-) create mode 100644 src/components/viewer/EntityLink/index.tsx create mode 100644 src/components/viewer/EntityLink/styles.scss diff --git a/src/components/input/GeoInput/GeoModal/GeoInputList/index.js b/src/components/input/GeoInput/GeoModal/GeoInputList/index.js index a6a590969f..19d8b5fb8a 100644 --- a/src/components/input/GeoInput/GeoModal/GeoInputList/index.js +++ b/src/components/input/GeoInput/GeoModal/GeoInputList/index.js @@ -231,7 +231,7 @@ const GeoInputList = (props) => { ); const groupKeySelector = useCallback( (selection) => { - const { adminLevel, region } = geoOptionsById[selection.id]; + const { adminLevel, region } = geoOptionsById[selection.id] || {}; return `${region}-${adminLevel}`; }, [geoOptionsById], @@ -245,7 +245,7 @@ const GeoInputList = (props) => { disabled: !!value.polygons || isNotDefined(onSelectionsChange), readOnly, - value: geoOptionsById[key].title, + value: geoOptionsById[key] ? geoOptionsById[key].title : undefined, polygons: value.polygons, }), [handleSelectionRemove, geoOptionsById, onSelectionsChange, readOnly], diff --git a/src/components/input/GeoInput/index.js b/src/components/input/GeoInput/index.js index d5f3c5eb01..590282f2a4 100644 --- a/src/components/input/GeoInput/index.js +++ b/src/components/input/GeoInput/index.js @@ -1,6 +1,5 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { connect } from 'react-redux'; import memoize from 'memoize-one'; import { _cs, @@ -14,9 +13,6 @@ import { FaramInputElement } from '@togglecorp/faram'; import AccentButton from '#rsca/Button/AccentButton'; import SearchMultiSelectInput from '#rsci/SearchMultiSelectInput'; -import featuresMapping from '#constants/features'; - -import { activeUserSelector } from '#redux'; import GeoInputList from './GeoModal/GeoInputList'; import GeoModal from './GeoModal'; @@ -26,15 +22,8 @@ const MAX_DISPLAY_OPTIONS = 100; const keySelector = v => v.key; -const mapStateToProps = state => ({ - activeUser: activeUserSelector(state), -}); - const propTypes = { className: PropTypes.string, - activeUser: PropTypes.shape({ - accessibleFeatures: PropTypes.array, - }), onChange: PropTypes.func, geoOptionsByRegion: PropTypes.object, // eslint-disable-line react/forbid-prop-types @@ -66,7 +55,6 @@ const defaultProps = { className: undefined, label: undefined, showLabel: true, - activeUser: {}, onChange: undefined, geoOptionsByRegion: {}, disabled: false, @@ -86,7 +74,6 @@ const defaultProps = { }; @FaramInputElement -@connect(mapStateToProps, undefined) export default class GeoInput extends React.PureComponent { static propTypes = propTypes; static defaultProps = defaultProps; @@ -215,9 +202,6 @@ export default class GeoInput extends React.PureComponent { hideList, polygonsEnabled, - activeUser: { - accessibleFeatures = [], - }, icons, } = this.props; @@ -233,14 +217,6 @@ export default class GeoInput extends React.PureComponent { const polygons = this.getPolygons(value); const options = this.getAllGeoOptions(geoOptionsByRegion); - // NOTE: why not move this to GeoModal - const polygonSupportIndex = accessibleFeatures - .findIndex(f => f.key === featuresMapping.polygonSupportGeo); - - const isPolygonFeatureEnabled = polygonSupportIndex !== -1; - - const shouldEnablePolygon = isPolygonFeatureEnabled && polygonsEnabled; - return ( <div className={className}> <div className={styles.inputContainer}> @@ -308,7 +284,7 @@ export default class GeoInput extends React.PureComponent { onApply={this.handleModalApply} onCancel={this.handleModalCancel} - polygonsEnabled={shouldEnablePolygon} + polygonsEnabled={polygonsEnabled} /> )} </div> diff --git a/src/components/viewer/EntityLink/index.tsx b/src/components/viewer/EntityLink/index.tsx new file mode 100644 index 0000000000..d7722bea8f --- /dev/null +++ b/src/components/viewer/EntityLink/index.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { _cs } from '@togglecorp/fujs'; + +import styles from './styles.scss'; + +interface Props { + className?: string; + title: string; + link: string; +} + +function EntityLink(props: Props) { + const { + className, + title, + link, + } = props; + + return ( + <Link + className={_cs(className, styles.link)} + to={link} + > + {title} + </Link> + ); +} + +export default EntityLink; diff --git a/src/components/viewer/EntityLink/styles.scss b/src/components/viewer/EntityLink/styles.scss new file mode 100644 index 0000000000..ba2362e125 --- /dev/null +++ b/src/components/viewer/EntityLink/styles.scss @@ -0,0 +1,6 @@ +@import '~base-scss/utils'; + +.link { + @extend %accent-color-link; + padding: var(--spacing-extra-small); +} diff --git a/src/constants/features.js b/src/constants/features.js index 0ce0aa6ff7..c7c49c20e3 100644 --- a/src/constants/features.js +++ b/src/constants/features.js @@ -1,6 +1,5 @@ // eslint-disable-next-line import/prefer-default-export const featuresMapping = { - polygonSupportGeo: 'polygon_support_geo', zoomableImage: 'zoomable_image', privateProject: 'private_project', entryVizConfig: 'entry_visualization_configuration', diff --git a/src/views/Entries/LeadGroupedEntries/index.js b/src/views/Entries/LeadGroupedEntries/index.js index 951267e32b..c81d5c0ed5 100644 --- a/src/views/Entries/LeadGroupedEntries/index.js +++ b/src/views/Entries/LeadGroupedEntries/index.js @@ -13,6 +13,7 @@ import Button from '#rsca/Button'; import modalize from '#rscg/Modalize'; import Cloak from '#components/general/Cloak'; +import EntityLink from '#components/viewer/EntityLink'; import LeadPreview from '#views/Leads/LeadPreview'; import { pathNames, @@ -133,16 +134,14 @@ export default class LeadGroupedEntries extends React.PureComponent { title={_ts('entries', 'assigneeIconTitle')} name="user" /> - <Link - key={assignee} + <EntityLink className={styles.assigneeLink} - to={reverseRoute( + link={reverseRoute( pathNames.userProfile, { userId: assignee }, )} - > - {assigneeDetails.displayName} - </Link> + title={assigneeDetails.displayName} + /> </> )} </div> diff --git a/src/views/Entries/LeadGroupedEntries/styles.scss b/src/views/Entries/LeadGroupedEntries/styles.scss index 8eab8aba7d..2ba283de19 100644 --- a/src/views/Entries/LeadGroupedEntries/styles.scss +++ b/src/views/Entries/LeadGroupedEntries/styles.scss @@ -48,8 +48,6 @@ } .assignee-link { - @extend %accent-color-link; - padding: var(--spacing-small); font-size: var(--font-size-medium); } } diff --git a/src/views/Project/Details/Frameworks/FrameworkDetail/index.js b/src/views/Project/Details/Frameworks/FrameworkDetail/index.js index 5d74182fc8..92f4a02746 100644 --- a/src/views/Project/Details/Frameworks/FrameworkDetail/index.js +++ b/src/views/Project/Details/Frameworks/FrameworkDetail/index.js @@ -18,6 +18,7 @@ import Button from '#rsca/Button'; import AccentButton from '#rsca/Button/AccentButton'; import modalize from '#rscg/Modalize'; import Badge from '#components/viewer/Badge'; +import EntityLink from '#components/viewer/EntityLink'; import { RequestClient, @@ -113,9 +114,9 @@ const requestOptions = { const keySelector = u => u.id; const userRendererParams = (_, u) => ({ - className: styles.badge, + className: styles.link, title: u.displayName, - tooltip: u.email, + link: reverseRoute(pathNames.userProfile, { userId: u.id }), }); const projectRendererParams = (_, p) => ({ @@ -342,11 +343,11 @@ export default class FrameworkDetail extends React.PureComponent { {_ts('framework', 'frameworkOwnersLabel')}: </h4> <ListView - className={styles.values} + className={styles.userValues} data={usersWithAddPermission} keySelector={keySelector} rendererParams={userRendererParams} - renderer={Badge} + renderer={EntityLink} /> </div> )} diff --git a/src/views/Project/Details/Frameworks/FrameworkDetail/styles.scss b/src/views/Project/Details/Frameworks/FrameworkDetail/styles.scss index b0422782b1..5d879b4edf 100644 --- a/src/views/Project/Details/Frameworks/FrameworkDetail/styles.scss +++ b/src/views/Project/Details/Frameworks/FrameworkDetail/styles.scss @@ -94,6 +94,21 @@ margin-left: var(--spacing-extra-small); } + .user-values { + display: flex; + flex-grow: 1; + flex-wrap: wrap; + margin-left: var(--spacing-extra-small); + + .link { + &:not(:last-child) { + &:after { + content: ','; + } + } + } + } + .badge { margin: var(--spacing-extra-small); } From f31748b6a9248cf6118c21f967de61dc3928c75d Mon Sep 17 00:00:00 2001 From: Aditya Khatri <aditya.khatri@togglecorp.com> Date: Fri, 26 Jun 2020 09:50:53 +0545 Subject: [PATCH 3/4] Fix update behavior of widgets --- src/redux/initial-state/dev-lang.json | 4 ++-- src/redux/reducers/siloDomainData/analysisFramework.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/redux/initial-state/dev-lang.json b/src/redux/initial-state/dev-lang.json index 019603ca21..ba934a6144 100644 --- a/src/redux/initial-state/dev-lang.json +++ b/src/redux/initial-state/dev-lang.json @@ -738,7 +738,7 @@ "-43376795": "Failed to fetch cluster data.", "-72859218": "Project options", "-45091634": "Failed to get project options.", - "-44183195": "Modifying this framework may affect {count} entries. Are you sure you want to save these changes?", + "-44183195": "Warning: {count} number of entries will be affected if you've edited or removed widgets. Would you like to continue?", "-82545000": "Default", "-70199668": "No notifications to display", "-53914293": "Are you sure you want to remove the connector {connector}?", @@ -3246,4 +3246,4 @@ "importQuestionnaireFromXLSFormButtonLabel": -37971354 } } -} \ No newline at end of file +} diff --git a/src/redux/reducers/siloDomainData/analysisFramework.js b/src/redux/reducers/siloDomainData/analysisFramework.js index 70df030f61..2b8620642f 100644 --- a/src/redux/reducers/siloDomainData/analysisFramework.js +++ b/src/redux/reducers/siloDomainData/analysisFramework.js @@ -234,7 +234,7 @@ const afViewUpdateWidget = (state, action) => { { properties: { $auto: { data: { $auto: { - $merge: widgetData, + $set: widgetData, } }, } }, }, From ab880ede8ce08d2c1bcf1efd0f1301d60f6c2b8f Mon Sep 17 00:00:00 2001 From: tnagorra <weathermist@gmail.com> Date: Fri, 26 Jun 2020 12:38:28 +0545 Subject: [PATCH 4/4] Fix geo list bug --- .../input/GeoInput/GeoModal/GeoInputList/index.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/input/GeoInput/GeoModal/GeoInputList/index.js b/src/components/input/GeoInput/GeoModal/GeoInputList/index.js index 19d8b5fb8a..453e969850 100644 --- a/src/components/input/GeoInput/GeoModal/GeoInputList/index.js +++ b/src/components/input/GeoInput/GeoModal/GeoInputList/index.js @@ -231,7 +231,10 @@ const GeoInputList = (props) => { ); const groupKeySelector = useCallback( (selection) => { - const { adminLevel, region } = geoOptionsById[selection.id] || {}; + if (!geoOptionsById[selection.id]) { + return undefined; + } + const { adminLevel, region } = geoOptionsById[selection.id]; return `${region}-${adminLevel}`; }, [geoOptionsById], @@ -253,6 +256,12 @@ const GeoInputList = (props) => { const groupRendererParams = useCallback( (groupKey) => { + if (!groupKey) { + return { + children: 'Ungrouped', + }; + } + const [regionKey, adminLevelKey] = groupKey.split('-'); // FIXME: this can be made efficient const adminLevel = adminLevelTitles.find( @@ -262,7 +271,7 @@ const GeoInputList = (props) => { return { children: adminLevel ? `${adminLevel.regionTitle} / ${adminLevel.title}` - : '', + : 'Ungrouped', }; }, [adminLevelTitles],