diff --git a/root/components/forms.tt b/root/components/forms.tt index 974f4bf9c7b..87611b156c2 100644 --- a/root/components/forms.tt +++ b/root/components/forms.tt @@ -153,7 +153,8 @@ [% END %] [%- END -%] -[%- MACRO form_row_text_list(r, field_name, label, item_name) BLOCK -%] +[%- MACRO form_row_text_list(r, field_name, label, item_name) BLOCK # Converted to React at root/static/scripts/edit/components/FormTowTextList.js +-%] [% WRAPPER form_row %]
diff --git a/root/static/scripts/edit/components/AddButton.js b/root/static/scripts/edit/components/AddButton.js new file mode 100644 index 00000000000..cdef659bdee --- /dev/null +++ b/root/static/scripts/edit/components/AddButton.js @@ -0,0 +1,25 @@ +/* + * @flow strict + * Copyright (C) 2024 MetaBrainz Foundation + * + * This file is part of MusicBrainz, the open internet music database, + * and is licensed under the GPL version 2, or (at your option) any + * later version: http://www.gnu.org/licenses/gpl-2.0.txt + */ + +component AddButton( + onClick: (event: SyntheticEvent) => void, + label?: string, +) { + if (label == null) { + return + ); +} + +export default AddButton; diff --git a/root/static/scripts/edit/components/FormRowTextList.js b/root/static/scripts/edit/components/FormRowTextList.js new file mode 100644 index 00000000000..b9be1b56ed0 --- /dev/null +++ b/root/static/scripts/edit/components/FormRowTextList.js @@ -0,0 +1,139 @@ +/* + * @flow strict + * Copyright (C) 2024 MetaBrainz Foundation + * + * This file is part of MusicBrainz, the open internet music database, + * and is licensed under the GPL version 2, or (at your option) any + * later version: http://www.gnu.org/licenses/gpl-2.0.txt + */ + +import React, {useState} from 'react'; + +import AddButton from './AddButton.js'; +import FieldErrors from './FieldErrors.js'; +import FormLabel from './FormLabel.js'; +import FormRow from './FormRow.js'; +import RemoveButton from './RemoveButton.js'; + +type TextListRowProps = { + +index?: number, + +name: string, + +onChange?: (event: SyntheticEvent) => void, + +onRemove?: (event: SyntheticEvent) => void, + +template?: boolean, + +value?: string, +}; + +component TextListRow(...{ + index = 0, + name, + onChange = () => {}, + onRemove = () => {}, + template = false, + value = '', +}: TextListRowProps) { + if (template) { + return ( +
+ + +
+ ); + } + + return ( +
+ + +
+ ); +} + +const initialRows = (repeatable: RepeatableFieldT>) => { + if (repeatable.field.length === 0) { + return [{name: repeatable.html_name + '.0', value: ''}]; + } + + return repeatable.field.map((field, index) => ({ + name: repeatable.html_name + '.' + index, + value: field.value ?? '', + })); +}; + +component FormRowTextList( + repeatable: RepeatableFieldT>, + label: string, + itemName: string, + required: boolean = false, +) { + const newRow = (name: string, value: string, index: number) => { + return {name: name + '.' + index, value}; + }; + + const [rows, setRows] = useState(initialRows(repeatable)); + + const add = () => { + const index = rows.length; + + setRows([...rows, newRow(repeatable.html_name, '', index)]); + }; + + const change = (index: number, value: string) => { + const newRows = [...rows]; + newRows[index] = newRow(repeatable.html_name, value, index); + setRows(newRows); + }; + + const removeRow = (index: number) => { + if (rows.length === 1) { + setRows([newRow(repeatable.html_name, '', 0)]); + return; + } + + setRows(rows.filter((_, i) => i !== index)); + }; + + return ( + + + +
+ + + {rows.map((field, index) => ( + change(index, event.currentTarget.value)} + onRemove={() => removeRow(index)} + value={field.value} + /> + ))} + +
+ +
+
+ + +
+ ); +} + +export default FormRowTextList;