@selfcommunity/react-ui 0.11.0-alpha.110 → 0.11.0-alpha.112

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.
@@ -76,16 +76,14 @@ function Category(inProps) {
76
76
  // MEMO
77
77
  const _ButtonBaseProps = (0, react_1.useMemo)(() => ButtonBaseProps ? ButtonBaseProps : { component: react_core_1.Link, to: scCategory ? scRoutingContext.url(react_core_1.SCRoutes.CATEGORY_ROUTE_NAME, scCategory) : '' }, [ButtonBaseProps, scRoutingContext, scCategory]);
78
78
  // HOOKS
79
- const intl = (0, react_intl_1.useIntl)();
80
79
  const categoryFollowEnabled = (0, react_core_1.useSCPreferenceEnabled)(react_core_1.SCPreferences.CONFIGURATIONS_CATEGORY_FOLLOW_ENABLED);
81
80
  if (!scCategory) {
82
81
  return (0, jsx_runtime_1.jsx)(Skeleton_1.default, Object.assign({ elevation: elevation }, (variant && { variant })));
83
82
  }
84
83
  // RENDER
85
84
  if (!autoHide) {
86
- return ((0, jsx_runtime_1.jsx)(Root, Object.assign({ disableTypography: showTooltip, elevation: elevation }, (variant && { variant }), { className: (0, classnames_1.default)(classes.root, className, { [classes.followed]: scCategory.followed }, { [classes.autoFollowed]: scCategory.auto_follow === types_1.SCCategoryAutoFollowType.FORCED }), ButtonBaseProps: _ButtonBaseProps, image: (0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: scCategory.name, src: scCategory.image_medium, variant: "square", className: classes.categoryImage }), primary: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: showTooltip ? ((0, jsx_runtime_1.jsx)(material_1.Tooltip, Object.assign({ title: scCategory.name }, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ className: classes.primary, component: "span", variant: "body1" }, { children: scCategory.name })) }))) : (scCategory.name) }), secondary: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: showTooltip ? ((0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ className: classes.secondary, component: "p", variant: "body2" }, { children: showFollowers && categoryFollowEnabled ? `${intl.formatMessage(messages.categoryFollowers, { total: scCategory.followers_counter })}` : scCategory.slogan }))) : ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: showFollowers && categoryFollowEnabled
87
- ? `${intl.formatMessage(messages.categoryFollowers, { total: scCategory.followers_counter })}`
88
- : scCategory.slogan })) }), actions: (0, jsx_runtime_1.jsx)(CategoryFollowButton_1.default, Object.assign({ category: scCategory }, categoryFollowButtonProps)) }, rest)));
85
+ return ((0, jsx_runtime_1.jsx)(Root, Object.assign({ disableTypography: showTooltip, elevation: elevation }, (variant && { variant }), { className: (0, classnames_1.default)(classes.root, className, { [classes.followed]: scCategory.followed }, { [classes.autoFollowed]: scCategory.auto_follow === types_1.SCCategoryAutoFollowType.FORCED }), ButtonBaseProps: _ButtonBaseProps, image: (0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: scCategory.name, src: scCategory.image_medium, variant: "square", className: classes.categoryImage }), primary: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: showTooltip ? ((0, jsx_runtime_1.jsx)(material_1.Tooltip, Object.assign({ title: scCategory.name }, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ className: classes.primary, component: "span", variant: "body1" }, { children: scCategory.name })) }))) : (scCategory.name) }), secondary: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: showTooltip && showFollowers && categoryFollowEnabled ? ((0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ className: classes.secondary, component: "p", variant: "body2" }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, Object.assign({}, messages.categoryFollowers, { values: { total: scCategory.followers_counter } })) }))) : (showFollowers &&
86
+ categoryFollowEnabled && (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, Object.assign({}, messages.categoryFollowers, { values: { total: scCategory.followers_counter } }))) }), actions: (0, jsx_runtime_1.jsx)(CategoryFollowButton_1.default, Object.assign({ category: scCategory }, categoryFollowButtonProps)) }, rest)));
89
87
  }
90
88
  return null;
91
89
  }
@@ -10,6 +10,8 @@ const material_1 = require("@mui/material");
10
10
  const system_1 = require("@mui/system");
