|
|
|
|
@ -9,14 +9,15 @@ import { |
|
|
|
|
Button, |
|
|
|
|
Icon, |
|
|
|
|
Box, |
|
|
|
|
FieldDescription, |
|
|
|
|
FieldHint, |
|
|
|
|
FieldLabel, |
|
|
|
|
FieldRow, |
|
|
|
|
FieldError, |
|
|
|
|
} from '@rocket.chat/fuselage'; |
|
|
|
|
import { useUniqueId } from '@rocket.chat/fuselage-hooks'; |
|
|
|
|
import { useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; |
|
|
|
|
import { useMutation } from '@tanstack/react-query'; |
|
|
|
|
import type { ComponentProps, ReactElement } from 'react'; |
|
|
|
|
import type { ReactElement } from 'react'; |
|
|
|
|
import React from 'react'; |
|
|
|
|
import { useForm, Controller } from 'react-hook-form'; |
|
|
|
|
|
|
|
|
|
@ -44,12 +45,12 @@ const CreateDiscussion = ({ onClose, defaultParentRoom, parentMessageId, nameSug |
|
|
|
|
const t = useTranslation(); |
|
|
|
|
|
|
|
|
|
const { |
|
|
|
|
register, |
|
|
|
|
formState: { isDirty, errors }, |
|
|
|
|
formState: { isDirty, isSubmitting, isValidating, errors }, |
|
|
|
|
handleSubmit, |
|
|
|
|
control, |
|
|
|
|
watch, |
|
|
|
|
} = useForm({ |
|
|
|
|
mode: 'onBlur', |
|
|
|
|
defaultValues: { |
|
|
|
|
name: nameSuggestion || '', |
|
|
|
|
parentRoom: '', |
|
|
|
|
@ -81,22 +82,28 @@ const CreateDiscussion = ({ onClose, defaultParentRoom, parentMessageId, nameSug |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const targetChannelField = useUniqueId(); |
|
|
|
|
const encryptedField = useUniqueId(); |
|
|
|
|
const discussionField = useUniqueId(); |
|
|
|
|
const usersField = useUniqueId(); |
|
|
|
|
const firstMessageField = useUniqueId(); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<Modal |
|
|
|
|
data-qa='create-discussion-modal' |
|
|
|
|
wrapperFunction={(props: ComponentProps<typeof Box>) => <Box is='form' onSubmit={handleSubmit(handleCreate)} {...props} />} |
|
|
|
|
wrapperFunction={(props) => <Box is='form' onSubmit={handleSubmit(handleCreate)} {...props} />} |
|
|
|
|
> |
|
|
|
|
<Modal.Header> |
|
|
|
|
<Modal.Title>{t('Discussion_title')}</Modal.Title> |
|
|
|
|
<Modal.Close onClick={onClose} /> |
|
|
|
|
<Modal.Close tabIndex={-1} onClick={onClose} /> |
|
|
|
|
</Modal.Header> |
|
|
|
|
<Modal.Content> |
|
|
|
|
<Box mbe={24}>{t('Discussion_description')}</Box> |
|
|
|
|
<FieldGroup> |
|
|
|
|
<Field> |
|
|
|
|
<FieldDescription>{t('Discussion_description')}</FieldDescription> |
|
|
|
|
</Field> |
|
|
|
|
<Field> |
|
|
|
|
<FieldLabel>{t('Discussion_target_channel')}</FieldLabel> |
|
|
|
|
<FieldLabel htmlFor={targetChannelField} required> |
|
|
|
|
{t('Discussion_target_channel')} |
|
|
|
|
</FieldLabel> |
|
|
|
|
<FieldRow> |
|
|
|
|
{defaultParentRoom && ( |
|
|
|
|
<Controller |
|
|
|
|
@ -105,78 +112,119 @@ const CreateDiscussion = ({ onClose, defaultParentRoom, parentMessageId, nameSug |
|
|
|
|
render={() => <DefaultParentRoomField defaultParentRoom={defaultParentRoom} />} |
|
|
|
|
/> |
|
|
|
|
)} |
|
|
|
|
|
|
|
|
|
{!defaultParentRoom && ( |
|
|
|
|
<Controller |
|
|
|
|
control={control} |
|
|
|
|
name='parentRoom' |
|
|
|
|
rules={{ required: t('Field_required') }} |
|
|
|
|
render={({ field: { onChange, value } }) => ( |
|
|
|
|
rules={{ required: t('error-the-field-is-required', { field: t('Discussion_target_channel') }) }} |
|
|
|
|
render={({ field: { name, onBlur, onChange, value } }) => ( |
|
|
|
|
<RoomAutoComplete |
|
|
|
|
value={value} |
|
|
|
|
name={name} |
|
|
|
|
onBlur={onBlur} |
|
|
|
|
onChange={onChange} |
|
|
|
|
value={value} |
|
|
|
|
id={targetChannelField} |
|
|
|
|
placeholder={t('Discussion_target_channel_description')} |
|
|
|
|
disabled={Boolean(defaultParentRoom)} |
|
|
|
|
aria-invalid={Boolean(errors.parentRoom)} |
|
|
|
|
aria-required='true' |
|
|
|
|
aria-describedby={`${targetChannelField}-error`} |
|
|
|
|
/> |
|
|
|
|
)} |
|
|
|
|
/> |
|
|
|
|
)} |
|
|
|
|
</FieldRow> |
|
|
|
|
{errors.parentRoom && <FieldError>{errors.parentRoom.message}</FieldError>} |
|
|
|
|
{errors.parentRoom && ( |
|
|
|
|
<FieldError aria-live='assertive' id={`${targetChannelField}-error`}> |
|
|
|
|
{errors.parentRoom.message} |
|
|
|
|
</FieldError> |
|
|
|
|
)} |
|
|
|
|
</Field> |
|
|
|
|
<Field display='flex' alignItems='center' flexDirection='row' justifyContent='spaceBetween' flexGrow={1}> |
|
|
|
|
<Box display='flex' flexDirection='column' width='full'> |
|
|
|
|
<FieldLabel>{t('Encrypted')}</FieldLabel> |
|
|
|
|
</Box> |
|
|
|
|
<Controller |
|
|
|
|
control={control} |
|
|
|
|
name='encrypted' |
|
|
|
|
render={({ field: { onChange, value } }) => ( |
|
|
|
|
<ToggleSwitch |
|
|
|
|
checked={value} |
|
|
|
|
onChange={onChange} |
|
|
|
|
aria-describedby='Encrypted_discussion_Description' |
|
|
|
|
aria-labelledby='Encrypted_discussion_Label' |
|
|
|
|
<Field> |
|
|
|
|
<Box display='flex' alignItems='center' flexDirection='row' justifyContent='spaceBetween' flexGrow={1}> |
|
|
|
|
<FieldLabel htmlFor={encryptedField}>{t('Encrypted')}</FieldLabel> |
|
|
|
|
<FieldRow> |
|
|
|
|
<Controller |
|
|
|
|
control={control} |
|
|
|
|
name='encrypted' |
|
|
|
|
render={({ field: { value, ...field } }) => <ToggleSwitch id={encryptedField} {...field} checked={value} />} |
|
|
|
|
/> |
|
|
|
|
)} |
|
|
|
|
/> |
|
|
|
|
</FieldRow> |
|
|
|
|
</Box> |
|
|
|
|
</Field> |
|
|
|
|
<Field> |
|
|
|
|
<FieldLabel>{t('Discussion_name')}</FieldLabel> |
|
|
|
|
<FieldLabel htmlFor={discussionField} required> |
|
|
|
|
{t('Discussion_name')} |
|
|
|
|
</FieldLabel> |
|
|
|
|
<FieldRow> |
|
|
|
|
<TextInput |
|
|
|
|
{...register('name', { required: t('Field_required') })} |
|
|
|
|
placeholder={t('New_discussion_name')} |
|
|
|
|
addon={<Icon name='baloons' size='x20' />} |
|
|
|
|
<Controller |
|
|
|
|
name='name' |
|
|
|
|
control={control} |
|
|
|
|
rules={{ required: t('Field_required') }} |
|
|
|
|
render={({ field }) => ( |
|
|
|
|
<TextInput |
|
|
|
|
id={discussionField} |
|
|
|
|
{...field} |
|
|
|
|
placeholder={t('New_discussion_name')} |
|
|
|
|
aria-invalid={Boolean(errors.name)} |
|
|
|
|
aria-required='true' |
|
|
|
|
aria-describedby={`${discussionField}-error`} |
|
|
|
|
addon={<Icon name='baloons' size='x20' />} |
|
|
|
|
/> |
|
|
|
|
)} |
|
|
|
|
/> |
|
|
|
|
</FieldRow> |
|
|
|
|
{errors.name && <FieldError>{errors.name.message}</FieldError>} |
|
|
|
|
{errors.name && ( |
|
|
|
|
<FieldError aria-live='assertive' id={`${discussionField}-error`}> |
|
|
|
|
{errors.name.message} |
|
|
|
|
</FieldError> |
|
|
|
|
)} |
|
|
|
|
</Field> |
|
|
|
|
<Field> |
|
|
|
|
<FieldLabel>{t('Invite_Users')}</FieldLabel> |
|
|
|
|
<FieldRow w='full' display='flex' flexDirection='column' alignItems='stretch'> |
|
|
|
|
<FieldLabel htmlFor={usersField}>{t('Invite_Users')}</FieldLabel> |
|
|
|
|
<FieldRow> |
|
|
|
|
<Controller |
|
|
|
|
control={control} |
|
|
|
|
name='usernames' |
|
|
|
|
render={({ field: { onChange, value } }) => ( |
|
|
|
|
<UserAutoCompleteMultiple value={value} onChange={onChange} placeholder={t('Username_Placeholder')} /> |
|
|
|
|
render={({ field: { name, onChange, value, onBlur } }) => ( |
|
|
|
|
<UserAutoCompleteMultiple |
|
|
|
|
id={usersField} |
|
|
|
|
name={name} |
|
|
|
|
onChange={onChange} |
|
|
|
|
value={value} |
|
|
|
|
onBlur={onBlur} |
|
|
|
|
placeholder={t('Username_Placeholder')} |
|
|
|
|
/> |
|
|
|
|
)} |
|
|
|
|
/> |
|
|
|
|
</FieldRow> |
|
|
|
|
</Field> |
|
|
|
|
<Field> |
|
|
|
|
<FieldLabel>{t('Discussion_first_message_title')}</FieldLabel> |
|
|
|
|
<FieldLabel htmlFor={firstMessageField}>{t('Discussion_first_message_title')}</FieldLabel> |
|
|
|
|
<FieldRow> |
|
|
|
|
<TextAreaInput {...register('firstMessage')} placeholder={t('New_discussion_first_message')} rows={5} disabled={encrypted} /> |
|
|
|
|
<Controller |
|
|
|
|
control={control} |
|
|
|
|
name='firstMessage' |
|
|
|
|
render={({ field }) => ( |
|
|
|
|
<TextAreaInput |
|
|
|
|
id={firstMessageField} |
|
|
|
|
{...field} |
|
|
|
|
placeholder={t('New_discussion_first_message')} |
|
|
|
|
rows={5} |
|
|
|
|
disabled={encrypted} |
|
|
|
|
aria-describedby={`${firstMessageField}-hint`} |
|
|
|
|
/> |
|
|
|
|
)} |
|
|
|
|
/> |
|
|
|
|
</FieldRow> |
|
|
|
|
{encrypted && <FieldDescription>{t('Discussion_first_message_disabled_due_to_e2e')}</FieldDescription>} |
|
|
|
|
{encrypted && <FieldHint id={`${firstMessageField}-hint`}>{t('Discussion_first_message_disabled_due_to_e2e')}</FieldHint>} |
|
|
|
|
</Field> |
|
|
|
|
</FieldGroup> |
|
|
|
|
</Modal.Content> |
|
|
|
|
<Modal.Footer> |
|
|
|
|
<Modal.FooterControllers> |
|
|
|
|
<Button onClick={onClose}>{t('Cancel')}</Button> |
|
|
|
|
<Button type='submit' primary disabled={!isDirty || createDiscussionMutation.isLoading}> |
|
|
|
|
<Button type='submit' primary disabled={!isDirty || isSubmitting || isValidating}> |
|
|
|
|
{t('Create')} |
|
|
|
|
</Button> |
|
|
|
|
</Modal.FooterControllers> |
|
|
|
|
|