Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
83f1de6
chore: create all VD types tables
danji90 Mar 2, 2026
9984aa7
chore: remove Paulownia tree from tree types
danji90 Mar 9, 2026
8fcaa4e
Merge branch 'master' into daniel/addVdSpecificData
danji90 Mar 9, 2026
fe6ee1d
Merge branch 'master' into daniel/addVdSpecificData
danji90 Mar 9, 2026
5fc0610
chore: update VD CSVs, rebuild DB
danji90 Mar 9, 2026
db33daf
chore: update and correct CSV data, update db
danji90 Mar 9, 2026
0c74345
chore: update db
danji90 Mar 9, 2026
a00278a
Merge branch 'master' into daniel/addVdSpecificData
danji90 May 27, 2026
e5813d2
chore: remove all VD specific treetype data and code
danji90 May 28, 2026
80e6c86
chore: update maps.geo.admin import urls, adjust some scripts
danji90 May 28, 2026
68dfa9b
chore: clean
danji90 May 28, 2026
124aa36
fix(tg): add new attributes to table, add az values az export view
danji90 Jun 22, 2026
ab6c190
Merge branch 'daniel/addVdSpecificData' into daniel/tgDataUpdateWithVD
danji90 Jun 25, 2026
0bafa92
chore: upfate import data script to support forest_type gpkg files
danji90 Jun 29, 2026
73a17cc
chore: fix hono server
danji90 Jun 29, 2026
dc1556f
merge master, update documentation
danji90 Jun 29, 2026
c33c556
chore: simply field options fetch, update local tile server script
danji90 Jun 29, 2026
103a4f6
fix: redirect to /projection by default, dix minor location form issues
danji90 Jun 29, 2026
5d3cb42
fix(location): always switch to f projection form from location ft bu…
danji90 Jun 29, 2026
4fa0be4
fix(tg): add new attributes to table, add az values az export view
danji90 Jun 22, 2026
3ee5e2c
chore: create all VD types tables
danji90 Mar 2, 2026
7f16773
chore: update VD CSVs, rebuild DB
danji90 Mar 9, 2026
cae02a6
chore: update and correct CSV data, update db
danji90 Mar 9, 2026
45948e9
chore: remove all VD specific treetype data and code
danji90 May 28, 2026
8b640ed
chore: update maps.geo.admin import urls, adjust some scripts
danji90 May 28, 2026
5aaaf89
chore: clean
danji90 May 28, 2026
faf9005
chore: upfate import data script to support forest_type gpkg files
danji90 Jun 29, 2026
259ec10
chore: fix hono server
danji90 Jun 29, 2026
e276e48
chore: simply field options fetch, update local tile server script
danji90 Jun 29, 2026
670ab7f
fix: redirect to /projection by default, dix minor location form issues
danji90 Jun 29, 2026
bdc47a1
fix(location): always switch to f projection form from location ft bu…
danji90 Jun 29, 2026
fa2ef3f
Merge branch 'daniel/tgDataUpdateWithVD' of github.com:geops/tree-app…
danji90 Jun 29, 2026
65c4bcb
chore: clean merge
danji90 Jun 29, 2026
61339a7
chore: create all VD types tables
danji90 Mar 2, 2026
4d4cb19
chore: update VD CSVs, rebuild DB
danji90 Mar 9, 2026
5cb2855
chore: update and correct CSV data, update db
danji90 Mar 9, 2026
f5f5ec4
chore: remove all VD specific treetype data and code
danji90 May 28, 2026
f627aa0
chore: update maps.geo.admin import urls, adjust some scripts
danji90 May 28, 2026
ef575fa
chore: upfate import data script to support forest_type gpkg files
danji90 Jun 29, 2026
62f0780
Merge branch 'daniel/tgDataUpdateWithVD' of github.com:geops/tree-app…
danji90 Jun 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ lib/data/spatial/forest_types_tg
lib/data/spatial/forest_types_vd
lib/data/spatial/forest_types_zh
lib/data/spatial/forest_types_zh_2
lib/data/spatial/forest_types_union
lib/data/spatial/silver_fir_areas
lib/data/spatial/cantonal_boundaries.zip
lib/data/spatial/*.zip
Expand Down
29 changes: 11 additions & 18 deletions components/ForestEcoregionField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";

import { TreeAppLanguage } from "@/i18n/i18next";
import useStore from "@/store";
import { getTypeOptions } from "@/utils/getTypeOptions";

import Dropdown, { DropdownOption } from "./ui/Dropdown";
import Input from "./ui/Input";
Expand All @@ -26,24 +27,16 @@ function ForestEcoregionField() {

const options = useMemo(() => {
if (projectionMode === "m") return [];
const forestEcoregions = treeClient.getTypes<ForestEcoregion>(
"forestecoregion",
["code", i18n.language],
opts?.forestEcoregion?.length
? {
code: `IN (${opts.forestEcoregion.map((ecoRegion) => `'${ecoRegion}'`).join(", ")})`,
}
: undefined,
);

return (
forestEcoregions
.filter((ecoRegion) => opts.forestEcoregion?.includes(ecoRegion.code))
.map((ecoRegion) => ({
label: ecoRegion[i18n.language as TreeAppLanguage],
value: ecoRegion.code,
})) ?? []
);
return getTypeOptions<ForestEcoregion, DropdownOption>({
codes: opts?.forestEcoregion ?? [],
columns: ["code", i18n.language],
mapOption: (ecoRegion) => ({
label: ecoRegion[i18n.language as TreeAppLanguage],
value: ecoRegion.code,
}),
treeClient,
type: "forestecoregion",
});
}, [opts?.forestEcoregion, i18n.language, treeClient, projectionMode]);

if (projectionMode === "m") {
Expand Down
31 changes: 13 additions & 18 deletions components/LocationForm/IndicatorField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";

import { TreeAppLanguage } from "@/i18n/i18next";
import useStore from "@/store";
import { getTypeOptions } from "@/utils/getTypeOptions";

import LatinSwitcher from "../LatinSwitcher";
import Dropdown from "../ui/Dropdown";
Expand All @@ -20,24 +21,18 @@ function IndicatorField() {
const latinActive = useStore((state) => state.latinActive);

const options = useMemo(() => {
if (!opts?.indicator?.length) return [];
const indicators = treeClient.getTypes<TranslatedTypeRecordLatin>(
"indicator",
["code", "la", i18n.language],
opts?.indicator?.length
? { code: `IN (${opts.indicator.map((ind) => `${ind}`).join(", ")})` }
: undefined,
);

return (
indicators
.filter((ind) => opts.indicator?.includes(ind.code))
.map((ind) => ({
filterValue: `${ind.la} ${ind[i18n.language as TreeAppLanguage]}`,
label: latinActive ? ind.la : ind[i18n.language as TreeAppLanguage],
value: ind.code,
})) ?? []
);
return getTypeOptions<TranslatedTypeRecordLatin, DropdownOption>({
codes: opts?.indicator ?? [],
columns: ["code", "la", i18n.language],
mapOption: (ind) => ({
filterValue: `${ind.la} ${ind[i18n.language as TreeAppLanguage]}`,
label: latinActive ? ind.la : ind[i18n.language as TreeAppLanguage],
value: ind.code,
}),
quoteCodes: false,
treeClient,
type: "indicator",
});
}, [opts?.indicator, i18n.language, treeClient, latinActive]);

return (
Expand Down
29 changes: 11 additions & 18 deletions components/LocationForm/SilverFirAreaField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";

import { TreeAppLanguage } from "@/i18n/i18next";
import useStore from "@/store";
import { getTypeOptions } from "@/utils/getTypeOptions";

import Dropdown from "../ui/Dropdown";
import Input from "../ui/Input";
Expand All @@ -23,24 +24,16 @@ function SilverFirAreaField() {

const options = useMemo(() => {
if (projectionMode === "m" || !opts?.silverFirArea?.length) return [];
const silverFirAreas = treeClient.getTypes<SilverFirArea>(
"silverfirarea",
["code", i18n.language],
opts?.silverFirArea?.length
? {
code: `IN (${opts.silverFirArea.map((sfa) => `'${sfa}'`).join(", ")})`,
}
: undefined,
);

return (
silverFirAreas
.filter((sfa) => opts.silverFirArea?.includes(sfa.code))
.map((sfa) => ({
label: sfa[i18n.language as TreeAppLanguage],
value: sfa.code,
})) ?? []
);
return getTypeOptions<SilverFirArea, DropdownOption>({
codes: opts.silverFirArea,
columns: ["code", i18n.language],
mapOption: (sfa) => ({
label: sfa[i18n.language as TreeAppLanguage],
value: sfa.code,
}),
treeClient,
type: "silverfirarea",
});
}, [opts?.silverFirArea, i18n.language, treeClient, projectionMode]);

if (projectionMode === "m") {
Expand Down
30 changes: 12 additions & 18 deletions components/LocationForm/TreeTypesField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";

import { TreeAppLanguage } from "@/i18n/i18next";
import useStore from "@/store";
import { getTypeOptions } from "@/utils/getTypeOptions";

import LatinSwitcher from "../LatinSwitcher";
import Dropdown from "../ui/Dropdown";
Expand All @@ -20,24 +21,17 @@ function TreeTypesField() {
const latinActive = useStore((state) => state.latinActive);

const options = useMemo(() => {
if (!opts?.treeType?.length) return [];
const treeTypes = treeClient.getTypes<TranslatedTypeRecordLatin>(
"treetype",
["code", "la", i18n.language],
opts?.treeType?.length
? { code: `IN (${opts.treeType.map((tt) => `'${tt}'`).join(", ")})` }
: undefined,
);

return (
treeTypes
.filter((tt) => opts.treeType?.includes(tt.code))
.map((tt) => ({
filterValue: `${tt.la} ${tt[i18n.language as TreeAppLanguage]}`,
label: latinActive ? tt.la : tt[i18n.language as TreeAppLanguage],
value: tt.code,
})) ?? []
);
return getTypeOptions<TranslatedTypeRecordLatin, DropdownOption>({
codes: opts?.treeType ?? [],
columns: ["code", "la", i18n.language],
mapOption: (tt) => ({
filterValue: `${tt.la} ${tt[i18n.language as TreeAppLanguage]}`,
label: latinActive ? tt.la : tt[i18n.language as TreeAppLanguage],
value: tt.code,
}),
treeClient,
type: "treetype",
});
}, [opts, i18n.language, treeClient, latinActive]);

return (
Expand Down
15 changes: 8 additions & 7 deletions components/LocationForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ function LocationForm() {
const { t } = useTranslation();
const formLocation = useStore((state) => state.formLocation);
const setFormLocation = useStore((state) => state.setFormLocation);
const hasFilters =
intersection(
Object.keys(formLocation).filter(
(key): key is keyof Location => !!formLocation[key as keyof Location],
),
filterFields,
)?.length > 0;

return (
<div className="flex flex-col gap-4 px-5">
Expand Down Expand Up @@ -87,13 +94,7 @@ function LocationForm() {
},
]}
/>
{intersection(
Object.keys(formLocation).filter(
(key): key is keyof Location =>
formLocation[key as keyof Location] !== "",
),
filterFields,
)?.length > 0 && (
{hasFilters && (
<Button
className="my-4"
onClick={() => {
Expand Down
14 changes: 5 additions & 9 deletions components/LocationResult/EcogramPopup.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useRouter } from "next/router";
import { useMemo, useRef } from "react";
import { useTranslation } from "react-i18next";
import { Tooltip, TooltipRefProps } from "react-tooltip";
Expand All @@ -8,19 +7,19 @@ import useStore from "@/store";
import Button from "../ui/Button";
import InfoButton from "../ui/InfoButton";

import ForestTypeButton from "./ForestTypeButton";

import type { ForestType } from "@geops/tree-lib/types";

import type { TreeAppLanguage } from "@/i18n/i18next";

function EcogramPopup({ forestTypes }: { forestTypes: string[] }) {
const { i18n, t } = useTranslation();
const router = useRouter();
const activeProfile = useStore((state) => state.activeProfile);
const treeClient = useStore((state) => state.treeClient);
const setForestTypeDescription = useStore(
(state) => state.setForestTypeDescription,
);
const setFormLocation = useStore((state) => state.setFormLocation);
const refTooltip = useRef<TooltipRefProps>(null);

const forestTypeInfos: ForestType[] = useMemo(() => {
Expand Down Expand Up @@ -74,16 +73,13 @@ function EcogramPopup({ forestTypes }: { forestTypes: string[] }) {
className="h-12 w-12 min-w-12 rounded bg-primary-500 text-white hover:bg-primary-200 hover:text-white"
onClick={() => setForestTypeDescription(code)}
/>
<Button
<ForestTypeButton
className="truncate"
onClick={() => {
setFormLocation({ forestType: code });
void router.push(`/projection${window.location.search}`);
}}
code={code}
title={`${code} - ${name}`}
>
{code} - {name}
</Button>
</ForestTypeButton>
</li>
);
})}
Expand Down
35 changes: 35 additions & 0 deletions components/LocationResult/ForestTypeButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useRouter } from "next/router";

import useStore from "@/store";

import Button, { ButtonProps } from "../ui/Button";

interface ForestTypeButtonProps extends ButtonProps {
code: string;
}

export default function ForestTypeButton({
children,
className,
code,
disabled,
...props
}: ForestTypeButtonProps) {
const setFormLocation = useStore((state) => state.setFormLocation);
const setProjectionMode = useStore((state) => state.setProjectionMode);
const router = useRouter();
return (
<Button
className={className}
disabled={disabled}
onClick={() => {
setProjectionMode("f");
setFormLocation({ forestType: code });
void router.push(`/projection${window.location.search}`);
}}
{...props}
>
{children}
</Button>
);
}
37 changes: 22 additions & 15 deletions components/LocationResult/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { useRouter } from "next/router";
import { useTranslation } from "react-i18next";

import useStore from "@/store";

import Button from "../ui/Button";
import Message from "../ui/Message";
import InfoModal from "../ui/Modal";

import Ecogram from "./Ecogram";
import ForestTypeButton from "./ForestTypeButton";

import type { ForestType, TreeLocationGroup } from "@geops/tree-lib/types";

Expand All @@ -22,16 +21,26 @@ const otherForestTypeGroups: TreeLocationGroup[] = [

function LocationResult() {
const { i18n, t } = useTranslation();
const router = useRouter();
const location = useStore((state) => state.location);
const formLocation = useStore((state) => state.formLocation);
const projectionMode = useStore((state) => state.projectionMode);
const treeClient = useStore((state) => state.treeClient);
const setFormLocation = useStore((state) => state.setFormLocation);
const { ecogram, forestTypes } = useStore((state) => state.locationResult);
console.log(formLocation);

const hasMainGroup =
!formLocation.groups || formLocation.groups.includes("main");
!formLocation.groups || formLocation.groups?.includes("main");
const hasOtherGroup =
!formLocation.groups ||
formLocation.groups.filter((group) => group !== "main").length > 0;
formLocation.groups.every((group) => group !== "main");
const hasRequiredFields =
projectionMode === "m"
? !!(location.altitudinalZone && location.forestEcoregion)
: !!(formLocation.altitudinalZone && formLocation.forestEcoregion);
const requirementsMessage =
projectionMode === "m"
? "projection.missingLocation"
: "location.selectAzAndEcoregion";

return forestTypes ? (
<div className="px-5">
Expand Down Expand Up @@ -61,6 +70,9 @@ function LocationResult() {
{t("location.otherResultHelp")}
</InfoModal>
</div>
{!hasRequiredFields && (
<Message className="mb-2">{t(requirementsMessage)}</Message>
)}
<div className="flex flex-col gap-4">
{otherForestTypeGroups
.filter((group) => forestTypes[group].length > 0)
Expand All @@ -73,24 +85,19 @@ function LocationResult() {
ftCode,
["code", i18n.language as TreeAppLanguage],
);
const onClick = () => {
setFormLocation({ forestType: ftCode });
void router.push(
`/projection${window.location.search}`,
);
};
return (
<li key={ftCode}>
<Button
<ForestTypeButton
className="grid grid-cols-[auto,auto,auto] gap-2 text-left"
onClick={onClick}
code={ftCode}
disabled={!hasRequiredFields}
>
<div>{ftCode}</div>
<div>-</div>
<div>
{ftInfo?.[i18n.language as TreeAppLanguage]}
</div>
</Button>
</ForestTypeButton>
</li>
);
})}
Expand Down
Loading