@selfcommunity/react-ui 0.8.0-alpha.4 → 0.8.0-alpha.6

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.
@@ -1,7 +1,7 @@
1
1
  import { __rest } from "tslib";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { LoadingButton } from '@mui/lab';
4
- import { Box, Button, FormControl, FormGroup, Icon, IconButton, InputAdornment, InputLabel, MenuItem, Paper, Select, Stack, Switch, TextField, Typography } from '@mui/material';
4
+ import { Box, FormControl, FormGroup, Icon, IconButton, InputAdornment, InputLabel, MenuItem, Paper, Select, Stack, Switch, TextField, Typography } from '@mui/material';
5
5
  import { styled } from '@mui/material/styles';
6
6
  import { useThemeProps } from '@mui/system';
7
7
  import { LocalizationProvider, MobileDatePicker, MobileTimePicker } from '@mui/x-date-pickers';
@@ -14,15 +14,16 @@ import classNames from 'classnames';
14
14
  import enLocale from 'date-fns/locale/en-US';
15
15
  import itLocale from 'date-fns/locale/it';
16
16
  import PubSub from 'pubsub-js';
17
- import { useMemo, useState } from 'react';
17
+ import { useCallback, useMemo, useState } from 'react';
18
18
  import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
19
19
  import { SCOPE_SC_UI } from '../../constants/Errors';
20
20
  import { EVENT_DESCRIPTION_MAX_LENGTH, EVENT_TITLE_MAX_LENGTH } from '../../constants/Event';
21
21
  import { SCGroupEventType, SCTopicType } from '../../constants/PubSub';
22
22
  import BaseDialog from '../../shared/BaseDialog';
23
- import { PREFIX } from './constants';
23
+ import { DAILY_LATER_DAYS, MONTHLY_LATER_DAYS, NEVER_LATER_DAYS, PREFIX, WEEKLY_LATER_DAYS } from './constants';
24
24
  import EventAddress from './EventAddress';
25
25
  import UploadEventCover from './UploadEventCover';
