feat(13-03): wire up Attach button in session toolbar

- Add imports for uploadAttachment, validation, and upload state selectors
- Add attachFileInputRef for hidden file input element
- Add handleAttachClick to trigger file dialog
- Add handleFileSelect with validateFile pre-upload validation
- Add useEffect to display upload error toasts
- Add hidden file input with accept attribute for valid file types
- Update Attach button with onClick handler and disabled state during upload
- Button shows 'Uploading...' text when upload is in progress
- Chat window opens automatically when upload starts
- File validation prevents invalid uploads (size/type) with immediate error feedback
This commit is contained in:
Nuwan 2026-02-05 11:06:39 +05:30
parent 765fcba8fe
commit 7455e2ec28
1 changed files with 70 additions and 3 deletions

View File

@ -55,7 +55,8 @@ import {
selectBackingTrackData,
selectJamTrackData
} from '../../store/features/activeSessionSlice';
import { addMessageFromWebSocket } from '../../store/features/sessionChatSlice';
import { addMessageFromWebSocket, uploadAttachment, selectIsUploading, selectUploadError, selectUploadFileName, clearUploadError } from '../../store/features/sessionChatSlice';
import { validateFile } from '../../services/attachmentValidation';
import { CLIENT_ROLE, RECORD_TYPE_AUDIO, RECORD_TYPE_BOTH } from '../../helpers/globals';
import { MessageType } from '../../helpers/MessageFactory.js';
@ -198,6 +199,14 @@ const JKSessionScreen = () => {
const backingTrackData = useSelector(selectBackingTrackData);
const showBackingTrackPlayer = Boolean(backingTrackData);
// Redux upload state for attachments
const isUploading = useSelector(selectIsUploading);
const uploadError = useSelector(selectUploadError);
const uploadFileName = useSelector(selectUploadFileName);
// File input ref for attach button
const attachFileInputRef = useRef(null);
// Stable callback for backing track popup close
const handleBackingTrackClose = useCallback(() => {
console.log('JKSessionScreen: Backing Track Popup closing');
@ -987,6 +996,50 @@ const JKSessionScreen = () => {
}
};
// Attach button handlers
const handleAttachClick = useCallback(() => {
attachFileInputRef.current?.click();
}, []);
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]);
// Show error toast when upload fails
useEffect(() => {
if (uploadError) {
toast.error(uploadError);
dispatch(clearUploadError());
}
}, [uploadError, dispatch]);
const handleBackingTrackSelected = async (result) => {
console.log('JKSessionScreen: handleBackingTrackSelected called with:', result);
console.log('JKSessionScreen: Current state - showBackingTrackPopup:', showBackingTrackPopup, 'popupGuard:', popupGuard);
@ -1175,9 +1228,23 @@ const JKSessionScreen = () => {
Broadcast</Button>
<JKSessionOpenMenu onBackingTrackSelected={handleBackingTrackSelected} onJamTrackSelected={() => dispatch(openModal('jamTrack'))} onMetronomeSelected={handleMetronomeSelected} />
<JKSessionChatButton sessionId={sessionId} />
<Button className='btn-custom-outline' outline size="md">
<input
type="file"
ref={attachFileInputRef}
style={{ display: 'none' }}
accept=".pdf,.xml,.mxl,.txt,.png,.jpg,.jpeg,.gif,.mp3,.wav"
onChange={handleFileSelect}
/>
<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' }} />
Attach</Button>
{isUploading ? 'Uploading...' : 'Attach'}
</Button>
<Button className='btn-custom-outline' outline size="md">
<img src={resyncIcon} alt="Resync" style={{ width: '16px', height: '16px', marginRight: '0.2rem' }} />
Resync</Button>