From e7a16fa3b9d2b54cdd740fee357dab80cff80a8f Mon Sep 17 00:00:00 2001 From: HF Date: Wed, 8 Jan 2020 15:58:21 +0100 Subject: [PATCH] store / reducers fixes, move websocketClient to reducers --- src/actions/index.js | 46 +++++++++++++++-------------- src/actions/types.js | 28 +++++++++++++++--- src/components/ReCaptcha.jsx | 3 +- src/store/ads.js | 2 +- src/store/analytics.js | 2 +- src/store/array.js | 2 +- src/store/configureStore.js | 16 +++++++---- src/store/notifications.js | 2 +- src/store/promise.js | 2 +- src/store/protocolClientHook.js | 51 +++++++++++++++++++++++++++++++++ src/store/sweetAlert.js | 31 ++++++++++++++++++++ src/store/track.js | 4 +-- 12 files changed, 148 insertions(+), 41 deletions(-) create mode 100644 src/store/protocolClientHook.js create mode 100644 src/store/sweetAlert.js diff --git a/src/actions/index.js b/src/actions/index.js index 5273a07..0082ad7 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,8 +1,5 @@ /* @flow */ -import swal from 'sweetalert2'; -import 'sweetalert2/src/sweetalert2.scss'; - import type { Action, ThunkAction, @@ -11,13 +8,27 @@ import type { import type { Cell } from '../core/Cell'; import type { ColorIndex } from '../core/Palette'; -import ProtocolClient from '../socket/ProtocolClient'; import { loadImage } from '../ui/loadImage'; import { getColorIndexOfPixel, } from '../core/utils'; +export function sweetAlert( + title: string, + text: string, + icon: string, + confirmButtonText: string, +): Action { + return { + type: 'ALERT', + title, + text, + icon, + confirmButtonText, + }; +} + export function toggleChatBox(): Action { return { type: 'TOGGLE_CHAT_BOX', @@ -255,12 +266,12 @@ export function requestPlacePixel( } dispatch(pixelFailure()); - swal.fire({ - title: (errorTitle || `Error ${response.status}`), - text: errors[0].msg, - icon: 'error', - confirmButtonText: 'OK', - }); + dispatch(sweetAlert( + (errorTitle || `Error ${response.status}`), + errors[0].msg, + 'error', + 'OK', + )); } finally { dispatch(setPlaceAllowed(true)); } @@ -418,7 +429,6 @@ export function fetchChunk(canvasId, center: Cell): PromiseAction { return async (dispatch) => { dispatch(requestBigChunk(center)); try { - ProtocolClient.registerChunk([cx, cy]); const url = `/chunks/${canvasId}/${cx}/${cy}.bmp`; const response = await fetch(url); if (response.ok) { @@ -475,7 +485,6 @@ export function receiveMe( minecraftname, canvases, } = me; - ProtocolClient.setName(name); return { type: 'RECEIVE_ME', name: (name) || null, @@ -504,7 +513,6 @@ export function receiveStats( export function setName( name: string, ): Action { - ProtocolClient.setName(name); return { type: 'SET_NAME', name, @@ -557,9 +565,7 @@ export function fetchMe(): PromiseAction { if (response.ok) { const me = await response.json(); - await dispatch(receiveMe(me)); - const state = getState(); - ProtocolClient.setCanvas(state.canvas.canvasId); + dispatch(receiveMe(me)); } }; } @@ -660,18 +666,14 @@ export function onViewFinishChange(): Action { } export function urlChange(): PromiseAction { - return async (dispatch, getState) => { - await dispatch(reloadUrl()); - const state = getState(); - ProtocolClient.setCanvas(state.canvas.canvasId); + return (dispatch, getState) => { + dispatch(reloadUrl()); }; } export function switchCanvas(canvasId: number): PromiseAction { return async (dispatch, getState) => { await dispatch(selectCanvas(canvasId)); - const state = getState(); - ProtocolClient.setCanvas(state.canvas.canvasId); dispatch(onViewFinishChange()); }; } diff --git a/src/actions/types.js b/src/actions/types.js index 409d363..2265b22 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -8,6 +8,12 @@ import type { State } from '../reducers'; export type Action = { type: 'LOGGED_OUT' } // my actions + | { type: 'ALERT', + title: string, + text: string, + icon: string, + confirmButtonText: string, + } | { type: 'TOGGLE_GRID' } | { type: 'TOGGLE_PIXEL_NOTIFY' } | { type: 'TOGGLE_AUTO_ZOOM_IN' } @@ -38,13 +44,27 @@ export type Action = | { type: 'RECEIVE_IMAGE_TILE', center: Cell, tile: Image } | { type: 'RECEIVE_BIG_CHUNK_FAILURE', center: Cell, error: Error } | { type: 'RECEIVE_COOLDOWN', waitSeconds: number } - | { type: 'RECEIVE_PIXEL_UPDATE', i: number, j: number, offset: number, color: ColorIndex } + | { type: 'RECEIVE_PIXEL_UPDATE', + i: number, + j: number, + offset: number, + color: ColorIndex, + } | { type: 'RECEIVE_ONLINE', online: number } | { type: 'RECEIVE_CHAT_MESSAGE', name: string, text: string } | { type: 'RECEIVE_CHAT_HISTORY', data: Array } - | { type: 'RECEIVE_ME', name: string, waitSeconds: number, messages: Array, - mailreg: boolean, totalPixels: number, dailyTotalPixels: number, - ranking: number, dailyRanking: number, minecraftname: string, canvases: Object} + | { type: 'RECEIVE_ME', + name: string, + waitSeconds: number, + messages: Array, + mailreg: boolean, + totalPixels: number, + dailyTotalPixels: number, + ranking: number, + dailyRanking: number, + minecraftname: string, + canvases: Object + } | { type: 'RECEIVE_STATS', totalRanking: Object, totalDailyRanking: Object } | { type: 'SET_NAME', name: string } | { type: 'SET_MINECRAFT_NAME', minecraftname: string } diff --git a/src/components/ReCaptcha.jsx b/src/components/ReCaptcha.jsx index f575554..27c4ae9 100644 --- a/src/components/ReCaptcha.jsx +++ b/src/components/ReCaptcha.jsx @@ -7,7 +7,6 @@ import React from 'react'; -import type { State } from '../reducers'; import store from '../ui/store'; import { requestPlacePixel } from '../actions'; @@ -18,7 +17,7 @@ function onCaptcha(token: string) { const { canvasId, coordinates, color } = window.pixel; store.dispatch(requestPlacePixel(canvasId, coordinates, color, token)); - grecaptcha.reset(); + window.grecaptcha.reset(); } // https://stackoverflow.com/questions/41717304/recaptcha-google-data-callback-with-angularjs window.onCaptcha = onCaptcha; diff --git a/src/store/ads.js b/src/store/ads.js index 3b0032c..5dfe9b1 100644 --- a/src/store/ads.js +++ b/src/store/ads.js @@ -11,7 +11,7 @@ import { playAd } from '../ui/ads'; -export default (store) => (next) => (action) => { +export default () => (next) => (action) => { switch (action.type) { case 'PLACE_PIXEL': { // wait 1 second diff --git a/src/store/analytics.js b/src/store/analytics.js index adc3d70..03fe3f7 100644 --- a/src/store/analytics.js +++ b/src/store/analytics.js @@ -22,7 +22,7 @@ import track from './track'; -export default (store) => (next) => (action) => { +export default () => (next) => (action) => { track(action); return next(action); }; diff --git a/src/store/array.js b/src/store/array.js index 321e172..5c56ab1 100644 --- a/src/store/array.js +++ b/src/store/array.js @@ -20,6 +20,6 @@ * DEALINGS IN THE SOFTWARE */ -export default (store) => (next) => (action) => (Array.isArray(action) +export default () => (next) => (action) => (Array.isArray(action) ? action.map(next) : next(action)); diff --git a/src/store/configureStore.js b/src/store/configureStore.js index ede17d1..c2025e1 100644 --- a/src/store/configureStore.js +++ b/src/store/configureStore.js @@ -3,11 +3,13 @@ import { applyMiddleware, createStore, compose } from 'redux'; import thunk from 'redux-thunk'; import { createLogger } from 'redux-logger'; -import { persistStore, autoRehydrate } from 'redux-persist'; +import { persistStore } from 'redux-persist'; -import ads from './ads'; import audio from './audio'; -import analytics from './analytics'; +import swal from './sweetAlert'; +import protocolClientHook from './protocolClientHook'; +// import ads from './ads'; +// import analytics from './analytics'; import array from './array'; import promise from './promise'; import notifications from './notifications'; @@ -18,7 +20,7 @@ import reducers from '../reducers'; const isDebuggingInChrome = __DEV__ && !!window.navigator.userAgent; const logger = createLogger({ - predicate: (getState, action) => isDebuggingInChrome, + predicate: () => isDebuggingInChrome, collapsed: true, duration: true, }); @@ -31,11 +33,13 @@ const store = createStore( thunk, promise, array, - ads, + swal, audio, notifications, title, - analytics, + protocolClientHook, + // ads, + // analytics, logger, ), ), diff --git a/src/store/notifications.js b/src/store/notifications.js index c3818a1..4ad1296 100644 --- a/src/store/notifications.js +++ b/src/store/notifications.js @@ -5,7 +5,7 @@ */ -export default (store) => (next) => (action) => { +export default () => (next) => (action) => { try { switch (action.type) { case 'PLACE_PIXEL': { diff --git a/src/store/promise.js b/src/store/promise.js index bc6a363..d99e15f 100644 --- a/src/store/promise.js +++ b/src/store/promise.js @@ -25,6 +25,6 @@ function warn(error) { throw error; // To let the caller handle the rejection } -export default (store) => (next) => (action) => (typeof action.then === 'function' +export default () => (next) => (action) => (typeof action.then === 'function' ? Promise.resolve(action).then(next, warn) : next(action)); diff --git a/src/store/protocolClientHook.js b/src/store/protocolClientHook.js new file mode 100644 index 0000000..be53d4f --- /dev/null +++ b/src/store/protocolClientHook.js @@ -0,0 +1,51 @@ +/* + * Hooks for websocket client to store changes + * + * @flow + */ + +import ProtocolClient from '../socket/ProtocolClient'; + +export default (store) => (next) => (action) => { + switch (action.type) { + case 'RECEIVE_BIG_CHUNK': { + const [, cx, cy] = action.center; + ProtocolClient.registerChunk([cx, cy]); + break; + } + + case 'RECEIVE_ME': { + const { name } = action; + ProtocolClient.setName(name); + break; + } + + case 'SET_NAME': { + const { name } = action; + ProtocolClient.setName(name); + break; + } + + default: + // nothing + } + + const ret = next(action); + + // executed after reducers + switch (action.type) { + case 'RELOAD_URL': + case 'SELECT_CANVAS': + case 'RECEIVE_ME': { + const state = store.getState(); + const { canvasId } = state.canvas; + ProtocolClient.setCanvas(canvasId); + break; + } + + default: + // nothing + } + + return ret; +}; diff --git a/src/store/sweetAlert.js b/src/store/sweetAlert.js new file mode 100644 index 0000000..809da84 --- /dev/null +++ b/src/store/sweetAlert.js @@ -0,0 +1,31 @@ +/* + * @flow + */ + +import swal from 'sweetalert2'; +import 'sweetalert2/src/sweetalert2.scss'; + +export default () => (next) => (action) => { + switch (action.type) { + case 'ALERT': { + const { + title, + text, + icon, + confirmButtonText, + } = action; + swal.fire({ + title, + text, + icon, + confirmButtonText, + }); + break; + } + + default: + // nothing + } + + return next(action); +}; diff --git a/src/store/track.js b/src/store/track.js index 010cd73..07d96b6 100644 --- a/src/store/track.js +++ b/src/store/track.js @@ -26,12 +26,12 @@ import type { Action } from '../actions/types'; export default function track(action: Action): void { - if (typeof ga === 'undefined') return; + if (typeof window.ga === 'undefined') return; switch (action.type) { case 'PLACE_PIXEL': { const [x, y] = action.coordinates; - ga('send', { + window.ga('send', { hitType: 'event', eventCategory: 'Place', eventAction: action.color,