# Redux Migration Guide for JKSessionScreen

## Files Created

### 1. `src/store/features/activeSessionSlice.js`
Redux slice for managing the active session state including:
- Session data and lifecycle (joining, leaving)
- Participants management
- User tracks, jam tracks, and backing tracks
- Recording state
- Connection status

**Key Actions:**
- `fetchActiveSession(sessionId)` - Async thunk to fetch session data
- `joinActiveSession({ sessionId, options })` - Async thunk to join session
- `leaveActiveSession(sessionId)` - Async thunk to leave session
- `addParticipant(participant)` - Add a participant to the session
- `removeParticipant(participantId)` - Remove a participant
- `addUserTrack(track)` - Add a user track
- `setSelectedJamTrack(jamTrack)` - Set the selected jam track
- `startRecording(recordingId)` - Start recording
- `stopRecording()` - Stop recording
- `setConnectionStatus(status)` - Update connection status
- `clearSession()` - Clear all session state

**Key Selectors:**
- `selectActiveSession(state)` - Get session data
- `selectJoinStatus(state)` - Get join status
- `selectHasJoined(state)` - Check if user has joined
- `selectParticipants(state)` - Get participants list
- `selectUserTracks(state)` - Get user tracks
- `selectIsRecording(state)` - Check if recording is active
- `selectConnectionStatus(state)` - Get connection status

### 2. `src/store/features/sessionUISlice.js`
Redux slice for managing session UI state including:
- Modal visibility (settings, invite, volume, recording, leave, etc.)
- Panel visibility (chat, mixer, participants, tracks)
- View preferences (layout, video visibility, sidebar state)

**Key Actions:**
- `openModal(modalName)` - Open a specific modal
- `closeModal(modalName)` - Close a specific modal
- `toggleModal(modalName)` - Toggle a modal
- `closeAllModals()` - Close all modals
- `togglePanel(panelName)` - Toggle a panel
- `setParticipantLayout(layout)` - Set participant layout ('grid' | 'list' | 'compact')
- `toggleMixer()` - Toggle mixer visibility
- `resetUI()` - Reset all UI state

**Key Selectors:**
- `selectModal(modalName)(state)` - Check if a modal is open
- `selectIsAnyModalOpen(state)` - Check if any modal is open
- `selectPanel(panelName)(state)` - Check if a panel is open
- `selectShowMixer(state)` - Check if mixer is visible
- `selectParticipantLayout(state)` - Get participant layout

### 3. `src/hooks/useSessionWebSocket.js`
Custom hook that integrates WebSocket messages with Redux actions. This hook:
- Listens to WebSocket events from `jamServer`
- Dispatches appropriate Redux actions when events occur
- Handles cleanup on unmount

**Usage:**
```javascript
import { useSessionWebSocket } from '../hooks/useSessionWebSocket';

function JKSessionScreen() {
  const { sessionId } = useParams();

  // This hook will automatically dispatch Redux actions
  // when WebSocket events are received
  useSessionWebSocket(sessionId);

  // ... rest of component
}
```

### 4. Updated `src/store/store.js`
Added the new reducers to the Redux store:
- `activeSession` - Active session state
- `sessionUI` - Session UI state

## Migration Strategy

### Phase 1: Quick Wins - Migrate Modal State (Start Here)

Replace `useState` for modals with Redux:

**Before:**
```javascript
const [showSettingsModal, setShowSettingsModal] = useState(false);
const [showInviteModal, setShowInviteModal] = useState(false);

// In JSX
<button onClick={() => setShowSettingsModal(true)}>Settings</button>
{showSettingsModal && <SettingsModal onClose={() => setShowSettingsModal(false)} />}
```

**After:**
```javascript
import { useDispatch, useSelector } from 'react-redux';
import { openModal, closeModal, selectModal } from '../../store/features/sessionUISlice';

const dispatch = useDispatch();
const showSettingsModal = useSelector(selectModal('settings'));

// In JSX
<button onClick={() => dispatch(openModal('settings'))}>Settings</button>
{showSettingsModal && <SettingsModal onClose={() => dispatch(closeModal('settings'))} />}
```

**Benefits:**
- Removes 5-8 useState hooks immediately
- Easy to test
- Good practice for team

### Phase 2: Migrate Session Lifecycle

Replace session join/leave logic with Redux thunks:

**Before:**
```javascript
const [hasJoined, setHasJoined] = useState(false);
const [sessionGuardsPassed, setSessionGuardsPassed] = useState(false);

const handleJoinSession = async () => {
  // Guard checks...
  setSessionGuardsPassed(true);
  const response = await joinSession(sessionId, options);
  setHasJoined(true);
};
```

