@selfcommunity/react-ui 0.11.0-alpha.101 → 0.11.0-alpha.103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -377,13 +377,13 @@ function Composer(inProps) {
377
377
  else if (event || (value && Object.prototype.hasOwnProperty.call(value, 'recurring'))) {
378
378
  dispatch({ type: 'event', value });
379
379
  }
380
- else if ((Array.isArray(value) &&
381
- value.some((item) => (typeof item === 'object' && item !== null && !('color' in item)) || typeof item === 'string')) ||
382
- (Array.isArray(recipients) && recipients.length > 0)) {
380
+ else if ((value && Array.isArray(value) && value.some((item) => typeof item === 'object' && !('color' in item))) ||
381
+ (value === null && Array.isArray(recipients) && recipients.length > 0)) {
383
382
  dispatch({
384
383
  type: 'multiple',
385
384
  value: {
386
385
  recipients: value,
386
+ addressing: [],
387
387
  addressingError: addressingRequiredEnabled && !value ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.addressing.error.missing", defaultMessage: "ui.composer.addressing.error.missing" })) : null
388
388
  }
389
389
  });
@@ -393,6 +393,7 @@ function Composer(inProps) {
393
393
  type: 'multiple',
394
394
  value: {
395
395
  addressing: value,
396
+ recipients: [],
396
397
  addressingError: addressingRequiredEnabled && !value ? ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.addressing.error.missing", defaultMessage: "ui.composer.addressing.error.missing" })) : null
397
398
  }
398
399
  });
@@ -400,19 +401,20 @@ function Composer(inProps) {
400
401
  setLayer(null);
401
402
  }, [group, event, recipients]);
402
403
  const handleAddAudienceLayer = (0, react_1.useCallback)(() => {
404
+ const defaultValue = group || (addressing && Object.prototype.hasOwnProperty.call(addressing, 'emotional_image_position'))
405
+ ? group
406
+ : event || (addressing && Object.prototype.hasOwnProperty.call(addressing, 'recurring'))
407
+ ? event
408
+ : Array.isArray(recipients) && recipients.some((item) => typeof item === 'object' && item !== null && !('color' in item))
409
+ ? recipients
410
+ : addressing;
403
411
  handleAddLayer({
404
412
  name: 'audience',
405
413
  Component: AudienceLayer_1.default,
406
414
  ComponentProps: {
407
415
  onClose: handleRemoveLayer,
408
416
  onSave: handleChangeAudience,
409
- defaultValue: group || (addressing && Object.prototype.hasOwnProperty.call(addressing, 'emotional_image_position'))
410
- ? group
411
- : event || (addressing && Object.prototype.hasOwnProperty.call(addressing, 'recurring'))
412
- ? event
413
- : (recipients === null || recipients === void 0 ? void 0 : recipients.length) !== 0 || ((recipients === null || recipients === void 0 ? void 0 : recipients.length) !== 0 && !recipients.some((r) => 'color' in r))
414
- ? recipients
415
- : addressing
417
+ defaultValue: defaultValue
416
418
  }
417
419
  });
418
420
  }, [handleAddLayer, handleRemoveLayer, handleChangeAudience, addressing, event, group, recipients]);
@@ -705,6 +707,8 @@ function Composer(inProps) {
705
707
  .map((mediaObjectType) => {
706
708
  const props = mediaObjectType.layerComponent ? { onClick: handleMediaTriggerClick(mediaObjectType) } : { onAdd: handleAddMedia };
707
709
  return ((0, jsx_runtime_1.jsx)(mediaObjectType.triggerButton, Object.assign({ disabled: isSubmitting || hasMediaShare, color: medias.filter(mediaObjectType.filter).length > 0 ? 'primary' : 'default' }, props), mediaObjectType.name));
708
- }), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: isSubmitting, onClick: handleAddCategoryLayer, color: (categories === null || categories === void 0 ? void 0 : categories.length) !== 0 ? 'primary' : 'default' }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "category" }) })), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ color: group || event || (addressing !== null && (addressing === null || addressing === void 0 ? void 0 : addressing.length) > 0) ? 'primary' : 'default', disabled: isSubmitting || !features.includes(types_1.SCFeatureName.TAGGING) || Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.group) || Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.event), onClick: handleAddAudienceLayer }, { children: group ? ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "groups" })) : event ? ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "CalendarIcon" })) : addressing === null || (addressing === null || addressing === void 0 ? void 0 : addressing.length) === 0 ? (addressingRequiredEnabled ? ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "label" })) : ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "public" }))) : ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "label" })) })), preferences[react_core_1.SCPreferences.ADDONS_POST_GEOLOCATION_ENABLED].value && ((0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: isSubmitting, onClick: handleAddLocationLayer, color: location !== null ? 'primary' : 'default' }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "add_location_alt" }) }))), preferences[react_core_1.SCPreferences.CONFIGURATIONS_SCHEDULED_POSTS_ENABLED].value && ((0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: isSubmitting || (Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.scheduled_at) && Boolean(!(feedObject === null || feedObject === void 0 ? void 0 : feedObject.draft))), onClick: handleAddScheduledLayer, color: scheduled_at !== null ? 'primary' : 'default' }, { children: (0, jsx_runtime_1.jsxs)(material_1.Box, Object.assign({ className: classes.selectedAction }, { children: [(0, jsx_runtime_1.jsx)(material_1.Icon, { children: "access_time" }), scheduled_at !== null && ((0, jsx_runtime_1.jsx)(material_1.Icon, Object.assign({ color: "primary", className: classes.actionSelectedIcon }, { children: "fiber_manual_record" })))] })) })))] }))] })), layer && ((0, jsx_runtime_1.jsx)(LayerTransitionRoot, Object.assign({ className: classes.layerTransitionRoot, in: true, container: dialogRef.current, direction: "left" }, { children: (0, jsx_runtime_1.jsx)(layer.Component, Object.assign({}, layer.ComponentProps)) })))] })));
710
+ }), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: isSubmitting, onClick: handleAddCategoryLayer, color: (categories === null || categories === void 0 ? void 0 : categories.length) !== 0 ? 'primary' : 'default' }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "category" }) })), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ color: group || event || (addressing !== null && (addressing === null || addressing === void 0 ? void 0 : addressing.length) > 0) || (recipients !== null && (recipients === null || recipients === void 0 ? void 0 : recipients.length) > 0)
711
+ ? 'primary'
712
+ : 'default', disabled: isSubmitting || !features.includes(types_1.SCFeatureName.TAGGING) || Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.group) || Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.event), onClick: handleAddAudienceLayer }, { children: group ? ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "groups" })) : event ? ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "CalendarIcon" })) : addressing === null || (addressing === null || addressing === void 0 ? void 0 : addressing.length) === 0 ? (addressingRequiredEnabled ? ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "label" })) : ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "public" }))) : ((0, jsx_runtime_1.jsx)(material_1.Icon, { children: "label" })) })), preferences[react_core_1.SCPreferences.ADDONS_POST_GEOLOCATION_ENABLED].value && ((0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: isSubmitting, onClick: handleAddLocationLayer, color: location !== null ? 'primary' : 'default' }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "add_location_alt" }) }))), preferences[react_core_1.SCPreferences.CONFIGURATIONS_SCHEDULED_POSTS_ENABLED].value && ((0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ disabled: isSubmitting || (Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.scheduled_at) && Boolean(!(feedObject === null || feedObject === void 0 ? void 0 : feedObject.draft))), onClick: handleAddScheduledLayer, color: scheduled_at !== null ? 'primary' : 'default' }, { children: (0, jsx_runtime_1.jsxs)(material_1.Box, Object.assign({ className: classes.selectedAction }, { children: [(0, jsx_runtime_1.jsx)(material_1.Icon, { children: "access_time" }), scheduled_at !== null && ((0, jsx_runtime_1.jsx)(material_1.Icon, Object.assign({ color: "primary", className: classes.actionSelectedIcon }, { children: "fiber_manual_record" })))] })) })))] }))] })), layer && ((0, jsx_runtime_1.jsx)(LayerTransitionRoot, Object.assign({ className: classes.layerTransitionRoot, in: true, container: dialogRef.current, direction: "left" }, { children: (0, jsx_runtime_1.jsx)(layer.Component, Object.assign({}, layer.ComponentProps)) })))] })));
709
713
  }
