init redux
This commit is contained in:
parent
05b5843c08
commit
2d2ed497ca
46
package-lock.json
generated
46
package-lock.json
generated
@ -24,7 +24,9 @@
|
|||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.53.1",
|
"react-hook-form": "^7.53.1",
|
||||||
"react-icons": "^5.3.0",
|
"react-icons": "^5.3.0",
|
||||||
|
"react-redux": "^9.2.0",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
|
"redux": "^5.0.1",
|
||||||
"typescript-eslint": "^8.6.0"
|
"typescript-eslint": "^8.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2566,6 +2568,12 @@
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/use-sync-external-store": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.6.0",
|
"version": "8.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz",
|
||||||
@ -8392,6 +8400,29 @@
|
|||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/react-redux": {
|
||||||
|
"version": "9.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
||||||
|
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/use-sync-external-store": "^0.0.6",
|
||||||
|
"use-sync-external-store": "^1.4.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^18.2.25 || ^19",
|
||||||
|
"react": "^18.0 || ^19",
|
||||||
|
"redux": "^5.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"redux": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-remove-scroll": {
|
"node_modules/react-remove-scroll": {
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz",
|
||||||
@ -8564,6 +8595,12 @@
|
|||||||
"recursive-watch": "bin.js"
|
"recursive-watch": "bin.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/redux": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/reflect.getprototypeof": {
|
"node_modules/reflect.getprototypeof": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
|
||||||
@ -9976,6 +10013,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/use-sync-external-store": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/util-deprecate": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
@ -31,7 +31,9 @@
|
|||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.53.1",
|
"react-hook-form": "^7.53.1",
|
||||||
"react-icons": "^5.3.0",
|
"react-icons": "^5.3.0",
|
||||||
|
"react-redux": "^9.2.0",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
|
"redux": "^5.0.1",
|
||||||
"typescript-eslint": "^8.6.0"
|
"typescript-eslint": "^8.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
src/__data__/actions/stars.ts
Normal file
23
src/__data__/actions/stars.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import * as types from '../const'
|
||||||
|
|
||||||
|
export const setStars = (userId: string, value: number) => ({
|
||||||
|
type: types.SET_STARS,
|
||||||
|
payload: {
|
||||||
|
id: userId,
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const incrementStart = (userId: string) => ({
|
||||||
|
type: types.INCREMENT_STARS,
|
||||||
|
payload: {
|
||||||
|
id: userId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const decrementStart = (userId: string) => ({
|
||||||
|
type: types.INCREMENT_STARS,
|
||||||
|
payload: {
|
||||||
|
id: userId
|
||||||
|
}
|
||||||
|
})
|
3
src/__data__/const.ts
Normal file
3
src/__data__/const.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const SET_STARS = 'SET_STARS'
|
||||||
|
export const INCREMENT_STARS = 'INCREMENT_STARS'
|
||||||
|
export const DECREMENT_STARS = 'DECREMENT_STARS'
|
38
src/__data__/reducers/stars.ts
Normal file
38
src/__data__/reducers/stars.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import * as types from '../const'
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
friends: {} as Record<string, number>,
|
||||||
|
user: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const starsReducer = (state = initialState, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case types.SET_STARS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
friends: {
|
||||||
|
...state.friends,
|
||||||
|
[action.payload.id]: action.payload.value,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case types.INCREMENT_STARS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
friends: {
|
||||||
|
...state.friends,
|
||||||
|
[action.payload.id]: state[action.payload.id] + 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.DECREMENT_STARS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
friends: {
|
||||||
|
...state.friends,
|
||||||
|
[action.payload.id]: state[action.payload.id] - 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
default: return state
|
||||||
|
}
|
||||||
|
}
|
12
src/__data__/store.ts
Normal file
12
src/__data__/store.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { combineReducers, legacy_createStore } from 'redux'
|
||||||
|
|
||||||
|
import { starsReducer } from './reducers/stars'
|
||||||
|
|
||||||
|
export const store = legacy_createStore(
|
||||||
|
combineReducers({
|
||||||
|
stars: starsReducer,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
(window as unknown as { redux: string }).redux = store as unknown as string
|
||||||
|
|
11
src/app.tsx
11
src/app.tsx
@ -1,10 +1,12 @@
|
|||||||
import React, { useCallback, useState } from 'react'
|
import React, { useCallback, useState } from 'react'
|
||||||
import { BrowserRouter } from 'react-router-dom'
|
import { BrowserRouter } from 'react-router-dom'
|
||||||
import { ChakraProvider } from '@chakra-ui/react'
|
import { ChakraProvider } from '@chakra-ui/react'
|
||||||
|
import { Provider } from 'react-redux'
|
||||||
|
|
||||||
import { Dashboard } from './dashboard'
|
import { Dashboard } from './dashboard'
|
||||||
import { stars as starsContext } from './__data__/context'
|
import { stars as starsContext } from './__data__/context'
|
||||||
import { users } from './__data__/users'
|
import { users } from './__data__/users'
|
||||||
|
import { store } from './__data__/store'
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [stars, setStar] = useState(
|
const [stars, setStar] = useState(
|
||||||
@ -14,8 +16,11 @@ const App = () => {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
const updateStar = useCallback((userId: string, rate: number) =>
|
const updateStar = useCallback(
|
||||||
setStar((state) => ({ ...state, [userId]: rate })), [setStar])
|
(userId: string, rate: number) =>
|
||||||
|
setStar((state) => ({ ...state, [userId]: rate })),
|
||||||
|
[setStar],
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<starsContext.Provider
|
<starsContext.Provider
|
||||||
value={{
|
value={{
|
||||||
@ -25,7 +30,9 @@ const App = () => {
|
|||||||
>
|
>
|
||||||
<ChakraProvider>
|
<ChakraProvider>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
<Provider store={store}>
|
||||||
<Dashboard />
|
<Dashboard />
|
||||||
|
</Provider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</ChakraProvider>
|
</ChakraProvider>
|
||||||
</starsContext.Provider>
|
</starsContext.Provider>
|
||||||
|
@ -2,9 +2,12 @@ import { HStack, Icon } from '@chakra-ui/react'
|
|||||||
import { FaRegStar, FaStar } from 'react-icons/fa6'
|
import { FaRegStar, FaStar } from 'react-icons/fa6'
|
||||||
import React, { useMemo, useState } from 'react'
|
import React, { useMemo, useState } from 'react'
|
||||||
import { getConfigValue } from '@brojs/cli'
|
import { getConfigValue } from '@brojs/cli'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
import { stars } from '../__data__/context'
|
import { stars } from '../__data__/context'
|
||||||
import { useUsers } from '../hooks'
|
import { useUsers } from '../hooks'
|
||||||
|
|
||||||
|
|
||||||
const useStars = (currentRated, starsCount) => {
|
const useStars = (currentRated, starsCount) => {
|
||||||
const [rated, setRated] = useState(currentRated)
|
const [rated, setRated] = useState(currentRated)
|
||||||
const stars = useMemo(
|
const stars = useMemo(
|
||||||
@ -34,7 +37,9 @@ export const Stars = ({
|
|||||||
// stars,
|
// stars,
|
||||||
// setRated: starsSetRated
|
// setRated: starsSetRated
|
||||||
// } = useStars(rated, count)
|
// } = useStars(rated, count)
|
||||||
const { rate, setUserRate } = useUsers(state => state[userId].rated)
|
const { setUserRate } = useUsers(state => state[userId].rated)
|
||||||
|
const rate = useSelector((store) => store.stars.friends[userId]) ?? 0
|
||||||
|
|
||||||
const handleStarsClick = (stars: number) => {
|
const handleStarsClick = (stars: number) => {
|
||||||
setUserRate(userId, stars)
|
setUserRate(userId, stars)
|
||||||
fetch(getConfigValue('dry-wash.api.url') + '/user-rate', {
|
fetch(getConfigValue('dry-wash.api.url') + '/user-rate', {
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
import { HStack } from '@chakra-ui/react'
|
import { HStack } from '@chakra-ui/react'
|
||||||
import React, { memo, useEffect, useState } from 'react'
|
import React, { memo, useEffect, useState } from 'react'
|
||||||
|
import { useDispatch } from 'react-redux'
|
||||||
|
|
||||||
import { Profile } from '../components'
|
import { Profile } from '../components'
|
||||||
import { users } from '../__data__/users'
|
import { users } from '../__data__/users'
|
||||||
|
import { setStars } from '../__data__/actions/stars'
|
||||||
|
|
||||||
export const Friends = memo(() => {
|
export const Friends = memo(() => {
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [data, setData] = useState(null)
|
const [data, setData] = useState(null)
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const getUser = async () => {
|
const getUser = async () => {
|
||||||
@ -17,7 +20,12 @@ export const Friends = memo(() => {
|
|||||||
const response = await fetch('/api/users/')
|
const response = await fetch('/api/users/')
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
setData((await response.json()).body)
|
const data = (await response.json()).body
|
||||||
|
setData(data)
|
||||||
|
|
||||||
|
Object.keys(data).forEach(userId => {
|
||||||
|
dispatch(setStars(userId, data[userId].rated))
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
throw 'Что-то пошло не так'
|
throw 'Что-то пошло не так'
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"name": "alexandr",
|
"name": "alexandr",
|
||||||
"surname": null,
|
"surname": null,
|
||||||
"email": null,
|
"email": null,
|
||||||
"rated": 3,
|
"rated": 4,
|
||||||
"avatar": "https://www.gravatar.com/avatar/6529e885535ef67a3fad810ad71167c2c03f79480936e9b3a714731753cbb47e?d=robohash",
|
"avatar": "https://www.gravatar.com/avatar/6529e885535ef67a3fad810ad71167c2c03f79480936e9b3a714731753cbb47e?d=robohash",
|
||||||
"friends": [
|
"friends": [
|
||||||
{
|
{
|
||||||
@ -24,7 +24,7 @@
|
|||||||
"name": "not alexandr",
|
"name": "not alexandr",
|
||||||
"surname": null,
|
"surname": null,
|
||||||
"email": null,
|
"email": null,
|
||||||
"rated": 2,
|
"rated": 5,
|
||||||
"avatar": "https://www.gravatar.com/avatar/6e?d=robohash",
|
"avatar": "https://www.gravatar.com/avatar/6e?d=robohash",
|
||||||
"friends": [
|
"friends": [
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user