113 lines
2.6 KiB
TypeScript
113 lines
2.6 KiB
TypeScript
/**
|
|
* Calls State Slice
|
|
* Manages voice and video calls
|
|
*/
|
|
|
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
|
|
export interface Call {
|
|
id: string;
|
|
type: 'voice' | 'video';
|
|
participants: string[];
|
|
initiatorId: string;
|
|
status: 'ringing' | 'active' | 'ended' | 'declined' | 'missed';
|
|
startedAt?: string;
|
|
endedAt?: string;
|
|
}
|
|
|
|
export interface VoiceState {
|
|
muted: boolean;
|
|
deafened: boolean;
|
|
speaking: boolean;
|
|
volume: number;
|
|
}
|
|
|
|
interface CallsState {
|
|
activeCall: Call | null;
|
|
incomingCall: Call | null;
|
|
callHistory: Call[];
|
|
voiceState: VoiceState;
|
|
error: string | null;
|
|
}
|
|
|
|
const initialState: CallsState = {
|
|
activeCall: null,
|
|
incomingCall: null,
|
|
callHistory: [],
|
|
voiceState: {
|
|
muted: false,
|
|
deafened: false,
|
|
speaking: false,
|
|
volume: 100,
|
|
},
|
|
error: null,
|
|
};
|
|
|
|
const callsSlice = createSlice({
|
|
name: 'calls',
|
|
initialState,
|
|
reducers: {
|
|
setActiveCall: (state, action: PayloadAction<Call>) => {
|
|
state.activeCall = action.payload;
|
|
state.incomingCall = null;
|
|
},
|
|
setIncomingCall: (state, action: PayloadAction<Call>) => {
|
|
state.incomingCall = action.payload;
|
|
},
|
|
endCall: (state) => {
|
|
if (state.activeCall) {
|
|
const endedCall = {
|
|
...state.activeCall,
|
|
status: 'ended' as const,
|
|
endedAt: new Date().toISOString(),
|
|
};
|
|
state.callHistory.unshift(endedCall);
|
|
state.activeCall = null;
|
|
}
|
|
},
|
|
declineCall: (state) => {
|
|
if (state.incomingCall) {
|
|
const declinedCall = {
|
|
...state.incomingCall,
|
|
status: 'declined' as const,
|
|
endedAt: new Date().toISOString(),
|
|
};
|
|
state.callHistory.unshift(declinedCall);
|
|
state.incomingCall = null;
|
|
}
|
|
},
|
|
setMuted: (state, action: PayloadAction<boolean>) => {
|
|
state.voiceState.muted = action.payload;
|
|
},
|
|
setDeafened: (state, action: PayloadAction<boolean>) => {
|
|
state.voiceState.deafened = action.payload;
|
|
// Deafening also mutes
|
|
if (action.payload) {
|
|
state.voiceState.muted = true;
|
|
}
|
|
},
|
|
setSpeaking: (state, action: PayloadAction<boolean>) => {
|
|
state.voiceState.speaking = action.payload;
|
|
},
|
|
setVolume: (state, action: PayloadAction<number>) => {
|
|
state.voiceState.volume = Math.max(0, Math.min(100, action.payload));
|
|
},
|
|
clearError: (state) => {
|
|
state.error = null;
|
|
},
|
|
},
|
|
});
|
|
|
|
export const {
|
|
setActiveCall,
|
|
setIncomingCall,
|
|
endCall,
|
|
declineCall,
|
|
setMuted,
|
|
setDeafened,
|
|
setSpeaking,
|
|
setVolume,
|
|
clearError,
|
|
} = callsSlice.actions;
|
|
|
|
export default callsSlice.reducer;
|