diff --git a/client/package-lock.json b/client/package-lock.json index 34d06c5..5cc69d9 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "license": "MIT", "dependencies": { + "@reduxjs/toolkit": "^1.8.5", "lodash": "^4.17.21", "preact": "^10.10.0", "preact-render-to-string": "^5.2.1", @@ -2663,6 +2664,29 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/@reduxjs/toolkit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.5.tgz", + "integrity": "sha512-f4D5EXO7A7Xq35T0zRbWq5kJQyXzzscnHKmjnu2+37B3rwHU6mX9PYlbfXdnxcY6P/7zfmjhgan0Z+yuOfeBmA==", + "dependencies": { + "immer": "^9.0.7", + "redux": "^4.1.2", + "redux-thunk": "^2.4.1", + "reselect": "^4.1.5" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -10063,6 +10087,15 @@ "node": ">=0.10.0" } }, + "node_modules/immer": { + "version": "9.0.15", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz", + "integrity": "sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -16224,6 +16257,14 @@ "@babel/runtime": "^7.9.2" } }, + "node_modules/redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "peerDependencies": { + "redux": "^4" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -16523,6 +16564,11 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, + "node_modules/reselect": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz", + "integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==" + }, "node_modules/resolve": { "version": "2.0.0-next.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", @@ -23102,6 +23148,17 @@ "@prefresh/utils": "^1.1.2" } }, + "@reduxjs/toolkit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.5.tgz", + "integrity": "sha512-f4D5EXO7A7Xq35T0zRbWq5kJQyXzzscnHKmjnu2+37B3rwHU6mX9PYlbfXdnxcY6P/7zfmjhgan0Z+yuOfeBmA==", + "requires": { + "immer": "^9.0.7", + "redux": "^4.1.2", + "redux-thunk": "^2.4.1", + "reselect": "^4.1.5" + } + }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -28975,6 +29032,11 @@ "dev": true, "optional": true }, + "immer": { + "version": "9.0.15", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz", + "integrity": "sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -33670,6 +33732,12 @@ "@babel/runtime": "^7.9.2" } }, + "redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "requires": {} + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -33902,6 +33970,11 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, + "reselect": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz", + "integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==" + }, "resolve": { "version": "2.0.0-next.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", diff --git a/client/package.json b/client/package.json index 6a68949..d9909ff 100644 --- a/client/package.json +++ b/client/package.json @@ -9,6 +9,7 @@ "lint": "eslint src" }, "dependencies": { + "@reduxjs/toolkit": "^1.8.5", "lodash": "^4.17.21", "preact": "^10.10.0", "preact-render-to-string": "^5.2.1", @@ -16,7 +17,6 @@ "react-feather": "^2.0.10", "react-redux": "^8.0.2", "redux": "^4.2.0", - "unistore": "^3.5.2" }, "devDependencies": { "@babel/plugin-transform-react-jsx-source": "^7.18.6", diff --git a/client/src/app.tsx b/client/src/app.tsx index 3a9a52d..7585715 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -1,9 +1,8 @@ import { h } from 'preact'; import { useState, useEffect } from 'preact/hooks'; import { Route, Router, route } from 'preact-router'; -import { Provider, connect } from 'unistore/preact' +import { Provider } from 'react-redux' -import createStore from './store'; import createWs from './ws'; import http from './http'; @@ -16,17 +15,17 @@ import Login from './routes/login'; import Search from './routes/search'; import List from './routes/list'; -const store = createStore(); -const ws = createWs(store); +import store, { userState, wsState } from './store' +const ws = createWs(store); ws.connect(); async function init() { const [error, user] = await http.getLogin(); if (error) return route('/login'); route('/bundles'); - store.setState({ user }); - store.setState({ ws }); + store.dispatch(userState.actions.set(user)); + store.dispatch(wsState.actions.set(ws)); } init(); diff --git a/client/src/components/header.tsx b/client/src/components/header.tsx index e280a39..73c6cd4 100644 --- a/client/src/components/header.tsx +++ b/client/src/components/header.tsx @@ -1,15 +1,19 @@ import { h } from 'preact'; import { route } from 'preact-router'; -import { connect } from 'unistore/preact' +import { useSelector, useDispatch } from 'react-redux' import http from './../http'; -import actions from './../actions'; +import { State, userState } from './../store'; -const Header = ({ user, logout }) => { +const Header = () => { + const dispatch = useDispatch() + const user = useSelector((state: State) => state.user); - function logoutClick(e) { + async function logoutClick(e) { e.preventDefault(); - logout(); + await http.postLogout(); + route('/login'); + dispatch(userState.actions.set(null)); } const nav = () => ( @@ -39,7 +43,6 @@ const Header = ({ user, logout }) => { Account Logout - ) return ( @@ -51,5 +54,4 @@ const Header = ({ user, logout }) => { ); } -// @ts-ignore unistore types -export default connect(['user'], actions)(Header); +export default Header; diff --git a/client/src/routes/acp.tsx b/client/src/routes/acp.tsx index 79b8fe9..f76fe41 100644 --- a/client/src/routes/acp.tsx +++ b/client/src/routes/acp.tsx @@ -7,9 +7,7 @@ import AcpOffer from './../components/acp.offer'; import { Status } from './../../../api/src/offers'; -function ItemEl({ item, ws }) { - console.log(item); - console.log(ws); +function Item({ item, ws }) { const statuses = Object.entries(Status).map(([label, value]) => ( )); @@ -32,8 +30,6 @@ function ItemEl({ item, ws }) { ); } -const Item = connect(['ws'], {}, ItemEl); - function SellerGroup(group) { return (
Mates Crates is a record importing service.
diff --git a/client/src/store.tsx b/client/src/store.tsx index d9d2f44..0e62733 100644 --- a/client/src/store.tsx +++ b/client/src/store.tsx @@ -1,10 +1,39 @@ -import unistore from 'unistore' +import { createStore, combineReducers } from 'redux' +import { configureStore, createSlice } from '@reduxjs/toolkit' -export default function createStore() { - return unistore({ - bundles: [], - offers: [], - user: null, - ws: null, - }); -}; +export const userState = createSlice({ + name: 'user', + initialState: null, + reducers: { + set: (state, action) => action.payload + }, +}); + +export const offersState = createSlice({ + name: 'offers', + initialState: [], + reducers: { + set: (state, action) => action.payload + }, +}); + +export const wsState = createSlice({ + name: 'ws', + initialState: null, + reducers: { + set: (state, action) => action.payload + }, +}); + +const reducer = combineReducers({ + user: userState.reducer, + offers: offersState.reducer, + ws: wsState.reducer, +}); + +const store = createStore(reducer); + +export default store; + +export type State = ReturnType