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

Module/map #521

Merged
merged 30 commits into from
Jul 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
86b1ef3
feat(map): base page
b-n Jun 4, 2019
07efa65
add map scaffolding
chrismclarke Jun 4, 2019
bc44313
feat(map): basic render with data
b-n Jun 6, 2019
d84cbb1
feat(map): attempt to fix performance
b-n Jun 9, 2019
e129823
feat(map): beginning of filters
b-n Jun 9, 2019
dad6f68
feat(map): using mobx more, removed "optimization", tidied styles
b-n Jun 26, 2019
e143a71
feat(map): begin of work on controls section
b-n Jun 26, 2019
0ca95f6
feat(maps): filters now filters the filters
b-n Jul 3, 2019
cf43226
feat(maps): now with counts in the filters
b-n Jul 3, 2019
3881d7a
feat(maps): now centers and zooms on location search
b-n Jul 3, 2019
0de8eb3
feat(map): WIP popups as a shell
b-n Jul 3, 2019
45cfc03
feat(maps): making popups styled again
b-n Jul 3, 2019
4d736d8
Revert "add map scaffolding"
b-n Jul 8, 2019
b5b6154
chore: renaming + tidying up things, removing bind
b-n Jul 10, 2019
c9562dc
chore: organising files a bit better
b-n Jul 10, 2019
04610d0
feat(container): pageWidth characteristics on page containers
b-n Jul 10, 2019
9f1ad45
chore: check pull #519 for this change
b-n Jul 10, 2019
1b7d83b
fix(container): fullPageWidth is optional
b-n Jul 11, 2019
10e5a21
Merge pull request #519 from OneArmyWorld/feat/module/map/pageWidth
BenGamma Jul 11, 2019
d3b825a
Merge pull request #517 from OneArmyWorld/feat/module/map/frontend
BenGamma Jul 11, 2019
32b2416
fix commit in pageList
BenGamma Jul 12, 2019
5a38535
add yarn.lock
BenGamma Jul 12, 2019
f8b1a04
rename /maps to /map & add map link to header
BenGamma Jul 12, 2019
1bc2fb3
remove padding & margin from pageContainer on ignoreMaxWidth components
BenGamma Jul 12, 2019
70ede27
add welcome text in breadcrumb for map
BenGamma Jul 12, 2019
dedf56f
quick and dirty fix for map height
BenGamma Jul 12, 2019
cf60723
link my pin btn to my location section in settings
BenGamma Jul 12, 2019
fca2f66
remove validation on settings fields
BenGamma Jul 12, 2019
a1ee531
close YearSelector on year select
BenGamma Jul 12, 2019
15f508b
remove /feedback page, add feedback button redirecting to the typefor…
BenGamma Jul 12, 2019
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
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"@devexpress/dx-react-core": "^1.10.1",
"@devexpress/dx-react-grid": "^1.10.1",
"@devexpress/dx-react-grid-material-ui": "^1.10.1",
"@khanacademy/react-multi-select": "^0.3.3",
"@material-ui/core": "3.7.1",
"@material-ui/icons": "3.0.2",
"@rebass/grid": "^6.0.0",
Expand All @@ -31,6 +32,7 @@
"client-compress": "^2.1.2",
"css-loader": "1.0.0",
"date-fns": "^1.30.1",
"debounce": "^1.2.0",
"dompurify": "^1.0.10",
"dotenv": "6.0.0",
"dotenv-expand": "4.2.0",
Expand All @@ -48,6 +50,7 @@
"firebase": "5.8.1",
"fork-ts-checker-webpack-plugin-alt": "0.4.14",
"fs-extra": "7.0.1",
"geolocation-utils": "^1.2.1",
"google-oauth-jwt": "^0.2.0",
"googleapis": "^37.2.0",
"html-webpack-plugin": "4.0.0-alpha.2",
Expand All @@ -58,6 +61,8 @@
"jest-resolve": "23.6.0",
"jest-watch-typeahead": "^0.2.1",
"leaflet": "^1.3.4",
"leaflet.markercluster": "^1.4.1",
"lorem-ipsum": "^2.0.3",
"md5": "^2.2.1",
"mini-css-extract-plugin": "0.5.0",
"mobx": "4.9.2",
Expand All @@ -84,6 +89,7 @@
"react-icons": "^3.2.2",
"react-image-lightbox": "^5.1.0",
"react-leaflet": "^2.1.4",
"react-leaflet-markercluster": "^2.0.0-rc3",
"react-linkify": "^0.2.2",
"react-portal": "^4.2.0",
"react-pose": "^4.0.8",
Expand Down
21 changes: 15 additions & 6 deletions src/components/Layout/PageContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,30 @@ import { Flex, FlexProps } from 'rebass'
import theme from 'src/themes/styled.theme'
import { VersionNumber } from '../VersionNumber/VersionNumber'

