Skip to content
Draft
Show file tree
Hide file tree
Changes from 76 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
73efb9e
MUI theme baseline
a-limyr Sep 25, 2025
92acb69
MUI theme baseline
a-limyr Sep 25, 2025
dd94d6c
Created a new header and menu that is modern and uses the theme.
a-limyr Sep 25, 2025
ac97014
Fixed theme loading based on config.
a-limyr Sep 25, 2025
d063e1c
Fixes several issues with menus.
a-limyr Sep 25, 2025
f63f401
Created new updated SearchBox.
a-limyr Sep 26, 2025
6c35a50
improve header layout and search input styling
a-limyr Sep 29, 2025
68f0f61
Hides search box for report page.
a-limyr Sep 29, 2025
7c5858b
Lots of updates and refactoring to separate old and new UI components.
a-limyr Oct 7, 2025
6c4469b
Added theme switching.
a-limyr Oct 7, 2025
d4cbc59
Creating a new map menu and moving map settings from header menu to t…
a-limyr Oct 9, 2025
ce49542
Adding missing translations.
a-limyr Oct 9, 2025
4253e6b
Removed buttons no longer needed and refactored some files.
a-limyr Oct 10, 2025
27546a7
Forgotten files
a-limyr Oct 10, 2025
2ca8773
Created a TS version of the search menu item component.
a-limyr Oct 10, 2025
dab84c6
Merge branch 'master' into feature/modernize-ui-with-mui-theming
a-limyr Oct 14, 2025
b24e2ba
Added location search to main search box.
a-limyr Oct 14, 2025
e62ba20
Fixed fare zone to work with the new layout.
a-limyr Oct 15, 2025
45d664f
Refactored styling to move styling away from components into a separa…
a-limyr Oct 16, 2025
19d0751
Merge branch 'master' into feature/modernize-ui-with-mui-theming
a-limyr Oct 17, 2025
1de63c7
Refactoring the UI structure by introduction an App.tsx file that is …
a-limyr Oct 23, 2025
4b766fd
Support for changing logo.
a-limyr Oct 23, 2025
38ecab0
Changed the theme configuration to be more robust.
a-limyr Oct 23, 2025
3f7b288
Fixed theme switching to use bootstrap.json as point for finding themes.
a-limyr Oct 27, 2025
62db39d
Upgrades to search results, let us view children better and fixes gro…
a-limyr Oct 27, 2025
7585b39
Laying the groundwork for all edit boxes.
a-limyr Oct 28, 2025
f0c3431
Parent stop edit box implementation.
a-limyr Oct 30, 2025
dad5a82
Merge branch 'master' into feature/modernize-ui-with-mui-theming
a-limyr Nov 6, 2025
6850a59
Merge branch 'master' into feature/modernize-ui-with-mui-theming
a-limyr Nov 6, 2025
970547e
Created better navigation after search.
a-limyr Nov 18, 2025
809ab22
Created mini edit box for group of stop places.
a-limyr Nov 21, 2025
38f53fb
Major refactoring of the modern UI to follow best practices with cust…
a-limyr Nov 25, 2025
b42a2ea
Updated context file with latest updates.
a-limyr Nov 25, 2025
c84eef5
Merge branch 'master' into feature/modernize-ui-with-mui-theming
a-limyr Nov 25, 2025
0995c0d
Fixed rendering issues.
a-limyr Nov 25, 2025
d75ef96
Merge remote-tracking branch 'origin/master' into feature/modernize-u…
a-limyr Mar 6, 2026
668184f
Created a modern report page.
a-limyr Mar 6, 2026
f5e2d27
Cleaning up styles.
a-limyr Mar 11, 2026
2c525bf
Upgraded look and design on the first parts of the implementation to …
a-limyr Mar 19, 2026
5461d06
Lots of minor UI tweaks.
a-limyr Mar 24, 2026
acc8807
Fixing build errors.
a-limyr Mar 24, 2026
6a34af1
Merge remote-tracking branch 'origin/master' into feature/modernize-u…
a-limyr Mar 24, 2026
2cb6922
Cleaning up the language files.
a-limyr Mar 24, 2026
5cc598b
Fixed formatting.
a-limyr Mar 24, 2026
fb64a9f
Fixing some build errors.
a-limyr Mar 24, 2026
5993257
Fixed a stale reference.
a-limyr Mar 24, 2026
7a8f9ae
Fixed merge gone wrong.
a-limyr Mar 24, 2026
7dca96a
Turning off kartverket flyfoto.
a-limyr Mar 24, 2026
33b8245
Turning off kartverket flyfoto v2.
a-limyr Mar 24, 2026
6ce8774
Updated config for dev.
a-limyr Mar 24, 2026
a7b5444
Updated config for dev.
a-limyr Mar 25, 2026
f08348c
Minor change in Entur theme file,
a-limyr Mar 25, 2026
6ed8d10
Fixing possible theme loading errors.
a-limyr Mar 25, 2026
f71066a
Merge branch 'master' into feature/modernize-ui-with-mui-theming
a-limyr Apr 8, 2026
a899942
First part of migration to map libre for the modern map.
a-limyr Apr 10, 2026
f0a0dee
Merge branch 'master' into feature/modernize-ui-with-mui-theming
a-limyr Apr 13, 2026
2759730
Map markers.
a-limyr Apr 16, 2026
a5419b7
Merge branch 'master' into feature/modernize-ui-with-mui-theming
a-limyr Apr 16, 2026
2350a38
Fix for build fail.
a-limyr Apr 16, 2026
d9201b7
Separated MapLibre into separate chunk for deployment.
a-limyr Apr 16, 2026
445e39f
Trying to fix the build issues.
a-limyr Apr 16, 2026
e27559f
Circular references in chunks hopefully resolved.
a-limyr Apr 16, 2026
222ebe3
Updated CSP to allow MapLibre to consume map tiles.
a-limyr Apr 16, 2026
b68b4cc
New stop place wizard, initial version.
a-limyr Apr 20, 2026
0bb785a
Code cleanup and minor issues fixed.
a-limyr Apr 21, 2026
95dac12
Added theming guide document.
a-limyr Apr 21, 2026
ff1cdbd
Fixed <h6> inside <h2> nesting issues.
a-limyr Apr 21, 2026
55531d9
Added missing translations.
a-limyr Apr 22, 2026
2adc0f4
Cleaning up separation between legacy and modern code.
a-limyr Apr 22, 2026
20539e9
Cleaning up some more code.
a-limyr Apr 22, 2026
1f87304
Config created for turning modern UI on/off or have dual mode.
a-limyr Apr 23, 2026
030e80e
Updating config for PR build.
a-limyr Apr 23, 2026
6f3a4e6
Removing some clutter from the legacy app files.
a-limyr Apr 27, 2026
4a48f1f
Merge branch 'master' into feature/modernize-ui-with-mui-theming
a-limyr May 6, 2026
fd638f6
Added support for Kartverket flyfoto in the modern UI
a-limyr May 6, 2026
73eef4e
Remove from group button now visible again.
a-limyr May 11, 2026
a434a18
Fixed remove button for GOSP.
a-limyr May 11, 2026
f969c32
Created a new TiamatActions for the modern UI
a-limyr May 15, 2026
73b3132
Removed Google API key
a-limyr May 18, 2026
4f1092c
Merge branch 'master' into feature/modernize-ui-with-mui-theming
a-limyr Jun 3, 2026
bcbb1af
Fix for search bar bug.
a-limyr Jun 3, 2026
3735372
Fixed small search bar bug.
a-limyr Jun 3, 2026
a896848
Changed color for markers.
a-limyr Jun 3, 2026
b94872e
Updated entur theme with right warning color.
a-limyr Jun 3, 2026
6483904
Added a special line for terminated stop places.
a-limyr Jun 3, 2026
d24bf4c
Added updated precision for placing markers.
a-limyr Jun 4, 2026
1a70a03
Added updated precision for placing markers.
a-limyr Jun 4, 2026
e4186c8
Fixed multimodal connection bug.
a-limyr Jun 4, 2026
53e430a
Moved key values to tab.
a-limyr Jun 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
272 changes: 272 additions & 0 deletions .claude/context/feature-modernize-ui-with-mui-theming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
# Abzu UI Modernization

