1
0
Fork 0
mirror of https://git.sr.ht/~ashkeel/strimertul synced 2024-09-18 01:50:50 +00:00

refactor: remove typecasting from thunks

This commit is contained in:
Ash Keel 2023-05-03 17:18:52 +02:00
parent 4de2b0a817
commit 2cf63534e5
No known key found for this signature in database
GPG key ID: BAD8D93E7314ED3E

View file

@ -9,7 +9,7 @@ import {
Dispatch, Dispatch,
PayloadAction, PayloadAction,
} from '@reduxjs/toolkit'; } from '@reduxjs/toolkit';
import KilovoltWS from '@strimertul/kilovolt-client'; import KilovoltWS, { KilovoltMessage } from '@strimertul/kilovolt-client';
import type { kvError } from '@strimertul/kilovolt-client/types/messages'; import type { kvError } from '@strimertul/kilovolt-client/types/messages';
import { AuthenticateKVClient, IsServerReady } from '@wailsapp/go/main/App'; import { AuthenticateKVClient, IsServerReady } from '@wailsapp/go/main/App';
import { delay } from '~/lib/time'; import { delay } from '~/lib/time';
@ -20,44 +20,38 @@ import {
LoyaltyRedeem, LoyaltyRedeem,
LoyaltyStorage, LoyaltyStorage,
} from './types'; } from './types';
import { ThunkConfig } from '..';
type ThunkAPIState = { api: APIState };
interface AppThunkAPI { interface AppThunkAPI {
dispatch: Dispatch; dispatch: Dispatch;
getState: () => unknown; getState: () => ThunkAPIState;
}
function makeGetterThunk<T>(key: string) {
return async (_: void, { getState }: AppThunkAPI) => {
const { api } = getState() as { api: APIState };
return api.client.getJSON<T>(key);
};
}
function makeSetterThunk<T>(
key: string,
// eslint-disable-next-line @typescript-eslint/ban-types
getter: AsyncThunk<T, void, {}>,
) {
return async (data: T, { getState, dispatch }: AppThunkAPI) => {
const { api } = getState() as { api: APIState };
const result = await api.client.putJSON(key, data);
if ('ok' in result) {
if (result.ok) {
// Re-load value from KV
// Need to do type fuckery to avoid cyclic redundancy
// (unless there's a better way that I'm missing)
void dispatch(getter() as unknown as AnyAction);
}
}
return result;
};
} }
function makeGetSetThunks<T>(key: string) { function makeGetSetThunks<T>(key: string) {
const getter = createAsyncThunk(`api/get/${key}`, makeGetterThunk<T>(key)); const getter = createAsyncThunk<T, void, { state: ThunkAPIState }>(
const setter = createAsyncThunk( `api/get/${key}`,
async (_, { getState }) => {
const { api } = getState();
return api.client.getJSON<T>(key);
},
);
const setter = createAsyncThunk<KilovoltMessage, T, { state: ThunkAPIState }>(
`api/set/${key}`, `api/set/${key}`,
makeSetterThunk<T>(key, getter), async (data: T, { getState, dispatch }: AppThunkAPI) => {
const { api } = getState();
const result = await api.client.putJSON(key, data);
if ('ok' in result) {
if (result.ok) {
// Re-load value from KV
// Need to do type fuckery to avoid cyclic redundancy
// (unless there's a better way that I'm missing)
void dispatch(getter() as unknown as AnyAction);
}
}
return result;
},
); );
return { getter, setter }; return { getter, setter };
} }
@ -117,39 +111,34 @@ export const createWSClient = createAsyncThunk(
}, },
); );
export const getUserPoints = createAsyncThunk( export const getUserPoints = createAsyncThunk<
'api/getUserPoints', LoyaltyStorage,
async (_: void, { getState }) => { void,
const { api } = getState() as { api: APIState }; ThunkConfig
const keys = await api.client.getKeysByPrefix(loyaltyPointsPrefix); >('api/getUserPoints', async (_, { getState }) => {
const userpoints: LoyaltyStorage = {}; const { api } = getState();
Object.entries(keys).forEach(([k, v]) => { const keys = await api.client.getKeysByPrefix(loyaltyPointsPrefix);
userpoints[k.substring(loyaltyPointsPrefix.length)] = JSON.parse( const userpoints: LoyaltyStorage = {};
v, Object.entries(keys).forEach(([k, v]) => {
) as LoyaltyPointsEntry; userpoints[k.substring(loyaltyPointsPrefix.length)] = JSON.parse(
}); v,
return userpoints; ) as LoyaltyPointsEntry;
}, });
); return userpoints;
});
export const setUserPoints = createAsyncThunk( export const setUserPoints = createAsyncThunk<
'api/setUserPoints', KilovoltMessage,
async ( { user: string; points: number; relative: boolean },
{ ThunkConfig
user, >('api/setUserPoints', async ({ user, points, relative }, { getState }) => {
points, const { api } = getState();
relative, const entry: LoyaltyPointsEntry = { points };
}: { user: string; points: number; relative: boolean }, if (relative) {
{ getState }, entry.points += api.loyalty.users[user]?.points ?? 0;
) => { }
const { api } = getState() as { api: APIState }; return api.client.putJSON(loyaltyPointsPrefix + user, entry);
const entry: LoyaltyPointsEntry = { points }; });
if (relative) {
entry.points += api.loyalty.users[user]?.points ?? 0;
}
return api.client.putJSON(loyaltyPointsPrefix + user, entry);
},
);
export const modules = { export const modules = {
httpConfig: makeModule( httpConfig: makeModule(
@ -242,21 +231,23 @@ export const modules = {
), ),
}; };
export const createRedeem = createAsyncThunk( export const createRedeem = createAsyncThunk<
'api/createRedeem', KilovoltMessage,
async (redeem: LoyaltyRedeem, { getState }) => { LoyaltyRedeem,
const { api } = getState() as { api: APIState }; ThunkConfig
return api.client.putJSON(loyaltyCreateRedeemKey, redeem); >('api/createRedeem', async (redeem: LoyaltyRedeem, { getState }) => {
}, const { api } = getState();
); return api.client.putJSON(loyaltyCreateRedeemKey, redeem);
});
export const removeRedeem = createAsyncThunk( export const removeRedeem = createAsyncThunk<
'api/removeRedeem', KilovoltMessage,
async (redeem: LoyaltyRedeem, { getState }) => { LoyaltyRedeem,
const { api } = getState() as { api: APIState }; ThunkConfig
return api.client.putJSON(loyaltyRemoveRedeemKey, redeem); >('api/removeRedeem', async (redeem: LoyaltyRedeem, { getState }) => {
}, const { api } = getState();
); return api.client.putJSON(loyaltyRemoveRedeemKey, redeem);
});
const moduleChangeReducers = Object.fromEntries( const moduleChangeReducers = Object.fromEntries(
Object.entries(modules).map(([key, mod]) => [ Object.entries(modules).map(([key, mod]) => [
@ -419,10 +410,10 @@ kvErrorReceived = createAsyncThunk(
}, },
); );
export const useAuthBypass = createAsyncThunk( export const useAuthBypass = createAsyncThunk<void, void, ThunkConfig>(
'api/authBypass', 'api/authBypass',
async (_: void, { getState, dispatch }) => { async (_: void, { getState, dispatch }) => {
const { api } = getState() as { api: APIState }; const { api } = getState();
const response = await api.client.send({ command: '_uid' }); const response = await api.client.send({ command: '_uid' });
if ('ok' in response && response.ok && 'data' in response) { if ('ok' in response && response.ok && 'data' in response) {
const uid = response.data; const uid = response.data;