Files
Investidor-V2/resources/js/pages/management/editor.tsx
T
nala 67dad461d9
tests / ci (push) Canceled after 0s
provincias
2026-09-29 14:14:06 +02:00

227 lines
10 KiB
TypeScript

import { Link, useForm } from "@inertiajs/react";
import InvestmentCoordinates from "@/components/investment-coordinates";
import { TerritoryLevel, type TerritoryOption } from "@/components/investment-territory";
import { useState } from "react";
import { Management, Field, button, control, states } from "./shared";
type Values = Record<string, string | boolean>;
type Entry = Record<string, string | number | boolean | null> & { id: number };
const opportunityFields = {
reference: "Referência",
title: "Título",
slug: "Slug (endereço)",
summary: "Resumo",
description: "Descrição",
promoter_name: "Promotor",
promoter_type: "Tipo de promotor",
estimated_investment_amount: "Investimento estimado",
estimated_investment_currency: "Moeda (código de três letras)",
financing_modality: "Modalidade de financiamento",
expected_impact: "Impacto esperado",
};
const sectorFields = {
name: "Nome",
slug: "Slug (endereço)",
short_description: "Descrição curta",
description: "Descrição",
sort_order: "Ordem de apresentação",
};
const maturities = [
"Ideia identificada",
"Pré-estudo disponível",
"Estudo de viabilidade em curso",
"Projecto estruturado",
"Pronto para investimento",
"Em negociação ou implementação",
];
export default function Editor({
resource,
record,
sectors,
territoryPath = [],
}: {
resource: "sectors" | "opportunities";
record: Entry | null;
sectors: { id: number; name: string }[];
territoryPath?: TerritoryOption[];
}) {
const isSector = resource === "sectors";
const fields = isSector ? sectorFields : opportunityFields;
const initial: Values = Object.fromEntries(
Object.keys(fields).map((key) => [
key,
String(
record?.[key] ??
(key === "estimated_investment_currency"
? "USD"
: key === "sort_order"
? "0"
: ""),
),
]),
);
if (isSector) initial.is_active = Boolean(record?.is_active ?? true);
else {
initial.sector_id = String(record?.sector_id ?? "");
initial.maturity_level = String(record?.maturity_level ?? "");
initial.status = String(record?.status ?? "draft");
initial.is_featured = Boolean(record?.is_featured ?? false);
initial.territory_version = String(record?.territory_version ?? 0);
["province_id", "district_id", "admin_post_id", "locality_id"].forEach((field, index) => {
initial[field] = territoryPath[index]?.id ?? "";
});
}
const form = useForm<Values>(initial);
const [creationPath, setCreationPath] = useState<TerritoryOption[]>(territoryPath);
return (
<Management
title={`${record ? "Editar" : "Criar"} ${isSector ? "sector" : "oportunidade"}`}
>
{!isSector && record && (
<Link className="underline" href={`/management/opportunities/${record.id}/context`}>
Gerir clusters, corredores, projectos, educação e necessidades
</Link>
)}
<form
className="max-w-3xl space-y-5"
onSubmit={(event) => {
event.preventDefault();
if (record) form.put(`/management/${resource}/${record.id}`);
else form.post(`/management/${resource}`);
}}
>
<fieldset disabled={form.processing} className="space-y-5">
{!isSector && (
<div className="grid gap-4 md:grid-cols-2">
{(
[
"province_id",
"district_id",
"admin_post_id",
"locality_id",
] as const
).map((key, index) => (
<TerritoryLevel
key={`${key}-${creationPath[index - 1]?.id ?? ""}`}
index={index}
parent={creationPath[index - 1]?.id ?? ""}
selected={creationPath[index]}
endpoint="/management/territory-options"
fieldError={form.errors[key]}
onChange={(value) => {
const path = [
...creationPath.slice(0, index),
...(value ? [value] : []),
];
setCreationPath(path);
form.setData((data) => ({
...data,
province_id: path[0]?.id ?? "",
district_id: path[1]?.id ?? "",
admin_post_id: path[2]?.id ?? "",
locality_id: path[3]?.id ?? "",
}));
}}
/>
))}
</div>
)}
{Object.entries(fields).map(([key, label]) => (
<Field key={key} label={label} error={form.errors[key]}>
{[
"description",
"summary",
"short_description",
"expected_impact",
].includes(key) ? (
<textarea
className={control}
rows={key === "description" ? 6 : 3}
value={String(form.data[key])}
onChange={(e) => form.setData(key, e.target.value)}
/>
) : (
<input
className={control}
value={String(form.data[key])}
onChange={(e) => form.setData(key, e.target.value)}
/>
)}
</Field>
))}
{!isSector && (
<>
<Field label="Sector" error={form.errors.sector_id}>
<select
className={control}
value={String(form.data.sector_id)}
onChange={(e) => form.setData("sector_id", e.target.value)}
>
<option value="">Seleccione</option>
{sectors.map((sector) => (
<option key={sector.id} value={sector.id}>
{sector.name}
</option>
))}
</select>
</Field>
<Field label="Maturidade" error={form.errors.maturity_level}>
<select
className={control}
value={String(form.data.maturity_level)}
onChange={(e) => form.setData("maturity_level", e.target.value)}
>
<option value="">Por indicar</option>
{maturities.map((label, index) => (
<option key={label} value={index + 1}>
{label}
</option>
))}
</select>
</Field>
<Field label="Estado" error={form.errors.status}>
<select
className={control}
value={String(form.data.status)}
onChange={(e) => form.setData("status", e.target.value)}
>
{["draft", "published", "archived"].map((key) => (
<option key={key} value={key}>
{states[key]}
</option>
))}
</select>
</Field>
</>
)}
<Field
label={isSector ? "Activo" : "Em destaque"}
error={form.errors[isSector ? "is_active" : "is_featured"]}
>
<input
type="checkbox"
checked={Boolean(form.data[isSector ? "is_active" : "is_featured"])}
onChange={(e) =>
form.setData(
isSector ? "is_active" : "is_featured",
e.target.checked,
)
}
/>
</Field>
<div className="flex gap-4">
<button className={button} disabled={form.processing}>
{form.processing ? "A guardar…" : "Guardar"}
</button>
<Link className="p-2 underline" href={`/management/${resource}`}>
Cancelar
</Link>
</div>
</fieldset>
</form>
{!isSector && record && <InvestmentCoordinates id={record.id} />}
</Management>
);
}