26
+ import { combineDateAndTime, getLaterDaysDate, getLaterHoursDate, getNewDate } from './utils';
26
27
  const messages = defineMessages({
27
28
  name: {
28
29
  id: 'ui.eventForm.name.placeholder',
@@ -111,7 +112,7 @@ const Root = styled(BaseDialog, {
111
112
  * @param inProps
112
113
  */
113
114
  export default function EventForm(inProps) {
114
- var _a, _b, _c, _d, _e;
115
+ var _a, _b, _c, _d;
115
116
  //PROPS
116
117
  const props = useThemeProps({
117
118
  props: inProps,
@@ -122,13 +123,15 @@ export default function EventForm(inProps) {
122
123
  const scContext = useSCContext();
123
124
  // INTL
124
125
  const intl = useIntl();
126
+ const startDateTime = useMemo(() => getNewDate(event === null || event === void 0 ? void 0 : event.start_date), [event]);
127
+ const endDateTime = useMemo(() => getNewDate(event === null || event === void 0 ? void 0 : event.end_date), [event]);
125
128
  const initialFieldState = {
126
129
  imageOriginal: (event === null || event === void 0 ? void 0 : event.image_bigger) || '',
127
130
  imageOriginalFile: '',
128
- startDate: event ? new Date(event.start_date) : null,
129
- startTime: event ? new Date(event.start_date) : null,
130
- endDate: (event === null || event === void 0 ? void 0 : event.end_date) ? new Date(event.end_date) : null,
131
- endTime: (event === null || event === void 0 ? void 0 : event.end_date) ? new Date(event.end_date) : null,
131
+ startDate: event ? startDateTime : getNewDate(),
132
+ startTime: event ? startDateTime : getLaterHoursDate(1),
133
+ endDate: (event === null || event === void 0 ? void 0 : event.end_date) ? endDateTime : getNewDate(),
134
+ endTime: (event === null || event === void 0 ? void 0 : event.end_date) ? endDateTime : getLaterHoursDate(3),
132
135
  location: (event === null || event === void 0 ? void 0 : event.location) || SCEventLocationType.PERSON,
133
136
  geolocation: (event === null || event === void 0 ? void 0 : event.geolocation) || '',
134
137
  lat: (event === null || event === void 0 ? void 0 : event.geolocation_lat) || null,
@@ -138,8 +141,7 @@ export default function EventForm(inProps) {
138
141
  name: (event === null || event === void 0 ? void 0 : event.name) || '',
139
142
  description: event ? event.description : '',
140
143
  isPublic: (_a = (event === null || event === void 0 ? void 0 : event.privacy) === SCEventPrivacyType.PUBLIC) !== null && _a !== void 0 ? _a : true,
141
- isSubmitting: false,
142
- showEndDateTime: (_b = !!(event === null || event === void 0 ? void 0 : event.end_date)) !== null && _b !== void 0 ? _b : false
144
+ isSubmitting: false
143
145
  };
144
146
  // STATE
145
147
  const [field, setField] = useState(initialFieldState);
@@ -148,23 +150,12 @@ export default function EventForm(inProps) {
148
150
  const scPreferences = useSCPreferences();
149
151
  const privateEnabled = useMemo(() => scPreferences.preferences[SCPreferences.CONFIGURATIONS_EVENTS_PRIVATE_ENABLED].value, [scPreferences.preferences]);
150
152
  const visibilityEnabled = useMemo(() => scPreferences.preferences[SCPreferences.CONFIGURATIONS_EVENTS_VISIBILITY_ENABLED].value, [scPreferences.preferences]);
151
- const disablePastStartTime = useMemo(() => (field.startDate ? new Date(field.startDate).getDate() === new Date().getDate() : false), [field]);
152
- const disablePastEndTime = useMemo(() => (field.endDate ? new Date(field.endDate).getDate() === new Date().getDate() : false), [field]);
153
+ const disablePastStartTime = useMemo(() => field.startDate.getDate() === getNewDate().getDate(), [field]);
154
+ const disablePastEndTime = useMemo(() => field.endDate.getDate() === getNewDate().getDate(), [field]);
153
155
  const _backgroundCover = Object.assign({}, (field.imageOriginal
154
156
  ? { background: `url('${field.imageOriginal}') center / cover` }
155
157
  : { background: `url('${scPreferences.preferences[SCPreferences.IMAGES_USER_DEFAULT_COVER].value}') center / cover` }));
156
- const combineDateAndTime = (date, time) => {
157
- if (date && time) {
158
- const combined = new Date(date);
159
- combined.setHours(time.getHours());
160
- combined.setMinutes(time.getMinutes());
161
- combined.setSeconds(time.getSeconds());
162
- combined.setMilliseconds(time.getMilliseconds());
163
- return combined.toISOString();
164
- }
165
- return null;
166
- };
167
- function handleChangeCover(cover) {
158
+ const handleChangeCover = useCallback((cover) => {
168
159
  setField((prev) => (Object.assign(Object.assign({}, prev), { ['imageOriginalFile']: cover })));
169
160
  const reader = new FileReader();
170
161
  reader.onloadend = () => {
@@ -175,27 +166,25 @@ export default function EventForm(inProps) {
175
166
  delete error.imageOriginalError;
176
167
  setError(error);
177
168
  }
178
- }
169
+ }, [error]);
179
170
  /**
180
171
  * Notify when a group info changed
181
172
  * @param data
182
173
  */
183
- function notifyChanges(data) {
184
- if (data) {
185
- if (event) {
186
- // Edit group
187
- PubSub.publish(`${SCTopicType.EVENT}.${SCGroupEventType.EDIT}`, data);
188
- }
189
- else {
190
- // Create group
191
- PubSub.publish(`${SCTopicType.EVENT}.${SCGroupEventType.CREATE}`, data);
192
- }
174
+ const notifyChanges = useCallback((data) => {
175
+ if (event) {
176
+ // Edit group
177
+ PubSub.publish(`${SCTopicType.EVENT}.${SCGroupEventType.EDIT}`, data);
193
178
  }
194
- }
195
- const handleGeoData = (data) => {
179
+ else {
180
+ // Create group
181
+ PubSub.publish(`${SCTopicType.EVENT}.${SCGroupEventType.CREATE}`, data);
182
+ }
183
+ }, [event]);
184
+ const handleGeoData = useCallback((data) => {
196
185
  setField((prev) => (Object.assign(Object.assign({}, prev), data)));
197
- };
198
- const handleSubmit = () => {
186
+ }, []);
187
+ const handleSubmit = useCallback(() => {
199
188
  setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: true })));
200
189
  const formData = new FormData();
201
190
  if (field.imageOriginalFile) {
@@ -204,14 +193,12 @@ export default function EventForm(inProps) {
204
193
  formData.append('name', field.name);
205
194
  formData.append('start_date', combineDateAndTime(field.startDate, field.startTime));
206
195
  formData.append('recurring', field.recurring);
207
- if (field.endDate) {
208
- formData.append('end_date', combineDateAndTime(field.endDate, field.endTime));
209
- }
196
+ formData.append('end_date', combineDateAndTime(field.endDate, field.endTime));
210
197
  formData.append('location', field.location);
211
198
  if (field.location === SCEventLocationType.ONLINE) {
212
199
  formData.append('link', field.link);
213
200
  }
214
- if (field.location === SCEventLocationType.PERSON) {
201
+ else if (field.location === SCEventLocationType.PERSON) {
215
202
  formData.append('geolocation', field.geolocation);
216
203
  formData.append('geolocation_lat', field.lat.toString());
217
204
  formData.append('geolocation_lng', field.lng.toString());
@@ -250,28 +237,52 @@ export default function EventForm(inProps) {
250
237
  setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: false })));
251
238
  Logger.error(SCOPE_SC_UI, e);
252
239
  });
253
- };
254
- const handleChange = (event) => {
240
+ }, [field, privateEnabled, visibilityEnabled]);
241
+ const handleChange = useCallback((event) => {
255
242
  const { name, value } = event.target;
256
243
  setField((prev) => (Object.assign(Object.assign({}, prev), { [name]: value })));
257
244
  if (error[`${name}Error`]) {
258
245
  delete error[`${name}Error`];
259
246
  setError(error);
260
247
  }
261
- };
262
- const handleChangeDateTime = (value, name) => {
248
+ }, [error]);
249
+ const handleChangeDateTime = useCallback((value, name) => {
263
250
  setField((prev) => (Object.assign(Object.assign({}, prev), { [name]: value })));
264
251
  if (error[`${name}Error`]) {
265
252
  delete error[`${name}Error`];
266
253
  setError(error);
267
254
  }
268
- };
255
+ }, [error]);
256
+ const shouldDisabledDate = useCallback((date) => {
257
+ let disabled = false;
258
+ switch (field.recurring) {
259
+ case SCEventRecurrenceType.DAILY:
260
+ disabled = date.getTime() > getLaterDaysDate(DAILY_LATER_DAYS).getTime();
261
+ break;
262
+ case SCEventRecurrenceType.WEEKLY:
263
+ disabled = date.getTime() > getLaterDaysDate(WEEKLY_LATER_DAYS).getTime();
264
+ break;
265
+ case SCEventRecurrenceType.MONTHLY:
266
+ disabled = date.getTime() > getLaterDaysDate(MONTHLY_LATER_DAYS).getTime();
267
+ break;
268
+ case SCEventRecurrenceType.NEVER:
269
+ default:
270
+ disabled = date.getTime() > getLaterDaysDate(NEVER_LATER_DAYS).getTime();
271
+ }
272
+ if (field.startDate.getDate() > date.getDate()) {
273
+ disabled = true;
274
+ }
275
+ return disabled;
276
+ }, [field]);
277
+ const shouldDisabledTime = useCallback((date, _view) => field.startTime.getTime() > date.getTime(), [field]);
269
278
  /**
270
279
  * Renders root object
271
280
  */
272
281
  return (_jsx(Root, Object.assign({ DialogContentProps: { dividers: false }, title: event ? (_jsx(FormattedMessage, { id: "ui.eventForm.title.edit", defaultMessage: "ui.eventForm.title.edit" })) : (_jsx(FormattedMessage, { id: "ui.eventForm.title", defaultMessage: "ui.eventForm.title" })), open: open, onClose: onClose, className: classNames(classes.root, className), actions: _jsx(LoadingButton, Object.assign({ loading: field.isSubmitting, disabled: !field.name ||
273
282
  !field.startDate ||
274
283
  !field.startTime ||
284
+ !field.endDate ||
285
+ !field.endTime ||
275
286
  (field.location === SCEventLocationType.ONLINE && !field.link) ||
276
287
  (field.location === SCEventLocationType.PERSON && !field.geolocation) ||
277
288
  (field.recurring !== SCEventRecurrenceType.NEVER && !field.endDate && !field.endTime) ||
@@ -300,11 +311,11 @@ export default function EventForm(inProps) {
300
311
  return _jsx("em", { children: `${intl.formatMessage(messages.frequencyPlaceholder)}` });
301
312
  }
302
313
  return (_jsx(FormattedMessage, { id: `ui.eventForm.frequency.${selected}.placeholder`, defaultMessage: `ui.eventForm.frequency.${selected}.placeholder` }));
303
- }, startAdornment: _jsx(InputAdornment, Object.assign({ position: "start" }, { children: _jsx(IconButton, { children: _jsx(Icon, { children: "frequency" }) }) })) }, { children: Object.values(SCEventRecurrenceType).map((f) => (_jsx(MenuItem, Object.assign({ value: f }, { children: _jsx(FormattedMessage, { id: `ui.eventForm.frequency.${f}.placeholder`, defaultMessage: `ui.eventForm.frequency.${f}.placeholder` }) }), f))) }))] })), (field.showEndDateTime || field.recurring !== SCEventRecurrenceType.NEVER) && (_jsx(Box, Object.assign({ className: classes.dateTime }, { children: _jsxs(LocalizationProvider, Object.assign({ dateAdapter: AdapterDateFns, adapterLocale: scContext.settings.locale.default === 'it' ? itLocale : enLocale }, { children: [_jsx(MobileDatePicker, { className: classes.picker, disablePast: true, label: field.endDate && _jsx(FormattedMessage, { id: "ui.eventForm.date.end.placeholder", defaultMessage: "ui.eventForm.date.end.placeholder" }), value: field.endDate, slots: {
314
+ }, startAdornment: _jsx(InputAdornment, Object.assign({ position: "start" }, { children: _jsx(IconButton, { children: _jsx(Icon, { children: "frequency" }) }) })) }, { children: Object.values(SCEventRecurrenceType).map((f) => (_jsx(MenuItem, Object.assign({ value: f }, { children: _jsx(FormattedMessage, { id: `ui.eventForm.frequency.${f}.placeholder`, defaultMessage: `ui.eventForm.frequency.${f}.placeholder` }) }), f))) }))] })), _jsx(Box, Object.assign({ className: classes.dateTime }, { children: _jsxs(LocalizationProvider, Object.assign({ dateAdapter: AdapterDateFns, adapterLocale: scContext.settings.locale.default === 'it' ? itLocale : enLocale }, { children: [_jsx(MobileDatePicker, { className: classes.picker, disablePast: true, label: _jsx(FormattedMessage, { id: "ui.eventForm.date.end.placeholder", defaultMessage: "ui.eventForm.date.end.placeholder" }), value: field.endDate, slots: {
304
315
  textField: (params) => (_jsx(TextField, Object.assign({}, params, { InputProps: Object.assign(Object.assign({}, params.InputProps), { placeholder: `${intl.formatMessage(messages.endDate)}`, startAdornment: (_jsx(InputAdornment, Object.assign({ position: "start" }, { children: _jsx(IconButton, { children: _jsx(Icon, { children: "calendar_off" }) }) }))) }) })))
305
- }, onChange: (value) => handleChangeDateTime(value, 'endDate') }), _jsx(MobileTimePicker, { className: classes.picker, disablePast: disablePastEndTime, label: field.endTime && _jsx(FormattedMessage, { id: "ui.eventForm.time.end.placeholder", defaultMessage: "ui.eventForm.time.end.placeholder" }), value: field.endTime, slots: {
316
+ }, onChange: (value) => handleChangeDateTime(value, 'endDate'), shouldDisableDate: shouldDisabledDate }), _jsx(MobileTimePicker, { className: classes.picker, disablePast: disablePastEndTime, label: field.endTime && _jsx(FormattedMessage, { id: "ui.eventForm.time.end.placeholder", defaultMessage: "ui.eventForm.time.end.placeholder" }), value: field.endTime, slots: {
306
317
  textField: (params) => (_jsx(TextField, Object.assign({}, params, { InputProps: Object.assign(Object.assign({}, params.InputProps), { placeholder: `${intl.formatMessage(messages.endTime)}`, startAdornment: (_jsx(InputAdornment, Object.assign({ position: "start" }, { children: _jsx(IconButton, { children: _jsx(Icon, { children: "access_time" }) }) }))) }) })))
307
- }, onChange: (value) => handleChangeDateTime(value, 'endTime') })] })) }))), _jsx(Button, Object.assign({ variant: "text", color: "secondary", onClick: () => setField((prev) => (Object.assign(Object.assign({}, prev), { ['showEndDateTime']: !field.showEndDateTime }))), disabled: field.showEndDateTime && field.recurring !== SCEventRecurrenceType.NEVER }, { children: _jsx(FormattedMessage, { id: "ui.eventForm.dateTime.placeholder", defaultMessage: "ui.eventForm.dateTime.placeholder", values: { symbol: field.showEndDateTime ? '-' : '+' } }) })), _jsx(EventAddress, { forwardGeolocationData: handleGeoData, event: event !== null && event !== void 0 ? event : null }), privateEnabled && (_jsxs(Box, Object.assign({ className: classes.privacySection }, { children: [_jsxs(Stack, Object.assign({ direction: "row", spacing: 1, alignItems: "center", justifyContent: "center" }, { children: [_jsxs(Typography, Object.assign({ className: classNames(classes.switchLabel, { [classes.active]: !field.isPublic }) }, { children: [_jsx(Icon, { children: "private" }), _jsx(FormattedMessage, { id: "ui.eventForm.privacy.private", defaultMessage: "ui.eventForm.privacy.private" })] })), _jsx(Switch, { className: classes.switch, checked: field.isPublic, onChange: () => setField((prev) => (Object.assign(Object.assign({}, prev), { ['isPublic']: !field.isPublic }))) }), _jsxs(Typography, Object.assign({ className: classNames(classes.switchLabel, { [classes.active]: field.isPublic }) }, { children: [_jsx(Icon, { children: "public" }), _jsx(FormattedMessage, { id: "ui.eventForm.privacy.public", defaultMessage: "ui.eventForm.privacy.public" })] }))] })), _jsx(Typography, Object.assign({ variant: "body2", textAlign: "center", className: classes.privacySectionInfo }, { children: field.isPublic ? (_jsx(FormattedMessage, { id: "ui.eventForm.privacy.public.info", defaultMessage: "ui.eventForm.privacy.public.info", values: {
318
+ }, onChange: (value) => handleChangeDateTime(value, 'endTime'), shouldDisableTime: shouldDisabledTime })] })) })), _jsx(EventAddress, { forwardGeolocationData: handleGeoData, event: event !== null && event !== void 0 ? event : null }), privateEnabled && (_jsxs(Box, Object.assign({ className: classes.privacySection }, { children: [_jsxs(Stack, Object.assign({ direction: "row", spacing: 1, alignItems: "center", justifyContent: "center" }, { children: [_jsxs(Typography, Object.assign({ className: classNames(classes.switchLabel, { [classes.active]: !field.isPublic }) }, { children: [_jsx(Icon, { children: "private" }), _jsx(FormattedMessage, { id: "ui.eventForm.privacy.private", defaultMessage: "ui.eventForm.privacy.private" })] })), _jsx(Switch, { className: classes.switch, checked: field.isPublic, onChange: () => setField((prev) => (Object.assign(Object.assign({}, prev), { ['isPublic']: !field.isPublic }))) }), _jsxs(Typography, Object.assign({ className: classNames(classes.switchLabel, { [classes.active]: field.isPublic }) }, { children: [_jsx(Icon, { children: "public" }), _jsx(FormattedMessage, { id: "ui.eventForm.privacy.public", defaultMessage: "ui.eventForm.privacy.public" })] }))] })), _jsx(Typography, Object.assign({ variant: "body2", textAlign: "center", className: classes.privacySectionInfo }, { children: field.isPublic ? (_jsx(FormattedMessage, { id: "ui.eventForm.privacy.public.info", defaultMessage: "ui.eventForm.privacy.public.info", values: {
308
319
  // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
309
320
  // @ts-ignore
310
321
  b: (chunks) => _jsx("strong", { children: chunks })
@@ -313,6 +324,6 @@ export default function EventForm(inProps) {
313
324
  // @ts-ignore
314
325
  b: (chunks) => _jsx("strong", { children: chunks })
315
326
  } })) }))] }))), _jsx(TextField, { multiline: true, className: classes.description, placeholder: `${intl.formatMessage(messages.description)}`, margin: "normal", value: field.description, name: "description", onChange: handleChange, InputProps: {
316
- endAdornment: (_jsx(Typography, Object.assign({ variant: "body2" }, { children: ((_c = field.description) === null || _c === void 0 ? void 0 : _c.length) ? EVENT_DESCRIPTION_MAX_LENGTH - field.description.length : EVENT_DESCRIPTION_MAX_LENGTH })))
317
- }, error: Boolean(((_d = field.description) === null || _d === void 0 ? void 0 : _d.length) > EVENT_DESCRIPTION_MAX_LENGTH), helperText: ((_e = field.description) === null || _e === void 0 ? void 0 : _e.length) > EVENT_DESCRIPTION_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.eventForm.description.error.maxLength", defaultMessage: "ui.eventForm.description.error.maxLength" })) : null })] }))] }) })));
327
+ endAdornment: (_jsx(Typography, Object.assign({ variant: "body2" }, { children: ((_b = field.description) === null || _b === void 0 ? void 0 : _b.length) ? EVENT_DESCRIPTION_MAX_LENGTH - field.description.length : EVENT_DESCRIPTION_MAX_LENGTH })))
328
+ }, error: Boolean(((_c = field.description) === null || _c === void 0 ? void 0 : _c.length) > EVENT_DESCRIPTION_MAX_LENGTH), helperText: ((_d = field.description) === null || _d === void 0 ? void 0 : _d.length) > EVENT_DESCRIPTION_MAX_LENGTH ? (_jsx(FormattedMessage, { id: "ui.eventForm.description.error.maxLength", defaultMessage: "ui.eventForm.description.error.maxLength" })) : null })] }))] }) })));
318
329
  }