type InnerContainerProps = MaxWidthProps & SpaceProps & WidthProps
type InnerContainerProps = MaxWidthProps &
SpaceProps &
WidthProps & {
ignoreMaxWidth?: boolean
}

const InnerContainer = styled.div<InnerContainerProps>`
${space}
${width}
${maxWidth}
${p => (p.ignoreMaxWidth ? 'max-width: inherit;' : maxWidth)}
margin: ${p => (p.ignoreMaxWidth ? 0 : undefined)};
padding: ${p => (p.ignoreMaxWidth ? 0 : undefined)};
min-height: calc(100vh - 156px);
margin-bottom:0;
padding-bottom: 32px;
position: relative
position: relative;
`
interface IProps extends FlexProps {
ignoreMaxWidth?: boolean
}

const PageContainer = (props: FlexProps) => (
const PageContainer = (props: IProps) => (
<Flex {...props} bg={theme.colors.background}>
<InnerContainer>
<InnerContainer ignoreMaxWidth={props.ignoreMaxWidth}>
{props.children} <VersionNumber />
</InnerContainer>
</Flex>
Expand All @@ -35,13 +44,13 @@ const PageContainer = (props: FlexProps) => (
PageContainer.defaultProps = {
className: 'page-container',
justifyContent: 'center',
px: '2em',
}
InnerContainer.defaultProps = {
className: 'page-inner-container',
maxWidth: theme.maxContainerWidth,
width: 1,
my: 4,
px: '2em',
}

export default PageContainer
105 changes: 105 additions & 0 deletions src/mocks/maps.mock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { loremIpsum } from 'lorem-ipsum'
import {
IMapPin,
IMapPinDetail,
IPinType,
IDatabaseMapPin,
EntityType,
} from 'src/models/maps.models'

export const generatePins = (count: number): Array<IDatabaseMapPin> => {
const filters = generatePinFilters()
const newPins = [] as Array<IDatabaseMapPin>
for (let i = 0; i < count; i++) {
const pinType = filters[Math.floor(Math.random() * filters.length)]

newPins.push({
id: '' + Math.random(),
location: {
address: 'testing',
lat: 51 + (Math.random() * 1000 - 500) / 500,
lng: 0 + (Math.random() * 1000 - 500) / 250,
},
pinType: pinType.name,
})
}
return newPins
}

export const generatePinDetails = (pin: IMapPin): IMapPinDetail => {
const lastActive = new Date()
lastActive.setSeconds(lastActive.getSeconds() - Math.random() * 10000)
return {
...pin,
name: loremIpsum({ count: 2, units: 'words' })
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' '),
shortDescription: loremIpsum({ count: 2, units: 'sentences' }),
lastActive,
profilePicUrl: 'https://picsum.photos/50/50',
profileUrl: '/testing',
heroImageUrl: 'https://picsum.photos/285/175',
}
}

export const generatePinFilters = (): Array<IPinType> => {
return [
{
grouping: 'place' as EntityType,
displayName: 'Extruder',
name: 'extruder',
icon: 'E',
count: 0,
},
{
grouping: 'place' as EntityType,
displayName: 'Injection',
name: 'injecter',
icon: 'I',
count: 0,
},
{
grouping: 'place' as EntityType,
displayName: 'Shredder',
name: 'shredder',
icon: 'S',
count: 0,
},
{
grouping: 'place' as EntityType,
displayName: 'Sheet Press',
name: 'sheetPresser',
icon: 'P',
count: 0,
},
{
grouping: 'place' as EntityType,
displayName: 'R & D / Lab',
name: 'lab',
icon: 'R',
count: 0,
},
{
grouping: 'individual' as EntityType,
displayName: 'Community Builder',
name: 'communityBuilder',
icon: 'C',
count: 0,
},
{
grouping: 'individual' as EntityType,
displayName: 'Member',
name: 'member',
icon: '',
count: 0,
},
{
grouping: 'individual' as EntityType,
displayName: 'Machine Builder',
name: 'machineBuilder',
icon: 'M',
count: 0,
},
]
}
44 changes: 44 additions & 0 deletions src/models/maps.models.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export interface IDatabaseMapPin {
id: string
location: ILatLng & {
address: string
}
pinType: string
}

export interface IMapPin {
id: string
location: ILatLng & {
address: string
}
pinType: IPinType
}

export interface IMapPinDetail extends IMapPin {
name: string
shortDescription: string
lastActive: Date
profilePicUrl: string
profileUrl: string
heroImageUrl: string
}

export interface ILatLng {
lat: number
lng: number
}

export interface IBoundingBox {
topLeft: ILatLng
bottomRight: ILatLng
}

export interface IPinType {
displayName: string
name: string
grouping: EntityType
icon: string
count: number
}

export type EntityType = 'individual' | 'place'
13 changes: 13 additions & 0 deletions src/pages/Maps/Content/Controls/GroupingFilter.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.multi-select {
width: 100%;
max-width: 225px;
margin-left: 20px;
}

.multi-select .dropdown-heading {
height: 45px !important;
}

.multi-select .dropdown-heading-value {
line-height: 45px !important;
}
102 changes: 102 additions & 0 deletions src/pages/Maps/Content/Controls/GroupingFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { Component } from 'react'
import styled from 'styled-components'
import MultiSelect from '@khanacademy/react-multi-select'
import './GroupingFilter.css'

interface IProps {
items: Array<any>
entityType: string
onChange?: (selectedItems) => void
}

interface IState {
selectedItems: Array<string>
}

const ItemLabel = styled.span`
display: inline-block;
vertical-align: middle;
cursor: default;
padding: 2px 8px;
`

interface ItemCounterProps {
grouping: string
}

const ItemCounter = styled.span<ItemCounterProps>`
border-radius: ${p => (p.grouping === 'individual' ? '50%' : '0%')};
background-color: ${p =>
p.grouping === 'individual' ? '#6666FF' : '#FF6666'};
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
line-height: 20px;
font-size: 0.65rem;
text-align: center;
color: white;
margin-left: 5px;
`

const ItemRenderer = ({ checked, option, onClick }) => {
return (
<span>
<input
type="checkbox"
onChange={onClick}
checked={checked}
tabIndex={-1}
/>
<ItemCounter grouping={option.value.grouping}>
{option.value.count}
</ItemCounter>
<ItemLabel>{option.label}</ItemLabel>
</span>
)
}

class GroupingFilter extends React.Component<IProps, IState> {
constructor(props) {
super(props)
this.state = {
selectedItems: props.items,
}
}

handleChange(selectedItems) {
if (this.props.onChange) {
this.props.onChange(selectedItems)
}
this.setState({ selectedItems })
}

render() {
const { selectedItems } = this.state
const { items, entityType } = this.props
const options = items.map(item => ({
label: item.displayName,
value: item,
}))
return (
<MultiSelect
options={options}
selected={selectedItems}
selectAllLabel="Select All"
disableSearch={true}
onSelectedChanged={selected => this.handleChange(selected)}
valueRenderer={() =>
entityType === 'place' ? 'Workplaces' : 'Members'
}
hasSelectAll={false}
ItemRenderer={ItemRenderer}
style={{
maxWidth: '250px',
width: '100%',
}}
/>
)
}
}

export { GroupingFilter }
Loading