diff --git a/package.json b/package.json index 5edefe8e..1d1e6e8c 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,6 @@ "workbox-window": "^7.0.0" }, "dependencies": { - "i18next-http-backend": "^2.5.0", "@capacitor-mlkit/barcode-scanning": "^5.3.0", "@capacitor/android": "^5.5.1", "@capacitor/app": "^5.0.6", @@ -49,19 +48,21 @@ "@capacitor/filesystem": "^5.1.4", "@capacitor/haptics": "^5.0.6", "@capacitor/ios": "^5.5.1", + "@capacitor/network": "^6.0.0", "@capacitor/share": "^5.0.6", "@capacitor/status-bar": "^5.0.6", "@capacitor/toast": "^5.0.6", "@kobalte/core": "^0.12.6", "@kobalte/tailwindcss": "^0.9.0", - "@mutinywallet/mutiny-wasm": "0.6.5", "@modular-forms/solid": "^0.20.0", + "@mutinywallet/mutiny-wasm": "0.6.5", "@solid-primitives/upload": "^0.0.117", "@solidjs/meta": "^0.29.3", "@solidjs/router": "^0.13.1", "capacitor-secure-storage-plugin": "^0.9.0", "i18next": "^23.10.1", "i18next-browser-languagedetector": "^7.1.0", + "i18next-http-backend": "^2.5.0", "lucide-solid": "^0.363.0", "qr-scanner": "^1.4.2", "solid-js": "^1.8.16", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4fd24dd2..3f8e894b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ dependencies: '@capacitor/ios': specifier: ^5.5.1 version: 5.7.4(@capacitor/core@5.7.4) + '@capacitor/network': + specifier: ^6.0.0 + version: 6.0.0(@capacitor/core@5.7.4) '@capacitor/share': specifier: ^5.0.6 version: 5.0.7(@capacitor/core@5.7.4) @@ -1517,6 +1520,14 @@ packages: '@capacitor/core': 5.7.4 dev: false + /@capacitor/network@6.0.0(@capacitor/core@5.7.4): + resolution: {integrity: sha512-igGbz3VZuchnfQ/kSFxMsQjLGvKYmEKYzK5RD5S7leLaoBox0B3ueW04yRI2HcGC+PSIo9F52qDL8J6qb1N0vg==} + peerDependencies: + '@capacitor/core': ^6.0.0 + dependencies: + '@capacitor/core': 5.7.4 + dev: false + /@capacitor/share@5.0.7(@capacitor/core@5.7.4): resolution: {integrity: sha512-4GraggRRxwhstxIdF9JyOEBq4QTufqFOekdB4P9GeiQYWJoA5VraSR1mwy4Trke1VFfaBjz/nGi4WQOJdHIAgg==} peerDependencies: @@ -7567,7 +7578,6 @@ packages: /workbox-google-analytics@7.0.0: resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==} - deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained dependencies: workbox-background-sync: 7.0.0 workbox-core: 7.0.0 diff --git a/public/i18n/en.json b/public/i18n/en.json index 9030f1aa..694e6344 100644 --- a/public/i18n/en.json +++ b/public/i18n/en.json @@ -780,5 +780,10 @@ "nowish": "Nowish", "seconds_future": "Seconds from now", "seconds_past": "Just now" + }, + "no_connection": { + "title": "No internet connection", + "prompt": "Get back online to start using Mutiny.", + "reload": "Reload" } } diff --git a/src/components/NoConnection.tsx b/src/components/NoConnection.tsx new file mode 100644 index 00000000..516c7e05 --- /dev/null +++ b/src/components/NoConnection.tsx @@ -0,0 +1,26 @@ +import { WifiOff } from "lucide-solid"; + +import { Button, DefaultMain } from "~/components/layout"; +import { useI18n } from "~/i18n/context"; + +export function NoConnection() { + const i18n = useI18n(); + return ( + +
+
+ +

+ {i18n.t("no_connection.title")} +

+

+ {i18n.t("no_connection.prompt")} +

+
+ +
+ + ); +} diff --git a/src/components/index.ts b/src/components/index.ts index b2c9e40e..77254e5a 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -58,3 +58,4 @@ export * from "./EditProfileForm"; export * from "./ImportNsecForm"; export * from "./LightningAddressShower"; export * from "./FederationInviteShower"; +export * from "./NoConnection"; diff --git a/src/router.tsx b/src/router.tsx index 1c78239f..5158f7a8 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -15,6 +15,7 @@ import { import { ErrorDisplay, I18nProvider, + NoConnection, SetupErrorDisplay, Toaster } from "~/components"; @@ -125,6 +126,9 @@ function ChildrenOrError(props: { children: JSX.Element }) { password={state.password} /> + + + {props.children} ); diff --git a/src/state/megaStore.tsx b/src/state/megaStore.tsx index 0d7dda32..5b30e587 100644 --- a/src/state/megaStore.tsx +++ b/src/state/megaStore.tsx @@ -1,6 +1,7 @@ /* @refresh reload */ // Inspired by https://github.com/solidjs/solid-realworld/blob/main/src/store/index.js +import { ConnectionStatus, Network } from "@capacitor/network"; import { MutinyBalance, MutinyWallet, @@ -74,6 +75,7 @@ type MegaStore = [ should_zap_hodl: boolean; federations?: MutinyFederationIdentity[]; balanceView: "sats" | "fiat" | "hidden"; + network_status?: ConnectionStatus; }, { setup(password?: string): Promise; @@ -140,7 +142,8 @@ export const Provider: ParentComponent = (props) => { testflightPromptDismissed: localStorage.getItem("testflightPromptDismissed") === "true", federations: undefined as MutinyFederationIdentity[] | undefined, - balanceView: localStorage.getItem("balanceView") || "sats" + balanceView: localStorage.getItem("balanceView") || "sats", + network_status: undefined as ConnectionStatus | undefined }); const actions = { @@ -527,6 +530,15 @@ export const Provider: ParentComponent = (props) => { return; } + const _networkListener = Network.addListener( + "networkStatusChange", + async (status) => { + setState({ + network_status: status + }); + } + ); + console.log("checking for browser compatibility"); try { await checkBrowserCompatibility();