11
11
  const TagChip_1 = tslib_1.__importDefault(require("../../shared/TagChip"));
12
12
  const api_services_1 = require("@selfcommunity/api-services");
13
+ const Errors_1 = require("../../constants/Errors");
14
+ const utils_1 = require("@selfcommunity/utils");
13
15
  const PREFIX = 'SCTagAutocomplete';
14
16
  const classes = {
15
17
  root: `${PREFIX}-root`
@@ -55,24 +57,28 @@ const TagAutocomplete = (inProps) => {
55
57
  const [value, setValue] = (0, react_1.useState)(typeof defaultValue === 'string' ? null : defaultValue);
56
58
  const [tags, setTags] = (0, react_1.useState)([]);
57
59
  const [inputValue, setInputValue] = (0, react_1.useState)('');
60
+ const [loading, setLoading] = (0, react_1.useState)(true);
61
+ const fetchTags = (query) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
62
+ setLoading(true);
63
+ try {
64
+ const res = yield api_services_1.TagService.searchUserTags({ search: query || '' });
65
+ const results = (res === null || res === void 0 ? void 0 : res.results) || [];
66
+ setTags(results);
67
+ return results;
68
+ }
69
+ catch (error) {
70
+ utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error);
71
+ setTags([]);
72
+ return [];
73
+ }
74
+ finally {
75
+ setLoading(false);
76
+ }
77
+ });
58
78
  (0, react_1.useEffect)(() => {
59
- let active = true;
60
79
  if (open && inputValue.length >= 3) {
61
- api_services_1.TagService.searchUserTags({ search: inputValue || '' })
62
- .then((res) => {
63
- if (active) {
64
- setTags((res === null || res === void 0 ? void 0 : res.results) || []);
65
- }
66
- })
67
- .catch(() => {
68
- if (active) {
69
- setTags([]);
70
- }
71
- });
80
+ fetchTags(inputValue);
72
81
  }
73
- return () => {
74
- active = false;
75
- };
76
82
  }, [open, inputValue]);
77
83
  (0, react_1.useEffect)(() => {
78
84
  if (value !== null) {
@@ -80,10 +86,16 @@ const TagAutocomplete = (inProps) => {
80
86
  }
81
87
  }, [value]);
82
88
  (0, react_1.useEffect)(() => {
83
- if ((tags === null || tags === void 0 ? void 0 : tags.length) !== 0 && typeof defaultValue === 'string') {
84
- setValue(tags.find((t) => t.id === Number(defaultValue)));
85
- }
86
- }, [tags, defaultValue]);
89
+ const loadDefault = () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
90
+ if (typeof defaultValue === 'string' && defaultValue.trim() !== '') {
91
+ const results = yield fetchTags(defaultValue);
92
+ const match = results.find((t) => t.id === Number(defaultValue));
93
+ if (match)
94
+ setValue(match);
95
+ }
96
+ });
97
+ loadDefault();
98
+ }, [defaultValue]);
87
99
  // Handlers