710
714
  exports.default = Composer;
@@ -83,12 +83,7 @@ const AudienceLayer = react_1.default.forwardRef((props, ref) => {
83
83
  ? AudienceTypes.AUDIENCE_EVENT
84
84
  : Object.prototype.hasOwnProperty.call(defaultValue, 'managed_by')
85
85
  ? AudienceTypes.AUDIENCE_GROUP
86
- : Array.isArray(defaultValue) &&
87
- defaultValue.length > 0 &&
88
- // case: array of user objects
89
- (((_a = defaultValue[0]) === null || _a === void 0 ? void 0 : _a.username) !== undefined ||
90
- // case: array of strings
91
- typeof defaultValue[0] === 'string')
86
+ : Array.isArray(defaultValue) && defaultValue.length > 0 && ((_a = defaultValue[0]) === null || _a === void 0 ? void 0 : _a.username) !== undefined
92
87
  ? AudienceTypes.AUDIENCE_USERS
93
88
  : AudienceTypes.AUDIENCE_TAG);
94
89
  // HANDLERS
@@ -107,24 +102,31 @@ const AudienceLayer = react_1.default.forwardRef((props, ref) => {
107
102
  const handleChangeAudience = (0, react_1.useCallback)((_event, data) => setAudience(data), []);
108
103
  const handleAutocompleteOpen = (0, react_1.useCallback)(() => setAutocompleteOpen(true), []);
109
104
  const handleAutocompleteClose = (0, react_1.useCallback)(() => setAutocompleteOpen(false), []);
110
- return ((0, jsx_runtime_1.jsxs)(Root, Object.assign({ ref: ref, className: (0, classnames_1.default)(className, classes.root) }, rest, { children: [(0, jsx_runtime_1.jsxs)(material_1.DialogTitle, Object.assign({ className: classes.title }, { children: [(0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ onClick: onClose }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "arrow_back" }) })), (0, jsx_runtime_1.jsx)(material_1.Typography, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.title", defaultMessage: "ui.composer.layer.audience.title" }) }), (0, jsx_runtime_1.jsx)(material_1.Button, Object.assign({ size: "small", color: "secondary", variant: "contained", onClick: handleSave }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.save", defaultMessage: "ui.composer.layer.save" }) }))] })), (0, jsx_runtime_1.jsxs)(material_1.DialogContent, Object.assign({ className: classes.content }, { children: [(0, jsx_runtime_1.jsxs)(material_1.Tabs, Object.assign({ value: audience, onChange: handleChangeAudience, "aria-label": "audience type" }, { children: [!taggingRequiredEnabled && ((0, jsx_runtime_1.jsx)(material_1.Tab, { value: AudienceTypes.AUDIENCE_ALL, icon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "public" }), label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.all", defaultMessage: "ui.composer.layer.audience.all" }) })), eventsEnabled && ((0, jsx_runtime_1.jsx)(material_1.Tab, { disabled: (Boolean(value === null || value === void 0 ? void 0 : value.length) && !Object.prototype.hasOwnProperty.call(value, 'recurring')) ||
111
- (value !== undefined && Boolean(!(value === null || value === void 0 ? void 0 : value.length)) && audience !== AudienceTypes.AUDIENCE_ALL) ||
112
- (Boolean((value === null || value === void 0 ? void 0 : value.length) === 0) && audience === AudienceTypes.AUDIENCE_ALL && Boolean((defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.length) !== 0)), value: AudienceTypes.AUDIENCE_EVENT, icon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "CalendarIcon" }), label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.event", defaultMessage: "ui.composer.layer.audience.event" }) })), groupsEnabled && ((0, jsx_runtime_1.jsx)(material_1.Tab, { disabled: (Boolean(value === null || value === void 0 ? void 0 : value.length) && !Object.prototype.hasOwnProperty.call(value, 'managed_by')) ||
113
- (value !== undefined && Boolean(!(value === null || value === void 0 ? void 0 : value.length)) && audience !== AudienceTypes.AUDIENCE_ALL) ||
114
- (Boolean((value === null || value === void 0 ? void 0 : value.length) === 0) && audience === AudienceTypes.AUDIENCE_ALL && Boolean((defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.length) !== 0)), value: AudienceTypes.AUDIENCE_GROUP, icon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "groups" }), label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.group", defaultMessage: "ui.composer.layer.audience.group" }) })), (0, jsx_runtime_1.jsx)(material_1.Tab, { disabled: value &&
115
- ((Array.isArray(value) &&
116
- (value.some((v) => v === null || v === void 0 ? void 0 : v.username) || // user tagging
117
- value.some((v) => typeof v === 'string'))) ||
118
- (!Array.isArray(value) && Object.prototype.hasOwnProperty.call(value, 'managed_by'))) // group object
119
- , value: AudienceTypes.AUDIENCE_TAG, icon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "label" }), label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.tag", defaultMessage: "ui.composer.layer.audience.tag" }) }), usersTaggingEnabled && ((0, jsx_runtime_1.jsx)(material_1.Tab, { disabled: value &&
120
- ((Array.isArray(value) &&
121
- value.length > 0 &&
122
- // disable only if NOT user objects and NOT strings
123
- !value.some((v) => v === null || v === void 0 ? void 0 : v.username) &&
124
- !value.every((v) => typeof v === 'string')) ||
125
- (!Array.isArray(value) &&
126
- Object.keys(value).length > 0 &&
127
- (Object.prototype.hasOwnProperty.call(value, 'managed_by') || Object.prototype.hasOwnProperty.call(value, 'recurring')))), value: AudienceTypes.AUDIENCE_USERS, icon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "people_alt" }), label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.users", defaultMessage: "ui.composer.layer.audience.users" }) }))] })), (0, jsx_runtime_1.jsxs)(material_1.Typography, Object.assign({ className: classes.message }, { children: [audience === AudienceTypes.AUDIENCE_ALL && !taggingRequiredEnabled && ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.all.message", defaultMessage: "ui.composer.layer.audience.all.message" })), audience === AudienceTypes.AUDIENCE_EVENT && ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.event.message", defaultMessage: "ui.composer.layer.audience.event.message" })), audience === AudienceTypes.AUDIENCE_GROUP && ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.group.message", defaultMessage: "ui.composer.layer.audience.group.message" })), audience === AudienceTypes.AUDIENCE_TAG && ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.tag.message", defaultMessage: "ui.composer.layer.audience.tag.message" })), audience === AudienceTypes.AUDIENCE_USERS && ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.users.message", defaultMessage: "ui.composer.layer.audience.users.message" }))] })), audience === AudienceTypes.AUDIENCE_TAG && ((0, jsx_runtime_1.jsx)(material_1.Autocomplete, { className: classes.autocomplete, open: autocompleteOpen, onOpen: handleAutocompleteOpen, onClose: handleAutocompleteClose, multiple: true, options: scAddressingTags || [], getOptionLabel: (option) => option.name || '', value: value, selectOnFocus: true, clearOnBlur: true, handleHomeEndKeys: true, clearIcon: null, noOptionsText: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.tags.empty", defaultMessage: "ui.composer.layer.audience.tags.empty" }), onChange: handleChange, isOptionEqualToValue: (option, value) => value.id === option.id, renderTags: (value, getTagProps) => {
105
+ const isAudienceTypeSelected = (type) => {
106
+ // "ALL" tab is never disabled
107
+ if (type === AudienceTypes.AUDIENCE_ALL)
108
+ return false;
109
+ // Empty value nothing is disabled
110
+ if (!value || (Array.isArray(value) && value.length === 0))
111
+ return false;
112
+ const valueType = (() => {
113
+ if (Array.isArray(value)) {
114
+ if (value.some((v) => 'color' in v))
115
+ return AudienceTypes.AUDIENCE_TAG;
116
+ return AudienceTypes.AUDIENCE_USERS;
117
+ }
118
+ else {
119
+ if ('recurring' in value)
120
+ return AudienceTypes.AUDIENCE_EVENT;
121
+ if ('managed_by' in value)
122
+ return AudienceTypes.AUDIENCE_GROUP;
123
+ return AudienceTypes.AUDIENCE_USERS;
124
+ }
125
+ })();
126
+ // Disable all tabs except the currently selected type
127
+ return type !== valueType;
128
+ };
129
+ return ((0, jsx_runtime_1.jsxs)(Root, Object.assign({ ref: ref, className: (0, classnames_1.default)(className, classes.root) }, rest, { children: [(0, jsx_runtime_1.jsxs)(material_1.DialogTitle, Object.assign({ className: classes.title }, { children: [(0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ onClick: onClose }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "arrow_back" }) })), (0, jsx_runtime_1.jsx)(material_1.Typography, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.title", defaultMessage: "ui.composer.layer.audience.title" }) }), (0, jsx_runtime_1.jsx)(material_1.Button, Object.assign({ size: "small", color: "secondary", variant: "contained", onClick: handleSave }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.save", defaultMessage: "ui.composer.layer.save" }) }))] })), (0, jsx_runtime_1.jsxs)(material_1.DialogContent, Object.assign({ className: classes.content }, { children: [(0, jsx_runtime_1.jsxs)(material_1.Tabs, Object.assign({ value: audience, onChange: handleChangeAudience, "aria-label": "audience type" }, { children: [!taggingRequiredEnabled && ((0, jsx_runtime_1.jsx)(material_1.Tab, { value: AudienceTypes.AUDIENCE_ALL, icon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "public" }), label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.all", defaultMessage: "ui.composer.layer.audience.all" }) })), eventsEnabled && ((0, jsx_runtime_1.jsx)(material_1.Tab, { disabled: isAudienceTypeSelected(AudienceTypes.AUDIENCE_EVENT), value: AudienceTypes.AUDIENCE_EVENT, icon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "CalendarIcon" }), label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.event", defaultMessage: "ui.composer.layer.audience.event" }) })), groupsEnabled && ((0, jsx_runtime_1.jsx)(material_1.Tab, { disabled: isAudienceTypeSelected(AudienceTypes.AUDIENCE_GROUP), value: AudienceTypes.AUDIENCE_GROUP, icon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "groups" }), label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.group", defaultMessage: "ui.composer.layer.audience.group" }) })), (0, jsx_runtime_1.jsx)(material_1.Tab, { disabled: isAudienceTypeSelected(AudienceTypes.AUDIENCE_TAG), value: AudienceTypes.AUDIENCE_TAG, icon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "label" }), label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.tag", defaultMessage: "ui.composer.layer.audience.tag" }) }), usersTaggingEnabled && ((0, jsx_runtime_1.jsx)(material_1.Tab, { disabled: isAudienceTypeSelected(AudienceTypes.AUDIENCE_USERS), value: AudienceTypes.AUDIENCE_USERS, icon: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "people_alt" }), label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.users", defaultMessage: "ui.composer.layer.audience.users" }) }))] })), (0, jsx_runtime_1.jsxs)(material_1.Typography, Object.assign({ className: classes.message }, { children: [audience === AudienceTypes.AUDIENCE_ALL && !taggingRequiredEnabled && ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.all.message", defaultMessage: "ui.composer.layer.audience.all.message" })), audience === AudienceTypes.AUDIENCE_EVENT && ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.event.message", defaultMessage: "ui.composer.layer.audience.event.message" })), audience === AudienceTypes.AUDIENCE_GROUP && ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.group.message", defaultMessage: "ui.composer.layer.audience.group.message" })), audience === AudienceTypes.AUDIENCE_TAG && ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.tag.message", defaultMessage: "ui.composer.layer.audience.tag.message" })), audience === AudienceTypes.AUDIENCE_USERS && ((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.users.message", defaultMessage: "ui.composer.layer.audience.users.message" }))] })), audience === AudienceTypes.AUDIENCE_TAG && ((0, jsx_runtime_1.jsx)(material_1.Autocomplete, { className: classes.autocomplete, open: autocompleteOpen, onOpen: handleAutocompleteOpen, onClose: handleAutocompleteClose, multiple: true, options: scAddressingTags || [], getOptionLabel: (option) => option.name || '', value: value, selectOnFocus: true, clearOnBlur: true, handleHomeEndKeys: true, clearIcon: null, noOptionsText: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.composer.layer.audience.tags.empty", defaultMessage: "ui.composer.layer.audience.tags.empty" }), onChange: handleChange, isOptionEqualToValue: (option, value) => value.id === option.id, renderTags: (value, getTagProps) => {
128
130
  return value.map((option, index) => (0, jsx_runtime_1.jsx)(TagChip_1.default, Object.assign({ tag: option }, getTagProps({ index })), option.id));
129
131
  }, renderOption: (props, option, { selected, inputValue }) => {
130
132
  const matches = (0, match_1.default)(option.name, inputValue);
@@ -132,6 +134,6 @@ const AudienceLayer = react_1.default.forwardRef((props, ref) => {
132
134
  return ((0, jsx_runtime_1.jsx)("li", Object.assign({}, props, { children: (0, jsx_runtime_1.jsx)(TagChip_1.default, { disposable: false, tag: option, label: (0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: parts.map((part, index) => ((0, jsx_runtime_1.jsx)("span", Object.assign({ style: { fontWeight: part.highlight ? 700 : 400 } }, { children: part.text }), index))) }) }, option.id) })));
133
135
  }, renderInput: (params) => {
134
136
  return ((0, jsx_runtime_1.jsx)(material_1.TextField, Object.assign({}, params, TextFieldProps, { InputProps: Object.assign(Object.assign({}, params.InputProps), { autoComplete: 'addressing', endAdornment: (0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: params.InputProps.endAdornment }) }) })));
135
- } })), audience === AudienceTypes.AUDIENCE_USERS && (0, jsx_runtime_1.jsx)(UserAutocomplete_1.default, { onChange: handleUsersChange, defaultValue: defaultValue }), audience === AudienceTypes.AUDIENCE_GROUP && (0, jsx_runtime_1.jsx)(GroupAutocomplete_1.default, { onChange: handleGroupChange, defaultValue: defaultValue }), audience === AudienceTypes.AUDIENCE_EVENT && (0, jsx_runtime_1.jsx)(EventAutocomplete_1.default, { onChange: handleEventChange, defaultValue: defaultValue })] }))] })));
137
+ } })), audience === AudienceTypes.AUDIENCE_USERS && (0, jsx_runtime_1.jsx)(UserAutocomplete_1.default, { onChange: handleUsersChange, defaultValue: value }), audience === AudienceTypes.AUDIENCE_GROUP && (0, jsx_runtime_1.jsx)(GroupAutocomplete_1.default, { onChange: handleGroupChange, defaultValue: value }), audience === AudienceTypes.AUDIENCE_EVENT && (0, jsx_runtime_1.jsx)(EventAutocomplete_1.default, { onChange: handleEventChange, defaultValue: value })] }))] })));
136
138
  });
