Skip to content
This repository has been archived by the owner on Oct 13, 2023. It is now read-only.

Commit

Permalink
add provider
Browse files Browse the repository at this point in the history
  • Loading branch information
Vadim committed Dec 12, 2022
1 parent 181016f commit cfa0b01
Show file tree
Hide file tree
Showing 8 changed files with 1,944 additions and 367 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
"@types/node": "^16.7.13",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"i": "^0.3.7",
"npm": "^9.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typed-ts-events": "^1.2.1",
"typescript": "^4.4.2",
"web-vitals": "^2.1.0"
},
Expand Down
707 changes: 369 additions & 338 deletions src/App.tsx

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/Signer/Signer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export class Signer {

}
33 changes: 33 additions & 0 deletions src/Signer/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export interface UserData {
name: string;
addressByIndex: string;
}

export interface Provider {
user: UserData | null;

on<EVENT extends keyof AuthEvents>(
event: EVENT,
handler: Handler<AuthEvents[EVENT]>
): Provider;

once<EVENT extends keyof AuthEvents>(
event: EVENT,
handler: Handler<AuthEvents[EVENT]>
): Provider;

off<EVENT extends keyof AuthEvents>(
event: EVENT,
handler: Handler<AuthEvents[EVENT]>
): Provider;
/**
* Logs in user using provider
*/
login(): Promise<UserData>;
}
export type Handler<T> = (data: T) => any;

export type AuthEvents = {
login: Readonly<UserData>;
logout: void;
};
57 changes: 57 additions & 0 deletions src/components/Tab/Button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { ReactElement, useMemo } from 'react';

type ButtonProps = {
title: string | ReactElement;
disabled?: boolean;
mode: 'gradient' | 'icon_transparent' | 'transparent';
className?: string;
iconLeft?: JSX.Element;
iconRight?: JSX.Element;
onClick?: () => void;
};

export const Button: React.FC<ButtonProps> = ({
mode,
title,
disabled,
className,
iconLeft,
iconRight,
onClick,
}) => {
const cn = useMemo(() => {
if (mode === 'gradient' && !disabled)
return `w-[100%] button_gradient text-white text_button ext:py-[7px] tablet:py-[14px] rounded-[15px] ${className}`;

if (mode === 'gradient' && disabled)
return `w-[100%] button_gradient_disabled text-white-0.3 text_button ext:py-[7px] tablet:py-[14px] rounded-[15px] ${className}`;

if (mode === 'transparent' && !disabled)
return `w-[100%] bg-brown text-white text_button border-[1px] border-solid border-dark_grey ext:py-[7px] tablet:py-[14px] rounded-[15px]
hover:bg-gradient-to-r hover:from-[rgba(139,228,217,0.15)] hover:to-[rgba(255,144,47,0.15]
${className}`;

if (mode === 'transparent' && disabled)
return `w-[100%] bg-brown text-light_brown text_button border-[1px] border-solid border-dark_grey ext:py-[7px] tablet:py-[14px] rounded-[15px]
${className}`;
}, [className, mode, disabled]);

if (mode === 'icon_transparent')
return (
<button
disabled={disabled}
onClick={onClick}
className={`flex text_button items-center justify-center text-light_grey ${className}`}
>
<span>{iconLeft}</span>
<span>{title}</span>
{iconRight && <span className="ml-[6px]">{iconRight}</span>}
</button>
);

return (
<button disabled={disabled} onClick={onClick} className={`${cn}`}>
{title}
</button>
);
};
21 changes: 20 additions & 1 deletion src/types/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,28 @@ declare global {
}
}

declare namespace Penumbra {
export declare namespace Penumbra {
type TPenumbraApi = {
/**
* If a website is trusted, Penumbra public data are returned.
*/
publicState(): Promise<IPublicStateResponse>;
/**
* On initialize window.penumbra has no api methods.
* You can use penumbra.initialPromise for waiting end initializing api
*/
initialPromise: Promise<any>;

/**
* Allows subscribing to Waves Keeper events.
* If a website is not trusted, events won't show.
* @param event
* Supports events:
* update – subscribe to updates of the state
* @param cb
*/
on(event: 'update', cb: (state: IPublicStateResponse) => any): object;

getAssets(): Promise<TAsset[]>;
getChainParameters(): Promise<string>;
getNotes(): Promise<TNote[]>;
Expand Down
83 changes: 71 additions & 12 deletions src/utils/ProviderPenumbra.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,80 @@
export interface UserData {
address: string;
publicKey: string;
}

interface Provider {
user: UserData | null;
}
import { AuthEvents, Handler, Provider, UserData } from '../Signer/types';
import { Penumbra } from '../types/globals';
import { EventEmitter } from 'typed-ts-events';

export class ProviderPenumbra implements Provider {
public user: UserData | null = null;
// protected _apiPromise: Promise<WavesKeeper.TWavesKeeperApi>;
protected _apiPromise: Promise<Penumbra.TPenumbraApi>;
protected _connectPromise: Promise<void>; // used in _ensureApi
private _connectResolve!: () => void; // initialized in Promise constructor

private readonly _emitter: EventEmitter<AuthEvents> =
new EventEmitter<AuthEvents>();

constructor() {
// this._apiPromise = isPenumbraInstalled();
this._apiPromise = isPenumbraInstalled().then((isInstalled) => {
return isInstalled
? window.penumbra.initialPromise.then((api) => Promise.resolve(api))
: Promise.reject(new Error('WavesKeeper is not installed.'));
});

this._apiPromise.catch(() => {
// avoid unhandled rejection
});

this._connectPromise = new Promise((resolve) => {
this._connectResolve = resolve;
});
}
}

public on<EVENT extends keyof AuthEvents>(
event: EVENT,
handler: Handler<AuthEvents[EVENT]>
): Provider {
this._emitter.on(event, handler);

return this;
}

public once<EVENT extends keyof AuthEvents>(
event: EVENT,
handler: Handler<AuthEvents[EVENT]>
): Provider {
this._emitter.once(event, handler);

return this;
}

public off<EVENT extends keyof AuthEvents>(
event: EVENT,
handler: Handler<AuthEvents[EVENT]>
): Provider {
this._emitter.off(event, handler);

return this;
}

public login(): Promise<UserData> {
return this._apiPromise
.then((api) => api.publicState())
.then((state) => {
// in this case we already have state.account,
// otherwise api.publicState will throw an error
this.user = {
name: state.account?.name!,
addressByIndex: state.account?.addressByIndex!,
};
this._emitter.trigger('login', this.user);
return this.user;
});
}

public logout(): Promise<void> {
this.user = null;
this._emitter.trigger('logout', void 0);
return Promise.resolve();
}
}

const poll = (
resolve: (result: boolean) => void,
Expand All @@ -35,4 +94,4 @@ const _isPenumbraInstalled = new Promise(poll);

export async function isPenumbraInstalled() {
return _isPenumbraInstalled;
}
}
Loading

0 comments on commit cfa0b01

Please sign in to comment.