diff --git a/public/i18n/en.json b/public/i18n/en.json
index bb0d2611..e24fef04 100644
--- a/public/i18n/en.json
+++ b/public/i18n/en.json
@@ -92,7 +92,8 @@
"redeem_bitcoin": "Redeem Bitcoin",
"lnurl_amount_message": "Enter withdrawal amount between {{min}} and {{max}} sats",
"lnurl_redeem_failed": "Withdrawal Failed",
- "lnurl_redeem_success": "Payment Received"
+ "lnurl_redeem_success": "Payment Received",
+ "cashu_already_spent": "That token has already been spent"
},
"request": {
"request_bitcoin": "Request Bitcoin",
@@ -781,6 +782,7 @@
"minutes_short": "{{count}}m",
"nowish": "Nowish",
"seconds_future": "Seconds from now",
- "seconds_past": "Just now"
+ "seconds_past": "Just now",
+ "weeks_short": "{{count}}w"
}
}
diff --git a/src/components/Activity.tsx b/src/components/Activity.tsx
index 4163f768..a2fcbf04 100644
--- a/src/components/Activity.tsx
+++ b/src/components/Activity.tsx
@@ -1,6 +1,6 @@
import { TagItem } from "@mutinywallet/mutiny-wasm";
import { cache, createAsync, useNavigate } from "@solidjs/router";
-import { Plus, Save, Search, Shuffle, Users } from "lucide-solid";
+import { Nut, Plus, Save, Search, Shuffle, Users } from "lucide-solid";
import {
createEffect,
createMemo,
@@ -157,12 +157,21 @@ export function UnifiedActivityItem(props: {
return filtered[0];
};
- const shouldShowShuffle = () => {
- return (
+ const maybeIcon = () => {
+ if (
props.item.kind === "ChannelOpen" ||
props.item.kind === "ChannelClose" ||
(props.item.labels.length > 0 && props.item.labels[0] === "SWAP")
- );
+ ) {
+ return
+ {parsed()?.message_without_invoice} +
+Paid
+
{props.dm.message}
diff --git a/src/routes/Redeem.tsx b/src/routes/Redeem.tsx
index d166499b..71a3b025 100644
--- a/src/routes/Redeem.tsx
+++ b/src/routes/Redeem.tsx
@@ -18,6 +18,7 @@ import {
BackLink,
Button,
DefaultMain,
+ Failure,
InfoBox,
LargeHeader,
LoadingShimmer,
@@ -33,7 +34,7 @@ import { useI18n } from "~/i18n/context";
import { useMegaStore } from "~/state/megaStore";
import { eify, vibrateSuccess } from "~/utils";
-type RedeemState = "edit" | "paid";
+type RedeemState = "edit" | "paid" | "already_paid";
export function Redeem() {
const [state, _actions, sw] = useMegaStore();
@@ -67,12 +68,13 @@ export function Redeem() {
setError("");
}
+ //
+ // Lnurl stuff
+ //
const [decodedLnurl] = createResource(async () => {
- if (state.scan_result) {
- if (state.scan_result.lnurl) {
- const decoded = await sw.decode_lnurl(state.scan_result.lnurl);
- return decoded;
- }
+ if (state.scan_result && state.scan_result.lnurl) {
+ const decoded = await sw.decode_lnurl(state.scan_result.lnurl);
+ return decoded;
}
});
@@ -107,7 +109,7 @@ export function Redeem() {
}
});
- const canSend = createMemo(() => {
+ const lnUrlCanSend = createMemo(() => {
const lnurlParams = lnurlData();
if (!lnurlParams) return false;
const min = mSatsToSats(lnurlParams.min);
@@ -140,6 +142,50 @@ export function Redeem() {
}
}
+ //
+ // Cashu stuff
+ //
+ const [decodedCashuToken] = createResource(async () => {
+ if (state.scan_result && state.scan_result.cashu_token) {
+ // If it's a cashu token we already have what we need
+ const token = state.scan_result?.cashu_token;
+ const amount = state.scan_result?.amount_sats;
+ if (amount) {
+ setAmount(amount);
+ setFixedAmount(true);
+ }
+
+ return token;
+ }
+ });
+
+ const cashuCanSend = createMemo(() => {
+ if (!decodedCashuToken()) return false;
+ if (amount() === 0n) return false;
+ return true;
+ });
+
+ async function meltCashuToken() {
+ try {
+ setError("");
+ setLoading(true);
+ if (!state.scan_result?.cashu_token) return;
+ await sw.melt_cashu_token(state.scan_result?.cashu_token);
+ setRedeemState("paid");
+ await vibrateSuccess();
+ } catch (e) {
+ console.error("melt_cashu_token failed", e);
+ const err = eify(e);
+ if (err.message === "Token has been already spent.") {
+ setRedeemState("already_paid");
+ } else {
+ showToast(err);
+ }
+ } finally {
+ setLoading(false);
+ }
+ }
+
return (
NICE+