Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0df7742
remove calls to API server
joephayes Sep 29, 2025
1e84573
documentation updates
joephayes Sep 29, 2025
f72ffb1
linter fixes and added plan to modernize the project
joephayes Sep 29, 2025
7de7471
update homepage
joephayes Sep 30, 2025
e2d88db
copies data to public/data directory so it will be included in the build
joephayes Sep 30, 2025
b59cb6d
homepage update
joephayes Sep 30, 2025
902029b
Search now uses static data files
joephayes Sep 30, 2025
b917947
Dependency fun
joephayes Sep 30, 2025
7ab4a1b
more dependecy fun - minimatch
joephayes Sep 30, 2025
7c4cc2b
locale fallback for place names component
joephayes Sep 30, 2025
5f93ee0
fixes search
joephayes Oct 3, 2025
3b27834
fixes various popup errors
joephayes Oct 3, 2025
3bfd541
fix critical vulnerability
joephayes Oct 3, 2025
5ea60a0
✅ 1. Fix axios security vulnerability
joephayes Oct 3, 2025
3ae4085
Legend Toggle Feature
joephayes Oct 3, 2025
dae2d04
add toggle state to search control
joephayes Oct 4, 2025
31a60b7
update to valid JSON
joephayes Oct 4, 2025
75d51f3
updates CLAUDE.md
joephayes Oct 5, 2025
edaaec7
refactors sparqljson2geojson
joephayes Oct 5, 2025
f9b1056
linter fix
joephayes Oct 5, 2025
026536a
remove unused import
joephayes Oct 5, 2025
03ae323
resolve react warnings
joephayes Oct 5, 2025
e1b3a0f
IRI format update
joephayes Oct 5, 2025
a381484
per site resource page
joephayes Oct 5, 2025
29de397
Handle multiple locales
joephayes Oct 5, 2025
2d43191
sync prettify and lint formats
joephayes Oct 5, 2025
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
7 changes: 7 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,12 @@ module.exports = {
allow: ['^nsp_|^cssi_|^wgs_|^rdfs_|^skos_|^foaf_'],
},
],
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: true,
packageDir: './',
},
],
},
};
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v16.20.2
5 changes: 3 additions & 2 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"singleQuote": true,
"trailingComma": "all",
"jsxBracketSameLine": true,
"bracketSameLine": false,
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"quoteProps": "as-needed"
"quoteProps": "as-needed",
"endOfLine": "lf"
}
87 changes: 67 additions & 20 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,105 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Overview

The Norman Sicily Project Interactive Map is a React application that displays historical places and sites in Norman Sicily using Leaflet maps. The application uses Redux for state management, Redux-Saga for side effects, and connects to an external API server for geographical and historical data.
The Norman Sicily Project Interactive Map is a standalone React application that displays historical places and sites in Norman Sicily using Leaflet maps. The application uses Redux for state management, Redux-Saga for side effects, and loads all data from local JSON files. No backend server is required.

## Prerequisites

- Node.js v16.20.2 (use nvm: `nvm use 16`)
- Yarn package manager (preferred) or npm

## Development Commands

- **Start development server**: `npm start` or `yarn start` - Starts the development server on port 3000
- **Build for production**: `npm run build` or `yarn build`
- **Run tests**: `npm test` or `yarn test` - Runs Jest tests in watch mode
- **Start development server**: `yarn start` or `npm start` - Starts the development server on port 3000
- **Build for production**: `yarn build` or `npm run build`
- **Run tests**: `yarn test` or `npm test` - Runs Jest tests in watch mode
- **Lint code**: `npm run lint` - ESLint check for JavaScript/JSX files in src/
- **Fix linting issues**: `npm run lint:fix` - Auto-fix ESLint issues
- **Format code**: `npm run prettify` - Format code using Prettier

## Architecture

### Data Format and IRIs

The project uses **Linked Open Data (LOD)** principles with slash-based IRIs for all entities:

**IRI Pattern**: `http://www.normansicily.org/{namespace}/{class}/{type}/{id}`

**Examples**:
- Places: `http://www.normansicily.org/nsp/place/monastery/164`
- Assessments: `http://www.normansicily.org/cssi/assessment/26`
- People: `http://www.example.com/genealogy.owl#51370564` (external)

This pattern supports:
- Content negotiation for different RDF formats (Turtle, RDF/XML, JSON-LD)
- Dereferenceable URIs following W3C best practices
- Proper 303 redirects from resource to document

