Kako izgraditi chat između kupaca i prodavatelja za marketplace u Next.js-u

Chat između kupaca i prodavatelja izgleda kao jedna značajka, a u marketplaceu izgrađenom u Next.js-u riječ je o nekoliko njih. Osoba koja kupuje pita o artiklu i dobije odgovor dok ga još gleda. Razgovor pripada samo tim dvjema osobama, s fotografijama koje nitko drugi ne može otvoriti. Ponekad fotografija nije dovoljna, i kratak videopoziv pokaže artikl prije nego što itko krene na put. Ponuda mora stići do osobe koja prodaje, na kojoj god stranici aplikacije bila, a odgovor se mora vratiti na isti način. I svi koji gledaju artikl trebali bi vidjeti njegovu cijenu, i je li još na prodaju, čim se nešto promijeni.
Ovaj članak prolazi kroz svaki dio koji prava aplikacija treba, na potpunom primjeru koji radi: marketplaceu iz našeg vodiča za Next.js, u kojem susjedi kupuju i prodaju svoje stvari. Možete ga isprobati uživo: budite Omar, s gramofonom na prodaju, a zatim otvorite stranicu u privatnom prozoru kao Ava, s ponudom od 130 $ koja čeka odgovor. Promijenite ponudu kao Ava, i Omar to odmah vidi, na kojoj god stranici bio otvoren Omarov preglednik.
Što chat na marketplaceu treba
- Jedan razgovor po artiklu i kupcu. Svaka osoba koja pita o artiklu dobije vlastiti razgovor s osobom koja ga prodaje, i nitko ga drugi ne čita, ni drugi kupci ni drugi prodavatelji.
- Poruke koje stižu dok gledate. Poruka prelazi sa stranice na stranicu čim se pošalje, uz oznaku tipkanja i potvrde čitanja, i sprema se u vašu vlastitu bazu podataka. Veze koje to traži ostaju otvorene dok je stranica otvorena, a serverless funkcija ih ne može držati (zašto, i što učiniti).
- Fotografije koje čuvate vi. Kupac želi nešto pogledati izbliza, a prodavatelj pošalje fotografiju. Fotografije ostaju na vašem poslužitelju, i samo ih dvije osobe iz razgovora mogu otvoriti.
- Poziv da se artikl vidi. Na videu, iz razgovora, prije nego što itko dođe.
- Ponude koje nijedna stranica ne može krivotvoriti. Ponuda, i da ili ne prodavatelja, dolaze s vašeg poslužitelja, nikad sa stranice, i obje ih strane odmah vide.
- Marketplace kakav je sada. Koliko drugih ljudi gleda artikl, njegova nova cijena, i je li rezerviran ili prodan, na svakoj stranici koja ga prikazuje.
Sve to možete izgraditi sami, na vlastitim websocketima i vlastitom WebRTC-u. Ili prepustite cloudu u stvarnom vremenu da prenosi poruke, pozive i brojanja, dok vaš poslužitelj zadržava ono što je stvarno vaše: tko smije razgovarati s kim, razgovore i ponude. To radi marketplace, preko WordPlus Clouda.
Primjer: marketplace
Susjedi objavljuju svoje stvari s fotografijama i cijenom. Osoba koja želi kupiti otvori artikl, pritisne Message Omar, i otvori se razgovor o njemu, s artiklom i ponudom iznad chata. To je Next.js aplikacija s App Routerom, Better Authom i Postgresom, a njezin dio za rad u stvarnom vremenu stane u nekoliko datoteka. Pet koraka čini njezine razgovore.
1. Jedan razgovor po artiklu i kupcu
Svaki razgovor je soba nazvana po svom broju u bazi podataka, deal:7, i obuhvaća jedan artikl, osobu koja ga prodaje i jednu osobu koja kupuje. Stranica te sobe deklarira jednom, po tom uzorku, s onim što stranica u njima smije slati i s pravilom:
realtime.room(
'deal:{id}',
{ history: 50, emit: ['message', 'typing', 'reaction', 'read'], webhook: ['message', 'reaction'] },
async (user, { id }) => mayTalk(user, id),
);export async function mayTalk(user: string | number | null, deal: string): Promise<boolean> {
return user !== null && (await partiesOf(deal)).includes(String(user));
}mayTalk pita bazu podataka tko su dvije osobe u razgovoru, i ne pušta nikoga drugoga. Stranica traži ulaz na vlastitoj ruti web-stranice, /api/realtime/auth, koja pokreće pravilo s vlastitom sesijom web-stranice i odgovara propusnicom potpisanom tajnom aplikacije, ili razlogom odbijanja. Poruke, oznake tipkanja, reakcije i potvrde čitanja zatim idu sa stranice na stranicu preko WordPlus Clouda, a webhook šalje svaku poruku i reakciju i web-stranici, koja ih sprema u Postgres:
realtime.on('message', async ({ room, from, data, event_id, at }) => {
const deal = idIn(room, 'deal');
if (!from || !deal) return;
await keepAndTell({ id: event_id, deal, from: String(from), text: String(data.text ?? ''), files: data.files as unknown[], at });
});keepAndTell sprema poruku samo jednom, po identifikatoru njezina događaja, i obavijesti drugu osobu iz razgovora s realtime.toUser(), što stiže do svake stranice koju ta osoba ima otvorenu: obavijest koja otvara razgovor.
2. Chat na stranici, s fotografijama kod vas
Razgovor je gotov chat, onaj iz Better Messagesa, u vašem vlastitom stablu:
<Chat
rt={useRealtime()}
room={room}
to={to}
name={name}
avatar={avatar}
call
messages={`/api/messages?room=${room}`}
upload="/api/files"
accept="image/jpeg,image/png,image/webp,image/gif"
maxFileSize={15 * 1024 * 1024}
/>Prikazuje poruke koje je vaš poslužitelj spremio, i učitava starije kad se pomaknete prema gore (messages), uz oznaku tipkanja, reakcije, potvrde čitanja i polje za pisanje. to, name i avatar stavljaju drugu osobu u njegovu gornju traku. upload prima fotografije: svaka ide na rutu web-stranice čim se odabere, a poruka nosi samo mjesto na kojem se nalazi, pa WordPlus Cloud nikad ne vidi samu fotografiju. Ruta pita isto pravilo kao soba:
if (!me || !deal || !(file instanceof File) || !(await realtime.mayJoin(room, me))) {
return Response.json({ error: 'This photo is not for this conversation.' }, { status: 403 });
}realtime.mayJoin pokreće pravilo sobe deal:{id} za prijavljenu osobu, pa se razgovor i njegove fotografije nikad ne razilaze oko toga tko ih smije koristiti. Ruta koja poslužuje fotografiju ponovno pita mayTalk, a svi ostali dobiju 404, čak i s adresom fotografije.
3. Poziv da se artikl vidi
realtime.calls('deal:{id}', async (user, other, { id }) => (await mayTalk(user, id)) && (await mayTalk(other, id)));Poziv nosi ime razgovora, i dvije osobe iz razgovora smiju se u njemu međusobno zvati. call na chatu stavlja gumbe za zvuk i video u njegovu gornju traku i prikazuje poziv u samom chatu, pokraj poruka, pa kupac može pitati za ogrebotinu dok prodavatelj okreće gramofon prema kameri. Na drugoj stranici web-stranice poziv se nastavlja u prozoru u kutu. Poziv između dviju osoba ide izravno između njihovih preglednika kad može, preko releja kad mreža to blokira, i šifriran je s kraja na kraj na svakom putu (kako implementirati videopozive u Next.js-u).
4. Ponude koje izgovara vaš poslužitelj
Ponuda je obećanje novca, pa je nijedna stranica ne smije poslati. emit sobe izostavlja ponude, i samo server actions web-stranice stvaraju ponudu, spremaju je i obavještavaju obje osobe:
export async function offer(deal: string, amount: number): Promise<{ error: string } | null> {
const me = await currentUserId();
if (!me) return { error: 'Sign in first.' };
const made = await makeOffer(deal, me, amount);
if (typeof made === 'string') return { error: made };
const found = (await dealOf(deal))!;
await realtime.to(`deal:${deal}`).emit('changed');
await realtime.toUser(found.listing.seller).emit('offer', { deal, name: found.buyerName, amount, title: found.listing.title });
return null;
}realtime.to() kaže changed u sobi razgovora, i obje njegove stranice ponovno traže svoj sadržaj od poslužitelja, bez ponovnog učitavanja. realtime.toUser() stiže do prodavatelja na bilo kojoj stranici, kao obavijest: „Ava offers $135 for Wooden turntable, works perfectly”. Accept ili Decline vraća se istim putem kupcu. Kad se ponuda prihvati, artikl je po toj cijeni rezerviran za osobu koja ju je dala, ostale otvorene ponude za njega se odbijaju, i svaka osoba koja ih je dala također to sazna:
for (const other of answered.declined) {
await realtime.toUser(other.buyer).emit('answer', {
deal: other.deal, name: seller, accepted: false, amount: other.amount, title: answered.listing.title,
});
}5. Tko gleda, i marketplace kakav jest
Stranica artikla ulazi u vlastitu sobu, listing:7, javnu i prebrojanu od strane WordPlus Clouda, bez ijedne vaše tablice:
realtime.room('listing:{id}', { public: true, count: true });const { count } = useRoom(`listing:${id}`, { changed: () => router.refresh() });
const others = count === null ? 0 : count - 1;Stranica prikazuje „2 other people are looking at this”, a broj se mijenja kako ljudi dolaze i odlaze. Ista soba čuje changed kad cijena padne, ili kad se artikl rezervira ili proda, i stranica to odmah prikaže. Svaka stranica prijavljene osobe ulazi u još jednu sobu, market, u kojoj govori samo poslužitelj, pa sam marketplace prikazuje novi artikl, novu cijenu ili prodani artikl, bez ponovnog učitavanja.
Što dolazi uz to
- Oznaka tipkanja i potvrde čitanja, u oba smjera, kao u aplikaciji za poruke.
- Pristigla pošta: svaki razgovor, pri kupnji i prodaji, najnoviji prvi, i obavijest o novoj poruci na bilo kojoj stranici.
- Je li prodavatelj na mreži, ili kad je posljednji put bio, na stranici artikla, iz
useOnline(). - Imena i lica iz vaše aplikacije. Chat i poziv prikazuju svakog susjeda s imenom i fotografijom koje daje vaša web-stranica, bez ikakvog popisa korisnika u WordPlus Cloudu.
- Zapečaćeno na putu. Ono što prolazi kroz privatnu sobu prelazi WordPlus Cloud zapečaćeno ključem koji izvodi vaša aplikacija, a poslužitelji WordPlus Clouda nikad ne drže taj ključ.
Isprobajte, a zatim izgradite svoj
U demu uživo susjedi i njihove stvari pripadaju samo vama jedan dan, pa ono što tamo napišete ili ponudite nitko drugi ne vidi. Ispod svake stranice How this page works korak po korak pokazuje kod koji je pokreće, s vrijednostima stranice koju imate otvorenu.
Vodič kroz marketplace izgrađuje cijelu web-stranicu, sa svakom datotekom njezina dijela za rad u stvarnom vremenu, a za sastanke mnogo ljudi u istoj vrsti aplikacije pročitajte kako implementirati videokonferencije u Next.js-u.
WordPlus Cloud for Apps ima cijenu prema istodobnim vezama, od 1.000 naviše, uz mjesečnu ili godišnju naplatu. Poruke, ponude, brojanje tko gleda i pozivi između dviju osoba ne troše kredite. Pogledajte WordPlus Cloud za aplikacije ili cijene za aplikacije. Pitanja o vašoj integraciji? Pišite nam.