Skip to content

Commit

Permalink
Merge pull request #2 from Vizzuality/feature/country-layer
Browse files Browse the repository at this point in the history
Country layer
  • Loading branch information
mbarrenechea authored Oct 26, 2023
2 parents f0c8724 + 952d3ed commit edca730
Show file tree
Hide file tree
Showing 21 changed files with 10,613 additions and 6,988 deletions.
9 changes: 9 additions & 0 deletions client/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ const nextConfig = {
images: {
domains: ["api.mapbox.com"],
},
// webpack: (config) => {
// // Fixes warning Critical dependency: the request of a dependency is an expression
// config.module = {
// ...config.module,
// exprContextCritical: false,
// };

// return config;
// },
};

export default nextConfig;
3 changes: 2 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
"react-icons": "4.11.0",
"react-map-gl": "7.1.6",
"rooks": "7.14.1",
"tailwindcss": "3.3.3",
"tailwind-merge": "1.14.0",
"tailwindcss": "3.3.3",
"tailwindcss-animate": "1.0.7",
"typescript": "5.2.2",
"zod": "3.22.2"
Expand All @@ -64,6 +64,7 @@
"@playwright/test": "1.38.1",
"@tanstack/eslint-plugin-query": "4.34.1",
"@types/express": "4.17.18",
"@types/geojson": "^7946.0.12",
"@types/mapbox": "1.6.43",
"@types/node": "20.7.0",
"@types/react": "18.2.23",
Expand Down
16 changes: 13 additions & 3 deletions client/src/app/layout-providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,22 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

import { TooltipProvider } from "@/components/ui/tooltip";

import { metropolis, openSans } from "@/styles/fonts";

export default function LayoutProviders({ children }: PropsWithChildren) {
const [queryClient] = useState(() => new QueryClient());

return (
<QueryClientProvider client={queryClient}>
<TooltipProvider>{children}</TooltipProvider>
</QueryClientProvider>
<>
<style jsx global>{`
:root {
--font-open-sans: ${openSans.style.fontFamily};
--font-metropolis: ${metropolis.style.fontFamily};
}
`}</style>
<QueryClientProvider client={queryClient}>
<TooltipProvider>{children}</TooltipProvider>
</QueryClientProvider>
</>
);
}
8 changes: 2 additions & 6 deletions client/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import "./globals.css";
import "@/styles/globals.css";
import "mapbox-gl/dist/mapbox-gl.css";

import { PropsWithChildren } from "react";

import type { Metadata } from "next";

import { Inter } from "next/font/google";

import LayoutProviders from "./layout-providers";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "CCSA",
description: "Generated by create next app",
Expand All @@ -20,7 +16,7 @@ export default async function RootLayout({ children }: PropsWithChildren) {
return (
<LayoutProviders>
<html lang="en">
<body className={inter.className}>{children}</body>
<body>{children}</body>
</html>
</LayoutProviders>
);
Expand Down
75 changes: 75 additions & 0 deletions client/src/components/map/layers/countries-layer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useEffect, useMemo } from "react";

import { Source, Layer, GeoJSONSourceRaw } from "react-map-gl";

import { Feature } from "geojson";

import { useGetCountries } from "@/types/generated/country";
import { LayerDataset } from "@/types/generated/strapi.schemas";
import { Config, LayerProps } from "@/types/layers";

export type CountriesLayerProps = LayerProps & {
config: Config;
dataset?: LayerDataset;
beforeId?: string;
};

