Skip to content

Instantly share code, notes, and snippets.

@nzambello
Last active August 5, 2021 14:03
Show Gist options
  • Save nzambello/30949078616328e6ee0293e5b302bb40 to your computer and use it in GitHub Desktop.
Save nzambello/30949078616328e6ee0293e5b302bb40 to your computer and use it in GitHub Desktop.
RichiedentiWidget.jsx for volto form block
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