Compose event modal improvements

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2022-11-30 19:32:35 +01:00
parent 13ccc3fe7f
commit 403bcba525
6 changed files with 79 additions and 16 deletions

View file

@ -5,15 +5,18 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom';
import { cancelReplyCompose } from 'soapbox/actions/compose';
import { cancelEventCompose } from 'soapbox/actions/events';
import { openModal, closeModal } from 'soapbox/actions/modals';
import { useAppDispatch, useAppSelector, usePrevious } from 'soapbox/hooks';
import { useAppDispatch, usePrevious } from 'soapbox/hooks';
import type { UnregisterCallback } from 'history';
import type { ModalType } from 'soapbox/features/ui/components/modal-root';
import type { ReducerCompose } from 'soapbox/reducers/compose';
import type { ReducerRecord as ReducerComposeEvent } from 'soapbox/reducers/compose-event';
const messages = defineMessages({
confirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
cancelEditing: { id: 'confirmations.cancel_editing.confirm', defaultMessage: 'Cancel editing' },
});
export const checkComposeContent = (compose?: ReturnType<typeof ReducerCompose>) => {
@ -25,6 +28,15 @@ export const checkComposeContent = (compose?: ReturnType<typeof ReducerCompose>)
].some(check => check === true);
};
export const checkEventComposeContent = (compose?: ReturnType<typeof ReducerComposeEvent>) => {
return !!compose && [
compose.name.length > 0,
compose.status.length > 0,
compose.location !== null,
compose.banner !== null,
].some(check => check === true);
};
interface IModalRoot {
onCancel?: () => void,
onClose: (type?: ModalType) => void,
@ -46,8 +58,6 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
const prevChildren = usePrevious(children);
const prevType = usePrevious(type);
const isEditing = useAppSelector(state => state.compose.get('compose-modal')?.id !== null);
const visible = !!children;
const handleKeyUp = (e: KeyboardEvent) => {
@ -58,13 +68,20 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
const handleOnClose = () => {
dispatch((_, getState) => {
const hasComposeContent = checkComposeContent(getState().compose.get('compose-modal'));
const compose = getState().compose.get('compose-modal');
const hasComposeContent = checkComposeContent(compose);
const hasEventComposeContent = checkEventComposeContent(getState().compose_event);
if (hasComposeContent && type === 'COMPOSE') {
const isEditing = compose!.id !== null;
dispatch(openModal('CONFIRM', {
icon: require('@tabler/icons/trash.svg'),
heading: isEditing ? <FormattedMessage id='confirmations.cancel_editing.heading' defaultMessage='Cancel post editing' /> : <FormattedMessage id='confirmations.delete.heading' defaultMessage='Delete post' />,
message: isEditing ? <FormattedMessage id='confirmations.cancel_editing.message' defaultMessage='Are you sure you want to cancel editing this post? All changes will be lost.' /> : <FormattedMessage id='confirmations.delete.message' defaultMessage='Are you sure you want to delete this post?' />,
heading: isEditing
? <FormattedMessage id='confirmations.cancel_editing.heading' defaultMessage='Cancel post editing' />
: <FormattedMessage id='confirmations.delete.heading' defaultMessage='Delete post' />,
message: isEditing
? <FormattedMessage id='confirmations.cancel_editing.message' defaultMessage='Are you sure you want to cancel editing this post? All changes will be lost.' />
: <FormattedMessage id='confirmations.delete.message' defaultMessage='Are you sure you want to delete this post?' />,
confirm: intl.formatMessage(messages.confirm),
onConfirm: () => {
dispatch(closeModal('COMPOSE'));
@ -74,7 +91,26 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type })
dispatch(closeModal('CONFIRM'));
},
}));
} else if (hasComposeContent && type === 'CONFIRM') {
} else if (hasEventComposeContent && type === 'COMPOSE_EVENT') {
const isEditing = getState().compose_event.id !== null;
dispatch(openModal('CONFIRM', {
icon: require('@tabler/icons/trash.svg'),
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: () => {
dispatch(closeModal('COMPOSE_EVENT'));
dispatch(cancelEventCompose());
},
onCancel: () => {
dispatch(closeModal('CONFIRM'));
},
}));
} else if ((hasComposeContent || hasEventComposeContent) && type === 'CONFIRM') {
dispatch(closeModal('CONFIRM'));
} else {
onClose();

View file

@ -56,9 +56,9 @@ const EventInformation: React.FC<IEventInformation> = ({ params }) => {
};
const renderEventLocation = useCallback(() => {
const event = status?.event;
const event = status!.event!;
return event?.location && (
return event.location && (
<Stack space={1}>
<Text size='xl' weight='bold'>
<FormattedMessage id='event.location' defaultMessage='Location' />
@ -86,12 +86,12 @@ const EventInformation: React.FC<IEventInformation> = ({ params }) => {
}, [status]);
const renderEventDate = useCallback(() => {
const event = status?.event;
const event = status!.event!;
if (!event.start_time) return null;
const startDate = new Date(event.start_time);
const endDate = new Date(event.end_time);
if (!startDate) return null;
const endDate = event.end_time && new Date(event.end_time);
const sameDay = endDate && startDate.getDate() === endDate.getDate() && startDate.getMonth() === endDate.getMonth() && startDate.getFullYear() === endDate.getFullYear();

View file

@ -16,9 +16,12 @@ import {
fetchEventParticipationRequests,
rejectEventParticipationRequest,
authorizeEventParticipationRequest,
cancelEventCompose,
} from 'soapbox/actions/events';
import { closeModal, openModal } from 'soapbox/actions/modals';
import { ADDRESS_ICONS } from 'soapbox/components/autosuggest-location';
import LocationSearch from 'soapbox/components/location-search';
import { checkEventComposeContent } from 'soapbox/components/modal-root';
import { Button, Form, FormGroup, HStack, Icon, IconButton, Input, Modal, Spinner, Stack, Tabs, Text, Textarea } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import { isCurrentOrFutureDate } from 'soapbox/features/compose/components/schedule-form';
@ -38,6 +41,8 @@ const messages = defineMessages({
pending: { id: 'compose_event.tabs.pending', defaultMessage: 'Manage requests' },
authorize: { id: 'compose_event.participation_requests.authorize', defaultMessage: 'Authorize' },
reject: { id: 'compose_event.participation_requests.reject', defaultMessage: 'Reject' },
confirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
cancelEditing: { id: 'confirmations.cancel_editing.confirm', defaultMessage: 'Cancel editing' },
});
@ -136,7 +141,26 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
};
const onClickClose = () => {
onClose('COMPOSE_EVENT');
dispatch((dispatch, getState) => {
if (checkEventComposeContent(getState().compose_event)) {
dispatch(openModal('CONFIRM', {
icon: require('@tabler/icons/trash.svg'),
heading: id
? <FormattedMessage id='confirmations.cancel_event_editing.heading' defaultMessage='Cancel event editing' />
: <FormattedMessage id='confirmations.delete_event.heading' defaultMessage='Delete event' />,
message: id
? <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: () => {
dispatch(closeModal('COMPOSE_EVENT'));
dispatch(cancelEventCompose());
},
}));
} else {
onClose('COMPOSE_EVENT');
}
});
};
const handleFiles = (files: FileList) => {

View file

@ -120,6 +120,7 @@ import { WrappedRoute } from './util/react-router-helpers';
// Dummy import, to make sure that <Status /> ends up in the application bundle.
// Without this it ends up in ~8 very commonly used bundles.
import 'soapbox/components/status';
import { uploadEventBanner } from 'soapbox/actions/events';
const EmptyPage = HomePage;
@ -384,7 +385,9 @@ const UI: React.FC = ({ children }) => {
if (e.dataTransfer && e.dataTransfer.files.length >= 1) {
const modals = getState().modals;
const isModalOpen = modals.last()?.modalType === 'COMPOSE';
dispatch(uploadCompose(isModalOpen ? 'compose-modal' : 'home', e.dataTransfer.files, intl));
const isEventsModalOpen = modals.last()?.modalType === 'COMPOSE_EVENT';
if (isEventsModalOpen) dispatch(uploadEventBanner(e.dataTransfer.files[0], intl));
else dispatch(uploadCompose(isModalOpen ? 'compose-modal' : 'home', e.dataTransfer.files, intl));
}
});
};

View file

@ -19,7 +19,7 @@ import chat_message_lists from './chat-message-lists';
import chat_messages from './chat-messages';
import chats from './chats';
import compose from './compose';
import compose_event from './compose_event';
import compose_event from './compose-event';
import contexts from './contexts';
import conversations from './conversations';
import custom_emojis from './custom-emojis';