234 lines
9.8 KiB
TypeScript
234 lines
9.8 KiB
TypeScript
import { useState } from "react";
|
|
import { Link, usePage } from "@inertiajs/react";
|
|
export type SectorResourceArea = {
|
|
id: string;
|
|
group_ids: string[];
|
|
title: string;
|
|
locations_text: string;
|
|
location_labels: string[];
|
|
market_evidence: string;
|
|
value_chain: string;
|
|
indicative_location: string;
|
|
promotion_ready: boolean;
|
|
source_row: string;
|
|
};
|
|
export type SectorResourceSelection = {
|
|
sector_slug: string;
|
|
key: string;
|
|
group_id?: string | null;
|
|
group_name?: string | null;
|
|
area_id: string;
|
|
title: string;
|
|
location_label: string | null;
|
|
locations_text: string;
|
|
value_chain: string;
|
|
source_sha256: string;
|
|
reference_date: string;
|
|
href: string;
|
|
};
|
|
export type SectorResourceData = {
|
|
sector_slug: string;
|
|
title: string;
|
|
introduction: string;
|
|
group_label: string;
|
|
resource_heading: string;
|
|
resource_notice: string;
|
|
background: {title:string;paragraphs:string[]}[];
|
|
source_sha256: string;
|
|
reference_date: string;
|
|
groups: { id: string; name: string; locations_text: string; location_labels: string[] }[];
|
|
areas: SectorResourceArea[];
|
|
projects: string[];
|
|
indicators: { label: string; value: string; source: string }[];
|
|
risks: string[];
|
|
sources: string[];
|
|
source_links?: {title:string;url:string}[];
|
|
};
|
|
export default function SectorResourceReference({ data }: { data: SectorResourceData }) {
|
|
const url = usePage().url,
|
|
query = new URL(url, "https://investmoz.invalid").searchParams;
|
|
const [location, setLocation] = useState(query.get("resource_location") ?? ""),
|
|
[search, setSearch] = useState(""),
|
|
[area, setArea] = useState(query.get("resource_area") ?? ""),
|
|
[group, setGroup] = useState(query.get("resource_group") ?? "");
|
|
const locations = [
|
|
...new Set(
|
|
data.groups
|
|
.flatMap((m) => m.location_labels)
|
|
.concat(data.areas.flatMap((m) => m.location_labels)),
|
|
),
|
|
].sort((a, b) => a.localeCompare(b, "pt"));
|
|
const matches = (x: { location_labels: string[] }, text: string) =>
|
|
(!location || x.location_labels.includes(location)) &&
|
|
(!search || text.toLocaleLowerCase("pt").includes(search.toLocaleLowerCase("pt")));
|
|
const groups = data.groups.filter(
|
|
(m) => (!group || m.id === group) && matches(m, m.name + " " + m.locations_text),
|
|
),
|
|
areas = data.areas.filter(
|
|
(a) =>
|
|
(!area || a.id === area) &&
|
|
(!group || a.group_ids.includes(group)) &&
|
|
matches(a, a.title + " " + a.value_chain + " " + a.locations_text),
|
|
);
|
|
return (
|
|
<section
|
|
aria-label={data.title}
|
|
className="space-y-5 rounded border p-4"
|
|
>
|
|
<h2 className="text-xl font-semibold">{data.title}</h2>
|
|
<p>{data.introduction}</p>
|
|
<div className="flex flex-wrap gap-3">
|
|
<label>
|
|
Localização
|
|
<select
|
|
className="mt-1 block max-w-full rounded border p-2"
|
|
aria-label="Localização sectorial"
|
|
value={location}
|
|
onChange={(e) => {
|
|
setLocation(e.target.value);
|
|
setArea("");
|
|
}}
|
|
>
|
|
<option value="">Todas as localizações</option>
|
|
{locations.map((p) => (
|
|
<option key={p} value={p}>
|
|
{p === "Maputo" ? "Maputo — província/cidade a precisar" : p}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
<label>
|
|
{data.group_label}
|
|
<select
|
|
className="mt-1 block max-w-full rounded border p-2"
|
|
aria-label={data.group_label}
|
|
value={group}
|
|
onChange={(e) => {
|
|
setGroup(e.target.value);
|
|
setArea("");
|
|
}}
|
|
>
|
|
<option value="">Todos os grupos</option>
|
|
{data.groups.map((m) => (
|
|
<option key={m.id} value={m.id}>
|
|
{m.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
<label>
|
|
Recurso, local ou actividade
|
|
<input
|
|
className="mt-1 block max-w-full rounded border p-2"
|
|
aria-label="Pesquisar recursos e cadeia de valor"
|
|
value={search}
|
|
onChange={(e) => {
|
|
setSearch(e.target.value);
|
|
setArea("");
|
|
}}
|
|
/>
|
|
</label>
|
|
{area && (
|
|
<button type="button" onClick={() => setArea("")}>
|
|
Ver todas as áreas
|
|
</button>
|
|
)}
|
|
</div>
|
|
<div>
|
|
<h3 className="font-semibold">{data.resource_heading}</h3>
|
|
{groups.length ? (
|
|
<ul className="space-y-3">
|
|
{groups.map((m) => (
|
|
<li key={m.id}>
|
|
<strong>{m.name}</strong>
|
|
<p>{m.locations_text}</p>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
) : (
|
|
<p>Sem referências para esta pesquisa.</p>
|
|
)}
|
|
<p className="text-sm">{data.resource_notice}</p>
|
|
</div>
|
|
<div>
|
|
<h3 className="font-semibold">Possibilidades na cadeia de valor</h3>
|
|
{areas.map((a) => (
|
|
<article key={a.id} className="my-3 space-y-2 rounded border p-3">
|
|
<h4 className="font-semibold">{a.title}</h4>
|
|
<p>{a.locations_text}</p>
|
|
<p>{a.value_chain.replace(/\s*\(indicativo\)/, "")}</p>
|
|
<details>
|
|
<summary>Evidência e âmbito territorial</summary>
|
|
<p>{a.market_evidence}</p>
|
|
{a.indicative_location !== a.locations_text && <p>{a.indicative_location}</p>}
|
|
<p>Referência de {data.reference_date}; preparação da actividade sujeita ao investimento concreto.</p>
|
|
</details>
|
|
<Link
|
|
className="underline"
|
|
href={
|
|
"/investimentos/a-partir-do-setor/" + data.sector_slug + "?" +
|
|
new URLSearchParams({
|
|
resource_area: a.id,
|
|
resource_source: data.source_sha256,
|
|
...(group ? { resource_group: group } : {}),
|
|
...(location ? { resource_location: location } : {}),
|
|
})
|
|
}
|
|
>
|
|
Preparar uma ideia nesta cadeia de valor
|
|
</Link>
|
|
</article>
|
|
))}
|
|
{!areas.length && <p>Sem áreas de investimento para esta selecção.</p>}
|
|
</div>
|
|
<details>
|
|
<summary>Projectos de referência</summary>
|
|
<ul>
|
|
{data.projects.map((p, i) => (
|
|
<li key={i}>{p}</li>
|
|
))}
|
|
</ul>
|
|
</details>
|
|
{!!data.indicators.length && (
|
|
<details>
|
|
<summary>Produção e recursos por período</summary>
|
|
{data.indicators.map((s, i) => (
|
|
<article key={i}>
|
|
<h4>{s.label}</h4>
|
|
<p>
|
|
{s.value.replace(
|
|
"Não encontrei dados de produção das outras gemas.",
|
|
"Outras gemas: sem valores apresentados.",
|
|
)}
|
|
</p>
|
|
<p>Fonte: {s.source}</p>
|
|
</article>
|
|
))}
|
|
<p>
|
|
Produção, capacidade, recursos e previsões são grandezas distintas. Os valores
|
|
conservam os períodos e divergências das fontes.
|
|
</p>
|
|
</details>
|
|
)}
|
|
<details>
|
|
<summary>Riscos a considerar</summary>
|
|
<ul>
|
|
{data.risks.map((r, i) => (
|
|
<li key={i}>{r}</li>
|
|
))}
|
|
</ul>
|
|
</details>
|
|
{data.background.map(section=><details key={section.title}><summary>{section.title}</summary>{section.paragraphs.map((text,i)=><p key={i}>{text}</p>)}{section.title.startsWith("Enquadramento")&&<p>Referência documental; não activa benefícios fiscais, licenças ou direitos no portal.</p>}</details>)}
|
|
<details>
|
|
<summary>Fontes e data</summary>
|
|
<p>Referências reunidas em {data.reference_date}.</p>
|
|
<ul>
|
|
{data.sources.map((s, i) => (
|
|
<li key={i}>{data.source_links?.find(link=>link.title===s)?.url ? <a className="underline" href={data.source_links.find(link=>link.title===s)!.url} target="_blank" rel="noopener noreferrer">{s}</a> : s}</li>
|
|
))}
|
|
</ul>
|
|
</details>
|
|
</section>
|
|
);
|
|
}
|