diff --git a/src/features/ui/components/modals/onboarding-flow-modal/steps/avatar-step.tsx b/src/features/ui/components/modals/onboarding-flow-modal/steps/avatar-step.tsx new file mode 100644 index 000000000..090a7a97c --- /dev/null +++ b/src/features/ui/components/modals/onboarding-flow-modal/steps/avatar-step.tsx @@ -0,0 +1,136 @@ +import clsx from 'clsx'; +import React from 'react'; +import { FormattedMessage, defineMessages } from 'react-intl'; + +import { patchMe } from 'soapbox/actions/me'; +import { Button, Stack, Text, Avatar, Icon, Spinner } from 'soapbox/components/ui'; +import IconButton from 'soapbox/components/ui/icon-button/icon-button'; +import { useAppDispatch, useOwnAccount } from 'soapbox/hooks'; +import toast from 'soapbox/toast'; +import { isDefaultAvatar } from 'soapbox/utils/accounts'; +import resizeImage from 'soapbox/utils/resize-image'; + +import type { AxiosError } from 'axios'; + +const closeIcon = require('@tabler/icons/outline/x.svg'); + +const messages = defineMessages({ + error: { id: 'onboarding.error', defaultMessage: 'An unexpected error occurred. Please try again or skip this step.' }, +}); + + +interface IAvatarSelectionModal { + onClose?(): void; + onNext: () => void; +} + +const AvatarSelectionModal: React.FC = ({ onClose, onNext }) => { + const dispatch = useAppDispatch(); + const { account } = useOwnAccount(); + const fileInput = React.useRef(null); + const [selectedFile, setSelectedFile] = React.useState(); + const [isSubmitting, setSubmitting] = React.useState(false); + const [isDisabled, setDisabled] = React.useState(true); + const isDefault = account ? isDefaultAvatar(account.avatar) : false; + + const openFilePicker = () => { + fileInput.current?.click(); + }; + + const handleFileChange = (event: React.ChangeEvent) => { + const maxPixels = 400 * 400; + const rawFile = event.target.files?.item(0); + + if (!rawFile) return; + + resizeImage(rawFile, maxPixels).then((file) => { + const url = file ? URL.createObjectURL(file) : account?.avatar as string; + + setSelectedFile(url); + setSubmitting(true); + + const formData = new FormData(); + formData.append('avatar', rawFile); + const credentials = dispatch(patchMe(formData)); + + Promise.all([credentials]).then(() => { + setDisabled(false); + setSubmitting(false); + onNext(); + }).catch((error: AxiosError) => { + setSubmitting(false); + setDisabled(false); + setSelectedFile(null); + + if (error.response?.status === 422) { + toast.error((error.response.data as any).error.replace('Validation failed: ', '')); + } else { + toast.error(messages.error); + } + }); + }).catch(console.error); + }; + return ( + + +
+ + + + + {/* Colocar o titulo aqui */} + + + + {/* Colocar o subtitulo aqui */} + + +
+ +
+ {account && ( + + )} + + {isSubmitting && ( +
+ +
+ )} + + + + +
+ + + + + {isDisabled && ( + + )} + +
+ ); +}; + + +export default AvatarSelectionModal; \ No newline at end of file diff --git a/src/features/ui/components/modals/onboarding-flow-modal/steps/bio-step.tsx b/src/features/ui/components/modals/onboarding-flow-modal/steps/bio-step.tsx new file mode 100644 index 000000000..f79c7e688 --- /dev/null +++ b/src/features/ui/components/modals/onboarding-flow-modal/steps/bio-step.tsx @@ -0,0 +1,101 @@ +import React from 'react'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import { patchMe } from 'soapbox/actions/me'; +import { Button, Text, FormGroup, Stack, Textarea } from 'soapbox/components/ui'; +import IconButton from 'soapbox/components/ui/icon-button/icon-button'; +import { useAppDispatch, useOwnAccount } from 'soapbox/hooks'; +import toast from 'soapbox/toast'; + +import type { AxiosError } from 'axios'; + +const messages = defineMessages({ + bioPlaceholder: { id: 'onboarding.bio.placeholder', defaultMessage: 'Tell the world a little about yourself…' }, + error: { id: 'onboarding.error', defaultMessage: 'An unexpected error occurred. Please try again or skip this step.' }, +}); + +const closeIcon = require('@tabler/icons/outline/x.svg'); + +interface IBioStep { + onClose(): void; + onNext: () => void; +} + +const BioStep: React.FC = ({ onClose, onNext }) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + const { account } = useOwnAccount(); + const [value, setValue] = React.useState(account?.source?.note ?? ''); + const [isSubmitting, setSubmitting] = React.useState(false); + const [errors, setErrors] = React.useState([]); + + const handleSubmit = () => { + setSubmitting(true); + + const credentials = dispatch(patchMe({ note: value })); + + Promise.all([credentials]) + .then(() => { + setSubmitting(false); + onNext(); + }).catch((error: AxiosError) => { + setSubmitting(false); + + if (error.response?.status === 422) { + setErrors([(error.response.data as any).error.replace('Validation failed: ', '')]); + } else { + toast.error(messages.error); + } + }); + }; + + return ( + + + +
+ + + + + + + + + +
+ +
+ } + labelText={} + errors={errors} + > +