pleroma/app/soapbox/features/ui/components/modals/manage-group-modal/steps/details-step.tsx
2023-05-02 13:26:30 -04:00

137 lines
4.6 KiB
TypeScript

import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { CreateGroupParams, useGroupValidation } from 'soapbox/api/hooks';
import { Form, FormGroup, Input, Textarea } from 'soapbox/components/ui';
import AvatarPicker from 'soapbox/features/group/components/group-avatar-picker';
import HeaderPicker from 'soapbox/features/group/components/group-header-picker';
import GroupTagsField from 'soapbox/features/group/components/group-tags-field';
import { useAppSelector, useDebounce, useInstance } from 'soapbox/hooks';
import { usePreview } from 'soapbox/hooks/forms';
import resizeImage from 'soapbox/utils/resize-image';
import type { List as ImmutableList } from 'immutable';
const messages = defineMessages({
groupNamePlaceholder: { id: 'manage_group.fields.name_placeholder', defaultMessage: 'Group Name' },
groupDescriptionPlaceholder: { id: 'manage_group.fields.description_placeholder', defaultMessage: 'Description' },
hashtagPlaceholder: { id: 'manage_group.fields.hashtag_placeholder', defaultMessage: 'Add a topic' },
});
interface IDetailsStep {
params: CreateGroupParams
onChange(params: CreateGroupParams): void
}
const DetailsStep: React.FC<IDetailsStep> = ({ params, onChange }) => {
const intl = useIntl();
const debounce = useDebounce;
const instance = useInstance();
const {
display_name: displayName = '',
note = '',
tags = [''],
} = params;
const debouncedName = debounce(displayName, 300);
const { data: { isValid, message: errorMessage } } = useGroupValidation(debouncedName);
const avatarSrc = usePreview(params.avatar);
const headerSrc = usePreview(params.header);
const attachmentTypes = useAppSelector(
state => state.instance.configuration.getIn(['media_attachments', 'supported_mime_types']) as ImmutableList<string>,
)?.filter(type => type.startsWith('image/')).toArray().join(',');
const handleTextChange = (property: keyof CreateGroupParams): React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement> => {
return (e) => {
onChange({
...params,
[property]: e.target.value,
});
};
};
const handleImageChange = (property: keyof CreateGroupParams, maxPixels?: number): React.ChangeEventHandler<HTMLInputElement> => {
return async ({ target: { files } }) => {
const file = files ? files[0] : undefined;
if (file) {
const resized = await resizeImage(file, maxPixels);
onChange({
...params,
[property]: resized,
});
}
};
};
const handleTagsChange = (tags: string[]) => {
onChange({
...params,
tags,
});
};
const handleAddTag = () => {
onChange({
...params,
tags: [...tags, ''],
});
};
const handleRemoveTag = (i: number) => {
const newTags = [...tags];
newTags.splice(i, 1);
onChange({
...params,
tags: newTags,
});
};
return (
<Form>
<div className='relative mb-12 flex'>
<HeaderPicker src={headerSrc} accept={attachmentTypes} onChange={handleImageChange('header', 1920 * 1080)} />
<AvatarPicker src={avatarSrc} accept={attachmentTypes} onChange={handleImageChange('avatar', 400 * 400)} />
</div>
<FormGroup
labelText={<FormattedMessage id='manage_group.fields.name_label' defaultMessage='Group name (required)' />}
hintText={<FormattedMessage id='manage_group.fields.name_help' defaultMessage='This cannot be changed after the group is created.' />}
errors={isValid ? [] : [errorMessage as string]}
>
<Input
type='text'
placeholder={intl.formatMessage(messages.groupNamePlaceholder)}
value={displayName}
onChange={handleTextChange('display_name')}
maxLength={Number(instance.configuration.getIn(['groups', 'max_characters_name']))}
/>
</FormGroup>
<FormGroup
labelText={<FormattedMessage id='manage_group.fields.description_label' defaultMessage='Description' />}
>
<Textarea
autoComplete='off'
placeholder={intl.formatMessage(messages.groupDescriptionPlaceholder)}
value={note}
onChange={handleTextChange('note')}
maxLength={Number(instance.configuration.getIn(['groups', 'max_characters_description']))}
/>
</FormGroup>
<div className='pb-6'>
<GroupTagsField
tags={tags}
onChange={handleTagsChange}
onAddItem={handleAddTag}
onRemoveItem={handleRemoveTag}
/>
</div>
</Form>
);
};
export default DetailsStep;