diff --git a/package-lock.json b/package-lock.json index 98a37c1f..6e35c406 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@getalby/bitcoin-connect-react": "^3.7.0", + "@getalby/bitcoin-connect-react": "^3.10.0", "@noble/hashes": "^1.6.1", "@radix-ui/react-alert-dialog": "^1.1.4", "@radix-ui/react-avatar": "^1.1.2", @@ -2253,32 +2253,35 @@ "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" }, "node_modules/@getalby/bitcoin-connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@getalby/bitcoin-connect/-/bitcoin-connect-3.7.0.tgz", - "integrity": "sha512-9Tzn7tCJ2awniiunRvTcEQRJQEhw5hZLVBCmhckgAP0GRj5kESnoWfA1jX0WKZZVtSq/2qOfX1wMiz73gCd8gQ==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@getalby/bitcoin-connect/-/bitcoin-connect-3.10.0.tgz", + "integrity": "sha512-6UXeu0SzEmw4Fhyw9jP6PMH7dqHYQTdmdziUPxv4HE8xMO6Q+g5xPbPrK9R36ASB7P680JCQRnoJiltgP3fwLA==", + "license": "MIT", "dependencies": { - "@getalby/lightning-tools": "^5.1.2", - "@getalby/sdk": "^4.1.1", - "@lightninglabs/lnc-web": "^0.3.2-alpha", - "qrcode-generator": "^1.4.4", - "zustand": "^4.5.6" + "@getalby/lightning-tools": "^5.2.1", + "@getalby/sdk": "^5.1.2", + "@lightninglabs/lnc-web": "^0.3.4-alpha", + "qrcode-generator": "1.4.4", + "zustand": "^4.5.7" } }, "node_modules/@getalby/bitcoin-connect-react": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@getalby/bitcoin-connect-react/-/bitcoin-connect-react-3.7.0.tgz", - "integrity": "sha512-wO8RhUlxJ4ub6vl8x8BScUaG4Z/tnLcDvJd9V4V7AOlrmrItMJfViZmc14c/WVU/RREeE3MSY2GZ0wYoH2TzxA==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@getalby/bitcoin-connect-react/-/bitcoin-connect-react-3.10.0.tgz", + "integrity": "sha512-yruMhqbzxOuNqOM/kiNpIxjtZqFHsBAl0pI4GCRlKflHrGSGlu9/vpYT1XkWWag2IDy9VnDYPvVvznAX17chjQ==", + "license": "MIT", "dependencies": { - "@getalby/bitcoin-connect": "^3.7.0" + "@getalby/bitcoin-connect": "^3.10.0" }, "peerDependencies": { "react": "^18.2.0" } }, "node_modules/@getalby/lightning-tools": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@getalby/lightning-tools/-/lightning-tools-5.1.2.tgz", - "integrity": "sha512-BwGm8eGbPh59BVa1gI5yJMantBl/Fdps6X4p1ZACnmxz9vDINX8/3aFoOnDlF7yyA2boXWCsReVQSr26Q2yjiQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@getalby/lightning-tools/-/lightning-tools-5.2.1.tgz", + "integrity": "sha512-dxOmJLJAh6qJ8rsbA5/Bwj7MSI9X3RkxxqmCedl5rfP+yKwNSdfu8i4EiCZN/tk2hNBJb8GHSCcPRNZfwfmEHg==", + "license": "MIT", "engines": { "node": ">=14" }, @@ -2288,11 +2291,13 @@ } }, "node_modules/@getalby/sdk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@getalby/sdk/-/sdk-4.1.1.tgz", - "integrity": "sha512-Tm0Puqm3qpXxSfUhiO8W7Uaq9Fx/Ww2aOv3sjRYL1jukLi+GRj4s65QCsjCIWaKWUN+RCJMlW3LtKFnUQC/O3A==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@getalby/sdk/-/sdk-5.1.2.tgz", + "integrity": "sha512-yUF9LhuvdIFOwjV1aG0ryzfwDiGBFk/CRLkRvrrM9dsE38SUjKsf1FDga5jxsKMu80nWcPZR9TiGGASWedoYPA==", + "license": "MIT", "dependencies": { - "nostr-tools": "2.9.4" + "@getalby/lightning-tools": "^5.2.0", + "nostr-tools": "2.15.0" }, "engines": { "node": ">=14" @@ -2306,6 +2311,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "license": "MIT", "engines": { "node": ">= 16" }, @@ -2314,19 +2320,18 @@ } }, "node_modules/@getalby/sdk/node_modules/nostr-tools": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.9.4.tgz", - "integrity": "sha512-Powumwkp+EWbdK1T8IsEX4daTLQhtWJvitfZ6OP2BdU1jJZvNlUp3SQB541UYw4uc9jgLbxZW6EZSdZoSfIygQ==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.15.0.tgz", + "integrity": "sha512-Jj/+UFbu3JbTAWP4ipPFNuyD4W5eVRBNAP+kmnoRCYp3bLmTrlQ0Qhs5O1xSQJTFpjdZqoS0zZOUKdxUdjc+pw==", + "license": "Unlicense", "dependencies": { "@noble/ciphers": "^0.5.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.1", "@scure/base": "1.1.1", "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1" - }, - "optionalDependencies": { - "nostr-wasm": "v0.1.0" + "@scure/bip39": "1.2.1", + "nostr-wasm": "0.1.0" }, "peerDependencies": { "typescript": ">=5.0.0" @@ -2468,16 +2473,18 @@ } }, "node_modules/@lightninglabs/lnc-core": { - "version": "0.3.2-alpha", - "resolved": "https://registry.npmjs.org/@lightninglabs/lnc-core/-/lnc-core-0.3.2-alpha.tgz", - "integrity": "sha512-H6tG+X9txCIdxTR+GPsbImzP2Juo+6Uvq/Ipaijd7xPISzgEU4J4GNE5PEHuIZqbnBo1RmpuXnFG6dmsl3PTzQ==" + "version": "0.3.4-alpha", + "resolved": "https://registry.npmjs.org/@lightninglabs/lnc-core/-/lnc-core-0.3.4-alpha.tgz", + "integrity": "sha512-S/L1gNHqF8jW3DVXBvzVX8zyJO4O2FRfKFNE5U3rtRBaczX+fSVpK3yz/CdgBqhBzyZ+1un6nVZE/tftnfjQwA==", + "license": "MIT" }, "node_modules/@lightninglabs/lnc-web": { - "version": "0.3.2-alpha", - "resolved": "https://registry.npmjs.org/@lightninglabs/lnc-web/-/lnc-web-0.3.2-alpha.tgz", - "integrity": "sha512-3aCBugBf0NzczpJqmHn03Oq2Ju9W5n0+nOdAe+Y/Zhf6YLXdqG1PTJ2J+7TXncpiogfPYDCw95tVQqSi4Zi/ZA==", + "version": "0.3.4-alpha", + "resolved": "https://registry.npmjs.org/@lightninglabs/lnc-web/-/lnc-web-0.3.4-alpha.tgz", + "integrity": "sha512-ARTsCm71ewJ3sWaW4DEauEXr9wG4qPpCMWGGVjbjvvo5Jvd3svLO610JLYoV7LvQhyW6dKLlAooLxYws2y9FLA==", + "license": "MIT", "dependencies": { - "@lightninglabs/lnc-core": "0.3.2-alpha", + "@lightninglabs/lnc-core": "0.3.4-alpha", "crypto-js": "4.2.0" } }, @@ -6756,7 +6763,8 @@ "node_modules/crypto-js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", - "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" }, "node_modules/crypto-random-string": { "version": "2.0.0", @@ -13059,9 +13067,10 @@ } }, "node_modules/zustand": { - "version": "4.5.6", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.6.tgz", - "integrity": "sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ==", + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", "dependencies": { "use-sync-external-store": "^1.2.2" }, diff --git a/package.json b/package.json index fc4a956f..b2e3dd09 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@getalby/bitcoin-connect-react": "^3.7.0", + "@getalby/bitcoin-connect-react": "^3.10.0", "@noble/hashes": "^1.6.1", "@radix-ui/react-alert-dialog": "^1.1.4", "@radix-ui/react-avatar": "^1.1.2", diff --git a/src/PageManager.tsx b/src/PageManager.tsx index a2a76a64..b9de6fc3 100644 --- a/src/PageManager.tsx +++ b/src/PageManager.tsx @@ -28,6 +28,7 @@ import { NotificationProvider } from './providers/NotificationProvider' import { useScreenSize } from './providers/ScreenSizeProvider' import { routes } from './routes' import modalManager from './services/modal-manager.service' +import CreateWalletGuideToast from './components/CreateWalletGuideToast' export type TPrimaryPageName = keyof typeof PRIMARY_PAGE_MAP @@ -321,6 +322,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { ))} + @@ -382,6 +384,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) { + diff --git a/src/components/CreateWalletGuideToast/index.tsx b/src/components/CreateWalletGuideToast/index.tsx new file mode 100644 index 00000000..3a6aae5d --- /dev/null +++ b/src/components/CreateWalletGuideToast/index.tsx @@ -0,0 +1,31 @@ +import { toWallet } from '@/lib/link' +import { useSecondaryPage } from '@/PageManager' +import { useNostr } from '@/providers/NostrProvider' +import storage from '@/services/local-storage.service' +import { useEffect } from 'react' +import { useTranslation } from 'react-i18next' +import { toast } from 'sonner' + +export default function CreateWalletGuideToast() { + const { t } = useTranslation() + const { push } = useSecondaryPage() + const { profile } = useNostr() + + useEffect(() => { + if ( + profile && + !profile.lightningAddress && + !storage.hasShownCreateWalletGuideToast(profile.pubkey) + ) { + toast(t('Set up your wallet to send and receive sats!'), { + action: { + label: t('Set up'), + onClick: () => push(toWallet()) + } + }) + storage.markCreateWalletGuideToastAsShown(profile.pubkey) + } + }, [profile]) + + return null +} diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index faad33f5..27030ecf 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -17,7 +17,7 @@ const buttonVariants = cva( 'secondary-2': 'bg-secondary text-secondary-foreground hover:bg-primary', ghost: 'clickable hover:text-accent-foreground', 'ghost-destructive': 'cursor-pointer hover:bg-destructive/20 text-destructive', - link: 'text-primary underline-offset-4 hover:underline' + link: 'text-foreground underline-offset-4 hover:underline' }, size: { default: 'h-9 px-4 py-2', diff --git a/src/constants.ts b/src/constants.ts index fe90f1f7..4028264c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -47,6 +47,7 @@ export const StorageKey = { HIDE_CONTENT_MENTIONING_MUTED_USERS: 'hideContentMentioningMutedUsers', NOTIFICATION_LIST_STYLE: 'notificationListStyle', MEDIA_AUTO_LOAD_POLICY: 'mediaAutoLoadPolicy', + SHOWN_CREATE_WALLET_GUIDE_TOAST_PUBKEYS: 'shownCreateWalletGuideToastPubkeys', MEDIA_UPLOAD_SERVICE: 'mediaUploadService', // deprecated HIDE_UNTRUSTED_EVENTS: 'hideUntrustedEvents', // deprecated ACCOUNT_RELAY_LIST_EVENT_MAP: 'accountRelayListEventMap', // deprecated diff --git a/src/i18n/locales/ar.ts b/src/i18n/locales/ar.ts index 3b590087..dd912060 100644 --- a/src/i18n/locales/ar.ts +++ b/src/i18n/locales/ar.ts @@ -421,6 +421,27 @@ export default { 'Write relays and {{count}} other relays': 'مرحلات الكتابة و {{count}} مرحل آخر', '{{count}} relays': '{{count}} ريلايات', 'Republishing...': 'جارٍ إعادة النشر...', - 'Trending Notes': 'الملاحظات الرائجة' + 'Trending Notes': 'الملاحظات الرائجة', + 'Connected to': 'متصل بـ', + 'Disconnect Wallet': 'قطع الاتصال بالمحفظة', + 'Are you absolutely sure?': 'هل أنت متأكد تماماً؟', + 'You will not be able to send zaps to others.': 'لن تتمكن من إرسال zaps للآخرين.', + Disconnect: 'قطع الاتصال', + 'Start with a Rizful Vault': 'ابدأ بمحفظة Rizful', + 'or other wallets': 'أو محافظ أخرى', + 'Rizful Vault': 'محفظة Rizful', + 'Rizful Vault connected!': 'تم توصيل محفظة Rizful!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'يمكنك الآن استخدام محفظة Rizful الخاصة بك لإرسال zap إلى ملاحظاتك والمبدعين المفضلين لديك.', + 'Your Lightning Address': 'عنوان Lightning الخاص بك', + 'New to Rizful?': 'جديد في Rizful؟', + 'Sign up for Rizful': 'سجل في Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'إذا كان لديك حساب Rizful بالفعل، يمكنك تخطي هذه الخطوة.', + 'Get your one-time code': 'احصل على رمز الاستخدام مرة واحدة', + 'Get code': 'احصل على الرمز', + 'Connect to your Rizful Vault': 'الاتصال بمحفظة Rizful الخاصة بك', + 'Paste your one-time code here': 'الصق رمز الاستخدام مرة واحدة هنا', + Connect: 'اتصال' } } diff --git a/src/i18n/locales/de.ts b/src/i18n/locales/de.ts index 2b2a91f5..ddf247fc 100644 --- a/src/i18n/locales/de.ts +++ b/src/i18n/locales/de.ts @@ -433,6 +433,28 @@ export default { 'Write relays and {{count}} other relays': 'Schreib-Relays und {{count}} andere Relays', '{{count}} relays': '{{count}} Relays', 'Republishing...': 'Wird erneut veröffentlicht...', - 'Trending Notes': 'Trendende Notizen' + 'Trending Notes': 'Trendende Notizen', + 'Connected to': 'Verbunden mit', + 'Disconnect Wallet': 'Wallet trennen', + 'Are you absolutely sure?': 'Bist du dir absolut sicher?', + 'You will not be able to send zaps to others.': + 'Du wirst keine Zaps mehr an andere senden können.', + Disconnect: 'Trennen', + 'Start with a Rizful Vault': 'Starte mit einem Rizful Vault', + 'or other wallets': 'oder andere Wallets', + 'Rizful Vault': 'Rizful Vault', + 'Rizful Vault connected!': 'Rizful Vault verbunden!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'Du kannst jetzt dein Rizful Vault verwenden, um deine Lieblingsnotizen und -ersteller zu zapen.', + 'Your Lightning Address': 'Deine Lightning-Adresse', + 'New to Rizful?': 'Neu bei Rizful?', + 'Sign up for Rizful': 'Registriere dich bei Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'Wenn du bereits ein Rizful-Konto hast, kannst du diesen Schritt überspringen.', + 'Get your one-time code': 'Hole dir deinen Einmal-Code', + 'Get code': 'Code holen', + 'Connect to your Rizful Vault': 'Verbinde dich mit deinem Rizful Vault', + 'Paste your one-time code here': 'Füge hier deinen Einmal-Code ein', + Connect: 'Verbinden' } } diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index dc2a840e..a834b942 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -420,6 +420,27 @@ export default { 'Write relays and {{count}} other relays': 'Write relays and {{count}} other relays', '{{count}} relays': '{{count}} relays', 'Republishing...': 'Republishing...', - 'Trending Notes': 'Trending Notes' + 'Trending Notes': 'Trending Notes', + 'Connected to': 'Connected to', + 'Disconnect Wallet': 'Disconnect Wallet', + 'Are you absolutely sure?': 'Are you absolutely sure?', + 'You will not be able to send zaps to others.': 'You will not be able to send zaps to others.', + Disconnect: 'Disconnect', + 'Start with a Rizful Vault': 'Start with a Rizful Vault', + 'or other wallets': 'or other wallets', + 'Rizful Vault': 'Rizful Vault', + 'Rizful Vault connected!': 'Rizful Vault connected!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'You can now use your Rizful Vault to zap your favorite notes and creators.', + 'Your Lightning Address': 'Your Lightning Address', + 'New to Rizful?': 'New to Rizful?', + 'Sign up for Rizful': 'Sign up for Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'If you already have a Rizful account, you can skip this step.', + 'Get your one-time code': 'Get your one-time code', + 'Get code': 'Get code', + 'Connect to your Rizful Vault': 'Connect to your Rizful Vault', + 'Paste your one-time code here': 'Paste your one-time code here', + Connect: 'Connect' } } diff --git a/src/i18n/locales/es.ts b/src/i18n/locales/es.ts index 0b923783..2d4ebb76 100644 --- a/src/i18n/locales/es.ts +++ b/src/i18n/locales/es.ts @@ -428,6 +428,27 @@ export default { 'Write relays and {{count}} other relays': 'Relés de escritura y {{count}} otros relés', '{{count}} relays': '{{count}} relés', 'Republishing...': 'Republicando...', - 'Trending Notes': 'Notas de tendencia' + 'Trending Notes': 'Notas de tendencia', + 'Connected to': 'Conectado a', + 'Disconnect Wallet': 'Desconectar billetera', + 'Are you absolutely sure?': '¿Estás absolutamente seguro?', + 'You will not be able to send zaps to others.': 'No podrás enviar zaps a otros.', + Disconnect: 'Desconectar', + 'Start with a Rizful Vault': 'Comienza con una Bóveda Rizful', + 'or other wallets': 'o otras billeteras', + 'Rizful Vault': 'Bóveda Rizful', + 'Rizful Vault connected!': '¡Bóveda Rizful conectada!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'Ahora puedes usar tu Bóveda Rizful para zapear tus notas y creadores favoritos.', + 'Your Lightning Address': 'Tu Dirección Lightning', + 'New to Rizful?': '¿Nuevo en Rizful?', + 'Sign up for Rizful': 'Regístrate en Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'Si ya tienes una cuenta de Rizful, puedes omitir este paso.', + 'Get your one-time code': 'Obtén tu código de un solo uso', + 'Get code': 'Obtener código', + 'Connect to your Rizful Vault': 'Conéctate a tu Bóveda Rizful', + 'Paste your one-time code here': 'Pega tu código de un solo uso aquí', + Connect: 'Conectar' } } diff --git a/src/i18n/locales/fa.ts b/src/i18n/locales/fa.ts index b51e42dc..fa697675 100644 --- a/src/i18n/locales/fa.ts +++ b/src/i18n/locales/fa.ts @@ -423,6 +423,27 @@ export default { 'Write relays and {{count}} other relays': 'رله‌های نوشتن و {{count}} رله دیگر', '{{count}} relays': '{{count}} رله', 'Republishing...': 'در حال بازنشر...', - 'Trending Notes': 'یادداشت‌های محبوب' + 'Trending Notes': 'یادداشت‌های محبوب', + 'Connected to': 'متصل به', + 'Disconnect Wallet': 'قطع اتصال کیف پول', + 'Are you absolutely sure?': 'آیا کاملاً مطمئن هستید؟', + 'You will not be able to send zaps to others.': 'شما قادر نخواهید بود به دیگران زپ ارسال کنید.', + Disconnect: 'قطع اتصال', + 'Start with a Rizful Vault': 'شروع با Rizful Vault', + 'or other wallets': 'یا کیف پول‌های دیگر', + 'Rizful Vault': 'Rizful Vault', + 'Rizful Vault connected!': 'Rizful Vault متصل شد!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'اکنون می‌توانید از Rizful Vault خود برای زپ کردن یادداشت‌ها و سازندگان مورد علاقه خود استفاده کنید.', + 'Your Lightning Address': 'آدرس لایتنینگ شما', + 'New to Rizful?': 'جدید در Rizful؟', + 'Sign up for Rizful': 'برای Rizful ثبت نام کنید', + 'If you already have a Rizful account, you can skip this step.': + 'اگر قبلاً حساب Rizful دارید، می‌توانید این مرحله را رد کنید.', + 'Get your one-time code': 'کد یکبار مصرف خود را دریافت کنید', + 'Get code': 'دریافت کد', + 'Connect to your Rizful Vault': 'اتصال به Rizful Vault خود', + 'Paste your one-time code here': 'کد یکبار مصرف خود را اینجا بچسبانید', + Connect: 'اتصال' } } diff --git a/src/i18n/locales/fr.ts b/src/i18n/locales/fr.ts index 277aba3b..a9be6e78 100644 --- a/src/i18n/locales/fr.ts +++ b/src/i18n/locales/fr.ts @@ -432,6 +432,28 @@ export default { 'Write relays and {{count}} other relays': 'Relais d’écriture et {{count}} autres relais', '{{count}} relays': '{{count}} relais', 'Republishing...': 'Republication en cours...', - 'Trending Notes': 'Notes tendance' + 'Trending Notes': 'Notes tendance', + 'Connected to': 'Connecté à', + 'Disconnect Wallet': 'Déconnecter le portefeuille', + 'Are you absolutely sure?': 'Êtes-vous absolument sûr ?', + 'You will not be able to send zaps to others.': + 'Vous ne pourrez plus envoyer de zaps aux autres.', + Disconnect: 'Déconnecter', + 'Start with a Rizful Vault': 'Démarrer avec un coffre Rizful', + 'or other wallets': 'ou d’autres portefeuilles', + 'Rizful Vault': 'Coffre Rizful', + 'Rizful Vault connected!': 'Coffre Rizful connecté !', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'Vous pouvez maintenant utiliser votre coffre Rizful pour zapper vos notes et créateurs préférés.', + 'Your Lightning Address': 'Votre adresse Lightning', + 'New to Rizful?': 'Nouveau sur Rizful ?', + 'Sign up for Rizful': 'Inscrivez-vous sur Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'Si vous avez déjà un compte Rizful, vous pouvez passer cette étape.', + 'Get your one-time code': 'Obtenez votre code à usage unique', + 'Get code': 'Obtenir le code', + 'Connect to your Rizful Vault': 'Connectez-vous à votre coffre Rizful', + 'Paste your one-time code here': 'Collez votre code à usage unique ici', + Connect: 'Connecter' } } diff --git a/src/i18n/locales/hi.ts b/src/i18n/locales/hi.ts index a89400a5..2b19c5b9 100644 --- a/src/i18n/locales/hi.ts +++ b/src/i18n/locales/hi.ts @@ -425,6 +425,27 @@ export default { 'Write relays and {{count}} other relays': 'राइट रिले और {{count}} अन्य रिले', '{{count}} relays': '{{count}} रिले', 'Republishing...': 'पुनः प्रकाशित कर रहे हैं...', - 'Trending Notes': 'ट्रेंडिंग नोट्स' + 'Trending Notes': 'ट्रेंडिंग नोट्स', + 'Connected to': 'से कनेक्टेड', + 'Disconnect Wallet': 'वॉलेट डिस्कनेक्ट करें', + 'Are you absolutely sure?': 'क्या आप पूरी तरह से सुनिश्चित हैं?', + 'You will not be able to send zaps to others.': 'आप दूसरों को जैप नहीं भेज पाएंगे।', + Disconnect: 'डिस्कनेक्ट करें', + 'Start with a Rizful Vault': 'Rizful वॉल्ट के साथ शुरू करें', + 'or other wallets': 'या अन्य वॉलेट', + 'Rizful Vault': 'Rizful वॉल्ट', + 'Rizful Vault connected!': 'Rizful वॉल्ट कनेक्टेड!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'अब आप अपने Rizful वॉल्ट का उपयोग अपने पसंदीदा नोट्स और क्रिएटर्स को जैप करने के लिए कर सकते हैं।', + 'Your Lightning Address': 'आपका लाइटनिंग पता', + 'New to Rizful?': 'Rizful में नया?', + 'Sign up for Rizful': 'Rizful के लिए साइन अप करें', + 'If you already have a Rizful account, you can skip this step.': + 'यदि आपके पास पहले से ही एक Rizful अकाउंट है, तो आप इस चरण को छोड़ सकते हैं।', + 'Get your one-time code': 'अपना वन-टाइम कोड प्राप्त करें', + 'Get code': 'कोड प्राप्त करें', + 'Connect to your Rizful Vault': 'अपने Rizful वॉल्ट से कनेक्ट करें', + 'Paste your one-time code here': 'अपना वन-टाइम कोड यहां पेस्ट करें', + Connect: 'कनेक्ट करें' } } diff --git a/src/i18n/locales/it.ts b/src/i18n/locales/it.ts index 05c90004..fee6acd3 100644 --- a/src/i18n/locales/it.ts +++ b/src/i18n/locales/it.ts @@ -428,6 +428,27 @@ export default { 'Write relays and {{count}} other relays': 'Relay di scrittura e {{count}} altri relay', '{{count}} relays': '{{count}} relay', 'Republishing...': 'Ricondivisione in corso...', - 'Trending Notes': 'Note di tendenza' + 'Trending Notes': 'Note di tendenza', + 'Connected to': 'Connesso a', + 'Disconnect Wallet': 'Disconnetti Wallet', + 'Are you absolutely sure?': 'Sei assolutamente sicuro?', + 'You will not be able to send zaps to others.': 'Non sarai in grado di inviare zaps ad altri.', + Disconnect: 'Disconnetti', + 'Start with a Rizful Vault': 'Inizia con un Rizful Vault', + 'or other wallets': 'o altri wallet', + 'Rizful Vault': 'Rizful Vault', + 'Rizful Vault connected!': 'Rizful Vault connesso!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'Puoi ora usare il tuo Rizful Vault per zappare le tue note e creatori preferiti.', + 'Your Lightning Address': 'Il tuo Indirizzo Lightning', + 'New to Rizful?': 'Nuovo a Rizful?', + 'Sign up for Rizful': 'Iscriviti a Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'Se hai già un account Rizful, puoi saltare questo passaggio.', + 'Get your one-time code': 'Ottieni il tuo codice monouso', + 'Get code': 'Ottieni codice', + 'Connect to your Rizful Vault': 'Connettiti al tuo Rizful Vault', + 'Paste your one-time code here': 'Incolla qui il tuo codice monouso', + Connect: 'Connetti' } } diff --git a/src/i18n/locales/ja.ts b/src/i18n/locales/ja.ts index 451212fb..adde8c46 100644 --- a/src/i18n/locales/ja.ts +++ b/src/i18n/locales/ja.ts @@ -424,6 +424,27 @@ export default { 'Write relays and {{count}} other relays': '書き込みリレーと他の {{count}} 個のリレー', '{{count}} relays': '{{count}} 個のリレー', 'Republishing...': '再公開中...', - 'Trending Notes': '注目のノート' + 'Trending Notes': '注目のノート', + 'Connected to': '接続先', + 'Disconnect Wallet': 'ウォレットの接続を解除', + 'Are you absolutely sure?': '本当に確かですか?', + 'You will not be able to send zaps to others.': '他の人にZapを送信できなくなります。', + Disconnect: '接続解除', + 'Start with a Rizful Vault': 'Rizful Vaultで始める', + 'or other wallets': 'または他のウォレット', + 'Rizful Vault': 'Rizful Vault', + 'Rizful Vault connected!': 'Rizful Vaultが接続されました!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'これで、Rizful Vaultを使用してお気に入りのノートやクリエイターにZapを送信できます。', + 'Your Lightning Address': 'あなたのライトニングアドレス', + 'New to Rizful?': 'Rizfulを初めて利用しますか?', + 'Sign up for Rizful': 'Rizfulにサインアップ', + 'If you already have a Rizful account, you can skip this step.': + 'すでにRizfulアカウントをお持ちの場合は、このステップをスキップできます。', + 'Get your one-time code': 'ワンタイムコードを取得', + 'Get code': 'コードを取得', + 'Connect to your Rizful Vault': 'Rizful Vaultに接続', + 'Paste your one-time code here': 'ここにワンタイムコードを貼り付けてください', + Connect: '接続' } } diff --git a/src/i18n/locales/ko.ts b/src/i18n/locales/ko.ts index 3fd094d0..7f3a783c 100644 --- a/src/i18n/locales/ko.ts +++ b/src/i18n/locales/ko.ts @@ -424,6 +424,27 @@ export default { 'Write relays and {{count}} other relays': '쓰기 릴레이 및 기타 {{count}}개 릴레이', '{{count}} relays': '{{count}}개 릴레이', 'Republishing...': '다시 게시 중...', - 'Trending Notes': '트렌딩 노트' + 'Trending Notes': '트렌딩 노트', + 'Connected to': '연결됨', + 'Disconnect Wallet': '지갑 연결 해제', + 'Are you absolutely sure?': '정말 확실합니까?', + 'You will not be able to send zaps to others.': '다른 사람에게 잽을 보낼 수 없습니다.', + Disconnect: '연결 해제', + 'Start with a Rizful Vault': 'Rizful Vault로 시작하기', + 'or other wallets': '또는 다른 지갑', + 'Rizful Vault': 'Rizful Vault', + 'Rizful Vault connected!': 'Rizful Vault 연결됨!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + '이제 Rizful Vault를 사용하여 좋아하는 노트와 크리에이터에게 잽을 보낼 수 있습니다.', + 'Your Lightning Address': '귀하의 라이트닝 주소', + 'New to Rizful?': 'Rizful이 처음이신가요?', + 'Sign up for Rizful': 'Rizful에 가입하기', + 'If you already have a Rizful account, you can skip this step.': + '이미 Rizful 계정이 있다면 이 단계를 건너뛸 수 있습니다.', + 'Get your one-time code': '일회용 코드 받기', + 'Get code': '코드 받기', + 'Connect to your Rizful Vault': 'Rizful Vault에 연결', + 'Paste your one-time code here': '여기에 일회용 코드를 붙여넣기', + Connect: '연결' } } diff --git a/src/i18n/locales/pl.ts b/src/i18n/locales/pl.ts index f568eacc..0c2b6491 100644 --- a/src/i18n/locales/pl.ts +++ b/src/i18n/locales/pl.ts @@ -428,6 +428,27 @@ export default { 'Write relays and {{count}} other relays': 'Przekaźniki zapisu i {{count}} innych przekaźników', '{{count}} relays': '{{count}} przekaźników', 'Republishing...': 'Ponowne publikowanie...', - 'Trending Notes': 'Popularne wpisy' + 'Trending Notes': 'Popularne wpisy', + 'Connected to': 'Połączono z', + 'Disconnect Wallet': 'Odłącz portfel', + 'Are you absolutely sure?': 'Czy jesteś całkowicie pewien?', + 'You will not be able to send zaps to others.': 'Nie będziesz mógł wysyłać zapów innym.', + Disconnect: 'Odłącz', + 'Start with a Rizful Vault': 'Zacznij od Rizful Vault', + 'or other wallets': 'Lub inne portfele', + 'Rizful Vault': 'Rizful Vault', + 'Rizful Vault connected!': 'Rizful Vault połączony!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'Możesz teraz używać swojego Rizful Vault, aby zapować swoje ulubione notatki i twórców.', + 'Your Lightning Address': 'Twój Lightning Adres', + 'New to Rizful?': 'Nowy w Rizful?', + 'Sign up for Rizful': 'Zarejestruj się w Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'Jeśli masz już konto Rizful, możesz pominąć ten krok.', + 'Get your one-time code': 'Uzyskaj swój jednorazowy kod', + 'Get code': 'Uzyskaj kod', + 'Connect to your Rizful Vault': 'Połącz się ze swoim Rizful Vault', + 'Paste your one-time code here': 'Wklej tutaj swój jednorazowy kod', + Connect: 'Połącz' } } diff --git a/src/i18n/locales/pt-BR.ts b/src/i18n/locales/pt-BR.ts index 57fc53fc..0c672812 100644 --- a/src/i18n/locales/pt-BR.ts +++ b/src/i18n/locales/pt-BR.ts @@ -425,6 +425,27 @@ export default { 'Write relays and {{count}} other relays': 'Relays de escrita e {{count}} outros relays', '{{count}} relays': '{{count}} relays', 'Republishing...': 'Republicando...', - 'Trending Notes': 'Notas em tendência' + 'Trending Notes': 'Notas em tendência', + 'Connected to': 'Conectado a', + 'Disconnect Wallet': 'Desconectar carteira', + 'Are you absolutely sure?': 'Você tem certeza absoluta?', + 'You will not be able to send zaps to others.': 'Você não poderá enviar zaps para outros.', + Disconnect: 'Desconectar', + 'Start with a Rizful Vault': 'Comece com um Cofre Rizful', + 'or other wallets': 'ou outras carteiras', + 'Rizful Vault': 'Cofre Rizful', + 'Rizful Vault connected!': 'Cofre Rizful conectado!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'Você pode agora usar seu Cofre Rizful para zapear suas notas e criadores favoritos.', + 'Your Lightning Address': 'Seu Endereço Lightning', + 'New to Rizful?': 'Novo no Rizful?', + 'Sign up for Rizful': 'Inscreva-se no Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'Se você já tem uma conta Rizful, pode pular esta etapa.', + 'Get your one-time code': 'Obtenha seu código único', + 'Get code': 'Obter código', + 'Connect to your Rizful Vault': 'Conecte-se ao seu Cofre Rizful', + 'Paste your one-time code here': 'Cole seu código único aqui', + Connect: 'Conectar' } } diff --git a/src/i18n/locales/pt-PT.ts b/src/i18n/locales/pt-PT.ts index 23a4e531..ec51b105 100644 --- a/src/i18n/locales/pt-PT.ts +++ b/src/i18n/locales/pt-PT.ts @@ -428,6 +428,27 @@ export default { 'Write relays and {{count}} other relays': 'Relays de escrita e {{count}} outros relays', '{{count}} relays': '{{count}} relays', 'Republishing...': 'Republicando...', - 'Trending Notes': 'Notas em Tendência' + 'Trending Notes': 'Notas em Tendência', + 'Connected to': 'Conectado a', + 'Disconnect Wallet': 'Desconectar Carteira', + 'Are you absolutely sure?': 'Tem certeza absoluta?', + 'You will not be able to send zaps to others.': 'Você não poderá enviar zaps para outros.', + Disconnect: 'Desconectar', + 'Start with a Rizful Vault': 'Comece com um Cofre Rizful', + 'or other wallets': 'outras carteiras', + 'Rizful Vault': 'Cofre Rizful', + 'Rizful Vault connected!': 'Cofre Rizful conectado!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'Agora você pode usar seu Cofre Rizful para zapear suas notas e criadores favoritos.', + 'Your Lightning Address': 'Seu Endereço Lightning', + 'New to Rizful?': 'Novo no Rizful?', + 'Sign up for Rizful': 'Inscreva-se no Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'Se você já tem uma conta Rizful, pode pular esta etapa.', + 'Get your one-time code': 'Obtenha seu código único', + 'Get code': 'Obter código', + 'Connect to your Rizful Vault': 'Conecte-se ao seu Cofre Rizful', + 'Paste your one-time code here': 'Cole seu código único aqui', + Connect: 'Conectar' } } diff --git a/src/i18n/locales/ru.ts b/src/i18n/locales/ru.ts index df70984d..4c013c55 100644 --- a/src/i18n/locales/ru.ts +++ b/src/i18n/locales/ru.ts @@ -430,6 +430,27 @@ export default { 'Ретрансляторы записи и {{count}} других ретрансляторов', '{{count}} relays': '{{count}} ретрансляторов', 'Republishing...': 'Ретрансляция...', - 'Trending Notes': 'Популярные заметки' + 'Trending Notes': 'Популярные заметки', + 'Connected to': 'Подключено к', + 'Disconnect Wallet': 'Отключить кошелёк', + 'Are you absolutely sure?': 'Вы абсолютно уверены?', + 'You will not be able to send zaps to others.': 'Вы не сможете отправлять запы другим.', + Disconnect: 'Отключить', + 'Start with a Rizful Vault': 'Начать с Rizful Vault', + 'or other wallets': 'или другие кошельки', + 'Rizful Vault': 'Rizful Vault', + 'Rizful Vault connected!': 'Rizful Vault подключён!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'Теперь вы можете использовать свой Rizful Vault, чтобы заппить ваши любимые заметки и создателей.', + 'Your Lightning Address': 'Ваш Lightning-адрес', + 'New to Rizful?': 'Новичок в Rizful?', + 'Sign up for Rizful': 'Зарегистрируйтесь на Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'Если у вас уже есть аккаунт Rizful, вы можете пропустить этот шаг.', + 'Get your one-time code': 'Получите ваш одноразовый код', + 'Get code': 'Получить код', + 'Connect to your Rizful Vault': 'Подключитесь к вашему Rizful Vault', + 'Paste your one-time code here': 'Вставьте ваш одноразовый код здесь', + Connect: 'Подключить' } } diff --git a/src/i18n/locales/th.ts b/src/i18n/locales/th.ts index 81bf48f2..e594016d 100644 --- a/src/i18n/locales/th.ts +++ b/src/i18n/locales/th.ts @@ -419,6 +419,27 @@ export default { 'Write relays and {{count}} other relays': 'รีเลย์เขียนและรีเลย์อื่น ๆ {{count}} ตัว', '{{count}} relays': 'รีเลย์ {{count}} ตัว', 'Republishing...': 'กำลังเผยแพร่ซ้ำ...', - 'Trending Notes': 'โน้ตยอดนิยม' + 'Trending Notes': 'โน้ตยอดนิยม', + 'Connected to': 'เชื่อมต่อกับ', + 'Disconnect Wallet': 'ตัดการเชื่อมต่อกระเป๋าสตางค์', + 'Are you absolutely sure?': 'คุณแน่ใจอย่างยิ่งหรือไม่?', + 'You will not be able to send zaps to others.': 'คุณจะไม่สามารถส่งซาตส์ไปยังผู้อื่นได้', + Disconnect: 'ตัดการเชื่อมต่อ', + 'Start with a Rizful Vault': 'เริ่มต้นด้วย Rizful Vault', + 'or other wallets': 'หรือกระเป๋าสตางค์อื่นๆ', + 'Rizful Vault': 'Rizful Vault', + 'Rizful Vault connected!': 'Rizful Vault เชื่อมต่อแล้ว!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + 'คุณสามารถใช้ Rizful Vault ของคุณเพื่อส่งซาตส์ไปยังโน้ตและผู้สร้างที่คุณชื่นชอบได้แล้ว', + 'Your Lightning Address': 'ที่อยู่ Lightning ของคุณ', + 'New to Rizful?': 'ใหม่กับ Rizful?', + 'Sign up for Rizful': 'สมัครสมาชิก Rizful', + 'If you already have a Rizful account, you can skip this step.': + 'หากคุณมีบัญชี Rizful อยู่แล้ว คุณสามารถข้ามขั้นตอนนี้ได้', + 'Get your one-time code': 'รับรหัสใช้ครั้งเดียวของคุณ', + 'Get code': 'รับรหัส', + 'Connect to your Rizful Vault': 'เชื่อมต่อกับ Rizful Vault ของคุณ', + 'Paste your one-time code here': 'วางรหัสใช้ครั้งเดียวของคุณที่นี่', + Connect: 'เชื่อมต่อ' } } diff --git a/src/i18n/locales/zh.ts b/src/i18n/locales/zh.ts index 97b67d09..aa9e2327 100644 --- a/src/i18n/locales/zh.ts +++ b/src/i18n/locales/zh.ts @@ -417,6 +417,27 @@ export default { 'Write relays and {{count}} other relays': '写服务器和其他 {{count}} 个服务器', '{{count}} relays': '{{count}} 个服务器', 'Republishing...': '正在重新发布...', - 'Trending Notes': '热门笔记' + 'Trending Notes': '热门笔记', + 'Connected to': '已连接到', + 'Disconnect Wallet': '断开钱包连接', + 'Are you absolutely sure?': '您确定吗?', + 'You will not be able to send zaps to others.': '您将无法向他人发送打闪。', + Disconnect: '断开连接', + 'Start with a Rizful Vault': '从 Rizful 钱包开始', + 'or other wallets': '或其他钱包', + 'Rizful Vault': 'Rizful 钱包', + 'Rizful Vault connected!': 'Rizful 钱包已连接!', + 'You can now use your Rizful Vault to zap your favorite notes and creators.': + '您现在可以使用您的 Rizful 钱包为您喜欢的笔记和创作者打闪。', + 'Your Lightning Address': '您的闪电地址', + 'New to Rizful?': '第一次使用 Rizful?', + 'Sign up for Rizful': '注册 Rizful', + 'If you already have a Rizful account, you can skip this step.': + '如果您已经有一个 Rizful 账户,可以跳过此步骤。', + 'Get your one-time code': '获取一次性代码', + 'Get code': '获取代码', + 'Connect to your Rizful Vault': '连接到您的 Rizful 钱包', + 'Paste your one-time code here': '将您的一次性代码粘贴到此处', + Connect: '连接' } } diff --git a/src/lib/link.ts b/src/lib/link.ts index ab691794..0c5a25ab 100644 --- a/src/lib/link.ts +++ b/src/lib/link.ts @@ -74,6 +74,7 @@ export const toProfileEditor = () => '/profile-editor' export const toRelay = (url: string) => `/relays/${encodeURIComponent(url)}` export const toRelayReviews = (url: string) => `/relays/${encodeURIComponent(url)}/reviews` export const toMuteList = () => '/mutes' +export const toRizful = () => '/rizful' export const toChachiChat = (relay: string, d: string) => { return `https://chachi.chat/${relay.replace(/^wss?:\/\//, '').replace(/\/$/, '')}/${d}` diff --git a/src/pages/secondary/ProfileEditorPage/index.tsx b/src/pages/secondary/ProfileEditorPage/index.tsx index 7af6c2a0..d5047bb7 100644 --- a/src/pages/secondary/ProfileEditorPage/index.tsx +++ b/src/pages/secondary/ProfileEditorPage/index.tsx @@ -65,21 +65,6 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => { return } - let lud06 = profile.lud06 - let lud16 = profile.lud16 - if (lightningAddress) { - if (isEmail(lightningAddress)) { - lud16 = lightningAddress - } else if (lightningAddress.startsWith('lnurl')) { - lud06 = lightningAddress - } else { - setLightningAddressError(t('Invalid Lightning Address')) - return - } - } - - setSaving(true) - setHasChanged(false) const oldProfileContent = profileEvent ? JSON.parse(profileEvent.content) : {} const newProfileContent = { ...oldProfileContent, @@ -90,10 +75,24 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => { website, nip05, banner, - picture: avatar, - lud06, - lud16 + picture: avatar } + + if (lightningAddress) { + if (isEmail(lightningAddress)) { + newProfileContent.lud16 = lightningAddress + } else if (lightningAddress.startsWith('lnurl')) { + newProfileContent.lud06 = lightningAddress + } else { + setLightningAddressError(t('Invalid Lightning Address')) + return + } + } else { + delete newProfileContent.lud16 + } + + setSaving(true) + setHasChanged(false) const profileDraftEvent = createProfileDraftEvent( JSON.stringify(newProfileContent), profileEvent?.tags diff --git a/src/pages/secondary/RizfulPage/index.tsx b/src/pages/secondary/RizfulPage/index.tsx new file mode 100644 index 00000000..7a4dabb9 --- /dev/null +++ b/src/pages/secondary/RizfulPage/index.tsx @@ -0,0 +1,203 @@ +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' +import { createProfileDraftEvent } from '@/lib/draft-event' +import { isEmail } from '@/lib/utils' +import { useNostr } from '@/providers/NostrProvider' +import { useZap } from '@/providers/ZapProvider' +import { connectNWC, WebLNProviders } from '@getalby/bitcoin-connect' +import { Check, CheckCircle2, Copy, ExternalLink, Loader2 } from 'lucide-react' +import { forwardRef, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { toast } from 'sonner' + +const RIZFUL_URL = 'https://rizful.com' +const RIZFUL_SIGNUP_URL = `${RIZFUL_URL}/create-account` +const RIZFUL_GET_TOKEN_URL = `${RIZFUL_URL}/nostr_onboarding_auth_token/get_token` +const RIZFUL_TOKEN_EXCHANGE_URL = `${RIZFUL_URL}/nostr_onboarding_auth_token/post_for_secrets` + +const RizfulPage = forwardRef(({ index }: { index?: number }, ref) => { + const { t } = useTranslation() + const { pubkey, profile, profileEvent, publish, updateProfileEvent } = useNostr() + const { provider } = useZap() + const [token, setToken] = useState('') + const [connecting, setConnecting] = useState(false) + const [connected, setConnected] = useState(false) + const [copiedLightningAddress, setCopiedLightningAddress] = useState(false) + const [lightningAddress, setLightningAddress] = useState('') + + useEffect(() => { + if (provider instanceof WebLNProviders.NostrWebLNProvider) { + const lud16 = provider.client.lud16 + const domain = lud16?.split('@')[1] + if (domain !== 'rizful.com') return + + if (lud16) { + setConnected(true) + setLightningAddress(lud16) + } + } + }, [provider]) + + const updateUserProfile = async (address: string) => { + try { + if (address === profile?.lightningAddress) { + return + } + + const profileContent = profileEvent ? JSON.parse(profileEvent.content) : {} + if (isEmail(address)) { + profileContent.lud16 = address + } else if (address.startsWith('lnurl')) { + profileContent.lud06 = address + } else { + throw new Error(t('Invalid Lightning Address')) + } + + if (!profileContent.nip05) { + profileContent.nip05 = address + } + + const profileDraftEvent = createProfileDraftEvent( + JSON.stringify(profileContent), + profileEvent?.tags + ) + const newProfileEvent = await publish(profileDraftEvent) + await updateProfileEvent(newProfileEvent) + } catch (e: unknown) { + toast.error(e instanceof Error ? e.message : String(e)) + } + } + + const connectRizful = async () => { + setConnecting(true) + try { + const r = await fetch(RIZFUL_TOKEN_EXCHANGE_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + credentials: 'omit', + body: JSON.stringify({ + secret_code: token.trim(), + nostr_public_key: pubkey + }) + }) + + if (!r.ok) { + const errorText = await r.text() + throw new Error(errorText || 'Exchange failed') + } + + const j = (await r.json()) as { + nwc_uri?: string + lightning_address?: string + } + + if (j.nwc_uri) { + connectNWC(j.nwc_uri) + } + if (j.lightning_address) { + updateUserProfile(j.lightning_address) + } + } catch (e: unknown) { + toast.error(e instanceof Error ? e.message : String(e)) + } finally { + setConnecting(false) + } + } + + if (connected) { + return ( + +
+ +
{t('Rizful Vault connected!')}
+
+ {t('You can now use your Rizful Vault to zap your favorite notes and creators.')} +
+ {lightningAddress && ( +
+
{t('Your Lightning Address')}:
+
{ + navigator.clipboard.writeText(lightningAddress) + setCopiedLightningAddress(true) + setTimeout(() => setCopiedLightningAddress(false), 2000) + }} + > + {lightningAddress}{' '} + {copiedLightningAddress ? ( + + ) : ( + + )} +
+
+ )} +
+
+ ) + } + + return ( + +
+
+
1. {t('New to Rizful?')}
+ +
+ {t('If you already have a Rizful account, you can skip this step.')} +
+
+ +
+
2. {t('Get your one-time code')}
+ +
+ +
+
3. {t('Connect to your Rizful Vault')}
+ { + setToken(e.target.value.trim()) + }} + /> + +
+
+
+ ) +}) +RizfulPage.displayName = 'RizfulPage' +export default RizfulPage + +function openPopup(url: string, name: string, width = 520, height = 700) { + const left = Math.max((window.screenX || 0) + (window.innerWidth - width) / 2, 0) + const top = Math.max((window.screenY || 0) + (window.innerHeight - height) / 2, 0) + + return window.open( + url, + name, + `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes,menubar=no,toolbar=no,location=no,status=no` + ) +} diff --git a/src/pages/secondary/SettingsPage/index.tsx b/src/pages/secondary/SettingsPage/index.tsx index b572f708..a7180b5d 100644 --- a/src/pages/secondary/SettingsPage/index.tsx +++ b/src/pages/secondary/SettingsPage/index.tsx @@ -49,20 +49,24 @@ const SettingsPage = forwardRef(({ index }: { index?: number }, ref) => { - push(toTranslation())}> -
- -
{t('Translation')}
-
- -
- push(toWallet())}> -
- -
{t('Wallet')}
-
- -
+ {!!pubkey && ( + push(toTranslation())}> +
+ +
{t('Translation')}
+
+ +
+ )} + {!!pubkey && ( + push(toWallet())}> +
+ +
{t('Wallet')}
+
+ +
+ )} {!!pubkey && ( push(toPostSettings())}>
diff --git a/src/pages/secondary/WalletPage/LightningAddressInput.tsx b/src/pages/secondary/WalletPage/LightningAddressInput.tsx index f3149400..6fb6022f 100644 --- a/src/pages/secondary/WalletPage/LightningAddressInput.tsx +++ b/src/pages/secondary/WalletPage/LightningAddressInput.tsx @@ -28,26 +28,21 @@ export default function LightningAddressInput() { const handleSave = async () => { setSaving(true) - let lud06 = profile.lud06 - let lud16 = profile.lud16 + const profileContent = profileEvent ? JSON.parse(profileEvent.content) : {} if (lightningAddress.startsWith('lnurl')) { - lud06 = lightningAddress + profileContent.lud06 = lightningAddress } else if (isEmail(lightningAddress)) { - lud16 = lightningAddress - } else { + profileContent.lud16 = lightningAddress + } else if (lightningAddress) { toast.error(t('Invalid Lightning Address. Please enter a valid Lightning Address or LNURL.')) setSaving(false) return + } else { + delete profileContent.lud16 } - const oldProfileContent = profileEvent ? JSON.parse(profileEvent.content) : {} - const newProfileContent = { - ...oldProfileContent, - lud06, - lud16 - } const profileDraftEvent = createProfileDraftEvent( - JSON.stringify(newProfileContent), + JSON.stringify(profileContent), profileEvent?.tags ) const newProfileEvent = await publish(profileDraftEvent) diff --git a/src/pages/secondary/WalletPage/index.tsx b/src/pages/secondary/WalletPage/index.tsx index 3dcb6dcc..154e88e0 100644 --- a/src/pages/secondary/WalletPage/index.tsx +++ b/src/pages/secondary/WalletPage/index.tsx @@ -1,5 +1,20 @@ +import { useSecondaryPage } from '@/PageManager' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger +} from '@/components/ui/alert-dialog' +import { Button } from '@/components/ui/button' import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' -import { Button as BcButton } from '@getalby/bitcoin-connect-react' +import { toRizful } from '@/lib/link' +import { useZap } from '@/providers/ZapProvider' +import { disconnect, launchModal } from '@getalby/bitcoin-connect-react' import { forwardRef } from 'react' import { useTranslation } from 'react-i18next' import DefaultZapAmountInput from './DefaultZapAmountInput' @@ -9,16 +24,60 @@ import QuickZapSwitch from './QuickZapSwitch' const WalletPage = forwardRef(({ index }: { index?: number }, ref) => { const { t } = useTranslation() + const { push } = useSecondaryPage() + const { isWalletConnected, walletInfo } = useZap() return ( -
- - - - - -
+ {isWalletConnected ? ( +
+
+ {walletInfo?.node.alias && ( +
+ {t('Connected to')} {walletInfo.node.alias} +
+ )} + + + + + + + {t('Are you absolutely sure?')} + + {t('You will not be able to send zaps to others.')} + + + + {t('Cancel')} + disconnect()}> + {t('Disconnect')} + + + + +
+ + + + +
+ ) : ( +
+ + +
+ )}
) }) diff --git a/src/providers/ZapProvider.tsx b/src/providers/ZapProvider.tsx index b7c4fe05..51fa5195 100644 --- a/src/providers/ZapProvider.tsx +++ b/src/providers/ZapProvider.tsx @@ -1,7 +1,13 @@ +import lightningService from '@/services/lightning.service' import storage from '@/services/local-storage.service' -import { createContext, useContext, useState } from 'react' +import { onConnected, onDisconnected } from '@getalby/bitcoin-connect-react' +import { GetInfoResponse, WebLNProvider } from '@webbtc/webln-types' +import { createContext, useContext, useEffect, useState } from 'react' type TZapContext = { + isWalletConnected: boolean + provider: WebLNProvider | null + walletInfo: GetInfoResponse | null defaultZapSats: number updateDefaultSats: (sats: number) => void defaultZapComment: string @@ -24,6 +30,29 @@ export function ZapProvider({ children }: { children: React.ReactNode }) { const [defaultZapSats, setDefaultZapSats] = useState(storage.getDefaultZapSats()) const [defaultZapComment, setDefaultZapComment] = useState(storage.getDefaultZapComment()) const [quickZap, setQuickZap] = useState(storage.getQuickZap()) + const [isWalletConnected, setIsWalletConnected] = useState(false) + const [provider, setProvider] = useState(null) + const [walletInfo, setWalletInfo] = useState(null) + + useEffect(() => { + const unSubOnConnected = onConnected((provider) => { + setIsWalletConnected(true) + setWalletInfo(null) + setProvider(provider) + lightningService.provider = provider + provider.getInfo().then(setWalletInfo) + }) + const unSubOnDisconnected = onDisconnected(() => { + setIsWalletConnected(false) + setProvider(null) + lightningService.provider = null + }) + + return () => { + unSubOnConnected() + unSubOnDisconnected() + } + }, []) const updateDefaultSats = (sats: number) => { storage.setDefaultZapSats(sats) @@ -43,6 +72,9 @@ export function ZapProvider({ children }: { children: React.ReactNode }) { return ( }, { path: '/settings/translation', element: }, { path: '/profile-editor', element: }, - { path: '/mutes', element: } + { path: '/mutes', element: }, + { path: '/rizful', element: } ] export const routes = ROUTES.map(({ path, element }) => ({ diff --git a/src/services/lightning.service.ts b/src/services/lightning.service.ts index b316c47d..924b1518 100644 --- a/src/services/lightning.service.ts +++ b/src/services/lightning.service.ts @@ -1,12 +1,7 @@ import { BIG_RELAY_URLS, CODY_PUBKEY, JUMBLE_PUBKEY } from '@/constants' import { getZapInfoFromEvent } from '@/lib/event-metadata' import { TProfile } from '@/types' -import { - init, - launchPaymentModal, - onConnected, - onDisconnected -} from '@getalby/bitcoin-connect-react' +import { init, launchPaymentModal } from '@getalby/bitcoin-connect-react' import { Invoice } from '@getalby/lightning-tools' import { bech32 } from '@scure/base' import { WebLNProvider } from '@webbtc/webln-types' @@ -23,7 +18,7 @@ const OFFICIAL_PUBKEYS = [JUMBLE_PUBKEY, CODY_PUBKEY] class LightningService { static instance: LightningService - private provider: WebLNProvider | null = null + provider: WebLNProvider | null = null private recentSupportersCache: TRecentSupporter[] | null = null constructor() { @@ -33,12 +28,6 @@ class LightningService { appName: 'Jumble', showBalance: false }) - onConnected((provider) => { - this.provider = provider - }) - onDisconnected(() => { - this.provider = null - }) } return LightningService.instance } diff --git a/src/services/local-storage.service.ts b/src/services/local-storage.service.ts index 9a835030..c04f3954 100644 --- a/src/services/local-storage.service.ts +++ b/src/services/local-storage.service.ts @@ -47,6 +47,7 @@ class LocalStorageService { private hideContentMentioningMutedUsers: boolean = false private notificationListStyle: TNotificationStyle = NOTIFICATION_LIST_STYLE.DETAILED private mediaAutoLoadPolicy: TMediaAutoLoadPolicy = MEDIA_AUTO_LOAD_POLICY.ALWAYS + private shownCreateWalletGuideToastPubkeys: Set = new Set() constructor() { if (!LocalStorageService.instance) { @@ -185,6 +186,13 @@ class LocalStorageService { this.mediaAutoLoadPolicy = mediaAutoLoadPolicy as TMediaAutoLoadPolicy } + const shownCreateWalletGuideToastPubkeysStr = window.localStorage.getItem( + StorageKey.SHOWN_CREATE_WALLET_GUIDE_TOAST_PUBKEYS + ) + this.shownCreateWalletGuideToastPubkeys = shownCreateWalletGuideToastPubkeysStr + ? new Set(JSON.parse(shownCreateWalletGuideToastPubkeysStr)) + : new Set() + // Clean up deprecated data window.localStorage.removeItem(StorageKey.ACCOUNT_PROFILE_EVENT_MAP) window.localStorage.removeItem(StorageKey.ACCOUNT_FOLLOW_LIST_EVENT_MAP) @@ -453,6 +461,21 @@ class LocalStorageService { this.mediaAutoLoadPolicy = policy window.localStorage.setItem(StorageKey.MEDIA_AUTO_LOAD_POLICY, policy) } + + hasShownCreateWalletGuideToast(pubkey: string) { + return this.shownCreateWalletGuideToastPubkeys.has(pubkey) + } + + markCreateWalletGuideToastAsShown(pubkey: string) { + if (this.shownCreateWalletGuideToastPubkeys.has(pubkey)) { + return + } + this.shownCreateWalletGuideToastPubkeys.add(pubkey) + window.localStorage.setItem( + StorageKey.SHOWN_CREATE_WALLET_GUIDE_TOAST_PUBKEYS, + JSON.stringify(Array.from(this.shownCreateWalletGuideToastPubkeys)) + ) + } } const instance = new LocalStorageService()