171 lines
4 KiB
TypeScript
171 lines
4 KiB
TypeScript
import { configureStore, createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
|
|
|
|
// Auth Slice
|
|
interface User {
|
|
id: string;
|
|
email: string;
|
|
username?: string;
|
|
}
|
|
|
|
interface AuthState {
|
|
user: User | null;
|
|
loading: boolean;
|
|
error: string | null;
|
|
}
|
|
|
|
const initialAuthState: AuthState = {
|
|
user: null,
|
|
loading: false,
|
|
error: null,
|
|
};
|
|
|
|
const authSlice = createSlice({
|
|
name: 'auth',
|
|
initialState: initialAuthState,
|
|
reducers: {
|
|
setLoading: (state, action: PayloadAction<boolean>) => {
|
|
state.loading = action.payload;
|
|
},
|
|
setUser: (state, action: PayloadAction<User | null>) => {
|
|
state.user = action.payload;
|
|
state.loading = false;
|
|
state.error = null;
|
|
},
|
|
setError: (state, action: PayloadAction<string>) => {
|
|
state.error = action.payload;
|
|
state.loading = false;
|
|
},
|
|
logout: (state) => {
|
|
state.user = null;
|
|
state.loading = false;
|
|
state.error = null;
|
|
},
|
|
},
|
|
});
|
|
|
|
export const { setLoading, setUser, setError, logout } = authSlice.actions;
|
|
|
|
// Messaging Slice
|
|
interface Conversation {
|
|
id: string;
|
|
participantName: string;
|
|
lastMessage: string;
|
|
unreadCount: number;
|
|
}
|
|
|
|
interface Message {
|
|
id: string;
|
|
conversationId: string;
|
|
content: string;
|
|
senderId: string;
|
|
timestamp: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
interface MessagingState {
|
|
conversations: Conversation[];
|
|
messages: Record<string, Message[]>;
|
|
}
|
|
|
|
const initialMessagingState: MessagingState = {
|
|
conversations: [],
|
|
messages: {},
|
|
};
|
|
|
|
const messagingSlice = createSlice({
|
|
name: 'messaging',
|
|
initialState: initialMessagingState,
|
|
reducers: {
|
|
setConversations: (state, action: PayloadAction<Conversation[]>) => {
|
|
state.conversations = action.payload;
|
|
},
|
|
addMessage: (state, action: PayloadAction<Message>) => {
|
|
const msg = action.payload;
|
|
if (!state.messages[msg.conversationId]) {
|
|
state.messages[msg.conversationId] = [];
|
|
}
|
|
state.messages[msg.conversationId].push(msg);
|
|
},
|
|
},
|
|
});
|
|
|
|
export const { setConversations, addMessage } = messagingSlice.actions;
|
|
|
|
// Calls Slice
|
|
interface Call {
|
|
id: string;
|
|
participantName: string;
|
|
type: 'audio' | 'video' | 'voice';
|
|
status: 'active' | 'ended' | 'missed';
|
|
duration?: string;
|
|
timestamp: string;
|
|
isMuted?: boolean;
|
|
isCameraOn?: boolean;
|
|
}
|
|
|
|
interface CallsState {
|
|
activeCall: Call | null;
|
|
callHistory: Call[];
|
|
}
|
|
|
|
const initialCallsState: CallsState = {
|
|
activeCall: null,
|
|
callHistory: [],
|
|
};
|
|
|
|
const callsSlice = createSlice({
|
|
name: 'calls',
|
|
initialState: initialCallsState,
|
|
reducers: {
|
|
setActiveCall: (state, action: PayloadAction<Call | null>) => {
|
|
state.activeCall = action.payload;
|
|
},
|
|
addCallToHistory: (state, action: PayloadAction<Call>) => {
|
|
state.callHistory.unshift(action.payload);
|
|
},
|
|
},
|
|
});
|
|
|
|
export const { setActiveCall, addCallToHistory } = callsSlice.actions;
|
|
|
|
// Async thunks
|
|
export const loginAsync = (credentials: { email: string; password: string }) => async (dispatch: AppDispatch) => {
|
|
dispatch(setLoading(true));
|
|
try {
|
|
// TODO: Integrate with Supabase auth
|
|
const mockUser: User = {
|
|
id: '1',
|
|
email: credentials.email,
|
|
username: credentials.email.split('@')[0],
|
|
};
|
|
dispatch(setUser(mockUser));
|
|
} catch (error) {
|
|
dispatch(setError((error as Error).message));
|
|
}
|
|
};
|
|
|
|
export const logoutAsync = () => async (dispatch: AppDispatch) => {
|
|
dispatch(setLoading(true));
|
|
try {
|
|
// TODO: Integrate with Supabase auth
|
|
dispatch(logout());
|
|
} catch (error) {
|
|
dispatch(setError((error as Error).message));
|
|
}
|
|
};
|
|
|
|
// Store
|
|
export const store = configureStore({
|
|
reducer: {
|
|
auth: authSlice.reducer,
|
|
messaging: messagingSlice.reducer,
|
|
calls: callsSlice.reducer,
|
|
},
|
|
});
|
|
|
|
export type RootState = ReturnType<typeof store.getState>;
|
|
export type AppDispatch = typeof store.dispatch;
|
|
|
|
export const useAppDispatch = () => useDispatch<AppDispatch>();
|
|
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|