Last active
January 16, 2022 20:57
-
-
Save DavidKloucek/f3cff595c2ec554b16037baef3e1cf78 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useCallback, useEffect, useState, useRef, Fragment} from 'react'; | |
import React from 'react'; | |
import Select from 'react-select'; | |
const defaultData = { | |
type: 'GroupControl', | |
data: { | |
operator: 'plus', | |
}, | |
children: [ | |
{ | |
type: 'ManufacturerControl', | |
data: { | |
value: [] | |
} | |
}, | |
{ | |
type: 'GroupControl', | |
data: { | |
operator: 'minus' | |
}, | |
children: [ | |
{ | |
type: 'RadioControl', | |
data: { | |
value: "1" | |
} | |
}, | |
{ | |
type: 'RadioControl', | |
data: { | |
value: "1" | |
} | |
}, | |
] | |
} | |
] | |
} | |
const Dump = (data) => ( | |
<pre style={{'fontSize': '13px'}}>{JSON.stringify(data, null, 4)}</pre> | |
) | |
function createDataGroup() { | |
return { | |
type: 'GroupControl', | |
data: { | |
'operator': 'plus' | |
}, | |
children: [] | |
} | |
} | |
function createDataRadio() { | |
return { | |
type: 'RadioControl', | |
data: { | |
'value': '1' | |
} | |
} | |
} | |
function createDataManufacturer() { | |
return { | |
type: 'ManufacturerControl', | |
data: { | |
'value': [] | |
} | |
} | |
} | |
function fetchManufacturers() { | |
return new Promise((success, fail) => { | |
window.setTimeout(() => success([ | |
{label: 'Altisport', value: 1}, | |
{label: 'Alpine Pro', value: 2}, | |
{label: 'Kixmi', value: 3}, | |
]), 1000) | |
}) | |
} | |
function ManufacturerControl({setData, depth, deleteMe, ...obj}) { | |
const [isLoading, setIsLoading] = useState(false) | |
const [options, setOptions] = useState(null) | |
async function handleFocus() { | |
if (options === null) { | |
setIsLoading(true) | |
setOptions(await fetchManufacturers()) | |
setIsLoading(false) | |
} | |
} | |
function handleChange(v) { | |
setData(d => ({...d, data: { | |
value: v === null ? [] : v.map(x => x.value) | |
}})) | |
} | |
const optionsArr = options === null ? [] : options; | |
return ( | |
<div> | |
<label>Značka: </label> | |
<span style={{width: '350px', display: 'inline-block'}}> | |
<Select | |
onFocus={handleFocus} | |
onChange={handleChange} | |
value={optionsArr.filter(o => obj.data.value.includes(o.value))} | |
noOptionsMessage={() => 'Nenalezeno'} | |
isLoading={isLoading} | |
loadingMessage={() => 'Načítám..'} | |
options={optionsArr} | |
placeholder="Vyberte.." | |
isMulti | |
/> | |
</span> | |
<button type="button" onClick={deleteMe}>×</button> | |
</div> | |
) | |
} | |
function GroupControl({setData, depth, deleteMe, ...obj}) { | |
function toggle() { | |
console.log('toggle') | |
setData(d => ({...d, | |
data: { | |
...d.data, | |
operator: d.data.operator === 'plus' ? 'minus' : 'plus' | |
} | |
})) | |
} | |
function addGroup() { | |
setData(d => ({...d, | |
children: d.children.concat(createDataGroup()) | |
})) | |
} | |
function addRadio() { | |
setData(d => ({...d, | |
children: d.children.concat(createDataRadio()) | |
})) | |
} | |
function addManufacturer() { | |
setData(d => ({...d, | |
children: d.children.concat(createDataManufacturer()) | |
})) | |
} | |
return ( | |
<div style={{ | |
'padding': '9px', | |
'margin': '9px 6px', | |
'border': '2px solid '+'rgba(0,0,0,.1)', | |
'borderRadius': '3px' | |
}}> | |
{obj.children.length === 0 && ( | |
<p>Přidejte podmínku nebo skupinu</p> | |
)} | |
{obj.children.map((sub, index) => ( | |
<Fragment key={index}> | |
<Walker | |
depth={depth} | |
data={sub} | |
deleteMe={() => { | |
setData(d => ({...d, children: d.children.filter((x, i) => i !== index)})) | |
}} | |
setData={(d) => { | |
setData(s => { | |
return {...s, children: s.children.map((x, i) => { | |
return i === index ? d(x) : x | |
})} | |
}) | |
}} | |
/> | |
{index+1 !== obj.children.length ? ( | |
<p onClick={toggle} className={"op-"+obj.data.operator}> | |
{obj.data.operator === 'plus' ? ( | |
<strong style={{'color': 'green'}}>Zároveň</strong> | |
) : ( | |
<strong style={{'color': 'red'}}>Nebo</strong> | |
)} | |
</p> | |
) : ( | |
<Fragment> | |
</Fragment> | |
)} | |
</Fragment> | |
))} | |
<div style={{ | |
'padding': '10px 0 0 0', | |
'margin': '15px 0 0 0', | |
'borderTop': '2px solid rgba(0,0,0,.1)' | |
}}> | |
Přidat: | |
<button type="button" onClick={addGroup}>Skupinu</button> | |
<button type="button" onClick={addManufacturer}>Značku</button> | |
<button type="button" onClick={addRadio}>Radio</button> | |
....... | |
{depth > 1 && ( | |
<button type="button" onClick={deleteMe}>×</button> | |
)} | |
</div> | |
</div> | |
) | |
} | |
function RadioControl({data, setData, depth, deleteMe, ...other}) { | |
function onChange(v) { | |
setData(d => ({...d, data: { | |
value: v.target.value | |
}})) | |
} | |
return ( | |
<div> | |
<label> | |
<input type="radio" onChange={onChange} value="1" checked={data.value === '1'} /> Ano | |
</label> | |
<label style={{'margin': '0 0 0 15px'}}> | |
<input type="radio" onChange={onChange} value="2" checked={data.value === '2'} /> Ne | |
</label> | |
<button type="button" onClick={deleteMe}>×</button> | |
</div> | |
) | |
} | |
const components = { | |
GroupControl, RadioControl, ManufacturerControl | |
} | |
function Walker({data, setData, depth, deleteMe}) { | |
if (!('type' in data)) { | |
console.log(data) | |
throw new Error('Chybi "type" v '+JSON.stringify(data, null, 4)); | |
} | |
if (!(data.type in components)) { | |
console.log(data.type, components) | |
throw new Error() | |
} | |
let comp = React.createElement(components[data.type], { | |
...data, | |
depth: depth+1, | |
deleteMe, | |
setData: (d) => { | |
setData(s => d(s)) | |
} | |
}) | |
return ( | |
<Fragment> | |
{comp} | |
</Fragment> | |
) | |
} | |
export function Rules() { | |
const [data, setData] = useState(defaultData) | |
return ( | |
<div> | |
<Walker | |
data={data} | |
setData={(d) => { | |
setData(s => d(s)) | |
}} | |
depth={0} | |
/> | |
<Dump {...data} /> | |
</div> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment