Last active
August 5, 2021 14:03
-
-
Save nzambello/30949078616328e6ee0293e5b302bb40 to your computer and use it in GitHub Desktop.
RichiedentiWidget.jsx for volto form block
This file contains 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 React from 'react'; | |
import { defineMessages, useIntl } from 'react-intl'; | |
import { | |
Accordion, | |
AccordionHeader, | |
AccordionBody, | |
Input, | |
Button, | |
Icon, | |
FormGroup, | |
Label, | |
} from 'design-react-kit/dist/design-react-kit'; | |
import { Checkbox } from '@italia/components'; | |
const messages = defineMessages({ | |
add: { | |
id: 'add', | |
defaultMessage: 'Aggiungi', | |
}, | |
addPeople: { | |
id: 'addPeople', | |
defaultMessage: 'Aggiungi persone per cui richiedi il servizio', | |
}, | |
delete: { | |
id: 'delete', | |
defaultMessage: 'Elimina', | |
}, | |
selectPlaceholder: { | |
id: 'selectPlaceholder', | |
defaultMessage: 'Per chi compili questa richiesta?', | |
}, | |
richiedoPerAltri: { | |
id: 'richiedoPerAltri', | |
defaultMessage: 'Richiedo per altri', | |
}, | |
nome: { | |
id: 'nome', | |
defaultMessage: 'Nome', | |
}, | |
cognome: { | |
id: 'Cognome', | |
defineMessages: 'Cognome', | |
}, | |
dataNascita: { | |
id: 'dataNascita', | |
defaultMessage: 'Data di nascita', | |
}, | |
luogoNascita: { | |
id: 'luogoNascita', | |
defaultMessage: 'Luogo di nascita', | |
}, | |
codiceFiscale: { id: 'codiceFiscale', defaultMessage: 'Codice fiscale' }, | |
codiceID: { | |
id: 'codiceID', | |
defaultMessage: 'Numero del documento di riconoscimento', | |
}, | |
}); | |
const familyFields = [ | |
'nome', | |
'cognome', | |
'dataNascita', | |
'luogoNascita', | |
'codiceFiscale', | |
'codiceID', | |
]; | |
const matchCF = (v) => | |
v.match( | |
/^(?:[A-Z][AEIOU][AEIOUX]|[B-DF-HJ-NP-TV-Z]{2}[A-Z]){2}(?:[\dLMNP-V]{2}(?:[A-EHLMPR-T](?:[04LQ][1-9MNP-V]|[15MR][\dLMNP-V]|[26NS][0-8LMNP-U])|[DHPS][37PT][0L]|[ACELMRT][37PT][01LM]|[AC-EHLMPR-T][26NS][9V])|(?:[02468LNQSU][048LQU]|[13579MPRTV][26NS])B[26NS][9V])(?:[A-MZ][1-9MNP-V][\dLMNP-V]{2}|[A-M][0L](?:[1-9MNP-V][\dLMNP-V]|[0L][1-9MNP-V]))[A-Z]$/i, | |
); | |
export const isValid = (formData, name) => { | |
let valid = true; | |
if (!formData[name]?.value?.richiedoPerAltri) return true; | |
if (!formData[name]?.value?.richiedenti) return false; | |
if (formData[name]?.value?.richiedenti.length < 1) return false; | |
formData[name].value.richiedenti.forEach((m) => { | |
familyFields.forEach((f) => { | |
if (m[f]?.length <= 0) valid = false; | |
else if (f === 'codiceFiscale' && !matchCF(m[f])) valid = false; | |
}); | |
}); | |
return valid; | |
}; | |
const RichiedentiWidget = ({ | |
id, | |
name, | |
title, | |
description, | |
onChange, | |
formHasErrors = false, | |
value = { richiedoPerAltri: false, richiedenti: [] }, | |
}) => { | |
const intl = useIntl(); | |
const [activeAccIndex, setActiveAccIndex] = React.useState(null); | |
return ( | |
<div className="form-group"> | |
<label htmlFor={`field-${id}`} className="active"> | |
{title} | |
</label> | |
{description && <small className="help px-2">{description}</small>} | |
<div className="form-richiedenti-widget px-2 my-3" id={`field-${id}`}> | |
<FormGroup check tag="div"> | |
<Checkbox | |
id="richiedoPerAltri" | |
checked={value.richiedoPerAltri} | |
onChange={(e) => { | |
onChange(name, { ...value, richiedoPerAltri: e.target.checked }); | |
}} | |
/> | |
<Label | |
check | |
htmlFor="richiedoPerAltri" | |
tag="label" | |
widths={['xs', 'sm', 'md', 'lg', 'xl']} | |
> | |
{intl.formatMessage(messages.richiedoPerAltri)} | |
</Label> | |
</FormGroup> | |
{value.richiedoPerAltri && ( | |
<div | |
className="px-2" | |
style={ | |
formHasErrors && !isValid({ [name]: { value: value } }, name) | |
? { border: '1px solid #d9364f', margin: '0.5rem 0' } | |
: null | |
} | |
> | |
{value.richiedenti.length > 0 ? ( | |
<Accordion className="my-4"> | |
{value.richiedenti.map((r, i) => ( | |
<div key={`richiedente-${i}`}> | |
<AccordionHeader | |
active={activeAccIndex === i} | |
onToggle={(e) => { | |
e.preventDefault(); | |
activeAccIndex === i | |
? setActiveAccIndex(null) | |
: setActiveAccIndex(i); | |
}} | |
tag="button" | |
aria-controls={`richiedente-${i}`} | |
id={`header-richiedente-${i}`} | |
> | |
{`Richiedente ${i + 1}${r.nome || r.cognome ? ':' : ''} ${ | |
r.nome || '' | |
} ${r.cognome || ''}`} | |
</AccordionHeader> | |
<AccordionBody | |
active={activeAccIndex === i} | |
id={`richiedente-${i}`} | |
aria-labelledby={`field-${id} header-richiedente-${i}`} | |
aria-hidden={!activeAccIndex === i} | |
role="region" | |
> | |
<div className="my-4 mx-2"> | |
{familyFields.map((field) => ( | |
<Input | |
key={field} | |
type={field === 'dataNascita' ? 'date' : 'text'} | |
id={`richiedente-${i}-${field}`} | |
name={field} | |
label={intl.formatMessage(messages[field])} | |
required | |
invalid={ | |
field === 'codiceFiscale' && r[field]?.length | |
? !matchCF(r[field]) | |
: false | |
} | |
onChange={(e) => { | |
let richiedenti = [...value.richiedenti]; | |
richiedenti[i][field] = e.target.value; | |
onChange(name, { ...value, richiedenti }); | |
}} | |
value={r[field] ?? ''} | |
/> | |
))} | |
<Button | |
primary | |
outline | |
onClick={() => { | |
let richiedenti = [...value.richiedenti]; | |
richiedenti.splice(i, 1); | |
onChange(name, { ...value, richiedenti }); | |
}} | |
title={intl.formatMessage(messages.delete)} | |
> | |
<Icon | |
color="primary" | |
icon="it-delete" | |
padding={false} | |
size="sm" | |
/> | |
</Button> | |
</div> | |
</AccordionBody> | |
</div> | |
))} | |
</Accordion> | |
) : ( | |
<p className="my-3 px-2"> | |
{intl.formatMessage(messages.addPeople)} | |
</p> | |
)} | |
<Button | |
primary | |
outline | |
className="mx-2" | |
onClick={() => { | |
onChange(name, { | |
...value, | |
richiedenti: [ | |
...value.richiedenti, | |
familyFields.reduce( | |
(acc, val) => ({ | |
...acc, | |
[val]: '', | |
}), | |
{}, | |
), | |
], | |
}); | |
setActiveAccIndex(value.length); | |
}} | |
title={intl.formatMessage(messages.add)} | |
> | |
<Icon color="primary" icon="it-plus" padding={false} size="sm" /> | |
</Button> | |
</div> | |
)} | |
</div> | |
</div> | |
); | |
}; | |
export default RichiedentiWidget; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment