---
phase: 13-file-upload-infrastructure
plan: 03
type: execute
wave: 2
depends_on: ["13-01", "13-02"]
files_modified:
  - jam-ui/src/components/client/JKSessionScreen.js
  - jam-ui/src/components/client/chat/JKChatUploadProgress.js
  - jam-ui/src/components/client/chat/JKChatMessageList.js
autonomous: false

must_haves:
  truths:
    - "User clicks Attach button in session toolbar and OS file dialog opens"
    - "User selects invalid file (too large or wrong type) and sees immediate error toast"
    - "User selects valid file and upload starts automatically"
    - "User sees 'Uploading [filename]...' message in chat window during upload"
    - "Upload progress message disappears when upload completes (success or error)"
    - "User can continue using app while upload is in progress (attach button disabled, UI responsive)"
    - "Upload error displays as toast with clear message"
  artifacts:
    - path: "jam-ui/src/components/client/JKSessionScreen.js"
      provides: "Session toolbar with functional Attach button"
    - path: "jam-ui/src/components/client/chat/JKChatUploadProgress.js"
      provides: "Temporary upload progress message component"
      exports: ["default (JKChatUploadProgress)"]
      min_lines: 30
    - path: "jam-ui/src/components/client/chat/JKChatMessageList.js"
      provides: "Chat message list showing upload progress"
  key_links:
    - from: "jam-ui/src/components/client/JKSessionScreen.js"
      to: "attachmentValidation.js"
      via: "validateFile import for pre-upload validation"
      pattern: "validateFile\\(file\\)"
    - from: "jam-ui/src/components/client/JKSessionScreen.js"
      to: "sessionChatSlice"
      via: "dispatch(uploadAttachment) on valid file"
      pattern: "dispatch\\(uploadAttachment"
    - from: "JKChatMessageList"
      to: "JKChatUploadProgress"
      via: "Renders upload progress when status='uploading'"
      pattern: "isUploading.*JKChatUploadProgress"
---

<objective>
Wire up the Attach button in session toolbar with validation and upload handling, plus display upload progress in chat window

Purpose: Provide the user-facing UI for file attachment - clicking the Attach button in the session toolbar opens OS file dialog, selected files are validated, valid files are uploaded, and upload progress is displayed in the chat window. This is the final plan that wires together the validation service (Plan 01) and upload state (Plan 02) into the user interface.

Output: Functional Attach button in session toolbar and upload progress display in chat window
</objective>

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

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/REQUIREMENTS.md (REQ-1.1: Attach Button in Session Toolbar)
@.planning/phases/12-attachment-research-&-backend-validation/docs/REACT_INTEGRATION_DESIGN.md
@.planning/phases/13-file-upload-infrastructure/13-01-SUMMARY.md
@.planning/phases/13-file-upload-infrastructure/13-02-SUMMARY.md
@jam-ui/src/components/client/JKSessionScreen.js
@jam-ui/src/components/client/chat/JKChatMessageList.js

# REQ-1.1 explicitly states: "Add 'Attach' button to session toolbar (top navigation)"
# Implementation note: "Similar pattern to Backing Track 'Open' button"
# The toolbar is in JKSessionScreen.js, NOT in JKChatComposer

# Dependencies from prior plans:
# - validateFile from attachmentValidation.js (Plan 01)
# - uploadAttachment, selectIsUploading, selectUploadError, selectUploadFileName, clearUploadError from sessionChatSlice.js (Plan 02)
</context>

<tasks>

<task type="auto">
  <name>Task 1: Wire up Attach button in session toolbar</name>
  <files>jam-ui/src/components/client/JKSessionScreen.js</files>
  <action>
    Modify JKSessionScreen.js to make the existing Attach button functional.

    The placeholder Attach button already exists at approximately line 1178-1180:
    ```jsx
    <Button className='btn-custom-outline' outline size="md">
      <img src={attachIcon} alt="Attach" style={{ width: '16px', height: '16px', marginRight: '0.2rem' }} />
      Attach</Button>
    ```

    Changes required:

    1. Add imports at the top of the file:
       - import { validateFile, getAttachmentType } from '../../services/attachmentValidation'
       - import { uploadAttachment, selectIsUploading, selectUploadError, selectUploadFileName, clearUploadError } from '../../store/features/sessionChatSlice'
       - toast is already imported from 'react-toastify'

    2. Add a hidden file input ref (inside component, before return):
       ```javascript
       const attachFileInputRef = useRef(null);
       ```

    3. Add useSelector for upload state:
       ```javascript
       const isUploading = useSelector(selectIsUploading);
       const uploadError = useSelector(selectUploadError);
       const uploadFileName = useSelector(selectUploadFileName);
       ```

    4. Create handleAttachClick callback:
       ```javascript
       const handleAttachClick = useCallback(() => {
         attachFileInputRef.current?.click();
       }, []);
       ```

    5. Create handleFileSelect callback:
       ```javascript
       const handleFileSelect = useCallback((e) => {
         const file = e.target.files?.[0];
         if (!file) return;

         // Reset input for re-selection of same file
         e.target.value = '';

         // Validate file before upload
         const validation = validateFile(file);

         if (!validation.valid) {
           toast.error(validation.error);
           return;
         }

         // Show warnings if any (e.g., backend may not fully support this type)
         validation.warnings?.forEach(warning => {
           console.warn('Attachment warning:', warning);
         });

         // Open chat window if not already open
         dispatch(openModal('chat'));

         // Dispatch upload
         dispatch(uploadAttachment({
           file,
           sessionId,
           clientId: server?.clientId
         }));
       }, [dispatch, sessionId, server?.clientId]);
       ```

    6. Add useEffect to show error toast when uploadError changes:
       ```javascript
       useEffect(() => {
         if (uploadError) {
           toast.error(uploadError);
           dispatch(clearUploadError());
         }
       }, [uploadError, dispatch]);
       ```

    7. Add hidden file input just before the Attach button:
       ```jsx
       <input
         type="file"
         ref={attachFileInputRef}
         style={{ display: 'none' }}
         accept=".pdf,.xml,.mxl,.txt,.png,.jpg,.jpeg,.gif,.mp3,.wav"
         onChange={handleFileSelect}
       />
       ```

    8. Update the Attach button to be functional:
       ```jsx
       <Button
         className='btn-custom-outline'
         outline
         size="md"
         onClick={handleAttachClick}
         disabled={isUploading}
       >
         <img src={attachIcon} alt="Attach" style={{ width: '16px', height: '16px', marginRight: '0.2rem' }} />
         {isUploading ? 'Uploading...' : 'Attach'}
       </Button>
       ```

    Key points:
    - Button is in the session toolbar (top navigation) per REQ-1.1
    - Similar pattern to JKSessionOpenMenu which uses a dropdown but also triggers file selection
    - File validation happens before upload starts (no wasted network requests)
    - Chat window opens automatically when upload starts so user can see progress
    - Error handling via toast notifications
  </action>
  <verify>
    cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run build
    No compilation errors
    No missing import errors
  </verify>
  <done>
    Attach button in session toolbar is functional: opens file dialog on click, validates selection, dispatches upload for valid files, shows errors for invalid files
  </done>
</task>

<task type="auto">
  <name>Task 2: Create upload progress component for chat window</name>
  <files>jam-ui/src/components/client/chat/JKChatUploadProgress.js</files>
  <action>
    Create new component to display upload progress in the chat window.

    Component requirements:
    1. Displays "Uploading [filename]..." message
    2. Shows a simple spinner or loading indicator
    3. Styled to look like a system message (not a user message)
    4. Props: fileName (required)

    Implementation:
    ```javascript
    import React, { memo } from 'react';
    import PropTypes from 'prop-types';
    import { Spinner } from 'reactstrap';

    const JKChatUploadProgress = memo(({ fileName }) => {
      return (
        <div
          style={{
            padding: '8px 12px',
            margin: '8px 0',
            backgroundColor: '#f0f0f0',
            borderRadius: '8px',
            display: 'flex',
            alignItems: 'center',
            gap: '8px',
            color: '#666',
            fontSize: '14px',
            fontStyle: 'italic'
          }}
        >
          <Spinner size="sm" color="secondary" />
          <span>Uploading {fileName}...</span>
        </div>
      );
    });

    JKChatUploadProgress.propTypes = {
      fileName: PropTypes.string.isRequired
    };

    JKChatUploadProgress.displayName = 'JKChatUploadProgress';

    export default JKChatUploadProgress;
    ```

    This component will be rendered in JKChatMessageList when an upload is in progress.
  </action>
  <verify>
    File exists at jam-ui/src/components/client/chat/JKChatUploadProgress.js
    No syntax errors when importing
  </verify>
  <done>
    JKChatUploadProgress component created with spinner and filename display
  </done>
