Skip to content

Commit

Permalink
feat: add map v2.0.0 (#3829)
Browse files Browse the repository at this point in the history
* feat: add banner component
* refactor: move some map related typing to shared
* chore: drop unused map store function
* feat: add CardList component for new map display
* ci: separate unit test run commands
  • Loading branch information
benfurber authored Aug 26, 2024
1 parent 3ee18a3 commit a164372
Show file tree
Hide file tree
Showing 56 changed files with 863 additions and 345 deletions.
4 changes: 3 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,9 @@ jobs:
- setup_repo
- run:
# NOTE - run-in-band to try reduce memory leaks (https://github.com/facebook/jest/issues/7874)
command: yarn run test:unit && yarn run test:components
command: yarn run test:unit
- run:
command: yarn run test:components
- store_artifacts:
path: coverage
- store_artifacts:
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
"main": "lib/index.js",
"type": "module",
"scripts": {
"start": "concurrently --kill-others --names themes,components,platform --prefix-colors cyan,blue,magenta \"yarn start:themes\" \"yarn start:components\" \"yarn start:platform\"",
"start": "concurrently --kill-others --names themes,components,platform --prefix-colors cyan,blue,magenta \"yarn start:shared\" \"yarn start:themes\" \"yarn start:components\" \"yarn start:platform\"",
"start-ci": "concurrently --kill-others --names themes,components,platform --prefix-colors cyan,blue,magenta \"yarn start:themes\" \"yarn start:components\" \"yarn start:platform-ci\"",
"start:themes": "yarn workspace oa-themes dev",
"start:components": "yarn workspace oa-components dev",
"start:platform": "yarn build:shared && vite",
"start:platform:for-emulated-backend": "yarn build:shared && vite --port 4000",
"start:platform-ci": "yarn build:shared && vite --port 3456",
"start:shared": "yarn workspace oa-shared dev",
"frontend:for-emulated-backend:watch": "concurrently --kill-others --names themes,components,platform --prefix-colors yellow,cyan,blue,magenta \"yarn start:themes\" \"yarn start:components\" \"yarn start:platform:for-emulated-backend\"",
"backend:emulator:watch": "docker-compose up --force-recreate --build",
"build:themes": "yarn workspace oa-themes build",
Expand All @@ -29,7 +30,7 @@
"build:post": "yarn workspace oa-scripts post-build",
"build:inject-config": "yarn build:post",
"build:shared": "yarn workspace oa-shared build",
"build": "yarn build:themes && yarn build:components && yarn build:shared && yarn build:vite",
"build": "yarn build:shared && yarn build:themes && yarn build:components && yarn build:vite",
"lint": "yarn lint:style && yarn lint:code",
"lint:commits": " npx commitlint --from=$(git merge-base master HEAD) --verbose",
"lint:code": "eslint . --ext .js,.jsx,.ts,.tsx src --color",
Expand All @@ -40,13 +41,13 @@
"format:style": "prettier --write '**/*.{md,json,js,tsx,ts}'",
"serve": "npx serve -s build",
"test": "yarn workspace oa-cypress start",
"test:components": "yarn workspace oa-components test-ci",
"test:components": "yarn workspace oa-components test",
"test:unit": "yarn build:themes && yarn build:components && vitest",
"test:madge": "npx madge --circular --extensions ts,tsx ./ --exclude src/stores",
"storybook": "yarn workspace oa-components start",
"__note_build-storybook": "build-storybook is needed for the CI",
"build-storybook": "yarn build:themes && yarn workspace oa-components chromatic",
"storybook:build": "yarn build:themes && yarn workspace oa-components build:sb",
"storybook:build": "yarn build:shared && yarn build:themes && yarn workspace oa-components build:sb",
"docs": "yarn workspace oa-docs start",
"install:clean": "yarn workspace oa-scripts install:clean",
"postinstall": "husky install",
Expand Down
30 changes: 30 additions & 0 deletions packages/components/src/Banner/Banner.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Banner } from './Banner'

import type { Meta, StoryFn } from '@storybook/react'

export default {
title: 'Layout/Banner',
component: Banner,
} as Meta<typeof Banner>

export const Default: StoryFn<typeof Banner> = () => (
<Banner>Defaults to a failure banner when no varient defined</Banner>
)

export const AccentWithOnclick: StoryFn<typeof Banner> = () => (
<Banner variant="accent" onClick={() => null}>
This is an accent with onClick
</Banner>
)

export const InfoWithCustomStylings: StoryFn<typeof Banner> = () => (
<Banner variant="info" sx={{ height: '200px', border: '4px solid #333' }}>
Info with custom stylings
</Banner>
)

export const Success: StoryFn<typeof Banner> = () => (
<Banner variant="success" onClick={() => null}>
Success Banner
</Banner>
)
16 changes: 16 additions & 0 deletions packages/components/src/Banner/Banner.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { fireEvent } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'

import { render } from '../test/utils'
import { Banner } from './Banner'

describe('Banner', () => {
it('sets the default varient if none is provided', () => {
const onClick = vi.fn()
const { getByText } = render(<Banner onClick={onClick}>Some words</Banner>)

fireEvent.click(getByText('Some words'))

expect(onClick).toHaveBeenCalled()
})
})
37 changes: 37 additions & 0 deletions packages/components/src/Banner/Banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Alert } from 'theme-ui'