@@ -1 +1,5 @@
1
1
  export declare const PREFIX = "SCEventForm";
2
+ export declare const NEVER_LATER_DAYS = 14;
3
+ export declare const DAILY_LATER_DAYS = 60;
4
+ export declare const WEEKLY_LATER_DAYS = 360;
5
+ export declare const MONTHLY_LATER_DAYS = 730;
@@ -1 +1,5 @@
1
1
  export const PREFIX = 'SCEventForm';
2
+ export const NEVER_LATER_DAYS = 14;
3
+ export const DAILY_LATER_DAYS = 60;
4
+ export const WEEKLY_LATER_DAYS = 360;
5
+ export const MONTHLY_LATER_DAYS = 730;
@@ -22,7 +22,6 @@ export declare type InitialFieldState = Geolocation & {
22
22
  description: string;
23
23
  isPublic: boolean;
24
24
  isSubmitting: boolean;
25
- showEndDateTime: boolean;
26
25
  };
27
26
  export declare type FieldStateKeys = keyof InitialFieldState;
28
27
  export declare type FieldStateValues = InitialFieldState[FieldStateKeys];
@@ -0,0 +1,4 @@
1
+ export declare function getNewDate(date?: string): Date;
2
+ export declare function getLaterHoursDate(h: number): Date;
3
+ export declare function getLaterDaysDate(d: number): Date;
4
+ export declare const combineDateAndTime: (date: Date, time: Date) => string;
@@ -0,0 +1,21 @@
1
+ import { addDays, addHours } from 'date-fns';
2
+ export function getNewDate(date) {
3
+ if (date) {
4
+ return new Date(date);
5
+ }
6
+ return new Date();
7
+ }
8
+ export function getLaterHoursDate(h) {
9
+ return addHours(getNewDate(), h);
10
+ }
11
+ export function getLaterDaysDate(d) {
12
+ return addDays(getNewDate(), d);
13
+ }
14
+ export const combineDateAndTime = (date, time) => {
15
+ const combined = date;
16
+ combined.setHours(time.getHours());
17
+ combined.setMinutes(time.getMinutes());
18
+ combined.setSeconds(time.getSeconds());
19
+ combined.setMilliseconds(time.getMilliseconds());
20
+ return combined.toISOString();
21
+ };
@@ -8,7 +8,7 @@ import classNames from 'classnames';
8
8
  import { useThemeProps } from '@mui/system';
