---
phase: 08-chat-window-ui
plan: 01
type: standard
---

<objective>
Create chat window shell with WindowPortal integration.

Purpose: Build the foundational chat window UI that opens in a popup window, with header and close functionality. This establishes the chat UI foundation that Plans 8.2 and 8.3 will build upon.

Output: JKSessionChatWindow component with WindowPortal wrapper, JKChatHeader component, integration with JKSessionScreen.
</objective>

<execution_context>
@./.claude/get-shit-done/workflows/execute-phase.md
@./.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md

# Phase 6 design documents
@.planning/phases/06-session-chat-research-design/CHAT_COMPONENT_DESIGN.md
@.planning/phases/06-session-chat-research-design/IMPLEMENTATION_ROADMAP.md

# Phase 7 summary
@.planning/phases/07-chat-infrastructure/07-03-SUMMARY.md

# WindowPortal reference
@jam-ui/src/components/common/WindowPortal.js
@jam-ui/src/components/client/JKSessionBackingTrackPlayer.js (WindowPortal usage example)
@jam-ui/src/components/client/JKSessionScreen.js (integration point)

# Redux selectors from Phase 7
@jam-ui/src/store/features/sessionChatSlice.js

# Codebase conventions
@.planning/codebase/ARCHITECTURE.md
@.planning/codebase/CONVENTIONS.md
@CLAUDE.md

**Key context from Phase 6 design:**
- Chat window uses WindowPortal for modeless popup (follows Backing Track/JamTrack pattern)
- Window dimensions: 450px width × 600px height (per CHAT_COMPONENT_DESIGN.md)
- Header shows channel name, close button
- Component hierarchy: JKSessionChatWindow → WindowPortal → JKChatHeader + [content area]
- Redux integration: `isWindowOpen`, `activeChannel`, `openChatWindow`, `closeChatWindow` actions

**Key context from Phase 7:**
- Redux infrastructure complete: sessionChatSlice with reducers, thunks, selectors
- Selectors available: `selectIsChatWindowOpen`, `selectActiveChannel`, `selectChatMessages`
- Actions available: `openChatWindow`, `closeChatWindow`, `setActiveChannel`, `setWindowPosition`
</context>

<tasks>

<task>
  <name>Task 1: Create JKChatHeader component</name>
  <files>jam-ui/src/components/client/chat/JKChatHeader.js</files>
  <action>
Create the chat window header component:

1. Create directory `jam-ui/src/components/client/chat/`
2. Create `JKChatHeader.js` with:
   - Props: `channelName` (string), `onClose` (function)
   - Render: Title bar with channel name and close button (X)
   - Style: Inline styles for now (SCSS in Plan 8.3)
   - Example structure:
     ```javascript
     const JKChatHeader = ({ channelName, onClose }) => {
       return (
         <div style={{
           display: 'flex',
           justifyContent: 'space-between',
           alignItems: 'center',
           padding: '12px 16px',
           borderBottom: '1px solid #e0e0e0',
           backgroundColor: '#f8f9fa'
         }}>
           <h5 style={{ margin: 0, fontSize: '16px', fontWeight: 600 }}>
             {channelName || 'Session Chat'}
           </h5>
           <button
             onClick={onClose}
             style={{
               background: 'transparent',
               border: 'none',
               fontSize: '20px',
               cursor: 'pointer',
               padding: '0 8px',
               color: '#6c757d'
             }}
             aria-label="Close chat"
           >
             ×
           </button>
         </div>
       );
     };
     ```
3. Add PropTypes validation
4. Export component

**Verification:**
- Component renders header with title
- Close button calls onClose callback
- Inline styles applied correctly
  </action>
  <verify>
JKChatHeader.js exists with channel name display and close button. PropTypes defined.
  </verify>
  <done>
Chat header component complete with close functionality.
  </done>
</task>

<task>
  <name>Task 2: Create JKSessionChatWindow component with WindowPortal</name>
  <files>jam-ui/src/components/client/JKSessionChatWindow.js</files>
  <action>
Create the main chat window component with WindowPortal wrapper:

1. Create `jam-ui/src/components/client/JKSessionChatWindow.js`
2. Import dependencies:
   - React, Redux (useSelector, useDispatch)
   - WindowPortal component
   - JKChatHeader component
   - sessionChatSlice actions and selectors
