mirror of
https://git.sr.ht/~ashkeel/strimertul
synced 2024-09-18 01:50:50 +00:00
Fix minor UI issues after update
This commit is contained in:
parent
ec7f882beb
commit
5a455951b7
4 changed files with 66 additions and 19 deletions
|
@ -1,9 +1,16 @@
|
|||
import { ActionCreatorWithOptionalPayload, AsyncThunk } from '@reduxjs/toolkit';
|
||||
import { useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { KilovoltMessage } from '@strimertul/kilovolt-client';
|
||||
import {
|
||||
KilovoltMessage,
|
||||
SubscriptionHandler,
|
||||
} from '@strimertul/kilovolt-client';
|
||||
import { RootState } from '../store';
|
||||
import { APIState } from '../store/api/reducer';
|
||||
import apiReducer, {
|
||||
APIState,
|
||||
getUserPoints,
|
||||
LoyaltyStorage,
|
||||
} from '../store/api/reducer';
|
||||
|
||||
export function useModule<T>({
|
||||
key,
|
||||
|
@ -37,6 +44,27 @@ export function useModule<T>({
|
|||
return [data, setter];
|
||||
}
|
||||
|
||||
export function useUserPoints(): LoyaltyStorage {
|
||||
const prefix = 'loyalty/points/';
|
||||
const client = useSelector((state: RootState) => state.api.client);
|
||||
const data = useSelector((state: RootState) => state.api.loyalty.users);
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
dispatch(getUserPoints());
|
||||
const subscriber: SubscriptionHandler = (newValue, key) => {
|
||||
const user = key.substring(prefix.length);
|
||||
const entry = JSON.parse(newValue);
|
||||
dispatch(apiReducer.actions.loyaltyUserPointsChanged({ user, entry }));
|
||||
};
|
||||
client.subscribePrefix(prefix, subscriber);
|
||||
return () => {
|
||||
client.subscribePrefix(prefix, subscriber);
|
||||
};
|
||||
}, []);
|
||||
return data;
|
||||
}
|
||||
|
||||
export default {
|
||||
useModule,
|
||||
useUserPoints,
|
||||
};
|
||||
|
|
|
@ -208,7 +208,6 @@ export const getUserPoints = createAsyncThunk(
|
|||
async (_: void, { getState }) => {
|
||||
const { api } = getState() as { api: APIState };
|
||||
const keys = await api.client.getKeysByPrefix(loyaltyPointsPrefix);
|
||||
console.log(keys);
|
||||
const userpoints: LoyaltyStorage = {};
|
||||
Object.entries(keys).forEach(([k, v]) => {
|
||||
userpoints[k.substr(loyaltyPointsPrefix.length)] = JSON.parse(v);
|
||||
|
@ -217,6 +216,25 @@ export const getUserPoints = createAsyncThunk(
|
|||
},
|
||||
);
|
||||
|
||||
export const setUserPoints = createAsyncThunk(
|
||||
'api/setUserPoints',
|
||||
async (
|
||||
{
|
||||
user,
|
||||
points,
|
||||
relative,
|
||||
}: { user: string; points: number; relative: boolean },
|
||||
{ getState },
|
||||
) => {
|
||||
const { api } = getState() as { api: APIState };
|
||||
const entry: LoyaltyPointsEntry = { points };
|
||||
if (relative) {
|
||||
entry.points += api.loyalty.users[user].points ?? 0;
|
||||
}
|
||||
return api.client.putJSON(loyaltyPointsPrefix + user, entry);
|
||||
},
|
||||
);
|
||||
|
||||
export const modules = {
|
||||
moduleConfig: makeModule<ModuleConfig>(
|
||||
moduleConfigKey,
|
||||
|
@ -333,6 +351,14 @@ const apiReducer = createSlice({
|
|||
loyaltyGoalsChanged(state, { payload }: PayloadAction<LoyaltyGoal[]>) {
|
||||
state.loyalty.goals = payload;
|
||||
},
|
||||
loyaltyUserPointsChanged(
|
||||
state,
|
||||
{
|
||||
payload: { user, entry },
|
||||
}: PayloadAction<{ user: string; entry: LoyaltyPointsEntry }>,
|
||||
) {
|
||||
state.loyalty.users[user] = entry;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(createWSClient.fulfilled, (state, { payload }) => {
|
||||
|
|
|
@ -141,7 +141,7 @@ function GoalModal({
|
|||
setID(newID.toLowerCase().replace(/[^a-zA-Z0-9]/gi, '-'));
|
||||
|
||||
const slug = id || name?.toLowerCase().replace(/[^a-zA-Z0-9]/gi, '-') || '';
|
||||
const idExists = goals?.some((reward) => reward.id === slug) ?? false;
|
||||
const idExists = goals?.some((goal) => goal.id === slug) ?? false;
|
||||
const idInvalid = slug !== initialData?.id && idExists;
|
||||
|
||||
const validForm = idInvalid === false && name !== '' && total >= 0;
|
||||
|
@ -175,7 +175,7 @@ function GoalModal({
|
|||
>
|
||||
<div className="field is-horizontal">
|
||||
<div className="field-label is-normal">
|
||||
<label className="label">Reward ID</label>
|
||||
<label className="label">Goal ID</label>
|
||||
</div>
|
||||
<div className="field-body">
|
||||
<div className="field">
|
||||
|
@ -183,20 +183,20 @@ function GoalModal({
|
|||
<input
|
||||
className={idInvalid ? 'input is-danger' : 'input'}
|
||||
type="text"
|
||||
placeholder="reward_id_here"
|
||||
placeholder="goal_id_here"
|
||||
value={slug}
|
||||
onChange={(ev) => setIDex(ev.target.value)}
|
||||
/>
|
||||
</p>
|
||||
{idInvalid ? (
|
||||
<p className="help is-danger">
|
||||
There is already a reward with this ID! Please choose a
|
||||
different one.
|
||||
There is already a goal with this ID! Please choose a different
|
||||
one.
|
||||
</p>
|
||||
) : (
|
||||
<p className="help">
|
||||
Choose a simple name that can be referenced by other software.
|
||||
It will be auto-generated from the reward name if you leave it
|
||||
It will be auto-generated from the goal name if you leave it
|
||||
blank.
|
||||
</p>
|
||||
)}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import React, { useState } from 'react';
|
||||
import { RouteComponentProps } from '@reach/router';
|
||||
import PageList from '../../components/PageList';
|
||||
import { RootState } from '../../../store';
|
||||
import { getUserPoints } from '../../../store/api/reducer';
|
||||
import { useUserPoints } from '../../../lib/react-utils';
|
||||
|
||||
interface SortingOrder {
|
||||
key: 'user' | 'points';
|
||||
|
@ -13,17 +11,12 @@ export default function LoyaltyUserListPage(
|
|||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
props: RouteComponentProps<unknown>,
|
||||
): React.ReactElement {
|
||||
const users = useSelector((state: RootState) => state.api.loyalty.users);
|
||||
const dispatch = useDispatch();
|
||||
const users = useUserPoints();
|
||||
const [sorting, setSorting] = useState<SortingOrder>({
|
||||
key: 'points',
|
||||
order: 'desc',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(getUserPoints());
|
||||
}, []);
|
||||
|
||||
const [entriesPerPage, setEntriesPerPage] = useState(15);
|
||||
const [page, setPage] = useState(0);
|
||||
const [usernameFilter, setUsernameFilter] = useState('');
|
||||
|
|
Loading…
Reference in a new issue