Skip to content

Commit

Permalink
Merge pull request #123 from Vizzuality/feature/project-bbox
Browse files Browse the repository at this point in the history
query state feature removed
  • Loading branch information
mluena authored Apr 23, 2024
2 parents 7356a76 + 2c30e2c commit 68bd230
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 48 deletions.
11 changes: 6 additions & 5 deletions client/cypress/e2e/navigation.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ describe('navigation', () => {

it('access to project detail page and switch dashboard', () => {
cy.visit('/').wait(10000);
cy.get('[data-cy="projects-list-tab"]').should('exist');
cy.get('[data-cy="projects-list-tab"]').click();
cy.get('a[data-cy="project-item-link"]').first().click();
cy.get('button[data-cy="project-dashboard-button"]').click().wait(1000);
cy.get('[data-cy="project-dashboard"]').should('exist');
cy.get('button[data-cy="project-dashboard-button"]').click();
cy.get('[data-cy="project-dashboard"]').should('not.exist');
cy.get('[data-cy="project-item-link"]').first().click();
// cy.get('button[data-cy="project-dashboard-button"]').click().wait(3000);
// cy.get('[data-cy="project-dashboard"]').should('exist');
// cy.get('button[data-cy="project-dashboard-button"]').click();
// cy.get('[data-cy="project-dashboard"]').should('not.exist');
});

it('access to country detail page', () => {
Expand Down
17 changes: 1 addition & 16 deletions client/src/containers/map/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { useCallback, useEffect, useMemo, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';

import { LngLatBoundsLike, MapLayerMouseEvent, useMap } from 'react-map-gl';

Expand Down Expand Up @@ -121,21 +121,6 @@ export default function MapContainer() {
}
}, [map, setBboxURL, setTmpBbox]);

useEffect(() => {
if (map && map?.getSource('projects') && params.id && pathname.includes('projects')) {
const projectFeatures = map?.querySourceFeatures('projects', {
sourceLayer: 'areas_centroids_c',
filter: ['==', 'project_code', params.id],
});

const bboxTurf = bbox({
type: 'FeatureCollection',
features: projectFeatures,
});
setTmpBbox(bboxTurf as Bbox);
}
}, [map, params.id, setTmpBbox, pathname]);

const handleMapClick = useCallback(
(e: MapLayerMouseEvent) => {
const ProjectData =
Expand Down
13 changes: 6 additions & 7 deletions client/src/containers/projects/item.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import Image from 'next/image';
import Link from 'next/link';
// import Link from 'next/link';

import { useAtomValue } from 'jotai';

Expand All @@ -11,16 +11,15 @@ import { hoveredProjectMapAtom } from '@/store';

import { ProjectListResponseDataItem } from '@/types/generated/strapi.schemas';

import { useSyncQueryParams } from '@/hooks/datasets';
// import { useSyncQueryParams } from '@/hooks/datasets';

export default function ProjectItem({ data }: { data: ProjectListResponseDataItem }) {
const hoveredProjectMap = useAtomValue(hoveredProjectMapAtom);
const queryParams = useSyncQueryParams();

// const queryParams = useSyncQueryParams({}, { bbox: data.attributes?.bbox });
return (
data && (
<Link
href={`/projects/${data?.attributes?.project_code}${queryParams}`}
<div
// href={`/projects/${data?.attributes?.project_code}${queryParams}`}
data-cy="project-item-link"
className={cn({
'flex space-x-4 rounded-lg border border-gray-100 bg-white py-2 pl-2 pr-4 shadow-sm transition-all duration-300 hover:border-yellow-500':
Expand Down Expand Up @@ -50,7 +49,7 @@ export default function ProjectItem({ data }: { data: ProjectListResponseDataIte
<p>{data?.attributes?.status}</p>
</div>
</div>
</Link>
</div>
)
);
}
23 changes: 23 additions & 0 deletions client/src/containers/projects/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@

import { MouseEvent, useCallback, useState } from 'react';

import { useRouter } from 'next/navigation';

import { useSetAtom } from 'jotai';
import { Search, X } from 'lucide-react';

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

import { hoveredProjectMapAtom } from '@/store';
import { tmpBboxAtom } from '@/store';

import { useGetProjects } from '@/types/generated/project';
import { Bbox } from '@/types/map';

import { useSyncQueryParams } from '@/hooks/datasets';
import { useSyncFilters } from '@/hooks/datasets/sync-query';

import Filters from '@/containers/filters';
Expand All @@ -24,8 +29,11 @@ import FiltersSelected from '../filters/selected';

export default function ProjectsList() {
const [searchValue, setSearchValue] = useState<string | null>(null);
const setTempBbox = useSetAtom(tmpBboxAtom);
const [filtersSettings] = useSyncFilters();
const setHoveredProjectList = useSetAtom(hoveredProjectMapAtom);
const router = useRouter();
const queryParams = useSyncQueryParams();

const { data, isFetching, isFetched, isError } = useGetProjects(
{
Expand Down Expand Up @@ -140,6 +148,19 @@ export default function ProjectsList() {
[setHoveredProjectList]
);

const handleClick = useCallback(
(e: MouseEvent<HTMLElement>) => {
const value = e.currentTarget?.getAttribute('data-bbox');

if (value) {
const currentValue = value.split(',').map((num) => parseFloat(num)) as Bbox;
setTempBbox(currentValue);
}
router.push(`/projects/${e.currentTarget.getAttribute('data-value')}${queryParams}`);
},
[setTempBbox, router, queryParams]
);

const filtersLength = Object.entries(filtersSettings)
.flat()
.filter((el) => typeof el === 'object')
Expand Down Expand Up @@ -201,6 +222,8 @@ export default function ProjectsList() {
type="button"
key={project?.id}
data-value={project?.attributes?.project_code}
data-bbox={project?.attributes?.bbox}
onClick={handleClick}
onMouseEnter={handleHover}
onMouseLeave={() => setHoveredProjectList(null)}
>
Expand Down
48 changes: 29 additions & 19 deletions client/src/hooks/datasets/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
'use client';
import { useCallback, useMemo } from 'react';

import { serialize } from './query-parsers';
import {
Expand Down Expand Up @@ -28,33 +29,42 @@ type ExcludeParams = {
};

export const useSyncQueryParams = (
exclude: ExcludeParams = {},
defaultValue: Partial<QueryParamsData> = {}
exclude: ExcludeParams = {}, // Optional parameter for exclusion
defaultValue: Partial<QueryParamsData> = {} // Optional default values
) => {
// Retrieve data from hooks, possibly undefined
const [filtersFromURL] = useSyncFilters();
const [layersFromURL] = useSyncLayers();
const [settingsFromURL] = useSyncBasemap();
const [projectsTabFromURL] = useSyncProjectsTab();
const [bboxFromURL] = useSyncBbox();

const filters = defaultValue?.filters || filtersFromURL;
const layers = defaultValue?.layers || layersFromURL;
const settings = defaultValue?.settings || settingsFromURL;
const projectsTab = defaultValue?.projectsTab || projectsTabFromURL;
const bbox = defaultValue?.bbox || bboxFromURL;
// Use useMemo to only recalculate when dependencies change
const data: QueryParamsData = useMemo(
() => ({
// Apply default values if provided, otherwise use values from URL
filters: defaultValue?.filters ?? filtersFromURL,
layers: defaultValue?.layers ?? layersFromURL,
settings: defaultValue?.settings ?? settingsFromURL,
projectsTab: defaultValue?.projectsTab ?? projectsTabFromURL,
bbox: defaultValue?.bbox ?? bboxFromURL ?? [0, 0, 0, 0], // Include fallback default for bbox
}),
[filtersFromURL, layersFromURL, settingsFromURL, projectsTabFromURL, bboxFromURL, defaultValue]
);

// Construct the data object with correct typing
const data: QueryParamsData = { filters, layers, settings, projectsTab, bbox };
// Construct the result by excluding specified keys
const result: Partial<QueryParamsData> = useMemo(() => {
const filteredResult: Partial<QueryParamsData> = {};
Object.keys(data).forEach((key) => {
const typedKey = key as keyof QueryParamsData;
// Only add key to result if it's not set to be excluded
if (!exclude[typedKey]) {
filteredResult[typedKey] = data[typedKey];
}
});
return filteredResult;
}, [data, exclude]);

// Filter out excluded keys
const result: Partial<QueryParamsData> = {};
Object.keys(data).forEach((key) => {
if (!(key in exclude && exclude[key as keyof ExcludeParams])) {
// Use type assertion here to ensure keys are recognized as valid
result[key as keyof QueryParamsData] = data[key as keyof QueryParamsData];
}
});

// Return the serialized object
// Serialize the result object to make it suitable for query parameters
return serialize(result);
};
2 changes: 1 addition & 1 deletion client/src/hooks/datasets/query-parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const searchQueryParams = {
layers: layersParser,
settings: basemapSettingsParser,
tab: projectsTabParser,
box: bboxParser,
bbox: bboxParser,
};

export const serialize = createSerializer(searchQueryParams);
3 changes: 3 additions & 0 deletions client/src/types/generated/strapi.schemas.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Bbox } from '@/types/map';

/**
* Generated by orval v6.16.0 🍺
* Do not edit manually.
Expand Down Expand Up @@ -418,6 +420,7 @@ export interface Project {
publishedAt?: string;
createdBy?: ProjectCreatedBy;
updatedBy?: ProjectUpdatedBy;
bbox?: Bbox;
}

export type ProjectGalleryDataItemAttributesUpdatedByDataAttributes = { [key: string]: any };
Expand Down

0 comments on commit 68bd230

Please sign in to comment.