From 1908beda4d0d0acf3a62141c62facd2dded95abf Mon Sep 17 00:00:00 2001 From: Matthias GOUPIL Date: Tue, 22 Oct 2024 15:01:09 +0200 Subject: [PATCH] feat(#1290383): [Example App] Add latitude and Longitude Field in a Settings Component --- .../src/components/Header/Header.tsx | 2 + .../Providers/AppProvider/AppProvider.tsx | 9 +- .../SettingsProvider/SettingsProvider.tsx | 29 ++++ .../src/components/Settings/Settings.tsx | 136 ++++++++++++++++++ front/example-app/src/contexts/index.ts | 1 + front/example-app/src/contexts/settings.ts | 10 ++ front/example-app/src/hooks/useProducts.ts | 27 +++- 7 files changed, 207 insertions(+), 7 deletions(-) create mode 100644 front/example-app/src/components/Providers/SettingsProvider/SettingsProvider.tsx create mode 100644 front/example-app/src/components/Settings/Settings.tsx create mode 100644 front/example-app/src/contexts/settings.ts diff --git a/front/example-app/src/components/Header/Header.tsx b/front/example-app/src/components/Header/Header.tsx index a5d5b3303..84c6c1bc0 100644 --- a/front/example-app/src/components/Header/Header.tsx +++ b/front/example-app/src/components/Header/Header.tsx @@ -18,6 +18,7 @@ import { catalogContext, extraBundlesContext } from '../../contexts' import HeaderFormControl from '../HeaderFormControl/HeaderFormControl' import SearchBar from '../SearchBar/SearchBar' import Logo from './logo.svg' +import Settings from '../Settings/Settings' function Header(): JSX.Element { const catalogLabelId = useId() @@ -142,6 +143,7 @@ function Header(): JSX.Element { )} + ) diff --git a/front/example-app/src/components/Providers/AppProvider/AppProvider.tsx b/front/example-app/src/components/Providers/AppProvider/AppProvider.tsx index 6f9ada588..95b6ba6c0 100644 --- a/front/example-app/src/components/Providers/AppProvider/AppProvider.tsx +++ b/front/example-app/src/components/Providers/AppProvider/AppProvider.tsx @@ -8,6 +8,7 @@ import RequestedPathProvider from '../RequestedPathProvider/RequestedPathProvide import SchemaProvider from '../SchemaProvider/SchemaProvider' import SearchProvider from '../SearchProvider/SearchProvider' import UserProvider from '../UserProvider/UserProvider' +import SettingsProvider from '../SettingsProvider/SettingsProvider' interface IProps { children: ReactNode @@ -22,9 +23,11 @@ function AppProvider(props: IProps): JSX.Element { - - {children} - + + + {children} + + diff --git a/front/example-app/src/components/Providers/SettingsProvider/SettingsProvider.tsx b/front/example-app/src/components/Providers/SettingsProvider/SettingsProvider.tsx new file mode 100644 index 000000000..491b0579d --- /dev/null +++ b/front/example-app/src/components/Providers/SettingsProvider/SettingsProvider.tsx @@ -0,0 +1,29 @@ +import React, { ReactNode, useMemo, useState } from 'react' +import { ISettingsContext, locationContext } from '../../../contexts' + +interface IProps { + children: ReactNode +} + +function SettingsProvider({ children }: IProps): JSX.Element { + const [longitude, setLongitude] = useState('') + const [latitude, setLatitude] = useState('') + + const context = useMemo( + () => ({ + longitude, + latitude, + setLatitude, + setLongitude, + }), + [longitude, latitude, setLatitude, setLongitude] + ) + + return ( + + {children} + + ) +} + +export default SettingsProvider diff --git a/front/example-app/src/components/Settings/Settings.tsx b/front/example-app/src/components/Settings/Settings.tsx new file mode 100644 index 000000000..bc5b2da67 --- /dev/null +++ b/front/example-app/src/components/Settings/Settings.tsx @@ -0,0 +1,136 @@ +import { + Button, + Fade, + IconButton, + Paper, + Popper, + TextField, + styled, +} from '@mui/material' +import SettingsIcon from '@mui/icons-material/Settings' +import React, { + FormEvent, + useContext, + useEffect, + useRef, + useState, +} from 'react' +import { locationContext } from 'src/contexts' + +function Settings(): JSX.Element { + const [anchorEl, setAnchorEl] = React.useState(null) + const formRef = useRef(null) + const [open, setOpen] = useState(false) + const popperRef = useRef(null) + const handleClick = (event: React.MouseEvent): void => { + setAnchorEl(anchorEl ? null : event.currentTarget) + setOpen((curr) => !curr) + } + + const { longitude, latitude, setLatitude, setLongitude } = + useContext(locationContext) + + const id = open ? 'simple-popper' : undefined + + function handleSubmit(e: FormEvent): void { + e.preventDefault() + const { latitude, longitude } = Object.fromEntries( + new FormData(formRef.current).entries() + ) + if (latitude && longitude) { + setLatitude(latitude.toString()) + setLongitude(longitude.toString()) + setOpen(false) + setAnchorEl(null) + } + } + + useEffect(() => { + function handleClickOutside(event: MouseEvent): void { + if ( + popperRef.current && + !popperRef.current.contains(event.target as Node) && + !anchorEl?.contains(event.target as Node) + ) { + setOpen(false) + setAnchorEl(null) + } + } + + if (open) { + document.addEventListener('mousedown', handleClickOutside) + } else { + document.removeEventListener('mousedown', handleClickOutside) + } + + return () => { + document.removeEventListener('mousedown', handleClickOutside) + } + }, [open, anchorEl]) + + const CutomForm = styled('form')(({ theme }) => ({ + padding: theme.spacing(2), + display: 'flex', + flexDirection: 'column', + gap: theme.spacing(2), + })) + + return ( + <> + + + + + {({ TransitionProps }): JSX.Element => ( + + + + + + + + + + + )} + + + ) +} + +export default Settings diff --git a/front/example-app/src/contexts/index.ts b/front/example-app/src/contexts/index.ts index 5756cb721..c6e7fc4aa 100644 --- a/front/example-app/src/contexts/index.ts +++ b/front/example-app/src/contexts/index.ts @@ -5,3 +5,4 @@ export * from './extraBundles' export * from './search' export * from './requestedPath' export * from './user' +export * from './settings' diff --git a/front/example-app/src/contexts/settings.ts b/front/example-app/src/contexts/settings.ts new file mode 100644 index 000000000..7fde77e6c --- /dev/null +++ b/front/example-app/src/contexts/settings.ts @@ -0,0 +1,10 @@ +import { Dispatch, SetStateAction, createContext } from 'react' + +export interface ISettingsContext { + longitude: string + latitude: string + setLongitude: Dispatch> + setLatitude: Dispatch> +} + +export const locationContext = createContext(null) diff --git a/front/example-app/src/hooks/useProducts.ts b/front/example-app/src/hooks/useProducts.ts index 200ff798a..ce08e76e0 100644 --- a/front/example-app/src/hooks/useProducts.ts +++ b/front/example-app/src/hooks/useProducts.ts @@ -21,7 +21,7 @@ import { isError, } from '@elastic-suite/gally-admin-shared' -import { catalogContext } from '../contexts' +import { catalogContext, locationContext } from '../contexts' import { IActiveFilters, IFilterMoreOptions, IProductsHook } from '../types' import { getProductFilters } from '../services' @@ -47,6 +47,7 @@ export function useProducts( () => getProductFilters(activeFilters), [activeFilters] ) + const { longitude, latitude } = useContext(locationContext) const [products, setProducts, load, debouncedLoad] = useGraphqlApi() @@ -90,7 +91,15 @@ export function useProducts( const loadFunction = activeFilters.length === 0 ? load : debouncedLoad return loadFunction( getSearchProductsQuery(queryFilters, true), - variables as unknown as Record + variables as unknown as Record, + { + headers: { + ...(latitude !== '' && + longitude !== '' && { + 'reference-location': `${latitude}, ${longitude}`, + }), + }, + } ) } setProducts(null) @@ -109,6 +118,8 @@ export function useProducts( setProducts, sort, sortOrder, + latitude, + longitude, ] ) @@ -131,7 +142,15 @@ export function useProducts( } graphqlApi( getMoreFacetProductOptionsQuery(queryFilters), - variables as unknown as Record + variables as unknown as Record, + { + headers: { + ...(latitude !== '' && + longitude !== '' && { + 'reference-location': `${latitude}, ${longitude}`, + }), + }, + } ).then((json) => { if (isError(json)) { setMoreOptions( @@ -158,7 +177,7 @@ export function useProducts( } }) }, - [graphqlApi, localizedCatalogId, queryFilters, search] + [graphqlApi, localizedCatalogId, queryFilters, search, latitude, longitude] ) function updateFilters(filters: SetStateAction): void {