Skip to content

Commit

Permalink
feat: authentication domain changes (#563)
Browse files Browse the repository at this point in the history
* feat: authentication domain changes

* First pass at new useLogin hook

* Implements useSession

* Fixes TS and linting ssues post rebase

* Adds changeset

* Fix unit test
  • Loading branch information
cesarenaldi authored Oct 8, 2023
1 parent ad478bf commit 6d0d62d
Show file tree
Hide file tree
Showing 132 changed files with 7,765 additions and 936 deletions.
8 changes: 8 additions & 0 deletions .changeset/hot-hornets-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@lens-protocol/shared-kernel": patch
"@lens-protocol/api-bindings": patch
"@lens-protocol/domain": patch
"@lens-protocol/react": patch
---

**feat:** new `useLogin` and `useSession` hooks
66 changes: 37 additions & 29 deletions examples/web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { LensConfig, LensProvider, development } from '@lens-protocol/react';
import { bindings as wagmiBindings } from '@lens-protocol/wagmi';
import { XMTPProvider } from '@xmtp/react-sdk';
import { Toaster } from 'react-hot-toast';
import { Route, BrowserRouter as Router, Routes } from 'react-router-dom';
Expand All @@ -7,8 +8,9 @@ import { polygonMumbai } from 'wagmi/chains';
import { InjectedConnector } from 'wagmi/connectors/injected';
import { publicProvider } from 'wagmi/providers/public';

import { Home } from './HomePage';
import { Breadcrumbs } from './components/Breadcrumbs';
import { HomePage } from './HomePage';
import { Layout } from './Layout';
import { LogInPage } from './LogInPage';
import { GenericErrorBoundary } from './components/GenericErrorBoundary';
import { ErrorMessage } from './components/error/ErrorMessage';
import { Header } from './components/header/Header';
Expand Down Expand Up @@ -56,6 +58,7 @@ const config = createConfig({
const lensConfig: LensConfig = {
environment: development,
storage: localStorage(),
bindings: wagmiBindings(),
};

export function App() {
Expand All @@ -66,38 +69,43 @@ export function App() {
<Router>
<Header />
<main>
<Breadcrumbs />
<GenericErrorBoundary fallback={ErrorMessage}>
<Routes>
<Route index element={<Home />} />
<Route index element={<HomePage />} />
<Route path="/login" element={<LogInPage />} />

<Route path="/publications">
<Route index element={<PublicationsPage />} />
<Route path="usePublication" element={<UsePublication />} />
<Route path="usePublications" element={<UsePublications />} />
<Route
path="useWhoReactedToPublication"
element={<UseWhoReactedToPublication />}
/>
</Route>
<Route element={<Layout />}>
<Route path="/publications">
<Route index element={<PublicationsPage />} />
<Route path="usePublication" element={<UsePublication />} />
<Route path="usePublications" element={<UsePublications />} />
<Route
path="useWhoReactedToPublication"
element={<UseWhoReactedToPublication />}
/>
</Route>

<Route path="/profiles">
<Route index element={<ProfilesPage />} />
<Route path="useProfile" element={<UseProfile />} />
<Route path="useProfiles" element={<UseProfiles />} />
<Route path="useProfileFollowers" element={<UseProfileFollowers />} />
<Route path="useProfileFollowing" element={<UseProfileFollowing />} />
<Route path="useMutualFollowers" element={<UseMutualFollowers />} />
<Route path="useRecommendedProfiles" element={<UseRecommendedProfiles />} />
<Route path="useWhoActedOnPublication" element={<UseWhoActedOnPublication />} />
<Route path="useProfileActionHistory" element={<UseProfileActionHistory />} />
</Route>
<Route path="/profiles">
<Route index element={<ProfilesPage />} />
<Route path="useProfile" element={<UseProfile />} />
<Route path="useProfiles" element={<UseProfiles />} />
<Route path="useProfileFollowers" element={<UseProfileFollowers />} />
<Route path="useProfileFollowing" element={<UseProfileFollowing />} />
<Route path="useMutualFollowers" element={<UseMutualFollowers />} />
<Route path="useRecommendedProfiles" element={<UseRecommendedProfiles />} />
<Route
path="useWhoActedOnPublication"
element={<UseWhoActedOnPublication />}
/>
<Route path="useProfileActionHistory" element={<UseProfileActionHistory />} />
</Route>

<Route path="/discovery">
<Route index element={<DiscoveryPage />} />
<Route path="useFeed" element={<UseFeed />} />
<Route path="useSearchPublications" element={<UseSearchPublications />} />
<Route path="useSearchProfiles" element={<UseSearchProfiles />} />
<Route path="/discovery">
<Route index element={<DiscoveryPage />} />
<Route path="useFeed" element={<UseFeed />} />
<Route path="useSearchPublications" element={<UseSearchPublications />} />
<Route path="useSearchProfiles" element={<UseSearchProfiles />} />
</Route>
</Route>

<Route path="*" element={<p>Not found</p>} />
Expand Down
22 changes: 9 additions & 13 deletions examples/web/src/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@ import { Link } from 'react-router-dom';

import { CATEGORIES } from './config';

export function Home() {
export function HomePage() {
return (
<>
<h1>Home</h1>

<div>
{CATEGORIES.map(({ path, label }) => (
<article key={path}>
<h2>{label}</h2>
<Link to={path}>View</Link>
</article>
))}
</div>
</>
<div>
{CATEGORIES.map(({ path, label }) => (
<article key={path}>
<h2>{label}</h2>
<Link to={path}>View</Link>
</article>
))}
</div>
);
}
12 changes: 12 additions & 0 deletions examples/web/src/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Outlet } from 'react-router-dom';

import { Breadcrumbs } from './components/Breadcrumbs';

export function Layout() {
return (
<>
<Breadcrumbs />
<Outlet />
</>
);
}
95 changes: 95 additions & 0 deletions examples/web/src/LogInPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { ProfileId, useLogin, useProfiles } from '@lens-protocol/react';
import toast from 'react-hot-toast';
import { useNavigate } from 'react-router-dom';
import { useAccount, useConnect } from 'wagmi';
import { InjectedConnector } from 'wagmi/connectors/injected';

import { ErrorMessage } from './components/error/ErrorMessage';
import { Loading } from './components/loading/Loading';
import { never } from './utils';

function ProfilesList({ owner }: { owner: string }) {
const navigate = useNavigate();
const { execute: login, isPending: isLoginPending } = useLogin();
const { data: profiles, error, loading } = useProfiles({ where: { ownedBy: [owner] } });

const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();

const form = event.currentTarget;
const formData = new FormData(form);

const profileId = (formData.get('id') as string) ?? never();

const result = await login({
address: owner,
profileId: profileId as ProfileId,
});

if (result.isSuccess()) {
toast.success(`Welcome ${String(result.value.handle)}`);
return navigate('/');
}

toast.error(result.error.message);
};

if (loading) {
return <Loading />;
}

if (error) {
return <ErrorMessage error={error} />;
}

if (profiles.length === 0) {
return <p>No profiles on this wallet.</p>;
}

return (
<form onSubmit={onSubmit}>
<fieldset>
<legend>Which Profile you want to log-in with?</legend>

{profiles.map((profile, idx) => (
<label key={profile.id}>
<input
disabled={isLoginPending}
type="radio"
defaultChecked={idx === 0}
name="id"
value={profile.id}
/>
{profile.handle}
</label>
))}

<div>
<button disabled={isLoginPending} type="submit">
Continue
</button>
</div>
</fieldset>
</form>
);
}

export function LogInPage() {
const { address, isConnected, isConnecting } = useAccount();

const { connect } = useConnect({
connector: new InjectedConnector(),
});

return (
<div>
{!isConnected && (
<button disabled={isConnecting} onClick={() => connect()}>
Connect first
</button>
)}

{address && <ProfilesList owner={address} />}
</div>
);
}
6 changes: 6 additions & 0 deletions examples/web/src/components/auth/LoginButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Link } from 'react-router-dom';

// TODO render log out button once useSession is implemented
export function LoginButton() {
return <Link to="/login">Log in</Link>;
}
1 change: 1 addition & 0 deletions examples/web/src/components/auth/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './LoginButton';
15 changes: 14 additions & 1 deletion examples/web/src/components/header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { SessionType, useSession } from '@lens-protocol/react';
import { NavLink } from 'react-router-dom';

import { CATEGORIES } from '../../config';
import { LoginButton } from '../auth';

export function Header() {
const { data: session } = useSession();
return (
<header>
<div
Expand All @@ -25,7 +28,17 @@ export function Header() {
justifyContent: 'space-between',
gap: '1rem',
}}
></div>
>
{session?.type === SessionType.WithProfile && (
<strong>
{session.profile.metadata?.displayName ??
session.profile.handle ??
session.profile.id}
</strong>
)}

<LoginButton />
</div>
</div>

<nav>
Expand Down
21 changes: 2 additions & 19 deletions packages/api-bindings/src/apollo/cache/__helpers__/mocks.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
import { ApolloCache, NormalizedCacheObject, ReactiveVar } from '@apollo/client';
import { ApolloCache, NormalizedCacheObject } from '@apollo/client';
import { faker } from '@faker-js/faker';
import { mockCreatePostRequest, mockWalletData } from '@lens-protocol/domain/mocks';
import { ProfileIdentifier, WalletData } from '@lens-protocol/domain/use-cases/lifecycle';
import { mockCreatePostRequest } from '@lens-protocol/domain/mocks';
import { AnyTransactionRequest } from '@lens-protocol/domain/use-cases/transactions';

import { createLensCache } from '../createLensCache';
import { authenticatedProfile, authenticatedWallet, updateSession } from '../session';
import { TransactionState, TxStatus } from '../transactions';

export type MockCacheConfiguration = {
activeWalletVar?: ReactiveVar<WalletData | null>;
};

export function mockLensCache(): ApolloCache<NormalizedCacheObject> {
return createLensCache();
}
Expand All @@ -26,14 +20,3 @@ export function mockTransactionState<T extends AnyTransactionRequest>(
...partial,
};
}

export function simulateAuthenticatedWallet(wallet = mockWalletData()) {
updateSession(authenticatedWallet(wallet));
}

export function simulateAuthenticatedProfile(
profile: ProfileIdentifier,
wallet = mockWalletData(),
) {
updateSession(authenticatedProfile(wallet, profile));
}
Loading

0 comments on commit 6d0d62d

Please sign in to comment.