Skip to content

Commit

Permalink
feat: update active pin interaction for new map
Browse files Browse the repository at this point in the history
  • Loading branch information
benfurber committed Nov 21, 2024
1 parent 19db983 commit 70e567b
Show file tree
Hide file tree
Showing 17 changed files with 192 additions and 175 deletions.
2 changes: 1 addition & 1 deletion packages/components/src/CardButton/CardButton.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default {

export const Basic: StoryFn<typeof CardButton> = () => (
<div style={{ width: '300px' }}>
<CardButton>
<CardButton isSelected={false}>
<div style={{ padding: '20px' }}>Basic Implementation</div>
</CardButton>
</div>
Expand Down
13 changes: 11 additions & 2 deletions packages/components/src/CardButton/CardButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import type { BoxProps, ThemeUIStyleObject } from 'theme-ui'
export interface IProps extends BoxProps {
children: React.ReactNode
extrastyles?: ThemeUIStyleObject | undefined
isSelected?: boolean
}

export const CardButton = (props: IProps) => {
const { children, extrastyles } = props
const { children, extrastyles, isSelected } = props

return (
<Card
Expand All @@ -19,7 +20,7 @@ export const CardButton = (props: IProps) => {
borderRadius: 2,
padding: 0,
transition: 'borderBottom 0.2s, transform 0.2s',
'&:hover': {
'&:hover': !isSelected && {
animationSpeed: '0.3s',
cursor: 'pointer',
marginTop: '0',
Expand All @@ -33,6 +34,14 @@ export const CardButton = (props: IProps) => {
borderColor: 'grey',
transition: 'borderBottom 0.2s, transform 0.2s, borderColor 0.2s',
},
...(isSelected
? {
marginTop: '0',
borderBottom: '4px solid',
borderColor: 'grey',
transform: 'translateY(-2px)',
}
: {}),
...extrastyles,
}}
{...props}
Expand Down
34 changes: 31 additions & 3 deletions packages/components/src/CardList/CardList.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,46 @@ const allItems = [
},
]

const onBlur = () => undefined
const onPinClick = () => undefined

export const Default: StoryFn<typeof CardList> = () => {
return <CardList dataCy="stories" list={allItems} filteredList={null} />
return (
<CardList
list={allItems}
onBlur={onBlur}
onPinClick={onPinClick}
filteredList={null}
selectedPin={undefined}
viewport="stories"
/>
)
}

export const FiltedDisplay: StoryFn<typeof CardList> = () => {
const filteredList = [allItems[0], allItems[2]]

return (
<CardList dataCy="stories" list={allItems} filteredList={filteredList} />
<CardList
list={allItems}
onBlur={onBlur}
onPinClick={onPinClick}
filteredList={filteredList}
selectedPin={undefined}
viewport="stories"
/>
)
}

export const WhenFiltedDisplayIsZero: StoryFn<typeof CardList> = () => {
return <CardList dataCy="stories" list={allItems} filteredList={[]} />
return (
<CardList
list={allItems}
onBlur={onBlur}
onPinClick={onPinClick}
filteredList={[]}
selectedPin={undefined}
viewport="stories"
/>
)
}
30 changes: 26 additions & 4 deletions packages/components/src/CardList/CardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,26 @@ import type { IMapPin } from 'oa-shared'

export interface IProps {
columnsCountBreakPoints?: { [key: number]: number }
dataCy: string
filteredList: IMapPin[] | null
list: IMapPin[]
onBlur: () => void
onPinClick: (arg: IMapPin) => void
selectedPin: IMapPin | undefined
viewport: string
}

export const EMPTY_LIST = 'Oh nos! Nothing to show!'

export const CardList = (props: IProps) => {
const { columnsCountBreakPoints, dataCy, filteredList, list } = props
const {
columnsCountBreakPoints,
filteredList,
list,
onBlur,
onPinClick,
selectedPin,
viewport,
} = props

const listToShow = filteredList === null ? list : filteredList
const displayItems = listToShow
Expand All @@ -26,7 +37,18 @@ export const CardList = (props: IProps) => {
Date.parse(b.creator?._lastActive || '0') -
Date.parse(a.creator?._lastActive || '0'),
)
.map((item) => <CardListItem item={item} key={item._id} />)
.map((item) => {
const isSelectedPin = item._id === selectedPin?._id
return (
<CardListItem
item={item}
key={item._id}
isSelectedPin={isSelectedPin}
onPinClick={isSelectedPin ? onBlur : onPinClick}
viewport={viewport}
/>
)
})

const isListEmpty = displayItems.length === 0
const hasListLoaded = list
Expand All @@ -36,7 +58,7 @@ export const CardList = (props: IProps) => {

return (
<Flex
data-cy={`CardList-${dataCy}`}
data-cy={`CardList-${viewport}`}
sx={{
flexDirection: 'column',
gap: 2,
Expand Down
24 changes: 21 additions & 3 deletions packages/components/src/CardListItem/CardListItem.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export default {
component: CardListItem,
} as Meta<typeof CardListItem>

const onPinClick = () => undefined
const viewport = 'desktop'

export const DefaultMember: StoryFn<typeof CardListItem> = () => {
const item = {
_deleted: false,
Expand All @@ -31,7 +34,12 @@ export const DefaultMember: StoryFn<typeof CardListItem> = () => {

return (
<div style={{ width: '500px' }}>
<CardListItem item={item} />
<CardListItem
item={item}
isSelectedPin={false}
onPinClick={onPinClick}
viewport={viewport}
/>
</div>
)
}
Expand Down Expand Up @@ -63,7 +71,12 @@ export const DefaultSpace: StoryFn<typeof CardListItem> = () => {

return (
<div style={{ width: '500px' }}>
<CardListItem item={item} />
<CardListItem
item={item}
isSelectedPin={false}
onPinClick={onPinClick}
viewport={viewport}
/>
</div>
)
}
Expand All @@ -80,7 +93,12 @@ export const DefaultFallback: StoryFn<typeof CardListItem> = () => {

return (
<div style={{ width: '500px' }}>
<CardListItem item={item} />
<CardListItem
item={item}
isSelectedPin={false}
onPinClick={onPinClick}
viewport={viewport}
/>
</div>
)
}
47 changes: 38 additions & 9 deletions packages/components/src/CardListItem/CardListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Box } from 'theme-ui'

import { CardButton } from '../CardButton/CardButton'
import { CardProfile } from '../CardProfile/CardProfile'
import { InternalLink } from '../InternalLink/InternalLink'
Expand All @@ -6,22 +8,49 @@ import type { IMapPin } from 'oa-shared'

export interface IProps {
item: IMapPin
isSelectedPin: boolean
onPinClick: (arg: IMapPin) => void
viewport: string
}

export const CardListItem = ({ item }: IProps) => {
export const CardListItem = (props: IProps) => {
const { item, onPinClick, isSelectedPin, viewport } = props
const testProp = `CardListItem${isSelectedPin ? '-selected' : ''}`

const Card = (
<CardButton isSelected={isSelectedPin}>
<CardProfile item={item} />
</CardButton>
)

const wrapperProps = {
'data-cy': testProp,
'data-testid': testProp,
sx: {
borderRadius: 2,
padding: 2,
},
}

if (viewport === 'mobile') {
return (
<InternalLink target="_blank" to={`/u/${item._id}`} {...wrapperProps}>
{Card}
</InternalLink>
)
}

return (
<InternalLink
data-cy="CardListItem"
data-testid="CardListItem"
to={`/u/${item._id}`}
<Box
data-cy={testProp}
data-testid={testProp}
onClick={() => onPinClick(item)}
sx={{
borderRadius: 2,
padding: 2,
}}
>
<CardButton>
<CardProfile item={item} />
</CardButton>
</InternalLink>
{Card}
</Box>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const CardDetailsFallback = ({ item, isLink }: IProps) => {
user={{ userName: _id }}
sx={{ alignSelf: 'flex-start' }}
isLink={isLink}
target="_blank"
/>
{subType && (
<Category
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const CardDetailsMemberProfile = ({ creator, isLink }: IProps) => {
}}
sx={{ alignSelf: 'flex-start' }}
isLink={isLink}
target="_blank"
/>
{tags && <ProfileTagsList tags={tags} />}
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export const CardDetailsSpaceProfile = ({ creator, isLink }: IProps) => {
}}
sx={{ alignSelf: 'flex-start' }}
isLink={isLink}
target="_blank"
/>
</Flex>

Expand Down
5 changes: 4 additions & 1 deletion packages/components/src/Username/Username.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ import { FlagIconHowTos } from '../FlagIcon/FlagIcon'
import { InternalLink } from '../InternalLink/InternalLink'
import { twoCharacterCountryCodes } from './TwoCharacterCountryCodes'

import type { HTMLAttributeAnchorTarget } from 'react'
import type { ThemeUIStyleObject } from 'theme-ui'
import type { User } from '../types/common'

export interface IProps {
user: User
sx?: ThemeUIStyleObject
isLink?: boolean
target?: HTMLAttributeAnchorTarget
}

const isValidCountryCode = (str: string) =>
str && twoCharacterCountryCodes.has(str.toUpperCase())

export const Username = ({ user, sx, isLink = true }: IProps) => {
export const Username = ({ user, sx, target, isLink = true }: IProps) => {
const { countryCode, userName, isSupporter, isVerified } = user

const UserNameBody = (
Expand Down Expand Up @@ -83,6 +85,7 @@ export const Username = ({ user, sx, isLink = true }: IProps) => {
return (
<InternalLink
to={`/u/${userName}`}
target={target || '_self'}
sx={{
border: '1px solid transparent',
display: 'inline-flex',
Expand Down
19 changes: 10 additions & 9 deletions packages/cypress/src/integration/map.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('[Map]', () => {
cy.url().should('not.include', `#${userId}`)

cy.step('Link to new map visible and clickable')
cy.wait(500) // wait for interaction
cy.get('[data-cy=Banner]').contains('Test it out!').click()
cy.get('[data-cy=Banner]').contains('go back to the old one!')

Expand Down Expand Up @@ -68,14 +69,16 @@ describe('[Map]', () => {
}
cy.get('[data-cy="list-results"]').contains('1 result')
cy.get('[data-cy="CardList-desktop"]').within(() => {
cy.get('[data-cy=CardListItem]')
.within(() => {
cy.contains(userId)
cy.get('[data-cy="MemberBadge-member"]')
})
.should('have.attr', 'href')
.and('include', `/u/${userId}`)
cy.get('[data-cy=CardListItem]').within(() => {
cy.contains(userId)
cy.get('[data-cy="MemberBadge-member"]')
})
})
cy.get('[data-cy=CardListItem]').contains(userId).click()
cy.get('[data-cy="PinProfile"]')
.get('[data-cy="Username"]')
.contains(userId)
cy.get('[data-cy=CardListItem-selected]').first().click()

cy.step('New map pins can be clicked on')
cy.get(`[data-cy=pin-${userId}]`).click()
Expand Down Expand Up @@ -115,8 +118,6 @@ describe('[Map]', () => {
cy.contains(userId)
cy.get('[data-cy="MemberBadge-member"]')
})
.should('have.attr', 'href')
.and('include', `/u/${userId}`)
})
cy.get('[data-cy=MapFilterProfileTypeCardList-ButtonRight]')
.last()
Expand Down
8 changes: 4 additions & 4 deletions src/pages/Maps/Content/MapView/MapView.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ import type { ILatLng, IMapPin } from 'oa-shared'
import type { Map as MapType } from 'react-leaflet'

interface IProps {
activePin: IMapPin | null
activePin: IMapPin | undefined
center: ILatLng
mapRef: React.RefObject<MapType>
pins: Array<IMapPin>
zoom: number
onPinClicked: (pin: IMapPin) => void
onPinClick: (pin: IMapPin) => void
onBlur: () => void
setZoom: (arg: number) => void
}

export const MapView = (props: IProps) => {
const { activePin, center, mapRef, onPinClicked, pins, zoom, setZoom } = props
const { activePin, center, mapRef, onPinClick, pins, zoom, setZoom } = props
const isViewportGreaterThanTablet = window.innerWidth > 1024
const mapCenter: LatLngExpression = center ? [center.lat, center.lng] : [0, 0]
const mapZoom = center ? zoom : 2
Expand All @@ -45,7 +45,7 @@ export const MapView = (props: IProps) => {
props.onBlur()
}}
>
<Clusters pins={pins} onPinClick={onPinClicked} />
<Clusters pins={pins} onPinClick={onPinClick} />
{activePin && <Popup activePin={activePin} mapRef={mapRef} />}
</Map>
)
Expand Down
Loading

0 comments on commit 70e567b

Please sign in to comment.