Stop Place Registry app modernizing UI with dual-app architecture. **Core goal: fully responsive design** supporting mobile, tablet, and desktop.

## Architecture

**CRITICAL: Complete UI Separation - Zero mixing of legacy and modern code**

Dual-app structure: `AppRouter` (index.js) switches between `LegacyApp.js` and `modern/App.tsx` based on Redux `uiMode`.

- **Legacy**: `/src/containers/LegacyApp.js`, `/src/components/` (JavaScript)
- **Modern**: `/src/containers/modern/App.tsx`, `/src/components/modern/` (TypeScript + MUI v7)
- **Shared**: Redux state, GraphQL client, map components (with `uiMode` prop), utilities

### Shared Containers Pattern

Some containers are shared by both apps but **MUST conditionally render** based on `uiMode`:

**StopPlace.tsx** - Shared container that renders:
- `uiMode === 'modern'` → `EditParentStopPlace` (modern) for parent stops
- `uiMode === 'legacy'` → `EditParentGeneral` (legacy) for parent stops
- Regular stops currently only have legacy `EditStopGeneral` (modern version not yet created)

**Violation Example:**
```typescript
// ❌ WRONG - Always renders modern component
<EditParentStopPlace />

// ✅ CORRECT - Conditionally renders based on uiMode
{uiMode === "modern" ? (
<EditParentStopPlace />
) : (
<EditParentGeneral disabled={disabled} />
)}
```

**Rule:** Any container or component used by both apps MUST check `uiMode` to render the appropriate version.

### Search Flow (Modern UI)

Direct navigation from search to edit page without intermediate panels:

1. **Search execution** (`useSearchBox.tsx`): User types → debounced search (500ms) → results displayed
2. **Selection** (`handleNewRequest`): Click result → set `loadingSelection=true` → fetch full stop place data
3. **Map marker**: Set marker on map with coordinates → map animates to location (0.25s)
4. **Navigation**: Navigate to edit route → URL changes → `StopPlace.tsx` detects new ID
5. **Data loading**: `getStopPlaceWithAll()` fetches complete stop place data
6. **Loading coverage**: LoadingDialog shows throughout entire flow (from click to data loaded)
7. **Clean transition**: Edit boxes hidden during loading to prevent showing stale data

**Key files**:
- `src/components/modern/MainPage/hooks/useSearchBox.tsx` - Search logic and navigation
- `src/containers/StopPlace.tsx` - Shared container with `uiMode` checks for loading states
- `src/components/modern/Shared/LoadingDialog.tsx` - Centered loading dialog with animation

## Standards

- **Responsive-first**: All modern components must work on mobile, tablet, desktop using `useMediaQuery` and MUI breakpoints
- TypeScript with proper types, custom hooks for logic
- MUI v7 APIs: `slotProps.htmlInput` not `inputProps`, `slotProps.input` not `InputProps`
- Barrel exports via `index.ts`, theme colors via `sx` prop

## Structure

Modern UI: `/src/components/modern/` with Header, MainPage, GroupOfStopPlaces, Dialogs, Shared. Each feature has `types.ts`, components/, hooks/.

## Theme System

JSON config → MUI Theme via module augmentation (`theme-config.d.ts`). Custom properties: `theme.assets.logo`, `theme.environment.{env}`. Config loaded from `bootstrap.json` `themeConfigs` array. First = default, auto-hides switcher if <2 themes.

## Patterns

**Dialogs**: CloseIcon top-right, buttons inline in DialogContent (no DialogActions)
**Drawers**: Persistent (desktop) / temporary (mobile), FloatingActionButton for collapse
**GroupOfStopPlaces**: X = close, chevron = collapse (horizontal on desktop, vertical on mobile)
**Loading States**: Use LoadingDialog (modern UI) for data fetching, shows ModalityLoadingAnimation with optional message

## Component Refactoring Best Practices

**When to Refactor**: Components over ~300 lines, multiple responsibilities, difficult to test, or hard to understand.

### The Refactoring Pattern

Follow this consistent pattern for splitting large components into maintainable pieces:

**1. Directory Structure**
```
ComponentName/
├── hooks/
│ └── useComponentName.ts # Business logic and state
├── components/
│ ├── SubComponent1.tsx # Focused UI components
│ ├── SubComponent2.tsx
│ └── index.ts # Barrel exports
└── types.ts (optional) # Shared types
```

**2. Extract Business Logic into Hooks**
- Move all state management (`useState`, `useEffect`) into custom hook
- Extract event handlers and business logic
- Use `useCallback` for handlers to prevent unnecessary re-renders
- Use `useMemo` for expensive computations or data transformations
- Return clean interface for component consumption

**Hook Pattern Example:**
```typescript
export const useComponentName = ({ prop1, prop2 }) => {
const [state, setState] = useState(initialState);

const handleAction = useCallback(() => {
// Business logic here
}, [dependencies]);

return {
state,
handleAction,
// Other handlers and computed values
};
};
```

**3. Split UI into Focused Components**
- Each component should have **single responsibility**
- Break down by UI section or logical grouping
- Keep components small (~50-150 lines)
- Pass only needed props (avoid prop drilling)
- Add JSDoc comments explaining purpose

