diff --git a/frontend/package.json b/frontend/package.json index 8d70ee3..ce92741 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,8 +27,8 @@ ], "devDependencies": { "@parcel/transformer-sass": "^2.0.0-beta.2", - "@typescript-eslint/eslint-plugin": "^4.6.1", - "@typescript-eslint/parser": "^4.6.1", + "@typescript-eslint/eslint-plugin": "^4.22.0", + "@typescript-eslint/parser": "^4.22.0", "eslint": "^7.12.1", "eslint-config-airbnb-base": "^14.2.0", "eslint-config-prettier": "^6.15.0", diff --git a/frontend/src/lib/strimertul-ws.ts b/frontend/src/lib/strimertul-ws.ts index 6d6929a..b4550ec 100644 --- a/frontend/src/lib/strimertul-ws.ts +++ b/frontend/src/lib/strimertul-ws.ts @@ -1,7 +1,5 @@ export type SubscriptionHandler = (newValue: string) => void; -export type wsMessage = wsError | wsPush | wsResponse; - interface wsError { ok: false; error: string; @@ -21,6 +19,8 @@ interface wsResponse { data?: string; } +export type wsMessage = wsError | wsPush | wsResponse; + export default class StrimertulWS { socket: WebSocket; diff --git a/frontend/src/store/api/reducer.ts b/frontend/src/store/api/reducer.ts index 0cb1583..7453723 100644 --- a/frontend/src/store/api/reducer.ts +++ b/frontend/src/store/api/reducer.ts @@ -245,6 +245,39 @@ export const modules = { ), }; +export const setUserPoints = createAsyncThunk( + 'api/setUserPoints', + async ( + { + user, + points, + relative, + }: { user: string; points: number; relative: boolean }, + { getState, dispatch }, + ) => { + const { api } = getState() as { api: APIState }; + const newAmount = relative + ? (api.loyalty.users[user] ?? 0) + points + : points; + return dispatch( + modules.loyaltyStorage.setter({ + ...api.loyalty.users, + [user]: newAmount, + }), + ); + }, +); + +export const createRedeem = createAsyncThunk( + 'api/createRedeem', + async (redeem: LoyaltyRedeem, { getState, dispatch }) => { + const { api } = getState() as { api: APIState }; + return dispatch( + modules.loyaltyRedeemQueue.setter([...api.loyalty.redeemQueue, redeem]), + ); + }, +); + const apiReducer = createSlice({ name: 'api', initialState, diff --git a/frontend/src/ui/pages/loyalty/Queue.tsx b/frontend/src/ui/pages/loyalty/Queue.tsx index b4d853c..633d8a8 100644 --- a/frontend/src/ui/pages/loyalty/Queue.tsx +++ b/frontend/src/ui/pages/loyalty/Queue.tsx @@ -2,7 +2,11 @@ import React, { useState } from 'react'; import { useDispatch } from 'react-redux'; import { RouteComponentProps } from '@reach/router'; import { useModule } from '../../../lib/react-utils'; -import { LoyaltyRedeem, modules } from '../../../store/api/reducer'; +import { + LoyaltyRedeem, + modules, + setUserPoints, +} from '../../../store/api/reducer'; import PageList from '../../components/PageList'; interface SortingOrder { @@ -15,7 +19,6 @@ export default function LoyaltyRedeemQueuePage( props: RouteComponentProps, ): React.ReactElement { const [redemptions, setRedeemQueue] = useModule(modules.loyaltyRedeemQueue); - const [points, setPoints] = useModule(modules.loyaltyStorage); const [sorting, setSorting] = useState({ key: 'when', @@ -86,9 +89,10 @@ export default function LoyaltyRedeemQueuePage( const refundRedeem = (redeem: LoyaltyRedeem) => { // Give points back to the viewer dispatch( - setPoints({ - ...points, - [redeem.username]: (points[redeem.username] ?? 0) + redeem.reward.price, + setUserPoints({ + user: redeem.username, + points: redeem.reward.price, + relative: true, }), ); // Take the redeem off the list @@ -157,8 +161,12 @@ export default function LoyaltyRedeemQueuePage( {redemption.reward.name} acceptRedeem(redemption)}>Accept - {' 🞄 '} - refundRedeem(redemption)}>Refund + {redemption.username !== '@PLATFORM' ? ( + <> + {' 🞄 '} + refundRedeem(redemption)}>Refund + + ) : null} ))} diff --git a/frontend/src/ui/pages/loyalty/Rewards.tsx b/frontend/src/ui/pages/loyalty/Rewards.tsx index cafb20d..bdbc149 100644 --- a/frontend/src/ui/pages/loyalty/Rewards.tsx +++ b/frontend/src/ui/pages/loyalty/Rewards.tsx @@ -3,7 +3,11 @@ import React, { useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { useModule } from '../../../lib/react-utils'; import { RootState } from '../../../store'; -import { LoyaltyReward, modules } from '../../../store/api/reducer'; +import { + createRedeem, + LoyaltyReward, + modules, +} from '../../../store/api/reducer'; import Modal from '../../components/Modal'; interface RewardItemProps { @@ -11,12 +15,14 @@ interface RewardItemProps { onToggleState: () => void; onEdit: () => void; onDelete: () => void; + onTest: () => void; } function RewardItem({ item, onToggleState, onEdit, onDelete, + onTest, }: RewardItemProps) { const currency = useSelector( (state: RootState) => @@ -71,6 +77,9 @@ function RewardItem({ ) : null}
+ + Test + {' '} {item.enabled ? 'Disable' : 'Enable'} {' '} @@ -358,6 +367,17 @@ export default function LoyaltyRewardsPage( dispatch(setRewards(rewards.filter((entry) => entry.id !== rewardID))); }; + const testRedeem = (reward: LoyaltyReward) => { + dispatch( + createRedeem({ + username: '@PLATFORM', + display_name: 'me :3', + when: new Date(), + reward, + }), + ); + }; + return ( <>

Loyalty rewards

@@ -413,6 +433,7 @@ export default function LoyaltyRewardsPage( onDelete={() => deleteReward(reward.id)} onEdit={() => setShowModifyReward(reward)} onToggleState={() => toggleReward(reward.id)} + onTest={() => testRedeem(reward)} /> ))}
diff --git a/main.go b/main.go index eb915a1..47d0332 100644 --- a/main.go +++ b/main.go @@ -218,6 +218,7 @@ func main() { }) if moduleConfig.EnableStaticServer { http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(httpConfig.Path)))) + httpLogger(logger.MTNotice, "serving %s", httpConfig.Path) } go func() { @@ -226,7 +227,6 @@ func main() { }() // Start HTTP server - httpLogger(logger.MTNotice, "serving %s", httpConfig.Path) fatalError(http.ListenAndServe(httpConfig.Bind, nil), "HTTP server died unexepectedly") }