Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loading time improvements #61

Merged
merged 6 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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">
Bo-Duke marked this conversation as resolved.
Show resolved Hide resolved
<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