Compare commits

..

No commits in common. "dev" and "main" have entirely different histories.
dev ... main

1 changed files with 28 additions and 42 deletions

View File

@ -42,31 +42,20 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
}; };
} }
generateRoomName(): string { generateRoomName(shapeId: string): string {
// Extract room/canvas slug from URL // Extract board ID from URL
// Supports both /:slug and /board/:slug patterns let boardId = 'default';
let roomSlug = 'default';
const currentUrl = window.location.pathname; const currentUrl = window.location.pathname;
// First try /board/:slug pattern
const boardMatch = currentUrl.match(/\/board\/([^\/]+)/); const boardMatch = currentUrl.match(/\/board\/([^\/]+)/);
if (boardMatch) { if (boardMatch) {
roomSlug = boardMatch[1]; boardId = boardMatch[1].substring(0, 8); // First 8 chars
} else {
// Try direct /:slug pattern (e.g., /mycofi, /ccc)
// Exclude known non-board routes
const excludedRoutes = ['login', 'contact', 'inbox', 'debug', 'dashboard', 'presentations', 'google', 'oauth'];
const slugMatch = currentUrl.match(/^\/([^\/]+)\/?$/);
if (slugMatch && !excludedRoutes.includes(slugMatch[1])) {
roomSlug = slugMatch[1];
}
} }
// Clean the slug (remove special chars, lowercase) // Clean the shape ID (remove 'shape:' prefix and special chars)
const cleanSlug = roomSlug.replace(/[^A-Za-z0-9-]/g, '').toLowerCase(); const cleanShapeId = shapeId.replace(/^shape:/, '').replace(/[^A-Za-z0-9]/g, '').substring(0, 8);
// Create room name: {slug}-jeffsi-meet // Create a readable room name
return `${cleanSlug}-jeffsi-meet`; return `canvas-${boardId}-${cleanShapeId}`;
} }
component(shape: IVideoChatShape) { component(shape: IVideoChatShape) {
@ -81,7 +70,7 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
// Initialize room name if not set // Initialize room name if not set
useEffect(() => { useEffect(() => {
if (!roomName) { if (!roomName) {
const newRoomName = this.generateRoomName(); const newRoomName = this.generateRoomName(shape.id);
setRoomName(newRoomName); setRoomName(newRoomName);
// Update shape props with room name // Update shape props with room name
@ -134,29 +123,26 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
// Construct Jitsi Meet URL with configuration // Construct Jitsi Meet URL with configuration
const jitsiUrl = new URL(`https://${JITSI_DOMAIN}/${roomName}`) const jitsiUrl = new URL(`https://${JITSI_DOMAIN}/${roomName}`)
// Add configuration via URL hash params (Jitsi supports this) // Add configuration via URL params (Jitsi supports this)
// Build hash string properly to avoid double-hash bug const config = {
const configParams = [
// Enable prejoin to request camera/mic permissions properly
'config.prejoinPageEnabled=true',
// Start with devices enabled based on props
`config.startWithAudioMuted=${props.allowMicrophone ? 'false' : 'true'}`,
`config.startWithVideoMuted=${props.allowCamera ? 'false' : 'true'}`,
// UI Configuration // UI Configuration
'config.disableModeratorIndicator=true', 'config.prejoinPageEnabled': 'false',
'config.enableWelcomePage=false', 'config.startWithAudioMuted': props.allowMicrophone ? 'false' : 'true',
'config.hideConferenceSubject=true', 'config.startWithVideoMuted': props.allowCamera ? 'false' : 'true',
'config.disableModeratorIndicator': 'true',
'config.enableWelcomePage': 'false',
// Interface configuration // Interface configuration
'interfaceConfig.SHOW_JITSI_WATERMARK=false', 'interfaceConfig.SHOW_JITSI_WATERMARK': 'false',
'interfaceConfig.SHOW_BRAND_WATERMARK=false', 'interfaceConfig.SHOW_BRAND_WATERMARK': 'false',
'interfaceConfig.SHOW_POWERED_BY=false', 'interfaceConfig.SHOW_POWERED_BY': 'false',
'interfaceConfig.HIDE_INVITE_MORE_HEADER=true', 'interfaceConfig.HIDE_INVITE_MORE_HEADER': 'true',
'interfaceConfig.MOBILE_APP_PROMO=false', 'interfaceConfig.MOBILE_APP_PROMO': 'false',
'interfaceConfig.DISABLE_JOIN_LEAVE_NOTIFICATIONS=true', }
]
// Set hash once with all params joined // Add config params to URL
jitsiUrl.hash = configParams.join('&') Object.entries(config).forEach(([key, value]) => {
jitsiUrl.hash = `${jitsiUrl.hash}${jitsiUrl.hash ? '&' : ''}${key}=${value}`
})
const handleClose = () => { const handleClose = () => {
this.editor.deleteShape(shape.id) this.editor.deleteShape(shape.id)
@ -249,8 +235,8 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
left: 0, left: 0,
right: 0, right: 0,
bottom: 0, bottom: 0,
// Always enable pointer events for mouse/touch/pen interaction // Only enable pointer events when selected, so canvas can pan when not selected
pointerEvents: "all", pointerEvents: isSelected ? "all" : "none",
}} }}
allow="camera; microphone; fullscreen; display-capture; autoplay; clipboard-write" allow="camera; microphone; fullscreen; display-capture; autoplay; clipboard-write"
referrerPolicy="no-referrer-when-downgrade" referrerPolicy="no-referrer-when-downgrade"