use actions for follow and unfollow

This commit is contained in:
hzrd149 2025-03-15 14:37:30 +00:00
parent 054c8817bc
commit 43ee4f7be0
16 changed files with 191 additions and 170 deletions

View File

@ -24,7 +24,7 @@
"@chakra-ui/breakpoint-utils": "^2.0.8",
"@chakra-ui/icons": "^2.2.4",
"@chakra-ui/media-query": "^3.3.0",
"@chakra-ui/react": "^2.10.6",
"@chakra-ui/react": "^2.10.7",
"@chakra-ui/shared-utils": "^2.0.4",
"@chakra-ui/styled-system": "^2.12.0",
"@chakra-ui/theme-tools": "^2.2.6",

142
pnpm-lock.yaml generated
View File

@ -24,13 +24,13 @@ importers:
version: 2.0.8
'@chakra-ui/icons':
specifier: ^2.2.4
version: 2.2.4(@chakra-ui/react@2.10.6(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(framer-motion@10.18.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
version: 2.2.4(@chakra-ui/react@2.10.7(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(framer-motion@10.18.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
'@chakra-ui/media-query':
specifier: ^3.3.0
version: 3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(react@19.0.0))(react@19.0.0)
'@chakra-ui/react':
specifier: ^2.10.6
version: 2.10.6(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(framer-motion@10.18.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
specifier: ^2.10.7
version: 2.10.7(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(framer-motion@10.18.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@chakra-ui/shared-utils':
specifier: ^2.0.4
version: 2.0.4
@ -105,34 +105,34 @@ importers:
version: 0.7.2
applesauce-accounts:
specifier: next
version: 0.0.0-next-20250314151125(typescript@5.8.2)
version: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-actions:
specifier: next
version: 0.0.0-next-20250314151125(typescript@5.8.2)
version: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-content:
specifier: next
version: 0.0.0-next-20250314151125(typescript@5.8.2)
version: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-core:
specifier: next
version: 0.0.0-next-20250314151125(typescript@5.8.2)
version: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-factory:
specifier: next
version: 0.0.0-next-20250314151125(typescript@5.8.2)
version: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-loaders:
specifier: next
version: 0.0.0-next-20250314151125(typescript@5.8.2)
version: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-react:
specifier: next
version: 0.0.0-next-20250314151125(react-dom@19.0.0(react@19.0.0))(typescript@5.8.2)
version: 0.0.0-next-20250315140539(react-dom@19.0.0(react@19.0.0))(typescript@5.8.2)
applesauce-relay:
specifier: next
version: 0.0.0-next-20250314151125(typescript@5.8.2)
version: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-signers:
specifier: next
version: 0.0.0-next-20250314151125(typescript@5.8.2)
version: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-wallet:
specifier: next
version: 0.0.0-next-20250314151125(typescript@5.8.2)
version: 0.0.0-next-20250315140539(typescript@5.8.2)
bech32:
specifier: ^2.0.0
version: 2.0.0
@ -417,10 +417,10 @@ importers:
specifier: ^0.6.8
version: 0.6.8
'@types/react':
specifier: ^18.2.22
specifier: ^18.3.18
version: 18.3.18
'@types/react-dom':
specifier: ^18.2.7
specifier: ^18.3.5
version: 18.3.5(@types/react@18.3.18)
'@types/react-window':
specifier: ^1.8.8
@ -1106,8 +1106,8 @@ packages:
peerDependencies:
react: '>=18'
'@chakra-ui/react@2.10.6':
resolution: {integrity: sha512-9cdzcUR3LV3E2as0QhZhHAH5qjbyspV12kU1E1Ibcv6/uKUi6bIfPfMSC6R/Tw8Beqhn2ClJFPqjtXzL+C0knQ==}
'@chakra-ui/react@2.10.7':
resolution: {integrity: sha512-GX1dCmnvrxxyZEofDX9GMAtRakZJKnUqFM9k8qhaycPaeyfkiTNNTjhPNX917hgVx1yhC3kcJOs5IeC7yW56/g==}
peerDependencies:
'@emotion/react': '>=11'
'@emotion/styled': '>=11'
@ -2205,35 +2205,35 @@ packages:
engines: {node: '>=8.0.0'}
hasBin: true
applesauce-accounts@0.0.0-next-20250314151125:
resolution: {integrity: sha512-QEumvkVlZVsSkShOKtIjokf8Pg5PxWgNJIfmNRIp/fDqzyICNGAwrQ28n9vq2A+A0aQRqFc700vWjs1uSACsoQ==}
applesauce-accounts@0.0.0-next-20250315140539:
resolution: {integrity: sha512-icnfZejz1vP8TgO7eIqNdX3wHuwEGWGDHCmPaWuk4MVqbVYFTT5seHOM6HdWLs4daUczX96oPcYFNetSfAfe8A==}
applesauce-actions@0.0.0-next-20250314151125:
resolution: {integrity: sha512-SapbCJ4vxrXMbWTzVP6v3zSBx1EHSXxqW8MBIywCyR+GVcXcWteIm6pgJGWgMzZDDdWY+BaDSdXedmr2r7eXDQ==}
applesauce-actions@0.0.0-next-20250315140539:
resolution: {integrity: sha512-R0Iy2W10sfWOKme9EbOGEaKsvbSDo6z2hR9XlSq12/oOBtnRLVGUN1lW62nFWpSbNUZGGLooZJkjFl+aL3f7YA==}
applesauce-content@0.0.0-next-20250314151125:
resolution: {integrity: sha512-C1PUbK4q89y2M7DqOHZEcPzTTfxXphK8VRFgsQ2E6T8MJIJV3719z78traoVtrsf/DYR9SR5zQP24BQ8k1dF7g==}
applesauce-content@0.0.0-next-20250315140539:
resolution: {integrity: sha512-pNWKIMaagcLrPoqD8QubrRDgYcPV4cLDnXFCTGa/R3z+WQR9ElPMfGEewhn1EyKicf0o58rG1LJmUhw20+VfBQ==}
applesauce-core@0.0.0-next-20250314151125:
resolution: {integrity: sha512-5c0An4cH89MYANPJQaYArMoWbU86BIt48cYDNLh9bMXtrX+t8bjvJ829uFatwCbw9Lc/v8ZFCLhjltiFTp1P4w==}
applesauce-core@0.0.0-next-20250315140539:
resolution: {integrity: sha512-NF/CPVxtvq2zReKMRoBQ2s0lgNajeHjL8ws1WoDWbNJhQV0xBtb71ldHXQuEQcdf2Kj9IuK2Le9oJSAB6Gwz7w==}
applesauce-factory@0.0.0-next-20250314151125:
resolution: {integrity: sha512-m36/ys37RzZPPzpvYOEi6pRYfXrWC6JEt1LrBxADBoZaluKIgKGf8MKj1bvS9anwobcxNKKgVPNsJqYZu4Y0ug==}
applesauce-factory@0.0.0-next-20250315140539:
resolution: {integrity: sha512-nKBZT8HcfCWozwzNrCoVwjz+50+lJeKi6vOTCeEcHXRC/4rTDsAw8/IPB+SBj0WTEHvZdtmz4AB4WHLJQEhcBw==}
applesauce-loaders@0.0.0-next-20250314151125:
resolution: {integrity: sha512-CfxxvsVptHEmBSBA0ilqImHSUn7ff4fritslH9SWrXp1aH3P/JFR66eLYfRVNUUKEDDEe/iZEvCb2PzsAnecRw==}
applesauce-loaders@0.0.0-next-20250315140539:
resolution: {integrity: sha512-/wrungJ7T2MH8yTUXUvlQm4uSvqc77slx7WzfsfTU4efgeHqKbTaRjw3dIkX3mlZiAW5VJ6+epQ4g6qhCnyvzg==}
applesauce-react@0.0.0-next-20250314151125:
resolution: {integrity: sha512-7f501dlHxbmSuBsOHqxF376KXUluDBrlatirqN+yuJQAIRpfy5bIuNIDvgePoQqB4IDjhCgxzD5Q8YIPY9Rpyw==}
applesauce-react@0.0.0-next-20250315140539:
resolution: {integrity: sha512-m54/KA51LqUZDewLg5XqEJju3fh8pJazOcpU/QbuyM+NKATdphLn3dRW6/UcD6yJNi7fEbF42OeyrioNxcQLWw==}
applesauce-relay@0.0.0-next-20250314151125:
resolution: {integrity: sha512-YEzPQkud+uilxZeuR7LxZkFduRO1tPeq3ATLF3mGP9q88BJn59sPvQO4IEo4nCnbBPKcTaIMy6Bh6Xc5RFx9TA==}
applesauce-relay@0.0.0-next-20250315140539:
resolution: {integrity: sha512-UDif/VN31PMcxXJgarEySzveOrpv6O5nJj+/RgTs5ZnamSOc9jIaRIZpTPsfkHYBOZZeJb1cU9Wr+nBQEApvVw==}
applesauce-signers@0.0.0-next-20250314151125:
resolution: {integrity: sha512-I0hvuchdPXM1riOSxC+ezKvCF5e9CcqFYx8e7if784OgsnM3OmL/3esMTu3c3X7OgT8PjFhdL8WieSOl1Tj1IA==}
applesauce-signers@0.0.0-next-20250315140539:
resolution: {integrity: sha512-LZZxC6PD10iPFVXrpCJ7lLCXewRF3EsBJD6FQ47SpgH9AVGWn+lbAB9fX87tdd+V8Ks1Ym1tp/CdrvL2AV4PJg==}
applesauce-wallet@0.0.0-next-20250314151125:
resolution: {integrity: sha512-/IRVsQIORXSg7B1B2Xh6hMt3UAh7vK8QfBvpMyI9HWUmrQTdczznYhZCVdmQxJRk3MLYQdL7iIg78Y++3mPemg==}
applesauce-wallet@0.0.0-next-20250315140539:
resolution: {integrity: sha512-6WgKT3er92cefaQcgYAslY7oitrLsLiUYbtVCdQV4v0G3MMMYGhiTuOtLlSYKeJ+e4e5BH9/YZgePrXCQoBlCA==}
arg@4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
@ -3059,8 +3059,8 @@ packages:
engines: {node: '>=0.10.0'}
hasBin: true
electron-to-chromium@1.5.118:
resolution: {integrity: sha512-yNDUus0iultYyVoEFLnQeei7LOQkL8wg8GQpkPCRrOlJXlcCwa6eGKZkxQ9ciHsqZyYbj8Jd94X1CTPzGm+uIA==}
electron-to-chromium@1.5.119:
resolution: {integrity: sha512-Ku4NMzUjz3e3Vweh7PhApPrZSS4fyiCIbcIrG9eKrriYVLmbMepETR/v6SU7xPm98QTqMSYiCwfO89QNjXLkbQ==}
elementtree@0.1.7:
resolution: {integrity: sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==}
@ -7042,9 +7042,9 @@ snapshots:
framesync: 6.1.2
react: 19.0.0
'@chakra-ui/icons@2.2.4(@chakra-ui/react@2.10.6(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(framer-motion@10.18.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)':
'@chakra-ui/icons@2.2.4(@chakra-ui/react@2.10.7(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(framer-motion@10.18.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)':
dependencies:
'@chakra-ui/react': 2.10.6(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(framer-motion@10.18.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@chakra-ui/react': 2.10.7(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(framer-motion@10.18.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0
'@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.2(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(react@19.0.0))(react@19.0.0)':
@ -7071,7 +7071,7 @@ snapshots:
'@chakra-ui/utils': 2.0.15
react: 19.0.0
'@chakra-ui/react@2.10.6(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(framer-motion@10.18.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
'@chakra-ui/react@2.10.7(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(react@19.0.0))(@types/react@18.3.18)(framer-motion@10.18.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@chakra-ui/hooks': 2.4.4(react@19.0.0)
'@chakra-ui/styled-system': 2.12.2(react@19.0.0)
@ -8480,10 +8480,10 @@ snapshots:
dependencies:
entities: 2.2.0
applesauce-accounts@0.0.0-next-20250314151125(typescript@5.8.2):
applesauce-accounts@0.0.0-next-20250315140539(typescript@5.8.2):
dependencies:
'@noble/hashes': 1.7.1
applesauce-signers: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-signers: 0.0.0-next-20250315140539(typescript@5.8.2)
nanoid: 5.1.3
nostr-tools: 2.11.0(typescript@5.8.2)
rxjs: 7.8.2
@ -8491,23 +8491,23 @@ snapshots:
- supports-color
- typescript
applesauce-actions@0.0.0-next-20250314151125(typescript@5.8.2):
applesauce-actions@0.0.0-next-20250315140539(typescript@5.8.2):
dependencies:
applesauce-core: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-factory: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-factory: 0.0.0-next-20250315140539(typescript@5.8.2)
nostr-tools: 2.11.0(typescript@5.8.2)
rxjs: 7.8.2
transitivePeerDependencies:
- supports-color
- typescript
applesauce-content@0.0.0-next-20250314151125(typescript@5.8.2):
applesauce-content@0.0.0-next-20250315140539(typescript@5.8.2):
dependencies:
'@cashu/cashu-ts': 2.0.0-rc1
'@types/hast': 3.0.4
'@types/mdast': 4.0.4
'@types/unist': 3.0.3
applesauce-core: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250315140539(typescript@5.8.2)
mdast-util-find-and-replace: 3.0.2
nostr-tools: 2.11.0(typescript@5.8.2)
remark: 15.0.1
@ -8518,7 +8518,7 @@ snapshots:
- supports-color
- typescript
applesauce-core@0.0.0-next-20250314151125(typescript@5.8.2):
applesauce-core@0.0.0-next-20250315140539(typescript@5.8.2):
dependencies:
'@noble/hashes': 1.7.1
'@scure/base': 1.2.4
@ -8533,19 +8533,19 @@ snapshots:
- supports-color
- typescript
applesauce-factory@0.0.0-next-20250314151125(typescript@5.8.2):
applesauce-factory@0.0.0-next-20250315140539(typescript@5.8.2):
dependencies:
applesauce-content: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-content: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250315140539(typescript@5.8.2)
nanoid: 5.1.3
nostr-tools: 2.11.0(typescript@5.8.2)
transitivePeerDependencies:
- supports-color
- typescript
applesauce-loaders@0.0.0-next-20250314151125(typescript@5.8.2):
applesauce-loaders@0.0.0-next-20250315140539(typescript@5.8.2):
dependencies:
applesauce-core: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250315140539(typescript@5.8.2)
nanoid: 5.1.3
nostr-tools: 2.11.0(typescript@5.8.2)
rx-nostr: 3.5.0
@ -8554,13 +8554,13 @@ snapshots:
- supports-color
- typescript
applesauce-react@0.0.0-next-20250314151125(react-dom@19.0.0(react@19.0.0))(typescript@5.8.2):
applesauce-react@0.0.0-next-20250315140539(react-dom@19.0.0(react@19.0.0))(typescript@5.8.2):
dependencies:
applesauce-accounts: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-actions: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-content: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-factory: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-accounts: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-actions: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-content: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-factory: 0.0.0-next-20250315140539(typescript@5.8.2)
nostr-tools: 2.11.0(typescript@5.8.2)
observable-hooks: 4.2.4(react-dom@19.0.0(react@19.0.0))(react@18.3.1)(rxjs@7.8.2)
react: 18.3.1
@ -8570,9 +8570,9 @@ snapshots:
- supports-color
- typescript
applesauce-relay@0.0.0-next-20250314151125(typescript@5.8.2):
applesauce-relay@0.0.0-next-20250315140539(typescript@5.8.2):
dependencies:
applesauce-core: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250315140539(typescript@5.8.2)
nanoid: 5.1.3
nostr-tools: 2.11.0(typescript@5.8.2)
rxjs: 7.8.2
@ -8580,12 +8580,12 @@ snapshots:
- supports-color
- typescript
applesauce-signers@0.0.0-next-20250314151125(typescript@5.8.2):
applesauce-signers@0.0.0-next-20250315140539(typescript@5.8.2):
dependencies:
'@noble/hashes': 1.7.1
'@noble/secp256k1': 1.7.1
'@scure/base': 1.2.4
applesauce-core: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250315140539(typescript@5.8.2)
debug: 4.4.0
nanoid: 5.1.3
nostr-tools: 2.11.0(typescript@5.8.2)
@ -8593,14 +8593,14 @@ snapshots:
- supports-color
- typescript
applesauce-wallet@0.0.0-next-20250314151125(typescript@5.8.2):
applesauce-wallet@0.0.0-next-20250315140539(typescript@5.8.2):
dependencies:
'@cashu/cashu-ts': 2.0.0-rc1
'@gandlaf21/bc-ur': 1.1.12
'@noble/hashes': 1.7.1
applesauce-actions: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-factory: 0.0.0-next-20250314151125(typescript@5.8.2)
applesauce-actions: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-core: 0.0.0-next-20250315140539(typescript@5.8.2)
applesauce-factory: 0.0.0-next-20250315140539(typescript@5.8.2)
nostr-tools: 2.11.0(typescript@5.8.2)
rxjs: 7.8.2
transitivePeerDependencies:
@ -8826,7 +8826,7 @@ snapshots:
browserslist@4.24.4:
dependencies:
caniuse-lite: 1.0.30001704
electron-to-chromium: 1.5.118
electron-to-chromium: 1.5.119
node-releases: 2.0.19
update-browserslist-db: 1.1.3(browserslist@4.24.4)
@ -9527,7 +9527,7 @@ snapshots:
dependencies:
jake: 10.9.2
electron-to-chromium@1.5.118: {}
electron-to-chromium@1.5.119: {}
elementtree@0.1.7:
dependencies:

View File

@ -19,26 +19,23 @@ export default function DVMFeedFavoriteButton({
const factory = useEventFactory();
const { favorites } = useFavoriteFeeds();
const isFavorite = !!favorites && isAddressPointerInList(favorites, pointer);
const [loading, setLoading] = useState(false);
const handleClick = useAsyncErrorHandler(async () => {
const toggle = useAsyncErrorHandler(async () => {
const prev = favorites || {
kind: kinds.Application,
tags: [["d", FAVORITE_FEEDS_IDENTIFIER]],
};
setLoading(true);
const draft = await factory.modifyTags(prev, isFavorite ? removeCoordinateTag(pointer) : addCoordinateTag(pointer));
await publish(isFavorite ? "Unfavorite feed" : "Favorite feed", draft);
setLoading(false);
}, [factory, favorites, pointer, publish, setLoading]);
}, [factory, favorites, pointer, publish]);
return (
<IconButton
icon={isFavorite ? <StarFullIcon /> : <StarEmptyIcon />}
aria-label={isFavorite ? "Favorite feed" : "Unfavorite feed"}
onClick={handleClick}
isLoading={loading}
onClick={toggle.run}
isLoading={toggle.loading}
color={isFavorite ? "yellow.400" : undefined}
{...props}
/>

View File

@ -1,4 +1,3 @@
import { useCallback, useState } from "react";
import {
Button,
ButtonProps,
@ -13,19 +12,14 @@ import {
} from "@chakra-ui/react";
import { kinds } from "nostr-tools";
import { isProfilePointerInList } from "applesauce-core/helpers/lists";
import { useActiveAccount } from "applesauce-react/hooks";
import { useActionHub, useActiveAccount } from "applesauce-react/hooks";
import { FollowUser, UnfollowUser, AddUserToFollowSet, RemoveUserFromFollowSet } from "applesauce-actions/actions";
import { getEventUID, getReplaceableIdentifier } from "applesauce-core/helpers";
import { ChevronDownIcon, FollowIcon, MuteIcon, PlusCircleIcon, UnfollowIcon, UnmuteIcon } from "../icons";
import useUserSets from "../../hooks/use-user-lists";
import {
createEmptyContactList,
listAddPerson,
listRemovePerson,
getListName,
getPubkeysFromList,
} from "../../helpers/nostr/lists";
import { getListName } from "../../helpers/nostr/lists";
import { getEventCoordinate } from "../../helpers/nostr/event";
import { useSigningContext } from "../../providers/global/signing-provider";
import useUserContactList from "../../hooks/use-user-contact-list";
import useAsyncErrorHandler from "../../hooks/use-async-error-handler";
import NewSetModal from "../../views/lists/components/new-set-modal";
@ -36,34 +30,31 @@ import { usePublishEvent } from "../../providers/global/publish-provider";
function UsersLists({ pubkey }: { pubkey: string }) {
const publish = usePublishEvent();
const account = useActiveAccount()!;
const { requestSignature } = useSigningContext();
const [isLoading, setLoading] = useState(false);
const newListModal = useDisclosure();
const actions = useActionHub();
const lists = useUserSets(account.pubkey).filter((list) => list.kind === kinds.Followsets);
const inLists = lists.filter((list) => getPubkeysFromList(list).some((p) => p.pubkey === pubkey));
const inLists = lists.filter((list) => isProfilePointerInList(list, { pubkey }));
const handleChange = useCallback(
const handleChange = useAsyncErrorHandler(
async (cords: string | string[]) => {
if (!Array.isArray(cords)) return;
setLoading(true);
const addToList = lists.find((list) => !inLists.includes(list) && cords.includes(getEventCoordinate(list)));
const removeFromList = lists.find((list) => inLists.includes(list) && !cords.includes(getEventCoordinate(list)));
if (addToList) {
const draft = listAddPerson(addToList, pubkey);
const signed = await requestSignature(draft);
await publish("Add to list", signed);
await actions
.exec(AddUserToFollowSet, pubkey, getReplaceableIdentifier(addToList))
.forEach((e) => publish("Add to list", e));
} else if (removeFromList) {
const draft = listRemovePerson(removeFromList, pubkey);
const signed = await requestSignature(draft);
await publish("Remove from list", signed);
await actions
.exec(RemoveUserFromFollowSet, pubkey, getReplaceableIdentifier(removeFromList))
.forEach((e) => publish("Remove from list", e));
}
setLoading(false);
},
[lists, publish, setLoading],
[lists, publish],
);
return (
@ -73,10 +64,10 @@ function UsersLists({ pubkey }: { pubkey: string }) {
title="Lists"
type="checkbox"
value={inLists.map((list) => getEventCoordinate(list))}
onChange={handleChange}
onChange={handleChange.run}
>
{lists.map((list) => (
<MenuItemOption key={getEventCoordinate(list)} value={getEventCoordinate(list)} isTruncated maxW="90vw">
<MenuItemOption key={getEventUID(list)} value={getEventCoordinate(list)} isTruncated maxW="90vw">
{getListName(list)}
</MenuItemOption>
))}
@ -100,28 +91,20 @@ export type UserFollowButtonProps = { pubkey: string; showLists?: boolean } & Om
export function UserFollowButton({ pubkey, showLists, ...props }: UserFollowButtonProps) {
const publish = usePublishEvent();
const account = useActiveAccount()!;
const { requestSignature } = useSigningContext();
const contacts = useUserContactList(account?.pubkey, undefined, true);
const { isMuted, unmute } = useUserMuteActions(pubkey);
const { openModal } = useMuteModalContext();
const actions = useActionHub();
const isFollowing = !!contacts && isProfilePointerInList(contacts, pubkey);
const [loading, setLoading] = useState(false);
const handleFollow = useAsyncErrorHandler(async () => {
setLoading(true);
const draft = listAddPerson(contacts || createEmptyContactList(), pubkey);
const signed = await requestSignature(draft);
await publish("Follow", signed);
setLoading(false);
}, [contacts, requestSignature, pubkey, publish]);
const handleUnfollow = useAsyncErrorHandler(async () => {
setLoading(true);
const draft = listRemovePerson(contacts || createEmptyContactList(), pubkey);
const signed = await requestSignature(draft);
await publish("Unfollow", signed);
setLoading(false);
}, [contacts, requestSignature, pubkey, publish]);
const toggleFollow = useAsyncErrorHandler(async () => {
if (isFollowing) {
await actions.exec(UnfollowUser, pubkey).forEach((e) => publish("Unfollow user", e));
} else {
await actions.exec(FollowUser, pubkey).forEach((e) => publish("Follow user", e));
}
}, [actions, isFollowing, pubkey]);
if (showLists) {
return (
@ -130,15 +113,13 @@ export function UserFollowButton({ pubkey, showLists, ...props }: UserFollowButt
{isFollowing ? "Unfollow" : "Follow"}
</MenuButton>
<MenuList>
{isFollowing ? (
<MenuItem onClick={handleUnfollow} icon={<UnfollowIcon />} isDisabled={loading}>
Unfollow
</MenuItem>
) : (
<MenuItem onClick={handleFollow} icon={<FollowIcon />} isDisabled={loading}>
Follow
</MenuItem>
)}
<MenuItem
onClick={toggleFollow.run}
icon={isFollowing ? <UnfollowIcon /> : <FollowIcon />}
isDisabled={toggleFollow.loading}
>
{isFollowing ? "Unfollow" : "Follow"}
</MenuItem>
{account?.pubkey !== pubkey && (
<MenuItem
onClick={isMuted ? unmute : () => openModal(pubkey)}
@ -159,13 +140,25 @@ export function UserFollowButton({ pubkey, showLists, ...props }: UserFollowButt
);
} else if (isFollowing) {
return (
<Button onClick={handleUnfollow} colorScheme="primary" icon={<UnfollowIcon />} isLoading={loading} {...props}>
<Button
onClick={toggleFollow.run}
colorScheme="primary"
icon={<UnfollowIcon />}
isLoading={toggleFollow.loading}
{...props}
>
Unfollow
</Button>
);
} else {
return (
<Button onClick={handleFollow} colorScheme="primary" icon={<FollowIcon />} isLoading={loading} {...props}>
<Button
onClick={toggleFollow.run}
colorScheme="primary"
icon={<FollowIcon />}
isLoading={toggleFollow.loading}
{...props}
>
Follow
</Button>
);

View File

@ -1,17 +1,22 @@
import { useToast } from "@chakra-ui/react";
import { DependencyList, useCallback } from "react";
import { DependencyList, useCallback, useState } from "react";
export default function useAsyncErrorHandler<T = any>(
fn: () => Promise<T>,
export default function useAsyncErrorHandler<Args extends Array<any>, T = any>(
fn: (...args: Args) => Promise<T>,
deps: DependencyList,
): () => Promise<T | undefined> {
): { loading: boolean; run: (...args: Args) => Promise<T | undefined> } {
const toast = useToast();
return useCallback(async () => {
const [loading, setLoading] = useState(false);
const run = useCallback<(...args: Args) => Promise<T | undefined>>(async (...args: Args) => {
setLoading(true);
try {
return await fn();
return await fn(...args);
} catch (e) {
if (e instanceof Error) toast({ description: e.message, status: "error" });
}
setLoading(false);
}, deps);
return { loading, run };
}

View File

@ -19,12 +19,12 @@ export default function useUserMuteActions(pubkey: string) {
const isMuted = isPubkeyInList(muteList, pubkey);
const expiration = muteList ? getPubkeyExpiration(muteList, pubkey) : 0;
const mute = useAsyncErrorHandler(async () => {
const { run: mute } = useAsyncErrorHandler(async () => {
let draft = muteListAddPubkey(muteList || createEmptyMuteList(), pubkey);
draft = pruneExpiredPubkeys(draft);
await publish("Mute", draft, undefined, false);
}, [publish, muteList]);
const unmute = useAsyncErrorHandler(async () => {
const { run: unmute } = useAsyncErrorHandler(async () => {
let draft = muteListRemovePubkey(muteList || createEmptyMuteList(), pubkey);
draft = pruneExpiredPubkeys(draft);
await publish("Unmute", draft, undefined, false);

View File

@ -1,14 +1,13 @@
import { Button, Card, CardBody, CardProps, Flex, Heading, Link } from "@chakra-ui/react";
import { removePubkeyTag } from "applesauce-factory/operations/tag";
import { Link as RouterLink } from "react-router-dom";
import { nip19 } from "nostr-tools";
import useUserProfile from "../../../hooks/use-user-profile";
import UserAvatar from "../../../components/user/user-avatar";
import UserDnsIdentity from "../../../components/user/user-dns-identity";
import { NostrEvent } from "../../../types/nostr-event";
import useAsyncErrorHandler from "../../../hooks/use-async-error-handler";
import { listRemovePerson } from "../../../helpers/nostr/lists";
import { useActiveAccount } from "applesauce-react/hooks";
import { useActiveAccount, useEventFactory } from "applesauce-react/hooks";
import { UserFollowButton } from "../../../components/user/user-follow-button";
import { usePublishEvent } from "../../../providers/global/publish-provider";
import UserName from "../../../components/user/user-name";
@ -18,11 +17,12 @@ export type UserCardProps = { pubkey: string; relay?: string; list: NostrEvent }
export default function UserCard({ pubkey, relay, list, ...props }: UserCardProps) {
const account = useActiveAccount();
const publish = usePublishEvent();
const metadata = useUserProfile(pubkey, relay ? [relay] : []);
const factory = useEventFactory();
const handleRemoveFromList = useAsyncErrorHandler(async () => {
const draft = listRemovePerson(list, pubkey);
publish("Remove from list", draft);
const remove = useAsyncErrorHandler(async () => {
const draft = await factory.modifyTags(list, removePubkeyTag(pubkey));
const signed = await factory.sign(draft);
await publish("Remove from list", signed);
}, [list, publish]);
return (
@ -38,7 +38,7 @@ export default function UserCard({ pubkey, relay, list, ...props }: UserCardProp
<UserDnsIdentity pubkey={pubkey} />
</Flex>
{account?.pubkey === list.pubkey ? (
<Button variant="outline" colorScheme="orange" onClick={handleRemoveFromList} size="sm">
<Button variant="outline" colorScheme="orange" onClick={remove.run} isLoading={remove.loading} size="sm">
Remove
</Button>
) : (

View File

@ -15,7 +15,7 @@ export default function MigrateAccountToDevice() {
const [loading, setLoading] = useState(false);
const manager = useAccountManager();
const migrate = useAsyncErrorHandler(async () => {
const { run: migrate } = useAsyncErrorHandler(async () => {
try {
setLoading(true);
if (!current?.signer) throw new Error("Account missing signer");

View File

@ -31,7 +31,8 @@ function BroadcastRelay({ relay }: { relay: string }) {
ml="auto"
colorScheme="red"
variant="ghost"
onClick={remove}
onClick={remove.run}
isLoading={remove.loading}
/>
</Flex>
);

View File

@ -40,7 +40,8 @@ function RelayLine({ relay, mode, list }: { relay: string; mode: RelayMode; list
ml="auto"
colorScheme="red"
variant="ghost"
onClick={remove}
onClick={remove.run}
isLoading={remove.loading}
/>
</Flex>
);

View File

@ -64,7 +64,7 @@ function MediaServersPage() {
await publish("Remove media server", draft);
};
const switchToBlossom = useAsyncErrorHandler(async () => {
const { run: switchToBlossom } = useAsyncErrorHandler(async () => {
await updateSettings({ mediaUploadService: "blossom" });
}, [updateSettings]);

View File

@ -21,7 +21,7 @@ export default function StreamOpenButton({
const { openAddress } = useContext(AppHandlerContext);
const address = useShareableEventAddress(stream);
const handleClick = useAsyncErrorHandler(async () => {
const { run: handleClick } = useAsyncErrorHandler(async () => {
if (!address) throw new Error("Failed to get address");
openAddress(address);
}, [address]);

View File

@ -0,0 +1,23 @@
import { Button, ButtonProps } from "@chakra-ui/react";
import { ConsolidateTokens } from "applesauce-wallet/actions";
import { useActionHub, useActiveAccount } from "applesauce-react/hooks";
import useUserWallet from "../../../hooks/use-user-wallet";
import useAsyncErrorHandler from "../../../hooks/use-async-error-handler";
export default function ConsolidateTokensButton({ children, ...props }: Omit<ButtonProps, "onClick" | "isLoading">) {
const account = useActiveAccount()!;
const wallet = useUserWallet(account.pubkey);
const actions = useActionHub();
const consolidate = useAsyncErrorHandler(async () => {
if (!wallet) throw new Error("Missing wallet");
await actions.run(ConsolidateTokens);
}, [wallet, actions]);
return (
<Button onClick={consolidate.run} isLoading={consolidate.loading} {...props}>
{children || "Consolidate"}
</Button>
);
}

View File

@ -18,7 +18,7 @@ export default function WalletUnlockButton({ children, ...props }: Omit<ButtonPr
}, [wallet, actions]);
return (
<Button onClick={unlock} {...props}>
<Button onClick={unlock.run} isLoading={unlock.loading} {...props}>
{children || "Unlock"}
</Button>
);

View File

@ -42,7 +42,6 @@ function HistoryEntry({ entry }: { entry: NostrEvent }) {
const eventStore = useEventStore();
const locked = isHistoryContentLocked(entry);
const details = !locked ? getHistoryContent(entry) : undefined;
const publish = usePublishEvent();
useEventUpdate(entry.id);
const ref = useEventIntersectionRef(entry);
@ -51,7 +50,7 @@ function HistoryEntry({ entry }: { entry: NostrEvent }) {
const redeemedIds = getHistoryRedeemed(entry);
const redeemed = useSingleEvents(redeemedIds);
const unlock = useAsyncErrorHandler(async () => {
const { run: unlock } = useAsyncErrorHandler(async () => {
await unlockHistoryContent(entry, account);
eventStore.update(entry);
}, [entry, account, eventStore]);
@ -122,7 +121,7 @@ export default function WalletHistoryTab() {
const history = useStoreQuery(WalletHistoryQuery, [account.pubkey]) ?? [];
const locked = useStoreQuery(WalletHistoryQuery, [account.pubkey, true]) ?? [];
const unlock = useAsyncErrorHandler(async () => {
const { run: unlock } = useAsyncErrorHandler(async () => {
for (const entry of locked) {
if (!isHistoryContentLocked(entry)) continue;
await unlockHistoryContent(entry, account);
@ -138,17 +137,16 @@ export default function WalletHistoryTab() {
return (
<Flex direction="column" gap="2" w="full">
{locked && locked.length > 0 && (
<Button onClick={unlock} size="sm" variant="link" p="2" ms="auto">
<ButtonGroup variant="link">
<Button onClick={clear.run} isLoading={clear.loading} isDisabled={history.length === 0}>
Clear History
</Button>
<Spacer />
<Button onClick={unlock} isDisabled={!locked || locked.length === 0}>
Unlock all ({locked?.length})
</Button>
)}
</ButtonGroup>
{history?.map((entry) => <HistoryEntry key={entry.id} entry={entry} />)}
{history.length > 0 && (
<Button variant="link" onClick={clear} ms="auto">
Clear history
</Button>
)}
</Flex>
);
}

View File

@ -25,6 +25,7 @@ import DebugEventButton from "../../../components/debug-modal/debug-event-button
import { useDeleteEventContext } from "../../../providers/route/delete-event-provider";
import Timestamp from "../../../components/timestamp";
import { getCashuWallet } from "../../../services/cashu-mints";
import ConsolidateTokensButton from "../components/consolidate-tokens-button";
function TokenEvent({ token }: { token: NostrEvent }) {
const account = useActiveAccount();
@ -37,7 +38,7 @@ function TokenEvent({ token }: { token: NostrEvent }) {
const amount = details?.proofs.reduce((t, p) => t + p.amount, 0);
const [spentState, setSpentState] = useState<ProofState[]>();
const check = useAsyncErrorHandler(async () => {
const { run: check } = useAsyncErrorHandler(async () => {
if (!details) return;
const wallet = await getCashuWallet(details.mint);
const state = await wallet.checkProofsStates(details.proofs);
@ -47,7 +48,7 @@ function TokenEvent({ token }: { token: NostrEvent }) {
const { deleteEvent } = useDeleteEventContext();
const unlock = useAsyncErrorHandler(async () => {
const { run: unlock } = useAsyncErrorHandler(async () => {
if (!account) return;
await unlockTokenContent(token, account);
eventStore.update(token);
@ -106,7 +107,7 @@ export default function WalletTokensTab({ ...props }: Omit<FlexProps, "children"
const tokens = useStoreQuery(WalletTokensQuery, [account.pubkey]) ?? [];
const locked = useStoreQuery(WalletTokensQuery, [account.pubkey, true]) ?? [];
const unlock = useAsyncErrorHandler(async () => {
const { run: unlock } = useAsyncErrorHandler(async () => {
if (!locked) return;
for (const token of locked) {
await unlockTokenContent(token, account);
@ -116,11 +117,13 @@ export default function WalletTokensTab({ ...props }: Omit<FlexProps, "children"
return (
<Flex direction="column" gap="2" {...props}>
{locked && locked.length > 0 && (
<Button onClick={unlock} size="sm" variant="link" p="2" ms="auto">
<ButtonGroup variant="link">
<ConsolidateTokensButton />
<Spacer />
<Button onClick={unlock} isDisabled={!locked || locked.length === 0}>
Unlock all ({locked?.length})
</Button>
)}
</ButtonGroup>
{tokens.map((token) => (
<TokenEvent key={token.id} token={token} />