wants list redux and removal

This commit is contained in:
ntr committed 2022-09-15 23:00:35 +10:00
1 parent 70a67b0c53
commit 12c3da9f5e
8 files changed
+86 -18

No files matched your search

+1 -1
View File
@@ -28,7 +28,7 @@ async function start() {
events, events,
} = createServices(log); } = createServices(log);
events.emit(Events.StartupSync); // events.emit(Events.StartupSync);
api.listen(); api.listen();
} }
+2
View File
@@ -177,6 +177,8 @@ export default function createApi(log: Log, pg: Pg, discogs, offers, events) {
ws.on('close', function onClose() { ws.on('close', function onClose() {
log.info('ws disconnected', { user: ctx.state.user }); log.info('ws disconnected', { user: ctx.state.user });
}); });
await rpc.onConnection();
}); });
return { return {
+30 -1
View File
@@ -23,7 +23,6 @@ export default function createRpc(log: Log, pg: Pg, user: User, ws, discogs, off
} }
async function offerStatusSet(params: OfferStatusSetParams): Promise<OffersMessage> { async function offerStatusSet(params: OfferStatusSetParams): Promise<OffersMessage> {
log.info(params);
const { id, status } = params; const { id, status } = params;
assert(id, 'no id supplied'); assert(id, 'no id supplied');
assert(Status[status], 'unknown status'); assert(Status[status], 'unknown status');
@@ -32,6 +31,16 @@ export default function createRpc(log: Log, pg: Pg, user: User, ws, discogs, off
return [RpcMessageType.Offers, []] return [RpcMessageType.Offers, []]
} }
async function wantRm(params: WantRmParams): Promise<WantsMessage> {
const { id } = params;
assert(id, 'no id supplied');
await pg.wantRm(id);
const wants = await pg.userWants(user);
return [RpcMessageType.Wants, wants];
}
async function receive(message: any): Promise<RpcMessage> { async function receive(message: any): Promise<RpcMessage> {
const [msgType, params] = message; const [msgType, params] = message;
@@ -44,6 +53,8 @@ export default function createRpc(log: Log, pg: Pg, user: User, ws, discogs, off
return ping(); return ping();
case RpcMessageType.OfferStatusSet: case RpcMessageType.OfferStatusSet:
return offerStatusSet(params); return offerStatusSet(params);
case RpcMessageType.WantRm:
return wantRm(params);
default: default:
throw new Error(`Message type ${msgType} is known but unhandled`); throw new Error(`Message type ${msgType} is known but unhandled`);
} }
@@ -54,6 +65,12 @@ export default function createRpc(log: Log, pg: Pg, user: User, ws, discogs, off
throw new Error(`Invalid parameters for message type ${msgType}: ${JSON.stringify(message)}`); throw new Error(`Invalid parameters for message type ${msgType}: ${JSON.stringify(message)}`);
} }
async function onConnection() {
const wants = await pg.userWants(user);
const wantsMsg: WantsMessage = [RpcMessageType.Wants, wants];
send(wantsMsg);
}
function send(msg: RpcMessage) { function send(msg: RpcMessage) {
ws.send(JSON.stringify(msg, (key, value) => ws.send(JSON.stringify(msg, (key, value) =>
typeof value === 'bigint' typeof value === 'bigint'
@@ -65,6 +82,7 @@ export default function createRpc(log: Log, pg: Pg, user: User, ws, discogs, off
return { return {
receive, receive,
send, send,
onConnection,
} }
} }
@@ -78,17 +96,24 @@ export enum RpcMessageType {
Error = 'Error', Error = 'Error',
OfferStatusSet = 'OfferStatusSet', OfferStatusSet = 'OfferStatusSet',
Wants = 'Wants',
WantRm = 'WantRm',
} }
type ErrorMessage = [RpcMessageType.Error, string]; type ErrorMessage = [RpcMessageType.Error, string];
type PongMessage = [RpcMessageType.Pong, []]; type PongMessage = [RpcMessageType.Pong, []];
type PingMessage = [RpcMessageType.Ping, []]; type PingMessage = [RpcMessageType.Ping, []];
type WantsMessage = [RpcMessageType.Wants, Want[]];
type OffersMessage = [RpcMessageType.Offers, Offer[]]; type OffersMessage = [RpcMessageType.Offers, Offer[]];
type OfferStatusSetMessage = [RpcMessageType.OfferStatusSet, Offer[]]; type OfferStatusSetMessage = [RpcMessageType.OfferStatusSet, Offer[]];
export type RpcMessage = export type RpcMessage =
PingMessage | PingMessage |
PongMessage | PongMessage |
WantsMessage |
OffersMessage | OffersMessage |
OfferStatusSetMessage | OfferStatusSetMessage |
ErrorMessage; ErrorMessage;
@@ -98,3 +123,7 @@ type OfferStatusSetParams = {
id: UUID, id: UUID,
status: Status, status: Status,
}; };
type WantRmParams = {
id: UUID,
};
+20 -1
View File
@@ -1,9 +1,27 @@
import { h } from 'preact'; import { h } from 'preact';
import { useState, useCallback } from 'preact/hooks';
import { useSelector } from 'react-redux'
import { State } from './../store'
import http from './../http';
function Want(want) { function Want(want) {
console.log(want);
const r = want.data; const r = want.data;
const ws = useSelector((state: State) => state.ws);
const [confirm, setConfirm] = useState(false);
function onClick() {
if (confirm) return ws.sendWantRm(want.id);
setTimeout(() => setConfirm(false), 2500);
return setConfirm(true);
};
const text = confirm
? 'confirm'
: 'remove';
return ( return (
<article key={r.id}> <article key={r.id}>
<div> <div>
@@ -12,6 +30,7 @@ function Want(want) {
<h5 class='alt-text'>{r.formats[0].descriptions.join(' ')}</h5> <h5 class='alt-text'>{r.formats[0].descriptions.join(' ')}</h5>
</div> </div>
<img src={r.thumb} /> <img src={r.thumb} />
<button onClick={onClick} >{text}</button>
</article> </article>
); );
} }
+4 -11
View File
@@ -1,6 +1,9 @@
import { h } from 'preact'; import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks'; import { useState, useEffect } from 'preact/hooks';
import { useSelector } from 'react-redux'
import { State } from './../store'
// import style from './style.less'; // import style from './style.less';
import http from './../http'; import http from './../http';
import Want from './../components/want'; import Want from './../components/want';
@@ -12,17 +15,7 @@ interface Props {
} }
const List = ({ user }: Props) => { const List = ({ user }: Props) => {
const [wants, setOffers] = useState([]); const wants = useSelector((state: State) => state.wants);
useEffect(() => {
async function getWants() {
const [error, wants] = await http.getWants();
if (error) return console.error(error);
setOffers(wants);
}
getWants();
}, []);
if (!wants.length) { if (!wants.length) {
return <div> loading... </div>; return <div> loading... </div>;
+10 -1
View File
@@ -17,6 +17,14 @@ export const offersState = createSlice({
}, },
}); });
export const wantsState = createSlice({
name: 'wants',
initialState: [],
reducers: {
set: (state, action) => action.payload
},
});
export const wsState = createSlice({ export const wsState = createSlice({
name: 'ws', name: 'ws',
initialState: null, initialState: null,
@@ -26,9 +34,10 @@ export const wsState = createSlice({
}); });
const reducer = combineReducers({ const reducer = combineReducers({
user: userState.reducer,
offers: offersState.reducer, offers: offersState.reducer,
wants: wantsState.reducer,
ws: wsState.reducer, ws: wsState.reducer,
user: userState.reducer,
}); });
const store = createStore( const store = createStore(
+9
View File
@@ -232,6 +232,15 @@ article {
1fr 1fr 1fr 1fr; 1fr 1fr 1fr 1fr;
article { article {
display: grid;
grid-template-areas:
"title img"
"remove remove";
button {
grid-area: remove
}
padding: var(--base-spacing); padding: var(--base-spacing);
margin: var(--base-spacing-half); margin: var(--base-spacing-half);
} }
+10 -3
View File
@@ -1,5 +1,7 @@
const SOCKET_URL = `${window.location.protocol === 'https:' ? 'wss://' : 'ws://'}${window.location.host}/api/ws`; const SOCKET_URL = `${window.location.protocol === 'https:' ? 'wss://' : 'ws://'}${window.location.host}/api/ws`;
import { wantsState, wsState } from './store'
export default function createSocket(store) { export default function createSocket(store) {
let ws; let ws;
@@ -28,6 +30,10 @@ export default function createSocket(store) {
send(['OfferStatusSet', { id, status }]); send(['OfferStatusSet', { id, status }]);
} }
function sendWantRm(id) {
send(['WantRm', { id }]);
}
let pongTimeout; let pongTimeout;
function onPong() { function onPong() {
pongTimeout = setTimeout(sendPing, 5000); pongTimeout = setTimeout(sendPing, 5000);
@@ -36,8 +42,8 @@ export default function createSocket(store) {
// ------------- // -------------
// Incoming // Incoming
// ------------- // -------------
function onSourcesAvailable(clouds) { function onWants(wants) {
// store.dispatch(http.LIBRARY_RECEIVE_POINTCLOUDS, clouds); store.dispatch(wantsState.actions.set(wants));
} }
// ------------- // -------------
@@ -46,7 +52,7 @@ export default function createSocket(store) {
// when the server sends a reply it will have one of these message types // when the server sends a reply it will have one of these message types
// this object wraps the reply types to a function // this object wraps the reply types to a function
const handlers = { const handlers = {
SourcesAvailable: onSourcesAvailable, Wants: onWants,
Pong: onPong, Pong: onPong,
Error: errHandler, Error: errHandler,
@@ -109,5 +115,6 @@ export default function createSocket(store) {
connect, connect,
sendOfferStatusSet, sendOfferStatusSet,
sendWantRm,
}; };
} }