reorganize code into smaller files & dirs

This commit is contained in:
Martti Malmi
2024-01-04 15:48:19 +02:00
parent 5ea2eb711f
commit afa6d39a56
321 changed files with 671 additions and 671 deletions

View 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>
);
}
}

View 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>
</>
);
}
}

View 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>
);
}
}

View 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>
</>
);
}
}

View 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 />
</>
);
}
}

View File

@ -0,0 +1,3 @@
.task-list a {
text-decoration: underline;
}

View 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>
);
};

View 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?.();
}
}