import type { ThemeUIStyleObject } from 'theme-ui'

// Types of alert currently specificed in the theme
type AlertVariants = 'accent' | 'failure' | 'info' | 'success'

export interface IProps {
children: React.ReactNode
onClick?: () => void
sx?: ThemeUIStyleObject | undefined
variant?: AlertVariants
}

export const Banner = (props: IProps) => {
const { children, onClick, sx, variant } = props

return (
<Alert
data-cy="Banner"
onClick={onClick}
variant={variant || 'failure'}
sx={{
borderRadius: 0,
alignItems: 'center',
flex: '1',
justifyContent: 'center',
cursor: onClick ? 'pointer' : 'default',
fontSize: 2,
':hover': { textDecoration: onClick ? 'underline' : 'none' },
...sx,
}}
>
{children}
</Alert>
)
}
30 changes: 30 additions & 0 deletions packages/components/src/CardList/CardList.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { CardList } from './CardList'

import type { Meta, StoryFn } from '@storybook/react'
import type { ProfileTypeName } from 'oa-shared'

export default {
title: 'Layout/CardList',
component: CardList,
} as Meta<typeof CardList>

const allItems = [
{ _id: 'first-one', type: 'member' as ProfileTypeName },
{ _id: 'second-one', type: 'collection-point' as ProfileTypeName },
{ _id: 'third', type: 'member' as ProfileTypeName },
{ _id: '4th', type: 'member' as ProfileTypeName },
]

export const Default: StoryFn<typeof CardList> = () => {
return <CardList list={allItems} filteredList={null} />
}

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

return <CardList list={allItems} filteredList={filteredList} />
}

export const WhenFiltedDisplayIsZero: StoryFn<typeof CardList> = () => {
return <CardList list={allItems} filteredList={[]} />
}
35 changes: 35 additions & 0 deletions packages/components/src/CardList/CardList.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import '@testing-library/jest-dom/vitest'

import { describe, expect, it } from 'vitest'

import { render } from '../test/utils'
import { EMPTY_LIST, type IProps } from './CardList'
import {
Default,
FiltedDisplay,
WhenFiltedDisplayIsZero,
} from './CardList.stories'

describe('CardList', () => {
it('Shows all items when no filtering is done', () => {
const { getAllByTestId } = render(<Default {...(Default.args as IProps)} />)

expect(getAllByTestId('CardListItem').length).toBe(4)
})

it('Shows only filted items when provided', () => {
const { getAllByTestId } = render(
<FiltedDisplay {...(FiltedDisplay.args as IProps)} />,
)

expect(getAllByTestId('CardListItem').length).toBe(2)
})

it('Shows the no items label when filted items is empty', () => {
const { getByText } = render(
<WhenFiltedDisplayIsZero {...(WhenFiltedDisplayIsZero.args as IProps)} />,
)

expect(getByText(EMPTY_LIST)).toBeInTheDocument()
})
})
57 changes: 57 additions & 0 deletions packages/components/src/CardList/CardList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Flex, Grid, Text } from 'theme-ui'

import { CardListItem } from '../CardListItem/CardListItem'
import { Loader } from '../Loader/Loader'

import type { ListItem } from '../CardListItem/CardListItem'

export interface IProps {
filteredList: ListItem[] | null
list: ListItem[]
}

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

