store / reducers fixes, move websocketClient to reducers

This commit is contained in:
HF 2020-01-08 15:58:21 +01:00
parent 337fbf2462
commit e7a16fa3b9
12 changed files with 148 additions and 41 deletions

View File

@ -1,8 +1,5 @@
/* @flow */ /* @flow */
import swal from 'sweetalert2';
import 'sweetalert2/src/sweetalert2.scss';
import type { import type {
Action, Action,
ThunkAction, ThunkAction,
@ -11,13 +8,27 @@ import type {
import type { Cell } from '../core/Cell'; import type { Cell } from '../core/Cell';
import type { ColorIndex } from '../core/Palette'; import type { ColorIndex } from '../core/Palette';
import ProtocolClient from '../socket/ProtocolClient';
import { loadImage } from '../ui/loadImage'; import { loadImage } from '../ui/loadImage';
import { import {
getColorIndexOfPixel, getColorIndexOfPixel,
} from '../core/utils'; } 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 { export function toggleChatBox(): Action {
return { return {
type: 'TOGGLE_CHAT_BOX', type: 'TOGGLE_CHAT_BOX',
@ -255,12 +266,12 @@ export function requestPlacePixel(
} }
dispatch(pixelFailure()); dispatch(pixelFailure());
swal.fire({ dispatch(sweetAlert(
title: (errorTitle || `Error ${response.status}`), (errorTitle || `Error ${response.status}`),
text: errors[0].msg, errors[0].msg,
icon: 'error', 'error',
confirmButtonText: 'OK', 'OK',
}); ));
} finally { } finally {
dispatch(setPlaceAllowed(true)); dispatch(setPlaceAllowed(true));
} }
@ -418,7 +429,6 @@ export function fetchChunk(canvasId, center: Cell): PromiseAction {
return async (dispatch) => { return async (dispatch) => {
dispatch(requestBigChunk(center)); dispatch(requestBigChunk(center));
try { try {
ProtocolClient.registerChunk([cx, cy]);
const url = `/chunks/${canvasId}/${cx}/${cy}.bmp`; const url = `/chunks/${canvasId}/${cx}/${cy}.bmp`;
const response = await fetch(url); const response = await fetch(url);
if (response.ok) { if (response.ok) {
@ -475,7 +485,6 @@ export function receiveMe(
minecraftname, minecraftname,
canvases, canvases,
} = me; } = me;
ProtocolClient.setName(name);
return { return {
type: 'RECEIVE_ME', type: 'RECEIVE_ME',
name: (name) || null, name: (name) || null,
@ -504,7 +513,6 @@ export function receiveStats(
export function setName( export function setName(
name: string, name: string,
): Action { ): Action {
ProtocolClient.setName(name);
return { return {
type: 'SET_NAME', type: 'SET_NAME',
name, name,
@ -557,9 +565,7 @@ export function fetchMe(): PromiseAction {
if (response.ok) { if (response.ok) {
const me = await response.json(); const me = await response.json();
await dispatch(receiveMe(me)); dispatch(receiveMe(me));
const state = getState();
ProtocolClient.setCanvas(state.canvas.canvasId);
} }
}; };
} }
@ -660,18 +666,14 @@ export function onViewFinishChange(): Action {
} }
export function urlChange(): PromiseAction { export function urlChange(): PromiseAction {
return async (dispatch, getState) => { return (dispatch, getState) => {
await dispatch(reloadUrl()); dispatch(reloadUrl());
const state = getState();
ProtocolClient.setCanvas(state.canvas.canvasId);
}; };
} }
export function switchCanvas(canvasId: number): PromiseAction { export function switchCanvas(canvasId: number): PromiseAction {
return async (dispatch, getState) => { return async (dispatch, getState) => {
await dispatch(selectCanvas(canvasId)); await dispatch(selectCanvas(canvasId));
const state = getState();
ProtocolClient.setCanvas(state.canvas.canvasId);
dispatch(onViewFinishChange()); dispatch(onViewFinishChange());
}; };
} }

View File

@ -8,6 +8,12 @@ import type { State } from '../reducers';
export type Action = export type Action =
{ type: 'LOGGED_OUT' } { type: 'LOGGED_OUT' }
// my actions // my actions
| { type: 'ALERT',
title: string,
text: string,
icon: string,
confirmButtonText: string,
}
| { type: 'TOGGLE_GRID' } | { type: 'TOGGLE_GRID' }
| { type: 'TOGGLE_PIXEL_NOTIFY' } | { type: 'TOGGLE_PIXEL_NOTIFY' }
| { type: 'TOGGLE_AUTO_ZOOM_IN' } | { type: 'TOGGLE_AUTO_ZOOM_IN' }
@ -38,13 +44,27 @@ export type Action =
| { type: 'RECEIVE_IMAGE_TILE', center: Cell, tile: Image } | { type: 'RECEIVE_IMAGE_TILE', center: Cell, tile: Image }
| { type: 'RECEIVE_BIG_CHUNK_FAILURE', center: Cell, error: Error } | { type: 'RECEIVE_BIG_CHUNK_FAILURE', center: Cell, error: Error }
| { type: 'RECEIVE_COOLDOWN', waitSeconds: number } | { 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_ONLINE', online: number }
| { type: 'RECEIVE_CHAT_MESSAGE', name: string, text: string } | { type: 'RECEIVE_CHAT_MESSAGE', name: string, text: string }
| { type: 'RECEIVE_CHAT_HISTORY', data: Array } | { type: 'RECEIVE_CHAT_HISTORY', data: Array }
| { type: 'RECEIVE_ME', name: string, waitSeconds: number, messages: Array, | { type: 'RECEIVE_ME',
mailreg: boolean, totalPixels: number, dailyTotalPixels: number, name: string,
ranking: number, dailyRanking: number, minecraftname: string, canvases: Object} 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: 'RECEIVE_STATS', totalRanking: Object, totalDailyRanking: Object }
| { type: 'SET_NAME', name: string } | { type: 'SET_NAME', name: string }
| { type: 'SET_MINECRAFT_NAME', minecraftname: string } | { type: 'SET_MINECRAFT_NAME', minecraftname: string }

View File

@ -7,7 +7,6 @@
import React from 'react'; import React from 'react';
import type { State } from '../reducers';
import store from '../ui/store'; import store from '../ui/store';
import { requestPlacePixel } from '../actions'; import { requestPlacePixel } from '../actions';
@ -18,7 +17,7 @@ function onCaptcha(token: string) {
const { canvasId, coordinates, color } = window.pixel; const { canvasId, coordinates, color } = window.pixel;
store.dispatch(requestPlacePixel(canvasId, coordinates, color, token)); store.dispatch(requestPlacePixel(canvasId, coordinates, color, token));
grecaptcha.reset(); window.grecaptcha.reset();
} }
// https://stackoverflow.com/questions/41717304/recaptcha-google-data-callback-with-angularjs // https://stackoverflow.com/questions/41717304/recaptcha-google-data-callback-with-angularjs
window.onCaptcha = onCaptcha; window.onCaptcha = onCaptcha;

View File

@ -11,7 +11,7 @@
import { playAd } from '../ui/ads'; import { playAd } from '../ui/ads';
export default (store) => (next) => (action) => { export default () => (next) => (action) => {
switch (action.type) { switch (action.type) {
case 'PLACE_PIXEL': { case 'PLACE_PIXEL': {
// wait 1 second // wait 1 second

View File

@ -22,7 +22,7 @@
import track from './track'; import track from './track';
export default (store) => (next) => (action) => { export default () => (next) => (action) => {
track(action); track(action);
return next(action); return next(action);
}; };

View File

@ -20,6 +20,6 @@
* DEALINGS IN THE SOFTWARE * DEALINGS IN THE SOFTWARE
*/ */
export default (store) => (next) => (action) => (Array.isArray(action) export default () => (next) => (action) => (Array.isArray(action)
? action.map(next) ? action.map(next)
: next(action)); : next(action));

View File

@ -3,11 +3,13 @@
import { applyMiddleware, createStore, compose } from 'redux'; import { applyMiddleware, createStore, compose } from 'redux';
import thunk from 'redux-thunk'; import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger'; 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 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 array from './array';
import promise from './promise'; import promise from './promise';
import notifications from './notifications'; import notifications from './notifications';
@ -18,7 +20,7 @@ import reducers from '../reducers';
const isDebuggingInChrome = __DEV__ && !!window.navigator.userAgent; const isDebuggingInChrome = __DEV__ && !!window.navigator.userAgent;
const logger = createLogger({ const logger = createLogger({
predicate: (getState, action) => isDebuggingInChrome, predicate: () => isDebuggingInChrome,
collapsed: true, collapsed: true,
duration: true, duration: true,
}); });
@ -31,11 +33,13 @@ const store = createStore(
thunk, thunk,
promise, promise,
array, array,
ads, swal,
audio, audio,
notifications, notifications,
title, title,
analytics, protocolClientHook,
// ads,
// analytics,
logger, logger,
), ),
), ),

View File

@ -5,7 +5,7 @@
*/ */
export default (store) => (next) => (action) => { export default () => (next) => (action) => {
try { try {
switch (action.type) { switch (action.type) {
case 'PLACE_PIXEL': { case 'PLACE_PIXEL': {

View File

@ -25,6 +25,6 @@ function warn(error) {
throw error; // To let the caller handle the rejection 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) ? Promise.resolve(action).then(next, warn)
: next(action)); : next(action));

View File

@ -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;
};

31
src/store/sweetAlert.js Normal file
View File

@ -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);
};

View File

@ -26,12 +26,12 @@ import type { Action } from '../actions/types';
export default function track(action: Action): void { export default function track(action: Action): void {
if (typeof ga === 'undefined') return; if (typeof window.ga === 'undefined') return;
switch (action.type) { switch (action.type) {
case 'PLACE_PIXEL': { case 'PLACE_PIXEL': {
const [x, y] = action.coordinates; const [x, y] = action.coordinates;
ga('send', { window.ga('send', {
hitType: 'event', hitType: 'event',
eventCategory: 'Place', eventCategory: 'Place',
eventAction: action.color, eventAction: action.color,