mirror of
https://github.com/aljazceru/hypergolic.git
synced 2025-12-18 14:04:21 +01:00
Problem: Not clear when sats paid to merit holders increases
Solution: Added NumberIncrement for animated numeric updates in MeritsAndSatflow.svelte and enhanced PayNow.svelte to animate intermediate payment states. Fixes #84
This commit is contained in:
@@ -6,11 +6,13 @@
|
|||||||
import Pie from './Pie.svelte';
|
import Pie from './Pie.svelte';
|
||||||
import { Avatar, Name } from '@nostr-dev-kit/ndk-svelte-components';
|
import { Avatar, Name } from '@nostr-dev-kit/ndk-svelte-components';
|
||||||
import { ndk } from '@/ndk';
|
import { ndk } from '@/ndk';
|
||||||
|
import NumberIncrement from '@components/ui/number-increment';
|
||||||
|
|
||||||
export let rocket: Rocket;
|
export let rocket: Rocket;
|
||||||
export let unratifiedZaps: Map<string, number>;
|
export let unratifiedZaps: Map<string, number>;
|
||||||
|
|
||||||
let unratifiedZapsAmount = 0;
|
let unratifiedZapsAmount = 0;
|
||||||
|
let dataLoaded = false;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
unratifiedZapsAmount = 0;
|
unratifiedZapsAmount = 0;
|
||||||
@@ -53,6 +55,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
merits.set(_merits);
|
merits.set(_merits);
|
||||||
|
dataLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const COLORS = [
|
const COLORS = [
|
||||||
@@ -98,8 +101,12 @@
|
|||||||
<Name ndk={$ndk} {pubkey} class="hidden max-w-32 truncate p-1 md:inline-block" />
|
<Name ndk={$ndk} {pubkey} class="hidden max-w-32 truncate p-1 md:inline-block" />
|
||||||
</div>
|
</div>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell class="hidden md:table-cell">{merits}</Table.Cell>
|
<Table.Cell class="hidden md:table-cell">
|
||||||
<Table.Cell class="text-right">{sats}</Table.Cell>
|
<NumberIncrement targetValue={merits} />
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell class="text-right">
|
||||||
|
<NumberIncrement targetValue={sats} />
|
||||||
|
</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
{/each}
|
{/each}
|
||||||
</Table.Body>
|
</Table.Body>
|
||||||
|
|||||||
@@ -13,12 +13,21 @@
|
|||||||
import CopyButton from './CopyButton.svelte';
|
import CopyButton from './CopyButton.svelte';
|
||||||
import type { Product, Rocket, RocketProduct } from '@/event_helpers/rockets';
|
import type { Product, Rocket, RocketProduct } from '@/event_helpers/rockets';
|
||||||
import { formatSats } from '@/helpers';
|
import { formatSats } from '@/helpers';
|
||||||
|
import { Spinner } from 'flowbite-svelte';
|
||||||
|
import { CheckCircleOutline } from 'flowbite-svelte-icons';
|
||||||
|
import { tweened, type Tweened } from 'svelte/motion';
|
||||||
|
import { cubicOut } from 'svelte/easing';
|
||||||
|
import { fade, fly } from 'svelte/transition';
|
||||||
|
|
||||||
export let product: Product;
|
export let product: Product;
|
||||||
export let rocketProduct: RocketProduct | undefined;
|
export let rocketProduct: RocketProduct | undefined;
|
||||||
export let rocket: Rocket;
|
export let rocket: Rocket;
|
||||||
|
|
||||||
let invoice: string | null;
|
let invoice: string | null;
|
||||||
|
let paymentInitiated: boolean;
|
||||||
|
let paymentFinished: boolean;
|
||||||
|
|
||||||
|
const scale = tweened(0, { duration: 1000, easing: cubicOut });
|
||||||
|
|
||||||
async function zap() {
|
async function zap() {
|
||||||
if (rocketProduct) {
|
if (rocketProduct) {
|
||||||
@@ -36,6 +45,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function payWithWebLn() {
|
async function payWithWebLn() {
|
||||||
|
paymentInitiated = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!invoice) {
|
if (!invoice) {
|
||||||
throw Error('invoice not found');
|
throw Error('invoice not found');
|
||||||
@@ -44,10 +55,20 @@
|
|||||||
const response = await webln.sendPayment(invoice);
|
const response = await webln.sendPayment(invoice);
|
||||||
if (response && response.preimage) {
|
if (response && response.preimage) {
|
||||||
console.log(response.preimage);
|
console.log(response.preimage);
|
||||||
|
paymentFinished = true;
|
||||||
|
|
||||||
|
await scale.set(1);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000)); // allow 1 second before resetting payment/dialog states
|
||||||
|
|
||||||
open = false;
|
open = false;
|
||||||
|
paymentFinished = false;
|
||||||
|
|
||||||
|
await scale.set(0);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
paymentInitiated = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,9 +83,14 @@
|
|||||||
|
|
||||||
{#if rocketProduct}
|
{#if rocketProduct}
|
||||||
<Dialog.Root bind:open>
|
<Dialog.Root bind:open>
|
||||||
<Dialog.Trigger class={buttonVariants({ variant: 'default' })}
|
<Dialog.Trigger class={buttonVariants({ variant: 'default' })}>
|
||||||
>Buy Now for {formatSats(rocketProduct.Price)}</Dialog.Trigger
|
{#if open}
|
||||||
>
|
<Spinner class="me-2" color="white" size={4} /> Confirming...
|
||||||
|
{:else}
|
||||||
|
Buy Now for {formatSats(rocketProduct.Price)}
|
||||||
|
{/if}
|
||||||
|
</Dialog.Trigger>
|
||||||
|
|
||||||
<Dialog.Content class="sm:max-w-[425px]">
|
<Dialog.Content class="sm:max-w-[425px]">
|
||||||
<Dialog.Header>
|
<Dialog.Header>
|
||||||
<Dialog.Title>Buy {product.Name()} from {rocket.Name()} now!</Dialog.Title>
|
<Dialog.Title>Buy {product.Name()} from {rocket.Name()} now!</Dialog.Title>
|
||||||
@@ -89,7 +115,17 @@
|
|||||||
<Input bind:value={invoice} readonly />
|
<Input bind:value={invoice} readonly />
|
||||||
<CopyButton text={invoice} />
|
<CopyButton text={invoice} />
|
||||||
</div>
|
</div>
|
||||||
<Button on:click={payWithWebLn}>Pay with WebLN</Button>
|
<Button on:click={payWithWebLn}>
|
||||||
|
{#if paymentFinished}
|
||||||
|
<div style="transform: scale({$scale});">
|
||||||
|
<CheckCircleOutline class="me-2 text-white" color="white" />
|
||||||
|
</div>
|
||||||
|
{:else if paymentInitiated}
|
||||||
|
<Spinner class="me-2" color="white" size={4} /> Confirming payment...
|
||||||
|
{:else}
|
||||||
|
Pay with WebLN
|
||||||
|
{/if}
|
||||||
|
</Button>
|
||||||
{:else}
|
{:else}
|
||||||
<Button on:click={zap}>Create invoice</Button>
|
<Button on:click={zap}>Create invoice</Button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
3
src/lib/components/ui/number-increment/index.ts
Normal file
3
src/lib/components/ui/number-increment/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import NumberIncrement from './number-increment.svelte';
|
||||||
|
|
||||||
|
export default NumberIncrement;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { cubicOut } from 'svelte/easing';
|
||||||
|
import { tweened } from 'svelte/motion';
|
||||||
|
|
||||||
|
export let targetValue: number;
|
||||||
|
|
||||||
|
let currentValue = tweened(0, { duration: 1000, easing: cubicOut });
|
||||||
|
|
||||||
|
// Re-trigger animation whenever targetValue changes
|
||||||
|
$: if (targetValue !== undefined && targetValue !== null) {
|
||||||
|
currentValue.set(targetValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
currentValue.set(targetValue);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span class="merits">{$currentValue.toFixed(0)}</span>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.merits {
|
||||||
|
transition:
|
||||||
|
transform 0.5s ease-in-out,
|
||||||
|
opacity 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user