137
139
  exports.default = AudienceLayer;
@@ -46,16 +46,18 @@ const UserAutocomplete = (inProps) => {
46
46
  .filter(Boolean)
47
47
  .join(','), [value]);
48
48
  // Fetch users excluding selected ones
49
- const { users, isLoading } = (0, react_core_1.useSCFetchUsers)({ search: inputValue, exclude: excludeIds });
49
+ const { users, isLoading } = (0, react_core_1.useSCFetchUsers)({ search: (inputValue === null || inputValue === void 0 ? void 0 : inputValue.length) >= 3 ? inputValue : '', exclude: excludeIds });
50
50
  const filteredUsers = users.filter((u) => !excludeIds.includes(u.id));
51
51
  (0, react_1.useEffect)(() => {
52
52
  onChange === null || onChange === void 0 ? void 0 : onChange(value);
53
53
  setTextAreaValue(value.map((u) => (typeof u === 'object' ? u.username : u)).join('\n'));
54
54
  }, [value]);
55
55
  // Handlers
56
- const handleOpen = () => {
57
- filteredUsers.length > 0 && setOpen(true);
58
- };
56
+ const handleOpen = (0, react_1.useCallback)(() => {
57
+ if (filteredUsers.length > 0) {
58
+ setOpen(true);
59
+ }
60
+ }, [filteredUsers]);
59
61
  const handleClose = () => {
60
62
  setOpen(false);
61
63
  };
