Skip to content

Commit

Permalink
Merge pull request #61 from Georiviere/perf_upgrades
Browse files Browse the repository at this point in the history
Loading time improvements
  • Loading branch information
Bo-Duke authored Apr 12, 2024
2 parents 34c273b + 179aa7e commit 1f4a1c8
Show file tree
Hide file tree
Showing 13 changed files with 274 additions and 179 deletions.
12 changes: 4 additions & 8 deletions src/api/details.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Settings, getMapSettings } from './settings';
import { getDetailsUrl } from './settings';

async function fetchDetails(url: string) {
const res = await fetch(`${process.env.apiHost}${url}`, {
Expand All @@ -11,18 +11,14 @@ async function fetchDetails(url: string) {
}

export async function getDetails(path: string, id: number) {
let settings = null;
let endpoint = '';
try {
settings = (await getMapSettings()) as Settings['map'];
endpoint = await getDetailsUrl(path);
} catch (error) {
// notfound
return null;
}
const { url: endpoint } =
settings.layersTree
.flatMap(({ layers }) => layers)
.find(item => item.type === path) ?? {};
if (endpoint === undefined) {
if (endpoint === '') {
return null;
}
let details = null;
Expand Down
39 changes: 39 additions & 0 deletions src/api/fullsettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { getLocalettings } from './localSettings';
import { Settings, fetchSettings } from './settings';

export async function getSettings(): Promise<Settings | null> {
let rawSettings = null;
let customization = null;
try {
rawSettings = await fetchSettings();
customization = await getLocalettings();
} catch (error) {
throw error;
}
const {
map: {
baseLayers,
group,
bounds: [lat1, lng1, lat2, lng2],
},
flatpages,
...settings
} = rawSettings;
return {
customization: {
...settings,
...customization,
},
flatpages,
map: {
baseLayers,
layersTree: group,
container: {
bounds: [
[lng1, lat1],
[lng2, lat2],
],
},
},
};
}
89 changes: 36 additions & 53 deletions src/api/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ import { FeatureCollection } from 'geojson';
import { GeoJSONOptions, LatLngBoundsExpression } from 'leaflet';
import slugify from 'slugify';

import { getGeoJSON } from './geojson';
import { getLocalettings } from './localSettings';

export type Attachement = { thumbnail: string; url: string; title: string };

type BaseLayers = {
Expand Down Expand Up @@ -152,7 +149,7 @@ export type Settings = {
customization: LocalSettings;
};

async function fetchSettings(): Promise<RawSettings> {
export async function fetchSettings(): Promise<RawSettings> {
try {
const res = await fetch(
`${process.env.apiHost}/api/portal/fr/portal/${process.env.portal}/`,
Expand All @@ -172,79 +169,65 @@ async function fetchSettings(): Promise<RawSettings> {
}
}

export async function getSettings(): Promise<Settings | null> {
let rawSettings = null;
let customization = null;
try {
rawSettings = await fetchSettings();
customization = await getLocalettings();
} catch (error) {
throw error;
}
async function getRawMapSettings(): Promise<Settings['map']> {
const settings = await fetchSettings();
const {
map: {
baseLayers,
group,
bounds: [lat1, lng1, lat2, lng2],
},
flatpages,
...settings
} = rawSettings;
} = settings;

return {
customization: {
...settings,
...customization,
},
flatpages,
map: {
baseLayers,
layersTree: group,
container: {
bounds: [
[lng1, lat1],
[lng2, lat2],
],
},
baseLayers,
layersTree: group,
container: {
bounds: [
[lng1, lat1],
[lng2, lat2],
],
},
};
} as Settings['map'];
}

export async function getMapSettings(): Promise<Settings['map'] | []> {
let settings = null;
let map = null;
try {
settings = await getSettings();
map = await getRawMapSettings();
} catch (error) {
throw error;
}

if (settings === null) {
if (map === null) {
return [];
}
return map;
}

const { map } = settings;
const layersTree = await Promise.all(
map.layersTree.map(async item => ({
...item,
layers: await Promise.all(
item.layers.map(async layer => {
if (layer.defaultActive === false) {
return layer;
}
return { ...layer, geojson: await getGeoJSON(layer.geojsonUrl) };
}),
),
})),
);
return {
...map,
layersTree,
};
export async function getDetailsUrl(path: string): Promise<string> {
let map = null;
try {
map = await getRawMapSettings();
} catch (error) {
throw error;
}

if (map === null) {
return '';
}

const { url: endpoint = '' } =
map.layersTree
.flatMap(({ layers }) => layers)
.find(item => item.type === path) ?? {};
return endpoint;
}

export async function getMenuSettings(): Promise<Menu[]> {
let settings = null;
try {
settings = await getSettings();
settings = await fetchSettings();
} catch (e) {
throw e;
}
Expand Down
3 changes: 2 additions & 1 deletion src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ReactNode } from 'react';
import { notFound } from 'next/navigation';
import { getMenuSettings, getSettings } from '@/api/settings';
import { getSettings } from '@/api/fullsettings';
import { getMenuSettings } from '@/api/settings';
import { SettingsContextProvider } from '@/context/settings';
import { NextIntlClientProvider, useLocale } from 'next-intl';
import { getTranslations } from 'next-intl/server';
Expand Down
14 changes: 14 additions & 0 deletions src/app/[locale]/map/[details]/[id]/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useTranslations } from 'next-intl';

import { Icons } from '@/components/icons';

export default function Loading() {
const t = useTranslations();
return (
<Icons.loading
className="m-auto h-8 w-8 animate-spin text-primary"
role="img"
aria-label={t('site.loading')}
/>
);
}
11 changes: 1 addition & 10 deletions src/app/[locale]/map/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ReactNode } from 'react';
import { Settings, getMapSettings } from '@/api/settings';
import { MapContextProvider } from '@/context/map';
import { getTranslations } from 'next-intl/server';

Expand All @@ -20,16 +19,8 @@ export const generateMetadata = async () => {
};

export default async function MapLayout({ children }: Props) {
let settings = null;

try {
settings = (await getMapSettings()) as Settings['map'];
} catch (error) {
throw error;
}

return (
<MapContextProvider defaultSettings={settings}>
<MapContextProvider>
<main
role="main"
className="grid h-full w-screen grid-cols-[100dvw_auto_100dvw] grid-rows-1 justify-stretch overflow-x-hidden scroll-smooth md:grid-cols-[50dvw_auto_50dvw] lg:grid-cols-[300px_auto_1fr]"
Expand Down
1 change: 0 additions & 1 deletion src/app/[locale]/page/[slug]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ type GenerateMetaDataProps = {
export const generateMetadata = async ({
params: { slug },
}: GenerateMetaDataProps) => {
const t = await getTranslations('site');
const content = await getPage(slug);
if (content === null) {
return;
Expand Down
60 changes: 35 additions & 25 deletions src/components/map-filters.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useCallback } from 'react';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useMapContext } from '@/context/map';
import { useTranslations } from 'next-intl';

import { getUrlSearchParamsForLayers, partition } from '@/lib/utils';
import { partition } from '@/lib/utils';
import {
Accordion,
AccordionContent,
Expand All @@ -14,40 +14,42 @@ import { Label } from './ui/label';
import { Switch } from './ui/switch';

export default function MapFilters() {
const { settings } = useMapContext();
const router = useRouter();
const pathname = usePathname();
const params = useSearchParams();
const layersFromParams = params.get('layers') ?? '';
const { settings, layers, toggleLayer } = useMapContext();
const t = useTranslations();

const handleChange = useCallback(
(id: number, isActive: boolean) => {
const nextLayerSearchParams = getUrlSearchParamsForLayers(
layersFromParams,
[id],
isActive,
);
const textFromParams = params.get('text')
? `&text=${params.get('text')}`
: '';
router.push(`${pathname}${nextLayerSearchParams}${textFromParams}`);
toggleLayer(id, isActive);
},
[layersFromParams, params, router, pathname],
[toggleLayer],
);

if (settings === null || settings.layersTree.length === 0) {
return null;
if (
settings === null ||
settings.layersTree.length === 0 ||
layers === null
) {
return (
<div className="bg-background px-3">
<p className="sr-only">{t('site.loading')}</p>
{Array.from({ length: 4 }, () => (
<div className="flex w-full justify-between border-b py-4 last:border-b-0">
<div className="skeleton-animation h-6 w-32 rounded"></div>
<div className="skeleton-animation h-6 w-12 rounded-xl"></div>
</div>
))}
</div>
);
}

const [grouped, [notGrouped]] = partition(
settings.layersTree,
layer => layer.label !== null,
);

const defaultActivatedLayers = layersFromParams
.split(',')
.filter(Boolean)
.map(Number);
const activatedLayers = layers
.filter(({ isActive }) => isActive)
.map(({ id }) => id);

return (
<>
Expand Down Expand Up @@ -75,7 +77,11 @@ export default function MapFilters() {
</Label>
<Switch
id={`layerItem-${layer.id}`}
checked={defaultActivatedLayers.includes(layer.id)}
checked={activatedLayers.includes(layer.id)}
isLoading={
!layers.find(e => e.id === layer.id)?.geojson &&
activatedLayers.includes(layer.id)
}
onCheckedChange={isActive =>
handleChange(layer.id, isActive)
}
Expand All @@ -100,7 +106,11 @@ export default function MapFilters() {
</Label>
<Switch
id={`layerItem-${layer.id}`}
checked={defaultActivatedLayers.includes(layer.id)}
checked={activatedLayers.includes(layer.id)}
isLoading={
!layers.find(e => e.id === layer.id)?.geojson &&
activatedLayers.includes(layer.id)
}
onCheckedChange={isActive => handleChange(layer.id, isActive)}
/>
</li>
Expand Down
2 changes: 1 addition & 1 deletion src/components/metadata-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const MetadataItem = ({
<div className="flex flex-row flex-wrap items-center justify-center gap-1">
<dt>
<Icon
className={cn('text-primary', small && 'w-4 h-4')}
className={cn('text-primary', small && 'h-4 w-4')}
{...propsForSVGPresentation}
/>
<span className="sr-only">{t(type)}</span>
Expand Down
Loading

0 comments on commit 1f4a1c8

Please sign in to comment.