@selfcommunity/react-ui 0.7.50-event.29 → 0.7.50-events.28

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.
Files changed (58) hide show
  1. package/lib/cjs/components/Category/Category.d.ts +1 -1
  2. package/lib/cjs/components/Category/Category.js +1 -1
  3. package/lib/cjs/components/Event/Event.d.ts +0 -6
  4. package/lib/cjs/components/Event/Event.js +4 -4
  5. package/lib/cjs/components/Event/Skeleton.d.ts +16 -2
  6. package/lib/cjs/components/Event/Skeleton.js +16 -8
  7. package/lib/cjs/components/Event/index.d.ts +2 -2
  8. package/lib/cjs/components/EventForm/EventForm.js +30 -17
  9. package/lib/cjs/components/EventInviteButton/EventInviteButton.d.ts +57 -0
  10. package/lib/cjs/components/EventInviteButton/EventInviteButton.js +284 -0
  11. package/lib/cjs/components/EventInviteButton/index.d.ts +3 -0
  12. package/lib/cjs/components/EventInviteButton/index.js +5 -0
  13. package/lib/cjs/components/Events/Events.d.ts +64 -0
  14. package/lib/cjs/components/Events/Events.js +230 -0
  15. package/lib/cjs/components/Events/Skeleton.d.ts +38 -0
  16. package/lib/cjs/components/Events/Skeleton.js +45 -0
  17. package/lib/cjs/components/Events/constants.d.ts +1 -0
  18. package/lib/cjs/components/Events/constants.js +4 -0
  19. package/lib/cjs/components/Events/index.d.ts +4 -0
  20. package/lib/cjs/components/Events/index.js +8 -0
  21. package/lib/cjs/components/Events/prefetchedEvents.d.ts +271 -0
  22. package/lib/cjs/components/Events/prefetchedEvents.js +278 -0
  23. package/lib/cjs/components/FeedObject/FeedObject.d.ts +1 -0
  24. package/lib/cjs/components/FeedObject/FeedObject.js +16 -4
  25. package/lib/cjs/constants/PubSub.d.ts +3 -8
  26. package/lib/cjs/constants/PubSub.js +2 -1
  27. package/lib/cjs/index.d.ts +4 -2
  28. package/lib/cjs/index.js +7 -2
  29. package/lib/esm/components/Category/Category.d.ts +1 -1
  30. package/lib/esm/components/Category/Category.js +1 -1
  31. package/lib/esm/components/Event/Event.d.ts +0 -6
  32. package/lib/esm/components/Event/Event.js +4 -4
  33. package/lib/esm/components/Event/Skeleton.d.ts +16 -2
  34. package/lib/esm/components/Event/Skeleton.js +17 -9
  35. package/lib/esm/components/Event/index.d.ts +2 -2
  36. package/lib/esm/components/EventForm/EventForm.js +30 -17
  37. package/lib/esm/components/EventInviteButton/EventInviteButton.d.ts +57 -0
  38. package/lib/esm/components/EventInviteButton/EventInviteButton.js +281 -0
  39. package/lib/esm/components/EventInviteButton/index.d.ts +3 -0
  40. package/lib/esm/components/EventInviteButton/index.js +2 -0
  41. package/lib/esm/components/Events/Events.d.ts +64 -0
  42. package/lib/esm/components/Events/Events.js +227 -0
  43. package/lib/esm/components/Events/Skeleton.d.ts +38 -0
  44. package/lib/esm/components/Events/Skeleton.js +42 -0
  45. package/lib/esm/components/Events/constants.d.ts +1 -0
  46. package/lib/esm/components/Events/constants.js +1 -0
  47. package/lib/esm/components/Events/index.d.ts +4 -0
  48. package/lib/esm/components/Events/index.js +4 -0
  49. package/lib/esm/components/Events/prefetchedEvents.d.ts +271 -0
  50. package/lib/esm/components/Events/prefetchedEvents.js +275 -0
  51. package/lib/esm/components/FeedObject/FeedObject.d.ts +1 -0
  52. package/lib/esm/components/FeedObject/FeedObject.js +16 -4
  53. package/lib/esm/constants/PubSub.d.ts +3 -8
  54. package/lib/esm/constants/PubSub.js +2 -1
  55. package/lib/esm/index.d.ts +4 -2
  56. package/lib/esm/index.js +3 -1
  57. package/lib/umd/react-ui.js +1 -1
  58. package/package.json +6 -6
@@ -3,7 +3,7 @@ import { CategoryFollowButtonProps } from '../CategoryFollowButton';
3
3
  import { WidgetProps } from '../Widget';
