From 58994092b7937b4aedd599d154a3a7bd6951dcbe Mon Sep 17 00:00:00 2001 From: Md Kaif Ansari Date: Wed, 29 Oct 2025 00:58:23 +0530 Subject: [PATCH 1/9] chore: re-run workflow From 76932159ba203f6d113836a2499488f7d336025f Mon Sep 17 00:00:00 2001 From: Md Kaif Ansari Date: Wed, 29 Oct 2025 01:00:50 +0530 Subject: [PATCH 2/9] fix: Prevent Accidental Map Zooming While Scrolling on Landing Page --- .../unit/components/ChapterMap.test.tsx | 85 +++++++++++++++++-- frontend/src/components/ChapterMap.tsx | 47 +++++++++- 2 files changed, 123 insertions(+), 9 deletions(-) diff --git a/frontend/__tests__/unit/components/ChapterMap.test.tsx b/frontend/__tests__/unit/components/ChapterMap.test.tsx index d16027d496..6612d371e7 100644 --- a/frontend/__tests__/unit/components/ChapterMap.test.tsx +++ b/frontend/__tests__/unit/components/ChapterMap.test.tsx @@ -1,4 +1,4 @@ -import { render } from '@testing-library/react' +import { render, fireEvent } from '@testing-library/react' import { Chapter } from 'types/chapter' import ChapterMap from 'components/ChapterMap' @@ -6,6 +6,11 @@ const mockMap = { setView: jest.fn().mockReturnThis(), addLayer: jest.fn().mockReturnThis(), fitBounds: jest.fn().mockReturnThis(), + on: jest.fn().mockReturnThis(), + scrollWheelZoom: { + enable: jest.fn(), + disable: jest.fn(), + }, } const mockMarker = { @@ -95,12 +100,16 @@ describe('ChapterMap', () => { describe('rendering', () => { it('renders the map container with correct id and style', () => { - render() + const { container } = render() const mapContainer = document.getElementById('chapter-map') expect(mapContainer).toBeInTheDocument() expect(mapContainer).toHaveAttribute('id', 'chapter-map') - expect(mapContainer).toHaveStyle('width: 100%; height: 400px;') + expect(mapContainer).toHaveClass('h-full', 'w-full') + + // Check that the parent container has the correct styles applied + const parentContainer = container.firstChild as HTMLElement + expect(parentContainer).toHaveClass('relative') }) it('renders with empty data without crashing', () => { @@ -123,6 +132,7 @@ describe('ChapterMap', () => { [90, 180], ], maxBoundsViscosity: 1.0, + scrollWheelZoom: false, }) expect(mockMap.setView).toHaveBeenCalledWith([20, 0], 2) }) @@ -150,6 +160,12 @@ describe('ChapterMap', () => { expect(L.markerClusterGroup).toHaveBeenCalled() expect(mockMap.addLayer).toHaveBeenCalledWith(mockMarkerClusterGroup) }) + + it('sets up event listeners for map interaction', () => { + render() + expect(mockMap.on).toHaveBeenCalledWith('click', expect.any(Function)) + expect(mockMap.on).toHaveBeenCalledWith('mouseout', expect.any(Function)) + }) }) describe('Markers', () => { @@ -221,6 +237,58 @@ describe('ChapterMap', () => { }) }) + describe('Interactive Overlay', () => { + it('displays overlay with "Click to interact with map" message initially', () => { + const { getByText } = render() + expect(getByText('Click to interact with map')).toBeInTheDocument() + }) + + it('removes overlay when clicked', () => { + const { getByText, queryByText } = render() + + const overlay = getByText('Click to interact with map').closest('div[role="button"]') + fireEvent.click(overlay!) + + expect(queryByText('Click to interact with map')).not.toBeInTheDocument() + }) + + it('enables scroll wheel zoom when overlay is clicked', () => { + const { getByText } = render() + + const overlay = getByText('Click to interact with map').closest('div[role="button"]') + fireEvent.click(overlay!) + + expect(mockMap.scrollWheelZoom.enable).toHaveBeenCalled() + }) + + it('handles keyboard interaction with Enter key', () => { + const { getByText } = render() + + const overlay = getByText('Click to interact with map').closest('div[role="button"]') + fireEvent.keyDown(overlay!, { key: 'Enter' }) + + expect(mockMap.scrollWheelZoom.enable).toHaveBeenCalled() + }) + + it('handles keyboard interaction with Space key', () => { + const { getByText } = render() + + const overlay = getByText('Click to interact with map').closest('div[role="button"]') + fireEvent.keyDown(overlay!, { key: ' ' }) + + expect(mockMap.scrollWheelZoom.enable).toHaveBeenCalled() + }) + + it('has proper accessibility attributes', () => { + const { getByText } = render() + + const overlay = getByText('Click to interact with map').closest('div[role="button"]') + expect(overlay).toHaveAttribute('role', 'button') + expect(overlay).toHaveAttribute('tabIndex', '0') + expect(overlay).toHaveAttribute('aria-label', 'Click to interact with map') + }) + }) + describe('Local View', () => { it('sets local view when showLocal is true', () => { // eslint-disable-next-line @typescript-eslint/no-require-imports @@ -281,10 +349,15 @@ describe('ChapterMap', () => { it('applies custom styles correctly', () => { const customStyle = { width: '800px', height: '600px', border: '1px solid red' } - render() + const { container } = render() + + // Custom styles should be applied to the parent container + const parentContainer = container.firstChild as HTMLElement + expect(parentContainer).toHaveStyle('width: 800px; height: 600px; border: 1px solid red;') + // Map container should have Tailwind classes const mapContainer = document.getElementById('chapter-map') - expect(mapContainer).toHaveStyle('width: 800px; height: 600px; border: 1px solid red;') + expect(mapContainer).toHaveClass('h-full', 'w-full') }) }) @@ -297,4 +370,4 @@ describe('ChapterMap', () => { expect(mapContainer).toHaveAttribute('id', 'chapter-map') }) }) -}) +}) \ No newline at end of file diff --git a/frontend/src/components/ChapterMap.tsx b/frontend/src/components/ChapterMap.tsx index 36c360aca5..65dff53755 100644 --- a/frontend/src/components/ChapterMap.tsx +++ b/frontend/src/components/ChapterMap.tsx @@ -1,6 +1,6 @@ 'use client' import L, { MarkerClusterGroup } from 'leaflet' -import React, { useEffect, useRef } from 'react' +import React, { useEffect, useRef, useState } from 'react' import type { Chapter } from 'types/chapter' import 'leaflet.markercluster' import 'leaflet/dist/leaflet.css' @@ -19,6 +19,7 @@ const ChapterMap = ({ }) => { const mapRef = useRef(null) const markerClusterRef = useRef(null) + const [isMapActive, setIsMapActive] = useState(false) useEffect(() => { if (!mapRef.current) { @@ -29,12 +30,25 @@ const ChapterMap = ({ [90, 180], ], maxBoundsViscosity: 1.0, + scrollWheelZoom: false, // Disable scroll wheel zoom by default }).setView([20, 0], 2) L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors', className: 'map-tiles', }).addTo(mapRef.current) + + // Enable scroll wheel zoom when user clicks on the map + mapRef.current.on('click', () => { + mapRef.current?.scrollWheelZoom.enable() + setIsMapActive(true) + }) + + // Disable scroll wheel zoom when mouse leaves the map + mapRef.current.on('mouseout', () => { + mapRef.current?.scrollWheelZoom.disable() + setIsMapActive(false) + }) } const map = mapRef.current @@ -102,7 +116,34 @@ const ChapterMap = ({ } }, [geoLocData, showLocal]) - return
+ return ( +
+
+ {!isMapActive && ( +
{ + mapRef.current?.scrollWheelZoom.enable() + setIsMapActive(true) + }} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault() + mapRef.current?.scrollWheelZoom.enable() + setIsMapActive(true) + } + }} + aria-label="Click to interact with map" + > +
+ Click to interact with map +
+
+ )} +
+ ) } -export default ChapterMap +export default ChapterMap \ No newline at end of file From 475b4dc66df74251e8f3bf5315f088e5905e5011 Mon Sep 17 00:00:00 2001 From: Md Kaif Ansari Date: Wed, 29 Oct 2025 01:29:55 +0530 Subject: [PATCH 3/9] chore: implemented mouseout event --- frontend/src/components/ChapterMap.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/ChapterMap.tsx b/frontend/src/components/ChapterMap.tsx index 65dff53755..4eda9b417b 100644 --- a/frontend/src/components/ChapterMap.tsx +++ b/frontend/src/components/ChapterMap.tsx @@ -30,7 +30,7 @@ const ChapterMap = ({ [90, 180], ], maxBoundsViscosity: 1.0, - scrollWheelZoom: false, // Disable scroll wheel zoom by default + scrollWheelZoom: false, }).setView([20, 0], 2) L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { @@ -38,14 +38,16 @@ const ChapterMap = ({ className: 'map-tiles', }).addTo(mapRef.current) - // Enable scroll wheel zoom when user clicks on the map mapRef.current.on('click', () => { mapRef.current?.scrollWheelZoom.enable() setIsMapActive(true) }) - // Disable scroll wheel zoom when mouse leaves the map - mapRef.current.on('mouseout', () => { + mapRef.current.on('mouseout', (e: L.LeafletMouseEvent) => { + const relatedTarget = (e.originalEvent as MouseEvent).relatedTarget as Node | null + const popupPane = mapRef.current?.getPanes().popupPane + if (relatedTarget && popupPane?.contains(relatedTarget)) return + mapRef.current?.scrollWheelZoom.disable() setIsMapActive(false) }) From ff3b3d10eb396c31acb7be30712523bb8f94b21a Mon Sep 17 00:00:00 2001 From: Md Kaif Ansari Date: Thu, 30 Oct 2025 00:07:24 +0530 Subject: [PATCH 4/9] fix: update ChapterMap component to use button for overlay interaction and improve accessibility, and run make check-test --- .../__tests__/unit/components/ChapterMap.test.tsx | 13 ++++++------- frontend/src/components/ChapterMap.tsx | 14 +++++++------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/frontend/__tests__/unit/components/ChapterMap.test.tsx b/frontend/__tests__/unit/components/ChapterMap.test.tsx index 6612d371e7..005a707413 100644 --- a/frontend/__tests__/unit/components/ChapterMap.test.tsx +++ b/frontend/__tests__/unit/components/ChapterMap.test.tsx @@ -246,7 +246,7 @@ describe('ChapterMap', () => { it('removes overlay when clicked', () => { const { getByText, queryByText } = render() - const overlay = getByText('Click to interact with map').closest('div[role="button"]') + const overlay = getByText('Click to interact with map').closest('button') fireEvent.click(overlay!) expect(queryByText('Click to interact with map')).not.toBeInTheDocument() @@ -255,7 +255,7 @@ describe('ChapterMap', () => { it('enables scroll wheel zoom when overlay is clicked', () => { const { getByText } = render() - const overlay = getByText('Click to interact with map').closest('div[role="button"]') + const overlay = getByText('Click to interact with map').closest('button') fireEvent.click(overlay!) expect(mockMap.scrollWheelZoom.enable).toHaveBeenCalled() @@ -264,7 +264,7 @@ describe('ChapterMap', () => { it('handles keyboard interaction with Enter key', () => { const { getByText } = render() - const overlay = getByText('Click to interact with map').closest('div[role="button"]') + const overlay = getByText('Click to interact with map').closest('button') fireEvent.keyDown(overlay!, { key: 'Enter' }) expect(mockMap.scrollWheelZoom.enable).toHaveBeenCalled() @@ -273,7 +273,7 @@ describe('ChapterMap', () => { it('handles keyboard interaction with Space key', () => { const { getByText } = render() - const overlay = getByText('Click to interact with map').closest('div[role="button"]') + const overlay = getByText('Click to interact with map').closest('button') fireEvent.keyDown(overlay!, { key: ' ' }) expect(mockMap.scrollWheelZoom.enable).toHaveBeenCalled() @@ -282,8 +282,7 @@ describe('ChapterMap', () => { it('has proper accessibility attributes', () => { const { getByText } = render() - const overlay = getByText('Click to interact with map').closest('div[role="button"]') - expect(overlay).toHaveAttribute('role', 'button') + const overlay = getByText('Click to interact with map').closest('button') expect(overlay).toHaveAttribute('tabIndex', '0') expect(overlay).toHaveAttribute('aria-label', 'Click to interact with map') }) @@ -370,4 +369,4 @@ describe('ChapterMap', () => { expect(mapContainer).toHaveAttribute('id', 'chapter-map') }) }) -}) \ No newline at end of file +}) diff --git a/frontend/src/components/ChapterMap.tsx b/frontend/src/components/ChapterMap.tsx index 4eda9b417b..2b68551230 100644 --- a/frontend/src/components/ChapterMap.tsx +++ b/frontend/src/components/ChapterMap.tsx @@ -47,7 +47,7 @@ const ChapterMap = ({ const relatedTarget = (e.originalEvent as MouseEvent).relatedTarget as Node | null const popupPane = mapRef.current?.getPanes().popupPane if (relatedTarget && popupPane?.contains(relatedTarget)) return - + mapRef.current?.scrollWheelZoom.disable() setIsMapActive(false) }) @@ -122,8 +122,8 @@ const ChapterMap = ({
{!isMapActive && ( -
{ @@ -139,13 +139,13 @@ const ChapterMap = ({ }} aria-label="Click to interact with map" > -
+

Click to interact with map -

-
+

+ )}
) } -export default ChapterMap \ No newline at end of file +export default ChapterMap From f20e4d8d69f6580944c4baa6dbf73796ea06d1cd Mon Sep 17 00:00:00 2001 From: Md Kaif Ansari Date: Fri, 31 Oct 2025 22:30:18 +0530 Subject: [PATCH 5/9] refactor: update the button style made it dark mode compatible --- frontend/src/components/ChapterMap.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/ChapterMap.tsx b/frontend/src/components/ChapterMap.tsx index 2b68551230..69ce80ee86 100644 --- a/frontend/src/components/ChapterMap.tsx +++ b/frontend/src/components/ChapterMap.tsx @@ -120,7 +120,7 @@ const ChapterMap = ({ return (
-
+
{!isMapActive && ( From e8503295bca835ed252f1351ab6f4832c8b9bfe4 Mon Sep 17 00:00:00 2001 From: Md Kaif Ansari Date: Fri, 31 Oct 2025 22:52:26 +0530 Subject: [PATCH 6/9] chore: add missing import --- frontend/__tests__/unit/components/ChapterMap.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/__tests__/unit/components/ChapterMap.test.tsx b/frontend/__tests__/unit/components/ChapterMap.test.tsx index df62ab8bc8..68400d3cfe 100644 --- a/frontend/__tests__/unit/components/ChapterMap.test.tsx +++ b/frontend/__tests__/unit/components/ChapterMap.test.tsx @@ -1,4 +1,5 @@ import { render, fireEvent } from '@testing-library/react' +import * as L from 'leaflet' import { Chapter } from 'types/chapter' import ChapterMap from 'components/ChapterMap' From 4fcb4e9a102162793419c1894f12ef98f2d2c77d Mon Sep 17 00:00:00 2001 From: Md Kaif Ansari Date: Fri, 31 Oct 2025 22:54:34 +0530 Subject: [PATCH 7/9] refactor: Avoid disabling on child mouseout events --- frontend/src/components/ChapterMap.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/ChapterMap.tsx b/frontend/src/components/ChapterMap.tsx index ec9006a3ec..f6af271ac0 100644 --- a/frontend/src/components/ChapterMap.tsx +++ b/frontend/src/components/ChapterMap.tsx @@ -44,9 +44,10 @@ const ChapterMap = ({ }) mapRef.current.on('mouseout', (e: L.LeafletMouseEvent) => { - const relatedTarget = (e.originalEvent as MouseEvent).relatedTarget as Node | null - const popupPane = mapRef.current?.getPanes().popupPane - if (relatedTarget && popupPane?.contains(relatedTarget)) return + const originalEvent = e.originalEvent as MouseEvent + const relatedTarget = originalEvent.relatedTarget as Node | null + const container = mapRef.current?.getContainer() + if (relatedTarget && container?.contains(relatedTarget)) return mapRef.current?.scrollWheelZoom.disable() setIsMapActive(false) From f8ae74d700693ff50d49ebc9ef3ffd8da1d30249 Mon Sep 17 00:00:00 2001 From: Kate Date: Fri, 31 Oct 2025 18:43:02 -0700 Subject: [PATCH 8/9] Update color for dark theme --- frontend/src/components/ChapterMap.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ChapterMap.tsx b/frontend/src/components/ChapterMap.tsx index f6af271ac0..ef269ee0a6 100644 --- a/frontend/src/components/ChapterMap.tsx +++ b/frontend/src/components/ChapterMap.tsx @@ -146,7 +146,7 @@ const ChapterMap = ({ }} aria-label="Click to interact with map" > -

+

Click to interact with map

From 34c2df7e580a7c80f9d5f41f1f1716257e8c67ea Mon Sep 17 00:00:00 2001 From: Kate Date: Fri, 31 Oct 2025 18:50:49 -0700 Subject: [PATCH 9/9] Address make check issues --- frontend/src/components/ChapterMap.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/ChapterMap.tsx b/frontend/src/components/ChapterMap.tsx index ef269ee0a6..3921e6711d 100644 --- a/frontend/src/components/ChapterMap.tsx +++ b/frontend/src/components/ChapterMap.tsx @@ -127,7 +127,7 @@ const ChapterMap = ({ return (
-
+
{!isMapActive && (