### State Management (Redux)
- **Store**: Configured in `src/index.js` with Redux DevTools integration
- **Reducers**: Main reducer in `src/reducers/index.js` handles map state (sites, currentPlace, loading states)
- Transforms data from SPARQL JSON format to GeoJSON via `sparqljson2geojson()`
- Handles multilingual labels (array format or simple strings)
- **Actions**: Located in `src/actions/index.js` for map initialization, site loading, and place fetching
- **Sagas**: `src/sagas/map_saga.js` handles asynchronous operations like API calls
- **Sagas**: `src/sagas/map_saga.js` handles asynchronous operations like loading data from JSON files
- Uses `takeEvery` for initial map load, `takeLatest` for place selection to prevent race conditions
- **Selectors**: `src/selectors/index.js` uses Reselect for memoized state derivation to optimize performance

### Components Structure
- **Presentational Components**: Located in `src/components/` (e.g., `interactive_map.jsx`, `markers.jsx`, `site_popup.jsx`)
- **Container Components**: Located in `src/containers/` - connect Redux state to presentational components
- **Icons**: SVG icons for different place types stored in `src/icons/`

### API Integration
- **Configuration**: `src/config.js` contains API endpoints and map settings
- **API Client**: `src/api.js` handles HTTP requests to the backend
- **Environment Variables**: API server settings configurable via `.env` directory:
- `REACT_APP_API_SERVER_PROTOCOL` (default: http)
- `REACT_APP_API_SERVER_HOST` (default: localhost)
- `REACT_APP_API_SERVER_PORT` (default: 4000)
### Data Integration
- **Configuration**: `src/config.js` contains map settings and tile configuration
- **API Client**: `src/api.js` loads data from local JSON files with retry logic and timeout handling
- Uses native Fetch API with AbortController for request cancellation
- Implements exponential backoff for failed requests
- Falls back to basic place data if detailed place file not found (404)
- **Local Data**: All place data stored in `public/data/places.json` and `public/data/place-details/`
- Detail files named `{placeType}_{placeId}.json`
- **Environment Variables**: Optional Mapbox configuration:
- `REACT_APP_MAPBOX_ACCESS_TOKEN` - Mapbox public access token
- `REACT_APP_MAPBOX_USERNAME` - Mapbox username (default: mapbox)
- `REACT_APP_MAPBOX_STYLE_ID` - Mapbox style ID (default: streets-v11)

### Data Flow
1. Map initializes via `initMap()` action
2. Saga fetches sites from API and transforms Stardog RDF data to GeoJSON
3. Sites are displayed as clustered markers on Leaflet map
4. User interactions (search, marker clicks) trigger place detail fetches
5. Place details are displayed in popups with historical data, images, and references
1. Map initializes via `initMap()` action dispatched in `src/index.js`
2. Saga loads sites from `public/data/places.json` via `getAllPlaces()` API call
3. Reducer transforms data to GeoJSON format and stores in Redux state
4. Sites are displayed as clustered markers on Leaflet map
5. User interactions (search, marker clicks) dispatch `setSelectedPlace()` action
6. Saga loads place details from `public/data/place-details/{placeType}_{placeId}.json`
7. Place details are displayed in popups with historical data, images, and references
8. Map tiles served directly from Mapbox API (if configured) or OpenStreetMap fallback

### Serverless Architecture
- **No Backend Required**: Application runs completely client-side
- **Local Data Storage**: All place data bundled in `public/data/` directory
- **External Tile Services**: Map tiles served from Mapbox or OpenStreetMap
- **Static Hosting Ready**: Can be deployed to any static hosting service

### Key Features
- **Multilingual Support**: Uses `react-redux-multilingual` for i18n
- **Search**: Leaflet GeoSearch integration for place searching
- **Map Clustering**: Uses `react-leaflet-markercluster` for marker grouping
- **Media Integration**: Connects to Mirador viewer for historical images
- **Flexible Tile Sources**: Supports Mapbox (with token) or OpenStreetMap fallback

### Testing
- Uses Jest and Enzyme for component testing
- Test files are co-located with source files (`.test.js` extension)
- Snapshots are stored in `__snapshots__` directories

### Code Quality
- **ESLint**: Configured with Airbnb config and additional plugins
- **Prettier**: Code formatting with pre-commit hooks
- **ESLint**: Configured with Airbnb config and additional plugins (`.eslintrc.js`)
- Custom camelCase exceptions for data field prefixes: `nsp_`, `cssi_`, `wgs_`, `rdfs_`, `skos_`, `foaf_`
- **Prettier**: Code formatting with pre-commit hooks (`.prettierrc`)
- **Husky**: Git hooks for linting and formatting on commit
- **Pre-commit**: Runs `lint:fix` and `prettify` on staged files
- **Lint-staged**: Runs `lint:fix` and `prettify` on staged files automatically

