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 4 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],
],
},
},
};
}
88 changes: 36 additions & 52 deletions src/api/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +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 };

Expand Down Expand Up @@ -152,7 +150,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 +170,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 { getMenuSettings } from '@/api/settings';
import { getSettings } from '@/api/fullsettings';
import { SettingsContextProvider } from '@/context/settings';
import { NextIntlClientProvider, useLocale } from 'next-intl';
import { getTranslations } from 'next-intl/server';
Expand Down
5 changes: 5 additions & 0 deletions src/app/[locale]/map/[details]/[id]/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Icons } from "@/components/icons";

export default function Loading() {
return <Icons.loading className="animate-spin text-primary h-8 w-8 m-auto" />;
Bo-Duke marked this conversation as resolved.
Show resolved Hide resolved
}
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
57 changes: 32 additions & 25 deletions src/components/map-filters.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useCallback } from 'react';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useMapContext } from '@/context/map';

import { getUrlSearchParamsForLayers, partition } from '@/lib/utils';
import { partition } from '@/lib/utils';
import {
Accordion,
AccordionContent,
Expand All @@ -14,40 +13,40 @@ 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 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
{Array.from({ length: 4 }).map(() => (
Bo-Duke marked this conversation as resolved.
Show resolved Hide resolved
<div className="w-full flex justify-between border-b last:border-b-0 py-4">
<div className="w-32 h-6 rounded skeleton-animation"></div>
Bo-Duke marked this conversation as resolved.
Show resolved Hide resolved
<div className="w-12 h-6 rounded-xl skeleton-animation"></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 +74,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 +103,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
12 changes: 9 additions & 3 deletions src/components/ui/switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import * as SwitchPrimitives from '@radix-ui/react-switch';

import { cn } from '@/lib/utils';

import { Icons } from '../icons';

const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> & { isLoading?: boolean }
>(({ className, isLoading, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
'peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
Expand All @@ -21,7 +23,11 @@ const Switch = React.forwardRef<
className={cn(
'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0',
)}
/>
>
{isLoading && (
<Icons.loading className="animate-spin text-primary w-full h-full" />
Bo-Duke marked this conversation as resolved.
Show resolved Hide resolved
)}
</SwitchPrimitives.Thumb>
</SwitchPrimitives.Root>
));
Switch.displayName = SwitchPrimitives.Root.displayName;
Expand Down
Loading
Loading