3. Component structure:
   ```javascript
   const JKSessionChatWindow = () => {
     const dispatch = useDispatch();

     // Selectors
     const isWindowOpen = useSelector(selectIsChatWindowOpen);
     const activeChannel = useSelector(selectActiveChannel);

     // Handlers
     const handleClose = useCallback(() => {
       dispatch(closeChatWindow());
     }, [dispatch]);

     // Channel name formatting
     const getChannelName = () => {
       if (!activeChannel) return 'Session Chat';
       if (activeChannel === 'global') return 'Global Chat';
       return 'Session Chat';
     };

     if (!isWindowOpen) return null;

     return (
       <WindowPortal
         title="JamKazam Chat"
         windowFeatures="width=450,height=600,left=200,top=200,menubar=no,toolbar=no,status=no,scrollbars=no,resizable=yes"
         onClose={handleClose}
         windowId="jamkazam-chat"
       >
         <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
           <JKChatHeader
             channelName={getChannelName()}
             onClose={handleClose}
           />
           <div style={{ flex: 1, padding: '16px', backgroundColor: '#ffffff' }}>
             {/* Message list placeholder - Plan 8.2 */}
             <p style={{ color: '#6c757d', textAlign: 'center', marginTop: '24px' }}>
               Chat messages will appear here
             </p>
           </div>
         </div>
       </WindowPortal>
     );
   };
   ```
4. Add PropTypes (none needed - uses Redux)
5. Export component with React.memo for performance

**Implementation notes:**
- Window dimensions: 450×600 per design spec
- Placeholder content area for message list (Plan 8.2)
- windowId for identification (useful for debugging)
- Conditional render: only if isWindowOpen is true
- Use useCallback for handleClose to prevent re-renders

**Verification:**
- WindowPortal opens when isWindowOpen is true
- Header displays correct channel name
- Close button calls closeChatWindow action
- Window has correct dimensions
- Popup window closes properly
  </action>
  <verify>
JKSessionChatWindow.js exists with WindowPortal wrapper. Window opens/closes correctly. Header displays channel name.
  </verify>
  <done>
Chat window component complete with WindowPortal integration and placeholder content.
  </done>
</task>

<task>
  <name>Task 3: Integrate chat window with JKSessionScreen</name>
  <files>jam-ui/src/components/client/JKSessionScreen.js</files>
  <action>
Add chat window to JKSessionScreen with conditional rendering:

1. Open `jam-ui/src/components/client/JKSessionScreen.js`
2. Import JKSessionChatWindow at top:
   ```javascript
   import JKSessionChatWindow from './JKSessionChatWindow.js';
   ```
3. Add chat window render at bottom of component JSX (after all other modals):
   - Find the location after JKSessionMetronomePlayer or other popup components
   - Add: `<JKSessionChatWindow />`
   - Example placement (near end of return statement):
     ```javascript
     return (
       <>
         {/* ... existing session UI ... */}

         {/* Media players */}
         {backingTrackPlayerOpen && <JKSessionBackingTrackPlayer />}
         {jamTrackPlayerOpen && <JKSessionJamTrackPlayer />}
         {metronomePlayerOpen && <JKSessionMetronomePlayer />}

         {/* Chat window */}
         <JKSessionChatWindow />
       </>
     );
     ```

**Integration notes:**
- No props needed (component uses Redux internally)
- Conditional rendering handled inside JKSessionChatWindow
- Follows same pattern as BackingTrackPlayer/JamTrackPlayer/MetronomePlayer
- Window lifecycle managed by WindowPortal

**Verification:**
- Component renders without errors
- No console warnings
- Chat window doesn't show by default (isWindowOpen = false)
- Other session UI unaffected
  </action>
  <verify>
JKSessionChatWindow integrated into JKSessionScreen. Component renders without errors. Window lifecycle works correctly.
  </verify>
  <done>
Chat window integrated into session screen. Ready for message list implementation (Plan 8.2).
  </done>
</task>

<task>
  <name>Task 4: Write integration test for window open/close behavior</name>
  <files>jam-ui/test/chat/chat-window.spec.ts</files>
  <action>
Create Playwright integration test for chat window behavior:

1. Create directory `jam-ui/test/chat/`
2. Create `chat-window.spec.ts` with:

```typescript
import { test, expect } from '@playwright/test';
import { loginToJamUI, createAndJoinSession } from '../helpers/sessionHelpers';

test.describe('Chat Window', () => {
  test.beforeEach(async ({ page }) => {
    await loginToJamUI(page);
    await createAndJoinSession(page);
  });

  test('opens chat window when dispatching openChatWindow action', async ({ page }) => {
    // Dispatch openChatWindow action via Redux DevTools or direct call
    await page.evaluate(() => {
      const store = window.__REDUX_STORE__;
      store.dispatch({ type: 'sessionChat/openChatWindow' });
    });

    // Wait for popup window
    const popupPromise = page.waitForEvent('popup');
    const popup = await popupPromise;

    // Verify popup opened
    expect(popup).toBeTruthy();
    await expect(popup).toHaveTitle('JamKazam Chat');

    // Verify header content
    const header = popup.locator('h5');
    await expect(header).toBeVisible();
    await expect(header).toContainText('Chat');
  });

  test('closes chat window when clicking close button', async ({ page }) => {
    // Open chat window
    await page.evaluate(() => {
      const store = window.__REDUX_STORE__;
      store.dispatch({ type: 'sessionChat/openChatWindow' });
    });

    const popupPromise = page.waitForEvent('popup');
    const popup = await popupPromise;

    // Click close button
    await popup.locator('button[aria-label="Close chat"]').click();

    // Verify popup closed
    await expect(popup).not.toBeAttached();

    // Verify Redux state updated
    const isWindowOpen = await page.evaluate(() => {
      const store = window.__REDUX_STORE__;
      return store.getState().sessionChat.isWindowOpen;
    });
    expect(isWindowOpen).toBe(false);
  });

  test('shows placeholder message before messages loaded', async ({ page }) => {
    // Open chat window
    await page.evaluate(() => {
      const store = window.__REDUX_STORE__;
      store.dispatch({ type: 'sessionChat/openChatWindow' });
    });

    const popupPromise = page.waitForEvent('popup');
    const popup = await popupPromise;

    // Verify placeholder text
    const placeholder = popup.locator('p:has-text("Chat messages will appear here")');
    await expect(placeholder).toBeVisible();
  });
});
```

3. Add Redux store exposure for testing (if not already present):
   - In `jam-ui/src/store/store.js`, add:
     ```javascript
     if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
       window.__REDUX_STORE__ = store;
     }
     ```

**Test coverage:**
- Window opens on openChatWindow action
- Window closes on close button click
- Header displays correct title
- Placeholder message visible
- Redux state updated correctly

**Verification:**
- All 3 tests pass
- No console errors
- Window lifecycle works correctly
  </action>
  <verify>
Integration tests written and passing. Window open/close behavior validated. Redux state updates confirmed.
  </verify>
  <done>
Integration tests complete for chat window shell. Plan 8.1 complete.
  </done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] JKChatHeader component exists with channel name and close button
- [ ] JKSessionChatWindow component exists with WindowPortal wrapper
- [ ] Chat window renders with correct dimensions (450×600)
- [ ] Window opens only when isWindowOpen is true
- [ ] Close button triggers closeChatWindow action
- [ ] JKSessionChatWindow integrated into JKSessionScreen
- [ ] Integration tests written and passing
- [ ] No console errors or warnings
- [ ] Popup window closes properly on unmount
</verification>

<success_criteria>

- JKChatHeader.js created with close button
- JKSessionChatWindow.js created with WindowPortal integration
- Chat window integrated into JKSessionScreen
- Integration tests passing (3 tests minimum)
- Window opens/closes correctly via Redux actions
- Header displays channel name
- Placeholder content visible
- Ready for Plan 8.2 (Message List & Auto-Scroll)
</success_criteria>

<output>
After completion, create `.planning/phases/08-chat-window-ui/08-01-SUMMARY.md`:

# Phase 8 Plan 1: Chat Window Shell & WindowPortal Integration Summary

**Created chat window foundation with popup window integration**

## Accomplishments

- Created JKChatHeader component with channel name display and close button
- Created JKSessionChatWindow component with WindowPortal wrapper
- Integrated chat window into JKSessionScreen (conditional rendering)
- Wrote integration tests for window open/close behavior
- Window lifecycle managed via Redux (openChatWindow/closeChatWindow actions)

## Files Created/Modified

- `jam-ui/src/components/client/chat/JKChatHeader.js` - Header component (NEW)
- `jam-ui/src/components/client/JKSessionChatWindow.js` - Main chat window (NEW)
- `jam-ui/src/components/client/JKSessionScreen.js` - Added chat window render (MODIFIED)
- `jam-ui/test/chat/chat-window.spec.ts` - Integration tests (NEW)

## Decisions Made

[Document any implementation decisions: Window dimensions? Styling approach? Redux integration patterns?]

## Issues Encountered

[Any challenges during implementation, or "None"]

## Next Phase Readiness

Ready for Plan 2 (Message List & Auto-Scroll)
</output>