4
4
  export interface CategoryProps extends WidgetProps {
5
5
  /**
6
- * Category id
6
+ * Category Id
7
7
  * @default null
8
8
  */
9
9
  categoryId?: number;
@@ -72,7 +72,7 @@ function Category(inProps) {
72
72
  // CONTEXT
73
73
  const scRoutingContext = (0, react_core_1.useSCRouting)();
74
74
  // STATE
75
- const { scCategory } = (0, react_core_1.useSCFetchCategory)({ id: categoryId, category });
75
+ const { scCategory, setSCCategory } = (0, react_core_1.useSCFetchCategory)({ id: categoryId, category });
76
76
  // MEMO
77
77
  const _ButtonBaseProps = (0, react_1.useMemo)(() => (ButtonBaseProps ? ButtonBaseProps : { component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.CATEGORY_ROUTE_NAME, scCategory) }), [ButtonBaseProps, scRoutingContext, scCategory]);
78
78
  // HOOKS
@@ -1,4 +1,3 @@
1
- import { ButtonBaseProps } from '@mui/material';
2
1
  import { SCEventType } from '@selfcommunity/types';
3
2
  import { WidgetProps } from '../Widget';
4
3
  export interface EventProps extends WidgetProps {
@@ -12,11 +11,6 @@ export interface EventProps extends WidgetProps {
12
11
  * @default null
13
12
  */
14
13
  eventId?: number;
15
- /**
16
- * Props to spread to the button
17
- * @default {}
18
- */
19
- buttonProps?: ButtonBaseProps;
20
14
  /**
21
15
  * Any other properties
22
16
  */
@@ -9,7 +9,7 @@ const react_core_1 = require("@selfcommunity/react-core");
9
9
  const react_intl_1 = require("react-intl");
10
10
  const classnames_1 = tslib_1.__importDefault(require("classnames"));
11
11
  const system_1 = require("@mui/system");
12
- const BaseItemButton_1 = tslib_1.__importDefault(require("../../shared/BaseItemButton"));
12
+ const BaseItem_1 = tslib_1.__importDefault(require("../../shared/BaseItem"));
13
13
  const constants_1 = require("./constants");
14
14
  const Skeleton_1 = tslib_1.__importDefault(require("./Skeleton"));
15
15
  const classes = {
@@ -19,7 +19,7 @@ const classes = {
19
19
  secondary: `${constants_1.PREFIX}-secondary`,
20
20
  actions: `${constants_1.PREFIX}-actions`
21
21
  };
22
- const Root = (0, styles_1.styled)(BaseItemButton_1.default, {
22
+ const Root = (0, styles_1.styled)(BaseItem_1.default, {
23
23
  name: constants_1.PREFIX,
24
24
  slot: 'Root',
25
25
  overridesResolver: (props, styles) => styles.root
@@ -62,7 +62,7 @@ function Event(inProps) {
62
62
  props: inProps,
63
63
  name: constants_1.PREFIX
64
64
  });
65
- const { eventId = null, event = null, className = null, elevation } = props, rest = tslib_1.__rest(props, ["eventId", "event", "className", "elevation"]);
65
+ const { eventId = null, event = null, className = null, elevation = 0 } = props, rest = tslib_1.__rest(props, ["eventId", "event", "className", "elevation"]);
66
66
  // STATE
67
67
  const { scEvent } = (0, react_core_1.useSCFetchEvent)({ id: eventId, event });
68
68
  // CONTEXT
@@ -78,7 +78,7 @@ function Event(inProps) {
78
78
  /**
79
79
  * Renders root object
80
80
  */
81
- return (react_1.default.createElement(Root, Object.assign({ elevation: elevation, disableTypography: true }, rest, { className: (0, classnames_1.default)(classes.root, className), ButtonBaseProps: { component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.EVENT_ROUTE_NAME, scEvent) }, image: react_1.default.createElement(material_1.Avatar, { variant: "square", alt: scEvent.name, src: scEvent.image_medium, className: classes.avatar }), primary: react_1.default.createElement(material_1.Typography, { component: "div", className: classes.primary },
81
+ return (react_1.default.createElement(Root, Object.assign({ elevation: elevation, disableTypography: true }, rest, { className: (0, classnames_1.default)(classes.root, className), image: react_1.default.createElement(material_1.Avatar, { variant: "square", alt: scEvent.name, src: scEvent.image_medium, className: classes.avatar }), primary: react_1.default.createElement(material_1.Typography, { component: "div", className: classes.primary },
82
82
  react_1.default.createElement(material_1.Typography, { component: "span" }, `${intl.formatDate(scEvent.start_date, { weekday: 'long', month: 'long', day: 'numeric' })}`),
83
83
  react_1.default.createElement(material_1.Typography, { variant: "body1" }, scEvent.name)), secondary: react_1.default.createElement(material_1.Typography, { component: "p", variant: "body2", className: classes.secondary },
84
84
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: `ui.eventForm.privacy.${scEvent.privacy}`, defaultMessage: `ui.eventForm.privacy.${scEvent.privacy}` }),
@@ -1,4 +1,16 @@
1
- import { WidgetProps } from '../Widget';
1
+ import React from 'react';
2
+ import { BaseItemProps } from '../../shared/BaseItem';
3
+ export interface EventSkeletonProps extends BaseItemProps {
4
+ /**
5
+ * Overrides or extends the styles applied to the component.
6
+ * @default null
7
+ */
8
+ className?: string;
9
+ /**
10
+ * Prop to pass an action to be rendered next to the skeleton
11
+ */
12
+ action?: React.ReactNode;
13
+ }
2
14
  /**
3
15
  * > API documentation for the Community-JS Event Skeleton component. Learn about the available props and the CSS API.
4
16
 
@@ -17,6 +29,8 @@ import { WidgetProps } from '../Widget';
17
29
  |Rule Name|Global class|Description|
18
30
  |---|---|---|
19
31
  |root|.SCEvent-skeleton-root|Styles applied to the root element.|
32
+ |image|.SCEvent-skeleton-image|Styles applied to the image element.|
33
+ |action|.SCEvent-skeleton-action|Styles applied to action section.|
20
34
  *
21
35
  */
22
- export default function EventSkeleton(props: WidgetProps): JSX.Element;
36
+ export default function EventSkeleton(inProps: EventSkeletonProps): JSX.Element;
@@ -5,10 +5,13 @@ const react_1 = tslib_1.__importDefault(require("react"));
5
5
  const material_1 = require("@mui/material");
6
6
  const styles_1 = require("@mui/material/styles");
7
7
  const Skeleton_1 = tslib_1.__importDefault(require("@mui/material/Skeleton"));
8
- const BaseItem_1 = tslib_1.__importDefault(require("../../shared/BaseItem"));
9
8
  const constants_1 = require("./constants");
9
+ const classnames_1 = tslib_1.__importDefault(require("classnames"));
10
+ const BaseItem_1 = tslib_1.__importDefault(require("../../shared/BaseItem"));
10
11
  const classes = {
11
- root: `${constants_1.PREFIX}-skeleton-root`
12
+ root: `${constants_1.PREFIX}-skeleton-root`,
13
+ image: `${constants_1.PREFIX}-skeleton-image`,
14
+ action: `${constants_1.PREFIX}-skeleton-action`
12
15
  };
13
16
  const Root = (0, styles_1.styled)(BaseItem_1.default, {
14
17
  name: constants_1.PREFIX,
@@ -32,13 +35,18 @@ const Root = (0, styles_1.styled)(BaseItem_1.default, {
32
35
  |Rule Name|Global class|Description|
33
36
  |---|---|---|
34
37
  |root|.SCEvent-skeleton-root|Styles applied to the root element.|
38
+ |image|.SCEvent-skeleton-image|Styles applied to the image element.|
39
+ |action|.SCEvent-skeleton-action|Styles applied to action section.|
35
40
  *
36
41
  */
37
- function EventSkeleton(props) {
38
- //const theme = useTheme<SCThemeType>();
39
- return (react_1.default.createElement(Root, Object.assign({ className: classes.root }, props, { image: react_1.default.createElement(Skeleton_1.default, { animation: "wave", variant: "rectangular", width: 100, height: 60 }), primary: react_1.default.createElement(Skeleton_1.default, { animation: "wave", height: 10, width: 120, style: { marginBottom: 10 } }), secondary: react_1.default.createElement(react_1.default.Fragment, null,
40
- react_1.default.createElement(Skeleton_1.default, { animation: "wave", height: 10, width: 120, style: { marginBottom: 10 } }),
41
- react_1.default.createElement(Skeleton_1.default, { animation: "wave", height: 10, width: 120, style: { marginBottom: 10 } })), actions: react_1.default.createElement(material_1.Button, { size: "small", variant: "outlined", disabled: true },
42
- react_1.default.createElement(Skeleton_1.default, { animation: "wave", height: 10, width: 30, style: { marginTop: 5, marginBottom: 5 } })) })));
42
+ function EventSkeleton(inProps) {
43
+ const { className, action } = inProps;
44
+ return (react_1.default.createElement(Root, { elevation: 0, className: (0, classnames_1.default)(classes.root, className), image: react_1.default.createElement(material_1.Box, { className: classes.image },
45
+ react_1.default.createElement(Skeleton_1.default, { animation: "wave", variant: "rectangular", width: 100, height: 60 }),
46
+ " ",
47
+ react_1.default.createElement(material_1.Icon, { fontSize: "large" }, "CalendarIcon")), primary: react_1.default.createElement(Skeleton_1.default, { animation: "wave", variant: "rectangular", height: 10, width: 100, style: { marginBottom: 12 } }), secondary: react_1.default.createElement(react_1.default.Fragment, null,
48
+ react_1.default.createElement(Skeleton_1.default, { animation: "wave", variant: "rectangular", height: 10, width: 160, style: { marginBottom: 10 } }),
49
+ react_1.default.createElement(Skeleton_1.default, { animation: "wave", variant: "rectangular", height: 10, width: 90 })), actions: react_1.default.createElement(react_1.default.Fragment, null, action !== null && action !== void 0 ? action : (react_1.default.createElement(material_1.Button, { size: "small", variant: "outlined", disabled: true },
50
+ react_1.default.createElement(Skeleton_1.default, { animation: "wave", height: 10, width: 30, style: { marginTop: 5, marginBottom: 5 } })))) }));
43
51
  }
44
52
  exports.default = EventSkeleton;
@@ -1,4 +1,4 @@
1
1
  import Event, { EventProps } from './Event';
2
- import EventSkeleton from './Skeleton';
2
+ import EventSkeleton, { EventSkeletonProps } from './Skeleton';
3
3
  export default Event;
4
- export { EventProps, EventSkeleton };
4
+ export { EventProps, EventSkeleton, EventSkeletonProps };
@@ -122,13 +122,13 @@ function EventForm(inProps) {
122
122
  // INTL
123
123
  const intl = (0, react_intl_1.useIntl)();
124
124
  const initialFieldState = {
125
- emotionalImageOriginal: '',
126
- emotionalImageOriginalFile: '',
125
+ imageOriginal: '',
126
+ imageOriginalFile: '',
127
127
  startDate: null,
128
128
  startTime: null,
129
129
  endDate: null,
130
130
  endTime: null,
131
- location: '',
131
+ location: types_1.SCEventLocationType.PERSON,
132
132
  geolocation: '',
133
133
  lat: null,
134
134
  lng: null,
@@ -146,8 +146,9 @@ function EventForm(inProps) {
146
146
  // PREFERENCES
147
147
  const scPreferences = (0, react_core_1.useSCPreferences)();
148
148
  const privateEnabled = (0, react_1.useMemo)(() => scPreferences.preferences[react_core_1.SCPreferences.CONFIGURATIONS_EVENTS_PRIVATE_ENABLED].value, [scPreferences.preferences]);
149
- const _backgroundCover = Object.assign({}, (field.emotionalImageOriginal
150
- ? { background: `url('${field.emotionalImageOriginal}') center / cover` }
149
+ const visibilityEnabled = (0, react_1.useMemo)(() => scPreferences.preferences[react_core_1.SCPreferences.CONFIGURATIONS_EVENTS_VISIBILITY_ENABLED].value, [scPreferences.preferences]);
150
+ const _backgroundCover = Object.assign({}, (field.imageOriginal
151
+ ? { background: `url('${field.imageOriginal}') center / cover` }
151
152
  : { background: `url('${scPreferences.preferences[react_core_1.SCPreferences.IMAGES_USER_DEFAULT_COVER].value}') center / cover` }));
152
153
  const combineDateAndTime = (date, time) => {
153
154
  if (date && time) {
@@ -161,14 +162,14 @@ function EventForm(inProps) {
161
162
  return null;
162
163
  };
163
164
  function handleChangeCover(cover) {
164
- setField((prev) => (Object.assign(Object.assign({}, prev), { ['emotionalImageOriginalFile']: cover })));
165
+ setField((prev) => (Object.assign(Object.assign({}, prev), { ['imageOriginalFile']: cover })));
165
166
  const reader = new FileReader();
166
167
  reader.onloadend = () => {
167
- setField((prev) => (Object.assign(Object.assign({}, prev), { ['emotionalImageOriginal']: reader.result })));
168
+ setField((prev) => (Object.assign(Object.assign({}, prev), { ['imageOriginal']: reader.result })));
168
169
  };
169
170
  reader.readAsDataURL(cover);
170
- if (error.emotionalImageOriginalError) {
171
- delete error.emotionalImageOriginalError;
171
+ if (error.imageOriginalError) {
172
+ delete error.imageOriginalError;
172
173
  setError(error);
173
174
  }
174
175
  }
@@ -178,8 +179,8 @@ function EventForm(inProps) {
178
179
  const handleSubmit = () => {
179
180
  setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: true })));
180
181
  const formData = new FormData();
181
- if (field.emotionalImageOriginalFile) {
182
- formData.append('emotional_image_original', field.emotionalImageOriginalFile);
182
+ if (field.imageOriginalFile) {
183
+ formData.append('image_original', field.imageOriginalFile);
183
184
  }
184
185
  formData.append('name', field.name);
185
186
  formData.append('start_date', combineDateAndTime(field.startDate, field.startTime));
@@ -199,6 +200,9 @@ function EventForm(inProps) {
199
200
  if (privateEnabled) {
200
201
  formData.append('privacy', field.isPublic ? types_1.SCEventPrivacyType.PUBLIC : types_1.SCEventPrivacyType.PRIVATE);
201
202
  }
203
+ if (visibilityEnabled) {
204
+ formData.append('visible', true);
205
+ }
202
206
  formData.append('description', field.description);
203
207
  api_services_1.EventService.createEvent(formData, { headers: { 'Content-Type': 'multipart/form-data' } })
204
208
  .then((data) => {
@@ -207,7 +211,15 @@ function EventForm(inProps) {
207
211
  setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: false })));
208
212
  })
209
213
  .catch((e) => {
210
- setError(Object.assign(Object.assign({}, error), (0, api_services_1.formatHttpErrorCode)(e)));
214
+ const _error = (0, api_services_1.formatHttpErrorCode)(e);
215
+ // eslint-disable-next-line @typescript-eslint/ban-ts-ignore,@typescript-eslint/ban-ts-comment
216
+ // @ts-ignore
217
+ if (Object.values(_error)[0].error === 'unique') {
218
+ setError(Object.assign(Object.assign({}, error), { ['nameError']: react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.name.error.unique", defaultMessage: "ui.eventForm.name.error.unique" }) }));
219
+ }
220
+ else {
221
+ setError(Object.assign(Object.assign({}, error), _error));
222
+ }
211
223
  setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: false })));
212
224
  utils_1.Logger.error(Errors_1.SCOPE_SC_UI, e);
213
225
  });
@@ -233,7 +245,8 @@ function EventForm(inProps) {
233
245
  return (react_1.default.createElement(Root, Object.assign({ DialogContentProps: { dividers: false }, title: react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.title", defaultMessage: "ui.eventForm.title" }), open: open, onClose: onClose, className: (0, classnames_1.default)(classes.root, className), actions: react_1.default.createElement(lab_1.LoadingButton, { loading: field.isSubmitting, disabled: !field.name ||
234
246
  (!field.startDate && !field.startTime) ||
235
247
  (field.location === types_1.SCEventLocationType.ONLINE && !field.link) ||
236
- ((field.recurring !== types_1.SCEventRecurrenceType.NEVER) && (!field.endDate && !field.endTime)) ||
248
+ (field.location === types_1.SCEventLocationType.PERSON && !field.geolocation) ||
249
+ (field.recurring !== types_1.SCEventRecurrenceType.NEVER && !field.endDate && !field.endTime) ||
237
250
  Object.keys(error).length !== 0 ||
238
251
  field.name.length > Event_1.EVENT_TITLE_MAX_LENGTH ||
239
252
  field.description.length > Event_1.EVENT_DESCRIPTION_MAX_LENGTH, variant: "contained", onClick: handleSubmit, color: "secondary" }, react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.button.create", defaultMessage: "ui.eventForm.button.create" })) }, rest),
@@ -243,7 +256,7 @@ function EventForm(inProps) {
243
256
  react_1.default.createElement(material_1.FormGroup, { className: classes.form },
244
257
  react_1.default.createElement(material_1.TextField, { required: true, className: classes.name, placeholder: `${intl.formatMessage(messages.name)}`, margin: "normal", value: field.name, name: "name", onChange: handleChange, InputProps: {
245
258
  endAdornment: react_1.default.createElement(material_1.Typography, { variant: "body2" }, Event_1.EVENT_TITLE_MAX_LENGTH - field.name.length)
246
- }, error: Boolean(((_a = field === null || field === void 0 ? void 0 : field.name) === null || _a === void 0 ? void 0 : _a.length) > Event_1.EVENT_TITLE_MAX_LENGTH), helperText: ((_b = field === null || field === void 0 ? void 0 : field.name) === null || _b === void 0 ? void 0 : _b.length) > Event_1.EVENT_TITLE_MAX_LENGTH ? (react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.name.error.maxLength", defaultMessage: "ui.eventForm.name.error.maxLength" })) : null }),
259
+ }, error: Boolean(((_a = field === null || field === void 0 ? void 0 : field.name) === null || _a === void 0 ? void 0 : _a.length) > Event_1.EVENT_TITLE_MAX_LENGTH) || Boolean(error[`nameError`]), helperText: ((_b = field === null || field === void 0 ? void 0 : field.name) === null || _b === void 0 ? void 0 : _b.length) > Event_1.EVENT_TITLE_MAX_LENGTH ? (react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.name.error.maxLength", defaultMessage: "ui.eventForm.name.error.maxLength" })) : error[`nameError`] ? (error[`nameError`]) : null }),
247
260
  react_1.default.createElement(material_1.Box, { className: classes.dateTime },
248
261
  react_1.default.createElement(x_date_pickers_1.LocalizationProvider, { dateAdapter: AdapterDateFns_1.AdapterDateFns, adapterLocale: scContext.settings.locale.default === 'it' ? it_1.default : en_US_1.default },
249
262
  react_1.default.createElement(x_date_pickers_1.MobileDatePicker, { className: classes.picker, disablePast: true, label: field.startDate && react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.date.placeholder", defaultMessage: "ui.eventForm.date.placeholder" }), value: field.startDate, slots: {
@@ -257,7 +270,7 @@ function EventForm(inProps) {
257
270
  toolbarTitle: react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.date.title", defaultMessage: "ui.eventForm.date.title" })
258
271
  }
259
272
  }, onChange: (value) => handleChangeDateTime(value, 'startDate') }),
260
- react_1.default.createElement(x_date_pickers_1.MobileTimePicker, { className: classes.picker, label: field.startTime && react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.time.placeholder", defaultMessage: "ui.eventForm.time.placeholder" }), value: field.startTime, slots: {
273
+ react_1.default.createElement(x_date_pickers_1.MobileTimePicker, { className: classes.picker, disablePast: true, label: field.startTime && react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.time.placeholder", defaultMessage: "ui.eventForm.time.placeholder" }), value: field.startTime, slots: {
261
274
  textField: (params) => (react_1.default.createElement(material_1.TextField, Object.assign({}, params, { InputProps: Object.assign(Object.assign({}, params.InputProps), { placeholder: `${intl.formatMessage(messages.startTime)}`, startAdornment: (react_1.default.createElement(material_1.InputAdornment, { position: "start" },
262
275
  react_1.default.createElement(material_1.IconButton, null,
263
276
  react_1.default.createElement(material_1.Icon, null, "access_time")))) }) })))
@@ -286,12 +299,12 @@ function EventForm(inProps) {
286
299
  react_1.default.createElement(material_1.IconButton, null,
287
300
  react_1.default.createElement(material_1.Icon, null, "calendar_off")))) }) })))
288
301
  }, onChange: (value) => handleChangeDateTime(value, 'endDate') }),
289
- react_1.default.createElement(x_date_pickers_1.MobileTimePicker, { className: classes.picker, label: field.endTime && react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.time.end.placeholder", defaultMessage: "ui.eventForm.time.end.placeholder" }), value: field.endTime, slots: {
302
+ react_1.default.createElement(x_date_pickers_1.MobileTimePicker, { className: classes.picker, disablePast: true, label: field.endTime && react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.time.end.placeholder", defaultMessage: "ui.eventForm.time.end.placeholder" }), value: field.endTime, slots: {
290
303
  textField: (params) => (react_1.default.createElement(material_1.TextField, Object.assign({}, params, { InputProps: Object.assign(Object.assign({}, params.InputProps), { placeholder: `${intl.formatMessage(messages.endTime)}`, startAdornment: (react_1.default.createElement(material_1.InputAdornment, { position: "start" },
291
304
  react_1.default.createElement(material_1.IconButton, null,
292
305
  react_1.default.createElement(material_1.Icon, null, "access_time")))) }) })))
293
306
  }, onChange: (value) => handleChangeDateTime(value, 'endTime') })))),
294
- react_1.default.createElement(material_1.Button, { variant: "text", color: "secondary", onClick: () => setField((prev) => (Object.assign(Object.assign({}, prev), { ['showEndDateTime']: !field.showEndDateTime }))) },
307
+ react_1.default.createElement(material_1.Button, { variant: "text", color: "secondary", onClick: () => setField((prev) => (Object.assign(Object.assign({}, prev), { ['showEndDateTime']: !field.showEndDateTime }))), disabled: field.showEndDateTime && field.recurring !== types_1.SCEventRecurrenceType.NEVER },
295
308
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventForm.dateTime.placeholder", defaultMessage: "ui.eventForm.dateTime.placeholder", values: { symbol: field.showEndDateTime ? '-' : '+' } })),
296
309
  react_1.default.createElement(EventAddress_1.default, { forwardGeolocationData: handleGeoData }),
297
310
  privateEnabled && (react_1.default.createElement(material_1.Box, { className: classes.privacySection },
@@ -0,0 +1,57 @@
1
+ import { ButtonProps } from '@mui/material/Button/Button';
2
+ import { SCEventType } from '@selfcommunity/types';
3
+ export interface EventInviteButtonProps extends ButtonProps {
4
+ /**
5
+ * Overrides or extends the styles applied to the component.
6
+ * @default null
7
+ */
8
+ className?: string;
9
+ /**
10
+ * Event Object
11
+ * @default null
12
+ */
13
+ event?: SCEventType;
14
+ /**
15
+ * Id of the event
16
+ * @default null
17
+ */
18
+ eventId?: number | string;
19
+ /**
20
+ * Functions to handle invitations sending in event creation mode
21
+ * @default null
22
+ */
23
+ handleInvitations?: (data: any) => any;
24
+ /**
25
+ * Any other properties
26
+ */
27
+ [p: string]: any;
28
+ }
29
+ /**
30
+ *> API documentation for the Community-JS Event Invite Button component. Learn about the available props and the CSS API.
31
+ *
32
+ #### Import
33
+ ```jsx
34
+ import {SCEventInviteButton} from '@selfcommunity/react-ui';
35
+ ```
36
+
37
+ #### Component Name
38
+ The name `SCEventInviteButton` can be used when providing style overrides in the theme.
39
+
40
+ #### CSS
41
+
42
+ |Rule Name|Global class|Description|
43
+ |---|---|---|
44
+ |root|.SCEventInviteButton-root|Styles applied to the root element.|
45
+ |dialogRoot|.SCEventInviteButton-dialog-root|Styles applied to the dialog root.|
46
+ |dialogTitle|.SCEventInviteButton-dialog-title|Styles applied to the dialog title element.|
47
+ |dialogContent|.SCEventInviteButton-dialog-content|Styles applied to the dialog content.|
48
+ |autocomplete|.SCEventInviteButton-autocomplete|Styles applied to the autocomplete element.|
49
+ |icon|.SCEventInviteButton-icon|Styles applied to the autocomplete icon element.|
50
+ |input|.SCEventInviteButton-input|Styles applied to the autocomplete input element.|
51
+ |clear|.SCEventInviteButton-clear|Styles applied to the autocomplete clear icon element.|
52
+ |invitedBox|.SCEventInviteButton-invited-box|Styles applied to the invited users box.|
53
+ |suggested|.SCEventInviteButton-suggested|Styles applied to the suggested users box.|
54
+
55
+ * @param inProps
56
+ */
57
+ export default function EventInviteButton(inProps: EventInviteButtonProps): JSX.Element;
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importStar(require("react"));
5
+ const system_1 = require("@mui/system");
6
+ const styles_1 = require("@mui/material/styles");
7
+ const material_1 = require("@mui/material");
8
+ const react_intl_1 = require("react-intl");
9
+ const react_core_1 = require("@selfcommunity/react-core");
10
+ const classnames_1 = tslib_1.__importDefault(require("classnames"));
11
+ const BaseDialog_1 = tslib_1.__importDefault(require("../../shared/BaseDialog"));
12
+ const lab_1 = require("@mui/lab");
13
+ const api_services_1 = require("@selfcommunity/api-services");
14
+ const Autocomplete_1 = tslib_1.__importDefault(require("@mui/material/Autocomplete"));
15
+ const User_1 = tslib_1.__importDefault(require("../User"));
16
+ const Errors_1 = require("../../constants/Errors");
17
+ const utils_1 = require("@selfcommunity/utils");
18
+ const PubSub_1 = require("../../constants/PubSub");
19
+ const pubsub_js_1 = tslib_1.__importDefault(require("pubsub-js"));
20
+ const messages = (0, react_intl_1.defineMessages)({
21
+ placeholder: {
22
+ id: 'ui.eventInviteButton.searchBar.placeholder',
23
+ defaultMessage: 'ui.eventInviteButton.searchBar.placeholder'
24
+ }
25
+ });
26
+ const PREFIX = 'SCEventInviteButton';
27
+ const classes = {
28
+ root: `${PREFIX}-root`,
29
+ dialogRoot: `${PREFIX}-dialog-root`,
30
+ dialogTitle: `${PREFIX}-dialog-title`,
31
+ dialogContent: `${PREFIX}-dialog-content`,
32
+ autocomplete: `${PREFIX}-autocomplete`,
33
+ icon: `${PREFIX}-icon`,
34
+ input: `${PREFIX}-input`,
35
+ clear: `${PREFIX}-clear`,
36
+ invitedBox: `${PREFIX}-invited-box`,
37
+ suggested: `${PREFIX}-suggested`
38
+ };
39
+ const Root = (0, styles_1.styled)(material_1.Button, {
40
+ name: PREFIX,
41
+ slot: 'Root',
42
+ overridesResolver: (props, styles) => styles.root
43
+ })(({ theme }) => ({}));
44
+ const DialogRoot = (0, styles_1.styled)(BaseDialog_1.default, {
45
+ name: PREFIX,
46
+ slot: 'Root',
47
+ overridesResolver: (props, styles) => styles.dialogRoot
48
+ })(({ theme }) => ({}));
49
+ /**
50
+ *> API documentation for the Community-JS Event Invite Button component. Learn about the available props and the CSS API.
51
+ *
52
+ #### Import
53
+ ```jsx
54
+ import {SCEventInviteButton} from '@selfcommunity/react-ui';
55
+ ```
56
+
57
+ #### Component Name
58
+ The name `SCEventInviteButton` can be used when providing style overrides in the theme.
59
+
60
+ #### CSS
61
+
62
+ |Rule Name|Global class|Description|
63
+ |---|---|---|
64
+ |root|.SCEventInviteButton-root|Styles applied to the root element.|
65
+ |dialogRoot|.SCEventInviteButton-dialog-root|Styles applied to the dialog root.|
66
+ |dialogTitle|.SCEventInviteButton-dialog-title|Styles applied to the dialog title element.|
67
+ |dialogContent|.SCEventInviteButton-dialog-content|Styles applied to the dialog content.|
68
+ |autocomplete|.SCEventInviteButton-autocomplete|Styles applied to the autocomplete element.|
69
+ |icon|.SCEventInviteButton-icon|Styles applied to the autocomplete icon element.|
70
+ |input|.SCEventInviteButton-input|Styles applied to the autocomplete input element.|
71
+ |clear|.SCEventInviteButton-clear|Styles applied to the autocomplete clear icon element.|
72
+ |invitedBox|.SCEventInviteButton-invited-box|Styles applied to the invited users box.|
73
+ |suggested|.SCEventInviteButton-suggested|Styles applied to the suggested users box.|
74
+
75
+ * @param inProps
76
+ */
77
+ function EventInviteButton(inProps) {
78
+ var _a;
79
+ //PROPS
80
+ const props = (0, system_1.useThemeProps)({
81
+ props: inProps,
82
+ name: PREFIX
83
+ });
84
+ const { className, event, eventId, handleInvitations = null } = props, rest = tslib_1.__rest(props, ["className", "event", "eventId", "handleInvitations"]);
85
+ // CONTEXT
86
+ const scUserContext = (0, react_1.useContext)(react_core_1.SCUserContext);
87
+ // STATE
88
+ const [open, setOpen] = (0, react_1.useState)(false);
89
+ const [isSending, setIsSending] = (0, react_1.useState)(false);
90
+ const [value, setValue] = (0, react_1.useState)('');
91
+ const [suggested, setSuggested] = (0, react_1.useState)([]);
92
+ const [list, setList] = (0, react_1.useState)([]);
93
+ const [loading, setLoading] = (0, react_1.useState)(false);
94
+ const [invited, setInvited] = (0, react_1.useState)([]);
95
+ /**
96
+ * Notify UI when a member is invited to a event
97
+ * @param event
98
+ * @param usersInvited
99
+ */
100
+ function notifyChanges(event, usersInvited) {
101
+ if (event && usersInvited) {
102
+ pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.EVENT}.${PubSub_1.SCGroupEventType.INVITE_MEMBER}`, usersInvited);
103
+ }
104
+ }
105
+ function convertToInvitedUsersObject(data) {
106
+ const invite_users = {};
107
+ data.forEach((user, index) => {
108
+ invite_users[`invite_users[${index}]`] = user.id;
109
+ });
110
+ return invite_users;
111
+ }
112
+ /**
113
+ * Memoized users invited ids
114
+ */
115
+ const ids = (0, react_1.useMemo)(() => {
116
+ if (invited) {
117
+ return invited.map((u) => {
118
+ return parseInt(u.id, 10);
119
+ });
120
+ }
121
+ return [invited];
122
+ }, [invited]);
123
+ // HOOKS
124
+ const { scEvent } = (0, react_core_1.useSCFetchEvent)({ id: eventId, event });
125
+ const isEventAdmin = (0, react_1.useMemo)(() => { var _a; return scUserContext.user && ((_a = scEvent === null || scEvent === void 0 ? void 0 : scEvent.managed_by) === null || _a === void 0 ? void 0 : _a.id) === scUserContext.user.id; }, [scUserContext.user, (_a = scEvent === null || scEvent === void 0 ? void 0 : scEvent.managed_by) === null || _a === void 0 ? void 0 : _a.id]);
126
+ // INTL
127
+ const intl = (0, react_intl_1.useIntl)();
128
+ function fetchResults() {
129
+ setLoading(true);
130
+ api_services_1.EventService.getEventSuggestedUsers(scEvent === null || scEvent === void 0 ? void 0 : scEvent.id, value)
131
+ .then((data) => {
132
+ setLoading(false);
133
+ setSuggested(data.results);
134
+ })
135
+ .catch((error) => {
136
+ setLoading(false);
137
+ utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error);
138
+ });
139
+ }
140
+ function fetchGeneralResults() {
141
+ setLoading(true);
142
+ api_services_1.EventService.getEventsSuggestedUsers(value)
143
+ .then((data) => {
144
+ setLoading(false);
145
+ setSuggested(data.results);
146
+ })
147
+ .catch((error) => {
148
+ setLoading(false);
149
+ utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error);
150
+ });
151
+ }
152
+ (0, react_1.useEffect)(() => {
153
+ if (scEvent === null || scEvent === void 0 ? void 0 : scEvent.id) {
154
+ api_services_1.EventService.getEventSuggestedUsers(scEvent === null || scEvent === void 0 ? void 0 : scEvent.id, value).then((data) => {
155
+ setLoading(false);
156
+ setList(data.results);
157
+ });
158
+ }
159
+ else {
160
+ api_services_1.EventService.getEventsSuggestedUsers(value).then((data) => {
161
+ setLoading(false);
162
+ setList(data.results);
163
+ });
164
+ }
165
+ }, [scEvent === null || scEvent === void 0 ? void 0 : scEvent.id]);
166
+ /**
167
+ * If a value is entered in new message field, it fetches user suggested
168
+ */
169
+ (0, react_1.useEffect)(() => {
170
+ if (scEvent) {
171
+ fetchResults();
172
+ }
173
+ else {
174
+ fetchGeneralResults();
175
+ }
176
+ }, [value, scEvent]);
177
+ /**
178
+ * Handles dialog close
179
+ */
180
+ const handleClose = () => {
181
+ setOpen((p) => !p);
182
+ };
183
+ /**
184
+ * Handles invitation sending
185
+ */
186
+ const handleSendInvitations = () => {
187
+ if (handleInvitations) {
188
+ handleInvitations(convertToInvitedUsersObject(invited));
189
+ setOpen(false);
190
+ }
191
+ else {
192
+ const data = { users: ids };
193
+ setIsSending(true);
194
+ api_services_1.EventService.inviteOrAcceptEventRequest(scEvent.id, data)
195
+ .then(() => {
196
+ setIsSending(false);
197
+ setOpen(false);
198
+ setInvited([]);
199
+ notifyChanges(scEvent, invited);
200
+ })
201
+ .catch((error) => {
202
+ setOpen(false);
203
+ setLoading(false);
204
+ utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error);
205
+ });
206
+ }
207
+ };
208
+ // Autocomplete Handlers
209
+ const handleInputChange = (event, value, reason) => {
210
+ switch (reason) {
211
+ case 'input':
212
+ setValue(value);
213
+ !value && setSuggested([]);
214
+ break;
215
+ case 'reset':
216
+ setValue(value);
217
+ break;
218
+ }
219
+ };
220
+ const handleChange = (event, value, reason, details) => {
221
+ event.preventDefault();
222
+ event.stopPropagation();
223
+ switch (reason) {
224
+ case 'selectOption':
225
+ setInvited(value);
226
+ setList((prev) => prev.filter((u) => u.id !== details.option.id));
227
+ break;
228
+ case 'removeOption':
229
+ setInvited(value);
230
+ setList((prev) => [...prev, details.option]);
231
+ break;
232
+ }
233
+ return false;
234
+ };
235
+ const handleUserInvite = (user) => {
236
+ setInvited((prev) => [...prev, user]);
237
+ setList((prev) => prev.filter((u) => u.id !== user.id));
238
+ };
239
+ const handleDelete = (option) => {
240
+ setInvited(invited.filter((v) => v !== option));
241
+ setList((prev) => [...prev, option]);
242
+ };
243
+ const filterOptions = (options, { inputValue }) => {
244
+ return options.filter((option) => {
245
+ const usernameMatch = option.username.toLowerCase().includes(inputValue.toLowerCase());
246
+ const nameMatch = option.real_name.toLowerCase().includes(inputValue.toLowerCase());
247
+ return usernameMatch || nameMatch;
248
+ });
249
+ };
250
+ /**
251
+ * If in event edit mode and logged-in user is not also the event manager, the component is hidden.
252
+ // */
253
+ if (event && !isEventAdmin) {
254
+ return null;
255
+ }
256
+ /**
257
+ * Renders root object
258
+ */
259
+ return (react_1.default.createElement(react_1.default.Fragment, null,
260
+ react_1.default.createElement(Root, Object.assign({ className: (0, classnames_1.default)(classes.root, className), onClick: handleClose, variant: scEvent ? 'contained' : 'outlined', color: scEvent ? 'secondary' : 'inherit', startIcon: react_1.default.createElement(material_1.Icon, null, "add") }, rest),
261
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventInviteButton", defaultMessage: "ui.eventInviteButton" })),
262
+ open && (react_1.default.createElement(DialogRoot, { DialogContentProps: { dividers: false }, open: true, className: classes.dialogRoot, title: react_1.default.createElement(react_1.default.Fragment, null,
263
+ react_1.default.createElement(material_1.IconButton, { onClick: handleClose },
264
+ react_1.default.createElement(material_1.Icon, null, "arrow_back")),
265
+ react_1.default.createElement(material_1.Typography, { className: classes.dialogTitle },
266
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventInviteButton.dialog.title", defaultMessage: "ui.eventInviteButton.dialog.title" })),
267
+ react_1.default.createElement(lab_1.LoadingButton, { size: "small", color: "secondary", variant: "contained", onClick: handleSendInvitations, loading: isSending, disabled: !invited.length },
268
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventInviteButton.dialog.button.end", defaultMessage: "ui.eventInviteButton.dialog.button.end" }))) },
269
+ react_1.default.createElement(material_1.Box, { className: classes.dialogContent },
270
+ react_1.default.createElement(Autocomplete_1.default, { className: classes.autocomplete, loading: loading, size: "small", multiple: true, freeSolo: true, disableClearable: true, options: suggested, onChange: handleChange, onInputChange: handleInputChange, inputValue: value, filterOptions: filterOptions, value: invited, getOptionLabel: (option) => (option ? option.username : '...'), isOptionEqualToValue: (option, value) => (option ? value.id === option.id : false), renderTags: () => null, renderOption: (props, option) => (react_1.default.createElement(material_1.Box, Object.assign({ component: "li" }, props),
271
+ react_1.default.createElement(material_1.Avatar, { alt: option.username, src: option.avatar }),
272
+ react_1.default.createElement(material_1.Typography, { ml: 1 }, option.username))), renderInput: (params) => (react_1.default.createElement(material_1.TextField, Object.assign({}, params, { variant: "outlined", placeholder: `${intl.formatMessage(messages.placeholder)}`, InputProps: Object.assign(Object.assign({}, params.InputProps), { className: classes.input, startAdornment: (react_1.default.createElement(react_1.default.Fragment, null,
273
+ react_1.default.createElement(material_1.InputAdornment, { position: "start" },
274
+ react_1.default.createElement(material_1.Icon, { className: classes.icon }, "search")),
275
+ params.InputProps.startAdornment)) }) }))) }),
276
+ react_1.default.createElement(material_1.Box, { className: classes.invitedBox }, invited.map((option, index) => (react_1.default.createElement(material_1.Chip, { key: index, avatar: react_1.default.createElement(material_1.Avatar, { alt: option.username, src: option.avatar }), label: option.username, onDelete: () => {
277
+ handleDelete(option);
278
+ }, style: { marginRight: 8 } })))),
279
+ react_1.default.createElement(material_1.Box, { className: classes.suggested },
280
+ list.length !== 0 && (react_1.default.createElement(material_1.Typography, { variant: "h4", fontWeight: "bold" },
281
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.eventInviteButton.dialog.content.list", defaultMessage: "ui.eventInviteButton.dialog.content.list" }))),
282
+ list.slice(0, 5).map((user, index) => (react_1.default.createElement(User_1.default, { elevation: 0, actions: react_1.default.createElement(react_1.default.Fragment, null), user: user, userId: user.id, key: index, buttonProps: { onClick: () => handleUserInvite(user) } })))))))));
283
+ }
284
+ exports.default = EventInviteButton;
@@ -0,0 +1,3 @@
1
+ import EventInviteButton, { EventInviteButtonProps } from './EventInviteButton';
2
+ export default EventInviteButton;
3
+ export { EventInviteButtonProps };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const EventInviteButton_1 = tslib_1.__importDefault(require("./EventInviteButton"));
5
+ exports.default = EventInviteButton_1.default;