mirror of
https://github.com/BlowaterNostr/blowater.git
synced 2024-10-18 23:43:23 +00:00
248 lines
8.1 KiB
TypeScript
248 lines
8.1 KiB
TypeScript
/** @jsx h */
|
|
import { h } from "https://esm.sh/preact@10.11.3";
|
|
import { tw } from "https://esm.sh/twind@0.16.16";
|
|
import { AlbyAccountContext, GetLocalStorageAccountContext } from "./account-context.ts";
|
|
import { ButtonClass, CenterClass, DividerClass } from "./components/tw.ts";
|
|
import KeyView from "./key-view.tsx";
|
|
import { PrivateKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/key.ts";
|
|
import {
|
|
InMemoryAccountContext,
|
|
NostrAccountContext,
|
|
} from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/nostr.ts";
|
|
import { EventBus, EventEmitter } from "../event-bus.ts";
|
|
|
|
export type SignInEvent = {
|
|
type: "signin";
|
|
privateKey?: PrivateKey; // undefined means sign in with extentions
|
|
} | {
|
|
type: "editSignInPrivateKey";
|
|
privateKey: string;
|
|
} | {
|
|
type: "createNewAccount";
|
|
} | {
|
|
type: "backToSignInPage";
|
|
};
|
|
|
|
type Props = {
|
|
eventBus: EventEmitter<SignInEvent>;
|
|
} & SignInModel;
|
|
|
|
export type SignInModel = {
|
|
state: "newAccount" | "enterPrivateKey";
|
|
privateKey: string;
|
|
warningString?: string;
|
|
};
|
|
|
|
const AlbyURL = "https://getalby.com/";
|
|
|
|
type SignInState = "none" | "nip07" | "local";
|
|
|
|
export function getSignInState(): SignInState {
|
|
const state = localStorage.getItem("SignInState");
|
|
if (state === null) {
|
|
return "none";
|
|
}
|
|
return state as SignInState;
|
|
}
|
|
|
|
export function setSignInState(state: SignInState) {
|
|
localStorage.setItem("SignInState", state);
|
|
}
|
|
|
|
////////////////////////
|
|
// Check Login Status //
|
|
////////////////////////
|
|
export async function signIn() {
|
|
if (getSignInState() === "nip07") {
|
|
const albyCtx = await AlbyAccountContext.New();
|
|
if (albyCtx instanceof Error) {
|
|
throw albyCtx;
|
|
}
|
|
if (albyCtx === undefined) {
|
|
setSignInState("none");
|
|
}
|
|
return albyCtx;
|
|
}
|
|
if (getSignInState() === "local") {
|
|
const ctx = GetLocalStorageAccountContext();
|
|
if (ctx instanceof Error) {
|
|
throw ctx;
|
|
}
|
|
if (ctx === undefined) {
|
|
console.log("GetLocalStorageAccountContext is undefined");
|
|
setSignInState("none");
|
|
}
|
|
return ctx;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export async function signInWithExtension() {
|
|
const albyCtx = await AlbyAccountContext.New();
|
|
if (albyCtx instanceof Error) {
|
|
return albyCtx;
|
|
}
|
|
if (albyCtx === undefined) {
|
|
open(AlbyURL);
|
|
} else {
|
|
try {
|
|
const enabled = await albyCtx.enable();
|
|
if (enabled) {
|
|
setSignInState("nip07");
|
|
} else {
|
|
console.error("User rejected Alby login");
|
|
}
|
|
} catch (e) {
|
|
console.log(e);
|
|
return "You rejected Alby login. Refresh page to enable it again.";
|
|
}
|
|
}
|
|
return albyCtx;
|
|
}
|
|
|
|
export function signInWithPrivateKey(privateKey: PrivateKey) {
|
|
const ctx = InMemoryAccountContext.New(privateKey);
|
|
if (ctx instanceof Error) {
|
|
throw ctx;
|
|
}
|
|
localStorage.setItem("MPK", privateKey.hex);
|
|
setSignInState("local");
|
|
return ctx;
|
|
}
|
|
|
|
export function SignIn(props: Props) {
|
|
if (props.state == "newAccount") {
|
|
const privateKey = PrivateKey.Generate();
|
|
return (
|
|
<div
|
|
class={tw`fixed inset-0 bg-[#313338] flex items-center justify-center px-4`}
|
|
>
|
|
<div class={tw`flex flex-col w-[40rem]`}>
|
|
<KeyView
|
|
privateKey={privateKey}
|
|
publicKey={privateKey.toPublicKey()}
|
|
/>
|
|
<button
|
|
onClick={() => {
|
|
props.eventBus.emit({
|
|
type: "backToSignInPage",
|
|
});
|
|
}}
|
|
class={tw`w-full mt-8 bg-[#404249] hover:bg-[#2B2D31] ${ButtonClass}`}
|
|
>
|
|
Back
|
|
</button>
|
|
<button
|
|
onClick={() => {
|
|
props.eventBus.emit({
|
|
type: "signin",
|
|
privateKey: privateKey,
|
|
});
|
|
}}
|
|
class={tw`w-full mt-8 bg-[#ED4545] hover:bg-[#E03030] ${ButtonClass}`}
|
|
>
|
|
Signup
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
let privateKey = PrivateKey.FromHex(props.privateKey);
|
|
if (privateKey instanceof Error) {
|
|
privateKey = PrivateKey.FromBech32(props.privateKey);
|
|
}
|
|
|
|
return (
|
|
<div
|
|
class={tw`fixed inset-0 bg-[#313338] flex items-center justify-center px-4`}
|
|
>
|
|
<div class={tw`w-[40rem] relative`}>
|
|
<img
|
|
class={tw`w-40 h-40 m-auto mb-16 absolute`}
|
|
style={{
|
|
top: "-12rem",
|
|
left: "calc(50% - 5rem)",
|
|
}}
|
|
src="logo.png"
|
|
alt="Logo"
|
|
/>
|
|
<h1
|
|
class={tw`text-[#F3F4EA] text-center text-[2rem]`}
|
|
>
|
|
Welcome to Blowater
|
|
</h1>
|
|
<input
|
|
onInput={(e) => {
|
|
props.eventBus.emit({
|
|
type: "editSignInPrivateKey",
|
|
privateKey: e.currentTarget.value,
|
|
});
|
|
}}
|
|
placeholder="Input your private key here"
|
|
type="text"
|
|
class={tw`w-full px-4 py-2 focus-visible:outline-none rounded-lg mt-8`}
|
|
/>
|
|
{privateKey instanceof Error
|
|
? (
|
|
<p class={tw`text-[#F3F4EA] mt-2`}>
|
|
Private Key has to be 64 letters hex-decimal or 63 letters nsec string
|
|
</p>
|
|
)
|
|
: undefined}
|
|
<button
|
|
onClick={() => {
|
|
if (privateKey instanceof PrivateKey) {
|
|
props.eventBus.emit({
|
|
type: "signin",
|
|
privateKey: privateKey,
|
|
});
|
|
}
|
|
}}
|
|
disabled={privateKey instanceof Error}
|
|
class={tw`w-full bg-[#2B2D31] hover:bg-[#404249] mt-4 disabled:bg-[#404249] ${ButtonClass}`}
|
|
>
|
|
Sign In
|
|
</button>
|
|
|
|
<div class={tw`h-16 w-full relative ${CenterClass}`}>
|
|
<div class={tw`${DividerClass}`}></div>
|
|
<div class={tw`absolute w-full h-full ${CenterClass}`}>
|
|
<span class={tw`bg-[#313338] px-2 text-[#F3F4EA]`}>Or you can</span>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
onClick={() => {
|
|
props.eventBus.emit({
|
|
type: "signin",
|
|
});
|
|
}}
|
|
class={tw`${ButtonClass} ${CenterClass} w-full bg-[#F8C455] text-[#313338] hover:bg-[#FFDF6F] py-0`}
|
|
>
|
|
<img
|
|
class={tw`h-10`}
|
|
src="alby-logo.svg"
|
|
alt="Alby Logo"
|
|
/>
|
|
Sign in with Alby
|
|
</button>
|
|
<button
|
|
onClick={() => {
|
|
props.eventBus.emit({
|
|
type: "createNewAccount",
|
|
});
|
|
}}
|
|
class={tw`${ButtonClass} w-full bg-[#2B2D31] hover:bg-[#404249] mt-4`}
|
|
>
|
|
Create an account
|
|
</button>
|
|
|
|
{props.warningString
|
|
? <p class={tw`text-[#F3F4EA] mt-2`}>{props.warningString}</p>
|
|
: undefined}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|