> For the complete documentation index, see [llms.txt](https://docs.wellcomecollection.org/request-for-comments-rfcs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.wellcomecollection.org/request-for-comments-rfcs/086-item-viewer-refactor/09-phase-3-canvas-data.md).

# Phase 3: Canvas Data to Context

[← Back to Index](/request-for-comments-rfcs/086-item-viewer-refactor.md)

**Effort:** 3 hours (tests) + 3-4 hours (refactoring) = **6-7 hours total**\
**Risk:** Low (tests prevent regressions)\
**Priority:** High (foundation for other phases)\
**Previous:** [Phase 2: Split MainViewer Components](/request-for-comments-rfcs/086-item-viewer-refactor/08-phase-2-split-components.md)\
**Next:** [Phase 4: Download Logic](/request-for-comments-rfcs/086-item-viewer-refactor/10-phase-4-download-logic.md)

## Goal

Add derived canvas data and boolean flags that are used by multiple components to `ItemViewerContextV2`. Components read these values instead of calculating them independently.

**Decision criteria:** Only add to context if:

1. Value is calculated in 2+ components (eliminates duplication), OR
2. Value will likely be needed by multiple components soon (e.g., `isCurrentCanvasRestricted` for download restrictions)

**Note:** Download logic stays OUT of context (goes to a hook instead) because it's only used in `ViewerTopBar`.

## Critical: Automated Tests FIRST

**Before writing any implementation code, you MUST:**

1. Write comprehensive automated tests for all derived values
2. Verify tests pass with current implementation
3. Then and only then make refactoring changes

See [refactoring-iiif-viewer-context-testing.md](/request-for-comments-rfcs/086-item-viewer-refactor/refactoring-iiif-viewer-context-testing.md) for complete test examples with TypeScript types.

## Steps Overview

### 1.1 Write Characterisation Tests FIRST (3 hours)

**Files to create:**

* `content/webapp/contexts/ItemViewerContextV2/ItemViewerContextV2.test.tsx` - Context unit tests
* `content/webapp/contexts/ItemViewerContextV2/test-utils.ts` - Properly typed mocks
* `content/webapp/views/pages/works/work/IIIFViewer/IIIFViewer.refactored.test.tsx` - Integration tests
* `content/webapp/views/pages/works/work/IIIFViewer/ViewerTopBar.refactored.test.tsx` - Component tests

**Test coverage required:**

* All derived canvas data (`currentCanvas`, `currentCanvasIndex`, `mainImageService`)
* All boolean flags (`hasMultipleCanvases`, `isFirstCanvas`, `canNavigateNext`, etc.)
* All edge cases (undefined manifest, empty canvases, invalid index)
* Component integration (verify components consume context)

See [Testing Guide](/request-for-comments-rfcs/086-item-viewer-refactor/refactoring-iiif-viewer-context-testing.md) for complete examples.

### 1.2 Make Tests Pass (Implementation)

Once tests are written, add the derived values to `IIIFViewer.refactored.tsx`:

```typescript
// Derived canvas data
const currentCanvasIndex = queryParamToArrayIndex(canvas);
const currentCanvas = transformedManifest?.canvases[currentCanvasIndex];
const totalCanvases = transformedManifest?.canvases?.length || 0;

// Canvas-related booleans (crystal clear!)
const hasMultipleCanvases = totalCanvases > 1;
const isFirstCanvas = currentCanvasIndex === 0;
const isLastCanvas = currentCanvasIndex === totalCanvases - 1;
const canNavigateNext = !isLastCanvas && hasMultipleCanvases;
const canNavigatePrevious = !isFirstCanvas && hasMultipleCanvases;
const isCurrentCanvasRestricted = currentCanvas 
  ? hasRestrictedItem(currentCanvas)  // Use helper from restricted-images merge
  : false;

// Image service data
const mainImageService = { '@id': currentCanvas?.imageServiceId || '' };
const hasIiifImageService = Boolean(currentCanvas?.imageServiceId);

// Probe service data (added in restricted-images merge)
// Note: Probe state itself stays in useIIIFProbeService hook (used in 2 places)
// Only add probeServiceId if other components need it beyond the hook
const currentProbeServiceId = currentCanvas?.probeServiceId;

// Add to context provider
<ItemViewerContextV2.Provider value={{
  // ... existing ...
  currentCanvasIndex,
  currentCanvas,
  mainImageService,
  hasMultipleCanvases,
  isFirstCanvas,
  isLastCanvas,
  canNavigateNext,
  canNavigatePrevious,
  isCurrentCanvasRestricted,
  hasIiifImageService,
  // Optionally add if needed by multiple components:
  // currentProbeServiceId,
}}>
```

**Note on probe service:** The `restricted-images` merge added `probeServiceId` to `TransformedCanvas` and a `useIIIFProbeService` hook. The hook handles probe polling state internally. Only add `currentProbeServiceId` to context if components beyond `MainViewer` and `ItemWrapper` need it.

### 1.3 Update `ItemViewerContextV2` Types

Add all new props to the TypeScript interface with clear types.

### 1.4 Update Components to Use Context

**`ViewerTopBar.refactored.tsx`** - Remove local calculations, use context:

```typescript
const {
  currentCanvas,
  isCurrentCanvasRestricted,
  canNavigateNext,
  canNavigatePrevious,
} = useItemViewerContextV2();

// Delete all local currentCanvas calculations
// Use values directly from context
```

**`ZoomedImage.refactored.tsx`** - Use `currentCanvas` and `mainImageService` from context

**`MainViewer.refactored.tsx`** - Use `currentCanvas` from context

**Styled components** - Use `hasMultipleCanvases` from context

### 1.5 Run Automated Tests

```bash
yarn test ItemViewerContextV2.test
yarn test IIIFViewer.refactored
yarn test ViewerTopBar.refactored
```

All tests should pass.

### 1.6 (Optional) Manual Testing

See [13-testing-strategy.md](https://github.com/wellcomecollection/docs/blob/main/rfcs/086-item-viewer-refactor/13-testing-strategy.md) for comprehensive manual testing checklist.

**Quick smoke tests:**

* [ ] Viewer loads correctly
* [ ] Navigate between canvases
* [ ] Toggle sidebar/grid
* [ ] Verify download options appear

## Why Crystal-Clear Boolean Naming Matters

**Before (confusing):**

```typescript
const hasNext = idx < canvases.length - 1 && canvases.length > 1;
<NextButton disabled={!hasNext} />
```

**After (crystal clear):**

```typescript
const { canNavigateNext } = useItemViewerContextV2();
<NextButton disabled={!canNavigateNext} />
```

Self-documenting code! No mental gymnastics required.

## Success Criteria

* [ ] All automated tests pass (context + components)
* [ ] TypeScript compiles with no errors
* [ ] Components use context values (not calculating locally)
* [ ] Feature flag toggle works (old vs new identical behaviour)
* [ ] Manual testing checklist complete (optional)

## Time Breakdown

* 3 hours: Write comprehensive automated tests
* 2 hours: Add derived values to context
* 1-2 hours: Update components to use context
* 30 mins: Run tests and verify

Total: 6-7 hours

***

**Next:** [Phase 4: Download Logic](/request-for-comments-rfcs/086-item-viewer-refactor/10-phase-4-download-logic.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.wellcomecollection.org/request-for-comments-rfcs/086-item-viewer-refactor/09-phase-3-canvas-data.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