## Important Notes

- **Data Naming Conventions**: Place data fields use underscored prefixes (e.g., `nsp_id`, `wgs_lat`, `cssi_name`) which are exempted from ESLint camelCase rules
- **Locale Support**: Default locale is English (`en`), configurable via `?locale=` query parameter
- **Media Catalog**: Historical images served from external Mirador catalog at `https://media.normansicily.org/data/catalog.js`
173 changes: 173 additions & 0 deletions MODERNIZATION_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Norman Sicily Interactive Map - Modernization Plan

## Overview
This document outlines a phased approach to modernize the Norman Sicily Interactive Map application from its current stable setup (Node 16, React 17, react-scripts 4.x) to the latest Long Term Support (LTS) versions.

**Current Status (Stable):**
- Node.js: v16.20.2
- React: 17.0.1
- react-scripts: 4.0.1
- Dependencies: Legacy but stable versions

**Target (Modern LTS):**
- Node.js: v20.x (Current LTS as of 2024)
- React: 18.x
- react-scripts: 5.x
- Dependencies: Latest compatible versions

## Phase 1: Preparation (1-2 weeks)

### 1.1 Audit and Documentation
- [ ] Document all current functionality and test coverage
- [ ] Create comprehensive test suite for critical user paths
- [ ] Document all custom components and their dependencies
- [ ] Backup current stable version with git tag `stable-node16`

### 1.2 Development Environment Setup
- [ ] Set up parallel development environment with Node 20
- [ ] Create feature branch `modernization-phase1`
- [ ] Test current application compatibility with Node 20 in isolation

### 1.3 Dependency Analysis
- [ ] Run `npm audit` to identify security vulnerabilities
- [ ] Use tools like `npm-check-updates` to identify outdated packages
- [ ] Create compatibility matrix for major dependencies:
- React ecosystem (react, react-dom, react-scripts)
- Leaflet ecosystem (react-leaflet, leaflet plugins)
- Redux ecosystem (react-redux, redux-saga)
- Build tools and linting

## Phase 2: Foundation Upgrade (2-3 weeks)

### 2.1 Node.js Upgrade
- [ ] Upgrade Node.js from 16.20.2 to 20.x LTS
- [ ] Update `.nvmrc` file to specify Node 20
- [ ] Test all npm scripts work with new Node version
- [ ] Update CI/CD configurations if applicable

### 2.2 Package Manager and Lock Files
- [ ] Clean up and consolidate package management (ensure yarn consistency)
- [ ] Remove `package-lock.json` to avoid conflicts
- [ ] Update `yarn.lock` with new Node compatibility

### 2.3 Core React Upgrade
- [ ] Upgrade React from 17.0.1 to 18.x
- [ ] Upgrade react-dom to match React version
- [ ] Address React 18 breaking changes:
- Update to new Root API (`createRoot` vs `render`)
- Handle Strict Mode changes for useEffect
- Address automatic batching changes

## Phase 3: Build System Modernization (2-3 weeks)

### 3.1 react-scripts Upgrade
- [ ] Upgrade react-scripts from 4.0.1 to 5.x
- [ ] Address webpack 5 compatibility issues
- [ ] Handle PostCSS 8+ compatibility problems:
- Update or replace postcss-dependent plugins
- Configure PostCSS plugins properly
- [ ] Test build process thoroughly

### 3.2 ESLint and Code Quality
- [ ] Update ESLint to latest version
- [ ] Update eslint-config-airbnb to latest
- [ ] Address new linting rules and deprecations
- [ ] Update Prettier to latest version
- [ ] Test pre-commit hooks still work

### 3.3 Testing Framework Updates
- [ ] Update Jest and testing-library packages
- [ ] Update Enzyme or migrate to React Testing Library
- [ ] Address any testing compatibility issues
- [ ] Ensure all tests pass with new versions

## Phase 4: Dependencies Modernization (3-4 weeks)

### 4.1 Map Dependencies
- [ ] Update Leaflet to latest stable version
- [ ] Update react-leaflet to latest (v4.x)
- [ ] Address breaking changes in react-leaflet API
- [ ] Update leaflet plugins (markercluster, geosearch)
- [ ] Test all map functionality thoroughly

