Move compose event form state to modal itself
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
1150b05c11
commit
8cbaa75546
9 changed files with 169 additions and 359 deletions
|
@ -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>;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in a new issue