9
9
  import Category from './Steps/Category';
10
10
  import { PREFIX } from './constants';
11
- import { getTheme, usePreviousValue, UserUtils, useSCContext, useSCPreferences, useSCTheme, useSCUser } from '@selfcommunity/react-core';
11
+ import { getTheme, usePreviousValue, UserUtils, useSCContext, useSCFetchCategories, useSCPreferences, useSCTheme, useSCUser } from '@selfcommunity/react-core';
12
12
  import Appearance from './Steps/Appearance';
13
13
  import Profile from './Steps/Profile';
14
14
  import Invite from './Steps/Invite';
@@ -24,6 +24,7 @@ import OnBoardingWidgetSkeleton from './Skeleton';
24
24
  import { closeSnackbar, useSnackbar } from 'notistack';
25
25
  import { CONSOLE_PROD, CONSOLE_STAGE } from '../PlatformWidget/constants';
26
26
  import HeaderPlaceholder from '../../assets/onBoarding/header';
27
+ import BaseDialog from '../../shared/BaseDialog';
27
28
  const classes = {
28
29
  root: `${PREFIX}-root`,
29
30
  content: `${PREFIX}-content`,
@@ -52,7 +53,7 @@ const OnBoardingWidget = (inProps) => {
52
53
  });
53
54
  const { className, GenerateContentsParams = {}, onGeneratedContent = null, onHeightChange } = props, rest = __rest(props, ["className", "GenerateContentsParams", "onGeneratedContent", "onHeightChange"]);