@@ -67,24 +69,37 @@ const UserAutocomplete = (inProps) => {
67
69
  .split(/\s|,|\n/)
68
70
  .map((s) => s.trim())
69
71
  .filter(Boolean)));
70
- let resolvedUsers = [];
71
72
  try {
72
73
  if (names.length > 0) {
73
- const resp = yield api_services_1.UserService.matchUsernames(names.join(','));
74
- const matchedMap = new Map(resp.map((u) => [u.username, u]));
75
- resolvedUsers = names.map((name) => matchedMap.get(name) || name);
74
+ const resp = yield api_services_1.UserService.matchUsernames(names);
75
+ const resolvedUsernames = new Set(resp.map((u) => u.username));
76
+ const resolvedUsers = resp.filter((u) => resolvedUsernames.has(u.username));
77
+ setValue(resolvedUsers);
78
+ setTextAreaValue(resolvedUsers.map((u) => u.username).join('\n'));
79
+ }
80
+ else {
81
+ setValue([]);
82
+ setTextAreaValue('');
76
83
  }
77
84
  }
78
85
  catch (err) {
79
- console.error(`Failed fetching users`, err);
80
- resolvedUsers = names;
86
+ console.error(`Failed fetching matching usernames`, err);
87
+ setValue([]);
88
+ setTextAreaValue('');
81
89
  }
82
- setValue(resolvedUsers);
83
- setTextAreaValue(e.target.value);
84
90
  });
