124 lines
4.5 KiB
TypeScript
124 lines
4.5 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { api } from '@/pages/investment/shared';
|
|
|
|
export default function InvestmentCoordinates({ id }: { id: number | string }) {
|
|
const [data, setData] = useState({
|
|
version: 0,
|
|
latitude: '',
|
|
longitude: '',
|
|
source_reference: '',
|
|
});
|
|
const [ready, setReady] = useState(false);
|
|
const [confirmed, setConfirmed] = useState(false);
|
|
const [busy, setBusy] = useState(false);
|
|
const [message, setMessage] = useState('');
|
|
useEffect(() => {
|
|
let active = true;
|
|
api(`/management/opportunities/${id}/coordinates`)
|
|
.then((result) => {
|
|
if (active) {
|
|
setData({
|
|
...result,
|
|
latitude: String(result.latitude ?? ''),
|
|
longitude: String(result.longitude ?? ''),
|
|
});
|
|
setReady(true);
|
|
}
|
|
})
|
|
.catch((e) => {
|
|
if (active) setMessage(e.message);
|
|
});
|
|
return () => {
|
|
active = false;
|
|
};
|
|
}, [id]);
|
|
return (
|
|
<form
|
|
className="my-6 space-y-3 rounded border p-4"
|
|
onSubmit={async (event) => {
|
|
event.preventDefault();
|
|
setBusy(true);
|
|
try {
|
|
const result = await api(
|
|
`/management/opportunities/${id}/coordinates`,
|
|
{
|
|
...data,
|
|
confirmed_site: confirmed,
|
|
},
|
|
);
|
|
setData((previous) => ({
|
|
...previous,
|
|
version: result.version,
|
|
}));
|
|
setMessage(
|
|
'Coordenadas guardadas. O marcador acompanha a publicação da oportunidade.',
|
|
);
|
|
} catch (e) {
|
|
setMessage(
|
|
e instanceof Error ? e.message : 'Falha ao guardar.',
|
|
);
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
}}
|
|
>
|
|
<h2 className="text-lg font-bold">
|
|
Posição do investimento no mapa
|
|
</h2>
|
|
<p>
|
|
Registe a posição do local em WGS84 e a referência que a
|
|
confirma.
|
|
</p>
|
|
<div className="grid gap-3 md:grid-cols-2">
|
|
{(['latitude', 'longitude'] as const).map((field) => (
|
|
<label key={field}>
|
|
{field === 'latitude' ? 'Latitude' : 'Longitude'}
|
|
<input
|
|
className="w-full rounded border p-2"
|
|
type="number"
|
|
step="any"
|
|
min={field === 'latitude' ? -90 : -180}
|
|
max={field === 'latitude' ? 90 : 180}
|
|
required
|
|
value={data[field]}
|
|
onChange={(e) =>
|
|
setData({ ...data, [field]: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
))}
|
|
</div>
|
|
<label className="block">
|
|
Fonte das coordenadas
|
|
<input
|
|
className="w-full rounded border p-2"
|
|
required
|
|
minLength={10}
|
|
maxLength={2000}
|
|
value={data.source_reference}
|
|
onChange={(e) =>
|
|
setData({ ...data, source_reference: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="flex gap-2">
|
|
<input
|
|
type="checkbox"
|
|
required
|
|
checked={confirmed}
|
|
onChange={(e) => setConfirmed(e.target.checked)}
|
|
/>
|
|
Confirmo que esta posição corresponde ao local do investimento e
|
|
pode ser divulgada quando a ficha estiver publicada.
|
|
</label>
|
|
<button
|
|
className="bg-primary text-primary-foreground rounded px-4 py-2 disabled:opacity-50"
|
|
disabled={!ready || busy}
|
|
>
|
|
Guardar coordenadas
|
|
</button>
|
|
{message && <p role="status">{message}</p>}
|
|
</form>
|
|
);
|
|
}
|