54
55
  // STATE
55
- const [isLoading, setIsLoading] = useState(true);
56
+ const [loading, setLoading] = useState(true);
56
57
  const [initialized, setInitialized] = useState(false);
57
58
  const [steps, setSteps] = useState([]);
58
59
  const nextStep = useMemo(() => {
@@ -68,6 +69,7 @@ const OnBoardingWidget = (inProps) => {
68
69
  const prevContentsStep = usePreviousValue(currentContentsStep);
69
70
  const currentCategoriesStep = steps === null || steps === void 0 ? void 0 : steps.find((s) => s.step === SCOnBoardingStepType.CATEGORIES);
70
71
  const prevCategoriesStep = usePreviousValue(currentCategoriesStep);
72
+ const [showCategoriesModal, setShowCategoriesModal] = useState(false);
71
73
  // CONTEXT
72
74
  const scUserContext = useSCUser();
73
75
  const isAdmin = useMemo(() => UserUtils.isCommunityCreator(scUserContext.user), [scUserContext.user]);
@@ -80,6 +82,7 @@ const OnBoardingWidget = (inProps) => {
80
82
  // HOOKS
81
83
  const theme = useTheme();
82
84
  const isMobile = useMediaQuery(theme.breakpoints.down('md'));
85
+ const { categories, isLoading } = useSCFetchCategories();
83
86
  // HANDLERS
84
87
  const completeStep = (s) => __awaiter(void 0, void 0, void 0, function* () {
85
88
  if (s.status !== SCOnBoardingStepStatusType.COMPLETED) {
@@ -112,14 +115,14 @@ const OnBoardingWidget = (inProps) => {
112
115
  const contentStep = res.results.find((step) => step.step === SCOnBoardingStepType.CONTENTS);
113
116
  setIsGenerating(res.results.some((step) => step.status === 'in_progress'));
114
117
  setSteps(res.results);
115
- setIsLoading(false);
118
+ setLoading(false);
116
119
  if (contentStep.status === SCOnBoardingStepStatusType.IN_PROGRESS && contentStep.results.length !== 0 && onGeneratedContent) {
117
120
  onGeneratedContent(contentStep.results);
118
121
  }
119
122
  })
120
123
  .catch((error) => {
121
124
  Logger.error(SCOPE_SC_UI, error);
122
- setIsLoading(false);
125
+ setLoading(false);
123
126
  });
124
127
  });
125
128
  const handleChange = (newStep) => {
@@ -130,17 +133,22 @@ const OnBoardingWidget = (inProps) => {
130
133
  onHeightChange && onHeightChange();
131
134
  };
132
135
  const generateContent = (stepId) => __awaiter(void 0, void 0, void 0, function* () {
133
- yield OnBoardingService.startAStep(stepId, GenerateContentsParams)
134
- .then(() => {
135
- setIsGenerating(true);
136
- })
137
- .catch((error) => {
138
- Logger.error(SCOPE_SC_UI, error);
139
- enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.common.error.action", defaultMessage: "ui.common.error.action" }), {
140
- variant: 'error',
141
- autoHideDuration: 3000
136
+ if (!isLoading && !categories.length) {
137
+ setShowCategoriesModal(true);
138
+ }
139
+ else {
140
+ yield OnBoardingService.startAStep(stepId, GenerateContentsParams)
141
+ .then(() => {
142
+ setIsGenerating(true);
143
+ })
144
+ .catch((error) => {
145
+ Logger.error(SCOPE_SC_UI, error);
146
+ enqueueSnackbar(_jsx(FormattedMessage, { id: "ui.common.error.action", defaultMessage: "ui.common.error.action" }), {
147
+ variant: 'error',
148
+ autoHideDuration: 3000
149
+ });
142
150
  });
143
- });
151
+ }
144
152
  });
145
153
  const handlePreferencesUpdate = () => {
146
154
  PreferenceService.getAllPreferences().then((preferences) => {
@@ -152,7 +160,7 @@ const OnBoardingWidget = (inProps) => {
152
160
  // EFFECTS
153
161
  useEffect(() => {
154
162
  if (prevContentsStep &&
155
- prevCategoriesStep.status === SCOnBoardingStepStatusType.IN_PROGRESS &&
163
+ prevContentsStep.status === SCOnBoardingStepStatusType.IN_PROGRESS &&
156
164
  (currentContentsStep === null || currentContentsStep === void 0 ? void 0 : currentContentsStep.status) === SCOnBoardingStepStatusType.COMPLETED) {
157
165
  showSuccessAlert(currentContentsStep);
158
166
  }
@@ -233,6 +241,6 @@ const OnBoardingWidget = (inProps) => {
233
241
  // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
234
242
  // @ts-ignore
235
243
  icon: (...chunks) => (_jsx(Icon, Object.assign({ color: "secondary", fontSize: "medium" }, { children: chunks })))
236
- } }) }))) }) })), _jsx(AccordionDetails, { children: _jsx(Widget, Object.assign({ className: classes.content, elevation: 0 }, { children: isLoading ? (_jsx(OnBoardingWidgetSkeleton, {})) : (_jsxs(CardContent, { children: [_jsx(List, Object.assign({ className: isMobile ? classes.stepsMobile : classes.steps }, { children: steps === null || steps === void 0 ? void 0 : steps.map((step) => (_jsx(ListItem, { children: isMobile ? (_jsx(Chip, { size: "small", label: _jsxs(_Fragment, { children: [_jsx(FormattedMessage, { id: `ui.onBoardingWidget.${step.step}`, defaultMessage: `ui.onBoardingWidget.${step.step}` }), ' ', step.status === SCOnBoardingStepStatusType.COMPLETED && (_jsx(Icon, Object.assign({ color: (step === null || step === void 0 ? void 0 : step.status) === SCOnBoardingStepStatusType.COMPLETED && (step === null || step === void 0 ? void 0 : step.step) !== (_step === null || _step === void 0 ? void 0 : _step.step) ? 'success' : 'inherit' }, { children: "check" })))] }), onClick: () => handleChange(step), variant: step.step === (_step === null || _step === void 0 ? void 0 : _step.step) ? 'filled' : 'outlined', color: step.status === SCOnBoardingStepStatusType.COMPLETED ? 'success' : 'default' })) : (_jsxs(ListItemButton, Object.assign({ onClick: () => handleChange(step), selected: (step === null || step === void 0 ? void 0 : step.step) === (_step === null || _step === void 0 ? void 0 : _step.step) }, { children: [_jsx(ListItemIcon, { children: _jsx(Checkbox, { edge: "start", checked: step.status === SCOnBoardingStepStatusType.COMPLETED, tabIndex: -1, disableRipple: true, inputProps: { 'aria-labelledby': step.step }, size: 'small' }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: `ui.onBoardingWidget.${step.step}`, defaultMessage: `ui.onBoardingWidget.${step.step}` }) })] }))) }, step.id))) })), _jsx(Box, Object.assign({ className: classes.stepContent }, { children: _jsx(Fade, Object.assign({ in: true, timeout: 2400 }, { children: _jsx(Box, { children: getStepContent() }) })) }))] })) })) })] })) })));
244
+ } }) }))) }) })), _jsx(AccordionDetails, { children: _jsx(Widget, Object.assign({ className: classes.content, elevation: 0 }, { children: loading ? (_jsx(OnBoardingWidgetSkeleton, {})) : (_jsxs(CardContent, { children: [_jsx(List, Object.assign({ className: isMobile ? classes.stepsMobile : classes.steps }, { children: steps === null || steps === void 0 ? void 0 : steps.map((step) => (_jsx(ListItem, { children: isMobile ? (_jsx(Chip, { size: "small", label: _jsxs(_Fragment, { children: [_jsx(FormattedMessage, { id: `ui.onBoardingWidget.${step.step}`, defaultMessage: `ui.onBoardingWidget.${step.step}` }), ' ', step.status === SCOnBoardingStepStatusType.COMPLETED && (_jsx(Icon, Object.assign({ color: (step === null || step === void 0 ? void 0 : step.status) === SCOnBoardingStepStatusType.COMPLETED && (step === null || step === void 0 ? void 0 : step.step) !== (_step === null || _step === void 0 ? void 0 : _step.step) ? 'success' : 'inherit' }, { children: "check" })))] }), onClick: () => handleChange(step), variant: step.step === (_step === null || _step === void 0 ? void 0 : _step.step) ? 'filled' : 'outlined', color: step.status === SCOnBoardingStepStatusType.COMPLETED ? 'success' : 'default' })) : (_jsxs(ListItemButton, Object.assign({ onClick: () => handleChange(step), selected: (step === null || step === void 0 ? void 0 : step.step) === (_step === null || _step === void 0 ? void 0 : _step.step) }, { children: [_jsx(ListItemIcon, { children: _jsx(Checkbox, { edge: "start", checked: step.status === SCOnBoardingStepStatusType.COMPLETED, tabIndex: -1, disableRipple: true, inputProps: { 'aria-labelledby': step.step }, size: 'small' }) }), _jsx(ListItemText, { primary: _jsx(FormattedMessage, { id: `ui.onBoardingWidget.${step.step}`, defaultMessage: `ui.onBoardingWidget.${step.step}` }) })] }))) }, step.id))) })), _jsxs(Box, Object.assign({ className: classes.stepContent }, { children: [_jsx(Fade, Object.assign({ in: true, timeout: 2400 }, { children: _jsx(Box, { children: getStepContent() }) })), showCategoriesModal && (_jsx(BaseDialog, Object.assign({ title: _jsx(FormattedMessage, { id: "ui.onBoardingWidget.ai.no.categories", defaultMessage: "ui.onBoardingWidget.ai.no.categories" }), DialogContentProps: { dividers: false }, open: showCategoriesModal, onClose: () => setShowCategoriesModal(false), actions: _jsx(Button, Object.assign({ color: "secondary", onClick: () => setShowCategoriesModal(false) }, { children: _jsx(FormattedMessage, { id: "ui.onBoardingWidget.ai.no.categories.cancel", defaultMessage: "ui.onBoardingWidget.ai.no.categories.cancel" }) })) }, { children: _jsx(Button, Object.assign({ color: "primary", href: isStage ? CONSOLE_STAGE : CONSOLE_PROD, onClick: () => setShowCategoriesModal(false), target: "_blank", startIcon: _jsx(Icon, Object.assign({ fontSize: "small" }, { children: "edit" })) }, { children: _jsx(FormattedMessage, { id: "ui.onBoardingWidget.ai.no.categories.link", defaultMessage: "ui.onBoardingWidget.ai.no.categories.link" }) })) })))] }))] })) })) })] })) })));
237
245
  };
238
246
  export default OnBoardingWidget;