reorganize code into smaller files & dirs
This commit is contained in:
53
packages/app/src/Components/Tasks/BackupKey.tsx
Normal file
53
packages/app/src/Components/Tasks/BackupKey.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
import { BaseUITask } from "@/Components/Tasks/index";
|
||||
import { MetadataCache } from "@snort/system";
|
||||
import { LoginSession } from "@/Utils/Login";
|
||||
import Icon from "@/Components/Icons/Icon";
|
||||
|
||||
export class BackupKeyTask extends BaseUITask {
|
||||
id = "backup-key";
|
||||
noBaseStyle = true;
|
||||
|
||||
check(_: MetadataCache, session: LoginSession): boolean {
|
||||
return !this.state.muted && session.type == "private_key";
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="p card">
|
||||
<div className="flex g12 bg-superdark p24 br">
|
||||
<div>
|
||||
<div className="p12 bg-dark circle">
|
||||
<Icon name="key" size={21} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col g8">
|
||||
<div className="font-semibold text-xl">
|
||||
<FormattedMessage defaultMessage="Be sure to back up your keys!" id="1UWegE" />
|
||||
</div>
|
||||
<small>
|
||||
<FormattedMessage
|
||||
defaultMessage="No keys, no {app}, There is no way to reset it if you don't back up. It only takes a minute."
|
||||
id="YR2I9M"
|
||||
values={{
|
||||
app: CONFIG.appNameCapitalized,
|
||||
}}
|
||||
/>
|
||||
</small>
|
||||
<div className="flex g8">
|
||||
<Link to="/settings/keys">
|
||||
<button>
|
||||
<FormattedMessage defaultMessage="Back up now" id="rMgF34" />
|
||||
</button>
|
||||
</Link>
|
||||
<button className="secondary" onClick={() => this.mute()}>
|
||||
<FormattedMessage defaultMessage="Already backed up" id="j9xbzF" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
30
packages/app/src/Components/Tasks/DonateTask.tsx
Normal file
30
packages/app/src/Components/Tasks/DonateTask.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
import { BaseUITask } from "@/Components/Tasks/index";
|
||||
|
||||
export class DonateTask extends BaseUITask {
|
||||
id = "donate";
|
||||
|
||||
check(): boolean {
|
||||
return !this.state.muted;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Thanks for using {site}, please consider donating if you can."
|
||||
id="fBlba3"
|
||||
values={{ site: CONFIG.appNameCapitalized }}
|
||||
/>
|
||||
</p>
|
||||
<Link to="/donate">
|
||||
<button>
|
||||
<FormattedMessage defaultMessage="Donate" id="2IFGap" />
|
||||
</button>
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
30
packages/app/src/Components/Tasks/Nip5Task.tsx
Normal file
30
packages/app/src/Components/Tasks/Nip5Task.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
import { MetadataCache } from "@snort/system";
|
||||
import { BaseUITask } from "@/Components/Tasks/index";
|
||||
|
||||
export class Nip5Task extends BaseUITask {
|
||||
id = "buy-nip5";
|
||||
|
||||
check(user: MetadataCache): boolean {
|
||||
return !this.state.muted && !user.nip05;
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Hey, it looks like you dont have a Nostr Address yet, you should get one! Check out {link}"
|
||||
id="ojzbwv"
|
||||
values={{
|
||||
link: (
|
||||
<Link to="/nostr-address">
|
||||
<FormattedMessage defaultMessage="Buy nostr address" id="MuVeKe" />
|
||||
</Link>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
}
|
39
packages/app/src/Components/Tasks/NoticeZapPool.tsx
Normal file
39
packages/app/src/Components/Tasks/NoticeZapPool.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { FormattedMessage, FormattedNumber } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
import { BaseUITask } from "@/Components/Tasks/index";
|
||||
|
||||
export class NoticeZapPoolDefault extends BaseUITask {
|
||||
id = "zap-pool-default";
|
||||
|
||||
check(): boolean {
|
||||
return !this.state.muted && CONFIG.defaultZapPoolFee !== undefined;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="A default Zap Pool split of {n} has been configured for {site} developers, you can disable it at any time in {link}"
|
||||
id="dmsiLv"
|
||||
values={{
|
||||
site: CONFIG.appNameCapitalized,
|
||||
n: (
|
||||
<FormattedNumber
|
||||
value={(CONFIG.defaultZapPoolFee ?? 0) / 100}
|
||||
style="percent"
|
||||
maximumFractionDigits={2}
|
||||
/>
|
||||
),
|
||||
link: (
|
||||
<Link to="/zap-pool">
|
||||
<FormattedMessage defaultMessage="Zap Pool" id="i/dBAR" />
|
||||
</Link>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
33
packages/app/src/Components/Tasks/RenewSubscription.tsx
Normal file
33
packages/app/src/Components/Tasks/RenewSubscription.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { MetadataCache } from "@snort/system";
|
||||
|
||||
import { BaseUITask } from "@/Components/Tasks/index";
|
||||
import { LoginSession } from "@/Utils/Login";
|
||||
import { getCurrentSubscription } from "@/Utils/Subscription";
|
||||
import { RenewSub } from "@/Pages/subscribe/RenewSub";
|
||||
|
||||
export class RenewSubTask extends BaseUITask {
|
||||
id = "renew-sub";
|
||||
|
||||
check(user: MetadataCache, session: LoginSession): boolean {
|
||||
const sub = getCurrentSubscription(session.subscriptions);
|
||||
return !sub && session.subscriptions.length > 0;
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
defaultMessage="Your {site_name} subscription is expired"
|
||||
id="jAmfGl"
|
||||
values={{
|
||||
site_name: CONFIG.appName,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<RenewSub />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
3
packages/app/src/Components/Tasks/TaskList.css
Normal file
3
packages/app/src/Components/Tasks/TaskList.css
Normal file
@ -0,0 +1,3 @@
|
||||
.task-list a {
|
||||
text-decoration: underline;
|
||||
}
|
72
packages/app/src/Components/Tasks/TaskList.tsx
Normal file
72
packages/app/src/Components/Tasks/TaskList.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import "./TaskList.css";
|
||||
import { Fragment, useSyncExternalStore } from "react";
|
||||
import { useUserProfile } from "@snort/system-react";
|
||||
|
||||
import useLogin from "@/Hooks/useLogin";
|
||||
import Icon from "@/Components/Icons/Icon";
|
||||
import { UITask } from "@/Components/Tasks/index";
|
||||
import { DonateTask } from "./DonateTask";
|
||||
import { Nip5Task } from "./Nip5Task";
|
||||
import { RenewSubTask } from "./RenewSubscription";
|
||||
import { NoticeZapPoolDefault } from "./NoticeZapPool";
|
||||
import { BackupKeyTask } from "./BackupKey";
|
||||
import { ExternalStore } from "@snort/shared";
|
||||
import CloseButton from "@/Components/Button/CloseButton";
|
||||
|
||||
class TaskStore extends ExternalStore<Array<UITask>> {
|
||||
#tasks: Array<UITask>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
const AllTasks: Array<UITask> = [new BackupKeyTask(), new Nip5Task(), new DonateTask(), new NoticeZapPoolDefault()];
|
||||
if (CONFIG.features.subscriptions) {
|
||||
AllTasks.push(new RenewSubTask());
|
||||
}
|
||||
AllTasks.forEach(a =>
|
||||
a.load(() => {
|
||||
this.notifyChange();
|
||||
}),
|
||||
);
|
||||
this.#tasks = AllTasks;
|
||||
}
|
||||
|
||||
takeSnapshot(): UITask[] {
|
||||
return [...this.#tasks];
|
||||
}
|
||||
}
|
||||
|
||||
const AllTasks = new TaskStore();
|
||||
export const TaskList = () => {
|
||||
const session = useLogin();
|
||||
const user = useUserProfile(session.publicKey);
|
||||
const tasks = useSyncExternalStore(
|
||||
c => AllTasks.hook(c),
|
||||
() => AllTasks.snapshot(),
|
||||
);
|
||||
|
||||
function muteTask(t: UITask) {
|
||||
t.mute();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="task-list">
|
||||
{tasks
|
||||
.filter(a => (user ? a.check(user, session) : false))
|
||||
.map(a => {
|
||||
if (a.noBaseStyle) {
|
||||
return <Fragment key={a.id}>{a.render()}</Fragment>;
|
||||
} else {
|
||||
return (
|
||||
<div key={a.id} className="card">
|
||||
<div className="header">
|
||||
<Icon name="lightbulb" />
|
||||
<CloseButton onClick={() => muteTask(a)} />
|
||||
</div>
|
||||
{a.render()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
52
packages/app/src/Components/Tasks/index.ts
Normal file
52
packages/app/src/Components/Tasks/index.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { MetadataCache } from "@snort/system";
|
||||
import { LoginSession } from "@/Utils/Login";
|
||||
|
||||
export interface UITask {
|
||||
id: string;
|
||||
noBaseStyle: boolean;
|
||||
/**
|
||||
* Run checks to determine if this Task should be triggered for this user
|
||||
*/
|
||||
check(user: MetadataCache, session: LoginSession): boolean;
|
||||
mute(): void;
|
||||
load(cb: () => void): void;
|
||||
render(): JSX.Element;
|
||||
}
|
||||
|
||||
export interface UITaskState {
|
||||
id: string;
|
||||
muted: boolean;
|
||||
completed: boolean;
|
||||
}
|
||||
|
||||
export abstract class BaseUITask implements UITask {
|
||||
#cb?: () => void;
|
||||
protected state: UITaskState;
|
||||
|
||||
abstract id: string;
|
||||
noBaseStyle = false;
|
||||
abstract check(user: MetadataCache, session: LoginSession): boolean;
|
||||
abstract render(): JSX.Element;
|
||||
|
||||
constructor() {
|
||||
this.state = {} as UITaskState;
|
||||
}
|
||||
|
||||
mute(): void {
|
||||
this.state.muted = true;
|
||||
this.#save();
|
||||
}
|
||||
|
||||
load(cb: () => void) {
|
||||
this.#cb = cb;
|
||||
const state = window.localStorage.getItem(`task:${this.id}`);
|
||||
if (state) {
|
||||
this.state = JSON.parse(state);
|
||||
}
|
||||
}
|
||||
|
||||
#save() {
|
||||
window.localStorage.setItem(`task:${this.id}`, JSON.stringify(this.state));
|
||||
this.#cb?.();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user