feat(32-03): create JKVideoButton with colocated loading state

- Extracted video button from JKSessionScreen
- Local loading state prevents parent re-renders
- memo() wrapper for render optimization
- Preserves 10-second loading timeout behavior
- Handles permission checks via canVideo prop
This commit is contained in:
Nuwan 2026-03-05 19:37:51 +05:30
parent e35bed21e3
commit 2075989409
1 changed files with 78 additions and 0 deletions

View File

@ -0,0 +1,78 @@
import React, { useState, useCallback, memo } from 'react';
import { Button, Spinner } from 'reactstrap';
import { toast } from 'react-toastify';
import PropTypes from 'prop-types';
import videoIcon from '../../assets/images/icons8-video-call-50.png';
/**
* Self-contained video button with colocated loading state.
* Loading state changes only re-render this component, not the parent.
*
* State colocation: https://kentcdodds.com/blog/state-colocation-will-make-your-react-app-faster
*/
const JKVideoButton = memo(({
canVideo,
getVideoUrl,
onUpgradePrompt,
className
}) => {
const [loading, setLoading] = useState(false);
// Open external link in new window/tab
const openExternalLink = useCallback((url) => {
window.open(url, '_blank', 'noopener,noreferrer');
}, []);
const handleClick = useCallback(async () => {
if (!canVideo()) {
onUpgradePrompt();
return;
}
try {
setLoading(true);
// Get video conferencing room URL from server
const response = await getVideoUrl();
const videoUrl = `${response.url}&audiooff=true`;
// Open video URL in new browser window/tab
openExternalLink(videoUrl);
} catch (error) {
toast.error('Failed to start video session');
} finally {
// Keep loading state for 10 seconds to prevent multiple clicks
setTimeout(() => setLoading(false), 10000);
}
}, [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' }}
/>
{loading && <Spinner size="sm" />}
&nbsp;Video
</Button>
);
});
JKVideoButton.displayName = 'JKVideoButton';
JKVideoButton.propTypes = {
canVideo: PropTypes.func.isRequired,
getVideoUrl: PropTypes.func.isRequired,
onUpgradePrompt: PropTypes.func.isRequired,
className: PropTypes.string
};
export default JKVideoButton;