const CountriesLayer = ({ beforeId, dataset, config, onAdd, onRemove }: CountriesLayerProps) => {
const { data: countriesData } = useGetCountries({
"pagination[pageSize]": 100,
});

const SOURCE = useMemo(() => {
if (!countriesData?.data?.data) return null;

return {
type: "geojson",
data: {
type: "FeatureCollection",
features: countriesData.data.data.map((c) => ({
type: "Feature",
geometry: c.attributes?.geometry as Feature["geometry"],
properties: {
id: c.id,
name: c.attributes?.name,
...(dataset?.data?.attributes?.datum as Record<string, unknown>[])?.find(
(d) => d.iso3 === c.attributes?.iso3,
),
},
})),
},
} satisfies GeoJSONSourceRaw;
}, [countriesData, dataset?.data?.attributes?.datum]);

const STYLES = config.styles;

useEffect(() => {
if (SOURCE && STYLES && onAdd) {
onAdd({
source: SOURCE,
styles: STYLES,
});
}

return () => {
if (SOURCE && STYLES && onRemove) {
onRemove({
source: SOURCE,
styles: STYLES,
});
}
};
}, []); // eslint-disable-line react-hooks/exhaustive-deps

if (!SOURCE || !STYLES) return null;

return (
<Source {...SOURCE}>
{STYLES.map((layer) => (
<Layer key={layer.id} {...layer} beforeId={beforeId} />
))}
</Source>
);
};

export default CountriesLayer;
9 changes: 6 additions & 3 deletions client/src/constants/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ export const DEFAULT_VIEW_STATE: Partial<ViewState> = {
};

export const DEFAULT_BBOX: [number, number, number, number] = [
-118.3665, 1.1768, -53.9775, 32.7186,
-118.3665 * 1.1,
1.1768 * 1.1,
-53.9775 * 1.1,
32.7186 * 1.1,
];

export const BASEMAPS = [
Expand Down Expand Up @@ -85,6 +88,6 @@ export const DEFAULT_MAP_SETTINGS: {
} = {
basemap: "basemap-light",
labels: "labels-dark",
boundaries: true,
roads: true,
boundaries: false,
roads: false,
};
84 changes: 45 additions & 39 deletions client/src/containers/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ const Home = () => {

const categories = datasetsData.data.data.map((dataset) => dataset?.attributes?.category);

return Array.from(new Set(categories));
const categories_map = new Map(categories.map((d) => [d?.data?.id, d]));
return [...categories_map.values()];
}, [datasetsData]);

if (CATEGORIES.length === 0) return null;

