feat(payments): payment-event dispatcher + the provider-return UX
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 22s
CI / ui (pull_request) Successful in 1m9s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m45s
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 22s
CI / ui (pull_request) Successful in 1m9s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m45s
Deliver payment_events to connected clients as an in-app wallet-refresh push: a background dispatcher drains undispatched events and publishes a KindNotification "payment" signal, marking each delivered; the client bumps a wallet-refresh counter the open Wallet screen watches, re-fetching in place. A return-focus refetch is the fallback. The Robokassa Success/Fail return now serves a self-closing page (the payment opens in a separate window) so the customer drops back into the live app instead of a cold start. Integration test for the event drain/mark queue.
This commit is contained in:
@@ -137,6 +137,9 @@ export const app = $state<{
|
||||
/** Whether an operator feedback reply awaits the player, for the lobby ⚙️ badge (combined
|
||||
* with friend requests) and the Settings → Info badge. */
|
||||
feedbackReplyUnread: boolean;
|
||||
/** A monotone counter bumped when a payment-intake push signals the wallet changed; an open
|
||||
* Wallet screen watches it and re-fetches in place. */
|
||||
walletRefresh: number;
|
||||
/** Whether to show the "outdated invite link" notice: set when a Telegram deep-link friend
|
||||
* code is already used/expired, so the visitor lands in the lobby with a gentle pointer to
|
||||
* the bot instead of a scary error on the Friends screen. */
|
||||
@@ -175,6 +178,7 @@ export const app = $state<{
|
||||
chatUnread: {},
|
||||
messageUnread: {},
|
||||
feedbackReplyUnread: false,
|
||||
walletRefresh: 0,
|
||||
staleInvite: false,
|
||||
welcomeRedeem: false,
|
||||
resync: 0,
|
||||
@@ -439,6 +443,12 @@ function openStream(): void {
|
||||
if (e.sub === 'profile') {
|
||||
void refreshProfile();
|
||||
}
|
||||
// A payment-intake event credited (or refunded) the viewer's wallet: bump the signal an
|
||||
// open Wallet screen watches, so it re-fetches in place (the return-focus poll is the
|
||||
// fallback when the live stream is down).
|
||||
if (e.sub === 'payment') {
|
||||
app.walletRefresh++;
|
||||
}
|
||||
void refreshNotifications();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import Modal from '../components/Modal.svelte';
|
||||
import { handleError } from '../lib/app.svelte';
|
||||
import { app, handleError } from '../lib/app.svelte';
|
||||
import { gateway } from '../lib/gateway';
|
||||
import { t, i18n, type MessageKey } from '../lib/i18n/index.svelte';
|
||||
import { executionContext, formatAmount, needsWebSpendWarning, type SpendContext } from '../lib/wallet';
|
||||
@@ -39,7 +39,26 @@
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
onMount(load);
|
||||
onMount(() => {
|
||||
void load();
|
||||
// Fallback to the payment push: re-fetch when the tab regains focus, i.e. the user returned
|
||||
// from the provider's payment window.
|
||||
const onVisible = () => {
|
||||
if (!document.hidden) void load();
|
||||
};
|
||||
document.addEventListener('visibilitychange', onVisible);
|
||||
return () => document.removeEventListener('visibilitychange', onVisible);
|
||||
});
|
||||
|
||||
// Main path: a payment-intake push bumps app.walletRefresh; re-fetch in place when it changes
|
||||
// (a credit landed while the screen is open).
|
||||
let seenRefresh = app.walletRefresh;
|
||||
$effect(() => {
|
||||
if (app.walletRefresh !== seenRefresh) {
|
||||
seenRefresh = app.walletRefresh;
|
||||
void load();
|
||||
}
|
||||
});
|
||||
|
||||
function sourceLabel(source: string): string {
|
||||
return t(`wallet.source.${source}` as MessageKey);
|
||||
|
||||
Reference in New Issue
Block a user