Skip to content

Commit

Permalink
4204 - FRA Kiosk: Latest Activities map (#4241)
Browse files Browse the repository at this point in the history
* 4204 - FRA Kiosk: Latest Activities - Route & base map (#4237)

* 4204 - Add Latest activities Kiosk Route

* 4204 - Add base map

* 4204 - FRA Kiosk: Latest Activities map - Markers (#4242)

* 4204 - Add latestActivities.csv file

* 4204 - Remove unused json2csv & add client side csv parser papaparse

* 4204 - Add activity markers

* 4204 - Add Latest Activities list panel

* 4204 - Fix coordinates

* 4204 - Format data in the backend

* 4204 - Remove papaparse

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
yaguzmang and mergify[bot] authored Jan 28, 2025
1 parent 358853e commit b4bc8a7
Show file tree
Hide file tree
Showing 31 changed files with 543 additions and 30 deletions.
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
"@types/google.maps": "^3.48.3",
"@types/jest": "^27.4.1",
"@types/jsdom": "^21.1.6",
"@types/json2csv": "^5.0.3",
"@types/jsonwebtoken": "^8.5.6",
"@types/lodash.clonedeep": "^4.5.6",
"@types/lodash.debounce": "^4.0.6",
Expand Down Expand Up @@ -208,7 +207,6 @@
"jodit-react": "^4.0.9",
"jsdom": "^24.0.0",
"jsep": "^1.3.4",
"json2csv": "^5.0.7",
"jsonwebtoken": "^8.5.1",
"lodash.chunk": "^4.2.0",
"lodash.clonedeep": "^4.5.0",
Expand Down Expand Up @@ -297,4 +295,4 @@
"prettier --write"
]
}
}
}
6 changes: 6 additions & 0 deletions src/client/pages/Kiosk/Kiosk.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ const cards: Array<KioskCardProps> = [
link: Routes.Fra2020DataPlatform.path.relative,
title: 'FRA2020 \n data platform',
},
{
altText: 'Latest activities',
imageUrl: '/img/kiosk/latest-activities.png',
link: Routes.LatestActivities.path.relative,
title: 'Latest \n activities',
},
{
altText: 'Interactive stories',
imageUrl: '/img/kiosk/interactive-stories.png',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
$activities-bg: #c7e2c5;

.kiosk-latest-activities__list {
background-color: rgba($activities-bg, 0.6);
border-radius: 15px;
display: flex;
flex-direction: column;
left: 1%;
max-height: 95dvh;
overflow: auto;
position: absolute;
top: 1%;
width: 25%;
}

.kiosk-latest-activities__list-container {
padding: min(0.8dvw, 1.5dvh);
}

.kiosk-latest-activities__list-title-container {
background-color: rgba($activities-bg, 0.8);
display: flex;
justify-content: center;
width: 100%;

> h1 {
color: #ef7a2d;
font-size: min(2.331dvw, 4.1475dvh);
font-weight: 900;
margin: min(0.8dvw, 1.5dvh) 0;
text-align: center;
text-shadow: $activities-bg 0px 0px 5px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import './ActivityList.scss'
import React from 'react'

import { Activity } from 'meta/kiosk'

import ActivityListItem from 'client/pages/Kiosk/LatestActivities/ActivityListItem'

type Props = {
activities: Array<Activity> | undefined
expandedActivity: string | null
handleExpand: (activity: Activity, map: google.maps.Map) => void
map: google.maps.Map
}

const ActivityList: React.FC<Props> = (props: Props) => {
const { activities, expandedActivity, handleExpand, map } = props

return (
<div className="kiosk-latest-activities__list">
<div className="kiosk-latest-activities__list-title-container">
<h1>Latest Activities</h1>
</div>
<div className="kiosk-latest-activities__list-container">
{activities?.map((activity) => (
<ActivityListItem
key={activity.date}
activity={activity}
expanded={expandedActivity === activity.id}
handleExpand={handleExpand}
map={map}
/>
))}
</div>
</div>
)
}

export default ActivityList
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ActivityList'
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.kiosk-latest-activities__list-item {
display: grid;
padding: 0.5dvh 0;
transition: all 0.1s ease;

&.expanded {
background-color: rgba(white, 0.85);
border-radius: 10px;
box-shadow: 0 0 1px 1px rgba(#07090a, 0.5);
}
}

.kiosk-latest-activities__list-item-content {
color: black;
display: grid;
font-size: min(1dvw, 1.6dvh);
line-height: 1.5;

&.expanded {
padding: min(0.9dvw, 1.5dvh) min(0.9dvw, 1.5dvh);
transition: max-height 0.25s ease-out;
}

&:not(.expanded) {
max-height: 0;
transition: max-height 0.15s ease-out;
}
}

.kiosk-latest-activities__list-item-header {
display: grid;
justify-items: center;

button.button.inverse {
background-color: rgba(white, 0.85);

&:hover {
background-color: white;
}
}
}

.kiosk-latest-activities__list-item-button {
background-color: #5aa955;
border-radius: 10px;
display: flex;
font-size: min(0.89dvw, 1.5dvh);
height: 4dvh;
justify-content: center;
width: 75%;

&:hover {
background-color: lighten(#ef7a2d, 5%);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import './ActivityListItem.scss'
import React from 'react'

import classNames from 'classnames'

import { Activity } from 'meta/kiosk'

import Button, { ButtonType } from 'client/components/Buttons/Button'

type Props = {
activity: Activity
expanded: boolean
handleExpand: (activity: Activity, map: google.maps.Map) => void
map: google.maps.Map
}

const _getActivityLabel = (date: string, countryName: string): string => {
const parsedDate = new Date(date)
const month = parsedDate.toLocaleString('en-US', { month: 'long' })
const year = parsedDate.getFullYear()
return `${month} ${year} - ${countryName}`
}

const ActivityListItem: React.FC<Props> = (props: Props) => {
const { activity, expanded, handleExpand, map } = props

return (
<div className={classNames('kiosk-latest-activities__list-item', { expanded })}>
<div className="kiosk-latest-activities__list-item-header">
<Button
className="kiosk-latest-activities__list-item-button"
inverse={!expanded}
label={_getActivityLabel(activity.date, activity.countryName)}
onClick={() => {
handleExpand(activity, map)
}}
type={ButtonType.black}
/>
</div>
<div className={classNames(`kiosk-latest-activities__list-item-content`, { expanded })}>
{expanded && <div>{activity.description}</div>}
</div>
</div>
)
}

export default ActivityListItem
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ActivityListItem'
9 changes: 9 additions & 0 deletions src/client/pages/Kiosk/LatestActivities/LatestActivities.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react'

import MapWrapper from 'client/pages/Kiosk/LatestActivities/MapWrapper'

const LatestActivities: React.FC = () => {
return <MapWrapper />
}

export default LatestActivities
4 changes: 4 additions & 0 deletions src/client/pages/Kiosk/LatestActivities/Map/Map.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.kiosk-latest-activities__map {
height: 100%;
width: 100%;
}
32 changes: 32 additions & 0 deletions src/client/pages/Kiosk/LatestActivities/Map/Map.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import './Map.scss'
import React, { useCallback, useState } from 'react'

import { Activity } from 'meta/kiosk'

import ActivityList from 'client/pages/Kiosk/LatestActivities/ActivityList'

import { useFetchAndMarkActivities } from './hooks/useFetchAndMarkActivities'
import { useLatestActivitiesMap } from './hooks/useLatestActivitiesMap'

const Map: React.FC = () => {
const [expandedActivity, setExpandedActivity] = useState<string | null>(null)

const handleExpand = useCallback((activity: Activity, map: google.maps.Map) => {
setExpandedActivity((prev) => (prev === activity.id ? null : activity.id))
map?.panTo({ lat: activity.lat, lng: activity.lng })
}, [])

const { addMarkers, map, ref } = useLatestActivitiesMap({ expandedActivity, handleExpand })
const { data } = useFetchAndMarkActivities({ addMarkers, map })

return (
<>
<div ref={ref} className="kiosk-latest-activities__map" />
{map !== null && (
<ActivityList activities={data} expandedActivity={expandedActivity} handleExpand={handleExpand} map={map} />
)}
</>
)
}

export default Map
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useEffect, useState } from 'react'

import axios from 'axios'
import { Objects } from 'utils/objects'

import { ApiEndPoint } from 'meta/api/endpoint'
import { Activity } from 'meta/kiosk'

type Props = {
addMarkers: (activities: Array<Activity>) => void
map: google.maps.Map
}

export const useFetchAndMarkActivities = (props: Props) => {
const { addMarkers, map } = props

const [data, setData] = useState<Array<Activity> | null>(null)
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const [markersAdded, setMarkersAdded] = useState(false)

useEffect(() => {
if (!Objects.isNil(data) || isLoading || !Objects.isNil(error)) return

const fetchLatestActivities = async () => {
setIsLoading(true)
setError(null)

try {
const response = await axios.get<Array<Activity>>(ApiEndPoint.Kiosk.latestActivities(), {
responseType: 'json',
})

setData(response.data)
} catch (_err: unknown) {
setError('There was a problem while getting the latest activities.')
} finally {
setIsLoading(false)
}
}

fetchLatestActivities()
}, [data, error, isLoading])

useEffect(() => {
if (markersAdded || Objects.isNil(data) || !Objects.isFunction(addMarkers) || !map) return

addMarkers(data)
setMarkersAdded(true)
}, [addMarkers, data, map, markersAdded])

return { data, error, isLoading }
}
Loading

0 comments on commit b4bc8a7

Please sign in to comment.