mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-01-11 02:37:22 +03:00
Updated EditTagModal to be a functional component
This commit is contained in:
parent
656b68d422
commit
ebe649aaac
4 changed files with 38 additions and 117 deletions
|
@ -1,109 +1,62 @@
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Modal, ModalBody, ModalFooter, ModalHeader, Popover } from 'reactstrap';
|
import { Modal, ModalBody, ModalFooter, ModalHeader, Popover } from 'reactstrap';
|
||||||
import { ChromePicker } from 'react-color';
|
import { ChromePicker } from 'react-color';
|
||||||
import { faPalette as colorIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faPalette as colorIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import './EditTagModal.scss';
|
import './EditTagModal.scss';
|
||||||
|
import { useToggle } from '../../utils/helpers/hooks';
|
||||||
|
|
||||||
const EditTagModal = ({ getColorForKey }) => class EditTagModal extends React.Component {
|
const propTypes = {
|
||||||
static propTypes = {
|
tag: PropTypes.string,
|
||||||
tag: PropTypes.string,
|
editTag: PropTypes.func,
|
||||||
editTag: PropTypes.func,
|
toggle: PropTypes.func,
|
||||||
toggle: PropTypes.func,
|
tagEdited: PropTypes.func,
|
||||||
tagEdited: PropTypes.func,
|
isOpen: PropTypes.bool,
|
||||||
isOpen: PropTypes.bool,
|
tagEdit: PropTypes.shape({
|
||||||
tagEdit: PropTypes.shape({
|
error: PropTypes.bool,
|
||||||
error: PropTypes.bool,
|
editing: PropTypes.bool,
|
||||||
editing: PropTypes.bool,
|
}),
|
||||||
}),
|
};
|
||||||
};
|
|
||||||
|
|
||||||
saveTag = (e) => {
|
const EditTagModal = ({ getColorForKey }) => {
|
||||||
e.preventDefault();
|
const EditTagModalComp = ({ tag, editTag, toggle, tagEdited, isOpen, tagEdit }) => {
|
||||||
const { tag: oldName, editTag, toggle } = this.props;
|
const [ newTagName, setNewTagName ] = useState(tag);
|
||||||
const { tag: newName, color } = this.state;
|
const [ color, setColor ] = useState(getColorForKey(tag));
|
||||||
|
const [ showColorPicker, toggleColorPicker ] = useToggle();
|
||||||
|
const saveTag = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
editTag(oldName, newName, color)
|
editTag(tag, newTagName, color)
|
||||||
.then(() => {
|
.then(() => tagEdited(tag, newTagName, color))
|
||||||
this.tagWasEdited = true;
|
.then(toggle)
|
||||||
toggle();
|
.catch(() => {});
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
};
|
|
||||||
handleOnClosed = () => {
|
|
||||||
if (!this.tagWasEdited) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { tag: oldName, tagEdited } = this.props;
|
|
||||||
const { tag: newName, color } = this.state;
|
|
||||||
|
|
||||||
tagEdited(oldName, newName, color);
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
const { tag } = props;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
showColorPicker: false,
|
|
||||||
tag,
|
|
||||||
color: getColorForKey(tag),
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.tagWasEdited = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { isOpen, toggle, tagEdit } = this.props;
|
|
||||||
const { tag, color } = this.state;
|
|
||||||
const toggleColorPicker = () =>
|
|
||||||
this.setState(({ showColorPicker }) => ({ showColorPicker: !showColorPicker }));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} toggle={toggle} centered onClosed={this.handleOnClosed}>
|
<Modal isOpen={isOpen} toggle={toggle} centered>
|
||||||
<form onSubmit={(e) => this.saveTag(e)}>
|
<form onSubmit={saveTag}>
|
||||||
<ModalHeader toggle={toggle}>Edit tag</ModalHeader>
|
<ModalHeader toggle={toggle}>Edit tag</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
<div
|
<div className="input-group-prepend" id="colorPickerBtn" onClick={toggleColorPicker}>
|
||||||
className="input-group-prepend"
|
|
||||||
id="colorPickerBtn"
|
|
||||||
onClick={toggleColorPicker}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
className="input-group-text edit-tag-modal__color-picker-toggle"
|
className="input-group-text edit-tag-modal__color-picker-toggle"
|
||||||
style={{
|
style={{ backgroundColor: color, borderColor: color }}
|
||||||
backgroundColor: color,
|
|
||||||
borderColor: color,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={colorIcon} className="edit-tag-modal__color-icon" />
|
<FontAwesomeIcon icon={colorIcon} className="edit-tag-modal__color-icon" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Popover
|
<Popover isOpen={showColorPicker} toggle={toggleColorPicker} target="colorPickerBtn" placement="right">
|
||||||
isOpen={this.state.showColorPicker}
|
<ChromePicker color={color} disableAlpha onChange={({ hex }) => setColor(hex)} />
|
||||||
toggle={toggleColorPicker}
|
|
||||||
target="colorPickerBtn"
|
|
||||||
placement="right"
|
|
||||||
>
|
|
||||||
<ChromePicker
|
|
||||||
color={color}
|
|
||||||
disableAlpha
|
|
||||||
onChange={(color) => this.setState({ color: color.hex })}
|
|
||||||
/>
|
|
||||||
</Popover>
|
</Popover>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={tag}
|
value={newTagName}
|
||||||
placeholder="Tag"
|
placeholder="Tag"
|
||||||
required
|
required
|
||||||
className="form-control"
|
className="form-control"
|
||||||
onChange={(e) => this.setState({ tag: e.target.value })}
|
onChange={(e) => setNewTagName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -122,7 +75,11 @@ const EditTagModal = ({ getColorForKey }) => class EditTagModal extends React.Co
|
||||||
</form>
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
EditTagModalComp.propTypes = propTypes;
|
||||||
|
|
||||||
|
return EditTagModalComp;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EditTagModal;
|
export default EditTagModal;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { stateFlagTimeout } from '../utils';
|
|
||||||
import { useStateFlagTimeout } from '../helpers/hooks';
|
import { useStateFlagTimeout } from '../helpers/hooks';
|
||||||
import Storage from './Storage';
|
import Storage from './Storage';
|
||||||
import ColorGenerator from './ColorGenerator';
|
import ColorGenerator from './ColorGenerator';
|
||||||
|
@ -15,7 +14,6 @@ const provideServices = (bottle) => {
|
||||||
|
|
||||||
bottle.constant('setTimeout', global.setTimeout);
|
bottle.constant('setTimeout', global.setTimeout);
|
||||||
bottle.constant('clearTimeout', global.clearTimeout);
|
bottle.constant('clearTimeout', global.clearTimeout);
|
||||||
bottle.serviceFactory('stateFlagTimeout', stateFlagTimeout, 'setTimeout');
|
|
||||||
bottle.serviceFactory('useStateFlagTimeout', useStateFlagTimeout, 'setTimeout', 'clearTimeout');
|
bottle.serviceFactory('useStateFlagTimeout', useStateFlagTimeout, 'setTimeout', 'clearTimeout');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,6 @@ import marker from 'leaflet/dist/images/marker-icon.png';
|
||||||
import markerShadow from 'leaflet/dist/images/marker-shadow.png';
|
import markerShadow from 'leaflet/dist/images/marker-shadow.png';
|
||||||
import { isEmpty, isNil, range } from 'ramda';
|
import { isEmpty, isNil, range } from 'ramda';
|
||||||
|
|
||||||
const DEFAULT_TIMEOUT_DELAY = 2000;
|
|
||||||
|
|
||||||
export const stateFlagTimeout = (setTimeout) => (
|
|
||||||
setState,
|
|
||||||
flagName,
|
|
||||||
initialValue = true,
|
|
||||||
delay = DEFAULT_TIMEOUT_DELAY
|
|
||||||
) => {
|
|
||||||
setState({ [flagName]: initialValue });
|
|
||||||
setTimeout(() => setState({ [flagName]: !initialValue }), delay);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const determineOrderDir = (clickedField, currentOrderField, currentOrderDir) => {
|
export const determineOrderDir = (clickedField, currentOrderField, currentOrderDir) => {
|
||||||
if (currentOrderField !== clickedField) {
|
if (currentOrderField !== clickedField) {
|
||||||
return 'ASC';
|
return 'ASC';
|
||||||
|
|
|
@ -2,31 +2,9 @@ import L from 'leaflet';
|
||||||
import marker2x from 'leaflet/dist/images/marker-icon-2x.png';
|
import marker2x from 'leaflet/dist/images/marker-icon-2x.png';
|
||||||
import marker from 'leaflet/dist/images/marker-icon.png';
|
import marker from 'leaflet/dist/images/marker-icon.png';
|
||||||
import markerShadow from 'leaflet/dist/images/marker-shadow.png';
|
import markerShadow from 'leaflet/dist/images/marker-shadow.png';
|
||||||
import {
|
import { determineOrderDir, fixLeafletIcons, rangeOf } from '../../src/utils/utils';
|
||||||
stateFlagTimeout as stateFlagTimeoutFactory,
|
|
||||||
determineOrderDir,
|
|
||||||
fixLeafletIcons,
|
|
||||||
rangeOf,
|
|
||||||
} from '../../src/utils/utils';
|
|
||||||
|
|
||||||
describe('utils', () => {
|
describe('utils', () => {
|
||||||
describe('stateFlagTimeout', () => {
|
|
||||||
it('sets state and initializes timeout with provided delay', () => {
|
|
||||||
const setTimeout = jest.fn((callback) => callback());
|
|
||||||
const setState = jest.fn();
|
|
||||||
const stateFlagTimeout = stateFlagTimeoutFactory(setTimeout);
|
|
||||||
const delay = 5000;
|
|
||||||
|
|
||||||
stateFlagTimeout(setState, 'foo', false, delay);
|
|
||||||
|
|
||||||
expect(setState).toHaveBeenCalledTimes(2);
|
|
||||||
expect(setState).toHaveBeenNthCalledWith(1, { foo: false });
|
|
||||||
expect(setState).toHaveBeenNthCalledWith(2, { foo: true });
|
|
||||||
expect(setTimeout).toHaveBeenCalledTimes(1);
|
|
||||||
expect(setTimeout).toHaveBeenCalledWith(expect.anything(), delay);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('determineOrderDir', () => {
|
describe('determineOrderDir', () => {
|
||||||
it('returns ASC when current order field and selected field are different', () => {
|
it('returns ASC when current order field and selected field are different', () => {
|
||||||
expect(determineOrderDir('foo', 'bar')).toEqual('ASC');
|
expect(determineOrderDir('foo', 'bar')).toEqual('ASC');
|
||||||
|
|
Loading…
Reference in a new issue