Use superjson

This commit is contained in:
Amber Sprenkels
2025-07-06 10:39:26 +02:00
parent a31263f43b
commit 8364e72ec4
6 changed files with 75 additions and 16 deletions

View File

@@ -1,6 +1,11 @@
import { configureStore, createAction, createAsyncThunk, createListenerMiddleware, createReducer } from '@reduxjs/toolkit'
import DEFAULT_BRINGLIST_TEMPLATE from '@/lib/template'
import { trpc } from '@/client/trpc'
import SuperJSON from 'superjson'
const LOCAL_STORAGE_KEY_V1 = 'com.electricdusk.backpack.v1.state'
const LOCAL_STORAGE_KEY_V2 = 'com.electricdusk.backpack.v2.state'
const LOCAL_STORAGE_KEY_LATEST = LOCAL_STORAGE_KEY_V2
// --- Type Definitions ---
export interface KeyValueDict<T> {
@@ -10,8 +15,8 @@ export interface KeyValueDict<T> {
export interface State {
bringList: {
bringListTemplate: string,
tags: string[],
checked: string[],
tags: Set<string>,
checked: Set<string>,
nights: number,
header: string,
},
@@ -39,8 +44,8 @@ function startingState(): State {
return {
bringList: {
bringListTemplate: DEFAULT_BRINGLIST_TEMPLATE,
tags: [],
checked: [],
tags: new Set(),
checked: new Set(),
nights: 3,
header: '',
},
@@ -49,8 +54,15 @@ function startingState(): State {
}
function initialState(): State {
const stored = localStorage.getItem('com.electricdusk.backpack.v1.state')
return (stored ? JSON.parse(stored) : startingState())
let stored = localStorage.getItem(LOCAL_STORAGE_KEY_V2)
if (stored) {
return SuperJSON.parse(stored) as State
}
stored = localStorage.getItem(LOCAL_STORAGE_KEY_V1)
if (stored) {
return JSON.parse(stored) as State
}
return startingState()
}
// --- Reducers ---
@@ -60,20 +72,20 @@ const bringListReducer = createReducer(initialState, builder => {
})
.addCase(setTagEnabled, (state, action) => {
const [tag, enabled] = action.payload
state.bringList.tags = new Set(state.bringList.tags)
if (enabled) {
state.bringList.tags.push(tag)
state.bringList.tags.sort()
state.bringList.tags.add(tag)
} else {
state.bringList.tags = state.bringList.tags.filter(t => t !== tag)
state.bringList.tags.delete(tag)
}
})
.addCase(setChecked, (state, action) => {
const [item, checked] = action.payload
state.bringList.checked = new Set(state.bringList.checked)
if (checked) {
state.bringList.checked.push(item)
state.bringList.checked.sort()
state.bringList.checked.add(item)
} else {
state.bringList.checked = state.bringList.checked.filter(t => t !== item)
state.bringList.checked.delete(item)
}
})
.addCase(setNights, (state, action) => {
@@ -98,7 +110,7 @@ localStorageMiddleware.startListening({
predicate: (action) => action.type.startsWith('bringlist/'),
effect: (action, api) => {
const state = api.getState() as State
localStorage.setItem('com.electricdusk.backpack.v1.state', JSON.stringify(state))
localStorage.setItem(LOCAL_STORAGE_KEY_LATEST, SuperJSON.stringify(state))
}
})

View File

@@ -1,9 +1,11 @@
import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
import type { AppRouter } from "@/server/main";
import type { AppRouter } from "@/server/index";
import superjson from "superjson";
export const trpc = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
transformer: superjson,
url: '/backpack/api/hello',
}),
],

40
package-lock.json generated
View File

@@ -18,6 +18,7 @@
"react-dom": "^18",
"react-redux": "^9",
"reflect-metadata": "^0.2.2",
"superjson": "^2.2.2",
"tailwindcss": "^4.0.9"
},
"devDependencies": {
@@ -3173,6 +3174,21 @@
"node": ">=6.6.0"
}
},
"node_modules/copy-anything": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
"integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
"license": "MIT",
"dependencies": {
"is-what": "^4.1.8"
},
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -5020,6 +5036,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-what": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
"integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
"license": "MIT",
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
@@ -7243,6 +7271,18 @@
"dev": true,
"license": "MIT"
},
"node_modules/superjson": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz",
"integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==",
"license": "MIT",
"dependencies": {
"copy-anything": "^3.0.2"
},
"engines": {
"node": ">=16"
}
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",

View File

@@ -24,6 +24,7 @@
"react-dom": "^18",
"react-redux": "^9",
"reflect-metadata": "^0.2.2",
"superjson": "^2.2.2",
"tailwindcss": "^4.0.9"
},
"devDependencies": {

View File

@@ -5,6 +5,7 @@ import * as trpcExpress from '@trpc/server/adapters/express'
import { Pool, } from 'pg'
import { autoMigrate } from '@/server/migrations'
import { initTRPC } from '@trpc/server'
import superjson from 'superjson'
// Create a PostgreSQL connection pool
for (const envVar of ['PGUSER', 'PGPASSWORD', 'PGHOST', 'PGPORT', 'PGDATABASE']) {
@@ -32,7 +33,9 @@ try {
}
// Define tRPC router
const t = initTRPC.create()
const t = initTRPC.create({
transformer: superjson,
})
const appRouter = t.router({
hello: t.procedure.query(() => {
const rand = Math.floor(Math.random() * 1000)

View File

@@ -13,6 +13,7 @@
"skipLibCheck": true,
"esModuleInterop": false,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
"module": "ESNext",
"moduleResolution": "Node",
"sourceMap": true,
@@ -20,6 +21,6 @@
"isolatedModules": true,
"jsx": "react-jsx"
},
"include": ["server", "lib"],
"include": ["client", "server", "lib"],
"references": [{ "path": "./tsconfig.node.json" }]
}