From b0c9cce5c3ea9246fbc2f71ac64c10c5252ec9a4 Mon Sep 17 00:00:00 2001
From: Eric Bailey <git@esb.lol>
Date: Fri, 10 Nov 2023 08:46:45 -0600
Subject: [PATCH] Follow conventions for query, use isDirty flag in session
 store to avoid unneccessary writes

---
 src/{data => state/queries}/index.ts          |  0
 .../queries/profile.ts}                       |  4 ++--
 src/state/session/index.tsx                   | 20 +++++++++++++------
 src/view/com/auth/login/ChooseAccountForm.tsx |  4 ++--
 src/view/com/modals/SwitchAccount.tsx         |  4 ++--
 src/view/screens/Settings.tsx                 |  4 ++--
 src/view/shell/desktop/LeftNav.tsx            |  4 ++--
 7 files changed, 24 insertions(+), 16 deletions(-)
 rename src/{data => state/queries}/index.ts (100%)
 rename src/{data/useGetProfile.ts => state/queries/profile.ts} (68%)

diff --git a/src/data/index.ts b/src/state/queries/index.ts
similarity index 100%
rename from src/data/index.ts
rename to src/state/queries/index.ts
diff --git a/src/data/useGetProfile.ts b/src/state/queries/profile.ts
similarity index 68%
rename from src/data/useGetProfile.ts
rename to src/state/queries/profile.ts
index 5e0ab907..c2cd1948 100644
--- a/src/data/useGetProfile.ts
+++ b/src/state/queries/profile.ts
@@ -1,8 +1,8 @@
 import {useQuery} from '@tanstack/react-query'
 
-import {PUBLIC_BSKY_AGENT} from '#/data'
+import {PUBLIC_BSKY_AGENT} from '#/state/queries'
 
