settings and invitees dialogs in toolbar

This commit is contained in:
Nuwan 2025-11-10 11:14:49 +05:30
parent a5e6a4644d
commit dc98da5c58
14 changed files with 396 additions and 87 deletions

View File

@ -0,0 +1,71 @@
import React, { useState, useEffect } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Form } from 'reactstrap';
import JKModalDialog from '../common/JKModalDialog';
import JKFriendsAutoComplete from '../people/JKFriendsAutoComplete';
import JKSessionInviteesChips from '../people/JKSessionInviteesChips';
import { useTranslation } from 'react-i18next';
//TODO: show already invited friends as chips and prevent re-inviting them
const JKSessionInviteModal = ({ currentSession, show, onToggle, friends, initialInvitees = [], onSubmit, loading }) => {
const { t } = useTranslation();
const [availableFriends, setAvailableFriends] = useState([]);
const [invitees, setInvitees] = useState([]);
useEffect(() => {
const filteredFriends = friends.filter(f => !initialInvitees.some(i => i.id === f.id));
setAvailableFriends(filteredFriends);
setInvitees(initialInvitees);
}, [friends, initialInvitees, show]);
const handleOnSelect = submittedItems => {
updateSessionInvitations(submittedItems);
};
const updateSessionInvitations = submittedInvitees => {
const updatedInvitees = Array.from(new Set([...invitees, ...submittedInvitees]));
setInvitees(updatedInvitees);
const friendIds = submittedInvitees.map(si => si.id);
const updatedFriends = availableFriends.filter(f => !friendIds.includes(f.id));
setAvailableFriends(updatedFriends);
};
const removeInvitee = invitee => {
const updatedInvitees = invitees.filter(i => i.id !== invitee.id);
setInvitees(updatedInvitees);
const updatedFriends = [...availableFriends, invitee];
setAvailableFriends(updatedFriends);
};
const handleSubmit = (e) => {
e.preventDefault();
onSubmit(invitees);
onToggle();
};
return (
<Modal isOpen={show} toggle={onToggle} modalClassName="theme-modal" contentClassName="border">
<Form onSubmit={handleSubmit}>
<ModalHeader toggle={onToggle} className="bg-light d-flex flex-between-center border-bottom-0">
Invite to Session
</ModalHeader>
<ModalBody>
<JKFriendsAutoComplete friends={availableFriends} onSelect={handleOnSelect} />
{invitees.length > 0 && <JKSessionInviteesChips invitees={invitees} removeInvitee={removeInvitee} />}
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={onToggle} disabled={loading}>
Cancel
</Button>
<Button color="primary" type="submit" disabled={loading}>
{loading ? 'Sending...' : 'Send'}
</Button>
</ModalFooter>
</Form>
</Modal>
);
};
export default JKSessionInviteModal;

View File

