navbar and notifications

This commit is contained in:
ntr committed 2023-01-17 23:44:16 +11:00
1 parent a97560c1c7
commit 5b0c7c05ca
11 files changed
+65 -46

No files matched your search

+2 -2
View File
@@ -3,9 +3,9 @@ push offers
add last synced time to want
contact options on landing page
go over and reorganise event logic
move want add to rpc
contact options on landing page
skip unofficial release
+5
View File
@@ -11,6 +11,11 @@ datasource db {
}
model Listing {
// example listingId 2148851036
// works fine as a JS number
// but JS numbers are cast to int4 for pg by prisma
// becomes -2146116260
id BigInt @id
seller BigInt
data Json
-10
View File
@@ -63,16 +63,6 @@ export default function createApi(log: Log, pg: Pg, discogs: Discogs, offers: Of
ctx.status = 200;
});
router.post('/want', async function wantPost(ctx, next) {
ctx.assert(ctx.isAuthenticated(), 401, 'log in required');
const { releaseId } = ctx.request.body;
const user = await pg.userFindId(ctx.state.user.id);
const release = await discogs.release(releaseId);
const want = await pg.wantCreate(release, user);
events.emit(Events.WantsAdded, [want]);
ctx.response.body = [want];
});
router.post('/want/discogs', async function wantListPost(ctx, next) {
ctx.assert(ctx.isAuthenticated(), 401, 'log in required');
const { username } = ctx.request.body;
+11 -7
View File
@@ -12,11 +12,11 @@ import routerAuth from './routers/router.auth';
export enum Events {
WantsAdded = 'WantsAdded',
Sync = 'Sync',
ListingsUpdated = 'ListingsUpdated',
Connection = 'Connection',
OfferUpdated = 'OfferUpdated',
WantUpdated = 'WantUpdated',
ListingsUpdated = 'ListingsUpdated',
OffersUpdated = 'OffersUpdated',
WantsUpdated = 'WantsUpdated',
}
export default function createEvents(log: Log, pg: Pg, discogs, offers) {
@@ -68,6 +68,10 @@ export default function createEvents(log: Log, pg: Pg, discogs, offers) {
events.on(Events.ListingsUpdated, async function listingsUpdated() {
const updatedOffers = await offers.generate()
log.debug({ offers: updatedOffers.length }, 'offers up to date');
for (const [id, rpc] of connections) {
rpc.pushUserOffers();
}
});
events.on(Events.Connection, async function onConnection({ rpc, id }) {
@@ -75,17 +79,17 @@ export default function createEvents(log: Log, pg: Pg, discogs, offers) {
connections.set(id, rpc);
})
events.on(Events.OfferUpdated, async function onOfferUpdated(offer: Offer) {
events.on(Events.OffersUpdated, async function onOffersUpdated(offer: Offer) {
const rpc = connections.get(offer.userId);
if (!rpc) return null;
log.debug({ event: Events.OfferUpdated, rpc, offer });
log.debug({ event: Events.OffersUpdated, rpc, offer });
return rpc.pushUserOffers();
});
events.on(Events.WantUpdated, async function onWantUpdated(want: Want) {
events.on(Events.WantsUpdated, async function onWantsUpdated(want: Want) {
const rpc = connections.get(want.userId);
if (!rpc) return null;
log.debug({ event: Events.WantUpdated, rpc, want });
log.debug({ event: Events.WantsUpdated, rpc, want });
return rpc.pushUserWants();
});
+3 -2
View File
@@ -21,8 +21,8 @@ export default function createNotify(log: Log, pg: Pg, events) {
log.debug({ channel: OFFERS_CHANNEL, action, id });
if (action === 'DELETE') return null;
const offer = await pg.offerFindId(id);
// events.emit(Events.OfferUpdated, offer);
// const offer = await pg.offerFindId(id);
// events.emit(Events.OffersUpdated, offer);
}
async function handleUsers(payload) {
@@ -37,6 +37,7 @@ export default function createNotify(log: Log, pg: Pg, events) {
async function handleWants(payload) {
const { action, id } = payload;
// const want = await pg.offerFindId(id);
log.debug({ channel: WANTS_CHANNEL, action, id });
}
+6
View File
@@ -98,6 +98,12 @@ export default function createPg(log: Log, prisma: PrismaClient) {
});
}
async function wantFindId(id: UUID) {
return prisma.want.findFirstOrThrow({
where: { id },
});
}
async function wantList(user: User) {
return prisma.want.findMany({
where: { userId: user.id },
+19
View File
@@ -37,6 +37,7 @@ export enum RpcMessageType {
AcpListingsSync = 'AcpListingsSync',
WantRm = 'WantRm',
WantAdd = 'WantAdd',
}
type ErrorMessage = [RpcMessageType.Error, string];
@@ -82,6 +83,10 @@ type WantRmParams = {
id: UUID,
};
type WantAddParams = {
releaseId: number,
};
function checkMsgType(msgType: RpcMessageType): msgType is RpcMessageType {
if (RpcMessageType[msgType]) {
return true;
@@ -124,6 +129,18 @@ export default function createRpc(log: Log, pg: Pg, ws, discogs: Discogs, offers
return [RpcMessageType.Wants, wants];
}
async function wantAdd(params: WantAddParams): Promise<WantsMessage> {
const { releaseId } = params;
assert(releaseId, 'no id supplied');
const release = await discogs.release(releaseId);
const want = await pg.wantCreate(release, user);
events.emit(Events.WantsAdded, [want]);
const wants = await pg.userWants(user);
return [RpcMessageType.Wants, wants];
}
async function acpOfferStatusSet(params: OfferStatusSetParams): Promise<AcpOffersMessage> {
const { id, status } = params;
assert(isAdmin(user), 'not authorised');
@@ -171,6 +188,8 @@ export default function createRpc(log: Log, pg: Pg, ws, discogs: Discogs, offers
case RpcMessageType.WantRm:
return wantRm(params);
case RpcMessageType.WantAdd:
return wantAdd(params);
case RpcMessageType.AcpOfferStatusSet:
return acpOfferStatusSet(params);
+5 -1
View File
@@ -49,8 +49,12 @@ function OfferPriceBtn(offer) {
? offer.status
: 'Accept';
const title = accepted
? 'Click to cancel'
: 'Click to accept this offer';
return (
<button disabled={confirmed} onClick={() => setStatus()} class={classes}>${offer.total} {offer.condition}</button>
<button disabled={confirmed} title={title} onClick={() => setStatus()} class={classes}>${offer.total} {offer.condition}</button>
)
}
-13
View File
@@ -33,15 +33,10 @@ api.interceptors.response.use(onSuccess, onError);
const actions = {
// TODO move to rpc
postWantSearch: async function postWantSearch(query) {
return api.post('/want/search', { query });
},
postWant: async function postWant(releaseId) {
return api.post('/want', { releaseId });
},
postDiscogs: async function postDiscogs(username) {
return api.post('/want/discogs', { username });
},
@@ -71,14 +66,6 @@ const actions = {
password,
});
},
postOffers: async function postOffers(listingIds, shipping, baseShipping) {
return api.post('/offers', {
listingIds,
shipping,
baseShipping,
});
},
};
export default actions;
+9 -11
View File
@@ -7,25 +7,22 @@ import { State } from './../store';
import http from '../http';
function Result(r, wants) {
const [added, setAdded] = useState(false)
function Result(r, wants, ws) {
async function onClick() {
const [error, want] = await http.postWant(r.id);
if (error) return false;
setAdded(true);
ws.sendWantAdd(r.id);
}
const wanted = wants.some(w => w.release === r.id);
// releaseIds are bigints on server
const wanted = wants.some(w => BigInt(w.release) === BigInt(r.id));
const classes = `${added || wanted ? 'added' : ''}`;
const btnText = added
const classes = `${wanted ? 'added' : ''}`;
const btnText = wanted
? <Check />
: '+';
return (
<article key={r.id}>
<button onClick={onClick} disabled={added} class={classes} >{btnText}</button>
<button onClick={onClick} disabled={wanted} class={classes} >{btnText}</button>
<div>
<h3>{r.title} <a href={`https://discogs.com${r.uri}`} target="_blank"><ExternalLink /></a></h3>
<h5 class='alt-text' >{r.year}</h5>
@@ -45,6 +42,7 @@ const User = () => {
const [infoText, setInfoText] = useState('');
const wants = useSelector((state: State) => state.wants);
const ws = useSelector((state: State) => state.ws);
async function fetchResults() {
const [error, results] = await http.postWantSearch(query);
@@ -114,7 +112,7 @@ const User = () => {
</div>
<div class='results' ref={resultsRef}>
{infoEl}
{results.map(r => Result(r, wants))}
{results.map(r => Result(r, wants, ws))}
{topEl}
</div>
</div>
+5
View File
@@ -37,6 +37,10 @@ export default function createSocket(dispatch) {
send(['WantRm', { id }]);
}
function sendWantAdd(releaseId) {
send(['WantAdd', { releaseId }]);
}
function sendOffers() {
send(['Offers', {}]);
}
@@ -157,6 +161,7 @@ export default function createSocket(dispatch) {
sendOfferStatusSet,
sendWantRm,
sendWantAdd,
sendOffers,
sendWants,