MakePrisms / boardwalkcash

https://boardwalkcash.com
MIT License
31 stars 4 forks source link

Initialize users at the app level, not at the page #79

Open gudnuf opened 3 months ago

gudnuf commented 3 months ago

Move the logic executed by dispatch(initializeUser()) to the app level or make it a context.

Right now the user is loaded/initialized from the wallet page, but it seems like they should be initialized in the _app page. This might be wrong because we don't necessarily want the user to get initialized on all pages (like the /warning page for example)

AtlantisPleb commented 2 months ago

Hey folks, I had my agents analyze your codebase (see its knowledge base here) and propose here an approach to fix this issue. Unsure if this codebase is active / worth submitting PRs to, just let me know if you want a PR based on the below and I'm happy to contribute it. --Chris

Proposal: App-level User Initialization

Currently, the user initialization process is handled at the page level, which can lead to inconsistencies across different pages and potential race conditions. I propose moving the user initialization to the app level to improve consistency, performance, and overall user experience. Here's a detailed breakdown of the proposed changes and their benefits:

Current Implementation

The initializeUser function is called within individual pages, typically in a useEffect hook. This approach has several drawbacks:

  1. Inconsistent user state across pages
  2. Potential for multiple unnecessary initialization calls
  3. Race conditions when navigating between pages quickly

Proposed Solution

Move the user initialization to the _app.tsx file and implement a global context for user state. This approach will:

  1. Ensure consistent user state across all pages
  2. Reduce unnecessary API calls and improve performance
  3. Simplify page-level components by removing initialization logic

Implementation Steps

  1. Create a new UserContext.tsx file:
    
    import React, { createContext, useContext, useEffect, useState } from 'react';
    import { useDispatch, useSelector } from 'react-redux';
    import { initializeUser } from '@/redux/slices/UserSlice';
    import { RootState } from '@/redux/store';

interface UserContextType { isInitialized: boolean; isLoading: boolean; error: string | null; }

const UserContext = createContext<UserContextType | undefined>(undefined);

export const UserProvider: React.FC = ({ children }) => { const dispatch = useDispatch(); const user = useSelector((state: RootState) => state.user); const [isInitialized, setIsInitialized] = useState(false);

useEffect(() => { const initUser = async () => { if (!isInitialized && user.status === 'idle') { await dispatch(initializeUser()); setIsInitialized(true); } };

initUser();

}, [dispatch, isInitialized, user.status]);

return ( <UserContext.Provider value={{ isInitialized, isLoading: user.status === 'loading', error: user.error }}> {children} </UserContext.Provider> ); };

export const useUser = () => { const context = useContext(UserContext); if (context === undefined) { throw new Error('useUser must be used within a UserProvider'); } return context; };


2. Update `_app.tsx` to include the `UserProvider`:
```typescript
import { UserProvider } from '@/contexts/UserContext';

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <Provider store={store}>
      <UserProvider>
        <Component {...pageProps} />
      </UserProvider>
    </Provider>
  );
}
  1. Update page components to use the new useUser hook:
    
    import { useUser } from '@/contexts/UserContext';

const SomePage: React.FC = () => { const { isInitialized, isLoading, error } = useUser();

if (isLoading) return ; if (error) return ; if (!isInitialized) return null;

return ( // Page content ); };



### Benefits
1. **Consistency**: User state will be initialized once and shared across all pages.
2. **Performance**: Reduces redundant API calls and prevents race conditions.
3. **Simplicity**: Simplifies page-level components by centralizing user initialization logic.
4. **Error Handling**: Provides a centralized place to handle user initialization errors.

### Considerations
1. **Initial Load Time**: The initial app load might take slightly longer as user initialization will happen before any page renders. This can be mitigated with proper loading indicators.
2. **SSR Compatibility**: Ensure that the implementation is compatible with Next.js server-side rendering.

### Next Steps
1. Implement the proposed changes in a new branch.
2. Add comprehensive unit and integration tests to ensure the new initialization process works correctly.
3. Update relevant documentation to reflect the new user initialization process.
4. Consider implementing a retry mechanism for failed initializations.

I'd appreciate your thoughts on this approach. Are there any specific concerns or additional requirements we should consider? Once we agree on the general direction, I can proceed with creating a detailed implementation plan or a proof-of-concept PR for further discussion.