85
- return ((0, jsx_runtime_1.jsxs)(Root, Object.assign({ className: classes.root }, { children: [(0, jsx_runtime_1.jsx)(AutocompleteRoot, Object.assign({ multiple: true, className: classes.autocompleteRoot, open: open, onOpen: handleOpen, onClose: handleClose, options: filteredUsers || [], getOptionLabel: (option) => option.username || '', value: value, inputValue: inputValue, onInputChange: (_event, newInputValue) => {
91
+ const filterOptions = (0, react_1.useCallback)((options, state) => {
92
+ const search = state.inputValue.toLowerCase();
93
+ return options.filter((option) => {
94
+ var _a, _b;
95
+ const usernameMatch = (_a = option.username) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(search);
96
+ const nameMatch = (_b = option.real_name) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes(search);
97
+ return usernameMatch || nameMatch;
98
+ });
99
+ }, []);
100
+ return ((0, jsx_runtime_1.jsxs)(Root, Object.assign({ className: classes.root }, { children: [(0, jsx_runtime_1.jsx)(AutocompleteRoot, Object.assign({ multiple: true, className: classes.autocompleteRoot, open: open, onOpen: handleOpen, onClose: handleClose, options: filteredUsers || [], filterOptions: filterOptions, getOptionLabel: (option) => option.username || '', value: value, inputValue: inputValue, onInputChange: (_event, newInputValue) => {
86
101
  setInputValue(newInputValue);
87
- }, selectOnFocus: true, clearOnBlur: true, blurOnSelect: true, handleHomeEndKeys: true, clearIcon: null, disabled: disabled || isLoading, noOptionsText: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.userAutocomplete.empty", defaultMessage: "ui.userAutocomplete.empty" }), onChange: handleChange, isOptionEqualToValue: (option, val) => option.id === val.id, renderTags: (value, getTagProps) => value.map((option, index) => {
102
+ }, selectOnFocus: true, clearOnBlur: true, blurOnSelect: true, handleHomeEndKeys: true, clearIcon: null, disabled: disabled || isLoading, noOptionsText: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.userAutocomplete.empty", defaultMessage: "ui.userAutocomplete.empty" }), onChange: handleChange, isOptionEqualToValue: (option, val) => (option ? val.id === option.id : false), renderTags: (value, getTagProps) => value.map((option, index) => {
88
103
  const username = typeof option === 'string' ? option : option.username;
89
104
  const avatar = typeof option === 'string' ? '' : option.avatar;
90
105
  const id = typeof option === 'string' ? `fallback-${option}` : option.id;
@@ -92,8 +107,8 @@ const UserAutocomplete = (inProps) => {
92
107
  }), renderOption: (props, option, { inputValue }) => {
93
108
  const matches = (0, match_1.default)(option.username, inputValue);
94
109
  const parts = (0, parse_1.default)(option.username, matches);
95
- return ((0, jsx_runtime_1.jsxs)(material_1.Box, Object.assign({ component: "li" }, props, { children: [(0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: option.username, src: option.avatar, sx: { marginRight: 1 } }), (0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: parts.map((part, index) => ((0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ sx: { fontWeight: part.highlight ? 700 : 400 } }, { children: part.text }), index))) })] })));
96
- }, renderInput: (params) => ((0, jsx_runtime_1.jsx)(material_1.TextField, Object.assign({}, params, TextFieldProps, { margin: "dense", InputProps: Object.assign(Object.assign({}, params.InputProps), { autoComplete: 'off', endAdornment: ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [isLoading ? (0, jsx_runtime_1.jsx)(material_1.CircularProgress, { color: "inherit", size: 20 }) : null, params.InputProps.endAdornment] })) }) }))) }, rest)), (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2", color: "primary", className: classes.info }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.userAutocomplete.textarea.info", defaultMessage: "ui.userAutocomplete.textarea.info", values: {
110
+ return ((0, jsx_runtime_1.jsxs)(material_1.Box, Object.assign({ component: "li" }, props, { children: [(0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: option.username, src: option.avatar, sx: { marginRight: 1 } }), (0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: parts.map((part, index) => ((0, jsx_runtime_1.jsx)(material_1.Typography, { children: part.text }, index))) })] })));
111
+ }, renderInput: (params) => ((0, jsx_runtime_1.jsx)(material_1.TextField, Object.assign({}, params, TextFieldProps, { margin: "dense", InputProps: Object.assign(Object.assign({}, params.InputProps), { autoComplete: 'off', endAdornment: filteredUsers.length > 0 ? ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [isLoading && (0, jsx_runtime_1.jsx)(material_1.CircularProgress, { color: "inherit", size: 20 }), params.InputProps.endAdornment] })) : null }) }))) }, rest)), (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2", color: "primary", className: classes.info }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.userAutocomplete.textarea.info", defaultMessage: "ui.userAutocomplete.textarea.info", values: {
97
112
  // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
98
113
  // @ts-ignore
99
114
  icon: (...chunks) => (0, jsx_runtime_1.jsx)(material_1.Icon, { children: chunks })
@@ -375,13 +375,13 @@ export default function Composer(inProps) {
375
375
  else if (event || (value && Object.prototype.hasOwnProperty.call(value, 'recurring'))) {
376
376
  dispatch({ type: 'event', value });
377
377
  }
378
- else if ((Array.isArray(value) &&
379
- value.some((item) => (typeof item === 'object' && item !== null && !('color' in item)) || typeof item === 'string')) ||
380
- (Array.isArray(recipients) && recipients.length > 0)) {
378
+ else if ((value && Array.isArray(value) && value.some((item) => typeof item === 'object' && !('color' in item))) ||
379
+ (value === null && Array.isArray(recipients) && recipients.length > 0)) {
381
380
  dispatch({
382
381
  type: 'multiple',
383
382
  value: {
384
383
  recipients: value,
384
+ addressing: [],
385
385
  addressingError: addressingRequiredEnabled && !value ? (_jsx(FormattedMessage, { id: "ui.composer.addressing.error.missing", defaultMessage: "ui.composer.addressing.error.missing" })) : null
386
386
  }
387
387
  });
@@ -391,6 +391,7 @@ export default function Composer(inProps) {
391
391
  type: 'multiple',
392
392
  value: {
393
393
  addressing: value,
394
+ recipients: [],
394
395
  addressingError: addressingRequiredEnabled && !value ? (_jsx(FormattedMessage, { id: "ui.composer.addressing.error.missing", defaultMessage: "ui.composer.addressing.error.missing" })) : null
395
396
  }
396
397
  });
@@ -398,19 +399,20 @@ export default function Composer(inProps) {
398
399
  setLayer(null);
399
400
  }, [group, event, recipients]);
400
401
  const handleAddAudienceLayer = useCallback(() => {
402
+ const defaultValue = group || (addressing && Object.prototype.hasOwnProperty.call(addressing, 'emotional_image_position'))
403
+ ? group
404
+ : event || (addressing && Object.prototype.hasOwnProperty.call(addressing, 'recurring'))
405
+ ? event
406
+ : Array.isArray(recipients) && recipients.some((item) => typeof item === 'object' && item !== null && !('color' in item))
407
+ ? recipients
408
+ : addressing;
401
409
  handleAddLayer({
402
410
  name: 'audience',
403
411
  Component: AudienceLayer,
404
412
  ComponentProps: {
405
413
  onClose: handleRemoveLayer,
406
414
  onSave: handleChangeAudience,
407
- defaultValue: group || (addressing && Object.prototype.hasOwnProperty.call(addressing, 'emotional_image_position'))
408
- ? group
409
- : event || (addressing && Object.prototype.hasOwnProperty.call(addressing, 'recurring'))
410
- ? event
411
- : (recipients === null || recipients === void 0 ? void 0 : recipients.length) !== 0 || ((recipients === null || recipients === void 0 ? void 0 : recipients.length) !== 0 && !recipients.some((r) => 'color' in r))
412
- ? recipients
413
- : addressing
415
+ defaultValue: defaultValue
414
416
  }
415
417
  });
416
418
  }, [handleAddLayer, handleRemoveLayer, handleChangeAudience, addressing, event, group, recipients]);
@@ -703,5 +705,7 @@ export default function Composer(inProps) {
703
705
  .map((mediaObjectType) => {
704
706
  const props = mediaObjectType.layerComponent ? { onClick: handleMediaTriggerClick(mediaObjectType) } : { onAdd: handleAddMedia };
705
707
  return (_jsx(mediaObjectType.triggerButton, Object.assign({ disabled: isSubmitting || hasMediaShare, color: medias.filter(mediaObjectType.filter).length > 0 ? 'primary' : 'default' }, props), mediaObjectType.name));
706
- }), _jsx(IconButton, Object.assign({ disabled: isSubmitting, onClick: handleAddCategoryLayer, color: (categories === null || categories === void 0 ? void 0 : categories.length) !== 0 ? 'primary' : 'default' }, { children: _jsx(Icon, { children: "category" }) })), _jsx(IconButton, Object.assign({ color: group || event || (addressing !== null && (addressing === null || addressing === void 0 ? void 0 : addressing.length) > 0) ? 'primary' : 'default', disabled: isSubmitting || !features.includes(SCFeatureName.TAGGING) || Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.group) || Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.event), onClick: handleAddAudienceLayer }, { children: group ? (_jsx(Icon, { children: "groups" })) : event ? (_jsx(Icon, { children: "CalendarIcon" })) : addressing === null || (addressing === null || addressing === void 0 ? void 0 : addressing.length) === 0 ? (addressingRequiredEnabled ? (_jsx(Icon, { children: "label" })) : (_jsx(Icon, { children: "public" }))) : (_jsx(Icon, { children: "label" })) })), preferences[SCPreferences.ADDONS_POST_GEOLOCATION_ENABLED].value && (_jsx(IconButton, Object.assign({ disabled: isSubmitting, onClick: handleAddLocationLayer, color: location !== null ? 'primary' : 'default' }, { children: _jsx(Icon, { children: "add_location_alt" }) }))), preferences[SCPreferences.CONFIGURATIONS_SCHEDULED_POSTS_ENABLED].value && (_jsx(IconButton, Object.assign({ disabled: isSubmitting || (Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.scheduled_at) && Boolean(!(feedObject === null || feedObject === void 0 ? void 0 : feedObject.draft))), onClick: handleAddScheduledLayer, color: scheduled_at !== null ? 'primary' : 'default' }, { children: _jsxs(Box, Object.assign({ className: classes.selectedAction }, { children: [_jsx(Icon, { children: "access_time" }), scheduled_at !== null && (_jsx(Icon, Object.assign({ color: "primary", className: classes.actionSelectedIcon }, { children: "fiber_manual_record" })))] })) })))] }))] })), layer && (_jsx(LayerTransitionRoot, Object.assign({ className: classes.layerTransitionRoot, in: true, container: dialogRef.current, direction: "left" }, { children: _jsx(layer.Component, Object.assign({}, layer.ComponentProps)) })))] })));
708
+ }), _jsx(IconButton, Object.assign({ disabled: isSubmitting, onClick: handleAddCategoryLayer, color: (categories === null || categories === void 0 ? void 0 : categories.length) !== 0 ? 'primary' : 'default' }, { children: _jsx(Icon, { children: "category" }) })), _jsx(IconButton, Object.assign({ color: group || event || (addressing !== null && (addressing === null || addressing === void 0 ? void 0 : addressing.length) > 0) || (recipients !== null && (recipients === null || recipients === void 0 ? void 0 : recipients.length) > 0)
709
+ ? 'primary'
710
+ : 'default', disabled: isSubmitting || !features.includes(SCFeatureName.TAGGING) || Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.group) || Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.event), onClick: handleAddAudienceLayer }, { children: group ? (_jsx(Icon, { children: "groups" })) : event ? (_jsx(Icon, { children: "CalendarIcon" })) : addressing === null || (addressing === null || addressing === void 0 ? void 0 : addressing.length) === 0 ? (addressingRequiredEnabled ? (_jsx(Icon, { children: "label" })) : (_jsx(Icon, { children: "public" }))) : (_jsx(Icon, { children: "label" })) })), preferences[SCPreferences.ADDONS_POST_GEOLOCATION_ENABLED].value && (_jsx(IconButton, Object.assign({ disabled: isSubmitting, onClick: handleAddLocationLayer, color: location !== null ? 'primary' : 'default' }, { children: _jsx(Icon, { children: "add_location_alt" }) }))), preferences[SCPreferences.CONFIGURATIONS_SCHEDULED_POSTS_ENABLED].value && (_jsx(IconButton, Object.assign({ disabled: isSubmitting || (Boolean(feedObject === null || feedObject === void 0 ? void 0 : feedObject.scheduled_at) && Boolean(!(feedObject === null || feedObject === void 0 ? void 0 : feedObject.draft))), onClick: handleAddScheduledLayer, color: scheduled_at !== null ? 'primary' : 'default' }, { children: _jsxs(Box, Object.assign({ className: classes.selectedAction }, { children: [_jsx(Icon, { children: "access_time" }), scheduled_at !== null && (_jsx(Icon, Object.assign({ color: "primary", className: classes.actionSelectedIcon }, { children: "fiber_manual_record" })))] })) })))] }))] })), layer && (_jsx(LayerTransitionRoot, Object.assign({ className: classes.layerTransitionRoot, in: true, container: dialogRef.current, direction: "left" }, { children: _jsx(layer.Component, Object.assign({}, layer.ComponentProps)) })))] })));
707
711
  }
