mirror of
https://git.sr.ht/~ashkeel/strimertul
synced 2024-09-20 02:00:49 +00:00
Add test redeem button
This commit is contained in:
parent
c77d7c7a74
commit
61212f249c
6 changed files with 75 additions and 13 deletions
|
@ -27,8 +27,8 @@
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@parcel/transformer-sass": "^2.0.0-beta.2",
|
"@parcel/transformer-sass": "^2.0.0-beta.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.6.1",
|
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||||
"@typescript-eslint/parser": "^4.6.1",
|
"@typescript-eslint/parser": "^4.22.0",
|
||||||
"eslint": "^7.12.1",
|
"eslint": "^7.12.1",
|
||||||
"eslint-config-airbnb-base": "^14.2.0",
|
"eslint-config-airbnb-base": "^14.2.0",
|
||||||
"eslint-config-prettier": "^6.15.0",
|
"eslint-config-prettier": "^6.15.0",
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
export type SubscriptionHandler = (newValue: string) => void;
|
export type SubscriptionHandler = (newValue: string) => void;
|
||||||
|
|
||||||
export type wsMessage = wsError | wsPush | wsResponse;
|
|
||||||
|
|
||||||
interface wsError {
|
interface wsError {
|
||||||
ok: false;
|
ok: false;
|
||||||
error: string;
|
error: string;
|
||||||
|
@ -21,6 +19,8 @@ interface wsResponse {
|
||||||
data?: string;
|
data?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type wsMessage = wsError | wsPush | wsResponse;
|
||||||
|
|
||||||
export default class StrimertulWS {
|
export default class StrimertulWS {
|
||||||
socket: WebSocket;
|
socket: WebSocket;
|
||||||
|
|
||||||
|
|
|
@ -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({
|
const apiReducer = createSlice({
|
||||||
name: 'api',
|
name: 'api',
|
||||||
initialState,
|
initialState,
|
||||||
|
|
|
@ -2,7 +2,11 @@ import React, { useState } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { RouteComponentProps } from '@reach/router';
|
import { RouteComponentProps } from '@reach/router';
|
||||||
import { useModule } from '../../../lib/react-utils';
|
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';
|
import PageList from '../../components/PageList';
|
||||||
|
|
||||||
interface SortingOrder {
|
interface SortingOrder {
|
||||||
|
@ -15,7 +19,6 @@ export default function LoyaltyRedeemQueuePage(
|
||||||
props: RouteComponentProps<unknown>,
|
props: RouteComponentProps<unknown>,
|
||||||
): React.ReactElement {
|
): React.ReactElement {
|
||||||
const [redemptions, setRedeemQueue] = useModule(modules.loyaltyRedeemQueue);
|
const [redemptions, setRedeemQueue] = useModule(modules.loyaltyRedeemQueue);
|
||||||
const [points, setPoints] = useModule(modules.loyaltyStorage);
|
|
||||||
|
|
||||||
const [sorting, setSorting] = useState<SortingOrder>({
|
const [sorting, setSorting] = useState<SortingOrder>({
|
||||||
key: 'when',
|
key: 'when',
|
||||||
|
@ -86,9 +89,10 @@ export default function LoyaltyRedeemQueuePage(
|
||||||
const refundRedeem = (redeem: LoyaltyRedeem) => {
|
const refundRedeem = (redeem: LoyaltyRedeem) => {
|
||||||
// Give points back to the viewer
|
// Give points back to the viewer
|
||||||
dispatch(
|
dispatch(
|
||||||
setPoints({
|
setUserPoints({
|
||||||
...points,
|
user: redeem.username,
|
||||||
[redeem.username]: (points[redeem.username] ?? 0) + redeem.reward.price,
|
points: redeem.reward.price,
|
||||||
|
relative: true,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
// Take the redeem off the list
|
// Take the redeem off the list
|
||||||
|
@ -157,8 +161,12 @@ export default function LoyaltyRedeemQueuePage(
|
||||||
<td>{redemption.reward.name}</td>
|
<td>{redemption.reward.name}</td>
|
||||||
<td style={{ textAlign: 'right' }}>
|
<td style={{ textAlign: 'right' }}>
|
||||||
<a onClick={() => acceptRedeem(redemption)}>Accept</a>
|
<a onClick={() => acceptRedeem(redemption)}>Accept</a>
|
||||||
{' 🞄 '}
|
{redemption.username !== '@PLATFORM' ? (
|
||||||
<a onClick={() => refundRedeem(redemption)}>Refund</a>
|
<>
|
||||||
|
{' 🞄 '}
|
||||||
|
<a onClick={() => refundRedeem(redemption)}>Refund</a>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -3,7 +3,11 @@ import React, { useState } from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import { useModule } from '../../../lib/react-utils';
|
import { useModule } from '../../../lib/react-utils';
|
||||||
import { RootState } from '../../../store';
|
import { RootState } from '../../../store';
|
||||||
import { LoyaltyReward, modules } from '../../../store/api/reducer';
|
import {
|
||||||
|
createRedeem,
|
||||||
|
LoyaltyReward,
|
||||||
|
modules,
|
||||||
|
} from '../../../store/api/reducer';
|
||||||
import Modal from '../../components/Modal';
|
import Modal from '../../components/Modal';
|
||||||
|
|
||||||
interface RewardItemProps {
|
interface RewardItemProps {
|
||||||
|
@ -11,12 +15,14 @@ interface RewardItemProps {
|
||||||
onToggleState: () => void;
|
onToggleState: () => void;
|
||||||
onEdit: () => void;
|
onEdit: () => void;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
|
onTest: () => void;
|
||||||
}
|
}
|
||||||
function RewardItem({
|
function RewardItem({
|
||||||
item,
|
item,
|
||||||
onToggleState,
|
onToggleState,
|
||||||
onEdit,
|
onEdit,
|
||||||
onDelete,
|
onDelete,
|
||||||
|
onTest,
|
||||||
}: RewardItemProps) {
|
}: RewardItemProps) {
|
||||||
const currency = useSelector(
|
const currency = useSelector(
|
||||||
(state: RootState) =>
|
(state: RootState) =>
|
||||||
|
@ -71,6 +77,9 @@ function RewardItem({
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
<div style={{ marginTop: '1rem' }}>
|
<div style={{ marginTop: '1rem' }}>
|
||||||
|
<a className="button is-small" onClick={onTest}>
|
||||||
|
Test
|
||||||
|
</a>{' '}
|
||||||
<a className="button is-small" onClick={onToggleState}>
|
<a className="button is-small" onClick={onToggleState}>
|
||||||
{item.enabled ? 'Disable' : 'Enable'}
|
{item.enabled ? 'Disable' : 'Enable'}
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
|
@ -358,6 +367,17 @@ export default function LoyaltyRewardsPage(
|
||||||
dispatch(setRewards(rewards.filter((entry) => entry.id !== rewardID)));
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1 className="title is-4">Loyalty rewards</h1>
|
<h1 className="title is-4">Loyalty rewards</h1>
|
||||||
|
@ -413,6 +433,7 @@ export default function LoyaltyRewardsPage(
|
||||||
onDelete={() => deleteReward(reward.id)}
|
onDelete={() => deleteReward(reward.id)}
|
||||||
onEdit={() => setShowModifyReward(reward)}
|
onEdit={() => setShowModifyReward(reward)}
|
||||||
onToggleState={() => toggleReward(reward.id)}
|
onToggleState={() => toggleReward(reward.id)}
|
||||||
|
onTest={() => testRedeem(reward)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
2
main.go
2
main.go
|
@ -218,6 +218,7 @@ func main() {
|
||||||
})
|
})
|
||||||
if moduleConfig.EnableStaticServer {
|
if moduleConfig.EnableStaticServer {
|
||||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(httpConfig.Path))))
|
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(httpConfig.Path))))
|
||||||
|
httpLogger(logger.MTNotice, "serving %s", httpConfig.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -226,7 +227,6 @@ func main() {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Start HTTP server
|
// Start HTTP server
|
||||||
httpLogger(logger.MTNotice, "serving %s", httpConfig.Path)
|
|
||||||
fatalError(http.ListenAndServe(httpConfig.Bind, nil), "HTTP server died unexepectedly")
|
fatalError(http.ListenAndServe(httpConfig.Bind, nil), "HTTP server died unexepectedly")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue