@performant-software/semantic-components 0.5.11 → 0.5.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/KeyValuePairs.js +79 -0
- package/src/components/ReferenceCodeFormDropdown.js +81 -0
- package/src/components/ReferenceCodeFormLabel.js +51 -0
- package/src/hooks/BatchEdit.js +57 -0
- package/src/i18n/en.json +12 -0
- package/src/index.js +7 -0
- package/types/components/KeyValuePairs.js.flow +79 -0
- package/types/components/ReferenceCodeFormDropdown.js.flow +81 -0
- package/types/components/ReferenceCodeFormLabel.js.flow +51 -0
- package/types/hooks/BatchEdit.js.flow +57 -0
- package/types/index.js.flow +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@performant-software/semantic-components",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.12",
|
|
4
4
|
"description": "A package of shared components based on the Semantic UI Framework.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./build/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"build": "webpack --mode production && flow-copy-source -v src types"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@performant-software/shared-components": "^0.5.
|
|
15
|
+
"@performant-software/shared-components": "^0.5.12",
|
|
16
16
|
"@react-google-maps/api": "^2.8.1",
|
|
17
17
|
"axios": "^0.26.1",
|
|
18
18
|
"i18next": "^19.4.4",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"react-dom": ">= 16.13.1 < 18.0.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@performant-software/webpack-config": "^0.5.
|
|
36
|
+
"@performant-software/webpack-config": "^0.5.12",
|
|
37
37
|
"flow-copy-source": "^2.0.9",
|
|
38
38
|
"less": "^4.1.2",
|
|
39
39
|
"less-loader": "^11.0.0",
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { type ComponentType } from 'react';
|
|
4
|
+
import { Button, Grid, Input } from 'semantic-ui-react';
|
|
5
|
+
import _ from 'underscore';
|
|
6
|
+
import i18n from '../i18n/i18n';
|
|
7
|
+
import withBatchEdit, { type BatchEditProps } from '../hooks/BatchEdit';
|
|
8
|
+
|
|
9
|
+
type Item = {
|
|
10
|
+
key: string,
|
|
11
|
+
value: string
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type Props = BatchEditProps & {
|
|
15
|
+
items: Array<Item>,
|
|
16
|
+
onChange: (items: Array<Item>) => void
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const KeyValuePairs: ComponentType<any> = withBatchEdit((props: Props) => (
|
|
20
|
+
<div>
|
|
21
|
+
<Button
|
|
22
|
+
basic
|
|
23
|
+
content={i18n.t('Common.buttons.add')}
|
|
24
|
+
icon='plus'
|
|
25
|
+
onClick={props.onAddItem.bind(this)}
|
|
26
|
+
type='button'
|
|
27
|
+
/>
|
|
28
|
+
<Grid
|
|
29
|
+
padded='vertically'
|
|
30
|
+
>
|
|
31
|
+
{ _.map(props.items, (item, index) => (
|
|
32
|
+
<Grid.Row
|
|
33
|
+
columns={3}
|
|
34
|
+
>
|
|
35
|
+
<Grid.Column
|
|
36
|
+
width={8}
|
|
37
|
+
>
|
|
38
|
+
<Input
|
|
39
|
+
fluid
|
|
40
|
+
onChange={props.onUpdateItem.bind(this, index, 'key')}
|
|
41
|
+
placeholder={i18n.t('KeyValuePairs.labels.key')}
|
|
42
|
+
value={item.key}
|
|
43
|
+
/>
|
|
44
|
+
</Grid.Column>
|
|
45
|
+
<Grid.Column
|
|
46
|
+
width={7}
|
|
47
|
+
>
|
|
48
|
+
<Input
|
|
49
|
+
fluid
|
|
50
|
+
onChange={props.onUpdateItem.bind(this, index, 'value')}
|
|
51
|
+
placeholder={i18n.t('KeyValuePairs.labels.value')}
|
|
52
|
+
value={item.value}
|
|
53
|
+
/>
|
|
54
|
+
</Grid.Column>
|
|
55
|
+
<Grid.Column
|
|
56
|
+
width={1}
|
|
57
|
+
>
|
|
58
|
+
<Button
|
|
59
|
+
color='red'
|
|
60
|
+
icon='trash'
|
|
61
|
+
onClick={props.onRemoveItem.bind(this, index)}
|
|
62
|
+
/>
|
|
63
|
+
</Grid.Column>
|
|
64
|
+
</Grid.Row>
|
|
65
|
+
))}
|
|
66
|
+
{ _.isEmpty(props.items) && (
|
|
67
|
+
<Grid.Row
|
|
68
|
+
columns={1}
|
|
69
|
+
>
|
|
70
|
+
<Grid.Column>
|
|
71
|
+
{ i18n.t('Common.labels.noRecords') }
|
|
72
|
+
</Grid.Column>
|
|
73
|
+
</Grid.Row>
|
|
74
|
+
)}
|
|
75
|
+
</Grid>
|
|
76
|
+
</div>
|
|
77
|
+
));
|
|
78
|
+
|
|
79
|
+
export default KeyValuePairs;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import { ReferenceTablesService } from '@performant-software/shared-components';
|
|
4
|
+
import React, { type ComponentType, useEffect, useState } from 'react';
|
|
5
|
+
import { Form } from 'semantic-ui-react';
|
|
6
|
+
import EditModal from './EditModal';
|
|
7
|
+
import ReferenceCodeDropdown from './ReferenceCodeDropdown';
|
|
8
|
+
import ReferenceCodeFormLabel from './ReferenceCodeFormLabel';
|
|
9
|
+
import ReferenceTableModal from './ReferenceTableModal';
|
|
10
|
+
|
|
11
|
+
type Props = {
|
|
12
|
+
error?: boolean,
|
|
13
|
+
label?: string,
|
|
14
|
+
required?: boolean,
|
|
15
|
+
referenceTable: string
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const ReferenceCodeFormDropdown: ComponentType<any> = (props: Props) => {
|
|
19
|
+
const {
|
|
20
|
+
error,
|
|
21
|
+
label,
|
|
22
|
+
required,
|
|
23
|
+
referenceTable: key,
|
|
24
|
+
...rest
|
|
25
|
+
} = props;
|
|
26
|
+
|
|
27
|
+
const [modal, setModal] = useState(false);
|
|
28
|
+
const [dropdownKey, setDropdownKey] = useState(0);
|
|
29
|
+
const [referenceTable, setReferenceTable] = useState({ key });
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Looks up the existing reference table base on the passed key.
|
|
33
|
+
*/
|
|
34
|
+
useEffect(() => (
|
|
35
|
+
ReferenceTablesService
|
|
36
|
+
.fetchByKey(key)
|
|
37
|
+
.then(({ data }) => setReferenceTable((prevTable) => ({
|
|
38
|
+
...prevTable,
|
|
39
|
+
...data.reference_table
|
|
40
|
+
})))
|
|
41
|
+
), [key]);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<>
|
|
45
|
+
<Form.Input
|
|
46
|
+
error={error}
|
|
47
|
+
label={(
|
|
48
|
+
<ReferenceCodeFormLabel
|
|
49
|
+
label={label}
|
|
50
|
+
onClick={() => setModal(true)}
|
|
51
|
+
referenceTable={referenceTable.key}
|
|
52
|
+
/>
|
|
53
|
+
)}
|
|
54
|
+
required={required}
|
|
55
|
+
>
|
|
56
|
+
<ReferenceCodeDropdown
|
|
57
|
+
{...rest}
|
|
58
|
+
id={referenceTable}
|
|
59
|
+
referenceTable={referenceTable.key}
|
|
60
|
+
key={dropdownKey}
|
|
61
|
+
/>
|
|
62
|
+
</Form.Input>
|
|
63
|
+
{ modal && (
|
|
64
|
+
<EditModal
|
|
65
|
+
component={ReferenceTableModal}
|
|
66
|
+
item={referenceTable}
|
|
67
|
+
onClose={() => setModal(false)}
|
|
68
|
+
onSave={(record) => (
|
|
69
|
+
ReferenceTablesService
|
|
70
|
+
.save(record)
|
|
71
|
+
.then(({ data }) => data.reference_table)
|
|
72
|
+
.then(() => setDropdownKey((prevKey) => prevKey + 1))
|
|
73
|
+
.finally(() => setModal(false))
|
|
74
|
+
)}
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
77
|
+
</>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export default ReferenceCodeFormDropdown;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { type ComponentType } from 'react';
|
|
4
|
+
import { withTranslation } from 'react-i18next';
|
|
5
|
+
import {
|
|
6
|
+
Button,
|
|
7
|
+
Header,
|
|
8
|
+
Icon,
|
|
9
|
+
Popup
|
|
10
|
+
} from 'semantic-ui-react';
|
|
11
|
+
import i18n from '../i18n/i18n';
|
|
12
|
+
|
|
13
|
+
type Props = {
|
|
14
|
+
label: string,
|
|
15
|
+
onClick: () => void,
|
|
16
|
+
referenceTable: string
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const ReferenceCodeFormLabel: ComponentType<any> = withTranslation()((props: Props) => (
|
|
20
|
+
<div>
|
|
21
|
+
<label
|
|
22
|
+
htmlFor={props.referenceTable}
|
|
23
|
+
>
|
|
24
|
+
{ props.label }
|
|
25
|
+
</label>
|
|
26
|
+
<Popup
|
|
27
|
+
hoverable
|
|
28
|
+
trigger={(
|
|
29
|
+
<Icon
|
|
30
|
+
name='info circle'
|
|
31
|
+
style={{
|
|
32
|
+
marginLeft: '0.3em'
|
|
33
|
+
}}
|
|
34
|
+
/>
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
<Header
|
|
38
|
+
content={props.label}
|
|
39
|
+
/>
|
|
40
|
+
<p>{ i18n.t('ReferenceCodeFormLabel.content', { name: props.label })}</p>
|
|
41
|
+
<Button
|
|
42
|
+
content={i18n.t('Common.buttons.edit')}
|
|
43
|
+
icon='edit'
|
|
44
|
+
primary
|
|
45
|
+
onClick={props.onClick}
|
|
46
|
+
/>
|
|
47
|
+
</Popup>
|
|
48
|
+
</div>
|
|
49
|
+
));
|
|
50
|
+
|
|
51
|
+
export default ReferenceCodeFormLabel;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { useCallback, type ComponentType } from 'react';
|
|
4
|
+
import _ from 'underscore';
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
items: Array<any>,
|
|
8
|
+
onChange: (items: Array<any>) => void
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const withBatchEdit = (WrappedComponent: ComponentType<any>): any => (props: Props) => {
|
|
12
|
+
/**
|
|
13
|
+
* Adds a new item to the list.
|
|
14
|
+
*
|
|
15
|
+
* @type {(function(): void)|*}
|
|
16
|
+
*/
|
|
17
|
+
const onAddItem = useCallback(() => {
|
|
18
|
+
props.onChange([...props.items, {}]);
|
|
19
|
+
}, [props.items]);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Removes the item at the passed index from the list.
|
|
23
|
+
*
|
|
24
|
+
* @type {(function(*): void)|*}
|
|
25
|
+
*/
|
|
26
|
+
const onRemoveItem = useCallback((findIndex) => {
|
|
27
|
+
props.onChange(_.reject(props.items, (item, index) => index === findIndex));
|
|
28
|
+
}, [props.items]);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Updates the passed attribute of the item at the passed index.
|
|
32
|
+
*
|
|
33
|
+
* @type {(function(number, string, ?Event, {value: *}): void)|*}
|
|
34
|
+
*/
|
|
35
|
+
const onUpdateItem = useCallback((findIndex: number, attribute: string, e: ?Event, { value }) => {
|
|
36
|
+
props.onChange(_.map(props.items, (item, index) => (
|
|
37
|
+
index !== findIndex ? item : ({ ...item, [attribute]: value })
|
|
38
|
+
)));
|
|
39
|
+
}, [props.items]);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<WrappedComponent
|
|
43
|
+
{...props}
|
|
44
|
+
onAddItem={onAddItem}
|
|
45
|
+
onRemoveItem={onRemoveItem}
|
|
46
|
+
onUpdateItem={onUpdateItem}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default withBatchEdit;
|
|
52
|
+
|
|
53
|
+
export type BatchEditProps = {
|
|
54
|
+
onAddItem: () => void,
|
|
55
|
+
onRemoveItem: (index: number) => void,
|
|
56
|
+
onUpdateItem: (index: number, attribute: string, e: Event, data: any) => void
|
|
57
|
+
};
|
package/src/i18n/en.json
CHANGED
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
"errors": {
|
|
22
22
|
"title": "Oops!"
|
|
23
23
|
},
|
|
24
|
+
"labels": {
|
|
25
|
+
"noRecords": "No records."
|
|
26
|
+
},
|
|
24
27
|
"messages": {
|
|
25
28
|
"error": {
|
|
26
29
|
"header": "Oops!"
|
|
@@ -126,6 +129,12 @@
|
|
|
126
129
|
"showKeyboard": "Show Keyboard"
|
|
127
130
|
}
|
|
128
131
|
},
|
|
132
|
+
"KeyValuePairs": {
|
|
133
|
+
"labels": {
|
|
134
|
+
"key": "Key",
|
|
135
|
+
"value": "Value"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
129
138
|
"LazyDocument": {
|
|
130
139
|
"buttons": {
|
|
131
140
|
"download": "Download"
|
|
@@ -184,6 +193,9 @@
|
|
|
184
193
|
"loginErrorHeader": "Invalid Credentials",
|
|
185
194
|
"password": "Password"
|
|
186
195
|
},
|
|
196
|
+
"ReferenceCodeFormLabel": {
|
|
197
|
+
"content": "The values in this list can be edited via the {{name}} reference table."
|
|
198
|
+
},
|
|
187
199
|
"ReferenceCodeModal": {
|
|
188
200
|
"labels": {
|
|
189
201
|
"name": "Name"
|
package/src/index.js
CHANGED
|
@@ -38,6 +38,7 @@ export { default as ItemCollection } from './components/ItemCollection';
|
|
|
38
38
|
export { default as ItemList } from './components/ItemList';
|
|
39
39
|
export { default as Items } from './components/Items';
|
|
40
40
|
export { default as KeyboardField } from './components/KeyboardField';
|
|
41
|
+
export { default as KeyValuePairs } from './components/KeyValuePairs';
|
|
41
42
|
export { default as LazyDocument } from './components/LazyDocument';
|
|
42
43
|
export { default as LazyImage } from './components/LazyImage';
|
|
43
44
|
export { default as LazyVideo } from './components/LazyVideo';
|
|
@@ -59,6 +60,8 @@ export { default as NestedAccordion } from './components/NestedAccordion';
|
|
|
59
60
|
export { default as PlayButton } from './components/PlayButton';
|
|
60
61
|
export { default as PhotoViewer } from './components/PhotoViewer';
|
|
61
62
|
export { default as ReferenceCodeDropdown } from './components/ReferenceCodeDropdown';
|
|
63
|
+
export { default as ReferenceCodeFormDropdown } from './components/ReferenceCodeFormDropdown';
|
|
64
|
+
export { default as ReferenceCodeFormLabel } from './components/ReferenceCodeFormLabel';
|
|
62
65
|
export { default as ReferenceCodeModal } from './components/ReferenceCodeModal';
|
|
63
66
|
export { default as ReferenceTableModal } from './components/ReferenceTableModal';
|
|
64
67
|
export { default as ReferenceTablesList } from './components/ReferenceTablesList';
|
|
@@ -77,10 +80,14 @@ export { default as VideoPlayer } from './components/VideoPlayer';
|
|
|
77
80
|
export { default as VideoPlayerButton } from './components/VideoPlayerButton';
|
|
78
81
|
export { default as ViewXML } from './components/ViewXML';
|
|
79
82
|
|
|
83
|
+
// Hooks
|
|
84
|
+
export { default as BatchEdit } from './hooks/BatchEdit';
|
|
85
|
+
|
|
80
86
|
// Types
|
|
81
87
|
export type { EditPageProps } from './components/EditPage';
|
|
82
88
|
export type { FileUploadProps } from './components/FileUploadModal';
|
|
83
89
|
export type { Props as ListProps } from './components/List';
|
|
90
|
+
export type { BatchEditProps } from './hooks/BatchEdit';
|
|
84
91
|
|
|
85
92
|
// Constants
|
|
86
93
|
export { SORT_ASCENDING, SORT_DESCENDING } from './components/DataList';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { type ComponentType } from 'react';
|
|
4
|
+
import { Button, Grid, Input } from 'semantic-ui-react';
|
|
5
|
+
import _ from 'underscore';
|
|
6
|
+
import i18n from '../i18n/i18n';
|
|
7
|
+
import withBatchEdit, { type BatchEditProps } from '../hooks/BatchEdit';
|
|
8
|
+
|
|
9
|
+
type Item = {
|
|
10
|
+
key: string,
|
|
11
|
+
value: string
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type Props = BatchEditProps & {
|
|
15
|
+
items: Array<Item>,
|
|
16
|
+
onChange: (items: Array<Item>) => void
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const KeyValuePairs: ComponentType<any> = withBatchEdit((props: Props) => (
|
|
20
|
+
<div>
|
|
21
|
+
<Button
|
|
22
|
+
basic
|
|
23
|
+
content={i18n.t('Common.buttons.add')}
|
|
24
|
+
icon='plus'
|
|
25
|
+
onClick={props.onAddItem.bind(this)}
|
|
26
|
+
type='button'
|
|
27
|
+
/>
|
|
28
|
+
<Grid
|
|
29
|
+
padded='vertically'
|
|
30
|
+
>
|
|
31
|
+
{ _.map(props.items, (item, index) => (
|
|
32
|
+
<Grid.Row
|
|
33
|
+
columns={3}
|
|
34
|
+
>
|
|
35
|
+
<Grid.Column
|
|
36
|
+
width={8}
|
|
37
|
+
>
|
|
38
|
+
<Input
|
|
39
|
+
fluid
|
|
40
|
+
onChange={props.onUpdateItem.bind(this, index, 'key')}
|
|
41
|
+
placeholder={i18n.t('KeyValuePairs.labels.key')}
|
|
42
|
+
value={item.key}
|
|
43
|
+
/>
|
|
44
|
+
</Grid.Column>
|
|
45
|
+
<Grid.Column
|
|
46
|
+
width={7}
|
|
47
|
+
>
|
|
48
|
+
<Input
|
|
49
|
+
fluid
|
|
50
|
+
onChange={props.onUpdateItem.bind(this, index, 'value')}
|
|
51
|
+
placeholder={i18n.t('KeyValuePairs.labels.value')}
|
|
52
|
+
value={item.value}
|
|
53
|
+
/>
|
|
54
|
+
</Grid.Column>
|
|
55
|
+
<Grid.Column
|
|
56
|
+
width={1}
|
|
57
|
+
>
|
|
58
|
+
<Button
|
|
59
|
+
color='red'
|
|
60
|
+
icon='trash'
|
|
61
|
+
onClick={props.onRemoveItem.bind(this, index)}
|
|
62
|
+
/>
|
|
63
|
+
</Grid.Column>
|
|
64
|
+
</Grid.Row>
|
|
65
|
+
))}
|
|
66
|
+
{ _.isEmpty(props.items) && (
|
|
67
|
+
<Grid.Row
|
|
68
|
+
columns={1}
|
|
69
|
+
>
|
|
70
|
+
<Grid.Column>
|
|
71
|
+
{ i18n.t('Common.labels.noRecords') }
|
|
72
|
+
</Grid.Column>
|
|
73
|
+
</Grid.Row>
|
|
74
|
+
)}
|
|
75
|
+
</Grid>
|
|
76
|
+
</div>
|
|
77
|
+
));
|
|
78
|
+
|
|
79
|
+
export default KeyValuePairs;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import { ReferenceTablesService } from '@performant-software/shared-components';
|
|
4
|
+
import React, { type ComponentType, useEffect, useState } from 'react';
|
|
5
|
+
import { Form } from 'semantic-ui-react';
|
|
6
|
+
import EditModal from './EditModal';
|
|
7
|
+
import ReferenceCodeDropdown from './ReferenceCodeDropdown';
|
|
8
|
+
import ReferenceCodeFormLabel from './ReferenceCodeFormLabel';
|
|
9
|
+
import ReferenceTableModal from './ReferenceTableModal';
|
|
10
|
+
|
|
11
|
+
type Props = {
|
|
12
|
+
error?: boolean,
|
|
13
|
+
label?: string,
|
|
14
|
+
required?: boolean,
|
|
15
|
+
referenceTable: string
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const ReferenceCodeFormDropdown: ComponentType<any> = (props: Props) => {
|
|
19
|
+
const {
|
|
20
|
+
error,
|
|
21
|
+
label,
|
|
22
|
+
required,
|
|
23
|
+
referenceTable: key,
|
|
24
|
+
...rest
|
|
25
|
+
} = props;
|
|
26
|
+
|
|
27
|
+
const [modal, setModal] = useState(false);
|
|
28
|
+
const [dropdownKey, setDropdownKey] = useState(0);
|
|
29
|
+
const [referenceTable, setReferenceTable] = useState({ key });
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Looks up the existing reference table base on the passed key.
|
|
33
|
+
*/
|
|
34
|
+
useEffect(() => (
|
|
35
|
+
ReferenceTablesService
|
|
36
|
+
.fetchByKey(key)
|
|
37
|
+
.then(({ data }) => setReferenceTable((prevTable) => ({
|
|
38
|
+
...prevTable,
|
|
39
|
+
...data.reference_table
|
|
40
|
+
})))
|
|
41
|
+
), [key]);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<>
|
|
45
|
+
<Form.Input
|
|
46
|
+
error={error}
|
|
47
|
+
label={(
|
|
48
|
+
<ReferenceCodeFormLabel
|
|
49
|
+
label={label}
|
|
50
|
+
onClick={() => setModal(true)}
|
|
51
|
+
referenceTable={referenceTable.key}
|
|
52
|
+
/>
|
|
53
|
+
)}
|
|
54
|
+
required={required}
|
|
55
|
+
>
|
|
56
|
+
<ReferenceCodeDropdown
|
|
57
|
+
{...rest}
|
|
58
|
+
id={referenceTable}
|
|
59
|
+
referenceTable={referenceTable.key}
|
|
60
|
+
key={dropdownKey}
|
|
61
|
+
/>
|
|
62
|
+
</Form.Input>
|
|
63
|
+
{ modal && (
|
|
64
|
+
<EditModal
|
|
65
|
+
component={ReferenceTableModal}
|
|
66
|
+
item={referenceTable}
|
|
67
|
+
onClose={() => setModal(false)}
|
|
68
|
+
onSave={(record) => (
|
|
69
|
+
ReferenceTablesService
|
|
70
|
+
.save(record)
|
|
71
|
+
.then(({ data }) => data.reference_table)
|
|
72
|
+
.then(() => setDropdownKey((prevKey) => prevKey + 1))
|
|
73
|
+
.finally(() => setModal(false))
|
|
74
|
+
)}
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
77
|
+
</>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export default ReferenceCodeFormDropdown;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { type ComponentType } from 'react';
|
|
4
|
+
import { withTranslation } from 'react-i18next';
|
|
5
|
+
import {
|
|
6
|
+
Button,
|
|
7
|
+
Header,
|
|
8
|
+
Icon,
|
|
9
|
+
Popup
|
|
10
|
+
} from 'semantic-ui-react';
|
|
11
|
+
import i18n from '../i18n/i18n';
|
|
12
|
+
|
|
13
|
+
type Props = {
|
|
14
|
+
label: string,
|
|
15
|
+
onClick: () => void,
|
|
16
|
+
referenceTable: string
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const ReferenceCodeFormLabel: ComponentType<any> = withTranslation()((props: Props) => (
|
|
20
|
+
<div>
|
|
21
|
+
<label
|
|
22
|
+
htmlFor={props.referenceTable}
|
|
23
|
+
>
|
|
24
|
+
{ props.label }
|
|
25
|
+
</label>
|
|
26
|
+
<Popup
|
|
27
|
+
hoverable
|
|
28
|
+
trigger={(
|
|
29
|
+
<Icon
|
|
30
|
+
name='info circle'
|
|
31
|
+
style={{
|
|
32
|
+
marginLeft: '0.3em'
|
|
33
|
+
}}
|
|
34
|
+
/>
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
<Header
|
|
38
|
+
content={props.label}
|
|
39
|
+
/>
|
|
40
|
+
<p>{ i18n.t('ReferenceCodeFormLabel.content', { name: props.label })}</p>
|
|
41
|
+
<Button
|
|
42
|
+
content={i18n.t('Common.buttons.edit')}
|
|
43
|
+
icon='edit'
|
|
44
|
+
primary
|
|
45
|
+
onClick={props.onClick}
|
|
46
|
+
/>
|
|
47
|
+
</Popup>
|
|
48
|
+
</div>
|
|
49
|
+
));
|
|
50
|
+
|
|
51
|
+
export default ReferenceCodeFormLabel;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import React, { useCallback, type ComponentType } from 'react';
|
|
4
|
+
import _ from 'underscore';
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
items: Array<any>,
|
|
8
|
+
onChange: (items: Array<any>) => void
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const withBatchEdit = (WrappedComponent: ComponentType<any>): any => (props: Props) => {
|
|
12
|
+
/**
|
|
13
|
+
* Adds a new item to the list.
|
|
14
|
+
*
|
|
15
|
+
* @type {(function(): void)|*}
|
|
16
|
+
*/
|
|
17
|
+
const onAddItem = useCallback(() => {
|
|
18
|
+
props.onChange([...props.items, {}]);
|
|
19
|
+
}, [props.items]);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Removes the item at the passed index from the list.
|
|
23
|
+
*
|
|
24
|
+
* @type {(function(*): void)|*}
|
|
25
|
+
*/
|
|
26
|
+
const onRemoveItem = useCallback((findIndex) => {
|
|
27
|
+
props.onChange(_.reject(props.items, (item, index) => index === findIndex));
|
|
28
|
+
}, [props.items]);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Updates the passed attribute of the item at the passed index.
|
|
32
|
+
*
|
|
33
|
+
* @type {(function(number, string, ?Event, {value: *}): void)|*}
|
|
34
|
+
*/
|
|
35
|
+
const onUpdateItem = useCallback((findIndex: number, attribute: string, e: ?Event, { value }) => {
|
|
36
|
+
props.onChange(_.map(props.items, (item, index) => (
|
|
37
|
+
index !== findIndex ? item : ({ ...item, [attribute]: value })
|
|
38
|
+
)));
|
|
39
|
+
}, [props.items]);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<WrappedComponent
|
|
43
|
+
{...props}
|
|
44
|
+
onAddItem={onAddItem}
|
|
45
|
+
onRemoveItem={onRemoveItem}
|
|
46
|
+
onUpdateItem={onUpdateItem}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default withBatchEdit;
|
|
52
|
+
|
|
53
|
+
export type BatchEditProps = {
|
|
54
|
+
onAddItem: () => void,
|
|
55
|
+
onRemoveItem: (index: number) => void,
|
|
56
|
+
onUpdateItem: (index: number, attribute: string, e: Event, data: any) => void
|
|
57
|
+
};
|
package/types/index.js.flow
CHANGED
|
@@ -38,6 +38,7 @@ export { default as ItemCollection } from './components/ItemCollection';
|
|
|
38
38
|
export { default as ItemList } from './components/ItemList';
|
|
39
39
|
export { default as Items } from './components/Items';
|
|
40
40
|
export { default as KeyboardField } from './components/KeyboardField';
|
|
41
|
+
export { default as KeyValuePairs } from './components/KeyValuePairs';
|
|
41
42
|
export { default as LazyDocument } from './components/LazyDocument';
|
|
42
43
|
export { default as LazyImage } from './components/LazyImage';
|
|
43
44
|
export { default as LazyVideo } from './components/LazyVideo';
|
|
@@ -59,6 +60,8 @@ export { default as NestedAccordion } from './components/NestedAccordion';
|
|
|
59
60
|
export { default as PlayButton } from './components/PlayButton';
|
|
60
61
|
export { default as PhotoViewer } from './components/PhotoViewer';
|
|
61
62
|
export { default as ReferenceCodeDropdown } from './components/ReferenceCodeDropdown';
|
|
63
|
+
export { default as ReferenceCodeFormDropdown } from './components/ReferenceCodeFormDropdown';
|
|
64
|
+
export { default as ReferenceCodeFormLabel } from './components/ReferenceCodeFormLabel';
|
|
62
65
|
export { default as ReferenceCodeModal } from './components/ReferenceCodeModal';
|
|
63
66
|
export { default as ReferenceTableModal } from './components/ReferenceTableModal';
|
|
64
67
|
export { default as ReferenceTablesList } from './components/ReferenceTablesList';
|
|
@@ -77,10 +80,14 @@ export { default as VideoPlayer } from './components/VideoPlayer';
|
|
|
77
80
|
export { default as VideoPlayerButton } from './components/VideoPlayerButton';
|
|
78
81
|
export { default as ViewXML } from './components/ViewXML';
|
|
79
82
|
|
|
83
|
+
// Hooks
|
|
84
|
+
export { default as BatchEdit } from './hooks/BatchEdit';
|
|
85
|
+
|
|
80
86
|
// Types
|
|
81
87
|
export type { EditPageProps } from './components/EditPage';
|
|
82
88
|
export type { FileUploadProps } from './components/FileUploadModal';
|
|
83
89
|
export type { Props as ListProps } from './components/List';
|
|
90
|
+
export type { BatchEditProps } from './hooks/BatchEdit';
|
|
84
91
|
|
|
85
92
|
// Constants
|
|
86
93
|
export { SORT_ASCENDING, SORT_DESCENDING } from './components/DataList';
|