@@ -80,12 +80,7 @@ const AudienceLayer = React.forwardRef((props, ref) => {
80
80
  ? AudienceTypes.AUDIENCE_EVENT
81
81
  : Object.prototype.hasOwnProperty.call(defaultValue, 'managed_by')
82
82
  ? AudienceTypes.AUDIENCE_GROUP
83
- : Array.isArray(defaultValue) &&
84
- defaultValue.length > 0 &&
85
- // case: array of user objects
86
- (((_a = defaultValue[0]) === null || _a === void 0 ? void 0 : _a.username) !== undefined ||
87
- // case: array of strings
88
- typeof defaultValue[0] === 'string')
83
+ : Array.isArray(defaultValue) && defaultValue.length > 0 && ((_a = defaultValue[0]) === null || _a === void 0 ? void 0 : _a.username) !== undefined
89
84
  ? AudienceTypes.AUDIENCE_USERS
90
85
  : AudienceTypes.AUDIENCE_TAG);
91
86
  // HANDLERS
@@ -104,24 +99,31 @@ const AudienceLayer = React.forwardRef((props, ref) => {
104
99
  const handleChangeAudience = useCallback((_event, data) => setAudience(data), []);
105
100
  const handleAutocompleteOpen = useCallback(() => setAutocompleteOpen(true), []);
106
101
  const handleAutocompleteClose = useCallback(() => setAutocompleteOpen(false), []);
107
- return (_jsxs(Root, Object.assign({ ref: ref, className: classNames(className, classes.root) }, rest, { children: [_jsxs(DialogTitle, Object.assign({ className: classes.title }, { children: [_jsx(IconButton, Object.assign({ onClick: onClose }, { children: _jsx(Icon, { children: "arrow_back" }) })), _jsx(Typography, { children: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.title", defaultMessage: "ui.composer.layer.audience.title" }) }), _jsx(Button, Object.assign({ size: "small", color: "secondary", variant: "contained", onClick: handleSave }, { children: _jsx(FormattedMessage, { id: "ui.composer.layer.save", defaultMessage: "ui.composer.layer.save" }) }))] })), _jsxs(DialogContent, Object.assign({ className: classes.content }, { children: [_jsxs(Tabs, Object.assign({ value: audience, onChange: handleChangeAudience, "aria-label": "audience type" }, { children: [!taggingRequiredEnabled && (_jsx(Tab, { value: AudienceTypes.AUDIENCE_ALL, icon: _jsx(Icon, { children: "public" }), label: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.all", defaultMessage: "ui.composer.layer.audience.all" }) })), eventsEnabled && (_jsx(Tab, { disabled: (Boolean(value === null || value === void 0 ? void 0 : value.length) && !Object.prototype.hasOwnProperty.call(value, 'recurring')) ||
108
- (value !== undefined && Boolean(!(value === null || value === void 0 ? void 0 : value.length)) && audience !== AudienceTypes.AUDIENCE_ALL) ||
109
- (Boolean((value === null || value === void 0 ? void 0 : value.length) === 0) && audience === AudienceTypes.AUDIENCE_ALL && Boolean((defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.length) !== 0)), value: AudienceTypes.AUDIENCE_EVENT, icon: _jsx(Icon, { children: "CalendarIcon" }), label: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.event", defaultMessage: "ui.composer.layer.audience.event" }) })), groupsEnabled && (_jsx(Tab, { disabled: (Boolean(value === null || value === void 0 ? void 0 : value.length) && !Object.prototype.hasOwnProperty.call(value, 'managed_by')) ||
110
- (value !== undefined && Boolean(!(value === null || value === void 0 ? void 0 : value.length)) && audience !== AudienceTypes.AUDIENCE_ALL) ||
111
- (Boolean((value === null || value === void 0 ? void 0 : value.length) === 0) && audience === AudienceTypes.AUDIENCE_ALL && Boolean((defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.length) !== 0)), value: AudienceTypes.AUDIENCE_GROUP, icon: _jsx(Icon, { children: "groups" }), label: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.group", defaultMessage: "ui.composer.layer.audience.group" }) })), _jsx(Tab, { disabled: value &&
112
- ((Array.isArray(value) &&
113
- (value.some((v) => v === null || v === void 0 ? void 0 : v.username) || // user tagging
114
- value.some((v) => typeof v === 'string'))) ||
115
- (!Array.isArray(value) && Object.prototype.hasOwnProperty.call(value, 'managed_by'))) // group object
116
- , value: AudienceTypes.AUDIENCE_TAG, icon: _jsx(Icon, { children: "label" }), label: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.tag", defaultMessage: "ui.composer.layer.audience.tag" }) }), usersTaggingEnabled && (_jsx(Tab, { disabled: value &&
117
- ((Array.isArray(value) &&
118
- value.length > 0 &&
119
- // disable only if NOT user objects and NOT strings
120
- !value.some((v) => v === null || v === void 0 ? void 0 : v.username) &&
121
- !value.every((v) => typeof v === 'string')) ||
122
- (!Array.isArray(value) &&
123
- Object.keys(value).length > 0 &&
124
- (Object.prototype.hasOwnProperty.call(value, 'managed_by') || Object.prototype.hasOwnProperty.call(value, 'recurring')))), value: AudienceTypes.AUDIENCE_USERS, icon: _jsx(Icon, { children: "people_alt" }), label: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.users", defaultMessage: "ui.composer.layer.audience.users" }) }))] })), _jsxs(Typography, Object.assign({ className: classes.message }, { children: [audience === AudienceTypes.AUDIENCE_ALL && !taggingRequiredEnabled && (_jsx(FormattedMessage, { id: "ui.composer.layer.audience.all.message", defaultMessage: "ui.composer.layer.audience.all.message" })), audience === AudienceTypes.AUDIENCE_EVENT && (_jsx(FormattedMessage, { id: "ui.composer.layer.audience.event.message", defaultMessage: "ui.composer.layer.audience.event.message" })), audience === AudienceTypes.AUDIENCE_GROUP && (_jsx(FormattedMessage, { id: "ui.composer.layer.audience.group.message", defaultMessage: "ui.composer.layer.audience.group.message" })), audience === AudienceTypes.AUDIENCE_TAG && (_jsx(FormattedMessage, { id: "ui.composer.layer.audience.tag.message", defaultMessage: "ui.composer.layer.audience.tag.message" })), audience === AudienceTypes.AUDIENCE_USERS && (_jsx(FormattedMessage, { id: "ui.composer.layer.audience.users.message", defaultMessage: "ui.composer.layer.audience.users.message" }))] })), audience === AudienceTypes.AUDIENCE_TAG && (_jsx(Autocomplete, { className: classes.autocomplete, open: autocompleteOpen, onOpen: handleAutocompleteOpen, onClose: handleAutocompleteClose, multiple: true, options: scAddressingTags || [], getOptionLabel: (option) => option.name || '', value: value, selectOnFocus: true, clearOnBlur: true, handleHomeEndKeys: true, clearIcon: null, noOptionsText: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.tags.empty", defaultMessage: "ui.composer.layer.audience.tags.empty" }), onChange: handleChange, isOptionEqualToValue: (option, value) => value.id === option.id, renderTags: (value, getTagProps) => {
102
+ const isAudienceTypeSelected = (type) => {
103
+ // "ALL" tab is never disabled
104
+ if (type === AudienceTypes.AUDIENCE_ALL)
105
+ return false;
106
+ // Empty value nothing is disabled
107
+ if (!value || (Array.isArray(value) && value.length === 0))
108
+ return false;
109
+ const valueType = (() => {
110
+ if (Array.isArray(value)) {
111
+ if (value.some((v) => 'color' in v))
112
+ return AudienceTypes.AUDIENCE_TAG;
113
+ return AudienceTypes.AUDIENCE_USERS;
114
+ }
115
+ else {
116
+ if ('recurring' in value)
117
+ return AudienceTypes.AUDIENCE_EVENT;
118
+ if ('managed_by' in value)
119
+ return AudienceTypes.AUDIENCE_GROUP;
120
+ return AudienceTypes.AUDIENCE_USERS;
121
+ }
122
+ })();
123
+ // Disable all tabs except the currently selected type
124
+ return type !== valueType;
125
+ };
126
+ return (_jsxs(Root, Object.assign({ ref: ref, className: classNames(className, classes.root) }, rest, { children: [_jsxs(DialogTitle, Object.assign({ className: classes.title }, { children: [_jsx(IconButton, Object.assign({ onClick: onClose }, { children: _jsx(Icon, { children: "arrow_back" }) })), _jsx(Typography, { children: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.title", defaultMessage: "ui.composer.layer.audience.title" }) }), _jsx(Button, Object.assign({ size: "small", color: "secondary", variant: "contained", onClick: handleSave }, { children: _jsx(FormattedMessage, { id: "ui.composer.layer.save", defaultMessage: "ui.composer.layer.save" }) }))] })), _jsxs(DialogContent, Object.assign({ className: classes.content }, { children: [_jsxs(Tabs, Object.assign({ value: audience, onChange: handleChangeAudience, "aria-label": "audience type" }, { children: [!taggingRequiredEnabled && (_jsx(Tab, { value: AudienceTypes.AUDIENCE_ALL, icon: _jsx(Icon, { children: "public" }), label: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.all", defaultMessage: "ui.composer.layer.audience.all" }) })), eventsEnabled && (_jsx(Tab, { disabled: isAudienceTypeSelected(AudienceTypes.AUDIENCE_EVENT), value: AudienceTypes.AUDIENCE_EVENT, icon: _jsx(Icon, { children: "CalendarIcon" }), label: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.event", defaultMessage: "ui.composer.layer.audience.event" }) })), groupsEnabled && (_jsx(Tab, { disabled: isAudienceTypeSelected(AudienceTypes.AUDIENCE_GROUP), value: AudienceTypes.AUDIENCE_GROUP, icon: _jsx(Icon, { children: "groups" }), label: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.group", defaultMessage: "ui.composer.layer.audience.group" }) })), _jsx(Tab, { disabled: isAudienceTypeSelected(AudienceTypes.AUDIENCE_TAG), value: AudienceTypes.AUDIENCE_TAG, icon: _jsx(Icon, { children: "label" }), label: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.tag", defaultMessage: "ui.composer.layer.audience.tag" }) }), usersTaggingEnabled && (_jsx(Tab, { disabled: isAudienceTypeSelected(AudienceTypes.AUDIENCE_USERS), value: AudienceTypes.AUDIENCE_USERS, icon: _jsx(Icon, { children: "people_alt" }), label: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.users", defaultMessage: "ui.composer.layer.audience.users" }) }))] })), _jsxs(Typography, Object.assign({ className: classes.message }, { children: [audience === AudienceTypes.AUDIENCE_ALL && !taggingRequiredEnabled && (_jsx(FormattedMessage, { id: "ui.composer.layer.audience.all.message", defaultMessage: "ui.composer.layer.audience.all.message" })), audience === AudienceTypes.AUDIENCE_EVENT && (_jsx(FormattedMessage, { id: "ui.composer.layer.audience.event.message", defaultMessage: "ui.composer.layer.audience.event.message" })), audience === AudienceTypes.AUDIENCE_GROUP && (_jsx(FormattedMessage, { id: "ui.composer.layer.audience.group.message", defaultMessage: "ui.composer.layer.audience.group.message" })), audience === AudienceTypes.AUDIENCE_TAG && (_jsx(FormattedMessage, { id: "ui.composer.layer.audience.tag.message", defaultMessage: "ui.composer.layer.audience.tag.message" })), audience === AudienceTypes.AUDIENCE_USERS && (_jsx(FormattedMessage, { id: "ui.composer.layer.audience.users.message", defaultMessage: "ui.composer.layer.audience.users.message" }))] })), audience === AudienceTypes.AUDIENCE_TAG && (_jsx(Autocomplete, { className: classes.autocomplete, open: autocompleteOpen, onOpen: handleAutocompleteOpen, onClose: handleAutocompleteClose, multiple: true, options: scAddressingTags || [], getOptionLabel: (option) => option.name || '', value: value, selectOnFocus: true, clearOnBlur: true, handleHomeEndKeys: true, clearIcon: null, noOptionsText: _jsx(FormattedMessage, { id: "ui.composer.layer.audience.tags.empty", defaultMessage: "ui.composer.layer.audience.tags.empty" }), onChange: handleChange, isOptionEqualToValue: (option, value) => value.id === option.id, renderTags: (value, getTagProps) => {
125
127
  return value.map((option, index) => _jsx(TagChip, Object.assign({ tag: option }, getTagProps({ index })), option.id));
126
128
  }, renderOption: (props, option, { selected, inputValue }) => {
127
129
  const matches = match(option.name, inputValue);
@@ -129,6 +131,6 @@ const AudienceLayer = React.forwardRef((props, ref) => {
129
131
  return (_jsx("li", Object.assign({}, props, { children: _jsx(TagChip, { disposable: false, tag: option, label: _jsx(React.Fragment, { children: parts.map((part, index) => (_jsx("span", Object.assign({ style: { fontWeight: part.highlight ? 700 : 400 } }, { children: part.text }), index))) }) }, option.id) })));
130
132
  }, renderInput: (params) => {
131
133
  return (_jsx(TextField, Object.assign({}, params, TextFieldProps, { InputProps: Object.assign(Object.assign({}, params.InputProps), { autoComplete: 'addressing', endAdornment: _jsx(React.Fragment, { children: params.InputProps.endAdornment }) }) })));
132
- } })), audience === AudienceTypes.AUDIENCE_USERS && _jsx(UserAutocomplete, { onChange: handleUsersChange, defaultValue: defaultValue }), audience === AudienceTypes.AUDIENCE_GROUP && _jsx(GroupAutocomplete, { onChange: handleGroupChange, defaultValue: defaultValue }), audience === AudienceTypes.AUDIENCE_EVENT && _jsx(EventAutocomplete, { onChange: handleEventChange, defaultValue: defaultValue })] }))] })));
134
+ } })), audience === AudienceTypes.AUDIENCE_USERS && _jsx(UserAutocomplete, { onChange: handleUsersChange, defaultValue: value }), audience === AudienceTypes.AUDIENCE_GROUP && _jsx(GroupAutocomplete, { onChange: handleGroupChange, defaultValue: value }), audience === AudienceTypes.AUDIENCE_EVENT && _jsx(EventAutocomplete, { onChange: handleEventChange, defaultValue: value })] }))] })));
133
135
  });
