mirror of
https://github.com/aljazceru/hypergolic.git
synced 2026-01-21 14:24:34 +01:00
problem: not clear which rockets are for testing, and which are real
This commit is contained in:
@@ -4,15 +4,18 @@
|
||||
import Button from '@/components/ui/button/button.svelte';
|
||||
import { ndk } from '@/ndk';
|
||||
import { currentUser } from '@/stores/session';
|
||||
import ExclamationTriangle from 'svelte-radix/ExclamationTriangle.svelte';
|
||||
import * as Alert from '$lib/components/ui/alert/index.js';
|
||||
import validate from 'bitcoin-address-validation';
|
||||
|
||||
export let amrAuction: AMRAuction | undefined;
|
||||
export let rocket: Rocket;
|
||||
export let selected_amrs: Map<string, AMRAuction>;
|
||||
export let selected_amrs: AMRAuction | undefined;
|
||||
|
||||
let bitcoinAddress: string = '';
|
||||
$: bitcoinAddressInValid = true;
|
||||
$: bitcoinAddressError = '';
|
||||
$: isTestRocket = rocket.Name().toLowerCase().includes('test');
|
||||
|
||||
$: if (bitcoinAddress) {
|
||||
if (!validate(bitcoinAddress)) {
|
||||
@@ -49,7 +52,7 @@
|
||||
console.log('AMRAuction', e);
|
||||
e.publish().then((x) => {
|
||||
console.log(x, e);
|
||||
selected_amrs = new Map<string, AMRAuction>();
|
||||
selected_amrs = undefined;
|
||||
//goto(`${base}/rockets/${getRocketURL(e)}`);
|
||||
});
|
||||
}
|
||||
@@ -60,6 +63,15 @@
|
||||
You are selling {amrAuction.Merits} Merits
|
||||
</div>
|
||||
<div class="m-2 flex flex-col">
|
||||
{#if isTestRocket}
|
||||
<Alert.Root variant="destructive">
|
||||
<ExclamationTriangle class="h-4 w-4" />
|
||||
<Alert.Title>Warning</Alert.Title>
|
||||
<Alert.Description
|
||||
>Please do not enter a real Bitcoin address, as this is a test rocket.</Alert.Description
|
||||
>
|
||||
</Alert.Root>
|
||||
{/if}
|
||||
<div class="flex">
|
||||
<Input
|
||||
bind:value={bitcoinAddress}
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
import { ChevronRight } from 'lucide-svelte';
|
||||
|
||||
export let rocket: Rocket;
|
||||
|
||||
//$page.url.searchParams.get("tab")
|
||||
</script>
|
||||
|
||||
<Card.Root class="w-[350px]">
|
||||
<Card.Root class="flex w-[350px] flex-col justify-between">
|
||||
<Card.Header>
|
||||
<Card.Title>{rocket.Name()}</Card.Title>
|
||||
<Card.Description>{rocket.Mission()}</Card.Description>
|
||||
@@ -27,17 +28,19 @@
|
||||
<Name ndk={$ndk} pubkey={rocket.Event.pubkey} class="inline-block truncate" />
|
||||
</div>
|
||||
</Card.Content>
|
||||
<Card.Footer class="flex justify-between">
|
||||
<Button
|
||||
on:click={() => {
|
||||
console.log(rocket.Event.rawEvent());
|
||||
}}
|
||||
variant="outline">Print to Console</Button
|
||||
>
|
||||
<Button
|
||||
on:click={() => {
|
||||
goto(`${base}/rockets/${rocket.URL()}`);
|
||||
}}>View Full Rocket<ChevronRight class="h-4 w-4" /></Button
|
||||
>
|
||||
<Card.Footer>
|
||||
<div class="flex justify-between gap-2">
|
||||
<Button
|
||||
on:click={() => {
|
||||
console.log(rocket.Event.rawEvent());
|
||||
}}
|
||||
variant="outline">Print to Console</Button
|
||||
>
|
||||
<Button
|
||||
on:click={() => {
|
||||
goto(`${base}/rockets/${rocket.URL()}`);
|
||||
}}>View Full Rocket<ChevronRight class="h-4 w-4" /></Button
|
||||
>
|
||||
</div>
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
|
||||
103
src/components/SellMeritsTable.svelte
Normal file
103
src/components/SellMeritsTable.svelte
Normal file
@@ -0,0 +1,103 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import * as Table from '@/components/ui/table';
|
||||
import { currentUser } from '@/stores/session';
|
||||
import { type RocketAMR, AMRAuction, Rocket } from '@/event_helpers/rockets';
|
||||
import CreateAMRAuction from './CreateAMRAuction.svelte';
|
||||
import Heading from './Heading.svelte';
|
||||
|
||||
export let rocket: Rocket;
|
||||
export let amr: RocketAMR[];
|
||||
|
||||
let selected_amrs: AMRAuction | undefined;
|
||||
|
||||
function toggleSelected(amr: RocketAMR) {
|
||||
if (!selected_amrs) {
|
||||
selected_amrs = new AMRAuction(rocket.Event);
|
||||
}
|
||||
let existing = selected_amrs;
|
||||
if (existing.AMRIDs.includes(amr.ID)) {
|
||||
existing.Pop(amr);
|
||||
} else {
|
||||
existing.Push(amr);
|
||||
}
|
||||
selected_amrs = existing;
|
||||
}
|
||||
|
||||
function getSelectedStatus(id: string, data: AMRAuction): boolean {
|
||||
let has = false;
|
||||
let amr = data;
|
||||
if (amr) {
|
||||
has = amr.AMRIDs.includes(id);
|
||||
}
|
||||
return has;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $currentUser && amr.length > 0}
|
||||
<Heading title={`ROCKET: ${rocket.Name()}`} />
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.Head class="w-[100px]">Selected</Table.Head>
|
||||
<Table.Head class="w-[10px]">AMR</Table.Head>
|
||||
<Table.Head>Merits</Table.Head>
|
||||
<Table.Head>Status</Table.Head>
|
||||
<Table.Head>Receiving Address</Table.Head>
|
||||
<Table.Head class="text-right">Sats (approx)</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each rocket.PendingAMRAuctions().filter((r) => {
|
||||
return Boolean(r.Owner == $currentUser.pubkey);
|
||||
}) as p}
|
||||
<Table.Row class="bg-purple-500 hover:bg-purple-600">
|
||||
<Table.Cell><Checkbox /></Table.Cell>
|
||||
<Table.Cell>{p.AMRIDs.length > 1 ? 'multiple' : p.AMRIDs[0].substring(0, 12)}</Table.Cell>
|
||||
<Table.Cell>{p.Merits}</Table.Cell>
|
||||
<Table.Cell>Pending</Table.Cell>
|
||||
<Table.Cell>{p.RxAddress}</Table.Cell>
|
||||
<Table.Cell class="text-right">{p.Merits}</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
|
||||
{#each amr as a, id (a.ID)}
|
||||
{#if rocket.CanThisAMRBeSold(a.ID)}
|
||||
<Table.Row
|
||||
class={getSelectedStatus(a.ID, selected_amrs)
|
||||
? 'bg-orange-500 hover:bg-orange-500'
|
||||
: ''}
|
||||
>
|
||||
<Table.Cell
|
||||
><Checkbox
|
||||
disabled={Boolean(a.Extra?.eventAMR)}
|
||||
id={a.ID}
|
||||
checked={getSelectedStatus(a.ID, selected_amrs)}
|
||||
on:click={() => {
|
||||
toggleSelected(a);
|
||||
}}
|
||||
/></Table.Cell
|
||||
>
|
||||
<Table.Cell>
|
||||
<span
|
||||
class="cursor-pointer font-medium underline"
|
||||
on:click={() => {
|
||||
goto(`${base}/rockets/merits/${a.ID}`);
|
||||
}}
|
||||
>
|
||||
{a.ID.substring(0, 6)}
|
||||
</span>
|
||||
</Table.Cell>
|
||||
<Table.Cell>{a.Merits}</Table.Cell>
|
||||
<Table.Cell>{a.Extra?.eventAMR ? 'pending' : 'Eligible'}</Table.Cell>
|
||||
<Table.Cell>{a.Extra?.eventAMR?.RxAddress}</Table.Cell>
|
||||
<Table.Cell class="text-right">{a.Merits}</Table.Cell>
|
||||
</Table.Row>
|
||||
{/if}
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
<CreateAMRAuction {rocket} amrAuction={selected_amrs} bind:selected_amrs />
|
||||
{/if}
|
||||
@@ -7,6 +7,9 @@
|
||||
import Heading from '../../components/Heading.svelte';
|
||||
import { Product, Rocket } from '@/event_helpers/rockets';
|
||||
import ProductGroup from '../../components/ProductGroup.svelte';
|
||||
import * as Tabs from '$lib/components/ui/tabs/index.js';
|
||||
import ExclamationTriangle from 'svelte-radix/ExclamationTriangle.svelte';
|
||||
import * as Alert from '$lib/components/ui/alert/index.js';
|
||||
|
||||
let rockets: NDKEventStore<NDKEvent> | undefined;
|
||||
let products: NDKEventStore<NDKEvent> | undefined;
|
||||
@@ -25,43 +28,95 @@
|
||||
return $rockets;
|
||||
});
|
||||
|
||||
let productsToRender = derived([rocketsWithProducts, products], ([$rocketsWP, $products]) => {
|
||||
let data = new Map<Rocket, Map<string, Product[]>>();
|
||||
let productMap = new Map($products.map((e) => [e.id, e]));
|
||||
for (let r of $rocketsWP) {
|
||||
let events: Product[] = [];
|
||||
for (let p of r.getMatchingTags('product')) {
|
||||
let productEvent = productMap.get(p[1].split(':')[0]);
|
||||
if (productEvent) {
|
||||
events.push(new Product(productEvent));
|
||||
}
|
||||
}
|
||||
if (events.length > 0) {
|
||||
data.set(new Rocket(r), groups(events));
|
||||
}
|
||||
}
|
||||
let productsToRenderStore = derived(
|
||||
[rocketsWithProducts, products],
|
||||
([$rocketsWP, $products]) => {
|
||||
let mainnet: Map<Rocket, Map<string, Product[]>> = new Map();
|
||||
let testnet: Map<Rocket, Map<string, Product[]>> = new Map();
|
||||
|
||||
function groups(products: Product[]): Map</* group name*/ string, Product[]> {
|
||||
return products.reduce((acc, product) => {
|
||||
const group = product.Group();
|
||||
if (!acc.has(group)) {
|
||||
acc.set(group, []);
|
||||
let productMap = new Map($products.map((e) => [e.id, e]));
|
||||
|
||||
for (let r of $rocketsWP) {
|
||||
let events: Product[] = [];
|
||||
for (let p of r.getMatchingTags('product')) {
|
||||
let productEvent = productMap.get(p[1].split(':')[0]);
|
||||
if (productEvent) {
|
||||
events.push(new Product(productEvent));
|
||||
}
|
||||
}
|
||||
acc.get(group)!.push(product);
|
||||
return acc;
|
||||
}, new Map<string, Product[]>());
|
||||
if (events.length > 0) {
|
||||
let groupedProducts = groups(events);
|
||||
if (r.dTag!.toLowerCase().includes('test')) {
|
||||
testnet.set(new Rocket(r), groupedProducts);
|
||||
} else {
|
||||
mainnet.set(new Rocket(r), groupedProducts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function groups(products: Product[]): Map</* group name*/ string, Product[]> {
|
||||
return products.reduce((acc, product) => {
|
||||
const group = product.Group();
|
||||
if (!acc.has(group)) {
|
||||
acc.set(group, []);
|
||||
}
|
||||
acc.get(group)!.push(product);
|
||||
return acc;
|
||||
}, new Map<string, Product[]>());
|
||||
}
|
||||
|
||||
return { mainnet, testnet };
|
||||
}
|
||||
return data;
|
||||
);
|
||||
|
||||
let mainnet: Map<Rocket, Map<string, Product[]>> = new Map();
|
||||
let testnet: Map<Rocket, Map<string, Product[]>> = new Map();
|
||||
|
||||
productsToRenderStore.subscribe(($productsToRenderStore) => {
|
||||
mainnet = $productsToRenderStore.mainnet;
|
||||
testnet = $productsToRenderStore.testnet;
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if productsToRender && $productsToRender}
|
||||
{#each $productsToRender as [rocket, groups] (rocket.Event.id)}
|
||||
<Heading title={rocket.Event.dTag} />
|
||||
<div class="grid gap-4" style="grid-template-columns: repeat(auto-fit, 350px);">
|
||||
{#each groups as [identifier, products] (identifier)}
|
||||
<ProductGroup {products} {rocket} />
|
||||
<Heading title="Products" />
|
||||
<Tabs.Root value="mainnet">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="mainnet">Mainnet</Tabs.Trigger>
|
||||
<Tabs.Trigger value="testnet">Testnet</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.Content value="mainnet">
|
||||
{#if mainnet.size > 0}
|
||||
{#each mainnet as [rocket, groups] (rocket.Event.id)}
|
||||
<Heading title={rocket.Event.dTag} />
|
||||
<div class="grid gap-4" style="grid-template-columns: repeat(auto-fit, 350px);">
|
||||
{#each groups as [identifier, products] (identifier)}
|
||||
<ProductGroup {products} {rocket} />
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
{:else}
|
||||
<Alert.Root>
|
||||
<Alert.Description
|
||||
>Currently, there are no products on the mainnet; you can check the testnet.</Alert.Description
|
||||
>
|
||||
</Alert.Root>
|
||||
{/if}
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="testnet">
|
||||
<Alert.Root class="my-2">
|
||||
<ExclamationTriangle class="h-4 w-4" />
|
||||
<Alert.Title>Note</Alert.Title>
|
||||
<Alert.Description
|
||||
>The following products are for testing purposes only. Please do not send real Bitcoin.</Alert.Description
|
||||
>
|
||||
</Alert.Root>
|
||||
{#each testnet as [rocket, groups] (rocket.Event.id)}
|
||||
<Heading title={rocket.Event.dTag} />
|
||||
<div class="grid gap-4" style="grid-template-columns: repeat(auto-fit, 350px);">
|
||||
{#each groups as [identifier, products] (identifier)}
|
||||
<ProductGroup {products} {rocket} />
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import * as Table from '@/components/ui/table';
|
||||
import { type RocketAMR, AMRAuction, Rocket } from '@/event_helpers/rockets';
|
||||
import { ndk } from '@/ndk';
|
||||
import { currentUser } from '@/stores/session';
|
||||
@@ -10,10 +6,10 @@
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { derived } from 'svelte/store';
|
||||
import Login from '../../components/Login.svelte';
|
||||
import CreateAMRAuction from '../../components/CreateAMRAuction.svelte';
|
||||
import SellMeritsTable from '../../components/SellMeritsTable.svelte';
|
||||
import MeritAuctions from '../../stateupdaters/MeritAuctions.svelte';
|
||||
import Heading from '../../components/Heading.svelte';
|
||||
import type { NDKEventStore, ExtendedBaseType } from '@nostr-dev-kit/ndk-svelte';
|
||||
import * as Tabs from '$lib/components/ui/tabs/index.js';
|
||||
let rocketEvents = $ndk.storeSubscribe([{ kinds: [31108 as number] }], { subId: 'all_rockets' });
|
||||
let amrAuctionEvents = $ndk.storeSubscribe([{ kinds: [1412 as number] }], {
|
||||
subId: 'my_auctions'
|
||||
@@ -31,7 +27,7 @@
|
||||
if (!existing) {
|
||||
existing = e;
|
||||
}
|
||||
if (e.created_at > existing) {
|
||||
if (e.created_at > existing.created_at) {
|
||||
existing = e;
|
||||
}
|
||||
m.set(e.pubkey + e.dTag, e);
|
||||
@@ -57,13 +53,14 @@
|
||||
}
|
||||
);
|
||||
|
||||
let myMeritRequests = derived(
|
||||
let meritRequestStore = derived(
|
||||
[currentUser, rockets, myAmrAuctionEvents],
|
||||
([$currentUser, $rockets, $myAmrAuctionEvents]) => {
|
||||
let merits = new Map<Rocket, RocketAMR[]>();
|
||||
let mainnet: Map<Rocket, RocketAMR[]> = new Map();
|
||||
let testnet: Map<Rocket, RocketAMR[]> = new Map();
|
||||
|
||||
if ($currentUser) {
|
||||
for (let r of $rockets) {
|
||||
//let parsedRocket = new Rocket(r);
|
||||
let _merits: RocketAMR[] = [];
|
||||
for (let [_, amr] of r.ApprovedMeritRequests()) {
|
||||
let amrAuction = $myAmrAuctionEvents.get(amr.ID);
|
||||
@@ -74,47 +71,26 @@
|
||||
_merits.push(amr);
|
||||
}
|
||||
}
|
||||
merits.set(r, _merits);
|
||||
|
||||
if (r.Name().toLowerCase().includes('test')) {
|
||||
testnet.set(r, _merits);
|
||||
} else {
|
||||
mainnet.set(r, _merits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return merits;
|
||||
return { mainnet, testnet };
|
||||
}
|
||||
);
|
||||
|
||||
let selected_amrs = new Map</* rocket id */ string, AMRAuction>();
|
||||
function toggleSelected(amr: RocketAMR, rocket: Rocket) {
|
||||
if (!selected_amrs.has(rocket.Event.id)) {
|
||||
selected_amrs.set(rocket.Event.id, new AMRAuction(rocket.Event));
|
||||
}
|
||||
let existing = selected_amrs.get(rocket.Event.id)!;
|
||||
if (existing.AMRIDs.includes(amr.ID)) {
|
||||
existing.Pop(amr);
|
||||
} else {
|
||||
existing.Push(amr);
|
||||
}
|
||||
selected_amrs.set(rocket.Event.id, existing);
|
||||
selected_amrs = selected_amrs;
|
||||
}
|
||||
let mainnet: Map<Rocket, RocketAMR[]> = new Map();
|
||||
let testnet: Map<Rocket, RocketAMR[]> = new Map();
|
||||
|
||||
function getSelectedStatus(rocket: string, id: string, data: Map<string, AMRAuction>): boolean {
|
||||
let has = false;
|
||||
let amr = data.get(rocket);
|
||||
if (amr) {
|
||||
has = amr.AMRIDs.includes(id);
|
||||
}
|
||||
return has;
|
||||
}
|
||||
|
||||
function getMerits(rocket: string, data: Map<string, AMRAuction>): number {
|
||||
let m = data.get(rocket);
|
||||
console.log(m);
|
||||
let merits = 0;
|
||||
if (m && m.Merits) {
|
||||
merits = m.Merits;
|
||||
}
|
||||
return merits;
|
||||
}
|
||||
meritRequestStore.subscribe(($meritRequestStore) => {
|
||||
mainnet = $meritRequestStore.mainnet;
|
||||
testnet = $meritRequestStore.testnet;
|
||||
});
|
||||
|
||||
// function getTotal(auction:AMRAuction):number {
|
||||
// let total = 0
|
||||
@@ -138,77 +114,21 @@
|
||||
<Heading title="Trade your Merits for Sats" />
|
||||
|
||||
{#if $currentUser}
|
||||
{#each $myMeritRequests as [rocket, amr]}
|
||||
{#if amr.length > 0}
|
||||
<h1>ROCKET: {rocket.Name()}</h1>
|
||||
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.Head class="w-[100px]">Selected</Table.Head>
|
||||
<Table.Head class="w-[10px]">AMR</Table.Head>
|
||||
<Table.Head>Merits</Table.Head>
|
||||
<Table.Head>Status</Table.Head>
|
||||
<Table.Head>Receiving Address</Table.Head>
|
||||
<Table.Head class="text-right">Sats (approx)</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each rocket.PendingAMRAuctions().filter((r) => {
|
||||
return Boolean(r.Owner == $currentUser.pubkey);
|
||||
}) as p}
|
||||
<Table.Row class="bg-purple-500 hover:bg-purple-600">
|
||||
<Table.Cell><Checkbox /></Table.Cell>
|
||||
<Table.Cell
|
||||
>{p.AMRIDs.length > 1 ? 'multiple' : p.AMRIDs[0].substring(0, 12)}</Table.Cell
|
||||
>
|
||||
<Table.Cell>{p.Merits}</Table.Cell>
|
||||
<Table.Cell>Pending</Table.Cell>
|
||||
<Table.Cell>{p.RxAddress}</Table.Cell>
|
||||
<Table.Cell class="text-right">{p.Merits}</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
|
||||
{#each amr as a, id (a.ID)}
|
||||
{#if rocket.CanThisAMRBeSold(a.ID)}
|
||||
<Table.Row
|
||||
class={getSelectedStatus(rocket.Event.id, a.ID, selected_amrs)
|
||||
? 'bg-orange-500 hover:bg-orange-500'
|
||||
: ''}
|
||||
>
|
||||
<Table.Cell
|
||||
><Checkbox
|
||||
disabled={Boolean(a.Extra?.eventAMR)}
|
||||
id={a.ID}
|
||||
checked={getSelectedStatus(rocket.Event.id, a.ID, selected_amrs)}
|
||||
on:click={() => {
|
||||
toggleSelected(a, rocket);
|
||||
}}
|
||||
/></Table.Cell
|
||||
>
|
||||
<Table.Cell
|
||||
><span
|
||||
class="cursor-pointer font-medium underline"
|
||||
on:click={() => {
|
||||
goto(`${base}/rockets/merits/${a.ID}`);
|
||||
}}>{a.ID.substring(0, 6)}</span
|
||||
></Table.Cell
|
||||
>
|
||||
<Table.Cell>{a.Merits}</Table.Cell>
|
||||
<Table.Cell>{a.Extra?.eventAMR ? 'pending' : 'Eligible'}</Table.Cell>
|
||||
<Table.Cell>{a.Extra?.eventAMR?.RxAddress}</Table.Cell>
|
||||
<Table.Cell class="text-right">{a.Merits}</Table.Cell>
|
||||
</Table.Row>
|
||||
{/if}
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
<CreateAMRAuction
|
||||
{rocket}
|
||||
amrAuction={selected_amrs.get(rocket.Event.id)}
|
||||
bind:selected_amrs
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
<Tabs.Root value="mainnet">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="mainnet">Mainnet</Tabs.Trigger>
|
||||
<Tabs.Trigger value="testnet">Testnet</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.Content value="mainnet">
|
||||
{#each mainnet as [rocket, amr]}
|
||||
<SellMeritsTable {rocket} {amr} />
|
||||
{/each}
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="testnet">
|
||||
{#each testnet as [rocket, amr]}
|
||||
<SellMeritsTable {rocket} {amr} />
|
||||
{/each}
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
{:else}<Login />{/if}
|
||||
<MeritAuctions {rockets} />
|
||||
|
||||
@@ -3,19 +3,20 @@
|
||||
import { ndk } from '@/ndk';
|
||||
import { onDestroy } from 'svelte';
|
||||
import { derived } from 'svelte/store';
|
||||
import * as Tabs from '$lib/components/ui/tabs/index.js';
|
||||
import Heading from '../../components/Heading.svelte';
|
||||
import RocketCard from '../../components/RocketCard.svelte';
|
||||
import Todo from '../../components/Todo.svelte';
|
||||
import ExclamationTriangle from 'svelte-radix/ExclamationTriangle.svelte';
|
||||
import * as Alert from '$lib/components/ui/alert/index.js';
|
||||
import AssociateBitcoinAddress from '../../stateupdaters/AssociateBitcoinAddress.svelte';
|
||||
let _rockets = $ndk.storeSubscribe([{ kinds: [31108 as number] }], { subId: 'rockets' });
|
||||
|
||||
let _rockets = $ndk.storeSubscribe([{ kinds: [31108 as number] }], { subId: 'rockets' });
|
||||
onDestroy(() => {
|
||||
_rockets?.unsubscribe();
|
||||
});
|
||||
|
||||
let rockets = derived(_rockets, ($rockets) => {
|
||||
let _r = new Map<string, Rocket>();
|
||||
|
||||
for (let e of $rockets) {
|
||||
let existing = _r.get(`${e.pubkey}${e.dTag}`);
|
||||
if (!existing) {
|
||||
@@ -23,44 +24,82 @@
|
||||
}
|
||||
const existingCreatedAt = existing.Event?.created_at ?? 0;
|
||||
const newCreatedAt = e.created_at ?? 0;
|
||||
|
||||
if (existingCreatedAt <= newCreatedAt) {
|
||||
_r.set(`${e.pubkey}${e.dTag}`, existing);
|
||||
}
|
||||
}
|
||||
|
||||
let rocketArray = Array.from(_r.values());
|
||||
|
||||
rocketArray.sort((a, b) => {
|
||||
// First condition: "Nostrocket" at the top
|
||||
if (a.Name() === 'Nostrocket') return -1;
|
||||
if (b.Name() === 'Nostrocket') return 1;
|
||||
|
||||
// Second condition: "test" rockets grouped underneath
|
||||
const aIsTest = a.Name().toLowerCase().includes('test');
|
||||
const bIsTest = b.Name().toLowerCase().includes('test');
|
||||
if (aIsTest && !bIsTest) return 1;
|
||||
if (!aIsTest && bIsTest) return -1;
|
||||
|
||||
// Default sorting by created_at, handling undefined
|
||||
const aCreatedAt = a.Event?.created_at ?? 0;
|
||||
const bCreatedAt = b.Event?.created_at ?? 0;
|
||||
return aCreatedAt - bCreatedAt;
|
||||
});
|
||||
|
||||
rocketArray.sort((a, b) => sortRockets(a, b));
|
||||
return rocketArray;
|
||||
});
|
||||
|
||||
//todo: until we have namerocket working, just manually dedupe rockets based on my pubkey
|
||||
//todo: write a recognizer/validator for rocket events
|
||||
function sortRockets(a: Rocket, b: Rocket): number {
|
||||
// First condition: "Nostrocket" at the top
|
||||
if (a.Name() === 'Nostrocket') return 1;
|
||||
if (b.Name() === 'Nostrocket') return -1;
|
||||
// Second condition: "test" rockets grouped underneath
|
||||
const aIsTest = a.Name().toLowerCase().includes('test');
|
||||
const bIsTest = b.Name().toLowerCase().includes('test');
|
||||
if (aIsTest && !bIsTest) return -1;
|
||||
if (!aIsTest && bIsTest) return 1;
|
||||
// Default sorting by created_at, handling undefined
|
||||
const aCreatedAt = a.Event?.created_at ?? 0;
|
||||
const bCreatedAt = b.Event?.created_at ?? 0;
|
||||
return bCreatedAt - aCreatedAt;
|
||||
}
|
||||
|
||||
function splitRockets(rocketArray: Rocket[]): { mainnet: Rocket[]; testnet: Rocket[] } {
|
||||
let mainnet: Rocket[] = [];
|
||||
let testnet: Rocket[] = [];
|
||||
for (let rocket of rocketArray) {
|
||||
if (rocket.Name().toLowerCase().includes('test')) {
|
||||
testnet.push(rocket);
|
||||
} else {
|
||||
mainnet.push(rocket);
|
||||
}
|
||||
}
|
||||
return { mainnet, testnet };
|
||||
}
|
||||
|
||||
let rocketStore = derived(rockets, (rocketArray) => splitRockets(rocketArray));
|
||||
let mainnet: Rocket[] = [];
|
||||
let testnet: Rocket[] = [];
|
||||
|
||||
rocketStore.subscribe(($rocketStore) => {
|
||||
mainnet = $rocketStore.mainnet;
|
||||
testnet = $rocketStore.testnet;
|
||||
});
|
||||
</script>
|
||||
|
||||
<Heading title="Rockets" />
|
||||
{#if rockets && $rockets}
|
||||
<AssociateBitcoinAddress {rockets} />
|
||||
<Todo text={['render these in a nicer way, maybe a grid or something']} />
|
||||
|
||||
{#each $rockets as rocket (`${rocket.Event.pubkey}${rocket.Name()}`)}
|
||||
<RocketCard {rocket} />
|
||||
{/each}
|
||||
<Tabs.Root value="mainnet">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="mainnet">Mainnet</Tabs.Trigger>
|
||||
<Tabs.Trigger value="testnet">Testnet</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
<Tabs.Content value="mainnet">
|
||||
<div class="grid gap-2" style="grid-template-columns: repeat(auto-fit, 350px);">
|
||||
{#each mainnet as rocket (`${rocket.Event.pubkey}${rocket.Name()}`)}
|
||||
<RocketCard {rocket} />
|
||||
{/each}
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="testnet">
|
||||
<Alert.Root class="my-2">
|
||||
<ExclamationTriangle class="h-4 w-4" />
|
||||
<Alert.Title>Note</Alert.Title>
|
||||
<Alert.Description
|
||||
>The following rocket is for testing purposes only. Any rocket with "test" in its name is
|
||||
intended solely for testing.</Alert.Description
|
||||
>
|
||||
</Alert.Root>
|
||||
<div class="grid gap-2" style="grid-template-columns: repeat(auto-fit, 350px);">
|
||||
{#each testnet as rocket (`${rocket.Event.pubkey}${rocket.Name()}`)}
|
||||
<RocketCard {rocket} />
|
||||
{/each}
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
</Tabs.Root>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user