**Component Pattern Example:**
```typescript
interface SubComponentProps {
data: DataType;
onAction: () => void;
}

/**
* Brief description of what this component does
*/
export const SubComponent: React.FC<SubComponentProps> = ({
data,
onAction,
}) => {
// Render focused UI section
};
```

**4. Create Orchestrator Component**
- Main component becomes clean orchestrator
- Uses hook for business logic
- Composes sub-components
- Handles conditional rendering
- Delegates responsibilities to focused components

**Orchestrator Pattern Example:**
```typescript
export const MainComponent: React.FC<Props> = ({ prop1, prop2 }) => {
const {
state,
handleAction,
} = useMainComponent({ prop1, prop2 });

return (
<>
<SubComponent1 data={state.data1} onAction={handleAction} />
<SubComponent2 data={state.data2} />
</>
);
};
```

**5. Use Barrel Exports**
```typescript
// components/index.ts
export { SubComponent1 } from "./SubComponent1";
export { SubComponent2 } from "./SubComponent2";
```

### Refactoring Examples

**Completed Refactorings:**
1. **EditGroupOfStopPlaces** (410 → 183 lines, 56% reduction)
- Pattern: MinimizedBar, DrawerContent, Dialogs separation
- Location: `src/components/modern/MainPage/components/EditGroupOfStopPlaces/`

2. **FavoriteStopPlaces** (318 → 62 lines, 81% reduction)
- Pattern: Hook + EmptyState + List + ListItem
- Location: `src/components/modern/MainPage/components/FavoriteStopPlaces/`

3. **TagsDialog** (323 → 106 lines, 67% reduction)
- Pattern: Hook + List + AddForm + Item
- Location: `src/components/modern/Dialogs/TagsDialog/`

4. **TerminateStopPlaceDialog** (374 → 184 lines, 51% reduction)
- Pattern: Hook + Info + Warning + DateTime + Options
- Location: `src/components/modern/Dialogs/TerminateStopPlaceDialog/`

5. **NavigationMenu** (311 → 81 lines, 74% reduction)
- Pattern: Hook + Mobile + Desktop + ItemRenderer
- Location: `src/components/modern/Header/components/NavigationMenu/`

### Naming Conventions

- **Hooks**: `useComponentName` (e.g., `useTagsDialog`, `useNavigationMenu`)
- **Components**: `PascalCase` descriptive names (e.g., `DateTimeSelection`, `UsageWarning`)
- **Files**: Match component/hook names exactly
- **Directories**: Match main component name

### Benefits

- **Maintainability**: Small, focused files easy to understand
- **Testability**: Isolated logic and UI can be tested independently
- **Reusability**: Focused components can be reused elsewhere
- **Readability**: Clear separation of concerns
- **Type Safety**: Explicit prop interfaces prevent errors

## Recent Work

- Dual-app architecture (LegacyApp.js / modern/App.tsx)
- Modern GroupOfStopPlaces with drawer (responsive, collapsible)
- Theme system refactor (module augmentation, bootstrap.json config)
- UX improvements (X=close, chevron=collapse, FAB on desktop, minimized bar on mobile)
- Direct search-to-edit flow (modern UI): search → LoadingDialog → navigate to edit page
- LoadingDialog with ModalityLoadingAnimation (white background, shows stop place name)
- Fast map transitions (0.25s animation)
- Seamless loading coverage (no gaps, edit boxes hidden during load)
- Prevents map jumping during navigation

### Group of Stop Places Improvements

**Enhanced InfoDialog** - Comprehensive metadata display:
- Name field with optional display
- ID with integrated `CopyIdButton` for easy clipboard copy
- Lat/long coordinates with 6-decimal precision formatting
- Created/Modified/Version metadata
- Monospace font for technical data (ID, coordinates)
- Files: `InfoDialog.tsx`, `EditGroupOfStopPlaces.tsx`, `types.ts`, `MinimizedBar.tsx`

**Fixed Navigation Issues** - Consistent data fetching across all entry points:
- **Problem**: Navigating from one group to another via search/favorites did nothing; no loading animation
- **Root cause**: Container only fetched on mount, not on route changes; search skipped data fetch for groups
- **Solution**:
- `GroupOfStopPlaces.tsx`: Added `useParams`, refetch on `groupId` change, wrapped handlers in `useCallback`
- `useSearchBox.tsx`: Fetch group data via `getGroupOfStopPlacesById` before navigation
- `FavoriteStopPlaces.tsx`: Added same fetch-before-navigate pattern as search
- All paths now show LoadingDialog during data fetch

