From 741cbfe57159001ba9e2a678dfa976b8363eddb5 Mon Sep 17 00:00:00 2001 From: Hakan Shehu Date: Thu, 1 Aug 2024 16:17:59 +0200 Subject: [PATCH] Switch from redux-toolkit to mobx --- desktop/package-lock.json | 123 ++++++------------ desktop/package.json | 4 +- .../src/components/accounts/email-login.tsx | 10 +- .../components/accounts/email-register.tsx | 13 +- desktop/src/components/accounts/login.tsx | 12 +- desktop/src/components/app-loading.tsx | 2 +- desktop/src/components/app.tsx | 29 ++--- desktop/src/components/root.tsx | 8 +- .../components/spaces/space-create-button.tsx | 2 +- .../components/spaces/space-create-dialog.tsx | 12 +- .../components/workspaces/sidebar-header.tsx | 13 +- .../components/workspaces/sidebar-spaces.tsx | 2 +- desktop/src/components/workspaces/sidebar.tsx | 2 +- .../workspaces/workspace-create.tsx | 14 +- .../src/components/workspaces/workspace.tsx | 10 +- desktop/src/contexts/store.ts | 6 + desktop/src/lib/nodes.ts | 4 +- desktop/src/store/app-slice.ts | 57 -------- desktop/src/store/index.ts | 69 +++++++--- 19 files changed, 164 insertions(+), 228 deletions(-) create mode 100644 desktop/src/contexts/store.ts delete mode 100644 desktop/src/store/app-slice.ts diff --git a/desktop/package-lock.json b/desktop/package-lock.json index e2996b89..2fda0289 100644 --- a/desktop/package-lock.json +++ b/desktop/package-lock.json @@ -20,17 +20,17 @@ "@radix-ui/react-toast": "^1.2.1", "@radix-ui/react-tooltip": "^1.1.2", "@react-oauth/google": "^0.12.1", - "@reduxjs/toolkit": "^2.2.7", "axios": "^1.7.2", "better-sqlite3": "^11.1.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "electron-squirrel-startup": "^1.0.1", + "mobx": "^6.13.1", + "mobx-react-lite": "^4.0.7", "re-resizable": "^6.9.17", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.52.1", - "react-redux": "^9.1.2", "tailwind-merge": "^2.4.0", "tailwindcss-animate": "^1.0.7", "ulid": "^2.3.0", @@ -2332,30 +2332,6 @@ "react-dom": ">=16.8.0" } }, - "node_modules/@reduxjs/toolkit": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.7.tgz", - "integrity": "sha512-faI3cZbSdFb8yv9dhDTmGwclW0vk0z5o1cia+kf7gCbaCwHI5e+7tP57mJUv22pNcNbeA62GSrPpfrUfdXcQ6g==", - "license": "MIT", - "dependencies": { - "immer": "^10.0.3", - "redux": "^5.0.1", - "redux-thunk": "^3.1.0", - "reselect": "^5.1.0" - }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18", - "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-redux": { - "optional": true - } - } - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.19.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.1.tgz", @@ -2791,12 +2767,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", - "license": "MIT" - }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -7177,16 +7147,6 @@ "node": ">= 4" } }, - "node_modules/immer": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", - "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", - "license": "MIT", - "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", @@ -8332,6 +8292,41 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "license": "MIT" }, + "node_modules/mobx": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.13.1.tgz", + "integrity": "sha512-ekLRxgjWJr8hVxj9ZKuClPwM/iHckx3euIJ3Np7zLVNtqJvfbbq7l370W/98C8EabdQ1pB5Jd3BbDWxJPNnaOg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react-lite": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-4.0.7.tgz", + "integrity": "sha512-RjwdseshK9Mg8On5tyJZHtGD+J78ZnCnRaxeQDSiciKVQDUbfZcXhmld0VMxAwvcTnPEHZySGGewm467Fcpreg==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -9647,29 +9642,6 @@ "react": "^16.8.0 || ^17 || ^18 || ^19" } }, - "node_modules/react-redux": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", - "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", - "license": "MIT", - "dependencies": { - "@types/use-sync-external-store": "^0.0.3", - "use-sync-external-store": "^1.0.0" - }, - "peerDependencies": { - "@types/react": "^18.2.25", - "react": "^18.0", - "redux": "^5.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, "node_modules/react-remove-scroll": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", @@ -9934,21 +9906,6 @@ "node": ">= 10.13.0" } }, - "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/redux-thunk": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", - "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", - "license": "MIT", - "peerDependencies": { - "redux": "^5.0.0" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -9996,12 +9953,6 @@ "url": "https://github.com/sponsors/jet2jet" } }, - "node_modules/reselect": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", - "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", - "license": "MIT" - }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", diff --git a/desktop/package.json b/desktop/package.json index f4a15bdc..37a0abfc 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -54,17 +54,17 @@ "@radix-ui/react-toast": "^1.2.1", "@radix-ui/react-tooltip": "^1.1.2", "@react-oauth/google": "^0.12.1", - "@reduxjs/toolkit": "^2.2.7", "axios": "^1.7.2", "better-sqlite3": "^11.1.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "electron-squirrel-startup": "^1.0.1", + "mobx": "^6.13.1", + "mobx-react-lite": "^4.0.7", "re-resizable": "^6.9.17", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.52.1", - "react-redux": "^9.1.2", "tailwind-merge": "^2.4.0", "tailwindcss-animate": "^1.0.7", "ulid": "^2.3.0", diff --git a/desktop/src/components/accounts/email-login.tsx b/desktop/src/components/accounts/email-login.tsx index a6c580d4..25ae4b50 100644 --- a/desktop/src/components/accounts/email-login.tsx +++ b/desktop/src/components/accounts/email-login.tsx @@ -16,7 +16,7 @@ import { LoginOutput } from '@/types/accounts'; import { toast } from '@/components/ui/use-toast'; import {parseApiError} from "@/lib/axios"; import {Icon} from "@/components/ui/icon"; -import Axios from "axios"; +import axios from "axios"; const formSchema = z.object({ email: z.string().min(2).email(), @@ -28,7 +28,7 @@ interface EmailLoginProps { onLogin: (output: LoginOutput) => void; } -export function EmailLogin({ serverUrl, onLogin }: EmailLoginProps) { +export const EmailLogin = ({ serverUrl, onLogin }: EmailLoginProps) => { const [isPending, setIsPending] = React.useState(false); const form = useForm>({ resolver: zodResolver(formSchema), @@ -41,12 +41,8 @@ export function EmailLogin({ serverUrl, onLogin }: EmailLoginProps) { async function handleSubmit(values: z.infer) { setIsPending(true); try { - const axios = Axios.create({ - baseURL: serverUrl, - }); - const { data } = await axios.post( - 'v1/accounts/login/email', + `${serverUrl}/v1/accounts/login/email`, values, ); diff --git a/desktop/src/components/accounts/email-register.tsx b/desktop/src/components/accounts/email-register.tsx index 3f6896a2..4d6801da 100644 --- a/desktop/src/components/accounts/email-register.tsx +++ b/desktop/src/components/accounts/email-register.tsx @@ -16,7 +16,7 @@ import { LoginOutput } from '@/types/accounts'; import { toast } from '@/components/ui/use-toast'; import {parseApiError} from "@/lib/axios"; import {Icon} from "@/components/ui/icon"; -import Axios from "axios"; +import axios from "axios"; const formSchema = z.object({ name: z.string().min(2), @@ -29,7 +29,7 @@ interface EmailRegisterProps { onRegister: (output: LoginOutput) => void; } -export function EmailRegister({ serverUrl, onRegister }: EmailRegisterProps) { +export const EmailRegister = ({ serverUrl, onRegister }: EmailRegisterProps) => { const [isPending, setIsPending] = React.useState(false); const form = useForm>({ @@ -44,14 +44,9 @@ export function EmailRegister({ serverUrl, onRegister }: EmailRegisterProps) { async function onSubmit(values: z.infer) { setIsPending(true); try { - - const axios = Axios.create({ - baseURL: serverUrl, - }); - const { data } = await axios.post( - 'v1/accounts/register/email', - values, + `${serverUrl}/v1/accounts/register/email`, + values ); onRegister(data); diff --git a/desktop/src/components/accounts/login.tsx b/desktop/src/components/accounts/login.tsx index 2165a522..600951f8 100644 --- a/desktop/src/components/accounts/login.tsx +++ b/desktop/src/components/accounts/login.tsx @@ -2,20 +2,22 @@ import React from 'react'; import { EmailLogin } from '@/components/accounts/email-login'; import { LoginOutput } from '@/types/accounts'; import { EmailRegister } from '@/components/accounts/email-register'; -import {addAccount, addWorkspace} from "@/store/app-slice"; +import { useStore } from "@/contexts/store"; +import { observer } from "mobx-react-lite"; const serverUrl = 'http://localhost:3000'; -export function Login() { +export const Login = observer(() => { + const store = useStore(); const [showRegister, setShowRegister] = React.useState(false); async function handleLogin(output: LoginOutput) { - addAccount(output.account); + store.addAccount(output.account); await window.globalDb.addAccount(output.account); if (output.workspaces.length > 0) { for (const workspace of output.workspaces) { - addWorkspace(workspace); + store.addWorkspace(workspace); await window.globalDb.addWorkspace(workspace); } } @@ -57,4 +59,4 @@ export function Login() { ); -} +}); diff --git a/desktop/src/components/app-loading.tsx b/desktop/src/components/app-loading.tsx index 9e628e80..58215bff 100644 --- a/desktop/src/components/app-loading.tsx +++ b/desktop/src/components/app-loading.tsx @@ -1,7 +1,7 @@ import React from "react"; import {Spinner} from "@/components/ui/spinner"; -export function AppLoading() { +export const AppLoading = () => { return (
diff --git a/desktop/src/components/app.tsx b/desktop/src/components/app.tsx index 1b9e510b..815f0a5c 100644 --- a/desktop/src/components/app.tsx +++ b/desktop/src/components/app.tsx @@ -1,46 +1,43 @@ import React from "react"; -import {useDispatch, useSelector} from "react-redux"; -import {RootState} from "@/store"; import {Login} from "@/components/accounts/login"; import {AppLoading} from "@/components/app-loading"; -import {setWorkspaces, setAccounts, setLoaded} from "@/store/app-slice"; import {Workspace} from "@/components/workspaces/workspace"; import {AccountContext} from "@/contexts/account"; import Axios from "axios"; import {AxiosContext} from "@/contexts/axios"; +import {useStore} from "@/contexts/store"; +import {observer} from "mobx-react-lite"; const serverUrl = 'http://localhost:3000'; -export function App() { - const appLoaded = useSelector((state: RootState) => state.app.loaded); - const accounts = useSelector((state: RootState) => state.app.accounts); - const dispatch = useDispatch(); +export const App = observer(() => { + const store = useStore(); React.useEffect(() => { - if (!appLoaded) { + if (!store.loaded) { Promise.all([ window.globalDb.getAccounts(), window.globalDb.getWorkspaces(), ]).then(([accounts, workspaces]) => { - dispatch(setAccounts(accounts)); - dispatch(setWorkspaces(workspaces)); - dispatch(setLoaded()); + store.setAccounts(accounts); + store.setWorkspaces(workspaces); + store.setLoaded(); }).catch((error) => { // Handle any errors if needed console.error("Error loading data: ", error); }); } - }, [appLoaded]); + }, [store.loaded]); - if (!appLoaded) { + if (!store.loaded) { return ; } - if (accounts.length == 0) { + if (store.accounts.length == 0) { return ; } - const account = accounts[0]; + const account = store.accounts[0]; const axios = Axios.create({ baseURL: serverUrl, headers: { @@ -55,4 +52,4 @@ export function App() { ); -} \ No newline at end of file +}); \ No newline at end of file diff --git a/desktop/src/components/root.tsx b/desktop/src/components/root.tsx index a6f30355..b6231344 100644 --- a/desktop/src/components/root.tsx +++ b/desktop/src/components/root.tsx @@ -3,17 +3,17 @@ import { createRoot } from 'react-dom/client'; import {App} from "@/components/app"; import {TooltipProvider} from "@/components/ui/tooltip"; import {Toaster} from "@/components/ui/toaster"; -import {Provider as ReduxProvider} from "react-redux"; +import {StoreContext} from "@/contexts/store"; import {store} from "@/store"; -function Root() { +export const Root = () => { return ( - + - + ); } diff --git a/desktop/src/components/spaces/space-create-button.tsx b/desktop/src/components/spaces/space-create-button.tsx index 68f771aa..7407cebd 100644 --- a/desktop/src/components/spaces/space-create-button.tsx +++ b/desktop/src/components/spaces/space-create-button.tsx @@ -2,7 +2,7 @@ import React from "react"; import {SpaceCreateDialog} from "@/components/spaces/space-create-dialog"; import {Icon} from "@/components/ui/icon"; -export function SpaceCreateButton() { +export const SpaceCreateButton = () => { const [open, setOpen] = React.useState(false); return ( diff --git a/desktop/src/components/spaces/space-create-dialog.tsx b/desktop/src/components/spaces/space-create-dialog.tsx index 46961bb7..bdb9a493 100644 --- a/desktop/src/components/spaces/space-create-dialog.tsx +++ b/desktop/src/components/spaces/space-create-dialog.tsx @@ -25,13 +25,15 @@ const formSchema = z.object({ description: z.string(), }); -export function SpaceCreateDialog({ - open, - onOpenChange, -}: { +interface SpaceCreateDialogProps { open: boolean; onOpenChange: (open: boolean) => void; -}){ +} + +export const SpaceCreateDialog = ({ + open, + onOpenChange, +}: SpaceCreateDialogProps) => { const workspace = useWorkspace(); const [isPending, setIsPending] = React.useState(false); const form = useForm>({ diff --git a/desktop/src/components/workspaces/sidebar-header.tsx b/desktop/src/components/workspaces/sidebar-header.tsx index ee6b32a7..678c75f0 100644 --- a/desktop/src/components/workspaces/sidebar-header.tsx +++ b/desktop/src/components/workspaces/sidebar-header.tsx @@ -3,12 +3,15 @@ import {useWorkspace} from "@/contexts/workspace"; import {Popover, PopoverContent, PopoverTrigger} from "@/components/ui/popover"; import {Icon} from "@/components/ui/icon"; import {Avatar} from "@/components/ui/avatar"; -import {useSelector} from "@/store"; +import {useStore} from "@/contexts/store"; +import {observer} from "mobx-react-lite"; -export function SidebarHeader() { +export const SidebarHeader = observer(() => { + const store = useStore(); const workspace = useWorkspace(); - const account = useSelector(state => state.app.accounts)[0]; - const workspaces = useSelector(state => state.app.workspaces); + + const account = store.accounts[0]; + const workspaces = store.workspaces; return ( @@ -68,4 +71,4 @@ export function SidebarHeader() { ) -} \ No newline at end of file +}); \ No newline at end of file diff --git a/desktop/src/components/workspaces/sidebar-spaces.tsx b/desktop/src/components/workspaces/sidebar-spaces.tsx index 4d629203..cca3490a 100644 --- a/desktop/src/components/workspaces/sidebar-spaces.tsx +++ b/desktop/src/components/workspaces/sidebar-spaces.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {SpaceCreateButton} from "@/components/spaces/space-create-button"; -export function SidebarSpaces() { +export const SidebarSpaces = () => { const canAddEntities = true; return ( diff --git a/desktop/src/components/workspaces/sidebar.tsx b/desktop/src/components/workspaces/sidebar.tsx index 51c57c24..4bfd8000 100644 --- a/desktop/src/components/workspaces/sidebar.tsx +++ b/desktop/src/components/workspaces/sidebar.tsx @@ -23,7 +23,7 @@ const layouts: LayoutItem[] = [ } ]; -export function Sidebar() { +export const Sidebar = () => { const currentLayout = 'spaces'; return ( diff --git a/desktop/src/components/workspaces/workspace-create.tsx b/desktop/src/components/workspaces/workspace-create.tsx index 589e34cd..3e216fe7 100644 --- a/desktop/src/components/workspaces/workspace-create.tsx +++ b/desktop/src/components/workspaces/workspace-create.tsx @@ -17,17 +17,19 @@ import { Textarea } from '@/components/ui/textarea'; import { toast } from '@/components/ui/use-toast'; import {parseApiError} from "@/lib/axios"; import {Workspace} from "@/types/workspaces"; -import {useDispatch} from "react-redux"; -import {addWorkspace} from "@/store/app-slice"; import {useAxios} from "@/contexts/axios"; +import {useStore} from "@/contexts/store"; +import {observer} from "mobx-react-lite"; const formSchema = z.object({ name: z.string().min(3, 'Name must be at least 3 characters long.'), description: z.string(), }); -export function WorkspaceCreate() { +export const WorkspaceCreate = observer(() => { + const store = useStore(); const axios = useAxios(); + const [isPending, setIsPending] = React.useState(false); const form = useForm>({ resolver: zodResolver(formSchema), @@ -37,14 +39,12 @@ export function WorkspaceCreate() { }, }); - const dispatch = useDispatch(); - async function handleSubmit(values: z.infer) { setIsPending(true); try { const { data } = await axios.post('v1/workspaces', values); if (data) { - dispatch(addWorkspace(data)); + store.addWorkspace(data); await window.globalDb.addWorkspace(data); } else { toast({ @@ -120,4 +120,4 @@ export function WorkspaceCreate() {
) -} \ No newline at end of file +}); \ No newline at end of file diff --git a/desktop/src/components/workspaces/workspace.tsx b/desktop/src/components/workspaces/workspace.tsx index b1506b83..deabc874 100644 --- a/desktop/src/components/workspaces/workspace.tsx +++ b/desktop/src/components/workspaces/workspace.tsx @@ -2,10 +2,12 @@ import React from "react"; import {Sidebar} from "@/components/workspaces/sidebar"; import {WorkspaceCreate} from "@/components/workspaces/workspace-create"; import {WorkspaceContext} from "@/contexts/workspace"; -import {useSelector} from "@/store"; +import {useStore} from "@/contexts/store"; +import {observer} from "mobx-react-lite"; -export function Workspace() { - const workspaces = useSelector(state => state.app.workspaces); +export const Workspace = observer(() => { + const store = useStore(); + const workspaces = store.workspaces; if (workspaces.length === 0) { return ; } @@ -24,4 +26,4 @@ export function Workspace() { ) -} \ No newline at end of file +}); \ No newline at end of file diff --git a/desktop/src/contexts/store.ts b/desktop/src/contexts/store.ts new file mode 100644 index 00000000..d398e7ae --- /dev/null +++ b/desktop/src/contexts/store.ts @@ -0,0 +1,6 @@ +import { createContext, useContext } from "react"; +import { store, AppStore } from "@/store"; + +export const StoreContext = createContext(store); + +export const useStore = () => useContext(StoreContext); \ No newline at end of file diff --git a/desktop/src/lib/nodes.ts b/desktop/src/lib/nodes.ts index 0d6b01a1..12fe3a70 100644 --- a/desktop/src/lib/nodes.ts +++ b/desktop/src/lib/nodes.ts @@ -1,10 +1,10 @@ import {Node} from "@/types/nodes"; -import {setNode} from "@/store/app-slice"; import {CreateNodeTransactionInput, Transaction} from "@/types/transactions"; import {generateId, IdType} from "@/lib/id"; +import {store} from "@/store"; export async function createNode(accountId: string, node: Node) { - setNode(node); + store.setNode(node); const transactionInput: CreateNodeTransactionInput = { id: node.id, diff --git a/desktop/src/store/app-slice.ts b/desktop/src/store/app-slice.ts deleted file mode 100644 index e00fed1e..00000000 --- a/desktop/src/store/app-slice.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit' -import type { PayloadAction } from '@reduxjs/toolkit' -import {Workspace} from "@/types/workspaces"; -import {Node} from "@/types/nodes"; -import {Account} from "@/types/accounts"; - -export interface AppState { - loaded: boolean; - accounts: Account[]; - workspaces: Workspace[]; - nodes: Record; -} - -const initialState: AppState = { - loaded: false, - accounts: [], - workspaces: [], - nodes: {} -} - -export const appSlice = createSlice({ - name: 'app', - initialState: initialState, - reducers: { - setLoaded: (state) => { - state.loaded = true - }, - setWorkspaces: (state, action: PayloadAction) => { - state.workspaces = action.payload - }, - addWorkspace: (state, action: PayloadAction) => { - state.workspaces = [...state.workspaces, action.payload] - }, - setNodes: (state, action: PayloadAction) => { - state.nodes = action.payload.reduce((acc, node) => { - acc[node.id] = node - return acc - }, {} as Record) - }, - setNode: (state, action: PayloadAction) => { - state.nodes[action.payload.id] = action.payload - }, - removeNode: (state, action: PayloadAction) => { - delete state.nodes[action.payload] - }, - setAccounts: (state, action: PayloadAction) => { - state.accounts = action.payload - }, - addAccount: (state, action: PayloadAction) => { - state.accounts = [...state.accounts, action.payload] - } - }, -}) - -export const { setLoaded, setWorkspaces, addWorkspace, setNode, setNodes, removeNode, setAccounts, addAccount } = appSlice.actions -export const appReducer = appSlice.reducer - diff --git a/desktop/src/store/index.ts b/desktop/src/store/index.ts index 71bef387..c32f43c8 100644 --- a/desktop/src/store/index.ts +++ b/desktop/src/store/index.ts @@ -1,18 +1,57 @@ -import { configureStore } from '@reduxjs/toolkit' -import {useSelector as useReduxSelector} from "react-redux"; -import {appReducer} from "@/store/app-slice"; +import {Account} from "@/types/accounts"; +import {Workspace} from "@/types/workspaces"; +import {Node} from "@/types/nodes"; +import {makeAutoObservable} from "mobx"; -export const store = configureStore({ - reducer: { - app: appReducer, - }, -}) +export class AppStore { + loaded: boolean; + accounts: Account[]; + workspaces: Workspace[]; + nodes: Record; -// Infer the `RootState` and `AppDispatch` types from the store itself -export type RootState = ReturnType -// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState} -export type AppDispatch = typeof store.dispatch + constructor() { + this.loaded = false; + this.accounts = []; + this.workspaces = []; + this.nodes = {}; -export function useSelector(selector: (state: RootState) => T) { - return useReduxSelector(selector); -} \ No newline at end of file + makeAutoObservable(this); + } + + setLoaded() { + this.loaded = true; + } + + setAccounts(accounts: Account[]) { + this.accounts = accounts; + } + + addAccount(account: Account) { + this.accounts.push(account); + } + + setWorkspaces(workspaces: Workspace[]) { + this.workspaces = workspaces; + } + + addWorkspace(workspace: Workspace) { + this.workspaces.push(workspace); + } + + setNodes(nodes: Node[]) { + this.nodes = nodes.reduce((acc, node) => { + acc[node.id] = node; + return acc; + }, {} as Record); + } + + setNode(node: Node) { + this.nodes[node.id] = node; + } + + removeNode(nodeId: string) { + delete this.nodes[nodeId]; + } +} + +export const store = new AppStore(); \ No newline at end of file