134
136
  export default AudienceLayer;
@@ -1,6 +1,6 @@
1
1
  import { __awaiter, __rest } from "tslib";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import React, { Fragment, useEffect, useMemo, useState } from 'react';
3
+ import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react';
4
4
  import { FormattedMessage } from 'react-intl';
5
5
  import parse from 'autosuggest-highlight/parse';
6
6
  import match from 'autosuggest-highlight/match';
@@ -44,16 +44,18 @@ const UserAutocomplete = (inProps) => {
44
44
  .filter(Boolean)
45
45
  .join(','), [value]);
46
46
  // Fetch users excluding selected ones
47
- const { users, isLoading } = useSCFetchUsers({ search: inputValue, exclude: excludeIds });
47
+ const { users, isLoading } = useSCFetchUsers({ search: (inputValue === null || inputValue === void 0 ? void 0 : inputValue.length) >= 3 ? inputValue : '', exclude: excludeIds });
48
48
  const filteredUsers = users.filter((u) => !excludeIds.includes(u.id));
49
49
  useEffect(() => {
50
50
  onChange === null || onChange === void 0 ? void 0 : onChange(value);
51
51
  setTextAreaValue(value.map((u) => (typeof u === 'object' ? u.username : u)).join('\n'));
52
52
  }, [value]);