-export function useGetProfile({did}: {did: string}) {
+export function useProfileQuery({did}: {did: string}) {
   return useQuery({
     queryKey: ['getProfile', did],
     queryFn: async () => {
diff --git a/src/state/session/index.tsx b/src/state/session/index.tsx
index a5362ac6..85ae3b52 100644
--- a/src/state/session/index.tsx
+++ b/src/state/session/index.tsx
@@ -4,7 +4,7 @@ import {BskyAgent, AtpPersistSessionHandler} from '@atproto/api'
 import {networkRetry} from '#/lib/async/retry'
 import {logger} from '#/logger'
 import * as persisted from '#/state/persisted'
-import {PUBLIC_BSKY_AGENT} from '#/data'
+import {PUBLIC_BSKY_AGENT} from '#/state/queries'
 
 export type SessionAccount = persisted.PersistedAccount
 
@@ -102,6 +102,7 @@ function createPersistSessionHandler(
 }
 
 export function Provider({children}: React.PropsWithChildren<{}>) {
+  const isDirty = React.useRef(false)
   const [state, setState] = React.useState<StateContext>({
     agent: PUBLIC_BSKY_AGENT,
     hasSession: false,
@@ -113,6 +114,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
 
   const upsertAccount = React.useCallback(
     (account: persisted.PersistedAccount, expired = false) => {
+      isDirty.current = true
       setState(s => {
         return {
           ...s,
@@ -124,7 +126,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
     [setState],
   )
 
-  // TODO have not connected this yet
   const createAccount = React.useCallback<ApiContext['createAccount']>(
     async ({service, email, password, handle, inviteCode}: any) => {
       logger.debug(
@@ -231,6 +232,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
 
   const logout = React.useCallback<ApiContext['logout']>(async () => {
     logger.debug(`session: logout`, {}, logger.DebugContext.session)
+    isDirty.current = true
     setState(s => {
       return {
         ...s,
@@ -301,6 +303,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
 
   const removeAccount = React.useCallback<ApiContext['removeAccount']>(
     account => {
+      isDirty.current = true
       setState(s => {
         return {
           ...s,
@@ -317,6 +320,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
     ApiContext['updateCurrentAccount']
   >(
     account => {
+      isDirty.current = true
       setState(s => {
         const currentAccount = s.currentAccount
 
@@ -363,6 +367,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
   )
 
   const clearCurrentAccount = React.useCallback(() => {
+    isDirty.current = true
     setState(s => ({
       ...s,
       currentAccount: undefined,
@@ -370,10 +375,13 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
   }, [setState])
 
   React.useEffect(() => {
-    persisted.write('session', {
-      accounts: state.accounts,
-      currentAccount: state.currentAccount,
-    })
+    if (isDirty.current) {
+      persisted.write('session', {
+        accounts: state.accounts,
+        currentAccount: state.currentAccount,
+      })
+      isDirty.current = false
+    }
   }, [state])
 
   React.useEffect(() => {
diff --git a/src/view/com/auth/login/ChooseAccountForm.tsx b/src/view/com/auth/login/ChooseAccountForm.tsx
index f1503e64..add99789 100644
--- a/src/view/com/auth/login/ChooseAccountForm.tsx
+++ b/src/view/com/auth/login/ChooseAccountForm.tsx
@@ -11,7 +11,7 @@ import {Trans, msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {styles} from './styles'
 import {useSession, useSessionApi, SessionAccount} from '#/state/session'
-import {useGetProfile} from '#/data/useGetProfile'
+import {useProfileQuery} from '#/state/queries/profile'
 
 function AccountItem({
   account,
@@ -22,7 +22,7 @@ function AccountItem({
 }) {
   const pal = usePalette('default')
   const {_} = useLingui()
-  const {isError, data} = useGetProfile({did: account.did})
+  const {isError, data} = useProfileQuery({did: account.did})
 
   const onPress = React.useCallback(() => {
     onSelect(account)
diff --git a/src/view/com/modals/SwitchAccount.tsx b/src/view/com/modals/SwitchAccount.tsx
index 2ff70eea..55ba6936 100644
--- a/src/view/com/modals/SwitchAccount.tsx
+++ b/src/view/com/modals/SwitchAccount.tsx
@@ -19,7 +19,7 @@ import {Haptics} from 'lib/haptics'
 import {Trans, msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {useSession, useSessionApi, SessionAccount} from '#/state/session'
-import {useGetProfile} from '#/data/useGetProfile'
+import {useProfileQuery} from '#/state/queries/profile'
 
 export const snapPoints = ['40%', '90%']
 
@@ -29,7 +29,7 @@ function SwitchAccountCard({account}: {account: SessionAccount}) {
   const {track} = useAnalytics()
   const {isSwitchingAccounts, currentAccount} = useSession()
   const {logout} = useSessionApi()
-  const {isError, data: profile} = useGetProfile({did: account.did})
+  const {isError, data: profile} = useProfileQuery({did: account.did})
   const isCurrentAccount = account.did === currentAccount?.did
   const {onPressSwitchAccount} = useAccountSwitcher()
 
diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx
index 4fd2f2d5..cff92f8f 100644
--- a/src/view/screens/Settings.tsx
+++ b/src/view/screens/Settings.tsx
@@ -58,7 +58,7 @@ import {
   useSetRequireAltTextEnabled,
 } from '#/state/preferences'
 import {useSession, useSessionApi, SessionAccount} from '#/state/session'
-import {useGetProfile} from '#/data/useGetProfile'
+import {useProfileQuery} from '#/state/queries/profile'
 
 // TEMPORARY (APP-700)
 // remove after backend testing finishes
@@ -72,7 +72,7 @@ function SettingsAccountCard({account}: {account: SessionAccount}) {
   const pal = usePalette('default')
   const {isSwitchingAccounts, currentAccount} = useSession()
   const {logout} = useSessionApi()
-  const {isError, data} = useGetProfile({did: account.did})
+  const {isError, data} = useProfileQuery({did: account.did})
   const isCurrentAccount = account.did === currentAccount?.did
   const {onPressSwitchAccount} = useAccountSwitcher()
 
diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
index 3a0c0c95..45be67d2 100644
--- a/src/view/shell/desktop/LeftNav.tsx
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -41,7 +41,7 @@ import {router} from '../../../routes'
 import {makeProfileLink} from 'lib/routes/links'
 import {useLingui} from '@lingui/react'
 import {Trans, msg} from '@lingui/macro'
-import {useGetProfile} from '#/data/useGetProfile'
+import {useProfileQuery} from '#/state/queries/profile'
 import {useSession} from '#/state/session'
 
 const ProfileCard = observer(function ProfileCardImpl() {
@@ -50,7 +50,7 @@ const ProfileCard = observer(function ProfileCardImpl() {
     isLoading,
     isError,
     data: profile,
-  } = useGetProfile({did: currentAccount!.did})
+  } = useProfileQuery({did: currentAccount!.did})
   const {isDesktop} = useWebMediaQueries()
   const size = 48