88
100
  const handleOpen = () => {
89
101
  if (inputValue.length >= 3) {
@@ -92,12 +104,21 @@ const TagAutocomplete = (inProps) => {
92
104
  };
93
105
  const handleClose = () => setOpen(false);
94
106
  const handleChange = (_event, newValue) => setValue(newValue);
95
- return ((0, jsx_runtime_1.jsx)(Root, Object.assign({ className: classes.root, open: open, onOpen: handleOpen, onClose: handleClose, options: tags || [], 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 === null || value === void 0 ? void 0 : value.id) === (option === null || option === void 0 ? void 0 : option.id), inputValue: inputValue, onInputChange: (_e, newInputValue) => setInputValue(newInputValue), renderTags: (value, getTagProps) => value.map((option, index) => (0, jsx_runtime_1.jsx)(TagChip_1.default, Object.assign({ tag: option }, getTagProps({ index })), option.id)), renderOption: (props, option, { inputValue }) => {
107
+ const filterOptions = (0, react_1.useCallback)((options, state) => {
108
+ const search = state.inputValue.toLowerCase();
109
+ return options.filter((option) => {
110
+ var _a, _b;
111
+ const nameMatch = (_a = option.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(search);
112
+ const descMatch = (_b = option.description) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes(search);
113
+ return nameMatch || descMatch;
114
+ });
115
+ }, []);
116
+ return ((0, jsx_runtime_1.jsx)(Root, Object.assign({ className: classes.root, open: open, onOpen: handleOpen, onClose: handleClose, options: tags || [], filterOptions: filterOptions, 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 === null || value === void 0 ? void 0 : value.id) === (option === null || option === void 0 ? void 0 : option.id), inputValue: inputValue, onInputChange: (_e, newInputValue) => setInputValue(newInputValue), renderOption: (props, option, { inputValue }) => {
96
117
  const matches = (0, match_1.default)(option.name, inputValue);
97
118
  const parts = (0, parse_1.default)(option.name, matches);
98
119
  return ((0, jsx_runtime_1.jsx)("li", Object.assign({}, props, { children: (0, jsx_runtime_1.jsx)(TagChip_1.default, Object.assign({ 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))) }) }, TagChipProps), option.id) })));
99
120
  }, renderInput: (params) => {
100
- return ((0, jsx_runtime_1.jsx)(material_1.TextField, Object.assign({}, params, TextFieldProps, { InputProps: Object.assign(Object.assign({}, params.InputProps), { autoComplete: 'addressing', endAdornment: tags.length > 0 ? (0, jsx_runtime_1.jsx)(react_1.Fragment, { children: params.InputProps.endAdornment }) : null }) })));
121
+ return ((0, jsx_runtime_1.jsx)(material_1.TextField, Object.assign({}, params, TextFieldProps, { InputProps: Object.assign(Object.assign({}, params.InputProps), { autoComplete: 'tags', endAdornment: tags.length > 0 ? ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [loading && (0, jsx_runtime_1.jsx)(material_1.CircularProgress, { color: "inherit", size: 20 }), params.InputProps.endAdornment] })) : null }) })));
101
122
  } }, rest)));
102
123
  };
103
124
  exports.default = TagAutocomplete;