@ -1,5 +1,5 @@
// jam-ui/src/components/client/JKSessionScreen.js
import React, { useEffect, useContext, useState, memo } from 'react'
import React, { useEffect, useContext, useState, memo, useMemo } from 'react'
import { useParams } from 'react-router-dom';
//import useJamServer, { ConnectionStatus } from '../../hooks/useJamServer'
@ -14,8 +14,9 @@ import { useCurrentSessionContext } from '../../context/CurrentSessionContext.js
import { useJamServerContext } from '../../context/JamServerContext.js';
import { useJamKazamApp } from '../../context/JamKazamAppContext.js';
import { useMixersContext } from '../../context/MixersContext.js';
import { useAuth } from '../../context/UserAuth';
import { getSessionHistory, getSession, joinSession as joinSessionRest } from '../../helpers/rest';
import { getSessionHistory, getSession, joinSession as joinSessionRest, updateSessionSettings, getFriends } from '../../helpers/rest';
import { CLIENT_ROLE } from '../../helpers/globals';
import { MessageType } from '../../helpers/MessageFactory.js';
@ -23,10 +24,15 @@ import { MessageType } from '../../helpers/MessageFactory.js';
import { Alert, Col, Row, Button, Card, CardBody, Modal, ModalHeader, ModalBody, ModalFooter, CardHeader, Badge } from 'reactstrap';
import FalconCardHeader from '../common/FalconCardHeader';
import SessionTrackVU from './SessionTrackVU.js';
import JKSessionSettingsModal from './JKSessionSettingsModal.js';
import JKSessionInviteModal from './JKSessionInviteModal.js';
import { SESSION_PRIVACY_MAP } from '../../helpers/globals.js';
import { toast } from 'react-toastify';
const JKSessionScreen = () => {
const logger = console; // Replace with another logging mechanism if needed
const app = useJamKazamApp();
const { currentUser } = useAuth();
const {
guardAgainstInvalidConfiguration,
@ -66,6 +72,20 @@ const JKSessionScreen = () => {
const [myTracks, setMyTracks] = useState([]);
const [mixers, setMixers] = useState([]);
//state for settings modal
const [showSettingsModal, setShowSettingsModal] = useState(false);
const [settingsLoading, setSettingsLoading] = useState(false);
//state for invite modal
const [friends, setFriends] = useState([]);
const [showInviteModal, setShowInviteModal] = useState(false);
const [sessionInvitees, setSessionInvitees] = useState([]);
const [inviteLoading, setInviteLoading] = useState(false);
//state for volume level modal
const [showVolumeModal, setShowVolumeModal] = useState(false);
const [volumeLevel, setVolumeLevel] = useState(100);
useEffect(() => {
if (!isConnected || !jamClient) return;
console.debug("JKSessionScreen: -DEBUG- isConnected changed to true");
@ -322,6 +342,11 @@ const JKSessionScreen = () => {
const refreshCurrentSession = sessionModel.refreshCurrentSession;
const updateSession = sessionModel.updateSession;
const musicianAccess = useMemo(() => {
if (!currentSession) return null;
return sessionModel.getMusicianAccess();
}, [currentSession]);
// useEffect(() => {
// if (!isConnected) return;
// // validate session by fetching the session from the server
@ -409,16 +434,34 @@ const JKSessionScreen = () => {
setMixers(updatedMixers);
}, [mixerHelper.myTracks])
useEffect(() => {
fetchFriends();
}, []);
const fetchFriends = () => {
if (currentUser) {
getFriends(currentUser.id)
.then(resp => {
if (resp.ok) {
return resp.json();
}
})
.then(data => {
setFriends(data);
});
}
};
return (
<Card>
{!isConnected && <div className='d-flex align-items-center'>Connecting to backend...</div>}
<FalconCardHeader title={`Session ${currentSessionIdRef.current}`} titleClass="font-weight-bold">
<FalconCardHeader title="Session" titleClass="font-weight-bold">
</FalconCardHeader>
<CardHeader className="bg-light border-bottom border-top py-2 border-3">
<div className="d-flex flex-nowrap overflow-auto" style={{ gap: '0.5rem' }}>
<Button className='btn-custom-outline' outline size="md">Settings</Button>
<Button className='btn-custom-outline' outline size="md">Invite</Button>
<Button className='btn-custom-outline' outline size="md" onClick={() => setShowSettingsModal(true)}>Settings</Button>
<Button className='btn-custom-outline' outline size="md" onClick={() => setShowInviteModal(true)}>Invite</Button>
<Button className='btn-custom-outline' outline size="md">Volume</Button>
<Button className='btn-custom-outline' outline size="md">Video</Button>
<Button className='btn-custom-outline' outline size="md">Record</Button>
@ -461,7 +504,7 @@ const JKSessionScreen = () => {
<div className='sessionMix'>
<h5>Session Mix</h5>
<div className='d-flex' style={{ gap: '0.5rem' }}>
</div>
</div>
@ -567,8 +610,94 @@ const JKSessionScreen = () => {
<strong>Last Error:</strong> {lastError ? lastError.message : 'None'}
</div>
</div>
<div className='row mt-2'>
<div className='col-md-12'>
<strong>Current Session:</strong> {JSON.stringify(currentSession)}
</div>
</div>
</div>
</CardBody>
<JKSessionSettingsModal
isOpen={showSettingsModal}
toggle={() => setShowSettingsModal(!showSettingsModal)}
currentSession={{ ...currentSession, privacy: musicianAccess }}
loading={settingsLoading}
onSave={async (payload) => {
console.log('Session settings :', payload);
try {
setSettingsLoading(true);
switch (parseInt(payload.privacy)) {
case SESSION_PRIVACY_MAP['public']:
payload.musician_access = true;
payload.approval_required = false;
break;
case SESSION_PRIVACY_MAP['private_approve']:
payload.musician_access = true;
payload.approval_required = true;
break;
case SESSION_PRIVACY_MAP['private_invite']:
payload.musician_access = false;
payload.approval_required = false;
break;
default:
break;
}
const response = await updateSessionSettings({
id: currentSessionIdRef.current,
...payload
});
const data = await response.json();
console.log('Updated session settings response:', data);
setCurrentSession(prev => ({ ...prev, ...data }));
setShowSettingsModal(false);
toast.success('Session settings updated successfully');
} catch (error) {
console.error('Error updating session settings:', error);
toast.error('Failed to update session settings');
} finally {
setSettingsLoading(false);
}
}}
/>
<JKSessionInviteModal
currentSession={currentSession}
show={showInviteModal}
size="lg"
onToggle={() => setShowInviteModal(false)}
friends={friends}
initialInvitees={sessionInvitees}
loading={inviteLoading}
onSubmit={async (invitees) => {
setSessionInvitees(invitees);
console.log('Submitted invitees:', invitees);
const inviteeIds = invitees.map(i => i.id)
const payload = {
inviteeIds: inviteeIds.join()
};
try {
setInviteLoading(true);
const response = await updateSessionSettings({
id: currentSessionIdRef.current,
...payload
});
const data = await response.json();
console.log('Updated session settings response:', data);
setCurrentSession(prev => ({ ...prev, ...data }));
setShowInviteModal(false);
toast.success('Invitations sent successfully');
} catch (error) {
console.error('Error updating session settings:', error);
toast.error('Failed to send invitations');
} finally {
setInviteLoading(false);
}
}}
/>
</Card>
)
}

View File

@ -0,0 +1,101 @@
import React, { useState, useEffect } from 'react';
import {
Button,
Modal,
ModalHeader,
ModalBody,
ModalFooter,
Form,
FormGroup,
Label,
Input,
Alert
} from 'reactstrap';
import { SESSION_PRIVACY_MAP } from '../../helpers/globals.js';
import { useTranslation } from 'react-i18next'
const JKSessionSettingsModal = ({ isOpen, toggle, currentSession, onSave, loading }) => {
const [privacy, setPrivacy] = useState(currentSession ? currentSession.privacy : SESSION_PRIVACY_MAP.private_approve);
const [description, setDescription] = useState(currentSession ? currentSession.description : '');
const { t } = useTranslation();
const handleSubmit = (e) => {
e.preventDefault();
onSave({ privacy, description });
};
useEffect(() => {
if (isOpen && currentSession) {
setPrivacy(currentSession.privacy || SESSION_PRIVACY_MAP.private_approve);
setDescription(currentSession.description || '');
}
}, [isOpen, currentSession.privacy, currentSession.description]);
const handleCancel = () => {
// Reset to original values
// if (currentSession) {
// setPrivacy(currentSession.privacy || SESSION_PRIVACY_MAP.private_approve);
// setDescription(currentSession.description || '');
// }
toggle();
};
return (
<Modal isOpen={isOpen} toggle={handleCancel} modalClassName="theme-modal" contentClassName="border">
<Form onSubmit={handleSubmit}>
<ModalHeader toggle={handleCancel} className="bg-light d-flex flex-between-center border-bottom-0">
Session Settings
</ModalHeader>
<ModalBody>
<FormGroup>
<Label className="fs-0" for="privacySelect">
Access
</Label>
<Input
type="select"
aria-label="Session Privacy"
name="privacy"
value={privacy}
onChange={e => setPrivacy(e.target.value)}
data-testid="session-privacy"
>
<option value={SESSION_PRIVACY_MAP['public']}>{t('new.privacy_opt_public', { ns: 'sessions' })}</option>
<option value={SESSION_PRIVACY_MAP['private_invite']}>
{t('new.privacy_opt_private_invite', { ns: 'sessions' })}
</option>
<option value={SESSION_PRIVACY_MAP['private_approve']}>
{t('new.privacy_opt_private_approve', { ns: 'sessions' })}
</option>
</Input>
</FormGroup>
<FormGroup>
<Label className="fs-0" for="descriptionTextarea">
Description
</Label>
<Input
type="textarea"
name="description"
id="descriptionTextarea"
value={description}
onChange={(e) => setDescription(e.target.value)}
rows={4}
disabled={loading}
/>
</FormGroup>
</ModalBody>
<ModalFooter className="bg-light border-top-0">
<Button color="secondary" onClick={handleCancel} disabled={loading}>
Cancel
</Button>
<Button color="primary" type="submit" disabled={loading}>
{loading ? 'Saving...' : 'Save'}
</Button>
</ModalFooter>
</Form>
</Modal>
);
};
export default JKSessionSettingsModal;

View File

@ -9,7 +9,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { fetchOnlineMusicians } from '../../store/features/onlineMusiciansSlice';
import { fetchUserLatencies } from '../../store/features/latencySlice';
import { useAuth } from '../../context/UserAuth';
import { sessionPrivacyMap } from '../../config';
import { SESSION_PRIVACY_MAP } from '../../helpers/globals.js';
import jkCustomUrlScheme from '../../helpers/jkCustomUrlScheme';
import useNativeAppCheck from '../../hooks/useNativeAppCheck';
import { useNativeApp } from '../../context/NativeAppContext';
@ -138,7 +138,7 @@ function JKMusicSessionsLobby() {
const handleClick = async () => {
const payload = {
privacy: sessionPrivacyMap.public,
privacy: SESSION_PRIVACY_MAP.public,
description: t('list.descriptions.public_open_session', { ns: 'sessions' }),
inviteeIds: selectedUsers
};

View File

@ -12,7 +12,7 @@ import JKModalDialog from '../common/JKModalDialog';
import useNativeAppCheck from '../../hooks/useNativeAppCheck';
import { useNativeApp } from '../../context/NativeAppContext';
import { useResponsive } from '@farfetch/react-context-responsive';
import { sessionPrivacyMap } from '../../config';
import { SESSION_PRIVACY_MAP } from '../../helpers/globals';
import JKAppLaunch from './JKAppLaunch';
import { formatUtcTime } from '../../helpers/utils';
@ -119,15 +119,15 @@ const JKNewMusicSession = () => {
} else {
switch (parseInt(payload.privacy)) {
case sessionPrivacyMap['public']:
case SESSION_PRIVACY_MAP['public']:
payload.musician_access = true;
payload.approval_required = false;
break;
case sessionPrivacyMap['private_approve']:
case SESSION_PRIVACY_MAP['private_approve']:
payload.musician_access = true;
payload.approval_required = true;
break;
case sessionPrivacyMap['private_invite']:
case SESSION_PRIVACY_MAP['private_invite']:
payload.musician_access = false;
payload.approval_required = false;
break;
@ -232,11 +232,11 @@ const JKNewMusicSession = () => {
onChange={e => setPrivacy(e.target.value)}
data-testid="session-privacy"
>
<option value={sessionPrivacyMap['public']}>{t('new.privacy_opt_public', { ns: 'sessions' })}</option>
<option value={sessionPrivacyMap['private_invite']}>
<option value={SESSION_PRIVACY_MAP['public']}>{t('new.privacy_opt_public', { ns: 'sessions' })}</option>
<option value={SESSION_PRIVACY_MAP['private_invite']}>
{t('new.privacy_opt_private_invite', { ns: 'sessions' })}
</option>
<option value={sessionPrivacyMap['private_approve']}>
<option value={SESSION_PRIVACY_MAP['private_approve']}>
{t('new.privacy_opt_private_approve', { ns: 'sessions' })}
</option>
</Input>

View File

@ -15,9 +15,9 @@ export const settings = {
isNavbarVerticalCollapsed: false,
navbarStyle: 'transparent',
};
export const sessionPrivacyMap = {
public: 1,
private_invite: 2,
private_approve: 3
};
export default { version, navbarBreakPoint, topNavbarBreakpoint, settings, sessionPrivacyMap };
// export const sessionPrivacyMap = {
// public: 1,
// private_invite: 2,
// private_approve: 3
// };
export default { version, navbarBreakPoint, topNavbarBreakpoint, settings };

View File

@ -1,6 +1,6 @@
import React, { createContext, useContext, useState, useRef, useEffect } from 'react';
//import useMixerHelper from '../hooks/useMixerHelper';
import { useJamServerContext } from './JamServerContext';
import { getSessionHistory } from '../helpers/rest';
const CurrentSessionContext = createContext(null);
@ -8,16 +8,6 @@ export const CurrentSessionProvider = ({ children }) => {
const [currentSession, setCurrentSession] = useState({});
const currentSessionIdRef = useRef(null);
//const mixerHelper = useMixerHelper();
// const { isConnected,
// connectionStatus,
// reconnectAttempts,
// lastError,
// jamClient,
// server,
// registerMessageCallback,
// ConnectionStatus } = useJamServerContext();
const inSession = () => {
return currentSessionIdRef.current !== null;
};
@ -27,6 +17,20 @@ export const CurrentSessionProvider = ({ children }) => {
currentSessionIdRef.current = id;
};
const refreshSession = async () => {
if (currentSessionIdRef.current) {
try {
const sessionData = await getSessionHistory(currentSessionIdRef.current);
const musicSession = await sessionData.json();
setCurrentSession(musicSession);
} catch (error) {
console.error("Failed to refresh session data:", error);
}
}else {
console.warn("No current session ID set; cannot refresh session data.");
}
};
return (
<CurrentSessionContext.Provider value={{
currentSession,

View File

@ -398,4 +398,16 @@ export const LATENCY = {
UNACCEPTABLE: { description: "HIGH", style: "latency-poor", min: 100, max: 10000000 },
UNKNOWN: { description: "UNKNOWN", style: "latency-unknown", min: -2, max: -2 },
FAILED: { description: "N/A", style: "latency-failed", min: -3, max: -3 }
};
// export const SESSION_ACCESS_LEVELS = {
// RSVP_ONLY: 'rsvp-only',
// MUSICIANS_APPROVAL: 'musicians-approval',
// MUSICIANS: 'musicians',
// }
export const SESSION_PRIVACY_MAP = {
public: 1,
private_invite: 2,
private_approve: 3
};

View File

@ -824,19 +824,6 @@ export const updatePayment = (options = {}) => {
});
};
// function postUpdateEmail(email, current_password) {
// var url = "/api/users/" + context.JK.currentUserId + "/update_email";
// return $.ajax({
// type: "POST",
// dataType: "json",
// contentType: 'application/json',
// url: url,
// data: JSON.stringify({ update_email: email, current_password: current_password }),
// processData: false
// });
// }
export const updateEmail = (userId, email, current_password) => {
return new Promise((resolve, reject) => {
apiFetch(`/users/${userId}/update_email`, {
@ -848,19 +835,6 @@ export const updateEmail = (userId, email, current_password) => {
});
}
// function updateUdpReachable(options) {
// var id = getId(options);
// return $.ajax({
// type: "POST",
// dataType: "json",
// contentType: 'application/json',
// url: "/api/users/" + id + "/udp_reachable",
// data: JSON.stringify(options),
// processData: false
// });
// }
export const updateUdpReachable = (options = {}) => {
const { id, ...rest } = options;
return new Promise((resolve, reject) => {
@ -883,23 +857,6 @@ export const deleteParticipant = (clientId) => {
});
}
// function createDiagnostic(options) {
// var data = null;
// try {
// data = JSON.stringify(options)
// }
// catch (e) {
// data = JSON.stringify({data_error: "unable to JSON.stringify debug data:" + e.toString()})
// }
// return $.ajax({
// type: "POST",
// url: '/api/diagnostics',
// dataType: "json",
// contentType: 'application/json',
// data: data,
// });
// }
export const createDiagnostic = (options = {}) => {
let data = null;
try {
@ -928,3 +885,15 @@ export const putTrackSyncChange = (options = {}) => {
.catch(error => reject(error));
});
}
export const updateSessionSettings = (options = {}) => {
const { id, ...rest } = options;
return new Promise((resolve, reject) => {
apiFetch(`/sessions/${id}`, {
method: 'PUT',
body: JSON.stringify(rest)
})
.then(response => resolve(response))
.catch(error => reject(error));
});
}

View File

@ -57,7 +57,7 @@ const useMixerHelper = () => {
useEffect(() => {
allMixersRef.current = allMixers;
console.log("_XDEBUG_ useMixerHelper: allMixersRef updated", allMixersRef.current);
// console.log("_XDEBUG_ useMixerHelper: allMixersRef updated", allMixersRef.current);
}, [allMixers]);
const getMixer = (mixerId, mode) => {
@ -214,7 +214,7 @@ const useMixerHelper = () => {
useEffect(() => {
if (Object.keys(allMixers).length > 0 && !isReady.current) {
console.log("useMixerHelper: isReady set to true");
// console.log("useMixerHelper: isReady set to true");
isReady.current = true;
}
}, [allMixers, isReady]);
@ -1162,7 +1162,7 @@ const useMixerHelper = () => {
const mixer = getMixer(mixerId, mode);
if (mixer) {
console.log("useMixerHelper: updateVU mixer", allMixersRef.current, mixerId, mode, mixer);
// console.log("useMixerHelper: updateVU mixer", allMixersRef.current, mixerId, mode, mixer);
updateVU3(mixer, leftValue, leftClipping, rightValue, rightClipping);
}
}, []);

View File

@ -156,9 +156,9 @@ export default function useMixerStore() {
// value is a DB value from -80 to 20. Convert to float from 0.0-1.0
//console.log('handleBridgeCallback@mixers',@mixers)
console.log("mixerHelper.isReady", mixerHelper.isReady.current);
// console.log("mixerHelper.isReady", mixerHelper.isReady.current);
if (mixerHelper.isReady.current) {
console.log("mixerHelper handleBridgeCallback: ", mixerId, mode, leftValue, rightValue, leftClipping, rightClipping);
// console.log("mixerHelper handleBridgeCallback: ", mixerId, mode, leftValue, rightValue, leftClipping, rightClipping);
mixerHelper.updateVU(mixerId, mode, (leftValue + 80) / 80, leftClipping, (rightValue + 80) / 80, rightClipping);
}

View File

@ -162,6 +162,16 @@ const useSessionHelper = () => {
return currentSession?.id || null;
};
const musicianAccess = () => {
if (!currentSession.musician_access && !currentSession.approval_required) {
return 'only-rsvp';
}else if(currentSession.musician_access && currentSession.approval_required){
return 'musicians-approval';
}else if(currentSession.musician_access && !currentSession.approval_required){
return 'musicians';
}
};
return {
inSession: inSessionCheck,
participants,
@ -182,7 +192,7 @@ const useSessionHelper = () => {
recordedJamTrackName,
recordingName,
getParticipant,
id
id,
};
}, [currentSession, inSession]);

View File

@ -8,7 +8,7 @@ import useRecordingHelpers from './useRecordingHelpers';
import useSessionUtils from './useSessionUtils';
import { joinSession as joinSessionRest, getSession, deleteParticipant } from '../helpers/rest';
import { MessageType } from '../helpers/MessageFactory';
import { LATENCY } from '../helpers/globals';
import { LATENCY, SESSION_PRIVACY_MAP } from '../helpers/globals';
const logger = console;
@ -237,6 +237,18 @@ export default function useSessionModel(app, server, sessionScreen) {
return currentSession.user_id;
}, [currentSession]);
// Get musician access
const getMusicianAccess = useCallback(() => {
if (!currentSession.musician_access && !currentSession.approval_required) {
return SESSION_PRIVACY_MAP.private_invite;
} else if (currentSession.musician_access && currentSession.approval_required) {
return SESSION_PRIVACY_MAP.private_approve;
} else if (currentSession.musician_access && !currentSession.approval_required) {
return SESSION_PRIVACY_MAP.public;
}
}, [currentSession]);
// Check if already in session
const alreadyInSession = useCallback(() => {
let inSession = false;
@ -324,7 +336,7 @@ export default function useSessionModel(app, server, sessionScreen) {
});
}, [getUserTracks, isNoInputProfile]);
// Duplicate declaration of SessionPageEnter removed to fix redeclaration error.
// Duplicate declaration of SessionPageEnter removed to fix redeclaration error.
// Join session
@ -756,11 +768,11 @@ export default function useSessionModel(app, server, sessionScreen) {
const previousMetronomeTracks = previousAllTracks.metronomeTracks;
if (!(previousBackingTracks.length === 0 && backingTracksData.length === 0) &&
JSON.stringify(previousBackingTracks) !== JSON.stringify(backingTracksData)) {
JSON.stringify(previousBackingTracks) !== JSON.stringify(backingTracksData)) {
logger.debug("backing tracks changed", previousBackingTracks, backingTracksData);
syncTracks(allTracks);
} else if (!(previousMetronomeTracks.length === 0 && metronomeTracks.length === 0) &&
JSON.stringify(previousMetronomeTracks) !== JSON.stringify(metronomeTracks)) {
JSON.stringify(previousMetronomeTracks) !== JSON.stringify(metronomeTracks)) {
logger.debug("metronome state changed ", previousMetronomeTracks, metronomeTracks);
syncTracks(allTracks);
} else {
@ -1028,6 +1040,7 @@ export default function useSessionModel(app, server, sessionScreen) {
getBackingTrack: () => openBackingTrack,
hasShownAudioMediaMixerHelp: () => shownAudioMediaMixerHelp,
markShownAudioMediaMixerHelp: () => setShownAudioMediaMixerHelp(true),
getMusicianAccess,
// Audio establishment
setAudioEstablished,

View File

@ -108,7 +108,7 @@ export default function useVuHelpers() {
const updateVU3 = useCallback(
(mixer, leftValue, leftClipping, rightValue, rightClipping) => {
const fqId = createQualifiedId(mixer);
logger.debug('useVuHelpers: updateVU3', { fqId, mixer, leftValue, rightValue });
//logger.debug('useVuHelpers: updateVU3', { fqId, mixer, leftValue, rightValue });
// Update React state for declarative rendering
updateVuState(fqId, leftValue, leftClipping);
@ -149,7 +149,7 @@ export default function useVuHelpers() {
lightClass += 'vu-off';
}
console.debug('VuMeterComponent render', { i, lightThreshold, isOn, lightClass });
//console.debug('VuMeterComponent render', { i, lightThreshold, isOn, lightClass });
lights.push(
<td