234 lines
9.7 KiB
TypeScript
234 lines
9.7 KiB
TypeScript
import { useEffect, useId } from 'react';
|
|
import CountrySelect, { type Country } from './country-select';
|
|
import { Field, input, button, card } from '@/pages/investment/shared';
|
|
import {
|
|
useInvestmentProfileEditor,
|
|
type OrganizationRecord,
|
|
} from '@/lib/investment-profile-editor';
|
|
|
|
export default function OrganizationCountryEditor({
|
|
organization,
|
|
countries,
|
|
actorId,
|
|
reportDirty,
|
|
}: {
|
|
organization: OrganizationRecord;
|
|
countries: Country[];
|
|
actorId: number;
|
|
reportDirty: (id: string, dirty: boolean) => void;
|
|
}) {
|
|
const fields = ['country', 'source_reference'];
|
|
const editor = useInvestmentProfileEditor(
|
|
{
|
|
id: organization.id,
|
|
version: organization.version,
|
|
payload: {
|
|
country: organization.country ?? '',
|
|
source_reference: organization.provenance?.reference ?? '',
|
|
},
|
|
},
|
|
fields,
|
|
false,
|
|
actorId,
|
|
'organization-' + organization.id,
|
|
reportDirty,
|
|
organization,
|
|
);
|
|
const id = useId(),
|
|
disabled =
|
|
!editor.mayEdit ||
|
|
editor.busy ||
|
|
editor.uncertain ||
|
|
editor.blocked;
|
|
useEffect(() => {
|
|
if (Object.keys(editor.errors).length)
|
|
document
|
|
.getElementById(id)
|
|
?.querySelector<HTMLElement>('[aria-invalid="true"]')
|
|
?.focus();
|
|
}, [editor.errors, id]);
|
|
return (
|
|
<section
|
|
className={card}
|
|
aria-label={'País de constituição: ' + organization.name}
|
|
>
|
|
<h3 className="text-xl font-bold">{organization.name}</h3>
|
|
<p>
|
|
Versão guardada: {organization.version}.{' '}
|
|
{organization.provenance?.kind === 'representative_declaration'
|
|
? 'País declarado pelo representante.'
|
|
: 'Fonte do país ainda não informada.'}
|
|
</p>
|
|
{!editor.mayEdit && (
|
|
<p role="status">
|
|
Consulta do país de constituição. A sua representação actual
|
|
não permite alterar esta informação.
|
|
</p>
|
|
)}
|
|
<form
|
|
id={id}
|
|
className="mt-4 space-y-4"
|
|
aria-label={'País da organização: ' + organization.name}
|
|
onSubmit={(event) => {
|
|
event.preventDefault();
|
|
void editor.save();
|
|
}}
|
|
>
|
|
<Field label="País de constituição da organização">
|
|
<CountrySelect
|
|
id={id + '-country'}
|
|
label="País de constituição da organização"
|
|
required
|
|
countries={countries}
|
|
value={editor.draft.country}
|
|
disabled={disabled}
|
|
error={editor.errors.country}
|
|
onChange={(country) =>
|
|
editor.change('country', country)
|
|
}
|
|
/>
|
|
</Field>
|
|
<label htmlFor={id + '-source'}>
|
|
Fonte ou referência deste país
|
|
</label>
|
|
<textarea
|
|
id={id + '-source'}
|
|
aria-label="Fonte ou referência deste país"
|
|
className={input}
|
|
value={editor.draft.source_reference}
|
|
disabled={disabled}
|
|
required
|
|
minLength={5}
|
|
maxLength={2000}
|
|
rows={3}
|
|
aria-invalid={!!editor.errors.source_reference}
|
|
aria-describedby={
|
|
editor.errors.source_reference
|
|
? id + '-source-error'
|
|
: undefined
|
|
}
|
|
onChange={(event) =>
|
|
editor.change('source_reference', event.target.value)
|
|
}
|
|
/>
|
|
{editor.errors.source_reference && (
|
|
<p id={id + '-source-error'} role="alert">
|
|
{editor.errors.source_reference}
|
|
</p>
|
|
)}
|
|
{Object.entries(editor.errors)
|
|
.filter(([key]) => !fields.includes(key))
|
|
.map(([key, value]) => (
|
|
<p role="alert" key={key}>
|
|
{value}
|
|
</p>
|
|
))}
|
|
{editor.error && <p role="alert">{editor.error}</p>}
|
|
{editor.notice && <p role="status">{editor.notice}</p>}
|
|
{editor.stale && (
|
|
<p role="alert">
|
|
O país ou outra informação da organização foi alterado.
|
|
A sua preparação foi conservada; consulte e compare
|
|
antes de guardar.
|
|
</p>
|
|
)}
|
|
<div className="flex flex-wrap gap-3">
|
|
{editor.mayEdit && (
|
|
<button
|
|
className={button}
|
|
disabled={
|
|
editor.busy ||
|
|
editor.reading ||
|
|
editor.blocked ||
|
|
(editor.stale && !editor.uncertain)
|
|
}
|
|
>
|
|
{editor.uncertain
|
|
? 'Repetir o mesmo pedido'
|
|
: 'Guardar país da organização'}
|
|
</button>
|
|
)}
|
|
<button
|
|
className={button}
|
|
type="button"
|
|
disabled={editor.busy || editor.reading}
|
|
onClick={() => void editor.refresh()}
|
|
>
|
|
Consultar país guardado
|
|
</button>
|
|
</div>
|
|
{editor.remote && (
|
|
<section
|
|
aria-label="Comparação do país da organização"
|
|
className="space-y-3 rounded border p-3"
|
|
>
|
|
<p>
|
|
Versão guardada: {editor.remote.version}; versão da
|
|
preparação: {editor.base.version}.
|
|
</p>
|
|
<table className="w-full text-left text-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Campo</th>
|
|
<th>Preparação nesta página</th>
|
|
<th>Registo guardado</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{fields
|
|
.filter(
|
|
(key) =>
|
|
editor.draft[key] !==
|
|
editor.remote?.payload[key],
|
|
)
|
|
.map((key) => (
|
|
<tr key={key}>
|
|
<th>
|
|
{key === 'country'
|
|
? 'País de constituição'
|
|
: 'Fonte ou referência'}
|
|
</th>
|
|
<td className="break-words">
|
|
{editor.draft[key] ||
|
|
'Não informado'}
|
|
</td>
|
|
<td className="break-words">
|
|
{editor.remote?.payload[key] ||
|
|
'Não informado'}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
{editor.mayEdit && !editor.uncertain && (
|
|
<div className="flex flex-wrap gap-3">
|
|
<button
|
|
type="button"
|
|
className={button}
|
|
onClick={() => editor.adopt(true)}
|
|
>
|
|
Usar versão actual e manter a preparação
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className={button}
|
|
onClick={() => {
|
|
if (
|
|
window.confirm(
|
|
'Substituir a preparação desta organização pelos valores guardados?',
|
|
)
|
|
)
|
|
editor.adopt(false);
|
|
}}
|
|
>
|
|
Carregar os valores guardados
|
|
</button>
|
|
</div>
|
|
)}
|
|
</section>
|
|
)}
|
|
</form>
|
|
</section>
|
|
);
|
|
}
|