@@ -6,7 +6,7 @@ import { Link, SCPreferences, SCRoutes, useSCFetchCategory, useSCPreferenceEnabl
6
6
  import { SCCategoryAutoFollowType } from '@selfcommunity/types';
7
7
  import CategorySkeleton from './Skeleton';
8
8
  import CategoryFollowButton from '../CategoryFollowButton';
9
- import { defineMessages, useIntl } from 'react-intl';
9
+ import { defineMessages, FormattedMessage } from 'react-intl';
10
10
  import classNames from 'classnames';
11
11
  import { useThemeProps } from '@mui/system';
12
12
  import BaseItemButton from '../../shared/BaseItemButton';
@@ -74,16 +74,14 @@ export default function Category(inProps) {
74
74
  // MEMO
75
75
  const _ButtonBaseProps = useMemo(() => ButtonBaseProps ? ButtonBaseProps : { component: Link, to: scCategory ? scRoutingContext.url(SCRoutes.CATEGORY_ROUTE_NAME, scCategory) : '' }, [ButtonBaseProps, scRoutingContext, scCategory]);
76
76
  // HOOKS
77
- const intl = useIntl();
78
77
  const categoryFollowEnabled = useSCPreferenceEnabled(SCPreferences.CONFIGURATIONS_CATEGORY_FOLLOW_ENABLED);
79
78
  if (!scCategory) {
80
79
  return _jsx(CategorySkeleton, Object.assign({ elevation: elevation }, (variant && { variant })));
81
80
  }
82
81
  // RENDER
83
82
  if (!autoHide) {
84
- return (_jsx(Root, Object.assign({ disableTypography: showTooltip, elevation: elevation }, (variant && { variant }), { className: classNames(classes.root, className, { [classes.followed]: scCategory.followed }, { [classes.autoFollowed]: scCategory.auto_follow === SCCategoryAutoFollowType.FORCED }), ButtonBaseProps: _ButtonBaseProps, image: _jsx(Avatar, { alt: scCategory.name, src: scCategory.image_medium, variant: "square", className: classes.categoryImage }), primary: _jsx(_Fragment, { children: showTooltip ? (_jsx(Tooltip, Object.assign({ title: scCategory.name }, { children: _jsx(Typography, Object.assign({ className: classes.primary, component: "span", variant: "body1" }, { children: scCategory.name })) }))) : (scCategory.name) }), secondary: _jsx(_Fragment, { children: showTooltip ? (_jsx(Typography, Object.assign({ className: classes.secondary, component: "p", variant: "body2" }, { children: showFollowers && categoryFollowEnabled ? `${intl.formatMessage(messages.categoryFollowers, { total: scCategory.followers_counter })}` : scCategory.slogan }))) : (_jsx(_Fragment, { children: showFollowers && categoryFollowEnabled
85
- ? `${intl.formatMessage(messages.categoryFollowers, { total: scCategory.followers_counter })}`
86
- : scCategory.slogan })) }), actions: _jsx(CategoryFollowButton, Object.assign({ category: scCategory }, categoryFollowButtonProps)) }, rest)));
83
+ return (_jsx(Root, Object.assign({ disableTypography: showTooltip, elevation: elevation }, (variant && { variant }), { className: classNames(classes.root, className, { [classes.followed]: scCategory.followed }, { [classes.autoFollowed]: scCategory.auto_follow === SCCategoryAutoFollowType.FORCED }), ButtonBaseProps: _ButtonBaseProps, image: _jsx(Avatar, { alt: scCategory.name, src: scCategory.image_medium, variant: "square", className: classes.categoryImage }), primary: _jsx(_Fragment, { children: showTooltip ? (_jsx(Tooltip, Object.assign({ title: scCategory.name }, { children: _jsx(Typography, Object.assign({ className: classes.primary, component: "span", variant: "body1" }, { children: scCategory.name })) }))) : (scCategory.name) }), secondary: _jsx(_Fragment, { children: showTooltip && showFollowers && categoryFollowEnabled ? (_jsx(Typography, Object.assign({ className: classes.secondary, component: "p", variant: "body2" }, { children: _jsx(FormattedMessage, Object.assign({}, messages.categoryFollowers, { values: { total: scCategory.followers_counter } })) }))) : (showFollowers &&
84
+ categoryFollowEnabled && _jsx(FormattedMessage, Object.assign({}, messages.categoryFollowers, { values: { total: scCategory.followers_counter } }))) }), actions: _jsx(CategoryFollowButton, Object.assign({ category: scCategory }, categoryFollowButtonProps)) }, rest)));
87
85
  }
88
86
  return null;
89
87
  }
@@ -1,13 +1,15 @@
1
- import { __rest } from "tslib";
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import React, { Fragment, useEffect, useState } from 'react';
1
+ import { __awaiter, __rest } from "tslib";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import React, { Fragment, useCallback, useEffect, 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';
7
- import { Autocomplete, TextField, styled } from '@mui/material';
7
+ import { Autocomplete, TextField, styled, CircularProgress } from '@mui/material';
8
8
  import { useThemeProps } from '@mui/system';
9
9
  import TagChip from '../../shared/TagChip';
10
10
  import { TagService } from '@selfcommunity/api-services';
11
+ import { SCOPE_SC_UI } from '../../constants/Errors';
12
+ import { Logger } from '@selfcommunity/utils';
11
13
  const PREFIX = 'SCTagAutocomplete';
12
14
  const classes = {
13
15
  root: `${PREFIX}-root`
@@ -53,24 +55,28 @@ const TagAutocomplete = (inProps) => {
53
55
  const [value, setValue] = useState(typeof defaultValue === 'string' ? null : defaultValue);
54
56
  const [tags, setTags] = useState([]);
55
57
  const [inputValue, setInputValue] = useState('');
58
+ const [loading, setLoading] = useState(true);
59
+ const fetchTags = (query) => __awaiter(void 0, void 0, void 0, function* () {
60
+ setLoading(true);
61
+ try {
62
+ const res = yield TagService.searchUserTags({ search: query || '' });
63
+ const results = (res === null || res === void 0 ? void 0 : res.results) || [];
64
+ setTags(results);
65
+ return results;
66
+ }
67
+ catch (error) {
68
+ Logger.error(SCOPE_SC_UI, error);
69
+ setTags([]);
70
+ return [];
71
+ }
72
+ finally {
73
+ setLoading(false);
74
+ }
75
+ });
56
76
  useEffect(() => {
57
- let active = true;
58
77
  if (open && inputValue.length >= 3) {
59
- TagService.searchUserTags({ search: inputValue || '' })
60
- .then((res) => {
61
- if (active) {
62
- setTags((res === null || res === void 0 ? void 0 : res.results) || []);
63
- }
64
- })
65
- .catch(() => {
66
- if (active) {
67
- setTags([]);
68
- }
69
- });
78
+ fetchTags(inputValue);
70
79
  }
71
- return () => {
72
- active = false;
73
- };
74
80
  }, [open, inputValue]);
75
81
  useEffect(() => {
76
82
  if (value !== null) {
@@ -78,10 +84,16 @@ const TagAutocomplete = (inProps) => {
78
84
  }
79
85
  }, [value]);
80
86
  useEffect(() => {
81
- if ((tags === null || tags === void 0 ? void 0 : tags.length) !== 0 && typeof defaultValue === 'string') {
82
- setValue(tags.find((t) => t.id === Number(defaultValue)));
83
- }
84
- }, [tags, defaultValue]);
87
+ const loadDefault = () => __awaiter(void 0, void 0, void 0, function* () {
88
+ if (typeof defaultValue === 'string' && defaultValue.trim() !== '') {
89
+ const results = yield fetchTags(defaultValue);
90
+ const match = results.find((t) => t.id === Number(defaultValue));
91
+ if (match)
92
+ setValue(match);
93
+ }
94
+ });
95
+ loadDefault();
96
+ }, [defaultValue]);
85
97
  // Handlers
86
98
  const handleOpen = () => {
87
99
  if (inputValue.length >= 3) {
@@ -90,12 +102,21 @@ const TagAutocomplete = (inProps) => {
90
102
  };
91
103
  const handleClose = () => setOpen(false);
92
104
  const handleChange = (_event, newValue) => setValue(newValue);
93
- return (_jsx(Root, Object.assign({ className: classes.root, open: open, onOpen: handleOpen, onClose: handleClose, options: tags || [], 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 === null || value === void 0 ? void 0 : value.id) === (option === null || option === void 0 ? void 0 : option.id), inputValue: inputValue, onInputChange: (_e, newInputValue) => setInputValue(newInputValue), renderTags: (value, getTagProps) => value.map((option, index) => _jsx(TagChip, Object.assign({ tag: option }, getTagProps({ index })), option.id)), renderOption: (props, option, { inputValue }) => {
105
+ const filterOptions = useCallback((options, state) => {
106
+ const search = state.inputValue.toLowerCase();
107
+ return options.filter((option) => {
108
+ var _a, _b;
109
+ const nameMatch = (_a = option.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(search);
110
+ const descMatch = (_b = option.description) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes(search);
111
+ return nameMatch || descMatch;
112
+ });
113
+ }, []);
114
+ return (_jsx(Root, Object.assign({ className: classes.root, open: open, onOpen: handleOpen, onClose: handleClose, options: tags || [], filterOptions: filterOptions, 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 === null || value === void 0 ? void 0 : value.id) === (option === null || option === void 0 ? void 0 : option.id), inputValue: inputValue, onInputChange: (_e, newInputValue) => setInputValue(newInputValue), renderOption: (props, option, { inputValue }) => {
94
115
  const matches = match(option.name, inputValue);
95
116
  const parts = parse(option.name, matches);
96
117
  return (_jsx("li", Object.assign({}, props, { children: _jsx(TagChip, Object.assign({ 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))) }) }, TagChipProps), option.id) })));
97
118
  }, renderInput: (params) => {
98
- return (_jsx(TextField, Object.assign({}, params, TextFieldProps, { InputProps: Object.assign(Object.assign({}, params.InputProps), { autoComplete: 'addressing', endAdornment: tags.length > 0 ? _jsx(Fragment, { children: params.InputProps.endAdornment }) : null }) })));
119
+ return (_jsx(TextField, Object.assign({}, params, TextFieldProps, { InputProps: Object.assign(Object.assign({}, params.InputProps), { autoComplete: 'tags', endAdornment: tags.length > 0 ? (_jsxs(Fragment, { children: [loading && _jsx(CircularProgress, { color: "inherit", size: 20 }), params.InputProps.endAdornment] })) : null }) })));
99
120
  } }, rest)));
100
121
  };
101
122
  export default TagAutocomplete;