53
53
  // Handlers
54
- const handleOpen = () => {
55
- filteredUsers.length > 0 && setOpen(true);
56
- };
54
+ const handleOpen = useCallback(() => {
55
+ if (filteredUsers.length > 0) {
56
+ setOpen(true);
57
+ }
58
+ }, [filteredUsers]);
57
59
  const handleClose = () => {
58
60
  setOpen(false);
59
61
  };
@@ -65,24 +67,37 @@ const UserAutocomplete = (inProps) => {
65
67
  .split(/\s|,|\n/)
66
68
  .map((s) => s.trim())
67
69
  .filter(Boolean)));
68
- let resolvedUsers = [];
69
70
  try {
70
71
  if (names.length > 0) {
71
- const resp = yield UserService.matchUsernames(names.join(','));
72
- const matchedMap = new Map(resp.map((u) => [u.username, u]));
73
- resolvedUsers = names.map((name) => matchedMap.get(name) || name);
72
+ const resp = yield UserService.matchUsernames(names);
73
+ const resolvedUsernames = new Set(resp.map((u) => u.username));
74
+ const resolvedUsers = resp.filter((u) => resolvedUsernames.has(u.username));
75
+ setValue(resolvedUsers);
76
+ setTextAreaValue(resolvedUsers.map((u) => u.username).join('\n'));
77
+ }
78
+ else {
79
+ setValue([]);
80
+ setTextAreaValue('');
74
81
  }
75
82
  }
76
83
  catch (err) {
77
- console.error(`Failed fetching users`, err);
78
- resolvedUsers = names;
84
+ console.error(`Failed fetching matching usernames`, err);
85
+ setValue([]);
86
+ setTextAreaValue('');
79
87
  }
80
- setValue(resolvedUsers);
81
- setTextAreaValue(e.target.value);
82
88
  });
83
- return (_jsxs(Root, Object.assign({ className: classes.root }, { children: [_jsx(AutocompleteRoot, Object.assign({ multiple: true, className: classes.autocompleteRoot, open: open, onOpen: handleOpen, onClose: handleClose, options: filteredUsers || [], getOptionLabel: (option) => option.username || '', value: value, inputValue: inputValue, onInputChange: (_event, newInputValue) => {
89
+ const filterOptions = useCallback((options, state) => {
90
+ const search = state.inputValue.toLowerCase();
91
+ return options.filter((option) => {
92
+ var _a, _b;
93
+ const usernameMatch = (_a = option.username) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(search);
94
+ const nameMatch = (_b = option.real_name) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes(search);
95
+ return usernameMatch || nameMatch;
96
+ });
97
+ }, []);
98
+ return (_jsxs(Root, Object.assign({ className: classes.root }, { children: [_jsx(AutocompleteRoot, Object.assign({ multiple: true, className: classes.autocompleteRoot, open: open, onOpen: handleOpen, onClose: handleClose, options: filteredUsers || [], filterOptions: filterOptions, getOptionLabel: (option) => option.username || '', value: value, inputValue: inputValue, onInputChange: (_event, newInputValue) => {
84
99
  setInputValue(newInputValue);
85
- }, selectOnFocus: true, clearOnBlur: true, blurOnSelect: true, handleHomeEndKeys: true, clearIcon: null, disabled: disabled || isLoading, noOptionsText: _jsx(FormattedMessage, { id: "ui.userAutocomplete.empty", defaultMessage: "ui.userAutocomplete.empty" }), onChange: handleChange, isOptionEqualToValue: (option, val) => option.id === val.id, renderTags: (value, getTagProps) => value.map((option, index) => {
100
+ }, selectOnFocus: true, clearOnBlur: true, blurOnSelect: true, handleHomeEndKeys: true, clearIcon: null, disabled: disabled || isLoading, noOptionsText: _jsx(FormattedMessage, { id: "ui.userAutocomplete.empty", defaultMessage: "ui.userAutocomplete.empty" }), onChange: handleChange, isOptionEqualToValue: (option, val) => (option ? val.id === option.id : false), renderTags: (value, getTagProps) => value.map((option, index) => {
86
101
  const username = typeof option === 'string' ? option : option.username;
87
102
  const avatar = typeof option === 'string' ? '' : option.avatar;
88
103
  const id = typeof option === 'string' ? `fallback-${option}` : option.id;
@@ -90,8 +105,8 @@ const UserAutocomplete = (inProps) => {
90
105
  }), renderOption: (props, option, { inputValue }) => {
91
106
  const matches = match(option.username, inputValue);
92
107
  const parts = parse(option.username, matches);
93
- return (_jsxs(Box, Object.assign({ component: "li" }, props, { children: [_jsx(Avatar, { alt: option.username, src: option.avatar, sx: { marginRight: 1 } }), _jsx(React.Fragment, { children: parts.map((part, index) => (_jsx(Typography, Object.assign({ sx: { fontWeight: part.highlight ? 700 : 400 } }, { children: part.text }), index))) })] })));
94
- }, renderInput: (params) => (_jsx(TextField, Object.assign({}, params, TextFieldProps, { margin: "dense", InputProps: Object.assign(Object.assign({}, params.InputProps), { autoComplete: 'off', endAdornment: (_jsxs(Fragment, { children: [isLoading ? _jsx(CircularProgress, { color: "inherit", size: 20 }) : null, params.InputProps.endAdornment] })) }) }))) }, rest)), _jsx(Typography, Object.assign({ variant: "body2", color: "primary", className: classes.info }, { children: _jsx(FormattedMessage, { id: "ui.userAutocomplete.textarea.info", defaultMessage: "ui.userAutocomplete.textarea.info", values: {
108
+ return (_jsxs(Box, Object.assign({ component: "li" }, props, { children: [_jsx(Avatar, { alt: option.username, src: option.avatar, sx: { marginRight: 1 } }), _jsx(React.Fragment, { children: parts.map((part, index) => (_jsx(Typography, { children: part.text }, index))) })] })));
109
+ }, renderInput: (params) => (_jsx(TextField, Object.assign({}, params, TextFieldProps, { margin: "dense", InputProps: Object.assign(Object.assign({}, params.InputProps), { autoComplete: 'off', endAdornment: filteredUsers.length > 0 ? (_jsxs(Fragment, { children: [isLoading && _jsx(CircularProgress, { color: "inherit", size: 20 }), params.InputProps.endAdornment] })) : null }) }))) }, rest)), _jsx(Typography, Object.assign({ variant: "body2", color: "primary", className: classes.info }, { children: _jsx(FormattedMessage, { id: "ui.userAutocomplete.textarea.info", defaultMessage: "ui.userAutocomplete.textarea.info", values: {
95
110
  // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
96
111
  // @ts-ignore
97
112
  icon: (...chunks) => _jsx(Icon, { children: chunks })