Admin: redesign registration picker
This commit is contained in:
parent
52bdb48bfb
commit
4fde647aa8
4 changed files with 75 additions and 82 deletions
43
app/soapbox/components/radio.tsx
Normal file
43
app/soapbox/components/radio.tsx
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import List, { ListItem } from './list';
|
||||||
|
|
||||||
|
interface IRadioGroup {
|
||||||
|
onChange: React.ChangeEventHandler
|
||||||
|
children: React.ReactElement<{ onChange: React.ChangeEventHandler }>[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const RadioGroup = ({ onChange, children }: IRadioGroup) => {
|
||||||
|
const childrenWithProps = React.Children.map(children, child =>
|
||||||
|
React.cloneElement(child, { onChange }),
|
||||||
|
);
|
||||||
|
|
||||||
|
return <List>{childrenWithProps}</List>;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IRadioItem {
|
||||||
|
label: React.ReactNode,
|
||||||
|
hint?: React.ReactNode,
|
||||||
|
value: string,
|
||||||
|
checked: boolean,
|
||||||
|
onChange?: React.ChangeEventHandler,
|
||||||
|
}
|
||||||
|
|
||||||
|
const RadioItem: React.FC<IRadioItem> = ({ label, hint, checked = false, onChange, value }) => {
|
||||||
|
return (
|
||||||
|
<ListItem label={label} hint={hint}>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
checked={checked}
|
||||||
|
onChange={onChange}
|
||||||
|
value={value}
|
||||||
|
className='h-4 w-4 border-gray-300 text-primary-600 focus:ring-primary-500'
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
RadioGroup,
|
||||||
|
RadioItem,
|
||||||
|
};
|
|
@ -3,12 +3,7 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { updateConfig } from 'soapbox/actions/admin';
|
import { updateConfig } from 'soapbox/actions/admin';
|
||||||
import snackbar from 'soapbox/actions/snackbar';
|
import snackbar from 'soapbox/actions/snackbar';
|
||||||
import {
|
import { RadioGroup, RadioItem } from 'soapbox/components/radio';
|
||||||
SimpleForm,
|
|
||||||
FieldsGroup,
|
|
||||||
RadioGroup,
|
|
||||||
RadioItem,
|
|
||||||
} from 'soapbox/features/forms';
|
|
||||||
import { useAppDispatch, useInstance } from 'soapbox/hooks';
|
import { useAppDispatch, useInstance } from 'soapbox/hooks';
|
||||||
|
|
||||||
import type { Instance } from 'soapbox/types/entities';
|
import type { Instance } from 'soapbox/types/entities';
|
||||||
|
@ -54,33 +49,26 @@ const RegistrationModePicker: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SimpleForm>
|
<RadioGroup onChange={onChange}>
|
||||||
<FieldsGroup>
|
<RadioItem
|
||||||
<RadioGroup
|
label={<FormattedMessage id='admin.dashboard.registration_mode.open_label' defaultMessage='Open' />}
|
||||||
label={<FormattedMessage id='admin.dashboard.registration_mode_label' defaultMessage='Registrations' />}
|
hint={<FormattedMessage id='admin.dashboard.registration_mode.open_hint' defaultMessage='Anyone can join.' />}
|
||||||
onChange={onChange}
|
checked={mode === 'open'}
|
||||||
>
|
value='open'
|
||||||
<RadioItem
|
/>
|
||||||
label={<FormattedMessage id='admin.dashboard.registration_mode.open_label' defaultMessage='Open' />}
|
<RadioItem
|
||||||
hint={<FormattedMessage id='admin.dashboard.registration_mode.open_hint' defaultMessage='Anyone can join.' />}
|
label={<FormattedMessage id='admin.dashboard.registration_mode.approval_label' defaultMessage='Approval Required' />}
|
||||||
checked={mode === 'open'}
|
hint={<FormattedMessage id='admin.dashboard.registration_mode.approval_hint' defaultMessage='Users can sign up, but their account only gets activated when an admin approves it.' />}
|
||||||
value='open'
|
checked={mode === 'approval'}
|
||||||
/>
|
value='approval'
|
||||||
<RadioItem
|
/>
|
||||||
label={<FormattedMessage id='admin.dashboard.registration_mode.approval_label' defaultMessage='Approval Required' />}
|
<RadioItem
|
||||||
hint={<FormattedMessage id='admin.dashboard.registration_mode.approval_hint' defaultMessage='Users can sign up, but their account only gets activated when an admin approves it.' />}
|
label={<FormattedMessage id='admin.dashboard.registration_mode.closed_label' defaultMessage='Closed' />}
|
||||||
checked={mode === 'approval'}
|
hint={<FormattedMessage id='admin.dashboard.registration_mode.closed_hint' defaultMessage='Nobody can sign up. You can still invite people.' />}
|
||||||
value='approval'
|
checked={mode === 'closed'}
|
||||||
/>
|
value='closed'
|
||||||
<RadioItem
|
/>
|
||||||
label={<FormattedMessage id='admin.dashboard.registration_mode.closed_label' defaultMessage='Closed' />}
|
</RadioGroup>
|
||||||
hint={<FormattedMessage id='admin.dashboard.registration_mode.closed_hint' defaultMessage='Nobody can sign up. You can still invite people.' />}
|
|
||||||
checked={mode === 'closed'}
|
|
||||||
value='closed'
|
|
||||||
/>
|
|
||||||
</RadioGroup>
|
|
||||||
</FieldsGroup>
|
|
||||||
</SimpleForm>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,15 @@ const Dashboard: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
</DashCounters>
|
</DashCounters>
|
||||||
|
|
||||||
{account.admin && <RegistrationModePicker />}
|
{account.admin && (
|
||||||
|
<>
|
||||||
|
<CardTitle
|
||||||
|
title={<FormattedMessage id='admin.dashboard.registration_mode_label' defaultMessage='Registrations' />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<RegistrationModePicker />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<CardTitle
|
<CardTitle
|
||||||
title={<FormattedMessage id='admin.dashwidgets.software_header' defaultMessage='Software' />}
|
title={<FormattedMessage id='admin.dashwidgets.software_header' defaultMessage='Software' />}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import classNames from 'clsx';
|
import classNames from 'clsx';
|
||||||
import React, { useState, useRef } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { Text, Select } from '../../components/ui';
|
import { Select } from '../../components/ui';
|
||||||
|
|
||||||
interface IInputContainer {
|
interface IInputContainer {
|
||||||
label?: React.ReactNode,
|
label?: React.ReactNode,
|
||||||
|
@ -175,52 +175,6 @@ export const Checkbox: React.FC<ICheckbox> = (props) => (
|
||||||
<SimpleInput type='checkbox' {...props} />
|
<SimpleInput type='checkbox' {...props} />
|
||||||
);
|
);
|
||||||
|
|
||||||
interface IRadioGroup {
|
|
||||||
label?: React.ReactNode,
|
|
||||||
onChange?: React.ChangeEventHandler,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const RadioGroup: React.FC<IRadioGroup> = (props) => {
|
|
||||||
const { label, children, onChange } = props;
|
|
||||||
|
|
||||||
const childrenWithProps = React.Children.map(children, child =>
|
|
||||||
// @ts-ignore
|
|
||||||
React.cloneElement(child, { onChange }),
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='input with_floating_label radio_buttons'>
|
|
||||||
<div className='label_input'>
|
|
||||||
<label>{label}</label>
|
|
||||||
<ul>{childrenWithProps}</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IRadioItem {
|
|
||||||
label?: React.ReactNode,
|
|
||||||
hint?: React.ReactNode,
|
|
||||||
value: string,
|
|
||||||
checked: boolean,
|
|
||||||
onChange?: React.ChangeEventHandler,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const RadioItem: React.FC<IRadioItem> = (props) => {
|
|
||||||
const { current: id } = useRef<string>(uuidv4());
|
|
||||||
const { label, hint, checked = false, ...rest } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li className='radio'>
|
|
||||||
<label htmlFor={id}>
|
|
||||||
<input id={id} type='radio' checked={checked} {...rest} />
|
|
||||||
<Text>{label}</Text>
|
|
||||||
{hint && <span className='hint'>{hint}</span>}
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ISelectDropdown {
|
interface ISelectDropdown {
|
||||||
label?: React.ReactNode,
|
label?: React.ReactNode,
|
||||||
hint?: React.ReactNode,
|
hint?: React.ReactNode,
|
||||||
|
|
Loading…
Reference in a new issue