refactor services and reducers to parse JSON before data hits dispatch

This commit is contained in:
Sorrel Bri 2020-01-22 15:16:43 -08:00 committed by sorrelbri
parent 16adb58cb0
commit 95e54df9fd
16 changed files with 153 additions and 49 deletions

View file

@ -39,6 +39,7 @@ function App() {
}, []) }, [])
const socketConnect = () => { const socketConnect = () => {
socket.removeAllListeners();
socket.emit('connect'); socket.emit('connect');
socket.on('connected', data => setSocketData('socket connected')); socket.on('connected', data => setSocketData('socket connected'));
socket.on('connect_error', err => setError([...error, err])); socket.on('connect_error', err => setError([...error, err]));

View file

@ -36,9 +36,8 @@ const Login = (props) => {
username, username,
password password
}) })
const parsedResponse = JSON.parse(loginResponse); if (loginResponse.errors) {
if (parsedResponse.errors) { const authError = loginResponse.errors
const authError = parsedResponse.errors
return props.dispatch({ return props.dispatch({
...errorDispatchAction, ...errorDispatchAction,
body: { authError } body: { authError }
@ -48,7 +47,7 @@ const Login = (props) => {
return props.dispatch({ return props.dispatch({
type: 'AUTH', type: 'AUTH',
message: 'LOGIN', message: 'LOGIN',
body: parsedResponse body: loginResponse
}) })
} }

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { render } from '@testing-library/react'; import { render } from '@testing-library/react';
import Login from './Login'; import Login from './Login';
import { initState } from '../../reducers/init/stateReducer.init'; import { initState } from '../../../reducers/init/stateReducer.init';
test('renders Login without crashing', () => { test('renders Login without crashing', () => {
const state = initState(); const state = initState();

View file

@ -53,10 +53,9 @@ const Signup = (props) => {
password, password,
confirmPassword confirmPassword
}) })
const parsedResponse = JSON.parse(signupResponse)
if (parsedResponse.errors) { if (signupResponse.errors) {
const authError = parsedResponse.errors[0].auth const authError = signupResponse.errors[0].auth
return props.dispatch({ return props.dispatch({
...errorDispatchAction, ...errorDispatchAction,
body: { authError } body: { authError }
@ -66,7 +65,7 @@ const Signup = (props) => {
return props.dispatch({ return props.dispatch({
type: 'AUTH', type: 'AUTH',
message: 'SIGNUP', message: 'SIGNUP',
body: parsedResponse body: signupResponse
}) })
} }

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { render } from '@testing-library/react'; import { render } from '@testing-library/react';
import Signup from './Signup'; import Signup from './Signup';
import { initState } from '../../reducers/init/stateReducer.init'; import { initState } from '../../../reducers/init/stateReducer.init';
test('renders Signup without crashing', () => { test('renders Signup without crashing', () => {
const { getByTestId } = render(<Signup state={initState()}/>); const { getByTestId } = render(<Signup state={initState()}/>);

View file

@ -3,12 +3,30 @@ import { useParams } from 'react-router-dom';
import './Room.scss'; import './Room.scss';
import socketIOClient from 'socket.io-client'; import socketIOClient from 'socket.io-client';
import config from '../../config'; import config from '../../config';
import roomsServices from '../../services/api/roomsServices';
const Room = (props) => { const Room = (props) => {
const roomId = useParams().id; const roomId = parseInt(useParams().id) || 0;
const [ socketData, setSocketData ] = useState(); const [ socketData, setSocketData ] = useState();
const [ messages, setMessages ] = useState(); const [ messages, setMessages ] = useState();
const fetchRoomAPI = async () => {
const response = await roomsServices.getRoomService(roomId);
if (response) {
console.log(response);
// const action = {
// type: 'ROOMS',
// message: 'JOIN_ROOM',
// body: response
// }
// return dispatch(action);
}
}
useEffect(() => {
fetchRoomAPI();
}, [])
// ! [start] roomSocket // ! [start] roomSocket
const roomSocket = socketIOClient(`${config.socketAddress}/${roomId}`) const roomSocket = socketIOClient(`${config.socketAddress}/${roomId}`)
@ -23,6 +41,7 @@ const Room = (props) => {
useEffect(() => { useEffect(() => {
roomSocketConnect(); roomSocketConnect();
}, []) }, [])
// ! [end] // ! [end]
return ( return (

View file

@ -5,15 +5,10 @@ export const indexReducer = (state: state, action: action):state => {
switch(action.message) { switch(action.message) {
case 'SET_USER': case 'SET_USER':
const user = indexDataParse(action.body); const user = action.body;
return {...state, user}; return {...state, user};
default: default:
return state; return state;
} }
} }
function indexDataParse(indexData) {
const user = JSON.parse(indexData);
return user
}

View file

@ -0,0 +1,16 @@
// @flow
import type { state, action } from '../stateReducer';
import { stateReducer } from '../stateReducer';
export const messagesReducer = (state: state, action: action):state => {
switch(action.message) {
case 'SET_MESSAGES':
const rooms = parseData(action.body);
return {...state, rooms};
default:
return state;
}
}

View file

@ -0,0 +1,10 @@
import {stateReducer} from '../stateReducer';
import { initState } from '../init/stateReducer.init';
const messagesData = [];
it('default returns state unaltered', () => {
const state = initState();
const action = {type: 'MESSAGES', message: '', body: JSON.stringify(messagesData)};
expect(stateReducer(state, action)).toEqual(state);
})

View file

@ -1,19 +1,43 @@
// @flow // @flow
import type { state, action } from '../stateReducer'; import type { state, action } from '../stateReducer';
import { stateReducer } from '../stateReducer';
export const roomsReducer = (state: state, action: action):state => { export const roomsReducer = (state: state, action: action):state => {
switch(action.message) { switch(action.message) {
case 'SET_ROOMS': case 'SET_ROOMS':
const rooms = roomsParse(action.body); const rooms = action.body;
return {...state, rooms}; return {...state, rooms};
case 'JOIN_ROOM': {
// SET MESSAGES
const stateWithMessages = action.body.messages.length ? setMessages(state, action.body) : state;
// SET CURRENT ROOM
// if (!data.roomGames.length) {
// const errorAction = {
// type: 'ERR',
// message: 'JOIN_ROOM',
// body: { joinRoomError: 'Game room has no games' }
// }
// return stateReducer(stateWithMessages, errorAction);
// }
// SET GAMES
}
default: default:
return state; return state;
} }
} }
function roomsParse(roomsData) { function setMessages(state, data) {
const rooms = JSON.parse(roomsData); const messageAction = {
return rooms.rooms type: 'MESSAGE',
message: 'SET_MESSAGES',
body: data.messages
}
stateReducer(state, messageAction)
} }

View file

@ -10,9 +10,45 @@ const roomsData = [
} }
] ]
it('default returns state with rooms added', () => { const joinRoomData = {
"roomGames": [
{
"id":1, "name":"main",
"description":"A general place to play Go",
"language":"EN", "komi":6.5, "handicap":0, "board_size":19,
"player_black":"anon", "player_white":"anon",
"player_black_rank":"K3", "player_white_rank":"K2"
}
],
"messages": [
{
"content": "Hey! Welcome to the general room!", "username": "userOne", "admin":true
}
]
}
it('default returns state unaltered', () => {
const state = initState(); const state = initState();
const action = {type: 'ROOMS', message: 'SET_ROOMS', body: JSON.stringify(roomsData)}; const action = {type: 'ROOMS', message: '', body: JSON.stringify(roomsData)};
expect(stateReducer(state, action)).toEqual(state);
})
it('set rooms returns state with rooms added', () => {
const state = initState();
const action = {type: 'ROOMS', message: 'SET_ROOMS', body: roomsData};
expect(stateReducer(state, action)).toEqual({...state, rooms: roomsData}); expect(stateReducer(state, action)).toEqual({...state, rooms: roomsData});
}); });
it('join room returns state with current room, games and messages all populated', () => {
const state = initState();
const action = {type: 'ROOMS', message: 'JOIN_ROOM', body: joinRoomData};
const normalizedRoomGames = joinRoomData.roomGames.map(game => {delete game.id; delete game.name; delete game.description; return game});
expect(stateReducer(state, action)).toEqual({
...state,
currentRoom: roomsData[0],
messages: joinRoomData.messages,
roomGames: [
joinRoomData.roomGames
]
})
});

View file

@ -13,7 +13,7 @@ export type state = {
export type action = { export type action = {
type: string, type: string,
message: ?string, message: ?string,
body: {} body: {},
} }
export const stateReducer = (state: state, action: action): state => { export const stateReducer = (state: state, action: action): state => {

View file

@ -2,7 +2,7 @@ import {stateReducer} from './stateReducer';
it('default returns state unaltered', () => { it('default returns state unaltered', () => {
const state = {data: 'example'}; const state = {data: 'example'};
const action = {type: ''}; const action = {type: '', message: '', body:{}};
expect(stateReducer(state, action)).toBe(state); expect(stateReducer(state, action)).toBe(state);
}); });

View file

@ -11,9 +11,9 @@ const indexService = async () => {
const response = await fetch(apiAddress, const response = await fetch(apiAddress,
{method: 'GET', credentials: 'include', headers: headers} {method: 'GET', credentials: 'include', headers: headers}
) )
.then(res => { .then(res => res.text())
return res.text(); .then(text => JSON.parse(text))
}).catch(err => { .catch(err => {
return err; return err;
}); });
return response; return response;

View file

@ -12,18 +12,25 @@ const indexService = async () => {
const response = await fetch(roomsAddress, const response = await fetch(roomsAddress,
{method: 'GET', credentials: 'include', headers: headers} {method: 'GET', credentials: 'include', headers: headers}
) )
.then(res => { .then(res => res.text())
return res.text(); .then(text => JSON.parse(text))
}) .catch(err => err);
// .then(text => {
// return JSON.parse(text) return response;
// }) }
.catch(err => {
return err; const getRoomService = async (roomIndex) => {
}); const response = await fetch(`${roomsAddress}/${roomIndex}`,
{method: 'GET', credentials: 'include', headers: headers}
)
.then(res => res.text())
.then(text => JSON.parse(text))
.catch(err => err);
return response; return response;
} }
export default { export default {
indexService indexService,
getRoomService
} }

View file

@ -16,11 +16,10 @@ const loginService = async(formData) => {
body: JSON.stringify(formData), body: JSON.stringify(formData),
headers: headers headers: headers
}) })
.then(res => { .then(res => res.text())
return res.text(); .then(text => JSON.parse(text))
}).catch(err => { .catch(err => err);
return err;
});
return response; return response;
} }
@ -31,11 +30,10 @@ const signupService = async (formData) => {
body: JSON.stringify(formData), body: JSON.stringify(formData),
headers: headers headers: headers
}) })
.then(res => { .then(res => res.text())
return res.text(); .then(text => JSON.parse(text))
}).catch(err => { .catch(err => err);
return err;
});
return response; return response;
} }