### 4.2 Redux and State Management
- [ ] Update Redux to latest version
- [ ] Consider migrating to Redux Toolkit (RTK)
- [ ] Update react-redux to latest
- [ ] Update redux-saga or consider RTK Query migration
- [ ] Test all state management functionality

### 4.3 UI and Styling Dependencies
- [ ] Update react-tabs to latest
- [ ] Update mirador and mirador-image-tools
- [ ] Address any CSS/styling compatibility issues
- [ ] Test all UI components

### 4.4 Utility Libraries
- [ ] Update Lodash to latest version (consider tree-shaking)
- [ ] Update Axios to latest version
- [ ] Update other utility dependencies
- [ ] Consider replacing deprecated packages

## Phase 5: Final Integration and Testing (2-3 weeks)

### 5.1 Integration Testing
- [ ] Run full test suite with all updates
- [ ] Perform manual testing of all features
- [ ] Test in production-like environment
- [ ] Performance testing and comparison

### 5.2 Documentation Updates
- [ ] Update README.md with new requirements
- [ ] Update CLAUDE.md with architectural changes
- [ ] Document any breaking changes for users
- [ ] Update package.json scripts if needed

### 5.3 Deployment Preparation
- [ ] Test build process in CI/CD environment
- [ ] Create rollback plan
- [ ] Plan deployment strategy
- [ ] Prepare monitoring for post-deployment

## Risk Mitigation Strategies

### High-Risk Items
1. **react-leaflet API Changes**: Major version upgrades often have breaking changes
2. **PostCSS/webpack 5 Compatibility**: Known issue from previous attempt
3. **React 18 Concurrent Features**: May affect Redux/Saga interactions

### Mitigation Approaches
- Maintain parallel development branches
- Incremental testing at each phase
- Keep detailed rollback procedures
- Consider gradual rollout strategy

## Timeline Estimate

**Total Duration: 10-15 weeks**
- Phase 1: 1-2 weeks
- Phase 2: 2-3 weeks
- Phase 3: 2-3 weeks
- Phase 4: 3-4 weeks
- Phase 5: 2-3 weeks

## Success Criteria

- [ ] Application compiles without errors
- [ ] All existing functionality preserved
- [ ] No regression in performance
- [ ] All tests passing
- [ ] Clean security audit (`npm audit`)
- [ ] Production deployment successful
- [ ] Documentation updated

## Rollback Plan

If critical issues arise:
1. Revert to `stable-node16` git tag
2. Restore Node 16 environment
3. Revert package.json/yarn.lock
4. Clean install dependencies
5. Verify application functionality

This plan ensures a systematic, low-risk approach to modernizing the application while maintaining stability throughout the process.
40 changes: 36 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
[![Build Status](https://travis-ci.org/the-norman-sicily-project/interactive-map.svg?branch=master)](https://travis-ci.org/the-norman-sicily-project/interactive-map)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
A standalone React application that displays historical places and sites in Norman Sicily using interactive maps. This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).

**Note:** This application runs completely standalone without requiring a backend server. All data is bundled locally and map tiles are served directly from external providers.

## Prerequisites

- Node.js v16.20.2 (use nvm: `nvm use 16`)
- Yarn package manager

## Installing

Expand All @@ -13,13 +20,38 @@ Clone the repository:

Move to the directory of the clone:

yarn intall
cd interactive-map

Install dependencies:

yarn install

## Configuration

### Environment Variables (Optional)

For Mapbox tiles, set these environment variables:

- `REACT_APP_MAPBOX_ACCESS_TOKEN` - Your Mapbox public access token
- `REACT_APP_MAPBOX_USERNAME` - Your Mapbox username (default: mapbox)
- `REACT_APP_MAPBOX_STYLE_ID` - Your Mapbox style ID (default: streets-v11)

If not configured, the application will use OpenStreetMap tiles as fallback.

## Running

Start local server at port 3000:
### With Node v16:

source ~/.nvm/nvm.sh && nvm use 16 && yarn start

### With Mapbox configuration:

export REACT_APP_MAPBOX_ACCESS_TOKEN="your_token_here"
export REACT_APP_MAPBOX_USERNAME="your_username"
export REACT_APP_MAPBOX_STYLE_ID="your_style_id"
source ~/.nvm/nvm.sh && nvm use 16 && yarn start

yarn start
The application will start on port 3000: http://localhost:3000

## Running Tests

Expand Down
Loading