**After:**
```javascript
import { useDispatch, useSelector } from 'react-redux';
import {
  joinActiveSession,
  selectJoinStatus,
  selectHasJoined
} from '../../store/features/activeSessionSlice';

const dispatch = useDispatch();
const joinStatus = useSelector(selectJoinStatus);
const hasJoined = useSelector(selectHasJoined);

const handleJoinSession = async () => {
  // Guard checks...
  await dispatch(joinActiveSession({ sessionId, options }));
};
```

### Phase 3: Migrate Entity Collections

Replace `useState` arrays with Redux:

**Before:**
```javascript
const [userTracks, setUserTracks] = useState([]);
const [participants, setParticipants] = useState([]);

// When WebSocket message arrives
jamServer.on('trackAdded', (data) => {
  setUserTracks([...userTracks, data.track]);
});
```

**After:**
```javascript
import { useDispatch, useSelector } from 'react-redux';
import { selectUserTracks, selectParticipants } from '../../store/features/activeSessionSlice';
import { useSessionWebSocket } from '../../hooks/useSessionWebSocket';

const userTracks = useSelector(selectUserTracks);
const participants = useSelector(selectParticipants);

// WebSocket integration is automatic via custom hook
useSessionWebSocket(sessionId);

// No manual event handlers needed!
```

### Phase 4: Replace CurrentSessionContext

Once most state is in Redux, you can simplify or remove `CurrentSessionContext`:

**Before:**
```javascript
const { currentSession, setCurrentSession, refreshSession } = useCurrentSessionContext();
```

**After:**
```javascript
import { useSelector, useDispatch } from 'react-redux';
import { selectActiveSession, fetchActiveSession } from '../../store/features/activeSessionSlice';

const currentSession = useSelector(selectActiveSession);
const dispatch = useDispatch();

// To refresh
dispatch(fetchActiveSession(sessionId));
```

## Testing Your Migration

### Check Redux DevTools

Install Redux DevTools browser extension to:
1. View the entire state tree
2. See every action dispatched
3. Time-travel debug state changes
4. Export/import state for testing

### Verify State Updates

After each phase, verify:
```javascript
// Check if state is in Redux
console.log('Redux State:', store.getState().activeSession);
console.log('Redux UI:', store.getState().sessionUI);
```

### Test WebSocket Integration

In JKSessionScreen, verify the custom hook is working:
```javascript
useSessionWebSocket(sessionId);

// Watch Redux DevTools - you should see actions dispatched
// when WebSocket events occur
```

## Common Patterns

### Pattern 1: Conditional Rendering Based on Redux State

```javascript
const isRecording = useSelector(selectIsRecording);
const connectionStatus = useSelector(selectConnectionStatus);

return (
  <>
    {connectionStatus === 'disconnected' && <ConnectionAlert />}
    {isRecording && <RecordingIndicator />}
  </>
);
```

### Pattern 2: Dispatching Multiple Actions

```javascript
const handleLeaveSession = async () => {
  // Close all modals first
  dispatch(closeAllModals());

  // Leave the session
  await dispatch(leaveActiveSession(sessionId));

  // Navigate away
  navigate('/dashboard');
};
```

### Pattern 3: Using Multiple Selectors

```javascript
const session = useSelector(selectActiveSession);
const participants = useSelector(selectParticipants);
const tracks = useSelector(selectUserTracks);
const showMixer = useSelector(selectModal('mixer'));

// All selectors are memoized, so re-renders only happen when data changes
```

## Next Steps

1. **Start with Phase 1**: Migrate modal state first - it's the easiest and gives immediate value
2. **Test thoroughly**: After each phase, test the UI and check Redux DevTools
3. **Document as you go**: Update component documentation with Redux patterns
4. **Remove old contexts gradually**: Once state is migrated, clean up unused contexts

## Notes

- The WebSocket event names in `useSessionWebSocket.js` are examples. Update them to match your actual Protocol Buffer message types.
- The `jamServer` API methods (`on`, `off`) may differ based on your implementation. Adjust accordingly.
- Consider creating additional custom hooks for specific features (e.g., `useSessionRecording`, `useSessionTracks`) that encapsulate Redux logic.

## Questions?

If you need help with:
- Specific WebSocket message types and how to handle them
- Complex state transformations
- Performance optimization with selectors
- Testing Redux logic

Just ask!
