From 925509a985a6c688a01419ec462e71ccafec9cf3 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 8 Mar 2023 12:20:20 -0600 Subject: [PATCH] Fix groups modal bailing too soon --- app/soapbox/actions/groups.ts | 1 - .../manage-group-modal/manage-group-modal.tsx | 17 +- .../steps/confirmation-step.tsx | 163 ++++++++++++++++++ 3 files changed, 176 insertions(+), 5 deletions(-) create mode 100644 app/soapbox/features/ui/components/modals/manage-group-modal/steps/confirmation-step.tsx diff --git a/app/soapbox/actions/groups.ts b/app/soapbox/actions/groups.ts index 9715396f3..08039166f 100644 --- a/app/soapbox/actions/groups.ts +++ b/app/soapbox/actions/groups.ts @@ -148,7 +148,6 @@ const createGroup = (params: Record, shouldReset?: boolean) => if (shouldReset) { dispatch(resetGroupEditor()); } - dispatch(closeModal('MANAGE_GROUP')); }).catch(err => dispatch(createGroupFail(err))); }; diff --git a/app/soapbox/features/ui/components/modals/manage-group-modal/manage-group-modal.tsx b/app/soapbox/features/ui/components/modals/manage-group-modal/manage-group-modal.tsx index 77cdf5c29..22fe726b0 100644 --- a/app/soapbox/features/ui/components/modals/manage-group-modal/manage-group-modal.tsx +++ b/app/soapbox/features/ui/components/modals/manage-group-modal/manage-group-modal.tsx @@ -1,10 +1,11 @@ import React, { useMemo, useState } from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import { submitGroupEditor } from 'soapbox/actions/groups'; +import { resetGroupEditor, submitGroupEditor } from 'soapbox/actions/groups'; import { Modal, Stack } from 'soapbox/components/ui'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; +import ConfirmationStep from './steps/confirmation-step'; import DetailsStep from './steps/details-step'; import PrivacyStep from './steps/privacy-step'; @@ -12,16 +13,19 @@ const messages = defineMessages({ next: { id: 'manage_group.next', defaultMessage: 'Next' }, create: { id: 'manage_group.create', defaultMessage: 'Create' }, update: { id: 'manage_group.update', defaultMessage: 'Update' }, + done: { id: 'manage_group.done', defaultMessage: 'Done' }, }); enum Steps { ONE = 'ONE', TWO = 'TWO', + THREE = 'THREE', } const manageGroupSteps = { ONE: PrivacyStep, TWO: DetailsStep, + THREE: ConfirmationStep, }; interface IManageGroupModal { @@ -38,7 +42,7 @@ const ManageGroupModal: React.FC = ({ onClose }) => { const [currentStep, setCurrentStep] = useState(id ? Steps.TWO : Steps.ONE); - const onClickClose = () => { + const handleClose = () => { onClose('MANAGE_GROUP'); }; @@ -48,6 +52,8 @@ const ManageGroupModal: React.FC = ({ onClose }) => { const confirmationText = useMemo(() => { switch (currentStep) { + case Steps.THREE: + return intl.formatMessage(messages.done); case Steps.TWO: return intl.formatMessage(id ? messages.update : messages.create); default: @@ -62,7 +68,10 @@ const ManageGroupModal: React.FC = ({ onClose }) => { break; case Steps.TWO: handleSubmit(); - onClose(); + setCurrentStep(Steps.THREE); + break; + case Steps.THREE: + handleClose(); break; default: break; @@ -80,7 +89,7 @@ const ManageGroupModal: React.FC = ({ onClose }) => { confirmationText={confirmationText} confirmationDisabled={isSubmitting} confirmationFullWidth - onClose={onClickClose} + onClose={handleClose} > diff --git a/app/soapbox/features/ui/components/modals/manage-group-modal/steps/confirmation-step.tsx b/app/soapbox/features/ui/components/modals/manage-group-modal/steps/confirmation-step.tsx new file mode 100644 index 000000000..f0fa85cf9 --- /dev/null +++ b/app/soapbox/features/ui/components/modals/manage-group-modal/steps/confirmation-step.tsx @@ -0,0 +1,163 @@ +import clsx from 'clsx'; +import React, { useEffect, useState } from 'react'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import { + changeGroupEditorTitle, + changeGroupEditorDescription, + changeGroupEditorMedia, +} from 'soapbox/actions/groups'; +import Icon from 'soapbox/components/icon'; +import { Avatar, Form, FormGroup, HStack, Input, Text, Textarea } from 'soapbox/components/ui'; +import { useAppDispatch, useAppSelector, useInstance } from 'soapbox/hooks'; +import { isDefaultAvatar, isDefaultHeader } from 'soapbox/utils/accounts'; +import resizeImage from 'soapbox/utils/resize-image'; + +import type { List as ImmutableList } from 'immutable'; + +interface IMediaInput { + src: string | null + accept: string + onChange: React.ChangeEventHandler + disabled: boolean +} + +const messages = defineMessages({ + groupNamePlaceholder: { id: 'manage_group.fields.name_placeholder', defaultMessage: 'Group Name' }, + groupDescriptionPlaceholder: { id: 'manage_group.fields.description_placeholder', defaultMessage: 'Description' }, +}); + +const HeaderPicker: React.FC = ({ src, onChange, accept, disabled }) => { + return ( + + ); +}; + +const AvatarPicker: React.FC = ({ src, onChange, accept, disabled }) => { + return ( + + ); +}; + +const ConfirmationStep = () => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + const instance = useInstance(); + + const groupId = useAppSelector((state) => state.group_editor.groupId); + const isUploading = useAppSelector((state) => state.group_editor.isUploading); + const name = useAppSelector((state) => state.group_editor.displayName); + const description = useAppSelector((state) => state.group_editor.note); + + const [avatarSrc, setAvatarSrc] = useState(null); + const [headerSrc, setHeaderSrc] = useState(null); + + const attachmentTypes = useAppSelector( + state => state.instance.configuration.getIn(['media_attachments', 'supported_mime_types']) as ImmutableList, + )?.filter(type => type.startsWith('image/')).toArray().join(','); + + const onChangeName: React.ChangeEventHandler = ({ target }) => { + dispatch(changeGroupEditorTitle(target.value)); + }; + + const onChangeDescription: React.ChangeEventHandler = ({ target }) => { + dispatch(changeGroupEditorDescription(target.value)); + }; + + const handleFileChange: React.ChangeEventHandler = e => { + const rawFile = e.target.files?.item(0); + + if (!rawFile) return; + + if (e.target.name === 'avatar') { + resizeImage(rawFile, 400 * 400).then(file => { + dispatch(changeGroupEditorMedia('avatar', file)); + setAvatarSrc(URL.createObjectURL(file)); + }).catch(console.error); + } else { + resizeImage(rawFile, 1920 * 1080).then(file => { + dispatch(changeGroupEditorMedia('header', file)); + setHeaderSrc(URL.createObjectURL(file)); + }).catch(console.error); + } + }; + + useEffect(() => { + if (!groupId) return; + + dispatch((_, getState) => { + const group = getState().groups.items.get(groupId); + if (!group) return; + if (group.avatar && !isDefaultAvatar(group.avatar)) setAvatarSrc(group.avatar); + if (group.header && !isDefaultHeader(group.header)) setHeaderSrc(group.header); + }); + }, [groupId]); + + return ( +
+
+ + +
+
+ You're all set! +
+
+ ); +}; + +export default ConfirmationStep;