**Data Fetching Pattern** - Applied consistently across search, favorites, and route changes:
1. Set loading state with entity name
2. Fetch entity data (`getGroupOfStopPlacesById` for groups, `getStopPlaceById` for stops)
3. Update map markers (for stop places)
4. Navigate to edit page
5. Clear loading state in `.finally()`
6. Show LoadingDialog throughout process

**Result**: Reliable navigation with proper loading UX across all paths (search autocomplete, favorites panel, direct URL changes)

## Guidelines

**CRITICAL: Never mix legacy and modern**
- ❌ Import modern into legacy, add `uiMode` checks in legacy
- ✅ Create TypeScript copies in `/src/components/modern/`, keep legacy untouched

**New components**: TypeScript in `/src/components/modern/`, MUI v7, barrel exports, custom hooks, **responsive on all screen sizes**
**New routes**: Add to `modern/App.tsx` (not `LegacyApp.js`)

**Translations (MANDATORY)**:
- MUST add translations to ALL 5 language files: `/src/static/lang/{en,nb,sv,fi,fr}.json`
- NEVER use hardcoded text in UI components
- Check for existing similar translations to maintain consistency
- Test in all languages before committing

**Testing**: `npm run build`, test both UIs, **verify on mobile/tablet/desktop breakpoints**
11 changes: 9 additions & 2 deletions .github/environments/dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"hostname": "stoppested.dev.entur.org",
"claimsNamespace": "https://ror.entur.io/role_assignments",
"preferredNameNamespace": "https://ror.entur.io/preferred_name",
"uiMode": "dual",
"oidcConfig": {
"authority": "https://partner.dev.entur.org",
"client_id": "IAjOS4VshfCvu5K3OJ37B9LHqPTEwxG7",
Expand All @@ -16,7 +17,8 @@
}
},
"featureFlags": {
"SVVStreetViewLink": true
"SVVStreetViewLink": true,
"ModernUI": true
},
"mapConfig": {
"baseLayers": [
Expand Down Expand Up @@ -48,5 +50,10 @@
"localeConfig": {
"locales": ["nb", "en", "sv", "fi", "fr"],
"defaultLocale": "nb"
}
},
"themeConfigs": [
"theme/default-theme.json",
"theme/entur-theme.json",
"theme/fintraffic-theme.json"
]
}
2 changes: 1 addition & 1 deletion .github/environments/firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
},
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; script-src 'self' maps.googleapis.com; style-src 'self' 'unsafe-inline' cdnjs.cloudflare.com fonts.googleapis.com; object-src 'none'; base-uri 'self'; connect-src 'self' api.dev.entur.io api.staging.entur.io api.entur.io maps.googleapis.com *.ingest.sentry.io partner.dev.entur.org; font-src 'self' fonts.gstatic.com; frame-src 'self' ; img-src 'self' data: *.tile.openstreetmap.org cdnjs.cloudflare.com cache.kartverket.no gatekeeper1.geonorge.no *.googleapis.com maps.gstatic.com; manifest-src 'self'; media-src 'self'; worker-src 'none'; form-action 'none'; frame-ancestors 'none'; upgrade-insecure-requests; report-uri https://o209253.ingest.sentry.io/api/1354790/security/?sentry_key=2c74afd3e84f4dbf94232421f6b3f5dc"
"value": "default-src 'self'; script-src 'self' maps.googleapis.com; style-src 'self' 'unsafe-inline' cdnjs.cloudflare.com fonts.googleapis.com; object-src 'none'; base-uri 'self'; connect-src 'self' api.dev.entur.io api.staging.entur.io api.entur.io maps.googleapis.com *.ingest.sentry.io partner.dev.entur.org *.tile.openstreetmap.org *.arcgisonline.com cache.kartverket.no gatekeeper1.geonorge.no; font-src 'self' fonts.gstatic.com; frame-src 'self' ; img-src 'self' data: *.tile.openstreetmap.org cdnjs.cloudflare.com cache.kartverket.no gatekeeper1.geonorge.no *.googleapis.com maps.gstatic.com *.arcgisonline.com; manifest-src 'self'; media-src 'self'; worker-src 'none'; form-action 'none'; frame-ancestors 'none'; upgrade-insecure-requests; report-uri https://o209253.ingest.sentry.io/api/1354790/security/?sentry_key=2c74afd3e84f4dbf94232421f6b3f5dc"
},
{
"key": "Referrer-Policy",
Expand Down
Loading
Loading