diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 953c7e252..786d52d13 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -56,6 +56,7 @@ module.exports = { }, polyfills: [ 'es:all', // core-js + 'fetch', // not polyfilled, but ignore it 'IntersectionObserver', // npm:intersection-observer 'Promise', // core-js 'ResizeObserver', // npm:resize-observer-polyfill diff --git a/app/soapbox/components/ui/form-group/form-group.tsx b/app/soapbox/components/ui/form-group/form-group.tsx index e3c897a6f..7efb60ade 100644 --- a/app/soapbox/components/ui/form-group/form-group.tsx +++ b/app/soapbox/components/ui/form-group/form-group.tsx @@ -86,6 +86,12 @@ const FormGroup: React.FC = (props) => { )}
+ {hintText && ( +

+ {hintText} +

+ )} + {firstChild} {inputChildren.filter((_, i) => i !== 0)} @@ -97,12 +103,6 @@ const FormGroup: React.FC = (props) => { {errors.join(', ')}

)} - - {hintText && ( -

- {hintText} -

- )}
); diff --git a/app/soapbox/components/ui/input/input.tsx b/app/soapbox/components/ui/input/input.tsx index 2de6eb566..bb3f9957d 100644 --- a/app/soapbox/components/ui/input/input.tsx +++ b/app/soapbox/components/ui/input/input.tsx @@ -84,8 +84,10 @@ const Input = React.forwardRef( type={revealed ? 'text' : type} ref={ref} className={clsx('text-base placeholder:text-gray-600 dark:placeholder:text-gray-600', { - 'text-gray-900 dark:text-gray-100 block w-full sm:text-sm dark:ring-1 dark:ring-gray-800 focus:ring-primary-500 focus:border-primary-500 dark:focus:ring-primary-500 dark:focus:border-primary-500': + 'block w-full sm:text-sm dark:ring-1 dark:ring-gray-800 focus:ring-primary-500 focus:border-primary-500 dark:focus:ring-primary-500 dark:focus:border-primary-500': ['normal', 'search'].includes(theme), + 'text-gray-900 dark:text-gray-100': !props.disabled, + 'text-gray-600': props.disabled, 'rounded-md bg-white dark:bg-gray-900 border-gray-400 dark:border-gray-800': theme === 'normal', 'rounded-full bg-gray-200 border-gray-200 dark:bg-gray-800 dark:border-gray-800 focus:bg-white': theme === 'search', 'pr-7 rtl:pl-7 rtl:pr-3': isPassword || append, diff --git a/app/soapbox/features/group/edit-group.tsx b/app/soapbox/features/group/edit-group.tsx new file mode 100644 index 000000000..354901fe4 --- /dev/null +++ b/app/soapbox/features/group/edit-group.tsx @@ -0,0 +1,184 @@ +import clsx from 'clsx'; +import React, { useState } from 'react'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import Icon from 'soapbox/components/icon'; +import { Avatar, Button, Column, Form, FormActions, FormGroup, HStack, Input, Spinner, Text, Textarea } from 'soapbox/components/ui'; +import { useAppSelector, useInstance } from 'soapbox/hooks'; +import { useGroup, useUpdateGroup } from 'soapbox/hooks/api'; +import { useImageField, useTextField } from 'soapbox/hooks/forms'; +import { isDefaultAvatar, isDefaultHeader } from 'soapbox/utils/accounts'; + +import type { List as ImmutableList } from 'immutable'; + +const nonDefaultAvatar = (url: string | undefined) => url && isDefaultAvatar(url) ? undefined : url; +const nonDefaultHeader = (url: string | undefined) => url && isDefaultHeader(url) ? undefined : url; + +interface IMediaInput { + src: string | undefined + accept: string + onChange: React.ChangeEventHandler + disabled: boolean +} + +const messages = defineMessages({ + heading: { id: 'navigation_bar.edit_group', defaultMessage: 'Edit Group' }, + groupNamePlaceholder: { id: 'manage_group.fields.name_placeholder', defaultMessage: 'Group Name' }, + groupDescriptionPlaceholder: { id: 'manage_group.fields.description_placeholder', defaultMessage: 'Description' }, +}); + +const HeaderPicker = React.forwardRef(({ src, onChange, accept, disabled }, ref) => { + return ( + + ); +}); + +const AvatarPicker = React.forwardRef(({ src, onChange, accept, disabled }, ref) => { + return ( + + ); +}); + +interface IEditGroup { + params: { + id: string + } +} + +const EditGroup: React.FC = ({ params: { id: groupId } }) => { + const intl = useIntl(); + const instance = useInstance(); + + const { group, isLoading } = useGroup(groupId); + const { updateGroup } = useUpdateGroup(groupId); + + const [isSubmitting, setIsSubmitting] = useState(false); + + const avatar = useImageField({ maxPixels: 400 * 400, preview: nonDefaultAvatar(group?.avatar) }); + const header = useImageField({ maxPixels: 1920 * 1080, preview: nonDefaultHeader(group?.header) }); + + const displayName = useTextField(group?.display_name); + const note = useTextField(group?.note); + + const maxName = Number(instance.configuration.getIn(['groups', 'max_characters_name'])); + const maxNote = Number(instance.configuration.getIn(['groups', 'max_characters_description'])); + + const attachmentTypes = useAppSelector( + state => state.instance.configuration.getIn(['media_attachments', 'supported_mime_types']) as ImmutableList, + )?.filter(type => type.startsWith('image/')).toArray().join(','); + + async function handleSubmit() { + setIsSubmitting(true); + + await updateGroup({ + display_name: displayName.value, + note: note.value, + avatar: avatar.file, + header: header.file, + }); + + setIsSubmitting(false); + } + + if (isLoading) { + return ; + } + + return ( + +
+
+ + +
+ } + hintText={} + > + } + disabled + /> + + } + > +