diff --git a/src/assets/icons/scan.svg b/src/assets/icons/scan.svg index 397504e26..fdf5e04fe 100644 --- a/src/assets/icons/scan.svg +++ b/src/assets/icons/scan.svg @@ -1,3 +1,3 @@ - - + + diff --git a/src/assets/icons/search.svg b/src/assets/icons/search.svg new file mode 100644 index 000000000..accf10f3b --- /dev/null +++ b/src/assets/icons/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/BalanceBox.tsx b/src/components/BalanceBox.tsx index 40821db57..f1e3c836b 100644 --- a/src/components/BalanceBox.tsx +++ b/src/components/BalanceBox.tsx @@ -1,5 +1,5 @@ import { A, useNavigate } from "@solidjs/router"; -import { Match, Show, Switch } from "solid-js"; +import { createSignal, Match, Show, Switch } from "solid-js"; import shuffle from "~/assets/icons/shuffle.svg"; import { @@ -35,19 +35,10 @@ export function LoadingShimmer(props: { center?: boolean }) { const STYLE = "px-2 py-1 rounded-xl text-sm flex gap-2 items-center font-semibold"; -export function BalanceBox(props: { loading?: boolean }) { +export function BalanceBox(props: { loading?: boolean; small?: boolean }) { const [state, _actions] = useMegaStore(); const i18n = useI18n(); - const emptyBalance = () => - (state.balance?.confirmed || 0n) === 0n && - (state.balance?.lightning || 0n) === 0n && - (state.balance?.federation || 0n) === 0n && - (state.balance?.force_close || 0n) === 0n && - (state.balance?.unconfirmed || 0n) === 0n; - - const navigate = useNavigate(); - const totalOnchain = () => (state.balance?.confirmed || 0n) + (state.balance?.unconfirmed || 0n) + @@ -57,118 +48,121 @@ export function BalanceBox(props: { loading?: boolean }) { (state.balance?.confirmed || 0n) + (state.balance?.unconfirmed || 0n); return ( - <> - - }> - - -
- - {i18n.t("common.error_safe_mode")} - -
- - + + +

+ +

+
+ + + {/* */} + }> + + +
+ + {i18n.t("common.error_safe_mode")} + +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + } + > +
-
-
- - + + +
}> -
-
-
- +
+
+
+ +
+
+ +
-
- +
+ + + {i18n.t("common.pending")} + + + +
+ + 0n}> +
+ + swap + +
+
- -
- }> -
-
-
- -
-
- -
-
-
- - - {i18n.t("common.pending")} - - - -
- - 0n}> -
- - swap - -
-
-
-
- - -
- - -
- + + + ); } diff --git a/src/components/MeOrEverybody.tsx b/src/components/HomeSubnav.tsx similarity index 61% rename from src/components/MeOrEverybody.tsx rename to src/components/HomeSubnav.tsx index 3a0e4b55d..4574b355a 100644 --- a/src/components/MeOrEverybody.tsx +++ b/src/components/HomeSubnav.tsx @@ -5,22 +5,21 @@ import { CombinedActivity, LoadingShimmer, NostrActivity, + PendingNwc, VStack } from "~/components"; import { useI18n } from "~/i18n/context"; import { useMegaStore } from "~/state/megaStore"; -export function MeOrEverybody() { +export function HomeSubnav() { const i18n = useI18n(); const [state, _actions] = useMegaStore(); // const safari = iosNotNative(); - const [activeView, setActiveView] = createSignal<"me" | "everybody">("me"); - - function toggleActive() { - setActiveView(activeView() === "me" ? "everybody" : "me"); - } + const [activeView, setActiveView] = createSignal< + "me" | "everybody" | "requests" + >("me"); return ( <> @@ -28,22 +27,33 @@ export function MeOrEverybody() { + +
@@ -63,6 +73,13 @@ export function MeOrEverybody() { + + }> + + + + + ); } diff --git a/src/components/IntegratedQR.tsx b/src/components/IntegratedQR.tsx index b396d0463..4bff85a3f 100644 --- a/src/components/IntegratedQR.tsx +++ b/src/components/IntegratedQR.tsx @@ -68,8 +68,8 @@ async function share(receiveString: string) { export function IntegratedQr(props: { value: string; - amountSats: string; - kind: ReceiveFlavor | "gift"; + kind: ReceiveFlavor | "gift" | "lnAddress"; + amountSats?: string; }) { const i18n = useI18n(); const [copy, copied] = useCopy({ copiedTimeout: 1000 }); @@ -84,25 +84,34 @@ export function IntegratedQr(props: {

{i18n.t("common.copied")}

-
- -
-
- -
-
- + +
+ +
+
+ +
+
+ +
-
-
- -
+ + +
+
+ +
+
void; +}) { + return ( + + {props.children} + + ); +} + export function LabelCircle(props: { name?: string; image_url?: string; contact: boolean; label: boolean; channel?: HackActivityType; + size?: "small" | "large" | "xl"; + onClick?: () => void; }) { const [gradient] = createResource(async () => { if (props.name && props.contact) { @@ -31,11 +63,10 @@ export function LabelCircle(props: { const [errored, setErrored] = createSignal(false); return ( -
props.onClick && props.onClick()} + size={props.size} > {text()} @@ -58,6 +89,6 @@ export function LabelCircle(props: { {text()} -
+ ); } diff --git a/src/components/NavBar.tsx b/src/components/NavBar.tsx index de71ec47f..bfc211575 100644 --- a/src/components/NavBar.tsx +++ b/src/components/NavBar.tsx @@ -1,20 +1,12 @@ import { A } from "@solidjs/router"; -import airplane from "~/assets/icons/airplane.svg"; import receive from "~/assets/icons/big-receive.svg"; import mutiny_m from "~/assets/icons/m.svg"; import scan from "~/assets/icons/scan.svg"; +import send from "~/assets/icons/send.svg"; import settings from "~/assets/icons/settings.svg"; -import userClock from "~/assets/icons/user-clock.svg"; -type ActiveTab = - | "home" - | "scan" - | "send" - | "receive" - | "settings" - | "activity" - | "none"; +type ActiveTab = "home" | "scan" | "send" | "receive" | "settings" | "none"; function NavBarItem(props: { href: string; @@ -28,8 +20,9 @@ function NavBarItem(props: { class="block rounded-lg p-2" href={props.href} classList={{ - "hover:bg-white/5 active:bg-m-blue": !props.active, - "bg-black": props.active + "hover:bg-white/20 active:bg-white/10 active:mt-[2px] active:-mb-[2px]": + !props.active, + "bg-m-red": props.active }} > {props.alt} @@ -50,7 +43,7 @@ export function NavBar(props: { activeTab: ActiveTab }) { /> @@ -60,12 +53,6 @@ export function NavBar(props: { activeTab: ActiveTab }) { active={props.activeTab === "receive"} alt="receive" /> - void }) { + const i18n = useI18n(); + const [_state, actions] = useMegaStore(); + const [scanResult, setScanResult] = createSignal(); + const navigate = useNavigate(); + + function onResult(result: string) { + setScanResult(result); + } + + async function handlePaste() { + try { + let text; + + if (Capacitor.isNativePlatform()) { + const { value } = await Clipboard.read(); + text = value; + } else { + text = await navigator.clipboard.readText(); + } + + const trimText = text.trim(); + setScanResult(trimText); + } catch (e) { + console.error(e); + } + } + + // When we have a nice result we can head over to the send screen + createEffect(() => { + if (scanResult()) { + actions.handleIncomingString( + scanResult()!, + (error) => { + showToast(error); + }, + (result) => { + actions.setScanResult(result); + navigate("/send"); + } + ); + } + }); + + return ( +
+ +
+
+ + +
+
+
+ ); +} diff --git a/src/components/PendingNwc.tsx b/src/components/PendingNwc.tsx index 7bacd4178..50a872a2f 100644 --- a/src/components/PendingNwc.tsx +++ b/src/components/PendingNwc.tsx @@ -1,3 +1,4 @@ +import { A } from "@solidjs/router"; import { createEffect, createResource, @@ -16,6 +17,7 @@ import { Card, InfoBox, LoadingSpinner, + NiceP, VStack } from "~/components"; import { useI18n } from "~/i18n/context"; @@ -147,92 +149,108 @@ export function PendingNwc() { }); return ( - 0}> - -
- - - {error()?.message} - - - {(pendingItem) => ( -
- onchain -
- - {pendingItem.name_of_connection} - - -
-
- + 0}> + +
+ + + {error()?.message} + + + {(pendingItem) => ( +
+ onchain -
-
- - - - + + + - Reject - - - - - - + + + +
-
- )} - - -
- - -
- - + )} + + +
+ + +
+ + + + + No pending requests. Maybe you want to add a{" "} + Wallet Connection? + + + ); } diff --git a/src/components/Reader.tsx b/src/components/Reader.tsx index 1ded4eef7..cb7980d35 100644 --- a/src/components/Reader.tsx +++ b/src/components/Reader.tsx @@ -8,7 +8,7 @@ import { Capacitor } from "@capacitor/core"; import QrScanner from "qr-scanner"; import { onCleanup, onMount } from "solid-js"; -export function Scanner(props: { onResult: (result: string) => void }) { +export function Reader(props: { onResult: (result: string) => void }) { let container: HTMLVideoElement | undefined; let scanner: QrScanner | undefined; diff --git a/src/components/index.ts b/src/components/index.ts index 3ac5da9ba..f00e0c731 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -50,4 +50,5 @@ export * from "./FeeDisplay"; export * from "./ReceiveWarnings"; export * from "./SimpleInput"; export * from "./LabelCircle"; -export * from "./MeOrEverybody"; +export * from "./HomeSubnav"; +export * from "./OverlayScanner"; diff --git a/src/components/layout/BackPop.tsx b/src/components/layout/BackPop.tsx index d409b2462..6a846cd2e 100644 --- a/src/components/layout/BackPop.tsx +++ b/src/components/layout/BackPop.tsx @@ -20,6 +20,8 @@ export function BackPop() { const backPath = () => (state?.previous ? state?.previous : newBackPath); + console.log("backPath", backPath()); + return ( = (props) => { + + +
  • + +
  • + +
  • + +
  • + + + +
    + +
    + + ); +} export function Main() { - const i18n = useI18n(); const [state, _actions] = useMegaStore(); + const [params] = useSearchParams(); + const navigate = useNavigate(); - const safari = iosNotNative(); + const [searching, setSearching] = createSignal( + params.search ? true : false + ); + + const [scanner, setScanner] = createSignal(false); return ( - + -
    -
    - - -
    - {state.mutiny_wallet?.get_network()} -
    -
    - -
    - {i18n.t("common.self_hosted")} -
    -
    -
    -
    - - - - - - - - - + + - + setScanner(true)} + onSearch={() => setSearching(true)} + /> - - -
    - - - } - > - - - - - -
    - + {/*
    */} + +
    +
    + setSearching(false)} + showOnDesktop + /> +
    + + setSearching(true)} + onScan={() => setScanner(true)} + /> + + setScanner(false)} /> + + + diff --git a/src/routes/NewMain.tsx b/src/routes/NewMain.tsx deleted file mode 100644 index 765342a9e..000000000 --- a/src/routes/NewMain.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { A } from "@solidjs/router"; -import { createSignal, JSX, Show, Suspense } from "solid-js"; - -import scan from "~/assets/icons/scan.svg"; -import settings from "~/assets/icons/settings.svg"; -import { - AmountSats, - BalanceBox, - BetaWarningModal, - Card, - CombinedActivity, - DecryptDialog, - DefaultMain, - HomePrompt, - Hr, - IOSbanner, - LabelCircle, - LoadingIndicator, - LoadingShimmer, - Logo, - NavBar, - NostrActivity, - OnboardWarning, - PendingNwc, - ReloadPrompt, - SafeArea, - SimpleInput, - VStack -} from "~/components"; -import { useI18n } from "~/i18n/context"; -import { FeedbackLink } from "~/routes/Feedback"; -import { useMegaStore } from "~/state/megaStore"; -import { iosNotNative } from "~/utils/platform"; - -import { ActualSearch } from "./Search"; - -function Circle(props: { children: JSX.Element }) { - return ( -
    - {props.children} -
    - ); -} - -export function NewMain() { - return ( - - -
    - -
    -

    - -

    -
    - - mutiny - -
    - {/* {}} /> */} - - - - {/*
    */} - {/* */} -
    - - - - -
    - ); -} diff --git a/src/routes/OldMain.tsx b/src/routes/OldMain.tsx new file mode 100644 index 000000000..c5f781eb1 --- /dev/null +++ b/src/routes/OldMain.tsx @@ -0,0 +1,114 @@ +import { A } from "@solidjs/router"; +import { Show, Suspense } from "solid-js"; + +import scan from "~/assets/icons/scan.svg"; +import settings from "~/assets/icons/settings.svg"; +import { + BalanceBox, + BetaWarningModal, + Card, + CombinedActivity, + DecryptDialog, + DefaultMain, + HomePrompt, + IOSbanner, + LoadingIndicator, + LoadingShimmer, + Logo, + NavBar, + OnboardWarning, + PendingNwc, + ReloadPrompt, + SafeArea, + VStack +} from "~/components"; +import { useI18n } from "~/i18n/context"; +import { FeedbackLink } from "~/routes/Feedback"; +import { useMegaStore } from "~/state/megaStore"; +import { iosNotNative } from "~/utils/platform"; + +export function OldMain() { + const i18n = useI18n(); + const [state, _actions] = useMegaStore(); + + const safari = iosNotNative(); + + return ( + + + +
    +
    + + +
    + {state.mutiny_wallet?.get_network()} +
    +
    + +
    + {i18n.t("common.self_hosted")} +
    +
    +
    + +
    + + + + + + + + + + + + + + +
    + + + } + > + + + + + +
    + +
    + + + + + + + ); +} diff --git a/src/routes/Profile.tsx b/src/routes/Profile.tsx new file mode 100644 index 000000000..e058b190a --- /dev/null +++ b/src/routes/Profile.tsx @@ -0,0 +1,228 @@ +import { Capacitor } from "@capacitor/core"; +import { A } from "@solidjs/router"; +import { For, Show } from "solid-js"; + +import forward from "~/assets/icons/forward.svg"; +import { + BackLink, + BalanceBox, + ButtonLink, + CopyButton, + DefaultMain, + ExternalLink, + IntegratedQr, + LabelCircle, + LargeHeader, + MiniStringShower, + MutinyPlusCta, + NavBar, + SafeArea, + SettingsCard, + TinyText, + VStack +} from "~/components"; +import { useI18n } from "~/i18n/context"; +import { useMegaStore } from "~/state/megaStore"; +import { isFreeGiftingDay } from "~/utils"; + +function SettingsLinkList(props: { + header: string; + links: { + href: string; + text: string; + caption?: string; + accent?: "red" | "green"; + disabled?: boolean; + }[]; +}) { + return ( + + + {(link) => ( + +
    + + {link.text} + + go +
    + +
    + {link.caption} +
    +
    +
    + )} +
    +
    + ); +} + +export function Profile() { + const i18n = useI18n(); + const [state, _actions] = useMegaStore(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const RELEASE_VERSION = import.meta.env.__RELEASE_VERSION__; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const COMMIT_HASH = import.meta.env.__COMMIT_HASH__; + + const selfHosted = state.settings?.selfhosted === "true"; + const freeDay = isFreeGiftingDay(); + + const ios = Capacitor.getPlatform() === "ios"; + + return ( + + + +
    + +

    futurepaul

    + {/* */} +
    +
    futurepaul@mutiny.plus
    + +
    + + + Edit Profile + +
    + Accounts + + + {i18n.t("settings.header")} + + + + + + + +
    + + {i18n.t("settings.version")} {RELEASE_VERSION}{" "} + + {COMMIT_HASH} + + +
    +
    +
    + +
    + ); +} diff --git a/src/routes/Scanner.tsx b/src/routes/Scanner.tsx index 72383e457..0e4687d1d 100644 --- a/src/routes/Scanner.tsx +++ b/src/routes/Scanner.tsx @@ -3,7 +3,7 @@ import { Capacitor } from "@capacitor/core"; import { useNavigate } from "@solidjs/router"; import { createEffect, createSignal } from "solid-js"; -import { Button, Scanner as Reader, showToast } from "~/components"; +import { Button, Reader, showToast } from "~/components"; import { useI18n } from "~/i18n/context"; import { useMegaStore } from "~/state/megaStore"; diff --git a/src/routes/Search.tsx b/src/routes/Search.tsx index 19dfc6f3b..607a23416 100644 --- a/src/routes/Search.tsx +++ b/src/routes/Search.tsx @@ -1,7 +1,7 @@ import { Clipboard } from "@capacitor/clipboard"; import { Capacitor } from "@capacitor/core"; import { TagItem } from "@mutinywallet/mutiny-wasm"; -import { A, useNavigate } from "@solidjs/router"; +import { A, useNavigate, useSearchParams } from "@solidjs/router"; import { createEffect, createMemo, @@ -36,6 +36,7 @@ import { SafeArea } from "~/components/layout"; import { useI18n } from "~/i18n/context"; +import { ParsedParams } from "~/logic/waila"; import { useMegaStore } from "~/state/megaStore"; import { actuallyFetchNostrProfile, @@ -71,7 +72,7 @@ export function Search() { ); } -export function ActualSearch() { +export function ActualSearch(props: { initialValue?: string }) { const [searchValue, setSearchValue] = createSignal(""); const [debouncedSearchValue, setDebouncedSearchValue] = createSignal(""); const [state, actions] = useMegaStore(); @@ -149,6 +150,16 @@ export function ActualSearch() { return state; }); + function navWithSearchValue() { + navigate("/send", { + state: { + previous: searchValue() + ? `/search/?search=${searchValue().trim()}` + : "/search" + } + }); + } + function handleContinue() { actions.handleIncomingString( debouncedSearchValue().trim(), @@ -158,7 +169,11 @@ export function ActualSearch() { (result) => { if (result) { actions.setScanResult(result); - navigate("/send", { state: { previous: "/search" } }); + navigate("/send", { + state: { + previous: "/search" + } + }); } else { showToast(new Error(i18n.t("send.error_address"))); } @@ -179,7 +194,7 @@ export function ActualSearch() { ...result, contact_id: contact.id }); - navigate("/send", { state: { previous: "/search" } }); + navWithSearchValue(); } ); } else { @@ -251,7 +266,11 @@ export function ActualSearch() { let searchInputRef!: HTMLInputElement; + const [params, setParams] = useSearchParams(); + onMount(() => { + setSearchValue(props.initialValue || ""); + setParams({ search: "" }); searchInputRef.focus(); }); @@ -285,11 +304,11 @@ export function ActualSearch() {
    - + {/* }> - + */}