refactor(32-03): use JKResyncButton and JKVideoButton in JKSessionScreen

- Replaced inline video button with JKVideoButton component
- Replaced inline resync button with JKResyncButton component
- Removed videoLoading and resyncLoading state from parent
- Removed handleVideoClick and handleResync functions
- Removed unused videoIcon and resyncIcon imports
- Loading state changes no longer trigger parent re-renders
This commit is contained in:
Nuwan 2026-03-05 19:39:56 +05:30
parent 98e5a5ac15
commit f5bd1b1cd5
3 changed files with 32 additions and 123 deletions

View File

@ -12,7 +12,8 @@ import PropTypes from 'prop-types';
const JKResyncButton = memo(({ resyncAudio, className }) => {
const [loading, setLoading] = useState(false);
const handleClick = useCallback(async (e) => {
const handleClick = useCallback(
async e => {
e.preventDefault();
if (loading) return;
@ -29,16 +30,12 @@ const JKResyncButton = memo(({ resyncAudio, className }) => {
} finally {
setLoading(false);
}
}, [resyncAudio, loading]);
},
[resyncAudio, loading]
);
return (
<Button
className={className || 'btn-custom-outline'}
outline
size="md"
onClick={handleClick}
disabled={loading}
>
<Button className={className || 'btn-custom-outline'} outline size="md" onClick={handleClick} disabled={loading}>
{loading ? (
<>
<Spinner size="sm" /> Resyncing...

View File

@ -131,6 +131,8 @@ import JKSessionMetronomePlayer from './JKSessionMetronomePlayer.js';
import JKSessionChatWindow from './JKSessionChatWindow.js';
import JKSessionChatButton from './JKSessionChatButton.js';
import JKPopupMediaControls from '../popups/JKPopupMediaControls.js';
import JKResyncButton from './JKResyncButton.js';
import JKVideoButton from './JKVideoButton.js';
import { SESSION_PRIVACY_MAP } from '../../helpers/globals.js';
import { toast } from 'react-toastify';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
@ -139,13 +141,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import gearIcon from '../../assets/img/client/gear.svg';
import inviteIcon from '../../assets/img/client/invite.svg';
import volumeIcon from '../../assets/img/client/volume.svg';
import videoIcon from '../../assets/img/client/video.svg';
import recordIcon from '../../assets/img/client/record.svg';
import broadcastIcon from '../../assets/img/client/broadcast.svg';
import openIcon from '../../assets/img/client/open.svg';
import chatIcon from '../../assets/img/client/chat.svg';
import attachIcon from '../../assets/img/client/attach.svg';
import resyncIcon from '../../assets/img/client/resync.svg';
import helpIcon from '../../assets/img/client/help.svg';
const JKSessionScreen = () => {
@ -247,12 +247,6 @@ const JKSessionScreen = () => {
const [leaveComments, setLeaveComments] = useState('');
const [leaveLoading, setLeaveLoading] = useState(false);
//state for video button
const [videoLoading, setVideoLoading] = useState(false);
// State for resync button
const [resyncLoading, setResyncLoading] = useState(false);
// Redux backing track state (modal visibility and data)
const backingTrackData = useSelector(selectBackingTrackData);
const showBackingTrackPlayer = Boolean(backingTrackData);
@ -1017,39 +1011,6 @@ const JKSessionScreen = () => {
return currentSession?.can_use_video || false;
};
// Open external link in new window/tab
const openExternalLink = url => {
window.open(url, '_blank', 'noopener,noreferrer');
};
// Handle video button click - opens new video conferencing server
const handleVideoClick = async () => {
if (!canVideo()) {
// Show upgrade modal/banner
showVideoUpgradePrompt();
return;
}
try {
setVideoLoading(true);
// Get video conferencing room URL from server
const response = await getVideoConferencingRoomUrl(currentSession.id);
const videoUrl = `${response.url}&audiooff=true`;
// Open video URL in new browser window/tab
// console.debug("JKSessionScreen: Opening video conferencing URL", videoUrl);
openExternalLink(videoUrl);
} catch (error) {
// console.error('Failed to get video room URL:', error);
// Handle error - could show error message to user
toast.error('Failed to start video session');
} finally {
// Keep loading state for 10 seconds to prevent multiple clicks
setTimeout(() => setVideoLoading(false), 10000);
}
};
// Show upgrade prompt for users without video permissions
const showVideoUpgradePrompt = () => {
// Implementation for showing upgrade modal/banner
@ -1104,30 +1065,6 @@ const JKSessionScreen = () => {
}
};
// Handle Resync button click - performs audio resync via native client
const handleResync = useCallback(
async e => {
e.preventDefault();
if (resyncLoading) return;
setResyncLoading(true);
try {
await resyncAudio();
// Silent success (matches legacy behavior)
} catch (error) {
// console.error('Audio resync failed:', error);
if (error.message === 'timeout') {
toast.error('Audio resync timed out. Please try again.');
} else {
toast.error('Audio resync failed: ' + (error.message || 'Unknown error'));
}
} finally {
setResyncLoading(false);
}
},
[resyncAudio, resyncLoading]
);
// Attach button handlers
const handleAttachClick = useCallback(() => {
if (attachFileInputRef.current) {
@ -1407,11 +1344,11 @@ const JKSessionScreen = () => {
<img src={volumeIcon} alt="Volume" style={{ width: '20px', height: '20px', marginRight: '0.3rem' }} />
Volume
</Button>
<Button className="btn-custom-outline" outline size="md" onClick={handleVideoClick} disabled={videoLoading}>
<img src={videoIcon} alt="Video" style={{ width: '20px', height: '20px', marginRight: '0.3rem' }} />
{videoLoading && <Spinner size="sm" />}
&nbsp;Video
</Button>
<JKVideoButton
canVideo={canVideo}
getVideoUrl={() => getVideoConferencingRoomUrl(currentSession.id)}
onUpgradePrompt={showVideoUpgradePrompt}
/>
<Button
className={currentlyRecording ? 'btn-recording-active' : 'btn-custom-outline'}
color={currentlyRecording ? 'danger' : undefined}
@ -1447,16 +1384,7 @@ const JKSessionScreen = () => {
<img src={attachIcon} alt="Attach" style={{ width: '20px', height: '20px', marginRight: '0.3rem' }} />
{isUploading ? 'Uploading...' : 'Attach'}
</Button>
<Button className="btn-custom-outline" outline size="md" onClick={handleResync} disabled={resyncLoading}>
<img src={resyncIcon} alt="Resync" style={{ width: '20px', height: '20px', marginRight: '0.3rem' }} />
{resyncLoading ? (
<>
<Spinner size="sm" /> Resyncing...
</>
) : (
'Resync'
)}
</Button>
<JKResyncButton resyncAudio={resyncAudio} />
</div>
</CardHeader>

View File

@ -10,16 +10,11 @@ import videoIcon from '../../assets/images/icons8-video-call-50.png';
*
* State colocation: https://kentcdodds.com/blog/state-colocation-will-make-your-react-app-faster
*/
const JKVideoButton = memo(({
canVideo,
getVideoUrl,
onUpgradePrompt,
className
}) => {
const JKVideoButton = memo(({ canVideo, getVideoUrl, onUpgradePrompt, className }) => {
const [loading, setLoading] = useState(false);
// Open external link in new window/tab
const openExternalLink = useCallback((url) => {
const openExternalLink = useCallback(url => {
window.open(url, '_blank', 'noopener,noreferrer');
}, []);
@ -38,7 +33,6 @@ const JKVideoButton = memo(({
// Open video URL in new browser window/tab
openExternalLink(videoUrl);
} catch (error) {
toast.error('Failed to start video session');
} finally {
@ -48,18 +42,8 @@ const JKVideoButton = memo(({
}, [canVideo, getVideoUrl, onUpgradePrompt, openExternalLink]);
return (
<Button
className={className || 'btn-custom-outline'}
outline
size="md"
onClick={handleClick}
disabled={loading}
>
<img
src={videoIcon}
alt="Video"
style={{ width: '20px', height: '20px', marginRight: '0.3rem' }}
/>
<Button className={className || 'btn-custom-outline'} outline size="md" onClick={handleClick} disabled={loading}>
<img src={videoIcon} alt="Video" style={{ width: '20px', height: '20px', marginRight: '0.3rem' }} />
{loading && <Spinner size="sm" />}
&nbsp;Video
</Button>