diff --git a/package-lock.json b/package-lock.json
index b651be5..3591e62 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -38,7 +38,7 @@
"@types/node": "^20.14.2",
"autoprefixer": "^10.4.19",
"flowbite": "^2.3.0",
- "flowbite-svelte": "^0.46.1",
+ "flowbite-svelte": "^0.46.14",
"flowbite-svelte-icons": "^1.6.1",
"postcss": "^8.4.38",
"prettier": "^3.1.1",
@@ -462,18 +462,18 @@
}
},
"node_modules/@floating-ui/dom": {
- "version": "1.6.5",
- "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz",
- "integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==",
+ "version": "1.6.7",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.7.tgz",
+ "integrity": "sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==",
"dependencies": {
- "@floating-ui/core": "^1.0.0",
- "@floating-ui/utils": "^0.2.0"
+ "@floating-ui/core": "^1.6.0",
+ "@floating-ui/utils": "^0.2.4"
}
},
"node_modules/@floating-ui/utils": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
- "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw=="
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz",
+ "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA=="
},
"node_modules/@gcornut/valibot-json-schema": {
"version": "0.0.27",
@@ -824,6 +824,59 @@
"node": ">=18.16.0"
}
},
+ "node_modules/@rollup/plugin-node-resolve": {
+ "version": "15.2.3",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
+ "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
+ "dev": true,
+ "dependencies": {
+ "@rollup/pluginutils": "^5.0.1",
+ "@types/resolve": "1.20.2",
+ "deepmerge": "^4.2.2",
+ "is-builtin-module": "^3.2.1",
+ "is-module": "^1.0.0",
+ "resolve": "^1.22.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^2.78.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/pluginutils": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
+ "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/pluginutils/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.18.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
@@ -1290,6 +1343,12 @@
"integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==",
"dev": true
},
+ "node_modules/@types/resolve": {
+ "version": "1.20.2",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
+ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
+ "dev": true
+ },
"node_modules/@types/validator": {
"version": "13.11.10",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.10.tgz",
@@ -1381,9 +1440,9 @@
}
},
"node_modules/apexcharts": {
- "version": "3.49.1",
- "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.49.1.tgz",
- "integrity": "sha512-MqGtlq/KQuO8j0BBsUJYlRG8VBctKwYdwuBtajHgHTmSgUU3Oai+8oYN/rKCXwXzrUlYA+GiMgotAIbXY2BCGw==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.50.0.tgz",
+ "integrity": "sha512-LJT1PNAm+NoIU3aogL2P+ViC0y/Cjik54FdzzGV54UNnGQLBoLe5ok3fxsJDTgyez45BGYT8gqNpYKqhdfy5sg==",
"dev": true,
"dependencies": {
"@yr/monotone-cubic-spline": "^1.0.3",
@@ -1593,6 +1652,18 @@
"node": ">=6.14.2"
}
},
+ "node_modules/builtin-modules": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+ "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -2175,24 +2246,35 @@
}
},
"node_modules/flowbite": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-2.3.0.tgz",
- "integrity": "sha512-pm3JRo8OIJHGfFYWgaGpPv8E+UdWy0Z3gEAGufw+G/1dusaU/P1zoBLiQpf2/+bYAi+GBQtPVG86KYlV0W+AFQ==",
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-2.4.1.tgz",
+ "integrity": "sha512-I++vDsSOOlzHNuxY2OcFMNVC4CNzpPU2K14YHJ81cYrANXdzgizqniMB/1KQ219x8fqw+S0msY9Q45ZSXDqAPw==",
"dev": true,
"dependencies": {
"@popperjs/core": "^2.9.3",
+ "flowbite-datepicker": "^1.3.0",
"mini-svg-data-uri": "^1.4.3"
}
},
- "node_modules/flowbite-svelte": {
- "version": "0.46.1",
- "resolved": "https://registry.npmjs.org/flowbite-svelte/-/flowbite-svelte-0.46.1.tgz",
- "integrity": "sha512-GMQP4Fxn4mYu12XTNRbOHMYMklbP29sKFZUZYekryxhWak2zbSlI1ozhBtnrD2WDbFBPqZ64IcyButOkYpz+WQ==",
+ "node_modules/flowbite-datepicker": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/flowbite-datepicker/-/flowbite-datepicker-1.3.0.tgz",
+ "integrity": "sha512-CLVqzuoE2vkUvWYK/lJ6GzT0be5dlTbH3uuhVwyB67+PjqJWABm2wv68xhBf5BqjpBxvTSQ3mrmLHpPJ2tvrSQ==",
"dev": true,
"dependencies": {
- "@floating-ui/dom": "^1.6.3",
- "apexcharts": "^3.48.0",
- "flowbite": "^2.3.0",
+ "@rollup/plugin-node-resolve": "^15.2.3",
+ "flowbite": "^2.0.0"
+ }
+ },
+ "node_modules/flowbite-svelte": {
+ "version": "0.46.14",
+ "resolved": "https://registry.npmjs.org/flowbite-svelte/-/flowbite-svelte-0.46.14.tgz",
+ "integrity": "sha512-eIoQ7WQfyhHkCwmg2T9V46U27J+zpISmYcwPtPn689bNV9q8TB1e6Nvn1ElhjEjcIKZsHQBQWzJ6qk/8mkvxgg==",
+ "dev": true,
+ "dependencies": {
+ "@floating-ui/dom": "^1.6.7",
+ "apexcharts": "^3.49.2",
+ "flowbite": "^2.4.1",
"tailwind-merge": "^2.3.0"
},
"engines": {
@@ -2429,6 +2511,21 @@
"node": ">=8"
}
},
+ "node_modules/is-builtin-module": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
+ "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
+ "dev": true,
+ "dependencies": {
+ "builtin-modules": "^3.3.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-core-module": {
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
@@ -2467,6 +2564,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+ "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
+ "dev": true
+ },
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
diff --git a/package.json b/package.json
index fc24314..661ceed 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
"@types/node": "^20.14.2",
"autoprefixer": "^10.4.19",
"flowbite": "^2.3.0",
- "flowbite-svelte": "^0.46.1",
+ "flowbite-svelte": "^0.46.14",
"flowbite-svelte-icons": "^1.6.1",
"postcss": "^8.4.38",
"prettier": "^3.1.1",
diff --git a/src/components/Pie.svelte b/src/components/Pie.svelte
new file mode 100644
index 0000000..2d5f66e
--- /dev/null
+++ b/src/components/Pie.svelte
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
Merit Distribution
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/ProductCardFromEvent.svelte b/src/components/ProductCardFromEvent.svelte
new file mode 100644
index 0000000..f33ddc8
--- /dev/null
+++ b/src/components/ProductCardFromEvent.svelte
@@ -0,0 +1,22 @@
+
+
+{#if productEvent}
+
+{/if}
\ No newline at end of file
diff --git a/src/components/ProductPurchases.svelte b/src/components/ProductPurchases.svelte
new file mode 100644
index 0000000..c744366
--- /dev/null
+++ b/src/components/ProductPurchases.svelte
@@ -0,0 +1,63 @@
+
+
+{#each $zaps as z} {
+ console.log(z.rawEvent());
+ }}>{z.id} {/each}
+
+
+
+ Purchases
+ Purchase history for {product.ID}
+
+
+
+
+
+ Buyer
+ Date
+ Amount
+
+
+
+
+
+ Liam Johnson
+ liam@example.com
+
+ 2023-06-23
+ $250.00
+
+
+
+
+
diff --git a/src/components/ProductsForRocket.svelte b/src/components/ProductsForRocket.svelte
new file mode 100644
index 0000000..4df52e4
--- /dev/null
+++ b/src/components/ProductsForRocket.svelte
@@ -0,0 +1,23 @@
+
+
+{#if rocketEvent && rocketProducts.size > 0}
+ {#each rocketProducts as [id, product]}
+
+ {/each}
+{/if}
+
+
diff --git a/src/components/RocketDashboard copy.svelte b/src/components/RocketDashboard copy.svelte
new file mode 100644
index 0000000..9a01ff0
--- /dev/null
+++ b/src/components/RocketDashboard copy.svelte
@@ -0,0 +1,490 @@
+
+
+
+
+
+
+
+
+
+
+ Rocket Name
+
+
+
+ Dashboard
+
+
+
+ Recent Orders
+
+
+
+
+
+
+
+
+
+ Your Orders
+
+ Introducing Our Dynamic Orders Dashboard for Seamless Management and
+ Insightful Analysis.
+
+
+
+ Create New Order
+
+
+
+
+ This Week
+ $1329
+
+
+ +25% from last week
+
+
+
+
+
+
+
+ This Month
+ $5,329
+
+
+ +10% from last month
+
+
+
+
+
+
+
+
+
+ Week
+ Month
+ Year
+
+
+
+
+
+
+ Filter
+
+
+
+ Filter by
+
+
+ Fulfilled
+
+ Declined
+ Refunded
+
+
+
+
+ Export
+
+
+
+
+
+
+ Orders
+ Recent orders from your store.
+
+
+
+
+
+ Customer
+
+ Type
+
+
+ Status
+
+
+ Date
+
+ Amount
+
+
+
+
+
+ Liam Johnson
+
+ liam@example.com
+
+
+
+ Sale
+
+
+
+ Fulfilled
+
+
+
+ 2023-06-23
+
+ $250.00
+
+
+
+ Olivia Smith
+
+ olivia@example.com
+
+
+
+ Refund
+
+
+
+ Declined
+
+
+
+ 2023-06-24
+
+ $150.00
+
+
+
+ Noah Williams
+
+ noah@example.com
+
+
+
+ Subscription
+
+
+
+ Fulfilled
+
+
+
+ 2023-06-25
+
+ $350.00
+
+
+
+ Emma Brown
+
+ emma@example.com
+
+
+
+ Sale
+
+
+
+ Fulfilled
+
+
+
+ 2023-06-26
+
+ $450.00
+
+
+
+ Liam Johnson
+
+ liam@example.com
+
+
+
+ Sale
+
+
+
+ Fulfilled
+
+
+
+ 2023-06-23
+
+ $250.00
+
+
+
+ Liam Johnson
+
+ liam@example.com
+
+
+
+ Sale
+
+
+
+ Fulfilled
+
+
+
+ 2023-06-23
+
+ $250.00
+
+
+
+ Olivia Smith
+
+ olivia@example.com
+
+
+
+ Refund
+
+
+
+ Declined
+
+
+
+ 2023-06-24
+
+ $150.00
+
+
+
+ Emma Brown
+
+ emma@example.com
+
+
+
+ Sale
+
+
+
+ Fulfilled
+
+
+
+ 2023-06-26
+
+ $450.00
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Order Oe31b70H
+
+
+ Copy Order ID
+
+
+ Date: November 23, 2023
+
+
+
+
+
+ Track Order
+
+
+
+
+
+
+ More
+
+
+
+ Edit
+ Export
+
+ Trash
+
+
+
+
+
+
+
Order Details
+
+
+
+ Glimmer Lamps x 2
+
+ $250.00
+
+
+
+ Aqua Filters x 1
+
+ $49.00
+
+
+
+
+
+ Subtotal
+ $299.00
+
+
+ Shipping
+ $5.00
+
+
+ Tax
+ $25.00
+
+
+ Total
+ $329.00
+
+
+
+
+
+
+
Shipping Information
+
+ Liam Johnson
+ 1234 Main St.
+ Anytown, CA 12345
+
+
+
+
Billing Information
+
Same as shipping address
+
+
+
+
+
Customer Information
+
+
+
Customer
+ Liam Johnson
+
+
+
+
+
+
+
+
Payment Information
+
+
+
+
+ Visa
+
+ **** **** **** 4532
+
+
+
+
+
+
+ Updated November 23, 2023
+
+
+
+
+
+
+ Previous Order
+
+
+
+
+
+ Next Order
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/RocketDashboard.svelte b/src/components/RocketDashboard.svelte
index 9a01ff0..4d10f18 100644
--- a/src/components/RocketDashboard.svelte
+++ b/src/components/RocketDashboard.svelte
@@ -18,6 +18,11 @@
import { Separator } from "$lib/components/ui/separator/index.js";
import * as Table from "$lib/components/ui/table/index.js";
import * as Tabs from "$lib/components/ui/tabs/index.js";
+ import type { NDKEvent } from "@nostr-dev-kit/ndk";
+ import Pie from "./Pie.svelte";
+
+ export let rocket:NDKEvent;
+
@@ -30,19 +35,17 @@
- Rocket Name
+ {rocket.getMatchingTags('d')[0][1]}
- Dashboard
-
-
-
- Recent Orders
+ Dashboard
+
+
diff --git a/src/lib/event_helpers/rockets.ts b/src/lib/event_helpers/rockets.ts
new file mode 100644
index 0000000..d6b7b1a
--- /dev/null
+++ b/src/lib/event_helpers/rockets.ts
@@ -0,0 +1,98 @@
+import { NDKEvent, type NDKTag } from "@nostr-dev-kit/ndk";
+import type NDKSvelte from "@nostr-dev-kit/ndk-svelte";
+
+export function getZapData(ndk:NDKSvelte, zap: NDKEvent, rocket:NDKEvent) {
+ let productPrice = 0;
+ let zapAmount = 0;
+ let productID: string | undefined = undefined;
+ let buyerPubkey: string | undefined = undefined;
+ let zapRequest: NDKEvent | undefined = undefined;
+
+ let desc = zap.getMatchingTags('description');
+ if (desc && desc.length == 1 && rocket) {
+ zapRequest = new NDKEvent(ndk, JSON.parse(desc[0][1]));
+ let zapRequestETags = zapRequest.getMatchingTags('e');
+
+ if (zapRequestETags && zapRequestETags.length > 0) {
+ for (let productIDfromZapRequest of zapRequestETags) {
+ if (productIDfromZapRequest.length > 1) {
+ let productsInRocket = getMapOfProductsFromRocket(rocket);
+ if (productsInRocket.size > 0) {
+ productID = productIDfromZapRequest[1];
+ if (productID.length == 64) {
+ let productDataFromRocket = productsInRocket.get(productID);
+ if (productDataFromRocket) {
+ productPrice = productDataFromRocket.Price;
+ }
+ }
+ }
+ }
+ }
+ }
+ let amount = zapRequest.getMatchingTags('amount');
+ if (amount && amount.length == 1) {
+ if (amount[0].length == 2) {
+ zapAmount = parseInt(amount[0][1], 10);
+ }
+ }
+ buyerPubkey = zapRequest.author.pubkey;
+ }
+ let success = false;
+ if (zapRequest && productID && buyerPubkey && productPrice && zapAmount) {
+ if (zapAmount >= productPrice && productID.length == 64 && buyerPubkey.length == 64) {
+ success = true;
+ return {
+ productPrice: productPrice,
+ zapAmount: zapAmount,
+ productID: productID,
+ buyerPubkey: buyerPubkey,
+ zapReceipt: zap.id
+ };
+ }
+ }
+ if (!success) {
+ console.log('invalid product payment zap found:', zapRequest?.rawEvent());
+ }
+}
+
+export class RocketProduct {
+ ID: string;
+ Price: number;
+ ValidAfter: number; //unix time
+ MaxPurchases: number;
+ Purchases: Map;
+
+ constructor(tag: NDKTag) {
+ this.Purchases = new Map();
+ this.ID = tag[1].split(':')[0];
+ this.Price = parseInt(tag[1].split(':')[1], 10);
+ this.ValidAfter = parseInt(tag[1].split(':')[2], 10);
+ this.MaxPurchases = parseInt(tag[1].split(':')[3], 10);
+ let purchases = JSON.parse(tag[3]);
+ for (let p of purchases) {
+ let payment = new ProductPayment(p);
+ this.Purchases.set(payment.ZapID, payment);
+ }
+ }
+}
+
+export class ProductPayment {
+ ZapID: string;
+ BuyerPubkey: string;
+ WitnessedAt: number;
+ constructor(purchase: string) {
+ this.ZapID = purchase.split(':')[0];
+ this.BuyerPubkey = purchase.split(':')[1];
+ this.WitnessedAt = parseInt(purchase.split(':')[2], 10);
+ }
+}
+
+export function getMapOfProductsFromRocket(rocket: NDKEvent): Map {
+ let productIDs = new Map();
+ for (let product of rocket.getMatchingTags('product')) {
+ if (product.length > 1 && product[1].split(':') && product[1].split(':').length > 0) {
+ productIDs.set(product[1].split(':')[0], new RocketProduct(product));
+ }
+ }
+ return productIDs;
+}
\ No newline at end of file
diff --git a/src/routes/rockets/[ignition]/+page.svelte b/src/routes/rockets/[ignition]/+page.svelte
index b54786f..85429d3 100644
--- a/src/routes/rockets/[ignition]/+page.svelte
+++ b/src/routes/rockets/[ignition]/+page.svelte
@@ -1,15 +1,18 @@
-
{#if latestRocketEvent && $latestRocketEvent}
+
+{/if}
+{#if latestRocketEvent && $latestRocketEvent && false}
- {#if candidateProducts && $candidateProducts}
-
-
- {#each $candidateProducts as r} {/each}
- {/if}
+
+
+ {$latestRocketEvent.getMatchingTags('d')[0][1].toLocaleUpperCase()} Products
+
+
+ If there are products available for purchase they will be listed here
+
+
+
- {#if zaps && $zaps}
- {#each $zaps as z}
- {#if getZapData(z)}{getZapData(z)?.buyerPubkey}{/if}
- {
- let zapdata = getZapData(z);
- if (zapdata) {
- console.log(zapdata);
- }
- }}
- >
- {z.id}
-
{/each}
- {/if}
+
+
+ {$latestRocketEvent.getMatchingTags('d')[0][1].toLocaleUpperCase()} Product Proposals
+
+
+ If particpants of {$latestRocketEvent.getMatchingTags('d')[0][1]} have proposed any new products that are not yet included for sale, they will be listed here.
+
+
+ {#each $candidateProducts as r} {/each}
+
{:else}
+
IGNITION: {rIgnitionOrActual}
NAME: {rName}
PUBKEY: {rPubkey}