mirror of
https://github.com/kremalicious/umami.git
synced 2024-12-18 15:23:38 +01:00
Merge pull request #481 from gnarlex/proptyping-common
Add prop-types for "common" components
This commit is contained in:
commit
826facf56a
@ -1,10 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import ReactTooltip from 'react-tooltip';
|
import ReactTooltip from 'react-tooltip';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Icon from './Icon';
|
import Icon from './Icon';
|
||||||
import styles from './Button.module.css';
|
import styles from './Button.module.css';
|
||||||
|
|
||||||
export default function Button({
|
function Button({
|
||||||
type = 'button',
|
type = 'button',
|
||||||
icon,
|
icon,
|
||||||
size,
|
size,
|
||||||
@ -43,3 +44,19 @@ export default function Button({
|
|||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button.propTypes = {
|
||||||
|
type: PropTypes.oneOf(['button', 'submit', 'reset']),
|
||||||
|
icon: PropTypes.node,
|
||||||
|
size: PropTypes.oneOf(['xlarge', 'large', 'medium', 'small', 'xsmall']),
|
||||||
|
variant: PropTypes.oneOf(['action', 'danger', 'light']),
|
||||||
|
children: PropTypes.node,
|
||||||
|
className: PropTypes.string,
|
||||||
|
tooltip: PropTypes.node,
|
||||||
|
tooltipId: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
iconRight: PropTypes.bool,
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Button;
|
||||||
|
@ -1,16 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import styles from './ButtonGroup.module.css';
|
import styles from './ButtonGroup.module.css';
|
||||||
|
|
||||||
export default function ButtonGroup({
|
function ButtonGroup({ items = [], selectedItem, className, size, icon, onClick = () => {} }) {
|
||||||
items = [],
|
|
||||||
selectedItem,
|
|
||||||
className,
|
|
||||||
size,
|
|
||||||
icon,
|
|
||||||
onClick = () => {},
|
|
||||||
}) {
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(styles.group, className)}>
|
<div className={classNames(styles.group, className)}>
|
||||||
{items.map(item => {
|
{items.map(item => {
|
||||||
@ -30,3 +24,19 @@ export default function ButtonGroup({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ButtonGroup.propTypes = {
|
||||||
|
items: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
label: PropTypes.node,
|
||||||
|
value: PropTypes.any.isRequired,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
selectedItem: PropTypes.any,
|
||||||
|
className: PropTypes.string,
|
||||||
|
size: PropTypes.oneOf(['xlarge', 'large', 'medium', 'small', 'xsmall']),
|
||||||
|
icon: PropTypes.node,
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ButtonGroup;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import Icon from 'components/common/Icon';
|
import Icon from 'components/common/Icon';
|
||||||
import Check from 'assets/check.svg';
|
import Check from 'assets/check.svg';
|
||||||
import styles from './Checkbox.module.css';
|
import styles from './Checkbox.module.css';
|
||||||
|
|
||||||
export default function Checkbox({ name, value, label, onChange }) {
|
function Checkbox({ name, value, label, onChange }) {
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -25,3 +26,12 @@ export default function Checkbox({ name, value, label, onChange }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Checkbox.propTypes = {
|
||||||
|
name: PropTypes.string,
|
||||||
|
value: PropTypes.any,
|
||||||
|
label: PropTypes.node,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Checkbox;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
@ -6,7 +7,7 @@ const defaultText = (
|
|||||||
<FormattedMessage id="label.copy-to-clipboard" defaultMessage="Copy to clipboard" />
|
<FormattedMessage id="label.copy-to-clipboard" defaultMessage="Copy to clipboard" />
|
||||||
);
|
);
|
||||||
|
|
||||||
export default function CopyButton({ element, ...props }) {
|
function CopyButton({ element, ...props }) {
|
||||||
const [text, setText] = useState(defaultText);
|
const [text, setText] = useState(defaultText);
|
||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
@ -24,3 +25,13 @@ export default function CopyButton({ element, ...props }) {
|
|||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CopyButton.propTypes = {
|
||||||
|
element: PropTypes.shape({
|
||||||
|
current: PropTypes.shape({
|
||||||
|
select: PropTypes.func.isRequired,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CopyButton;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { endOfYear, isSameDay } from 'date-fns';
|
import { endOfYear, isSameDay } from 'date-fns';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
@ -54,7 +55,7 @@ const filterOptions = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function DateFilter({ value, startDate, endDate, onChange, className }) {
|
function DateFilter({ value, startDate, endDate, onChange, className }) {
|
||||||
const [showPicker, setShowPicker] = useState(false);
|
const [showPicker, setShowPicker] = useState(false);
|
||||||
const displayValue =
|
const displayValue =
|
||||||
value === 'custom' ? (
|
value === 'custom' ? (
|
||||||
@ -117,3 +118,13 @@ const CustomRange = ({ startDate, endDate, onClick }) => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DateFilter.propTypes = {
|
||||||
|
value: PropTypes.string,
|
||||||
|
startDate: PropTypes.instanceOf(Date),
|
||||||
|
endDate: PropTypes.instanceOf(Date),
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
className: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DateFilter;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import styles from './Dot.module.css';
|
import styles from './Dot.module.css';
|
||||||
|
|
||||||
export default function Dot({ color, size, className }) {
|
function Dot({ color, size, className }) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
<div
|
<div
|
||||||
@ -15,3 +16,11 @@ export default function Dot({ color, size, className }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dot.propTypes = {
|
||||||
|
color: PropTypes.string,
|
||||||
|
size: PropTypes.oneOf(['small', 'large']),
|
||||||
|
className: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Dot;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useState, useRef } from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Menu from './Menu';
|
import Menu from './Menu';
|
||||||
import useDocumentClick from 'hooks/useDocumentClick';
|
import useDocumentClick from 'hooks/useDocumentClick';
|
||||||
@ -6,13 +7,7 @@ import Chevron from 'assets/chevron-down.svg';
|
|||||||
import styles from './Dropdown.module.css';
|
import styles from './Dropdown.module.css';
|
||||||
import Icon from './Icon';
|
import Icon from './Icon';
|
||||||
|
|
||||||
export default function DropDown({
|
function DropDown({ value, className, menuClassName, options = [], onChange = () => {} }) {
|
||||||
value,
|
|
||||||
className,
|
|
||||||
menuClassName,
|
|
||||||
options = [],
|
|
||||||
onChange = () => {},
|
|
||||||
}) {
|
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
const selectedOption = options.find(e => e.value === value);
|
const selectedOption = options.find(e => e.value === value);
|
||||||
@ -52,3 +47,18 @@ export default function DropDown({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DropDown.propTypes = {
|
||||||
|
value: PropTypes.any,
|
||||||
|
className: PropTypes.string,
|
||||||
|
menuClassName: PropTypes.string,
|
||||||
|
options: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
value: PropTypes.any.isRequired,
|
||||||
|
label: PropTypes.node,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DropDown;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import Icon from 'components/common/Icon';
|
import Icon from 'components/common/Icon';
|
||||||
import Logo from 'assets/logo.svg';
|
import Logo from 'assets/logo.svg';
|
||||||
import styles from './EmptyPlaceholder.module.css';
|
import styles from './EmptyPlaceholder.module.css';
|
||||||
|
|
||||||
export default function EmptyPlaceholder({ msg, children }) {
|
function EmptyPlaceholder({ msg, children }) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.placeholder}>
|
<div className={styles.placeholder}>
|
||||||
<Icon className={styles.icon} icon={<Logo />} size="xlarge" />
|
<Icon className={styles.icon} icon={<Logo />} size="xlarge" />
|
||||||
@ -12,3 +13,10 @@ export default function EmptyPlaceholder({ msg, children }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EmptyPlaceholder.propTypes = {
|
||||||
|
msg: PropTypes.node,
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EmptyPlaceholder;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import styles from './Favicon.module.css';
|
import styles from './Favicon.module.css';
|
||||||
|
|
||||||
function getHostName(url) {
|
function getHostName(url) {
|
||||||
@ -6,7 +7,7 @@ function getHostName(url) {
|
|||||||
return match && match.length > 1 ? match[1] : null;
|
return match && match.length > 1 ? match[1] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Favicon({ domain, ...props }) {
|
function Favicon({ domain, ...props }) {
|
||||||
const hostName = domain ? getHostName(domain) : null;
|
const hostName = domain ? getHostName(domain) : null;
|
||||||
|
|
||||||
return hostName ? (
|
return hostName ? (
|
||||||
@ -19,3 +20,9 @@ export default function Favicon({ domain, ...props }) {
|
|||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Favicon.propTypes = {
|
||||||
|
domain: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Favicon;
|
||||||
|
@ -1,11 +1,25 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import ButtonLayout from 'components/layout/ButtonLayout';
|
import ButtonLayout from 'components/layout/ButtonLayout';
|
||||||
import ButtonGroup from './ButtonGroup';
|
import ButtonGroup from './ButtonGroup';
|
||||||
|
|
||||||
export default function FilterButtons({ buttons, selected, onClick }) {
|
function FilterButtons({ buttons, selected, onClick }) {
|
||||||
return (
|
return (
|
||||||
<ButtonLayout>
|
<ButtonLayout>
|
||||||
<ButtonGroup size="xsmall" items={buttons} selectedItem={selected} onClick={onClick} />
|
<ButtonGroup size="xsmall" items={buttons} selectedItem={selected} onClick={onClick} />
|
||||||
</ButtonLayout>
|
</ButtonLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FilterButtons.propTypes = {
|
||||||
|
buttons: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
label: PropTypes.node,
|
||||||
|
value: PropTypes.any.isRequired,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
selected: PropTypes.any,
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FilterButtons;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import styles from './Icon.module.css';
|
import styles from './Icon.module.css';
|
||||||
|
|
||||||
export default function Icon({ icon, className, size = 'medium', ...props }) {
|
function Icon({ icon, className, size = 'medium', ...props }) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(styles.icon, className, {
|
className={classNames(styles.icon, className, {
|
||||||
@ -18,3 +19,11 @@ export default function Icon({ icon, className, size = 'medium', ...props }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Icon.propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
icon: PropTypes.node.isRequired,
|
||||||
|
size: PropTypes.oneOf(['xlarge', 'large', 'medium', 'small', 'xsmall']),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Icon;
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import NextLink from 'next/link';
|
import NextLink from 'next/link';
|
||||||
import Icon from './Icon';
|
import Icon from './Icon';
|
||||||
import styles from './Link.module.css';
|
import styles from './Link.module.css';
|
||||||
|
|
||||||
export default function Link({ className, icon, children, size, iconRight, ...props }) {
|
function Link({ className, icon, children, size, iconRight, ...props }) {
|
||||||
return (
|
return (
|
||||||
<NextLink {...props}>
|
<NextLink {...props}>
|
||||||
<a
|
<a
|
||||||
@ -21,3 +22,13 @@ export default function Link({ className, icon, children, size, iconRight, ...pr
|
|||||||
</NextLink>
|
</NextLink>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Link.propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
icon: PropTypes.node,
|
||||||
|
children: PropTypes.node,
|
||||||
|
size: PropTypes.oneOf(['large', 'small', 'xsmall']),
|
||||||
|
iconRight: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Link;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import styles from './Loading.module.css';
|
import styles from './Loading.module.css';
|
||||||
|
|
||||||
export default function Loading({ className }) {
|
function Loading({ className }) {
|
||||||
return (
|
return (
|
||||||
<div className={classNames(styles.loading, className)}>
|
<div className={classNames(styles.loading, className)}>
|
||||||
<div />
|
<div />
|
||||||
@ -11,3 +12,9 @@ export default function Loading({ className }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading.propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Loading;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import styles from './Menu.module.css';
|
import styles from './Menu.module.css';
|
||||||
|
|
||||||
export default function Menu({
|
function Menu({
|
||||||
options = [],
|
options = [],
|
||||||
selectedOption,
|
selectedOption,
|
||||||
className,
|
className,
|
||||||
@ -46,3 +47,24 @@ export default function Menu({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Menu.propTypes = {
|
||||||
|
options: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
label: PropTypes.node,
|
||||||
|
value: PropTypes.any,
|
||||||
|
className: PropTypes.string,
|
||||||
|
render: PropTypes.func,
|
||||||
|
divider: PropTypes.bool,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
selectedOption: PropTypes.any,
|
||||||
|
className: PropTypes.string,
|
||||||
|
float: PropTypes.oneOf(['top', 'bottom']),
|
||||||
|
align: PropTypes.oneOf(['left', 'right']),
|
||||||
|
optionClassName: PropTypes.string,
|
||||||
|
selectedClassName: PropTypes.string,
|
||||||
|
onSelect: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Menu;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import React, { useState, useRef } from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Menu from 'components/common/Menu';
|
import Menu from 'components/common/Menu';
|
||||||
import Button from 'components/common/Button';
|
import Button from 'components/common/Button';
|
||||||
import useDocumentClick from 'hooks/useDocumentClick';
|
import useDocumentClick from 'hooks/useDocumentClick';
|
||||||
import styles from './MenuButton.module.css';
|
import styles from './MenuButton.module.css';
|
||||||
|
|
||||||
export default function MenuButton({
|
function MenuButton({
|
||||||
icon,
|
icon,
|
||||||
value,
|
value,
|
||||||
options,
|
options,
|
||||||
@ -58,3 +59,25 @@ export default function MenuButton({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MenuButton.propTypes = {
|
||||||
|
icon: PropTypes.node,
|
||||||
|
value: PropTypes.any,
|
||||||
|
options: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
label: PropTypes.node,
|
||||||
|
value: PropTypes.any,
|
||||||
|
className: PropTypes.string,
|
||||||
|
render: PropTypes.func,
|
||||||
|
divider: PropTypes.bool,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
buttonClassName: PropTypes.string,
|
||||||
|
menuClassName: PropTypes.string,
|
||||||
|
menuPosition: PropTypes.oneOf(['top', 'bottom']),
|
||||||
|
menuAlign: PropTypes.oneOf(['left', 'right']),
|
||||||
|
onSelect: PropTypes.func,
|
||||||
|
renderValue: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MenuButton;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { useSpring, animated } from 'react-spring';
|
import { useSpring, animated } from 'react-spring';
|
||||||
import styles from './Modal.module.css';
|
import styles from './Modal.module.css';
|
||||||
|
|
||||||
export default function Modal({ title, children }) {
|
function Modal({ title, children }) {
|
||||||
const props = useSpring({ opacity: 1, from: { opacity: 0 } });
|
const props = useSpring({ opacity: 1, from: { opacity: 0 } });
|
||||||
|
|
||||||
return ReactDOM.createPortal(
|
return ReactDOM.createPortal(
|
||||||
@ -16,3 +17,10 @@ export default function Modal({ title, children }) {
|
|||||||
document.getElementById('__modals'),
|
document.getElementById('__modals'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Modal.propTypes = {
|
||||||
|
title: PropTypes.node,
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Modal;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import styles from './NavMenu.module.css';
|
import styles from './NavMenu.module.css';
|
||||||
|
|
||||||
export default function NavMenu({ options = [], className, onSelect = () => {} }) {
|
function NavMenu({ options = [], className, onSelect = () => {} }) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -30,3 +31,17 @@ export default function NavMenu({ options = [], className, onSelect = () => {} }
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NavMenu.propTypes = {
|
||||||
|
options: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
label: PropTypes.node,
|
||||||
|
value: PropTypes.any,
|
||||||
|
className: PropTypes.string,
|
||||||
|
render: PropTypes.func,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
className: PropTypes.string,
|
||||||
|
onSelect: PropTypes.func,
|
||||||
|
};
|
||||||
|
export default NavMenu;
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import styles from './NoData.module.css';
|
import styles from './NoData.module.css';
|
||||||
|
|
||||||
export default function NoData({ className }) {
|
function NoData({ className }) {
|
||||||
return (
|
return (
|
||||||
<div className={classNames(styles.container, className)}>
|
<div className={classNames(styles.container, className)}>
|
||||||
<FormattedMessage id="message.no-data-available" defaultMessage="No data available." />
|
<FormattedMessage id="message.no-data-available" defaultMessage="No data available." />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NoData.propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NoData;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { setDateRange } from 'redux/actions/websites';
|
import { setDateRange } from 'redux/actions/websites';
|
||||||
@ -8,7 +9,7 @@ import Dots from 'assets/ellipsis-h.svg';
|
|||||||
import useDateRange from 'hooks/useDateRange';
|
import useDateRange from 'hooks/useDateRange';
|
||||||
import { getDateRange } from '../../lib/date';
|
import { getDateRange } from '../../lib/date';
|
||||||
|
|
||||||
export default function RefreshButton({ websiteId }) {
|
function RefreshButton({ websiteId }) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [dateRange] = useDateRange(websiteId);
|
const [dateRange] = useDateRange(websiteId);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@ -35,3 +36,9 @@ export default function RefreshButton({ websiteId }) {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefreshButton.propTypes = {
|
||||||
|
websiteId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RefreshButton;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import NoData from 'components/common/NoData';
|
import NoData from 'components/common/NoData';
|
||||||
import styles from './Table.module.css';
|
import styles from './Table.module.css';
|
||||||
|
|
||||||
export default function Table({
|
function Table({
|
||||||
columns,
|
columns,
|
||||||
rows,
|
rows,
|
||||||
empty,
|
empty,
|
||||||
@ -45,6 +46,34 @@ export default function Table({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const styledObject = PropTypes.shape({
|
||||||
|
className: PropTypes.string,
|
||||||
|
style: PropTypes.object,
|
||||||
|
});
|
||||||
|
|
||||||
|
Table.propTypes = {
|
||||||
|
columns: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
cell: styledObject,
|
||||||
|
className: PropTypes.string,
|
||||||
|
header: styledObject,
|
||||||
|
key: PropTypes.string,
|
||||||
|
label: PropTypes.node,
|
||||||
|
render: PropTypes.func,
|
||||||
|
style: PropTypes.object,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
rows: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
empty: PropTypes.node,
|
||||||
|
className: PropTypes.string,
|
||||||
|
bodyClassName: PropTypes.string,
|
||||||
|
rowKey: PropTypes.func,
|
||||||
|
showHeader: PropTypes.bool,
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Table;
|
||||||
|
|
||||||
export const TableRow = ({ columns, row }) => (
|
export const TableRow = ({ columns, row }) => (
|
||||||
<div className={classNames(styles.row, 'row')}>
|
<div className={classNames(styles.row, 'row')}>
|
||||||
{columns.map(({ key, render, className, style, cell }, index) => (
|
{columns.map(({ key, render, className, style, cell }, index) => (
|
||||||
|
@ -1,7 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import styles from './Tag.module.css';
|
import styles from './Tag.module.css';
|
||||||
|
|
||||||
export default function Tag({ className, children }) {
|
function Tag({ className, children }) {
|
||||||
return <span className={classNames(styles.tag, className)}>{children}</span>;
|
return <span className={classNames(styles.tag, className)}>{children}</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tag.propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Tag;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { useSpring, animated } from 'react-spring';
|
import { useSpring, animated } from 'react-spring';
|
||||||
import styles from './Toast.module.css';
|
import styles from './Toast.module.css';
|
||||||
import Icon from 'components/common/Icon';
|
import Icon from 'components/common/Icon';
|
||||||
import Close from 'assets/times.svg';
|
import Close from 'assets/times.svg';
|
||||||
|
|
||||||
export default function Toast({ message, timeout = 3000, onClose }) {
|
function Toast({ message, timeout = 3000, onClose }) {
|
||||||
const props = useSpring({
|
const props = useSpring({
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
transform: 'translate3d(0,0px,0)',
|
transform: 'translate3d(0,0px,0)',
|
||||||
@ -24,3 +25,11 @@ export default function Toast({ message, timeout = 3000, onClose }) {
|
|||||||
document.getElementById('__modals'),
|
document.getElementById('__modals'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Toast.propTypes = {
|
||||||
|
message: PropTypes.node,
|
||||||
|
timeout: PropTypes.number,
|
||||||
|
onClose: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Toast;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useState, useMemo } from 'react';
|
import React, { useState, useMemo } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import ReactTooltip from 'react-tooltip';
|
import ReactTooltip from 'react-tooltip';
|
||||||
import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps';
|
import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
@ -12,7 +13,7 @@ import { useRouter } from 'next/router';
|
|||||||
|
|
||||||
const geoUrl = '/world-110m.json';
|
const geoUrl = '/world-110m.json';
|
||||||
|
|
||||||
export default function WorldMap({ data, className }) {
|
function WorldMap({ data, className }) {
|
||||||
const { basePath } = useRouter();
|
const { basePath } = useRouter();
|
||||||
const [tooltip, setTooltip] = useState();
|
const [tooltip, setTooltip] = useState();
|
||||||
const [theme] = useTheme();
|
const [theme] = useTheme();
|
||||||
@ -89,3 +90,16 @@ export default function WorldMap({ data, className }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WorldMap.propTypes = {
|
||||||
|
data: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
x: PropTypes.string,
|
||||||
|
y: PropTypes.number,
|
||||||
|
z: PropTypes.number,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
className: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WorldMap;
|
||||||
|
Loading…
Reference in New Issue
Block a user