</task>

<task type="auto">
  <name>Task 3: Display upload progress in chat message list</name>
  <files>jam-ui/src/components/client/chat/JKChatMessageList.js</files>
  <action>
    Modify JKChatMessageList to show upload progress when an upload is in progress.

    Changes required:

    1. Add imports:
       ```javascript
       import { useSelector } from 'react-redux';
       import { selectIsUploading, selectUploadFileName } from '../../../store/features/sessionChatSlice';
       import JKChatUploadProgress from './JKChatUploadProgress';
       ```

    2. Add selector hooks inside component:
       ```javascript
       const isUploading = useSelector(selectIsUploading);
       const uploadFileName = useSelector(selectUploadFileName);
       ```

    3. Render JKChatUploadProgress at the end of the message list (after all messages, before closing div):
       ```jsx
       {/* Existing messages map */}
       {messages.map((message) => (
         // ... existing message rendering
       ))}

       {/* Upload progress indicator */}
       {isUploading && uploadFileName && (
         <JKChatUploadProgress fileName={uploadFileName} />
       )}
       ```

    The progress message should appear at the bottom of the chat list so the user sees it when they scroll down or when auto-scroll kicks in.
  </action>
  <verify>
    cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run build
    No compilation errors
    Upload progress appears in chat when isUploading is true
  </verify>
  <done>
    Chat message list displays upload progress indicator when upload is in progress
  </done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <what-built>
    Complete file upload infrastructure:
    1. Attach button in session toolbar - opens OS file dialog (REQ-1.1)
    2. File validation before upload - rejects invalid size/type (REQ-1.2, REQ-1.3)
    3. Upload progress display in chat window - shows "Uploading [filename]..." (REQ-1.4)
    4. Validation service (from Plan 01) - File size and type checking
    5. Redux upload state (from Plan 02) - Upload progress tracking
  </what-built>
  <how-to-verify>
    1. Start jam-ui dev server: cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run start
    2. Navigate to a session at http://beta.jamkazam.local:4000/
    3. Look at the session toolbar (top row of buttons: Settings, Invite, Volume, etc.)
    4. Verify the "Attach" button appears in the toolbar (NOT in the chat composer)
    5. Click "Attach" - OS file dialog should open
    6. Select a file that is TOO LARGE (>10 MB) - should see error toast, no upload
    7. Select a file with INVALID TYPE (.exe, .zip) - should see error toast, no upload
    8. Select a VALID file (.pdf, .png, .txt, etc.):
       - Chat window should open automatically
       - "Uploading [filename]..." should appear at bottom of chat
       - Attach button should show "Uploading..." and be disabled
    9. If backend is running, upload should complete:
       - "Uploading..." message disappears
       - Attach button returns to normal state
    10. Watch console for any errors

    Expected behaviors:
    - Attach button is in session TOOLBAR (next to Chat, Open, Record buttons)
    - NOT in chat composer area
    - File dialog opens on click
    - Invalid files show immediate error toast
    - Valid files trigger upload with progress shown in chat
    - No console errors
  </how-to-verify>
  <resume-signal>Type "approved" if upload flow works correctly with button in toolbar, or describe issues found</resume-signal>
</task>

</tasks>

<verification>
```bash
# Build verification
cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run build

# Run related tests
cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run test:unit -- attachmentValidation
cd /Users/nuwan/Code/jam-cloud/jam-ui && npm run test:unit -- sessionChatSlice
```
</verification>

<success_criteria>
1. Attach button in session toolbar (NOT chat composer) opens file dialog
2. File validation runs before upload attempt
3. Invalid files show immediate error toast without network request
4. Valid files dispatch uploadAttachment action
5. Upload progress indicator ("Uploading [filename]...") displays in chat window
6. Upload progress disappears when upload completes or fails
7. Attach button shows "Uploading..." state and is disabled during upload
8. Upload error displays as toast notification
9. User verified upload flow works correctly
</success_criteria>

<output>
After completion, create `.planning/phases/13-file-upload-infrastructure/13-03-SUMMARY.md`
</output>
