import { MiddlewareAPI, Dispatch } from 'redux'; import { Firebase } from '../../FirebaseContext'; import { GameActionTypes, GAME_HOSTING, GAME_JOINED, GAME_EXITED, GAME_START, GAME_SEND_SELECTED, GAME_SEND_WINNER, ErrorType, SIGNUP, LOGIN, NEW_DISPLAY_NAME, DELETE_USER, GAME_JOINING_EXISTING, Pack, LOGIN_AS_GUEST, } from '../actionTypes/gameTypes'; import Axios from 'axios'; import { userLoaded, joinGame, gameStarted, updatePlayers, newRound, error, newDisplayName } from '../actions/gameActions'; import { Subscription } from 'rxjs'; import ReactGA from '../../analytics'; import { GameState } from '../reducers/gameReducer'; export default function firebaseMiddleware(firebase: Firebase) { const middleware = function middleware(params: MiddlewareAPI<Dispatch, GameState>) { const { dispatch /*getState*/ } = params; let newPlayersSubscription: Subscription | null = null; let newRoundSubscription: Subscription | null = null; firebase.auth.onAuthStateChanged((user) => { if (user) { firebase.uid = user.uid; ReactGA.set({ userId: user.uid }); user.getIdToken(true).then((idToken) => { Axios.defaults.headers.common['Authorization'] = `Bearer ${idToken}`; }); setTimeout(() => { dispatch(userLoaded(true, user.uid, user.displayName || '')); }, 1000); } else { dispatch(userLoaded(false, '', '')); } }); const checkDisplayName = (displayName: string) => { if (!displayName.trim()) { dispatch(error('Display name not valid', 'Profile error', ErrorType.PROFILE)); return false; } return true; }; return function (next: Dispatch) { return async function (action: GameActionTypes) { switch (action.type) { case LOGIN: firebase.doSignInWithEmailAndPassword(action.payload.email, action.payload.password).catch((e) => { dispatch(error(e.message, 'Login error', ErrorType.LOGIN)); }); break; case LOGIN_AS_GUEST: if (checkDisplayName(action.payload.displayName)) { firebase .doSignInAsGuest() .then(() => { dispatch(newDisplayName(action.payload.displayName)); }) .catch((e) => { dispatch(error(e.message, 'Login error', ErrorType.LOGIN)); }); } break; case SIGNUP: if (checkDisplayName(action.payload.displayName)) { firebase .doCreateUserWithEmailAndPassword(action.payload.email, action.payload.password) .then(() => { dispatch(newDisplayName(action.payload.displayName)); }) .catch((e) => { dispatch(error(e.message, 'Signup error', ErrorType.SIGNUP)); }); } break; case NEW_DISPLAY_NAME: if (checkDisplayName(action.payload.displayName)) { firebase.changeDisplayName(action.payload.displayName); } else { return; } break; case DELETE_USER: firebase.deleteUser()?.catch((e) => { dispatch(error(e.message, 'Delete user', ErrorType.DELETE_USER)); }); break; case GAME_HOSTING: (async () => { const response = await Axios.get<{ roomID: string }>(`/game/createRoom/${action.payload.lang}`); dispatch(joinGame(response.data.roomID)); })(); break; case GAME_JOINING_EXISTING: Axios.get<{ roomID?: string; error?: string }>('/game/joinExisting') .then((response) => { if (response.data.roomID) { dispatch(joinGame(response.data.roomID)); } else { dispatch(error(response.data.error || 'No room available now', 'Join game', ErrorType.JOIN)); } }) .catch((e) => { dispatch(error(e.message, 'Join game', ErrorType.JOIN)); }); break; case GAME_JOINED: (async () => { try { await firebase.enterRoom(action.payload.roomID); // Richiedo il pack della room corrente const packRef = await firebase.getPackRef(); // Mi assicuro che sia scaricato il pack prima di iniziare il gioco const pack = (await Axios.get<Pack>(`/game/pack/${packRef.lang}/${packRef.selectedPack}`)).data; // Attendo l'inizio del gioco firebase.notifyOnGameStart().then(() => { dispatch(gameStarted(pack)); }); newRoundSubscription = firebase.notifyNewRound$(pack).subscribe((newRoundData) => { const { round, cards, role, blackCard, judgeID } = newRoundData; dispatch(newRound(round, cards, role, blackCard, judgeID)); }); newPlayersSubscription = firebase.notifyNewPlayers$(pack).subscribe((players) => { dispatch(updatePlayers(players)); }); } catch (e) { dispatch(error('Cannot join the game', 'Join game', ErrorType.JOIN)); } })(); break; case GAME_START: await firebase.startGame(); break; case GAME_EXITED: newRoundSubscription?.unsubscribe(); newPlayersSubscription?.unsubscribe(); await firebase.exitRoom(); break; case GAME_SEND_SELECTED: firebase.sendSelected(action.payload.cards); break; case GAME_SEND_WINNER: await Axios.post('/game/sendWinner', { player: action.payload.player.uid, roomID: firebase.roomID, }); break; } return next(action); }; }; }; return middleware; }