Files
Investidor-V2/resources/js/components/investment-coordinates.tsx
T
nala 1106509116
tests / ci (push) Canceled after 0s
vrsao 2
2026-10-08 14:02:01 +02:00

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>
);
}