export const CardList = (props: IProps) => {
const { filteredList, list } = props

const listToShow = filteredList === null ? list : filteredList
const displayItems = listToShow.map((item) => (
<CardListItem item={item} key={item._id} />
))

const isListEmpty = displayItems.length === 0
const hasListLoaded = list
const results = `${displayItems.length} ${displayItems.length == 1 ? 'result' : 'results'}`

return (
<Flex
data-cy="CardList"
sx={{
flexDirection: 'column',
gap: 4,
}}
>
{!hasListLoaded && <Loader />}
{hasListLoaded && (
<>
<Flex>
<Text data-cy="list-results">{results}</Text>
</Flex>
<Grid
sx={{
alignItems: 'flex-start',
flexWrap: 'wrap',
gap: 4,
}}
width="250px"
columns={3}
>
{!isListEmpty && displayItems}
{isListEmpty && EMPTY_LIST}
</Grid>
</>
)}
</Flex>
)
}
27 changes: 27 additions & 0 deletions packages/components/src/CardListItem/CardListItem.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { CardListItem } from './CardListItem'

import type { Meta, StoryFn } from '@storybook/react'
import type { ProfileTypeName } from 'oa-shared'

export default {
title: 'Components/CardListItem',
component: CardListItem,
} as Meta<typeof CardListItem>

export const DefaultMember: StoryFn<typeof CardListItem> = () => {
const item = {
_id: 'not-selected-onload',
type: 'member' as ProfileTypeName,
}

return <CardListItem item={item} />
}

export const DefaultSpace: StoryFn<typeof CardListItem> = () => {
const item = {
_id: 'not-selected-onload',
type: 'workspace' as ProfileTypeName,
}

return <CardListItem item={item} />
}
58 changes: 58 additions & 0 deletions packages/components/src/CardListItem/CardListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Card, Flex } from 'theme-ui'

import { InternalLink } from '../InternalLink/InternalLink'
import { MemberBadge } from '../MemberBadge/MemberBadge'
import { Username } from '../Username/Username'

import type { ProfileTypeName } from 'oa-shared'

export interface ListItem {
_id: string
type: ProfileTypeName
}

export interface IProps {
item: ListItem
}

export const CardListItem = (props: IProps) => {
const { item } = props

return (
<InternalLink
data-cy="CardListItem"
data-testid="CardListItem"
to={`/u/${item._id}`}
sx={{
borderRadius: 2,
marginTop: '2px',
'&:hover': {
animationSpeed: '0.3s',
cursor: 'pointer',
marginTop: '0',
borderBottom: '2px solid',
transform: 'translateY(-2px)',
transition: 'borderBottom 0.2s, transform 0.2s',
borderColor: 'black',
},
'&:active': {
transform: 'translateY(1px)',
borderBottom: '1px solid',
borderColor: 'grey',
transition: 'borderBottom 0.2s, transform 0.2s, borderColor 0.2s',
},
}}
>
<Card>
<Flex sx={{ flexDirection: 'row', gap: 2, padding: 2 }}>
<MemberBadge profileType={item.type} size={30} />
<Username
user={{ userName: item._id }}
hideFlag
sx={{ alignSelf: 'flex-start' }}
/>
</Flex>
</Card>
</InternalLink>
)
}
4 changes: 3 additions & 1 deletion packages/components/src/CreateComment/CreateComment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Box, Button, Flex, Text, Textarea } from 'theme-ui'

import { MemberBadge } from '../MemberBadge/MemberBadge'

import type { ProfileTypeName } from 'oa-shared'

export interface Props {
maxLength: number
isLoggedIn: boolean
Expand All @@ -12,7 +14,7 @@ export interface Props {
onChange: (value: string) => void
comment: string
placeholder?: string
userProfileType?: string
userProfileType?: ProfileTypeName
buttonLabel?: string
}

Expand Down
6 changes: 2 additions & 4 deletions packages/components/src/Map/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,15 @@ import './index.css'

export interface IProps extends MapProps {
children?: React.ReactNode | React.ReactNode[]
setZoom?: (arg: number) => void
setZoom: (arg: number) => void
ref?: RefObject<LeafletMap> | undefined
}

export const Map = forwardRef((props: IProps, ref: Ref<LeafletMap>) => {
const { children, setZoom } = props

const onViewportChanged = (viewport: Viewport) => {
if (viewport.zoom && setZoom) {
setZoom(viewport.zoom)
}
viewport.zoom && setZoom(viewport.zoom)
}

return (
Expand Down
Loading

0 comments on commit a164372

Please sign in to comment.