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