mirror of
https://github.com/strapi/strapi.git
synced 2025-09-07 15:49:24 +00:00
Remove old files
Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
parent
7e2f8063a8
commit
57ce9de53a
@ -1,41 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Option, Text } from '@buffetjs/core';
|
||||
|
||||
const Filter = ({ displayName, filter, name, onClick, value }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const label = (
|
||||
<>
|
||||
<Text color="mediumBlue" as="span">
|
||||
{displayName}
|
||||
</Text>
|
||||
<Text as="span" color="mediumBlue" fontWeight="bold">
|
||||
{formatMessage({ id: `components.FilterOptions.FILTER_TYPES.${filter}` })}
|
||||
</Text>
|
||||
<Text as="span" color="mediumBlue">
|
||||
{value}
|
||||
</Text>
|
||||
</>
|
||||
);
|
||||
|
||||
const handleClick = () => {
|
||||
onClick({ target: { name, value } });
|
||||
};
|
||||
|
||||
return <Option label={label} margin="0 10px 6px 0" onClick={handleClick} />;
|
||||
};
|
||||
|
||||
Filter.defaultProps = {
|
||||
onClick: () => {},
|
||||
};
|
||||
|
||||
Filter.propTypes = {
|
||||
filter: PropTypes.string.isRequired,
|
||||
displayName: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
onClick: PropTypes.func,
|
||||
value: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default Filter;
|
@ -1,14 +0,0 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FilterIcon } from '@strapi/helper-plugin';
|
||||
|
||||
const Button = () => {
|
||||
return (
|
||||
<>
|
||||
<FilterIcon />
|
||||
<FormattedMessage id="app.utils.filters" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
@ -1,35 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { InputText, Select, Toggle } from '@buffetjs/core';
|
||||
import { formatInputValue } from './utils';
|
||||
|
||||
const getInputType = type => {
|
||||
switch (type) {
|
||||
case 'toggle':
|
||||
return Toggle;
|
||||
case 'booleanSelect':
|
||||
return Select;
|
||||
default:
|
||||
return InputText;
|
||||
}
|
||||
};
|
||||
|
||||
function Input({ onChange, type, ...rest }) {
|
||||
const Component = getInputType(type);
|
||||
const handleChange = ({ target: { name, value } }) => {
|
||||
onChange({ target: { name, value: formatInputValue(type, value) } });
|
||||
};
|
||||
|
||||
return <Component onChange={handleChange} {...rest} autoComplete="off" />;
|
||||
}
|
||||
|
||||
Input.defaultProps = {
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
Input.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
type: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default Input;
|
@ -1,8 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
width: 260px;
|
||||
padding: 13px 15px;
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
@ -1,91 +0,0 @@
|
||||
import React, { useReducer } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Select, Padded } from '@buffetjs/core';
|
||||
import Button from '../../../FullWidthButton';
|
||||
import { form, getInputValue } from './utils';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import init from './init';
|
||||
import Input from './Input';
|
||||
import Wrapper from './Wrapper';
|
||||
|
||||
const Card = ({ onChange }) => {
|
||||
const [
|
||||
{
|
||||
modifiedData: { name, filter, value },
|
||||
},
|
||||
dispatch,
|
||||
] = useReducer(reducer, initialState, init);
|
||||
|
||||
const handleChangeName = ({ target: { value } }) => {
|
||||
dispatch({
|
||||
type: 'ON_CHANGE_NAME',
|
||||
value,
|
||||
});
|
||||
};
|
||||
|
||||
const handleChange = ({ target: { name, value } }) => {
|
||||
dispatch({
|
||||
type: 'ON_CHANGE',
|
||||
keys: name,
|
||||
value,
|
||||
});
|
||||
};
|
||||
|
||||
const renderFiltersOptions = () => {
|
||||
return form[name].allowedFilters.map(filter => (
|
||||
<FormattedMessage id={filter.id} key={filter.id}>
|
||||
{msg => <option value={filter.value}>{msg}</option>}
|
||||
</FormattedMessage>
|
||||
));
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
onChange({ name, filter, value });
|
||||
|
||||
dispatch({
|
||||
type: 'RESET_FORM',
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Padded bottom size="11px">
|
||||
<Select name="name" onChange={handleChangeName} options={Object.keys(form)} value={name} />
|
||||
</Padded>
|
||||
<Padded bottom size="11px">
|
||||
<Select
|
||||
onChange={handleChange}
|
||||
options={renderFiltersOptions()}
|
||||
name="filter"
|
||||
value={filter}
|
||||
/>
|
||||
</Padded>
|
||||
<Padded bottom size="11px">
|
||||
<Input
|
||||
onChange={handleChange}
|
||||
name="value"
|
||||
type={form[name].type}
|
||||
value={getInputValue(form[name].type, value)}
|
||||
options={[
|
||||
{ label: 'true', value: 'true' },
|
||||
{ label: 'false', value: 'false' },
|
||||
]}
|
||||
/>
|
||||
</Padded>
|
||||
<Button icon onClick={handleSubmit} type="button">
|
||||
<FormattedMessage id="app.utils.add-filter" />
|
||||
</Button>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
Card.defaultProps = {
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
Card.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
export default Card;
|
@ -1,5 +0,0 @@
|
||||
const init = initialState => {
|
||||
return initialState;
|
||||
};
|
||||
|
||||
export default init;
|
@ -1,39 +0,0 @@
|
||||
/* eslint-disable consistent-return */
|
||||
import produce from 'immer';
|
||||
import { get, set } from 'lodash';
|
||||
import form from './utils/form';
|
||||
|
||||
const initialState = {
|
||||
modifiedData: {
|
||||
name: 'firstname',
|
||||
filter: '',
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
|
||||
const reducer = (state, action) =>
|
||||
produce(state, draftState => {
|
||||
switch (action.type) {
|
||||
case 'ON_CHANGE': {
|
||||
set(draftState, ['modifiedData', ...action.keys.split('.')], action.value);
|
||||
break;
|
||||
}
|
||||
case 'ON_CHANGE_NAME': {
|
||||
// Change the name
|
||||
set(draftState, ['modifiedData', 'name'], action.value);
|
||||
// Reset the default filter
|
||||
set(draftState, ['modifiedData', 'filter'], '');
|
||||
// Reset the default value
|
||||
const defaultValue = get(form, [action.value, 'defaultValue'], '');
|
||||
set(draftState, ['modifiedData', 'value'], defaultValue);
|
||||
break;
|
||||
}
|
||||
case 'RESET_FORM': {
|
||||
return initialState;
|
||||
}
|
||||
default:
|
||||
return draftState;
|
||||
}
|
||||
});
|
||||
|
||||
export { initialState, reducer };
|
@ -1,11 +0,0 @@
|
||||
import init from '../init';
|
||||
|
||||
describe('ADMIN | COMPONENTS | USERS | FilterPicker | Card | init', () => {
|
||||
it('should return the initialState', () => {
|
||||
const initialState = {
|
||||
test: true,
|
||||
};
|
||||
|
||||
expect(init(initialState)).toEqual(initialState);
|
||||
});
|
||||
});
|
@ -1,92 +0,0 @@
|
||||
import { reducer } from '../reducer';
|
||||
|
||||
describe('ADMIN | COMPONENTS | USERS | FilterPicker | Card | reducer', () => {
|
||||
describe('DEFAULT_ACTION', () => {
|
||||
it('should return the initialState', () => {
|
||||
const initialState = {
|
||||
test: true,
|
||||
};
|
||||
|
||||
expect(reducer(initialState, {})).toEqual(initialState);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ON_CHANGE', () => {
|
||||
it('should change the data correctly', () => {
|
||||
const initialState = {
|
||||
modifiedData: {
|
||||
name: 'firstname',
|
||||
filter: '',
|
||||
value: '',
|
||||
},
|
||||
test: true,
|
||||
};
|
||||
const action = {
|
||||
type: 'ON_CHANGE',
|
||||
keys: 'filter',
|
||||
value: '_ne',
|
||||
};
|
||||
const expected = {
|
||||
modifiedData: {
|
||||
name: 'firstname',
|
||||
filter: '_ne',
|
||||
value: '',
|
||||
},
|
||||
test: true,
|
||||
};
|
||||
|
||||
expect(reducer(initialState, action)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ON_CHANGE_NAME', () => {
|
||||
it('should change the data correctly', () => {
|
||||
const initialState = {
|
||||
modifiedData: {
|
||||
name: 'firstname',
|
||||
filter: '_ne',
|
||||
value: 'test',
|
||||
},
|
||||
test: true,
|
||||
};
|
||||
const action = {
|
||||
type: 'ON_CHANGE_NAME',
|
||||
keys: 'name',
|
||||
value: 'isActive',
|
||||
};
|
||||
const expected = {
|
||||
modifiedData: {
|
||||
name: 'isActive',
|
||||
filter: '',
|
||||
value: true,
|
||||
},
|
||||
test: true,
|
||||
};
|
||||
|
||||
expect(reducer(initialState, action)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('RESET_FORM', () => {
|
||||
it('should reset the form correctly', () => {
|
||||
const action = {
|
||||
type: 'RESET_FORM',
|
||||
};
|
||||
const initialState = {
|
||||
test: true,
|
||||
modifiedData: {
|
||||
ok: true,
|
||||
},
|
||||
};
|
||||
const expected = {
|
||||
modifiedData: {
|
||||
name: 'firstname',
|
||||
filter: '',
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
|
||||
expect(reducer(initialState, action)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,57 +0,0 @@
|
||||
const textFilters = [
|
||||
{
|
||||
id: 'components.FilterOptions.FILTER_TYPES.=',
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
id: 'components.FilterOptions.FILTER_TYPES._ne',
|
||||
value: '_ne',
|
||||
},
|
||||
{
|
||||
id: 'components.FilterOptions.FILTER_TYPES._contains',
|
||||
value: '_contains',
|
||||
},
|
||||
{
|
||||
id: 'components.FilterOptions.FILTER_TYPES._containss',
|
||||
value: '_containss',
|
||||
},
|
||||
];
|
||||
|
||||
const form = {
|
||||
firstname: {
|
||||
type: 'text',
|
||||
defaultValue: '',
|
||||
allowedFilters: textFilters,
|
||||
},
|
||||
lastname: {
|
||||
type: 'text',
|
||||
defaultValue: '',
|
||||
allowedFilters: textFilters,
|
||||
},
|
||||
email: {
|
||||
type: 'email',
|
||||
defaultValue: '',
|
||||
allowedFilters: textFilters,
|
||||
},
|
||||
username: {
|
||||
type: 'text',
|
||||
defaultValue: '',
|
||||
allowedFilters: textFilters,
|
||||
},
|
||||
isActive: {
|
||||
type: 'booleanSelect',
|
||||
defaultValue: true,
|
||||
allowedFilters: [
|
||||
{
|
||||
id: 'components.FilterOptions.FILTER_TYPES.=',
|
||||
value: '=',
|
||||
},
|
||||
{
|
||||
id: 'components.FilterOptions.FILTER_TYPES._ne',
|
||||
value: '_ne',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default form;
|
@ -1,9 +0,0 @@
|
||||
const getInputValue = (type, value) => {
|
||||
if (type === 'booleanSelect') {
|
||||
return value === 'true';
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
export default getInputValue;
|
@ -1,9 +0,0 @@
|
||||
const getInputValue = (type, value) => {
|
||||
if (type === 'booleanSelect') {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
export default getInputValue;
|
@ -1,3 +0,0 @@
|
||||
export { default as form } from './form';
|
||||
export { default as formatInputValue } from './formatInputValue';
|
||||
export { default as getInputValue } from './getInputValue';
|
@ -1,35 +0,0 @@
|
||||
import formatInputValue from '../formatInputValue';
|
||||
import getInputValue from '../getInputValue';
|
||||
|
||||
describe('ADMIN | COMPONENTS | USER | FilterPicker | Card | utils', () => {
|
||||
describe('formatInputValue', () => {
|
||||
it('should return a boolean if the type is booleanSelect', () => {
|
||||
const type = 'booleanSelect';
|
||||
|
||||
expect(formatInputValue(type, 'true')).toBeTruthy();
|
||||
expect(formatInputValue(type, 'false')).toBeFalsy();
|
||||
expect(formatInputValue(type, 'test')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return the value if the type is not booleanSelect', () => {
|
||||
const type = 'test';
|
||||
|
||||
expect(formatInputValue(type, 'true')).toEqual('true');
|
||||
expect(formatInputValue(type, 'false')).toEqual('false');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getInputValue', () => {
|
||||
it('should return a string if the type is booleanSelect', () => {
|
||||
const type = 'booleanSelect';
|
||||
|
||||
expect(getInputValue(type, true)).toEqual('true');
|
||||
});
|
||||
|
||||
it('should return the value if the type is not booleanSelect', () => {
|
||||
const type = 'test';
|
||||
|
||||
expect(getInputValue(type, true)).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,35 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Picker } from '@buffetjs/core';
|
||||
|
||||
import Button from './Button';
|
||||
import Card from './Card';
|
||||
|
||||
const FilterPicker = ({ onChange }) => {
|
||||
return (
|
||||
<Picker
|
||||
renderButtonContent={Button}
|
||||
renderSectionContent={onToggle => (
|
||||
<Card
|
||||
onChange={({ value, ...rest }) => {
|
||||
if (value !== '') {
|
||||
onChange({ ...rest, value });
|
||||
}
|
||||
|
||||
onToggle();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
FilterPicker.defaultProps = {
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
FilterPicker.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
export default FilterPicker;
|
@ -1,7 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
padding: 12px 10px;
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
@ -1,40 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { PageFooter } from '@strapi/helper-plugin';
|
||||
import { Padded } from '@buffetjs/core';
|
||||
import Wrapper from './Wrapper';
|
||||
|
||||
const Footer = ({ count, onChange, params }) => {
|
||||
return (
|
||||
<Wrapper>
|
||||
<Padded left right size="xs">
|
||||
<PageFooter
|
||||
context={{ trackUsage: () => {} }}
|
||||
count={count}
|
||||
onChangeParams={onChange}
|
||||
params={params}
|
||||
/>
|
||||
</Padded>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
Footer.defaultProps = {
|
||||
count: 0,
|
||||
onChange: () => {},
|
||||
params: {
|
||||
_limit: 10,
|
||||
_page: 1,
|
||||
},
|
||||
};
|
||||
|
||||
Footer.propTypes = {
|
||||
count: PropTypes.number,
|
||||
onChange: PropTypes.func,
|
||||
params: PropTypes.shape({
|
||||
_limit: PropTypes.number,
|
||||
_page: PropTypes.number,
|
||||
}),
|
||||
};
|
||||
|
||||
export default Footer;
|
@ -1,20 +0,0 @@
|
||||
/* eslint-disable jsx-a11y/accessible-emoji */
|
||||
import React from 'react';
|
||||
|
||||
const Envelope = () => (
|
||||
<svg width="24" height="17" xmlns="http://www.w3.org/2000/svg">
|
||||
<text
|
||||
transform="translate(-23 -9)"
|
||||
fill="#4B515A"
|
||||
fillRule="evenodd"
|
||||
fontSize="24"
|
||||
fontFamily="AppleColorEmoji, Apple Color Emoji"
|
||||
>
|
||||
<tspan x="23" y="28">
|
||||
✉️
|
||||
</tspan>
|
||||
</text>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default Envelope;
|
@ -1,15 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
import { Flex } from '@buffetjs/core';
|
||||
|
||||
const IconWrapper = styled(Flex)`
|
||||
height: 100%;
|
||||
margin-right: 18px;
|
||||
transform: rotate(-20deg);
|
||||
`;
|
||||
|
||||
IconWrapper.defaultProps = {
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
};
|
||||
|
||||
export default IconWrapper;
|
@ -1,26 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
height: 68px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
&:before {
|
||||
content: '';
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
margin-right: 16px;
|
||||
background-color: #6dbb1a;
|
||||
border-top-left-radius: ${({ theme }) => theme.main.sizes.borderRadius};
|
||||
border-bottom-left-radius: ${({ theme }) => theme.main.sizes.borderRadius};
|
||||
}
|
||||
border-radius: ${({ theme }) => theme.main.sizes.borderRadius};
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.icon-duplicate {
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
@ -1,50 +0,0 @@
|
||||
// This component is a work in progress
|
||||
// It's made to be used when the users API is ready
|
||||
import React from 'react';
|
||||
import { useNotification } from '@strapi/helper-plugin';
|
||||
import { Flex, Text } from '@buffetjs/core';
|
||||
import { Duplicate } from '@buffetjs/icons';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||
import IconWrapper from './IconWrapper';
|
||||
import Envelope from './Envelope';
|
||||
import Wrapper from './Wrapper';
|
||||
|
||||
const LinkNotification = ({ target, children }) => {
|
||||
const toggleNotification = useNotification();
|
||||
|
||||
const handleCopy = () => {
|
||||
toggleNotification({ type: 'info', message: { id: 'notification.link-copied' } });
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<IconWrapper>
|
||||
<Envelope />
|
||||
</IconWrapper>
|
||||
<Flex flexDirection="column" justifyContent="center">
|
||||
<Text fontWeight="semiBold" color="black" fontSize="md" lineHeight="18px">
|
||||
{target}
|
||||
<CopyToClipboard onCopy={handleCopy} text={target}>
|
||||
<Duplicate fill="#8B91A0" className="icon-duplicate" />
|
||||
</CopyToClipboard>
|
||||
</Text>
|
||||
<Text fontWeight="regular" color="grey" fontSize="sm" lineHeight="18px">
|
||||
{children}
|
||||
</Text>
|
||||
</Flex>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
LinkNotification.defaultProps = {
|
||||
target: '',
|
||||
children: '',
|
||||
};
|
||||
|
||||
LinkNotification.propTypes = {
|
||||
target: PropTypes.string,
|
||||
children: PropTypes.string,
|
||||
};
|
||||
|
||||
export default LinkNotification;
|
@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from 'react-intl';
|
||||
import LinkNotification from '../LinkNotification';
|
||||
import basename from '../../../core/utils/basename';
|
||||
|
||||
const MagicLink = ({ registrationToken }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const link = `${window.location.origin}${basename}auth/register?registrationToken=${registrationToken}`;
|
||||
|
||||
return (
|
||||
<LinkNotification target={link}>
|
||||
{formatMessage({ id: 'app.components.Users.MagicLink.connect' })}
|
||||
</LinkNotification>
|
||||
);
|
||||
};
|
||||
|
||||
MagicLink.defaultProps = {
|
||||
registrationToken: '',
|
||||
};
|
||||
|
||||
MagicLink.propTypes = {
|
||||
registrationToken: PropTypes.string,
|
||||
};
|
||||
|
||||
export default MagicLink;
|
@ -1,12 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
import { Container } from 'reactstrap';
|
||||
|
||||
const Wrapper = styled(Container)`
|
||||
padding: 0;
|
||||
`;
|
||||
|
||||
Wrapper.defaultProps = {
|
||||
fluid: true,
|
||||
};
|
||||
|
||||
export default Wrapper;
|
@ -1,162 +0,0 @@
|
||||
import React, { forwardRef, useReducer, useImperativeHandle, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
BaselineAlignment,
|
||||
ModalSection,
|
||||
request,
|
||||
useNotification,
|
||||
useOverlayBlocker,
|
||||
} from '@strapi/helper-plugin';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { get } from 'lodash';
|
||||
import { Padded, Text } from '@buffetjs/core';
|
||||
import { Row } from 'reactstrap';
|
||||
import MagicLink from 'ee_else_ce/components/Users/MagicLink';
|
||||
|
||||
import checkFormValidity from '../../../utils/checkFormValidity';
|
||||
import form from './utils/form';
|
||||
import schema from './utils/schema';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import init from './init';
|
||||
import Input from '../../SizedInput';
|
||||
import Wrapper from './Wrapper';
|
||||
import RoleSettingsModalSection from '../RoleSettingsModalSection';
|
||||
|
||||
// This component accepts a ref so we can have access to the submit handler.
|
||||
const ModalCreateBody = forwardRef(
|
||||
({ isDisabled, onSubmit, registrationToken, setIsSubmiting, showMagicLink }, ref) => {
|
||||
const { lockApp, unlockApp } = useOverlayBlocker();
|
||||
|
||||
const toggleNotification = useNotification();
|
||||
const [reducerState, dispatch] = useReducer(reducer, initialState, init);
|
||||
const { formErrors, modifiedData } = reducerState;
|
||||
const buttonSubmitRef = useRef(null);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
submit: () => {
|
||||
buttonSubmitRef.current.click();
|
||||
},
|
||||
}));
|
||||
|
||||
const handleChange = ({ target: { name, value } }) => {
|
||||
dispatch({
|
||||
type: 'ON_CHANGE',
|
||||
keys: name,
|
||||
value,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSubmit = async e => {
|
||||
e.persist();
|
||||
e.preventDefault();
|
||||
const errors = await checkFormValidity(modifiedData, schema);
|
||||
|
||||
if (!errors) {
|
||||
try {
|
||||
// Prevent user interactions until the request is completed
|
||||
lockApp();
|
||||
|
||||
setIsSubmiting(true);
|
||||
|
||||
const requestURL = '/admin/users';
|
||||
const cleanedRoles = modifiedData.roles.map(role => role.id);
|
||||
|
||||
const { data } = await request(requestURL, {
|
||||
method: 'POST',
|
||||
body: { ...modifiedData, roles: cleanedRoles },
|
||||
});
|
||||
|
||||
onSubmit(e, data);
|
||||
} catch (err) {
|
||||
const message = get(err, ['response', 'payload', 'message'], 'An error occured');
|
||||
|
||||
toggleNotification({ type: 'warning', message });
|
||||
} finally {
|
||||
unlockApp();
|
||||
setIsSubmiting(false);
|
||||
}
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: 'SET_ERRORS',
|
||||
errors: errors || {},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
{showMagicLink && (
|
||||
<>
|
||||
<BaselineAlignment top size="18px" />
|
||||
<ModalSection>
|
||||
<MagicLink registrationToken={registrationToken} />
|
||||
</ModalSection>
|
||||
</>
|
||||
)}
|
||||
<ModalSection>
|
||||
<Padded top size="18px">
|
||||
<Text fontSize="xs" color="grey" fontWeight="bold" textTransform="uppercase">
|
||||
{formatMessage({ id: 'app.components.Users.ModalCreateBody.block-title.details' })}
|
||||
</Text>
|
||||
</Padded>
|
||||
</ModalSection>
|
||||
<ModalSection>
|
||||
<Wrapper>
|
||||
<Padded top size="smd">
|
||||
<Row>
|
||||
{Object.keys(form).map((inputName, i) => (
|
||||
<Input
|
||||
key={inputName}
|
||||
{...form[inputName]}
|
||||
autoFocus={i === 0}
|
||||
disabled={isDisabled}
|
||||
error={formErrors[inputName]}
|
||||
name={inputName}
|
||||
onChange={handleChange}
|
||||
value={modifiedData[inputName]}
|
||||
/>
|
||||
))}
|
||||
</Row>
|
||||
</Padded>
|
||||
</Wrapper>
|
||||
</ModalSection>
|
||||
<ModalSection>
|
||||
<Padded top size="3px">
|
||||
<Text fontSize="xs" color="grey" fontWeight="bold" textTransform="uppercase">
|
||||
{formatMessage({ id: 'app.components.Users.ModalCreateBody.block-title.login' })}
|
||||
</Text>
|
||||
</Padded>
|
||||
</ModalSection>
|
||||
<RoleSettingsModalSection
|
||||
hasSSORegistration={modifiedData.useSSORegistration}
|
||||
modifiedData={modifiedData}
|
||||
onChange={handleChange}
|
||||
formErrors={formErrors}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
<button type="submit" style={{ display: 'none' }} ref={buttonSubmitRef}>
|
||||
hidden button to use the native form event
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
ModalCreateBody.defaultProps = {
|
||||
isDisabled: false,
|
||||
onSubmit: e => e.preventDefault(),
|
||||
registrationToken: '',
|
||||
setIsSubmiting: () => {},
|
||||
showMagicLink: false,
|
||||
};
|
||||
|
||||
ModalCreateBody.propTypes = {
|
||||
isDisabled: PropTypes.bool,
|
||||
onSubmit: PropTypes.func,
|
||||
registrationToken: PropTypes.string,
|
||||
setIsSubmiting: PropTypes.func,
|
||||
showMagicLink: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default ModalCreateBody;
|
@ -1,5 +0,0 @@
|
||||
const init = initialState => {
|
||||
return initialState;
|
||||
};
|
||||
|
||||
export default init;
|
@ -1,27 +0,0 @@
|
||||
/* eslint-disable consistent-return */
|
||||
import produce from 'immer';
|
||||
import { set } from 'lodash';
|
||||
import formDataModel from 'ee_else_ce/components/Users/ModalCreateBody/utils/formDataModel';
|
||||
|
||||
const initialState = {
|
||||
formErrors: {},
|
||||
modifiedData: formDataModel,
|
||||
};
|
||||
|
||||
const reducer = (state, action) =>
|
||||
produce(state, draftState => {
|
||||
switch (action.type) {
|
||||
case 'ON_CHANGE': {
|
||||
set(draftState.modifiedData, action.keys.split('.'), action.value);
|
||||
break;
|
||||
}
|
||||
case 'SET_ERRORS': {
|
||||
draftState.formErrors = action.errors;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return draftState;
|
||||
}
|
||||
});
|
||||
|
||||
export { initialState, reducer };
|
@ -1,11 +0,0 @@
|
||||
import init from '../init';
|
||||
|
||||
describe('ADMIN | COMPONENTS | USERS | MODALCREATEBODY | init', () => {
|
||||
it('should return the initialState', () => {
|
||||
const initialState = {
|
||||
test: true,
|
||||
};
|
||||
|
||||
expect(init(initialState)).toEqual(initialState);
|
||||
});
|
||||
});
|
@ -1,74 +0,0 @@
|
||||
import { reducer } from '../reducer';
|
||||
|
||||
describe('ADMIN | COMPONENTS | USERS | MODALCREATEBODY | reducer', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
});
|
||||
|
||||
describe('DEFAULT_ACTION', () => {
|
||||
it('should return the initialState', () => {
|
||||
const initialState = {
|
||||
test: true,
|
||||
};
|
||||
|
||||
expect(reducer(initialState, {})).toEqual(initialState);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ON_CHANGE', () => {
|
||||
it('should change the data correctly', () => {
|
||||
const initialState = {
|
||||
modifiedData: {
|
||||
firstname: 'kai',
|
||||
lastname: '',
|
||||
email: 'kai@strapi.io',
|
||||
roles: [1],
|
||||
},
|
||||
test: true,
|
||||
};
|
||||
const action = {
|
||||
type: 'ON_CHANGE',
|
||||
keys: 'lastname',
|
||||
value: 'doe',
|
||||
};
|
||||
const expected = {
|
||||
modifiedData: {
|
||||
firstname: 'kai',
|
||||
lastname: 'doe',
|
||||
email: 'kai@strapi.io',
|
||||
roles: [1],
|
||||
},
|
||||
test: true,
|
||||
};
|
||||
|
||||
expect(reducer(initialState, action)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SET_ERRORS', () => {
|
||||
it('Should set the formErrors object correctly', () => {
|
||||
const action = {
|
||||
type: 'SET_ERRORS',
|
||||
errors: {
|
||||
test: 'this is required',
|
||||
},
|
||||
};
|
||||
const initialState = {
|
||||
formErrors: {},
|
||||
modifiedData: {
|
||||
ok: true,
|
||||
},
|
||||
};
|
||||
const expected = {
|
||||
formErrors: {
|
||||
test: 'this is required',
|
||||
},
|
||||
modifiedData: {
|
||||
ok: true,
|
||||
},
|
||||
};
|
||||
|
||||
expect(reducer(initialState, action)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,29 +0,0 @@
|
||||
const form = {
|
||||
firstname: {
|
||||
autoFocus: true,
|
||||
label: 'Settings.permissions.users.form.firstname',
|
||||
placeholder: 'e.g. Kai',
|
||||
type: 'text',
|
||||
validations: {
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
lastname: {
|
||||
label: 'Settings.permissions.users.form.lastname',
|
||||
placeholder: 'e.g. Doe',
|
||||
type: 'text',
|
||||
validations: {
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
email: {
|
||||
label: 'Settings.permissions.users.form.email',
|
||||
placeholder: 'e.g. kai.doe@strapi.io',
|
||||
type: 'email',
|
||||
validations: {
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default form;
|
@ -1,8 +0,0 @@
|
||||
const formDataModel = {
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
email: '',
|
||||
roles: [],
|
||||
};
|
||||
|
||||
export default formDataModel;
|
@ -1,10 +0,0 @@
|
||||
import RolesSelectComponent from '../../RoleSettingsModalSection/RolesSelectComponent';
|
||||
|
||||
const roleSettingsForm = {
|
||||
roles: {
|
||||
label: 'Settings.permissions.users.form.firstname',
|
||||
Component: RolesSelectComponent,
|
||||
},
|
||||
};
|
||||
|
||||
export default roleSettingsForm;
|
@ -1,17 +0,0 @@
|
||||
import * as yup from 'yup';
|
||||
import { translatedErrors } from '@strapi/helper-plugin';
|
||||
|
||||
const schema = yup.object().shape({
|
||||
firstname: yup.string().required(translatedErrors.required),
|
||||
lastname: yup.string().required(translatedErrors.required),
|
||||
email: yup
|
||||
.string()
|
||||
.email(translatedErrors.email)
|
||||
.required(translatedErrors.required),
|
||||
roles: yup
|
||||
.array()
|
||||
.min(1, translatedErrors.min)
|
||||
.required(translatedErrors.required),
|
||||
});
|
||||
|
||||
export default schema;
|
@ -1,53 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Padded } from '@buffetjs/core';
|
||||
import { Label, Description as BaseDescription } from '@buffetjs/styles';
|
||||
import { Col } from 'reactstrap';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import SelectRoles from '../SelectRoles';
|
||||
|
||||
const Description = styled(BaseDescription)`
|
||||
font-size: ${({ theme }) => theme.main.sizes.fonts.md};
|
||||
line-height: normal;
|
||||
`;
|
||||
|
||||
const RolesSelectComponent = ({ isDisabled, value, error, onChange }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return (
|
||||
<Col xs="6">
|
||||
<Padded bottom size="xs">
|
||||
<Label style={{ display: 'block' }} htmlFor="roles">
|
||||
{formatMessage({ id: 'app.components.Users.ModalCreateBody.block-title.roles' })}
|
||||
</Label>
|
||||
</Padded>
|
||||
<SelectRoles
|
||||
isDisabled={isDisabled}
|
||||
name="roles"
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
error={error}
|
||||
/>
|
||||
<Description>
|
||||
{formatMessage({
|
||||
id: 'app.components.Users.ModalCreateBody.block-title.roles.description',
|
||||
})}
|
||||
</Description>
|
||||
</Col>
|
||||
);
|
||||
};
|
||||
|
||||
RolesSelectComponent.defaultProps = {
|
||||
value: null,
|
||||
error: null,
|
||||
};
|
||||
RolesSelectComponent.propTypes = {
|
||||
isDisabled: PropTypes.bool.isRequired,
|
||||
value: PropTypes.array,
|
||||
error: PropTypes.object,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default RolesSelectComponent;
|
@ -1,76 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ModalSection } from '@strapi/helper-plugin';
|
||||
import { Padded } from '@buffetjs/core';
|
||||
import { Row } from 'reactstrap';
|
||||
import { useIntl } from 'react-intl';
|
||||
import roleSettingsForm from 'ee_else_ce/components/Users/ModalCreateBody/utils/roleSettingsForm';
|
||||
|
||||
import Input from '../../SizedInput';
|
||||
import Wrapper from '../ModalCreateBody/Wrapper';
|
||||
|
||||
const RoleSettingsModalSection = ({ isDisabled, modifiedData, onChange, formErrors }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return (
|
||||
<ModalSection>
|
||||
<Wrapper>
|
||||
<Padded top size="smd">
|
||||
<Row>
|
||||
{Object.keys(roleSettingsForm).map(inputName => {
|
||||
const value = modifiedData[inputName];
|
||||
const { description, type, Component } = roleSettingsForm[inputName];
|
||||
const error = formErrors[inputName];
|
||||
|
||||
if (Component) {
|
||||
return (
|
||||
<Component
|
||||
key={inputName}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
error={error}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Input
|
||||
{...roleSettingsForm[inputName]}
|
||||
key={inputName}
|
||||
description={formatMessage({ id: description })}
|
||||
type={type}
|
||||
disabled={isDisabled}
|
||||
name={inputName}
|
||||
onChange={onChange}
|
||||
value={modifiedData.useSSORegistration}
|
||||
error={formErrors.useSSORegistration}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
</Padded>
|
||||
</Wrapper>
|
||||
</ModalSection>
|
||||
);
|
||||
};
|
||||
|
||||
RoleSettingsModalSection.defaultProps = {
|
||||
isDisabled: false,
|
||||
formErrors: {},
|
||||
};
|
||||
|
||||
RoleSettingsModalSection.propTypes = {
|
||||
isDisabled: PropTypes.bool,
|
||||
modifiedData: PropTypes.shape({
|
||||
roles: PropTypes.array,
|
||||
useSSORegistration: PropTypes.bool,
|
||||
}).isRequired,
|
||||
formErrors: PropTypes.shape({
|
||||
roles: PropTypes.object,
|
||||
useSSORegistration: PropTypes.bool,
|
||||
}),
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default RoleSettingsModalSection;
|
@ -1,15 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Remove } from '@buffetjs/icons';
|
||||
import { components } from 'react-select';
|
||||
|
||||
const ClearIndicator = props => {
|
||||
const Component = components.ClearIndicator;
|
||||
|
||||
return (
|
||||
<Component {...props}>
|
||||
<Remove width="11px" height="11px" fill="#9EA7B8" />
|
||||
</Component>
|
||||
);
|
||||
};
|
||||
|
||||
export default ClearIndicator;
|
@ -1,39 +0,0 @@
|
||||
import React from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Flex } from '@buffetjs/core';
|
||||
import styled from 'styled-components';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Wrapper = styled(Flex)`
|
||||
height: 100%;
|
||||
width: 32px;
|
||||
background: #fafafb;
|
||||
> svg {
|
||||
align-self: center;
|
||||
font-size: 11px;
|
||||
color: #b3b5b9;
|
||||
}
|
||||
`;
|
||||
|
||||
const DropdownIndicator = ({ selectProps: { menuIsOpen } }) => {
|
||||
const icon = menuIsOpen ? 'caret-up' : 'caret-down';
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<FontAwesomeIcon icon={icon} />
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
DropdownIndicator.propTypes = {
|
||||
selectProps: PropTypes.shape({
|
||||
menuIsOpen: PropTypes.bool.isRequired,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
Wrapper.defaultProps = {
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
};
|
||||
|
||||
export default DropdownIndicator;
|
@ -1,10 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
import { ErrorMessage as Base } from '@buffetjs/styles';
|
||||
|
||||
const ErrorMessage = styled(Base)`
|
||||
padding-top: 11px;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 17px;
|
||||
`;
|
||||
|
||||
export default ErrorMessage;
|
@ -1,3 +0,0 @@
|
||||
const IndicatorSeparator = () => null;
|
||||
|
||||
export default IndicatorSeparator;
|
@ -1,43 +0,0 @@
|
||||
import React from 'react';
|
||||
import { components } from 'react-select';
|
||||
import PropTypes from 'prop-types';
|
||||
import StyledOption from './StyledOption';
|
||||
|
||||
const MultiValueContainer = ({ data, selectProps }) => {
|
||||
const Component = components.MultiValueContainer;
|
||||
|
||||
const handleClick = () => {
|
||||
const newValue = selectProps.value.filter(option => option.id !== data.id);
|
||||
|
||||
selectProps.onChange(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<Component {...data} {...selectProps}>
|
||||
<StyledOption
|
||||
label={data.name}
|
||||
height="24px"
|
||||
lineHeight="26px"
|
||||
margin="2px 5px 0px 0"
|
||||
onClick={handleClick}
|
||||
/>
|
||||
</Component>
|
||||
);
|
||||
};
|
||||
|
||||
MultiValueContainer.defaultProps = {
|
||||
data: {},
|
||||
selectProps: {
|
||||
value: [],
|
||||
},
|
||||
};
|
||||
|
||||
MultiValueContainer.propTypes = {
|
||||
data: PropTypes.object,
|
||||
selectProps: PropTypes.shape({
|
||||
onChange: PropTypes.func.isRequired,
|
||||
value: PropTypes.array,
|
||||
}),
|
||||
};
|
||||
|
||||
export default MultiValueContainer;
|
@ -1,11 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
import { Option } from '@buffetjs/core';
|
||||
|
||||
const StyledOption = styled(Option)`
|
||||
> span {
|
||||
display: block !important;
|
||||
color: #007eff !important;
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledOption;
|
@ -1,68 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Select from 'react-select';
|
||||
import { Padded } from '@buffetjs/core';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useRolesList } from '../../../hooks';
|
||||
import styles from './utils/styles';
|
||||
import ClearIndicator from './ClearIndicator';
|
||||
import DropdownIndicator from './DropdownIndicator';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import IndicatorSeparator from './IndicatorSeparator';
|
||||
import MultiValueContainer from './MultiValueContainer';
|
||||
|
||||
const SelectRoles = ({ error, isDisabled, name, onChange, value }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const translatedError = error && error.id ? formatMessage(error) : null;
|
||||
const { roles: data, isLoading } = useRolesList();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Select
|
||||
name={name}
|
||||
components={{
|
||||
ClearIndicator,
|
||||
DropdownIndicator,
|
||||
IndicatorSeparator,
|
||||
MultiValueContainer,
|
||||
}}
|
||||
error={error}
|
||||
getOptionLabel={option => option.name}
|
||||
getOptionValue={option => option.id}
|
||||
onChange={data => {
|
||||
onChange({ target: { name, value: data } });
|
||||
}}
|
||||
isClearable
|
||||
isDisabled={isDisabled}
|
||||
isLoading={isLoading}
|
||||
isMulti
|
||||
options={isLoading ? [] : data}
|
||||
styles={styles}
|
||||
value={value}
|
||||
/>
|
||||
{error && value.length === 0 ? (
|
||||
<ErrorMessage>{translatedError}</ErrorMessage>
|
||||
) : (
|
||||
<Padded top size="11px" />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
SelectRoles.defaultProps = {
|
||||
error: null,
|
||||
isDisabled: false,
|
||||
value: [],
|
||||
};
|
||||
|
||||
SelectRoles.propTypes = {
|
||||
error: PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
}),
|
||||
isDisabled: PropTypes.bool,
|
||||
name: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
value: PropTypes.array,
|
||||
};
|
||||
|
||||
export default SelectRoles;
|
@ -1,99 +0,0 @@
|
||||
/* eslint-disable indent */
|
||||
/* eslint-disable no-nested-ternary */
|
||||
|
||||
const styles = {
|
||||
control: (base, state) => {
|
||||
const borderRadiusStyle = state.selectProps.menuIsOpen
|
||||
? {
|
||||
borderBottomLeftRadius: '0 !important',
|
||||
borderBottomRightRadius: '0 !important',
|
||||
}
|
||||
: {};
|
||||
|
||||
const {
|
||||
selectProps: { error, value },
|
||||
} = state;
|
||||
|
||||
let border;
|
||||
let borderBottom;
|
||||
let backgroundColor;
|
||||
|
||||
if (state.isFocused) {
|
||||
border = '1px solid #78caff !important';
|
||||
} else if (error && !value.length) {
|
||||
border = '1px solid #f64d0a !important';
|
||||
} else {
|
||||
border = '1px solid #e3e9f3 !important';
|
||||
}
|
||||
|
||||
if (state.menuIsOpen === true) {
|
||||
borderBottom = '1px solid #e3e9f3 !important';
|
||||
}
|
||||
|
||||
if (state.isDisabled) {
|
||||
backgroundColor = '#fafafb !important';
|
||||
}
|
||||
|
||||
return {
|
||||
...base,
|
||||
fontSize: 13,
|
||||
minHeight: 34,
|
||||
border,
|
||||
outline: 0,
|
||||
boxShadow: 0,
|
||||
borderRadius: '2px !important',
|
||||
...borderRadiusStyle,
|
||||
borderBottom,
|
||||
backgroundColor,
|
||||
};
|
||||
},
|
||||
menu: base => {
|
||||
return {
|
||||
...base,
|
||||
width: 'calc(100% - 0px)',
|
||||
margin: '0',
|
||||
paddingTop: 0,
|
||||
borderRadius: '2px !important',
|
||||
borderTopLeftRadius: '0 !important',
|
||||
borderTopRightRadius: '0 !important',
|
||||
border: '1px solid #78caff !important',
|
||||
boxShadow: 0,
|
||||
borderTop: '0 !important',
|
||||
fontSize: '13px',
|
||||
};
|
||||
},
|
||||
menuList: base => ({
|
||||
...base,
|
||||
maxHeight: '112px',
|
||||
paddingTop: 2,
|
||||
}),
|
||||
option: (base, state) => {
|
||||
return {
|
||||
...base,
|
||||
height: 36,
|
||||
|
||||
backgroundColor: state.isFocused ? '#f6f6f6' : '#fff',
|
||||
':active': {
|
||||
...base[':active'],
|
||||
backgroundColor: '#f6f6f6',
|
||||
},
|
||||
WebkitFontSmoothing: 'antialiased',
|
||||
color: '#333740',
|
||||
fontWeight: state.isFocused ? '600' : '400',
|
||||
cursor: 'pointer',
|
||||
};
|
||||
},
|
||||
placeholder: base => ({
|
||||
...base,
|
||||
marginTop: 0,
|
||||
marginLeft: 8,
|
||||
color: '#aaa',
|
||||
}),
|
||||
valueContainer: base => ({
|
||||
...base,
|
||||
padding: '2px 4px 4px 4px',
|
||||
lineHeight: '18px',
|
||||
}),
|
||||
};
|
||||
|
||||
export default styles;
|
@ -1,300 +0,0 @@
|
||||
import styles from '../styles';
|
||||
|
||||
describe('ADMIN | COMPONENTS | USER | SelectRoles | utils | styles', () => {
|
||||
describe('control', () => {
|
||||
describe('menuIsOpen is equal to true', () => {
|
||||
it('should return the correct border-radius', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
};
|
||||
const state = {
|
||||
isFocused: false,
|
||||
selectProps: {
|
||||
menuIsOpen: true,
|
||||
error: null,
|
||||
value: [],
|
||||
},
|
||||
};
|
||||
|
||||
const expected = {
|
||||
ok: true,
|
||||
fontSize: 13,
|
||||
minHeight: 34,
|
||||
outline: 0,
|
||||
boxShadow: 0,
|
||||
border: '1px solid #e3e9f3 !important',
|
||||
borderRadius: '2px !important',
|
||||
borderBottomLeftRadius: '0 !important',
|
||||
borderBottomRightRadius: '0 !important',
|
||||
};
|
||||
|
||||
expect(styles.control(base, state)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return the correct border when the component is focused', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
};
|
||||
const state = {
|
||||
isFocused: true,
|
||||
selectProps: {
|
||||
menuIsOpen: true,
|
||||
error: null,
|
||||
value: [],
|
||||
},
|
||||
};
|
||||
|
||||
const expected = {
|
||||
ok: true,
|
||||
fontSize: 13,
|
||||
minHeight: 34,
|
||||
outline: 0,
|
||||
boxShadow: 0,
|
||||
border: '1px solid #78caff !important',
|
||||
borderRadius: '2px !important',
|
||||
borderBottomLeftRadius: '0 !important',
|
||||
borderBottomRightRadius: '0 !important',
|
||||
};
|
||||
|
||||
expect(styles.control(base, state)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return the correct border when the component is focused and has a value', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
};
|
||||
const state = {
|
||||
isFocused: true,
|
||||
selectProps: {
|
||||
menuIsOpen: true,
|
||||
error: null,
|
||||
value: ['test'],
|
||||
},
|
||||
};
|
||||
|
||||
const expected = {
|
||||
ok: true,
|
||||
fontSize: 13,
|
||||
minHeight: 34,
|
||||
outline: 0,
|
||||
boxShadow: 0,
|
||||
border: '1px solid #78caff !important',
|
||||
borderRadius: '2px !important',
|
||||
borderBottomLeftRadius: '0 !important',
|
||||
borderBottomRightRadius: '0 !important',
|
||||
};
|
||||
|
||||
expect(styles.control(base, state)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return the correct border when the component is focused, has a value and has an error', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
};
|
||||
const state = {
|
||||
isFocused: true,
|
||||
selectProps: {
|
||||
menuIsOpen: true,
|
||||
error: true,
|
||||
value: ['test'],
|
||||
},
|
||||
};
|
||||
|
||||
const expected = {
|
||||
ok: true,
|
||||
fontSize: 13,
|
||||
minHeight: 34,
|
||||
outline: 0,
|
||||
boxShadow: 0,
|
||||
border: '1px solid #78caff !important',
|
||||
borderRadius: '2px !important',
|
||||
borderBottomLeftRadius: '0 !important',
|
||||
borderBottomRightRadius: '0 !important',
|
||||
};
|
||||
|
||||
expect(styles.control(base, state)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return the correct border when the component is not focused, does not have a value and has an error', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
};
|
||||
const state = {
|
||||
isFocused: false,
|
||||
selectProps: {
|
||||
menuIsOpen: true,
|
||||
error: true,
|
||||
value: [],
|
||||
},
|
||||
};
|
||||
|
||||
const expected = {
|
||||
ok: true,
|
||||
fontSize: 13,
|
||||
minHeight: 34,
|
||||
outline: 0,
|
||||
boxShadow: 0,
|
||||
border: '1px solid #f64d0a !important',
|
||||
borderRadius: '2px !important',
|
||||
borderBottomLeftRadius: '0 !important',
|
||||
borderBottomRightRadius: '0 !important',
|
||||
};
|
||||
|
||||
expect(styles.control(base, state)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('menuIsOpen is false', () => {
|
||||
it('should return the correct border-radius', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
};
|
||||
const state = {
|
||||
isFocused: false,
|
||||
selectProps: {
|
||||
menuIsOpen: false,
|
||||
error: null,
|
||||
value: [],
|
||||
},
|
||||
};
|
||||
|
||||
const expected = {
|
||||
ok: true,
|
||||
fontSize: 13,
|
||||
minHeight: 34,
|
||||
outline: 0,
|
||||
boxShadow: 0,
|
||||
border: '1px solid #e3e9f3 !important',
|
||||
borderRadius: '2px !important',
|
||||
};
|
||||
|
||||
expect(styles.control(base, state)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('menu', () => {
|
||||
it('should return the correct object', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
};
|
||||
const expected = {
|
||||
ok: true,
|
||||
width: 'calc(100% - 0px)',
|
||||
margin: '0',
|
||||
paddingTop: 0,
|
||||
borderRadius: '2px !important',
|
||||
borderTopLeftRadius: '0 !important',
|
||||
borderTopRightRadius: '0 !important',
|
||||
border: '1px solid #78caff !important',
|
||||
boxShadow: 0,
|
||||
borderTop: '0 !important',
|
||||
fontSize: '13px',
|
||||
};
|
||||
|
||||
expect(styles.menu(base)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('menuList', () => {
|
||||
it('should return the correct object', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
};
|
||||
const expected = {
|
||||
ok: true,
|
||||
maxHeight: '112px',
|
||||
paddingTop: 2,
|
||||
};
|
||||
|
||||
expect(styles.menuList(base)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('option', () => {
|
||||
it('should return the correct object when it is focused', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
':active': {
|
||||
ok: true,
|
||||
},
|
||||
};
|
||||
const state = {
|
||||
isFocused: true,
|
||||
};
|
||||
const expected = {
|
||||
ok: true,
|
||||
height: 36,
|
||||
backgroundColor: '#f6f6f6',
|
||||
color: '#333740',
|
||||
fontWeight: '600',
|
||||
WebkitFontSmoothing: 'antialiased',
|
||||
':active': {
|
||||
ok: true,
|
||||
backgroundColor: '#f6f6f6',
|
||||
},
|
||||
cursor: 'pointer',
|
||||
};
|
||||
|
||||
expect(styles.option(base, state)).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return the correct object when it is not focused', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
':active': {
|
||||
ok: true,
|
||||
},
|
||||
};
|
||||
const state = {
|
||||
isFocused: false,
|
||||
};
|
||||
const expected = {
|
||||
ok: true,
|
||||
height: 36,
|
||||
backgroundColor: '#fff',
|
||||
color: '#333740',
|
||||
fontWeight: '400',
|
||||
WebkitFontSmoothing: 'antialiased',
|
||||
':active': {
|
||||
ok: true,
|
||||
backgroundColor: '#f6f6f6',
|
||||
},
|
||||
cursor: 'pointer',
|
||||
};
|
||||
|
||||
expect(styles.option(base, state)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('placeholder', () => {
|
||||
it('should return the correct object', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
};
|
||||
const expected = {
|
||||
ok: true,
|
||||
marginTop: 0,
|
||||
marginLeft: 8,
|
||||
color: '#aaa',
|
||||
};
|
||||
|
||||
expect(styles.placeholder(base)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('valueContainer', () => {
|
||||
it('should return the correct object', () => {
|
||||
const base = {
|
||||
ok: true,
|
||||
};
|
||||
const expected = {
|
||||
ok: true,
|
||||
padding: '2px 4px 4px 4px',
|
||||
lineHeight: '18px',
|
||||
};
|
||||
|
||||
expect(styles.valueContainer(base)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,14 +0,0 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Carret } from '@strapi/helper-plugin';
|
||||
|
||||
const Button = isOpen => {
|
||||
return (
|
||||
<>
|
||||
<FormattedMessage id="app.components.Users.SortPicker.button-label" />
|
||||
<Carret isUp={isOpen} fill={isOpen ? '#007eff' : '#292b2c'} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
@ -1,46 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import ListItem from './ListItem';
|
||||
import ListWrapper from './ListWrapper';
|
||||
|
||||
const sortOptions = {
|
||||
email_asc: 'email:ASC',
|
||||
email_desc: 'email:DESC',
|
||||
firstname_asc: 'firstname:ASC',
|
||||
firstname_desc: 'firstname:DESC',
|
||||
lastname_asc: 'lastname:ASC',
|
||||
lastname_desc: 'lastname:DESC',
|
||||
username_asc: 'username:ASC',
|
||||
username_desc: 'username:DESC',
|
||||
};
|
||||
|
||||
const SortList = ({ onClick, selectedItem }) => {
|
||||
return (
|
||||
<ListWrapper>
|
||||
{Object.keys(sortOptions).map(item => {
|
||||
return (
|
||||
<ListItem
|
||||
key={item}
|
||||
label={item}
|
||||
value={sortOptions[item]}
|
||||
onClick={onClick}
|
||||
selectedItem={selectedItem}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</ListWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
SortList.defaultProps = {
|
||||
onClick: () => {},
|
||||
selectedItem: null,
|
||||
};
|
||||
|
||||
SortList.propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
selectedItem: PropTypes.string,
|
||||
};
|
||||
|
||||
export default SortList;
|
@ -1,37 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Text } from '@buffetjs/core';
|
||||
import { useIntl } from 'react-intl';
|
||||
import StyledListItem from './StyledListItem';
|
||||
|
||||
const ListItem = ({ onClick, selectedItem, label, value }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const handleClick = () => {
|
||||
onClick({ target: { name: 'sort', value } });
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledListItem isActive={selectedItem === value} onClick={handleClick}>
|
||||
<Text lineHeight="27px">
|
||||
{formatMessage({ id: `app.components.Users.SortPicker.sortby.${label}` })}
|
||||
</Text>
|
||||
</StyledListItem>
|
||||
);
|
||||
};
|
||||
|
||||
ListItem.defaultProps = {
|
||||
selectedItem: null,
|
||||
label: '',
|
||||
onClick: () => {},
|
||||
value: null,
|
||||
};
|
||||
|
||||
ListItem.propTypes = {
|
||||
selectedItem: PropTypes.string,
|
||||
label: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
value: PropTypes.string,
|
||||
};
|
||||
|
||||
export default ListItem;
|
@ -1,18 +0,0 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { themePropTypes } from '@strapi/helper-plugin';
|
||||
import { Text } from '@buffetjs/core';
|
||||
|
||||
const ListWrapper = styled(props => <Text as="ul" fontSize="md" {...props} />)`
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
min-width: 230px;
|
||||
list-style-type: none;
|
||||
background-color: ${({ theme }) => theme.main.colors.white};
|
||||
`;
|
||||
|
||||
ListWrapper.propTypes = {
|
||||
...themePropTypes,
|
||||
};
|
||||
|
||||
export default ListWrapper;
|
@ -1,30 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
import PropTypes from 'prop-types';
|
||||
import { themePropTypes } from '@strapi/helper-plugin';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
const StyledListItem = styled.li`
|
||||
padding: 0 14px;
|
||||
height: 27px;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background-color: ${({ theme }) => theme.main.colors.mediumGrey};
|
||||
}
|
||||
${({ isActive, theme }) =>
|
||||
isActive &&
|
||||
`
|
||||
background-color: ${theme.main.colors.mediumGrey};
|
||||
`}
|
||||
`;
|
||||
|
||||
StyledListItem.defaultProps = {
|
||||
isActive: false,
|
||||
};
|
||||
|
||||
StyledListItem.propTypes = {
|
||||
isActive: PropTypes.bool,
|
||||
...themePropTypes,
|
||||
};
|
||||
|
||||
export default StyledListItem;
|
@ -1,34 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Picker } from '@buffetjs/core';
|
||||
import Button from './Button';
|
||||
import List from './List';
|
||||
|
||||
const SortPicker = ({ onChange, value }) => {
|
||||
return (
|
||||
<Picker
|
||||
renderButtonContent={Button}
|
||||
renderSectionContent={onToggle => (
|
||||
<List
|
||||
selectedItem={value}
|
||||
onClick={e => {
|
||||
onChange(e);
|
||||
onToggle();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
SortPicker.defaultProps = {
|
||||
onChange: () => {},
|
||||
value: 'firstname:ASC',
|
||||
};
|
||||
|
||||
SortPicker.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.string,
|
||||
};
|
||||
|
||||
export default SortPicker;
|
@ -1,7 +0,0 @@
|
||||
// export { default as MagicLink } from './MagicLink';
|
||||
// export { default as Filter } from './Filter';
|
||||
// export { default as Footer } from './Footer';
|
||||
// export { default as FilterPicker } from './FilterPicker';
|
||||
// export { default as SortPicker } from './SortPicker';
|
||||
// export { default as SelectRoles } from './SelectRoles';
|
||||
// export { default as ModalCreateBody } from './ModalCreateBody';
|
Loading…
x
Reference in New Issue
Block a user