Add redux, fix routing, add normalize
This commit is contained in:
@@ -1,12 +1,8 @@
|
||||
# TODO
|
||||
|
||||
- [ ] Fix: Initial load `pointString` validation (make sure all talents are valid and their deps are met)
|
||||
- [ ] Fix: Navigating between talent links for same class does not trigger re-render
|
||||
- [ ] Fix: Tooltips cause horizontal scroll on less-wide screens. Investigate.
|
||||
|
||||
- [ ] Styling:
|
||||
- [ ] SCSS: Normalize
|
||||
- [ ] General:
|
||||
- [ ] Add redux
|
||||
- [ ] Responsiveness:
|
||||
- [ ] Tooltips on mobile need different UX
|
||||
- [ ] Talent tree:
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-loadable": "^5.5.0",
|
||||
"react-redux": "^7.1.0",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"react-scripts": "3.0.1",
|
||||
"redux": "^4.0.4",
|
||||
"typescript": "3.5.3"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -47,11 +49,13 @@
|
||||
"@types/cheerio": "^0.22.12",
|
||||
"@types/node-fetch": "^2.5.0",
|
||||
"@types/react-loadable": "^5.5.1",
|
||||
"@types/react-redux": "^7.1.1",
|
||||
"@types/request": "^2.48.2",
|
||||
"@welldone-software/why-did-you-render": "^3.2.1",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"gh-pages": "^2.0.1",
|
||||
"node-fetch": "^2.6.0",
|
||||
"redux-devtools": "^3.5.0",
|
||||
"request": "^2.88.0",
|
||||
"ts-node": "^8.3.0"
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import './App.scss'
|
||||
import React from 'react'
|
||||
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom'
|
||||
import Loadable from 'react-loadable'
|
||||
import { PageLoader } from './components/PageLoader'
|
||||
@@ -17,7 +17,6 @@ const LoadablePlayground = Loadable({
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<Router>
|
||||
{/* <Router basename={process.env.NODE_ENV !== 'development' ? '%PUBLIC_URL%' : ''}> */}
|
||||
<div className="App">
|
||||
<main>
|
||||
<Switch>
|
||||
|
||||
@@ -2,21 +2,18 @@ import './Calculator.scss'
|
||||
import React from 'react'
|
||||
import { Map } from 'immutable'
|
||||
import { TalentTree } from './TalentTree'
|
||||
import {
|
||||
modifyTalentPoint,
|
||||
calcAvailablePoints,
|
||||
encodeKnownTalents,
|
||||
} from '../lib/tree'
|
||||
import { talentsBySpec } from '../data/talents'
|
||||
import { classByName } from '../data/classes'
|
||||
import { History } from 'history'
|
||||
// import { debugPrintKnown } from '../lib/debug'
|
||||
import { calcAvailablePoints } from '../lib/tree'
|
||||
import { classById } from '../data/classes'
|
||||
import { Link } from 'react-router-dom';
|
||||
import { connect } from 'react-redux';
|
||||
import { addPoint, removePoint } from '../store/calculator/actions'
|
||||
import { Points } from '../store/calculator/types'
|
||||
|
||||
interface Props {
|
||||
selectedClass: string
|
||||
history: History
|
||||
initialTalents?: Map<number, number>
|
||||
classId: number
|
||||
points: Points
|
||||
addPoint: typeof addPoint
|
||||
removePoint: typeof removePoint
|
||||
}
|
||||
|
||||
const EMPTY_TALENTS = Map<number, number>()
|
||||
@@ -28,46 +25,19 @@ export class Calculator extends React.PureComponent<Props> {
|
||||
knownTalents: EMPTY_TALENTS
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.initialTalents) {
|
||||
this.setState({ knownTalents: this.props.initialTalents })
|
||||
this.updateURL(this.props.initialTalents)
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (prevProps.selectedClass !== this.props.selectedClass) {
|
||||
this.setState({
|
||||
knownTalents: EMPTY_TALENTS
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
updateURL(knownTalents: Map<number, number>) {
|
||||
const { selectedClass } = this.props
|
||||
const pointString = encodeKnownTalents(knownTalents, selectedClass)
|
||||
this.props.history.replace(`/${selectedClass}` + (pointString ? `/${pointString}` : ''))
|
||||
}
|
||||
|
||||
handleTalentPress = (specId: number, talentId: number, modifier: 1 | -1) => {
|
||||
const talent = talentsBySpec[specId][talentId]
|
||||
console.log('Clicked talent: ', talentId)
|
||||
|
||||
const newKnownTalents = modifyTalentPoint(this.state.knownTalents, talent, modifier)
|
||||
if (newKnownTalents !== this.state.knownTalents) {
|
||||
this.updateURL(newKnownTalents)
|
||||
if (modifier === 1) {
|
||||
this.props.addPoint(talentId)
|
||||
} else {
|
||||
this.props.removePoint(talentId)
|
||||
}
|
||||
this.setState({ knownTalents: newKnownTalents })
|
||||
|
||||
// Debug
|
||||
// debugPrintKnown(newKnownTalents)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { selectedClass } = this.props
|
||||
const { knownTalents } = this.state
|
||||
const { classId } = this.props
|
||||
const knownTalents = this.props.points
|
||||
|
||||
const classData = classByName[selectedClass]
|
||||
const classData = classById[classId]
|
||||
const availablePoints = calcAvailablePoints(knownTalents)
|
||||
|
||||
return (
|
||||
@@ -99,3 +69,10 @@ export class Calculator extends React.PureComponent<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
{
|
||||
addPoint,
|
||||
removePoint
|
||||
}
|
||||
)(Calculator)
|
||||
+80
-16
@@ -1,33 +1,90 @@
|
||||
import React from 'react'
|
||||
import { Calculator } from '../components/Calculator'
|
||||
import { ClassPicker } from '../components/ClassPicker'
|
||||
import { connect } from 'react-redux'
|
||||
import { match } from 'react-router-dom'
|
||||
import { RouteComponentProps } from 'react-router'
|
||||
import { decodeKnownTalents } from '../lib/tree'
|
||||
import { classByName } from '../data/classes'
|
||||
import Calculator from '../components/Calculator'
|
||||
import { ClassPicker } from '../components/ClassPicker'
|
||||
import { classByName, classById } from '../data/classes'
|
||||
import { AppState } from '../store'
|
||||
import { setClass, setPoints } from '../store/calculator/actions'
|
||||
import { Points } from '../store/calculator/types'
|
||||
import { decodeKnownTalents, encodeKnownTalents } from '../lib/tree'
|
||||
|
||||
interface Props extends RouteComponentProps {
|
||||
match: match<{
|
||||
selectedClass: string
|
||||
pointString: string
|
||||
}>
|
||||
classId: number
|
||||
points: Points
|
||||
setClass: typeof setClass
|
||||
setPoints: typeof setPoints
|
||||
}
|
||||
|
||||
export default class Home extends React.PureComponent<Props> {
|
||||
export class Home extends React.PureComponent<Props> {
|
||||
static whyDidYouRender = true
|
||||
|
||||
get classSlug() {
|
||||
return classById[this.props.classId] && classById[this.props.classId].name.toLowerCase()
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { selectedClass } = this.props.match.params
|
||||
if (selectedClass && !classByName[selectedClass]) {
|
||||
this.loadFromUrlParams()
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
const prevParams = prevProps.match.params
|
||||
const { params } = this.props.match
|
||||
|
||||
if (prevParams.selectedClass !== params.selectedClass) {
|
||||
// Class changed in route
|
||||
this.loadFromUrlParams()
|
||||
} else {
|
||||
// Changes within same class
|
||||
if (prevParams.pointString !== params.pointString) {
|
||||
// Same class but point string changed
|
||||
const decoded = decodeKnownTalents(params.pointString || '', this.props.classId)
|
||||
if (!this.props.points.equals(decoded)) {
|
||||
this.props.setPoints(decoded)
|
||||
}
|
||||
} else if (prevProps.points !== this.props.points) {
|
||||
// Points map changed, update the URL
|
||||
this.updateURL(this.props.points)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.setClass(null)
|
||||
}
|
||||
|
||||
loadFromUrlParams() {
|
||||
const { selectedClass, pointString } = this.props.match.params
|
||||
const c = selectedClass && classByName[selectedClass]
|
||||
if (c) {
|
||||
const points = pointString && decodeKnownTalents(pointString || '', c.id)
|
||||
this.props.setClass(c.id, points)
|
||||
} else {
|
||||
this.props.setClass(null)
|
||||
this.props.history.replace('/')
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { match, history } = this.props
|
||||
const { selectedClass, pointString } = match.params
|
||||
updateURL(points: Points) {
|
||||
const { classId } = this.props
|
||||
const pointsString = encodeKnownTalents(points, classId)
|
||||
if (pointsString !== this.props.match.params.pointString) {
|
||||
this.props.history.replace(`/${this.classSlug}` + (pointsString ? `/${pointsString}` : ''))
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedClass && !classByName[selectedClass]) {
|
||||
render() {
|
||||
const { match, classId } = this.props
|
||||
const { selectedClass } = match.params
|
||||
|
||||
const currentClass = classById[classId]
|
||||
if (classId && !currentClass) {
|
||||
// We're redirecting to /
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -39,14 +96,21 @@ export default class Home extends React.PureComponent<Props> {
|
||||
selected={selectedClass}
|
||||
/>
|
||||
|
||||
{selectedClass &&
|
||||
{currentClass &&
|
||||
<Calculator
|
||||
initialTalents={pointString && decodeKnownTalents(pointString, selectedClass)}
|
||||
selectedClass={selectedClass}
|
||||
history={history}
|
||||
classId={classId}
|
||||
points={this.props.points}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
({ calculator }: AppState) => ({
|
||||
classId: calculator.classId,
|
||||
points: calculator.points,
|
||||
}),
|
||||
{ setClass, setPoints }
|
||||
)(Home)
|
||||
+12
-2
@@ -3,12 +3,22 @@ import ReactDOM from 'react-dom'
|
||||
import App from './App'
|
||||
import * as serviceWorker from './serviceWorker'
|
||||
|
||||
import { Provider } from 'react-redux'
|
||||
import store from './store'
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const whyDidYouRender = require('@welldone-software/why-did-you-render/dist/no-classes-transpile/umd/whyDidYouRender.min.js')
|
||||
whyDidYouRender(React)
|
||||
whyDidYouRender(React, {
|
||||
include: [/^ConnectFunction$/]
|
||||
})
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'))
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>,
|
||||
document.getElementById('root')
|
||||
)
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
|
||||
+5
-5
@@ -5,7 +5,7 @@ import {
|
||||
talentsBySpecArray,
|
||||
talentsById
|
||||
} from '../data/talents';
|
||||
import { classByName } from '../data/classes'
|
||||
import { classById } from '../data/classes'
|
||||
import spells from '../data/spells.json'
|
||||
|
||||
export const MAX_POINTS = 51
|
||||
@@ -204,9 +204,9 @@ export const modifyTalentPoint = (known: Map<number, number>, talent: TalentData
|
||||
/**
|
||||
* Encodes a Map of known talents into a URL-friendly string.
|
||||
*/
|
||||
export function encodeKnownTalents(known: Map<number, number>, className: string): string {
|
||||
export function encodeKnownTalents(known: Map<number, number>, classId: number): string {
|
||||
let string = ''
|
||||
const { specs } = classByName[className]
|
||||
const { specs } = classById[classId]
|
||||
for (let i = 0; i < specs.length; i++) {
|
||||
const specId = specs[i]
|
||||
const talents = talentsBySpecArray[specId].sort(SORT_TALENTS)
|
||||
@@ -222,8 +222,8 @@ export function encodeKnownTalents(known: Map<number, number>, className: string
|
||||
/**
|
||||
* Decodes a string of points into a Map of talents.
|
||||
*/
|
||||
export function decodeKnownTalents(pointString: string, className: string): Map<number, number> {
|
||||
const { specs } = classByName[className]
|
||||
export function decodeKnownTalents(pointString: string, classId: number): Map<number, number> {
|
||||
const { specs } = classById[classId]
|
||||
let known = Map<number, number>()
|
||||
|
||||
// TODO: Make sure we validate the point string
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import {
|
||||
CalculatorActionTypes,
|
||||
SET_CLASS,
|
||||
ADD_POINT,
|
||||
REMOVE_POINT,
|
||||
SET_POINTS,
|
||||
Points,
|
||||
} from './types'
|
||||
|
||||
export const setClass = (classId: number, points?: Points): CalculatorActionTypes => ({
|
||||
type: SET_CLASS,
|
||||
classId,
|
||||
points
|
||||
})
|
||||
|
||||
export const addPoint = (talentId: number): CalculatorActionTypes => ({
|
||||
type: ADD_POINT,
|
||||
talentId
|
||||
})
|
||||
|
||||
export const removePoint = (talentId: number): CalculatorActionTypes => ({
|
||||
type: REMOVE_POINT,
|
||||
talentId
|
||||
})
|
||||
|
||||
export const setPoints = (points: Points): CalculatorActionTypes => ({
|
||||
type: SET_POINTS,
|
||||
points
|
||||
})
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Map } from 'immutable'
|
||||
import {
|
||||
CalculatorState,
|
||||
CalculatorActionTypes,
|
||||
SET_CLASS,
|
||||
ADD_POINT,
|
||||
REMOVE_POINT,
|
||||
SET_POINTS
|
||||
} from './types'
|
||||
import { canLearnTalent, canUnlearnTalent, encodeKnownTalents } from '../../lib/tree'
|
||||
import { talentsById } from '../../data/talents'
|
||||
|
||||
const initialState: CalculatorState = {
|
||||
classId: null,
|
||||
points: Map<number, number>(),
|
||||
pointsEncoded: ''
|
||||
}
|
||||
|
||||
export default function(state = initialState, action: CalculatorActionTypes): CalculatorState {
|
||||
const { classId, points } = state
|
||||
|
||||
switch (action.type) {
|
||||
case SET_CLASS: {
|
||||
if (classId === action.classId) {
|
||||
return state
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
classId: action.classId,
|
||||
points: action.points || Map(),
|
||||
pointsEncoded: ''
|
||||
}
|
||||
}
|
||||
|
||||
case ADD_POINT: {
|
||||
const { talentId } = action
|
||||
const talent = talentsById[talentId]
|
||||
if (!canLearnTalent(points, talent)) {
|
||||
return state
|
||||
}
|
||||
const nextPoints = points.set(talentId, points.get(talentId, 0) + 1)
|
||||
return {
|
||||
...state,
|
||||
points: nextPoints,
|
||||
pointsEncoded: encodeKnownTalents(nextPoints, classId)
|
||||
}
|
||||
}
|
||||
|
||||
case REMOVE_POINT: {
|
||||
const { talentId } = action
|
||||
const talent = talentsById[talentId]
|
||||
if (!canUnlearnTalent(points, talent)) {
|
||||
return state
|
||||
}
|
||||
const nextPoints = points.set(talentId, points.get(talentId, 1) - 1)
|
||||
return {
|
||||
...state,
|
||||
points: nextPoints,
|
||||
pointsEncoded: encodeKnownTalents(nextPoints, classId)
|
||||
}
|
||||
}
|
||||
|
||||
case SET_POINTS: {
|
||||
if (points.equals(action.points)) {
|
||||
return state
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
points: action.points
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Map } from 'immutable'
|
||||
|
||||
export type Points = Map<number, number>
|
||||
|
||||
export interface CalculatorState {
|
||||
classId: number
|
||||
points: Points
|
||||
pointsEncoded: string
|
||||
}
|
||||
|
||||
export const SET_CLASS = 'SET_CLASS'
|
||||
export const ADD_POINT = 'ADD_POINT'
|
||||
export const REMOVE_POINT = 'REMOVE_POINT'
|
||||
export const SET_POINTS = 'SET_POINTS'
|
||||
|
||||
interface SetClassAction {
|
||||
type: typeof SET_CLASS
|
||||
classId: number
|
||||
points?: Points
|
||||
}
|
||||
|
||||
interface AddPointAction {
|
||||
type: typeof ADD_POINT
|
||||
talentId: number
|
||||
}
|
||||
|
||||
interface RemovePointAction {
|
||||
type: typeof REMOVE_POINT
|
||||
talentId: number
|
||||
}
|
||||
|
||||
interface SetPointsAction {
|
||||
type: typeof SET_POINTS
|
||||
points: Points
|
||||
}
|
||||
|
||||
export type CalculatorActionTypes = SetClassAction | AddPointAction | RemovePointAction |
|
||||
SetPointsAction
|
||||
@@ -0,0 +1,17 @@
|
||||
import { createStore, combineReducers, compose } from 'redux'
|
||||
import calculator from './calculator/reducers'
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
calculator,
|
||||
})
|
||||
|
||||
export type AppState = ReturnType<typeof rootReducer>
|
||||
|
||||
const store = createStore(
|
||||
rootReducer,
|
||||
compose(
|
||||
(window as any).__REDUX_DEVTOOLS_EXTENSION__ && (window as any).__REDUX_DEVTOOLS_EXTENSION__()
|
||||
),
|
||||
)
|
||||
|
||||
export default store
|
||||
Vendored
+2
-1
@@ -51,4 +51,5 @@ interface Talent {
|
||||
|
||||
type TalentClickHandler = (specId: number, talentId: number, modifier: 1 | -1) => void
|
||||
|
||||
type TooltipPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'left' | 'right'
|
||||
type TooltipPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'left' | 'right'
|
||||
|
||||
|
||||
@@ -881,7 +881,7 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.2"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5":
|
||||
version "7.5.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
|
||||
integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==
|
||||
@@ -1293,6 +1293,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.2.tgz#0e670ea254d559241b6eeb3894f8754991e73220"
|
||||
integrity sha512-ui3WwXmjTaY73fOQ3/m3nnajU/Orhi6cEu5rzX+BrAAJxa3eITXZ5ch9suPqtM03OWhAHhPSyBGCN4UKoxO20Q==
|
||||
|
||||
"@types/hoist-non-react-statics@^3.3.0":
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
|
||||
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
|
||||
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
|
||||
@@ -1367,6 +1375,16 @@
|
||||
"@types/react" "*"
|
||||
"@types/webpack" "*"
|
||||
|
||||
"@types/react-redux@^7.1.1":
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.1.tgz#eb01e89cf71cad77df9f442b819d5db692b997cb"
|
||||
integrity sha512-owqNahzE8en/jR4NtrUJDJya3tKru7CIEGSRL/pVS84LtSCdSoT7qZTkrbBd3S4Lp11sAp+7LsvxIeONJVKMnw==
|
||||
dependencies:
|
||||
"@types/hoist-non-react-statics" "^3.3.0"
|
||||
"@types/react" "*"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
redux "^4.0.0"
|
||||
|
||||
"@types/react-router-dom@^4.3.4":
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.3.4.tgz#63a7a8558129d2f4ff76e4bdd099bf4b98e25a0d"
|
||||
@@ -4745,7 +4763,7 @@ hmac-drbg@^1.0.0:
|
||||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.1"
|
||||
|
||||
hoist-non-react-statics@^3.1.0:
|
||||
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
|
||||
integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==
|
||||
@@ -6273,7 +6291,7 @@ lodash.uniq@^4.5.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||
|
||||
"lodash@>=3.5 <5", lodash@^4, lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.5, lodash@~4.17.10:
|
||||
"lodash@>=3.5 <5", lodash@^4, lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.5, lodash@^4.2.0, lodash@~4.17.10:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
@@ -8216,7 +8234,7 @@ prompts@^2.0.1:
|
||||
kleur "^3.0.2"
|
||||
sisteransi "^1.0.0"
|
||||
|
||||
prop-types@^15.5.0, prop-types@^15.6.2:
|
||||
prop-types@^15.5.0, prop-types@^15.5.7, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
@@ -8443,7 +8461,7 @@ react-error-overlay@^5.1.6:
|
||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-5.1.6.tgz#0cd73407c5d141f9638ae1e0c63e7b2bf7e9929d"
|
||||
integrity sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q==
|
||||
|
||||
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4:
|
||||
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
|
||||
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
|
||||
@@ -8455,6 +8473,18 @@ react-loadable@^5.5.0:
|
||||
dependencies:
|
||||
prop-types "^15.5.0"
|
||||
|
||||
react-redux@^7.1.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.1.0.tgz#72af7cf490a74acdc516ea9c1dd80e25af9ea0b2"
|
||||
integrity sha512-hyu/PoFK3vZgdLTg9ozbt7WF3GgX5+Yn3pZm5/96/o4UueXA+zj08aiSC9Mfj2WtD1bvpIb3C5yvskzZySzzaw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.5"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
invariant "^2.2.4"
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.7.2"
|
||||
react-is "^16.8.6"
|
||||
|
||||
react-router-dom@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.0.1.tgz#ee66f4a5d18b6089c361958e443489d6bab714be"
|
||||
@@ -8658,6 +8688,31 @@ redent@^1.0.0:
|
||||
indent-string "^2.1.0"
|
||||
strip-indent "^1.0.1"
|
||||
|
||||
redux-devtools-instrument@^1.9.0:
|
||||
version "1.9.6"
|
||||
resolved "https://registry.yarnpkg.com/redux-devtools-instrument/-/redux-devtools-instrument-1.9.6.tgz#6b412595f74b9d48cfd4ecc13e585b1588ed6e7e"
|
||||
integrity sha512-MwvY4cLEB2tIfWWBzrUR02UM9qRG2i7daNzywRvabOSVdvAY7s9BxSwMmVRH1Y/7QWjplNtOwgT0apKhHg2Qew==
|
||||
dependencies:
|
||||
lodash "^4.2.0"
|
||||
symbol-observable "^1.0.2"
|
||||
|
||||
redux-devtools@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-devtools/-/redux-devtools-3.5.0.tgz#d69ab76d4f0f8abdf6d24bcf5954d7a1aa2b6827"
|
||||
integrity sha512-pGU8TZNvWxPaCCE432AGm6H6alQbAz80gQM5CzM3SjX9/oSNu/HPF17xFdPQJOXasqyih1Gv167kZDTRe7r0iQ==
|
||||
dependencies:
|
||||
lodash "^4.2.0"
|
||||
prop-types "^15.5.7"
|
||||
redux-devtools-instrument "^1.9.0"
|
||||
|
||||
redux@^4.0.0, redux@^4.0.4:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.4.tgz#4ee1aeb164b63d6a1bcc57ae4aa0b6e6fa7a3796"
|
||||
integrity sha512-vKv4WdiJxOWKxK0yRoaK3Y4pxxB0ilzVx6dszU2W8wLxlb2yikRph4iV/ymtdJ6ZxpBLFbyrxklnT5yBbQSl3Q==
|
||||
dependencies:
|
||||
loose-envify "^1.4.0"
|
||||
symbol-observable "^1.2.0"
|
||||
|
||||
regenerate-unicode-properties@^8.0.2:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
|
||||
@@ -9694,6 +9749,11 @@ svgo@^1.0.0, svgo@^1.2.2:
|
||||
unquote "~1.1.1"
|
||||
util.promisify "~1.0.0"
|
||||
|
||||
symbol-observable@^1.0.2, symbol-observable@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
|
||||
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
|
||||
|
||||
symbol-tree@^3.2.2:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
||||
|
||||
Reference in New Issue
Block a user