interledger / web-monetization-extension

An open-source browser extension that enables Web Monetization.
Apache License 2.0
46 stars 2 forks source link

fix(popup): prevent data loss in connect screen #321

Closed dianafulga closed 1 week ago

dianafulga commented 2 weeks ago

Closes #293

raducristianpopa commented 2 weeks ago

Extension builds preview

Name Link
Latest commit 6ac25afd14337a3567f3ee9ca4888592122f73d6
Latest job logs Run #9495241071
BadgeDownload
BadgeDownload
sidvishnoi commented 2 weeks ago

A quick pass with localStorage.. Please test, I didn't test enough. Maybe sessionStorage could work too.

diff --git a/src/popup/components/ConnectWalletForm.tsx b/src/popup/components/ConnectWalletForm.tsx
index ce37049..9a589e7 100644
--- a/src/popup/components/ConnectWalletForm.tsx
+++ b/src/popup/components/ConnectWalletForm.tsx
@@ -27,6 +27,10 @@ interface ConnectWalletFormProps {
 }

 export const ConnectWalletForm = ({ publicKey }: ConnectWalletFormProps) => {
+  const [formState, setFormState] = useLocalStorage<ConnectWalletFormInputs>(
+    'form_state',
+    { amount: '', recurring: false, walletAddressUrl: '' }
+  )
   const {
     register,
     handleSubmit,
@@ -39,7 +43,7 @@ export const ConnectWalletForm = ({ publicKey }: ConnectWalletFormProps) => {
     mode: 'onSubmit',
     reValidateMode: 'onBlur',
     defaultValues: {
-      recurring: false
+      ...formState
     }
   })
   const [currencySymbol, setCurrencySymbol] = React.useState<{
@@ -147,7 +151,9 @@ export const ConnectWalletForm = ({ publicKey }: ConnectWalletFormProps) => {
         {...register('walletAddressUrl', {
           required: { value: true, message: 'Wallet address URL is required.' },
           onBlur: (e: React.FocusEvent<HTMLInputElement>) => {
-            getWalletCurrency(e.currentTarget.value)
+            const walletAddressUrl = e.currentTarget.value
+            setFormState((s) => ({ ...s, walletAddressUrl }))
+            getWalletCurrency(walletAddressUrl)
           }
         })}
       />
@@ -174,10 +180,12 @@ export const ConnectWalletForm = ({ publicKey }: ConnectWalletFormProps) => {
           required: { value: true, message: 'Amount is required.' },
           valueAsNumber: false,
           onBlur: (e: React.FocusEvent<HTMLInputElement>) => {
-            setValue(
-              'amount',
-              formatNumber(+e.currentTarget.value, currencySymbol.scale)
+            const amount = formatNumber(
+              +e.currentTarget.value,
+              currencySymbol.scale
             )
+            setFormState((s) => ({ ...s, amount }))
+            setValue('amount', amount)
           }
         })}
       />
@@ -198,3 +206,25 @@ export const ConnectWalletForm = ({ publicKey }: ConnectWalletFormProps) => {
 }

 const HOSTS_PERMISSION = { origins: ['http://*/*', 'https://*/*'] }
+
+import { useState, useEffect } from 'react'
+
+function useLocalStorage<T>(key: string, defaultValue?: T) {
+  const [value, setValue] = useState<T>(() => {
+    if (typeof localStorage === 'undefined') {
+      return defaultValue
+    }
+    const storedValue = localStorage.getItem(key)
+    if (storedValue) {
+      return JSON.parse(storedValue)
+    }
+    return defaultValue
+  })
+
+  useEffect(() => {
+    if (value === undefined) return
+    localStorage.setItem(key, JSON.stringify(value))
+  }, [value, key])
+
+  return [value, setValue] as const
+}
dianafulga commented 1 week ago

Also, were there some issues in the useLocalStorage hook based approach I suggested? I think it could've been used as is.

There is no need for using/keeping state, we only use the localStorage for initialisation and writing should be async