Skip to content

Commit

Permalink
feat: added sidebar login
Browse files Browse the repository at this point in the history
  • Loading branch information
acaldas committed Apr 10, 2024
1 parent 95d006f commit 2917809
Show file tree
Hide file tree
Showing 16 changed files with 153 additions and 108 deletions.
7 changes: 4 additions & 3 deletions .env
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
VITE_DISABLED_EDITORS=powerhouse/document-drive
VITE_RENOWN_URL=http://localhost:3000
VITE_DEFAULT_DRIVE_URL=https://apps.powerhouse.io/makerdao/switchboard/d/monetalis
VITE_BASE_HREF=/makerdao/connect
ASSET_URL=/makerdao/connect
VITE_BASE_HREF=/
ASSET_URL=/

# Set the base URL of the app (default: /)
VITE_ROUTER_BASENAME=/makerdao/connect
VITE_ROUTER_BASENAME=/

######## CONNECT CONTENT CONFIG ########
# Set to false to hide searchbar in folder conent (default: true)
Expand Down
3 changes: 3 additions & 0 deletions .env.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
VITE_BASE_HREF=/alpha/powerhouse/connect
ASSET_URL=/alpha/powerhouse/connect
VITE_ROUTER_BASENAME=/alpha/powerhouse/connect
10 changes: 7 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"xvfb-maybe": "^0.2.1"
},
"dependencies": {
"@powerhousedao/design-system": "1.0.0-alpha.90",
"@powerhousedao/design-system": "^1.0.0-alpha.91",
"did-key-creator": "^1.2.0",
"document-drive": "^1.0.0-alpha.28",
"document-model": "^1.0.35",
Expand Down
39 changes: 2 additions & 37 deletions src/components/login.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,15 @@
import IconRenown from '@/assets/icons/renown.svg?react';
import { Button } from '@powerhousedao/design-system';
import { useState } from 'react';
import DotsLoader from 'src/components/dots-loader';
import { useConnectCrypto } from 'src/hooks/useConnectCrypto';
import { useLogin } from 'src/hooks/useLogin';
import { useRenown } from 'src/hooks/useRenown';
import { RENOWN_URL } from 'src/services/renown/constants';
import { useUser } from 'src/store/user';

type LoginStatus = 'initial' | 'checking' | 'not-authorized' | 'authorized';

export const Login: React.FC = () => {
const [status, setStatus] = useState<LoginStatus>('initial');
const user = useUser();
const renown = useRenown();
const { did } = useConnectCrypto();

async function login() {
const connectId = await did();
const url = `${RENOWN_URL}?connect=${encodeURIComponent(connectId)}`;

if (window.electronAPI) {
const protocol = await window.electronAPI.protocol();
await window.electronAPI.openURL(`${url}&deeplink=${protocol}`);
} else {
window.open(url, '_blank')?.focus();
}
}

async function checkLogin() {
try {
setStatus('checking');
const connectId = await did();
const user = await renown?.login(connectId);
if (user) {
setStatus('authorized');
} else {
setStatus('initial');
}
} catch (e) {
setStatus('not-authorized');
}
}

if (status === 'initial' && user) {
setStatus('authorized');
}
const { login, status } = useLogin();

return (
<div>
Expand Down
4 changes: 3 additions & 1 deletion src/components/modal/modals/SettingsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ export const SettingsModal: React.FC<SettingsModalProps> = props => {
<>
<p>
Logged in with address:{' '}
<span className="text-sm">{user.address}</span>
<span className="text-sm font-semibold">
{user.address}
</span>
</p>
<Button
className="mt-2 w-full"
Expand Down
37 changes: 20 additions & 17 deletions src/components/root.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import IconConnect from '@/assets/icons/connect.svg?react';
import IconLogo from '@/assets/icons/logo.svg?react';
import { useSetAtom } from 'jotai';
import React, { Suspense, useEffect } from 'react';
import { Outlet, useNavigate } from 'react-router-dom';
import { Outlet, useNavigate, useSearchParams } from 'react-router-dom';
import { useDropFile } from 'src/hooks';
import { useLoadInitialData } from 'src/hooks/useLoadInitialData';
import { useRenown } from 'src/hooks/useRenown';
import { isElectron, isMac } from 'src/hooks/utils';
import { userAtom } from 'src/store/user';
import Sidebar from './sidebar';

const ROOT_FILE_DROP = false;
Expand All @@ -16,26 +14,31 @@ const Root = () => {
useLoadInitialData();
const ref = React.useRef(null);
const navigate = useNavigate();

const renown = useRenown();
const setUser = useSetAtom(userAtom);

useEffect(() => {
window.electronAPI?.ready();
}, []);

renown
?.user()
.then(user => {
setUser(user);
})
.catch(console.error);

const unsubscribeLogin = renown?.on.user(user => {
setUser(user);
});
const [searchParams, setSearchParams] = useSearchParams();

return unsubscribeLogin;
}, [renown, setUser]);
useEffect(() => {
const userStr = searchParams.get('user');
if (userStr) {
const userDid = decodeURIComponent(userStr);
searchParams.delete('user');
setSearchParams(searchParams);
renown
?.user()
.then(user => {
if (user?.did === userDid) {
return;
}
return renown.login(userDid);
})
.catch(console.error);
}
}, [renown, searchParams, setSearchParams]);

useEffect(() => {
const unsubscribe = window.electronAPI?.handleURL((_e, url) => {
Expand Down
17 changes: 11 additions & 6 deletions src/components/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/* eslint-disable tailwindcss/no-arbitrary-value */
import { ConnectSidebar, Icon } from '@powerhousedao/design-system';
import { useAtom, useAtomValue } from 'jotai';
import { useAtom } from 'jotai';
import { useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { useNavigate } from 'react-router-dom';
import { useENSInfo } from 'src/hooks/useEnsInfo';
import { useLogin } from 'src/hooks/useLogin';
import { sidebarCollapsedAtom } from 'src/store';
import { userAtom } from 'src/store/user';
import DriveContainer from './drive-container';
import { useModal } from './modal';

Expand All @@ -22,8 +22,11 @@ export default function Sidebar() {
const { showModal } = useModal();
const navigate = useNavigate();

const user = useAtomValue(userAtom);
const ensInfo = useENSInfo(user?.address, user?.chainId);
const { user, login } = useLogin();
const { info: ensInfo, loading: loadingUser } = useENSInfo(
user?.address,
user?.chainId,
);

function toggleCollapse() {
setCollapsed(value => !value);
Expand All @@ -44,10 +47,12 @@ export default function Sidebar() {
collapsed={collapsed}
onToggle={toggleCollapse}
username={ensInfo?.name || ''}
avatarUrl={ensInfo?.avatarUrl || ''}
avatarUrl={ensInfo?.avatarUrl}
onClickSettings={onClickSettings}
headerContent={headerContent}
address={user?.address ? shortAddress(user.address) : '-'}
address={user?.address ? shortAddress(user.address) : ''}
loadingUser={loadingUser}
onLogin={login}
>
<ErrorBoundary
fallback={
Expand Down
11 changes: 7 additions & 4 deletions src/hooks/useEnsInfo.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import { useEffect, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { getEnsInfo, type ENSInfo } from 'src/services/viem';

export function useENSInfo(
address?: `0x${string}`,
chainId?: number,
): ENSInfo | undefined {
): { info: ENSInfo | undefined; loading: boolean } {
const [info, setInfo] = useState<ENSInfo | undefined>(undefined);
const [loading, setLoading] = useState(false);

useEffect(() => {
if (!address || !chainId) {
return;
}
setLoading(true);
getEnsInfo(address, chainId)
.then(info => setInfo(info))
.catch(console.error);
.catch(console.error)
.finally(() => setLoading(false));
}, [address, chainId]);

return info;
return useMemo(() => ({ info, loading }) as const, [info, loading]);
}
43 changes: 43 additions & 0 deletions src/hooks/useLogin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useCallback, useMemo, useState } from 'react';
import { useConnectCrypto } from 'src/hooks/useConnectCrypto';
import { useRenown } from 'src/hooks/useRenown';
import { RENOWN_NETWORK_ID, RENOWN_URL } from 'src/services/renown/constants';
import { useUser } from 'src/store/user';

type LoginStatus = 'initial' | 'checking' | 'not-authorized' | 'authorized';

export const useLogin = () => {
const [status, setStatus] = useState<LoginStatus>('initial');
const user = useUser();
const renown = useRenown();
const { did } = useConnectCrypto();

const login = useCallback(async () => {
const connectId = await did();
const url = `${RENOWN_URL}?connect=${encodeURIComponent(connectId)}&network=${RENOWN_NETWORK_ID}`;

setStatus('checking');
if (window.electronAPI) {
const protocol = await window.electronAPI.protocol();
await window.electronAPI.openURL(`${url}&deeplink=${protocol}`);
} else {
window
.open(
`${url}&returnUrl=${encodeURIComponent(`${window.location.origin}${window.location.pathname}`)}`,
'_self',
)
?.focus();
}
}, [did]);

if (user && status !== 'authorized') {
setStatus('authorized');
}

const logout = useMemo(() => renown?.logout, [renown]);

return useMemo(
() => ({ user, status, login, logout }) as const,
[user, status, login, logout],
);
};
6 changes: 3 additions & 3 deletions src/hooks/useNavigateToItemId.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useNavigate } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router-dom';
import { useGetReadableItemPath } from './useGetReadableItemPath';

export const useNavigateToItemId = () => {
const navigate = useNavigate();
const location = useLocation();
const getReadableItemPath = useGetReadableItemPath();

return (id: string) => {
const itemPath = getReadableItemPath(id);
const fullPath = `/d/${encodeURI(itemPath)}`;

navigate(fullPath);
navigate({ pathname: fullPath, search: location.search });
};
};
10 changes: 0 additions & 10 deletions src/hooks/useRenown.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { atom, useAtom } from 'jotai';
import { useEffect } from 'react';
import { IRenown, User } from 'src/services/renown/types';
import { useConnectCrypto } from './useConnectCrypto';

Expand All @@ -11,15 +10,6 @@ export function useRenown() {
const [renown, setRenown] = useAtom(renownAtom);
const { did } = useConnectCrypto();

useEffect(() => {
const query = new URLSearchParams(window.location.search);
const userStr = query.get('user');
if (userStr) {
const userDid = decodeURIComponent(userStr);
renown?.login(userDid).catch(console.error);
}
}, [renown]);

async function initRenown(
getDid: () => Promise<string>,
): Promise<IRenown | undefined> {
Expand Down
5 changes: 2 additions & 3 deletions src/services/renown/constants.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
export const RENOWN_URL =
(import.meta.env.VITE_RENOWN_URL as string) || 'http://localhost:3001';

export const EIP712VC_CHAIN_ID =
(import.meta.env.EIP712VC_CHAIN_ID as number) || 11155111;
export const RENOWN_NETWORK_ID =
(import.meta.env.VITE_RENOWN_NETWORK_ID as string) || '11155111';

export const DOMAIN_TYPE = [
{ name: 'name', type: 'string' },
Expand Down
37 changes: 22 additions & 15 deletions src/services/renown/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,30 @@ export class Renown {
}

async login(did: string): Promise<User> {
const result = parsePkhDid(did);
const credential = await this.#getCredential(
result.address,
result.chainId,
this.#connectId,
);
if (!credential) {
try {
const result = parsePkhDid(did);

const credential = await this.#getCredential(
result.address,
result.chainId,
this.#connectId,
);
if (!credential) {
this.#updateUser(undefined);
throw new Error('Credential not found');
}
const user: User = {
...result,
did,
credential,
};
this.#updateUser(user);
return user;
} catch (error) {
console.error(error);
this.#updateUser(undefined);
throw new Error('Credential not found');
throw error;
}
const user: User = {
...result,
did,
credential,
};
this.#updateUser(user);
return user;
}

logout() {
Expand Down
Loading

0 comments on commit 2917809

Please sign in to comment.