Move compose event form state to modal itself

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-09-18 16:26:25 +02:00
parent 1150b05c11
commit 8cbaa75546
9 changed files with 169 additions and 359 deletions

View file

@ -10,17 +10,18 @@ import { PlApiClient, type CreateApplicationParams } from 'pl-api';
import * as BuildConfig from 'pl-fe/build-config';
import type { AnyAction } from 'redux';
import type { AppDispatch } from 'pl-fe/store';
const APP_CREATE_REQUEST = 'APP_CREATE_REQUEST' as const;
const APP_CREATE_SUCCESS = 'APP_CREATE_SUCCESS' as const;
const APP_CREATE_FAIL = 'APP_CREATE_FAIL' as const;
const createApp = (params: CreateApplicationParams, baseURL?: string) =>
(dispatch: React.Dispatch<AnyAction>) => {
(dispatch: AppDispatch) => {
dispatch({ type: APP_CREATE_REQUEST, params });
const client = new PlApiClient(baseURL || BuildConfig.BACKEND_URL || '');
return client.apps.createApplication(params).then((app) => {
dispatch({ type: APP_CREATE_SUCCESS, params, app });
return app as Record<string, string>;

View file

@ -1,39 +1,19 @@
import { defineMessages, IntlShape } from 'react-intl';
import { defineMessages } from 'react-intl';
import { getClient } from 'pl-fe/api';
import { useModalsStore } from 'pl-fe/stores';
import toast from 'pl-fe/toast';
import { importFetchedAccounts, importFetchedStatus, importFetchedStatuses } from './importer';
import { uploadFile } from './media';
import {
STATUS_FETCH_SOURCE_FAIL,
STATUS_FETCH_SOURCE_REQUEST,
STATUS_FETCH_SOURCE_SUCCESS,
} from './statuses';
import { STATUS_FETCH_SOURCE_FAIL, STATUS_FETCH_SOURCE_REQUEST, STATUS_FETCH_SOURCE_SUCCESS } from './statuses';
import type { Account, CreateEventParams, MediaAttachment, PaginatedResponse, Status } from 'pl-api';
import type { MinifiedStatus } from 'pl-fe/reducers/statuses';
import type { Account, CreateEventParams, Location, MediaAttachment, PaginatedResponse, Status } from 'pl-api';
import type { AppDispatch, RootState } from 'pl-fe/store';
const LOCATION_SEARCH_REQUEST = 'LOCATION_SEARCH_REQUEST' as const;
const LOCATION_SEARCH_SUCCESS = 'LOCATION_SEARCH_SUCCESS' as const;
const LOCATION_SEARCH_FAIL = 'LOCATION_SEARCH_FAIL' as const;
const EDIT_EVENT_NAME_CHANGE = 'EDIT_EVENT_NAME_CHANGE' as const;
const EDIT_EVENT_DESCRIPTION_CHANGE = 'EDIT_EVENT_DESCRIPTION_CHANGE' as const;
const EDIT_EVENT_START_TIME_CHANGE = 'EDIT_EVENT_START_TIME_CHANGE' as const;
const EDIT_EVENT_HAS_END_TIME_CHANGE = 'EDIT_EVENT_HAS_END_TIME_CHANGE' as const;
const EDIT_EVENT_END_TIME_CHANGE = 'EDIT_EVENT_END_TIME_CHANGE' as const;
const EDIT_EVENT_APPROVAL_REQUIRED_CHANGE = 'EDIT_EVENT_APPROVAL_REQUIRED_CHANGE' as const;
const EDIT_EVENT_LOCATION_CHANGE = 'EDIT_EVENT_LOCATION_CHANGE' as const;
const EVENT_BANNER_UPLOAD_REQUEST = 'EVENT_BANNER_UPLOAD_REQUEST' as const;
const EVENT_BANNER_UPLOAD_PROGRESS = 'EVENT_BANNER_UPLOAD_PROGRESS' as const;
const EVENT_BANNER_UPLOAD_SUCCESS = 'EVENT_BANNER_UPLOAD_SUCCESS' as const;
const EVENT_BANNER_UPLOAD_FAIL = 'EVENT_BANNER_UPLOAD_FAIL' as const;
const EVENT_BANNER_UPLOAD_UNDO = 'EVENT_BANNER_UPLOAD_UNDO' as const;
const EVENT_SUBMIT_REQUEST = 'EVENT_SUBMIT_REQUEST' as const;
const EVENT_SUBMIT_SUCCESS = 'EVENT_SUBMIT_SUCCESS' as const;
const EVENT_SUBMIT_FAIL = 'EVENT_SUBMIT_FAIL' as const;
@ -106,105 +86,28 @@ const locationSearch = (query: string, signal?: AbortSignal) =>
});
};
const changeEditEventName = (value: string) => ({
type: EDIT_EVENT_NAME_CHANGE,
value,
});
const changeEditEventDescription = (value: string) => ({
type: EDIT_EVENT_DESCRIPTION_CHANGE,
value,
});
const changeEditEventStartTime = (value: Date) => ({
type: EDIT_EVENT_START_TIME_CHANGE,
value,
});
const changeEditEventEndTime = (value: Date) => ({
type: EDIT_EVENT_END_TIME_CHANGE,
value,
});
const changeEditEventHasEndTime = (value: boolean) => ({
type: EDIT_EVENT_HAS_END_TIME_CHANGE,
value,
});
const changeEditEventApprovalRequired = (value: boolean) => ({
type: EDIT_EVENT_APPROVAL_REQUIRED_CHANGE,
value,
});
const changeEditEventLocation = (value: string | null) =>
(dispatch: AppDispatch, getState: () => RootState) => {
let location = null;
if (value) {
location = getState().locations.get(value);
}
dispatch({
type: EDIT_EVENT_LOCATION_CHANGE,
value: location,
});
};
const uploadEventBanner = (file: File, intl: IntlShape) =>
(dispatch: AppDispatch) => {
let progress = 0;
dispatch(uploadEventBannerRequest());
dispatch(uploadFile(
file,
intl,
(data) => dispatch(uploadEventBannerSuccess(data, file)),
(error) => dispatch(uploadEventBannerFail(error)),
({ loaded }: any) => {
progress = loaded;
dispatch(uploadEventBannerProgress(progress));
},
));
};
const uploadEventBannerRequest = () => ({
type: EVENT_BANNER_UPLOAD_REQUEST,
});
const uploadEventBannerProgress = (loaded: number) => ({
type: EVENT_BANNER_UPLOAD_PROGRESS,
loaded,
});
const uploadEventBannerSuccess = (media: MediaAttachment, file: File) => ({
type: EVENT_BANNER_UPLOAD_SUCCESS,
media,
file,
});
const uploadEventBannerFail = (error: unknown) => ({
type: EVENT_BANNER_UPLOAD_FAIL,
error,
});
const undoUploadEventBanner = () => ({
type: EVENT_BANNER_UPLOAD_UNDO,
});
const submitEvent = () =>
(dispatch: AppDispatch, getState: () => RootState) => {
const submitEvent = ({
statusId,
name,
status,
banner,
startTime,
endTime,
joinMode,
location,
}: {
statusId: string | null;
name: string;
status: string;
banner: MediaAttachment | null;
startTime: Date;
endTime: Date | null;
joinMode: 'restricted' | 'free';
location: Location | null;
}) =>
async (dispatch: AppDispatch, getState: () => RootState) => {
const state = getState();
const statusId = state.compose_event.id;
const name = state.compose_event.name;
const status = state.compose_event.status;
const banner = state.compose_event.banner;
const startTime = state.compose_event.start_time;
const endTime = state.compose_event.end_time;
const joinMode = state.compose_event.approval_required ? 'restricted' : 'free';
const location = state.compose_event.location;
if (!name || !name.length) {
return;
}
@ -539,9 +442,8 @@ const cancelEventCompose = () => ({
interface EventFormSetAction {
type: typeof EVENT_FORM_SET;
status: MinifiedStatus;
composeId: string;
text: string;
location: Record<string, any>;
}
const editEvent = (statusId: string) => (dispatch: AppDispatch, getState: () => RootState) => {
@ -553,11 +455,14 @@ const editEvent = (statusId: string) => (dispatch: AppDispatch, getState: () =>
dispatch({ type: STATUS_FETCH_SOURCE_SUCCESS, statusId });
dispatch({
type: EVENT_FORM_SET,
status,
composeId: `compose-event-modal-${statusId}`,
text: response.text,
location: response.location,
});
useModalsStore.getState().openModal('COMPOSE_EVENT');
useModalsStore.getState().openModal('COMPOSE_EVENT', {
status,
statusText: response.text,
location: response.location || undefined,
});
}).catch(error => {
dispatch({ type: STATUS_FETCH_SOURCE_FAIL, statusId, error });
});
@ -613,18 +518,6 @@ export {
LOCATION_SEARCH_REQUEST,
LOCATION_SEARCH_SUCCESS,
LOCATION_SEARCH_FAIL,
EDIT_EVENT_NAME_CHANGE,
EDIT_EVENT_DESCRIPTION_CHANGE,
EDIT_EVENT_START_TIME_CHANGE,
EDIT_EVENT_END_TIME_CHANGE,
EDIT_EVENT_HAS_END_TIME_CHANGE,
EDIT_EVENT_APPROVAL_REQUIRED_CHANGE,
EDIT_EVENT_LOCATION_CHANGE,
EVENT_BANNER_UPLOAD_REQUEST,
EVENT_BANNER_UPLOAD_PROGRESS,
EVENT_BANNER_UPLOAD_SUCCESS,
EVENT_BANNER_UPLOAD_FAIL,
EVENT_BANNER_UPLOAD_UNDO,
EVENT_SUBMIT_REQUEST,
EVENT_SUBMIT_SUCCESS,
EVENT_SUBMIT_FAIL,
@ -661,19 +554,6 @@ export {
JOINED_EVENTS_FETCH_SUCCESS,
JOINED_EVENTS_FETCH_FAIL,
locationSearch,
changeEditEventName,
changeEditEventDescription,
changeEditEventStartTime,
changeEditEventEndTime,
changeEditEventHasEndTime,
changeEditEventApprovalRequired,
changeEditEventLocation,
uploadEventBanner,
uploadEventBannerRequest,
uploadEventBannerProgress,
uploadEventBannerSuccess,
uploadEventBannerFail,
undoUploadEventBanner,
submitEvent,
submitEventRequest,
submitEventSuccess,

View file

@ -6,13 +6,11 @@ import 'wicg-inert';
import { cancelReplyCompose } from 'pl-fe/actions/compose';
import { saveDraftStatus } from 'pl-fe/actions/draft-statuses';
import { cancelEventCompose } from 'pl-fe/actions/events';
import { useAppDispatch, usePrevious } from 'pl-fe/hooks';
import { useModalsStore } from 'pl-fe/stores';
import type { ModalType } from 'pl-fe/features/ui/components/modal-root';
import type { ReducerCompose } from 'pl-fe/reducers/compose';
import type { ReducerRecord as ReducerComposeEvent } from 'pl-fe/reducers/compose-event';
const messages = defineMessages({
confirm: { id: 'confirmations.cancel.confirm', defaultMessage: 'Discard' },
@ -28,13 +26,13 @@ const checkComposeContent = (compose?: ReturnType<typeof ReducerCompose>) =>
compose.poll !== null,
].some(check => check === true);
const checkEventComposeContent = (compose?: ReturnType<typeof ReducerComposeEvent>) =>
!!compose && [
compose.name.length > 0,
compose.status.length > 0,
compose.location !== null,
compose.banner !== null,
].some(check => check === true);
// const checkEventComposeContent = (compose?: ReturnType<typeof ReducerComposeEvent>) =>
// !!compose && [
// compose.name.length > 0,
// compose.status.length > 0,
// compose.location !== null,
// compose.banner !== null,
// ].some(check => check === true);
interface IModalRoot {
onCancel?: () => void;
@ -71,7 +69,7 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
dispatch((_, getState) => {
const compose = getState().compose.get('compose-modal');
const hasComposeContent = checkComposeContent(compose);
const hasEventComposeContent = checkEventComposeContent(getState().compose_event);
// const hasEventComposeContent = checkEventComposeContent(getState().compose_event);
if (hasComposeContent && type === 'COMPOSE') {
const isEditing = compose!.id !== null;
@ -97,25 +95,26 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
dispatch(cancelReplyCompose());
},
});
} else if (hasEventComposeContent && type === 'COMPOSE_EVENT') {
const isEditing = getState().compose_event.id !== null;
openModal('CONFIRM', {
heading: isEditing
? <FormattedMessage id='confirmations.cancel_event_editing.heading' defaultMessage='Cancel event editing' />
: <FormattedMessage id='confirmations.delete_event.heading' defaultMessage='Delete event' />,
message: isEditing
? <FormattedMessage id='confirmations.cancel_event_editing.message' defaultMessage='Are you sure you want to cancel editing this event? All changes will be lost.' />
: <FormattedMessage id='confirmations.delete_event.message' defaultMessage='Are you sure you want to delete this event?' />,
confirm: intl.formatMessage(isEditing ? messages.cancelEditing : messages.confirm),
onConfirm: () => {
onClose('COMPOSE_EVENT');
dispatch(cancelEventCompose());
},
onCancel: () => {
onClose('CONFIRM');
},
});
} else if ((hasComposeContent || hasEventComposeContent) && type === 'CONFIRM') {
// TODO: restore this functionality
// } else if (hasEventComposeContent && type === 'COMPOSE_EVENT') {
// const isEditing = getState().compose_event.id !== null;
// openModal('CONFIRM', {
// heading: isEditing
// ? <FormattedMessage id='confirmations.cancel_event_editing.heading' defaultMessage='Cancel event editing' />
// : <FormattedMessage id='confirmations.delete_event.heading' defaultMessage='Delete event' />,
// message: isEditing
// ? <FormattedMessage id='confirmations.cancel_event_editing.message' defaultMessage='Are you sure you want to cancel editing this event? All changes will be lost.' />
// : <FormattedMessage id='confirmations.delete_event.message' defaultMessage='Are you sure you want to delete this event?' />,
// confirm: intl.formatMessage(isEditing ? messages.cancelEditing : messages.confirm),
// onConfirm: () => {
// onClose('COMPOSE_EVENT');
// dispatch(cancelEventCompose());
// },
// onCancel: () => {
// onClose('CONFIRM');
// },
// });
} else if ((hasComposeContent/* || hasEventComposeContent */) && type === 'CONFIRM') {
onClose('CONFIRM');
} else {
onClose();
@ -256,6 +255,5 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
export {
checkComposeContent,
checkEventComposeContent,
ModalRoot as default,
};

View file

@ -234,18 +234,16 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
};
const doDeleteStatus = (withRedraft = false) => {
dispatch((_) => {
if (!deleteModal) {
dispatch(deleteStatus(status.id, withRedraft));
} else {
openModal('CONFIRM', {
heading: intl.formatMessage(withRedraft ? messages.redraftHeading : messages.deleteHeading),
message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
onConfirm: () => dispatch(deleteStatus(status.id, withRedraft)),
});
}
});
if (!deleteModal) {
dispatch(deleteStatus(status.id, withRedraft));
} else {
openModal('CONFIRM', {
heading: intl.formatMessage(withRedraft ? messages.redraftHeading : messages.deleteHeading),
message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage),
confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm),
onConfirm: () => dispatch(deleteStatus(status.id, withRedraft)),
});
}
};
const handleDeleteClick: React.EventHandler<React.MouseEvent> = (e) => {

View file

@ -1,25 +1,17 @@
import React, { useEffect, useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { resetCompose } from 'pl-fe/actions/compose';
import {
changeEditEventApprovalRequired,
changeEditEventDescription,
changeEditEventEndTime,
changeEditEventHasEndTime,
changeEditEventName,
changeEditEventStartTime,
changeEditEventLocation,
uploadEventBanner,
undoUploadEventBanner,
submitEvent,
fetchEventParticipationRequests,
rejectEventParticipationRequest,
authorizeEventParticipationRequest,
cancelEventCompose,
} from 'pl-fe/actions/events';
import { uploadFile } from 'pl-fe/actions/media';
import { ADDRESS_ICONS } from 'pl-fe/components/autosuggest-location';
import LocationSearch from 'pl-fe/components/location-search';
import { checkEventComposeContent } from 'pl-fe/components/modal-root';
import { Button, Form, FormGroup, HStack, Icon, IconButton, Input, Modal, Spinner, Stack, Tabs, Text, Toggle } from 'pl-fe/components/ui';
import AccountContainer from 'pl-fe/containers/account-container';
import { isCurrentOrFutureDate } from 'pl-fe/features/compose/components/schedule-form';
@ -30,6 +22,8 @@ import { useModalsStore } from 'pl-fe/stores';
import UploadButton from './upload-button';
import type { BaseModalProps } from '../../modal-root';
import type { Location } from 'pl-api';
import type { MinifiedStatus } from 'pl-fe/reducers/statuses';
const messages = defineMessages({
eventNamePlaceholder: { id: 'compose_event.fields.name_placeholder', defaultMessage: 'Name' },
@ -87,84 +81,131 @@ const Account: React.FC<IAccount> = ({ eventId, id, participationMessage }) => {
);
};
const ComposeEventModal: React.FC<BaseModalProps> = ({ onClose }) => {
interface ComposeEventModalProps {
status?: MinifiedStatus;
statusText?: string;
location?: Location;
}
const ComposeEventModal: React.FC<BaseModalProps & ComposeEventModalProps> = ({
onClose,
status,
statusText,
location: sourceLocation,
}) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const { openModal } = useModalsStore();
const [tab, setTab] = useState<'edit' | 'pending'>('edit');
const [text, setText] = useState('');
const banner = useAppSelector((state) => state.compose_event.banner);
const isUploading = useAppSelector((state) => state.compose_event.is_uploading);
const [name, setName] = useState(status?.event?.name || '');
const [text, setText] = useState(statusText || '');
const [startTime, setStartTime] = useState(status?.event?.start_time ? new Date(status.event.start_time) : new Date());
const [endTime, setEndTime] = useState(status?.event?.end_time ? new Date(status.event.end_time) : null);
const [approvalRequired, setApprovalRequired] = useState(status?.event?.join_mode !== 'free');
const [banner, setBanner] = useState(status?.event?.banner || null);
const [location, setLocation] = useState(sourceLocation || null);
const name = useAppSelector((state) => state.compose_event.name);
const startTime = useAppSelector((state) => state.compose_event.start_time);
const endTime = useAppSelector((state) => state.compose_event.end_time);
const approvalRequired = useAppSelector((state) => state.compose_event.approval_required);
const location = useAppSelector((state) => state.compose_event.location);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isUploading, setIsUploading] = useState(false);
const statusId = useAppSelector((state) => state.compose_event.id);
const isSubmitting = useAppSelector((state) => state.compose_event.is_submitting);
const statusId = status?.id || null;
const composeId = statusId ? `compose-event-modal-${statusId}` : 'compose-event-modal';
const onChangeName: React.ChangeEventHandler<HTMLInputElement> = ({ target }) => {
dispatch(changeEditEventName(target.value));
setName(target.value);
};
const onChangeStartTime = (date: Date) => {
dispatch(changeEditEventStartTime(date));
setStartTime(date);
};
const onChangeEndTime = (date: Date) => {
dispatch(changeEditEventEndTime(date));
setEndTime(date);
};
const onChangeHasEndTime: React.ChangeEventHandler<HTMLInputElement> = ({ target }) => {
dispatch(changeEditEventHasEndTime(target.checked));
if (target.checked) {
const endTime = new Date(startTime);
endTime.setHours(endTime.getHours() + 2);
setEndTime(endTime);
} else setEndTime(null);
};
const onChangeApprovalRequired: React.ChangeEventHandler<HTMLInputElement> = ({ target }) => {
dispatch(changeEditEventApprovalRequired(target.checked));
setApprovalRequired(target.checked);
};
const onChangeLocation = (value: string | null) => {
dispatch(changeEditEventLocation(value));
};
dispatch((_, getState) => {
let location = null;
const onClickClose = () => {
dispatch((dispatch, getState) => {
if (checkEventComposeContent(getState().compose_event)) {
openModal('CONFIRM', {
heading: statusId
? <FormattedMessage id='confirmations.cancel_event_editing.heading' defaultMessage='Cancel event editing' />
: <FormattedMessage id='confirmations.delete_event.heading' defaultMessage='Delete event' />,
message: statusId
? <FormattedMessage id='confirmations.cancel_event_editing.message' defaultMessage='Are you sure you want to cancel editing this event? All changes will be lost.' />
: <FormattedMessage id='confirmations.delete_event.message' defaultMessage='Are you sure you want to delete this event?' />,
confirm: intl.formatMessage(messages.confirm),
onConfirm: () => {
onClose('COMPOSE_EVENT');
dispatch(cancelEventCompose());
},
});
} else {
onClose('COMPOSE_EVENT');
if (value) {
location = getState().locations.get(value, null);
}
setLocation(location);
});
};
const onClickClose = () => {
if (name.length || text.length || location || banner) {
openModal('CONFIRM', {
heading: statusId
? <FormattedMessage id='confirmations.cancel_event_editing.heading' defaultMessage='Cancel event editing' />
: <FormattedMessage id='confirmations.delete_event.heading' defaultMessage='Delete event' />,
message: statusId
? <FormattedMessage id='confirmations.cancel_event_editing.message' defaultMessage='Are you sure you want to cancel editing this event? All changes will be lost.' />
: <FormattedMessage id='confirmations.delete_event.message' defaultMessage='Are you sure you want to delete this event?' />,
confirm: intl.formatMessage(messages.confirm),
onConfirm: () => {
onClose('COMPOSE_EVENT');
dispatch(cancelEventCompose());
},
});
} else {
onClose('COMPOSE_EVENT');
}
};
const handleFiles = (files: FileList) => {
dispatch(uploadEventBanner(files[0], intl));
setIsUploading(true);
dispatch(uploadFile(
files[0],
intl,
(data) => {
setBanner(data);
setIsUploading(false);
},
() => setIsUploading(false),
));
};
const handleClearBanner = () => {
dispatch(undoUploadEventBanner());
setBanner(null);
};
const handleSubmit = () => {
dispatch(changeEditEventDescription(text));
dispatch(submitEvent());
setIsSubmitting(true);
dispatch(submitEvent({
statusId,
name,
status: text,
banner,
startTime,
endTime,
joinMode: approvalRequired ? 'restricted' : 'free',
location,
})).then(() => {
setIsSubmitting(false);
dispatch(resetCompose(composeId));
}).catch(() => {
setIsSubmitting(false);
});
};
const accounts = useAppSelector((state) => state.user_lists.event_participation_requests.get(statusId!)?.items);
@ -235,7 +276,7 @@ const ComposeEventModal: React.FC<BaseModalProps> = ({ onClose }) => {
<ComposeEditor
className='block w-full rounded-md border border-gray-400 bg-white px-3 py-2 text-base text-gray-900 ring-1 placeholder:text-gray-600 focus-within:border-primary-500 focus-within:ring-primary-500 sm:text-sm dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500'
placeholderClassName='pt-2'
composeId='compose-event-modal'
composeId={composeId}
placeholder={intl.formatMessage(messages.eventDescriptionPlaceholder)}
handleSubmit={handleSubmit}
onChange={setText}
@ -334,4 +375,4 @@ const ComposeEventModal: React.FC<BaseModalProps> = ({ onClose }) => {
);
};
export { ComposeEventModal as default };
export { ComposeEventModal as default, type ComposeEventModalProps };

View file

@ -1,108 +0,0 @@
import { Record as ImmutableRecord } from 'immutable';
import { AnyAction } from 'redux';
import {
EDIT_EVENT_APPROVAL_REQUIRED_CHANGE,
EDIT_EVENT_DESCRIPTION_CHANGE,
EDIT_EVENT_END_TIME_CHANGE,
EDIT_EVENT_HAS_END_TIME_CHANGE,
EDIT_EVENT_LOCATION_CHANGE,
EDIT_EVENT_NAME_CHANGE,
EDIT_EVENT_START_TIME_CHANGE,
EVENT_BANNER_UPLOAD_REQUEST,
EVENT_BANNER_UPLOAD_PROGRESS,
EVENT_BANNER_UPLOAD_SUCCESS,
EVENT_BANNER_UPLOAD_FAIL,
EVENT_BANNER_UPLOAD_UNDO,
EVENT_SUBMIT_REQUEST,
EVENT_SUBMIT_SUCCESS,
EVENT_SUBMIT_FAIL,
EVENT_COMPOSE_CANCEL,
EVENT_FORM_SET,
} from 'pl-fe/actions/events';
import type { Location, MediaAttachment } from 'pl-api';
const ReducerRecord = ImmutableRecord({
name: '',
status: '',
location: null as Location | null,
start_time: new Date(),
end_time: null as Date | null,
approval_required: false,
banner: null as MediaAttachment | null,
progress: 0,
is_uploading: false,
is_submitting: false,
id: null as string | null,
});
type State = ReturnType<typeof ReducerRecord>;
const setHasEndTime = (state: State) => {
const endTime = new Date(state.start_time);
endTime.setHours(endTime.getHours() + 2);
return state.set('end_time', endTime);
};
const compose_event = (state = ReducerRecord(), action: AnyAction): State => {
switch (action.type) {
case EDIT_EVENT_NAME_CHANGE:
return state.set('name', action.value);
case EDIT_EVENT_DESCRIPTION_CHANGE:
return state.set('status', action.value);
case EDIT_EVENT_START_TIME_CHANGE:
return state.set('start_time', action.value);
case EDIT_EVENT_END_TIME_CHANGE:
return state.set('end_time', action.value);
case EDIT_EVENT_HAS_END_TIME_CHANGE:
if (action.value) return setHasEndTime(state);
return state.set('end_time', null);
case EDIT_EVENT_APPROVAL_REQUIRED_CHANGE:
return state.set('approval_required', action.value);
case EDIT_EVENT_LOCATION_CHANGE:
return state.set('location', action.value);
case EVENT_BANNER_UPLOAD_REQUEST:
return state.set('is_uploading', true);
case EVENT_BANNER_UPLOAD_SUCCESS:
return state
.set('banner', action.media)
.set('is_uploading', false);
case EVENT_BANNER_UPLOAD_FAIL:
return state.set('is_uploading', false);
case EVENT_BANNER_UPLOAD_UNDO:
return state.set('banner', null);
case EVENT_BANNER_UPLOAD_PROGRESS:
return state.set('progress', action.loaded * 100);
case EVENT_SUBMIT_REQUEST:
return state.set('is_submitting', true);
case EVENT_SUBMIT_SUCCESS:
case EVENT_SUBMIT_FAIL:
return state.set('is_submitting', false);
case EVENT_COMPOSE_CANCEL:
return ReducerRecord();
case EVENT_FORM_SET:
return ReducerRecord({
name: action.status.event.name,
status: action.text,
start_time: new Date(action.status.event.start_time),
end_time: action.status.event.end_time ? new Date(action.status.event.end_time) : null,
approval_required: action.status.event.join_mode !== 'free',
banner: action.status.event.banner || null,
location: action.location || null,
progress: 0,
is_uploading: false,
is_submitting: false,
id: action.status.id,
});
default:
return state;
}
};
export {
ReducerRecord,
compose_event as default,
};

View file

@ -554,7 +554,7 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | Me
case EVENT_COMPOSE_CANCEL:
return updateCompose(state, 'event-compose-modal', compose => compose.set('text', ''));
case EVENT_FORM_SET:
return updateCompose(state, 'event-compose-modal', compose => compose.set('text', action.text));
return updateCompose(state, action.composeId, compose => compose.set('text', action.text));
case COMPOSE_CHANGE_MEDIA_ORDER:
return updateCompose(state, action.composeId, compose => compose.update('media_attachments', list => {
const indexA = list.findIndex(x => x.id === action.a);

View file

@ -12,7 +12,6 @@ import aliases from './aliases';
import auth from './auth';
import backups from './backups';
import compose from './compose';
import compose_event from './compose-event';
import contexts from './contexts';
import conversations from './conversations';
import custom_emojis from './custom-emojis';
@ -60,7 +59,6 @@ const reducers = {
auth,
backups,
compose,
compose_event,
contexts,
conversations,
custom_emojis,

View file

@ -7,6 +7,7 @@ import type { AccountModerationModalProps } from 'pl-fe/features/ui/components/m
import type { BoostModalProps } from 'pl-fe/features/ui/components/modals/boost-modal';
import type { CompareHistoryModalProps } from 'pl-fe/features/ui/components/modals/compare-history-modal';
import type { ComponentModalProps } from 'pl-fe/features/ui/components/modals/component-modal';
import type { ComposeEventModalProps } from 'pl-fe/features/ui/components/modals/compose-event-modal';
import type { ComposeModalProps } from 'pl-fe/features/ui/components/modals/compose-modal';
import type { ConfirmationModalProps } from 'pl-fe/features/ui/components/modals/confirmation-modal';
import type { DislikesModalProps } from 'pl-fe/features/ui/components/modals/dislikes-modal';
@ -38,11 +39,12 @@ import type { VideoModalProps } from 'pl-fe/features/ui/components/modals/video-
type OpenModalProps =
| [type: 'ACCOUNT_MODERATION', props: AccountModerationModalProps]
| [type: 'BIRTHDAYS' | 'COMPOSE_EVENT' | 'CREATE_GROUP' | 'HOTKEYS']
| [type: 'BIRTHDAYS' | 'CREATE_GROUP' | 'HOTKEYS']
| [type: 'BOOST', props: BoostModalProps]
| [type: 'COMPARE_HISTORY', props: CompareHistoryModalProps]
| [type: 'COMPONENT', props: ComponentModalProps]
| [type: 'COMPOSE', props?: ComposeModalProps]
| [type: 'COMPOSE_EVENT', props?: ComposeEventModalProps]
| [type: 'CONFIRM', props: ConfirmationModalProps]
| [type: 'CRYPTO_DONATE', props: ICryptoAddress]
| [type: 'DISLIKES', props: DislikesModalProps]