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

feat(#1290383): [Example App] Add latitude and Longitude Field in a S… #632

Merged
merged 1 commit into from
Oct 28, 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
2 changes: 2 additions & 0 deletions front/example-app/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -142,6 +143,7 @@ function Header(): JSX.Element {
)}
</Box>
</Box>
<Settings />
</Toolbar>
</AppBar>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,27 @@ exports[`Header match snapshot 1`] = `
</div>
</div>
</div>
<button
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeMedium css-142yyjb-MuiButtonBase-root-MuiIconButton-root"
tabindex="0"
type="button"
>
<svg
aria-hidden="true"
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-i4bv87-MuiSvgIcon-root"
color="#fff"
data-testid="SettingsIcon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"
/>
</svg>
<span
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
/>
</button>
</div>
</nav>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -22,9 +23,11 @@ function AppProvider(props: IProps): JSX.Element {
<ConfigurationsProvider>
<RequestedPathProvider>
<ExtraBundlesProvider>
<CategoryProvider>
<SearchProvider>{children}</SearchProvider>
</CategoryProvider>
<SettingsProvider>
<CategoryProvider>
<SearchProvider>{children}</SearchProvider>
</CategoryProvider>
</SettingsProvider>
</ExtraBundlesProvider>
</RequestedPathProvider>
</ConfigurationsProvider>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { ReactNode, useMemo, useState } from 'react'
import { ISettingsContext, settingsContext } from '../../../contexts'

interface IProps {
children: ReactNode
}

function SettingsProvider({ children }: IProps): JSX.Element {
const [longitude, setLongitude] = useState<string>('')
const [latitude, setLatitude] = useState<string>('')

const context = useMemo<ISettingsContext>(
() => ({
longitude,
latitude,
setLatitude,
setLongitude,
}),
[longitude, latitude, setLatitude, setLongitude]
)

return (
<settingsContext.Provider value={context}>
{children}
</settingsContext.Provider>
)
}

export default SettingsProvider
139 changes: 139 additions & 0 deletions front/example-app/src/components/Settings/Settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import {
Button,
Fade,
IconButton,
Paper,
Popper,
TextField,
styled,
} from '@mui/material'
import SettingsIcon from '@mui/icons-material/Settings'
import React, {
FormEvent,
MouseEvent,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from 'react'

import { settingsContext } from 'src/contexts'

function Settings(): JSX.Element {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
const formRef = useRef<HTMLFormElement>(null)
const open = useMemo(() => Boolean(anchorEl), [anchorEl])
const popperRef = useRef<HTMLDivElement>(null)
const handleClick = (event: MouseEvent<HTMLElement>): void => {
setAnchorEl(anchorEl ? null : event.currentTarget)
}

const { longitude, latitude, setLatitude, setLongitude } =
useContext(settingsContext)

const id = open ? 'simple-popper' : undefined

function handleSubmit(e: FormEvent<HTMLFormElement>): void {
e.preventDefault()
const { latitude, longitude } = Object.fromEntries(
new FormData(formRef.current).entries()
)
setLatitude(latitude.toString())
setLongitude(longitude.toString())
if (latitude && longitude) {
setAnchorEl(null)
}
}

useEffect(() => {
function handleClickOutside(event: globalThis.MouseEvent): void {
if (
popperRef.current &&
!popperRef.current.contains(event.target as Node) &&
!anchorEl?.contains(event.target as Node)
) {
setAnchorEl(null)
}
}

if (open) {
document.addEventListener('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),
}))

const Row = styled('div')(({ theme }) => ({
display: 'flex',
gap: theme.spacing(2),
alignItems: 'center',
}))

return (
<>
<IconButton onClick={handleClick} sx={{ marginLeft: '20px' }}>
<SettingsIcon htmlColor="#fff" />
</IconButton>
<Popper
id={id}
open={open}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tu pourrais n'avoir qu'un seul state anchorEl et supprimer open car tu peux ici faire: open={Boolean(anchorEl)}

anchorEl={anchorEl}
ref={popperRef}
sx={{
zIndex: 1200,
}}
transition
>
{({ TransitionProps }): JSX.Element => (
<Fade {...TransitionProps} timeout={350}>
<Paper>
<CutomForm ref={formRef} onSubmit={handleSubmit}>
<Row>
<TextField
id="outlined-basic"
label="Latitude"
variant="outlined"
name="latitude"
type="number"
defaultValue={latitude}
inputProps={{
step: '0.000001',
min: -90,
max: 90,
}}
/>
<TextField
id="outlined-basic"
label="Longitude"
variant="outlined"
type="number"
name="longitude"
defaultValue={longitude}
inputProps={{
step: '0.000001',
min: -180,
max: 180,
}}
/>
</Row>

<Button type="submit" variant="outlined">
Appliquer
</Button>
</CutomForm>
</Paper>
</Fade>
)}
</Popper>
</>
)
}

export default Settings
1 change: 1 addition & 0 deletions front/example-app/src/contexts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './extraBundles'
export * from './search'
export * from './requestedPath'
export * from './user'
export * from './settings'
10 changes: 10 additions & 0 deletions front/example-app/src/contexts/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Dispatch, SetStateAction, createContext } from 'react'

export interface ISettingsContext {
longitude: string
latitude: string
setLongitude: Dispatch<SetStateAction<ISettingsContext['longitude']>>
setLatitude: Dispatch<SetStateAction<ISettingsContext['latitude']>>
}

export const settingsContext = createContext<ISettingsContext>(null)
4 changes: 2 additions & 2 deletions front/example-app/src/hooks/useProducts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import {
fetchGraphql,
} from '@elastic-suite/gally-admin-shared'

import { renderHookWithProviders } from '../utils/tests'

import { useProducts } from './useProducts'
import { renderHookWithProviders } from '../utils/tests'

describe('useProducts', () => {
it('should call the API when loading the product', async () => {
const { result } = renderHookWithProviders(() =>
useProducts(ProductRequestType.SEARCH)
)

expect(result.current.products).toEqual({
status: LoadStatus.IDLE,
})
Expand Down
35 changes: 31 additions & 4 deletions front/example-app/src/hooks/useProducts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
isError,
} from '@elastic-suite/gally-admin-shared'

import { catalogContext } from '../contexts'
import { catalogContext, settingsContext } from '../contexts'
import { IActiveFilters, IFilterMoreOptions, IProductsHook } from '../types'
import { getProductFilters } from '../services'

Expand All @@ -47,6 +47,7 @@ export function useProducts(
() => getProductFilters(activeFilters),
[activeFilters]
)
const { longitude, latitude } = useContext(settingsContext)

const [products, setProducts, load, debouncedLoad] =
useGraphqlApi<IGraphqlSearchProducts>()
Expand Down Expand Up @@ -90,7 +91,15 @@ export function useProducts(
const loadFunction = activeFilters.length === 0 ? load : debouncedLoad
return loadFunction(
getSearchProductsQuery(queryFilters, true),
variables as unknown as Record<string, unknown>
variables as unknown as Record<string, unknown>,
{
headers: {
...(latitude !== '' &&
longitude !== '' && {
'reference-location': `${latitude}, ${longitude}`,
}),
},
}
)
}
setProducts(null)
Expand All @@ -109,6 +118,8 @@ export function useProducts(
setProducts,
sort,
sortOrder,
latitude,
longitude,
]
)

Expand All @@ -134,7 +145,15 @@ export function useProducts(
}
graphqlApi<IGraphqlViewMoreProductFacetOptions>(
getMoreFacetProductOptionsQuery(queryFilters),
variables as unknown as Record<string, unknown>
variables as unknown as Record<string, unknown>,
{
headers: {
...(latitude !== '' &&
longitude !== '' && {
'reference-location': `${latitude}, ${longitude}`,
}),
},
}
).then((json) => {
if (isError(json)) {
setMoreOptions(
Expand All @@ -161,7 +180,15 @@ export function useProducts(
}
})
},
[graphqlApi, localizedCatalogId, queryFilters, search]
[
graphqlApi,
localizedCatalogId,
queryFilters,
search,
latitude,
longitude,
currentCategoryId,
]
)

function updateFilters(filters: SetStateAction<IActiveFilters>): void {
Expand Down
15 changes: 14 additions & 1 deletion front/example-app/src/utils/TestProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { IApi, IUser, schemaContext } from '@elastic-suite/gally-admin-shared'

import {
ICatalogContext,
ISettingsContext,
catalogContext,
categoryContext,
settingsContext,
userContext,
} from '../contexts'
import { catalogsGraphql, categoriesGraphql } from '../mocks'
Expand Down Expand Up @@ -36,6 +38,13 @@ const catalogContextValue = {
onLocalizedCatalogIdChange: (): void => void null,
} as ICatalogContext

const settingsContextValue: ISettingsContext = {
longitude: '',
latitude: '',
setLatitude: (): void => void null,
setLongitude: (): void => void null,
}

function TestProvider(props: IProps): JSX.Element {
const { api, children } = props

Expand All @@ -51,7 +60,11 @@ function TestProvider(props: IProps): JSX.Element {
<categoryContext.Provider
value={categoriesGraphql.data.getCategoryTree.categories}
>
<RequestedPathProvider>{children}</RequestedPathProvider>
<RequestedPathProvider>
<settingsContext.Provider value={settingsContextValue}>
{children}
</settingsContext.Provider>
</RequestedPathProvider>
</categoryContext.Provider>
</catalogContext.Provider>
</schemaContext.Provider>
Expand Down
Loading