return (
<div className="h-full overflow-auto">
<div className="px-5 py-10">
<h1 className="text-3xl">Explore datasets</h1>
<h1 className="font-metropolis text-3xl text-gray-800">Explore Datasets</h1>

{/* List of datasets */}
<Accordion
Expand All @@ -52,45 +53,50 @@ const Home = () => {

return (
<AccordionItem key={category?.data?.id} value={`${category?.data?.id}`}>
<AccordionTrigger>{category?.data?.attributes?.name}</AccordionTrigger>
<AccordionTrigger className="text-xl">
{category?.data?.attributes?.name}
</AccordionTrigger>

<AccordionContent>
{DATASETS?.map((dataset) => {
if (!dataset?.attributes) return null;

const lysIds = dataset?.attributes?.layers?.data?.map((l) => l.id);

return (
<div
key={dataset?.id}
className="flex items-center justify-start space-x-2.5"
>
<Switch
defaultChecked={layers?.some((l) => lysIds?.includes(l))}
onCheckedChange={(c: boolean) => {
const lys = dataset?.attributes?.layers;

if (!lys) return;

setLayers((prev) => {
const ids = lys?.data?.map((l) => {
return l.id as number;
<ul className="space-y-5">
{DATASETS?.map((dataset) => {
if (!dataset?.attributes) return null;

const lysIds = dataset?.attributes?.layers?.data?.map((l) => l.id);

return (
<li
key={dataset?.id}
className="flex items-center justify-start space-x-2.5"
>
<Switch
defaultChecked={layers?.some((l) => lysIds?.includes(l))}
onCheckedChange={(c: boolean) => {
const lys = dataset?.attributes?.layers;

if (!lys) return;

setLayers((prev) => {
const ids = lys?.data?.map((l) => {
return l.id as number;
});

if (c && ids) return [...ids, ...prev];
if (!c && ids) {
return prev.filter((id) => !ids.includes(id));
}

return prev;
});

if (c && ids) return [...prev, ...ids];
if (!c && ids) {
return prev.filter((id) => !ids.includes(id));
}

return prev;
});
}}
/>
<div>
<h2>{dataset?.attributes?.name}</h2>
</div>
</div>
);
})}
}}
/>
<div>
<h2>{dataset?.attributes?.name}</h2>
</div>
</li>
);
})}
</ul>
</AccordionContent>
</AccordionItem>
);
Expand Down
3 changes: 0 additions & 3 deletions client/src/containers/map/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { LngLatBoundsLike, useMap } from "react-map-gl";

import { useSyncBbox } from "@/app/url-query-params";

import { DEFAULT_BBOX } from "@/constants/map";

import LayerManager from "@/containers/map/layer-manager";
import MapSettingsManagerPanel from "@/containers/map-settings";
import MapSettingsManager from "@/containers/map-settings/manager";
Expand Down Expand Up @@ -39,7 +37,6 @@ export default function MapContainer({ id = "default" }: { id?: string }) {
initialViewState={{
bounds: bbox as LngLatBoundsLike,
}}
maxBounds={DEFAULT_BBOX}
onMapViewStateChange={onMapViewStateChange}
>
<Controls className="absolute right-6 top-4">
Expand Down
26 changes: 25 additions & 1 deletion client/src/containers/map/layer-manager/item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useGetLayersId } from "@/types/generated/layer";
import { LayerResponseDataObject } from "@/types/generated/strapi.schemas";
import { Config, LayerTyped } from "@/types/layers";

import CountriesLayer from "@/components/map/layers/countries-layer";
import DeckLayer from "@/components/map/layers/deck-layer";
import MapboxLayer from "@/components/map/layers/mapbox-layer";

Expand All @@ -22,7 +23,7 @@ interface LayerManagerItemProps extends Required<Pick<LayerResponseDataObject, "

const LayerManagerItem = ({ id, beforeId, settings }: LayerManagerItemProps) => {
const { data } = useGetLayersId(id, {
populate: "metadata",
populate: "dataset,metadata",
});
const layersInteractive = useAtomValue(layersInteractiveAtom);
const setLayersInteractive = useSetAtom(layersInteractiveAtom);
Expand Down Expand Up @@ -96,6 +97,29 @@ const LayerManagerItem = ({ id, beforeId, settings }: LayerManagerItemProps) =>
);
}

if (type === "countries") {
const { config, params_config, dataset } = data.data.data.attributes;

const c = parseConfig<Config>({
config,
params_config,
settings,
});

if (!c) return null;

return (
<CountriesLayer
id={`${id}-layer`}
dataset={dataset}
beforeId={beforeId}
config={c}
onAdd={handleAddMapboxLayer}
onRemove={handleRemoveMapboxLayer}
/>
);
}

if (type === "deckgl") {
const { config, params_config } = data.data.data.attributes;
const c = parseConfig({
Expand Down
4 changes: 2 additions & 2 deletions client/src/containers/projects/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
const Projects = (): JSX.Element => {
return (
<div className="flex h-full overflow-auto">
<div className="p-5">
<h1 className="text-3xl">Projects</h1>
<div className="px-5 py-10">
<h1 className="font-metropolis text-3xl text-gray-800">Projects</h1>
</div>
</div>
);
Expand Down
Binary file added client/src/styles/Metropolis-Black.woff
Binary file not shown.
Binary file added client/src/styles/Metropolis-Black.woff2
Binary file not shown.
23 changes: 23 additions & 0 deletions client/src/styles/fonts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Open_Sans } from "next/font/google";
import localFont from "next/font/local";

export const openSans = Open_Sans({
subsets: ["latin"],
variable: "--font-open-sans",
fallback: ["system-ui", "Helvetica Neue", "Helvetica", "Arial"],
weight: ["300"],
style: ["italic", "normal"],
display: "block",
});

export const metropolis = localFont({
src: [
{
path: "./Metropolis-Black.woff2",
weight: "900",
style: "normal",
},
],
display: "block",
variable: "--font-metropolis",
});
File renamed without changes.
Loading

0 comments on commit edca730

Please sign in to comment.