diff --git a/packages/app/.eslintrc.cjs b/packages/app/.eslintrc.cjs
index c3e0837b..3fc75e48 100644
--- a/packages/app/.eslintrc.cjs
+++ b/packages/app/.eslintrc.cjs
@@ -20,7 +20,16 @@ module.exports = {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"@typescript-eslint/no-unused-vars": "error",
+ "max-lines": ["warn", { max: 300, skipBlankLines: true, skipComments: true }],
},
+ overrides: [
+ {
+ files: ["*.tsx"],
+ rules: {
+ "max-lines": ["warn", { max: 200, skipBlankLines: true, skipComments: true }],
+ },
+ },
+ ],
root: true,
ignorePatterns: ["build/", "*.test.ts", "*.js"],
env: {
diff --git a/packages/app/src/Components/SendSats/SendSats.tsx b/packages/app/src/Components/SendSats/SendSats.tsx
index 182c6b99..e2a3adbc 100644
--- a/packages/app/src/Components/SendSats/SendSats.tsx
+++ b/packages/app/src/Components/SendSats/SendSats.tsx
@@ -3,30 +3,18 @@ import "./SendSats.css";
import { LNURLSuccessAction } from "@snort/shared";
import { HexKey } from "@snort/system";
import React, { ReactNode, useEffect, useState } from "react";
-import { FormattedMessage, useIntl } from "react-intl";
-import AsyncButton from "@/Components/Button/AsyncButton";
import CloseButton from "@/Components/Button/CloseButton";
-import Copy from "@/Components/Copy/Copy";
-import Icon from "@/Components/Icons/Icon";
import Modal from "@/Components/Modal/Modal";
-import QrCode from "@/Components/QrCode";
-import ProfileImage from "@/Components/User/ProfileImage";
+import { SendSatsInput, SendSatsInputSelection } from "@/Components/SendSats/SendSatsInput";
+import { SendSatsInvoice } from "@/Components/SendSats/SendSatsInvoice";
+import { SendSatsTitle } from "@/Components/SendSats/SendSatsTitle";
+import { SuccessAction } from "@/Components/SendSats/SuccessAction";
+import { ZapType } from "@/Components/SendSats/ZapType";
import useEventPublisher from "@/Hooks/useEventPublisher";
-import useLogin from "@/Hooks/useLogin";
import { debounce } from "@/Utils";
-import { formatShort } from "@/Utils/Number";
import { Zapper, ZapTarget, ZapTargetResult } from "@/Utils/Zapper";
-import { LNWallet, useWallet } from "@/Wallet";
-
-import messages from "../messages";
-
-enum ZapType {
- PublicZap = 1,
- AnonZap = 2,
- PrivateZap = 3,
- NonZap = 4,
-}
+import { useWallet } from "@/Wallet";
export interface SendSatsProps {
onClose?: () => void;
@@ -97,91 +85,14 @@ export default function SendSats(props: SendSatsProps) {
}
}, [props.targets, props.show]);
- function successAction() {
- if (!success) return null;
- return (
-
-
-
- {success?.description ?? }
-
- {success.url && (
-
-
- {success.url}
-
-
- )}
-
- );
- }
-
- function title() {
- if (!props.targets) {
- return (
- <>
-
- {zapper?.canZap() ? (
-
- ) : (
-
- )}
-
- >
- );
- }
- if (props.targets.length === 1 && props.targets[0].name) {
- const t = props.targets[0];
- const values = {
- name: t.name,
- };
- return (
- <>
- {t.zap?.pubkey && }
-
- {zapper?.canZap() ? (
-
- ) : (
-
- )}
-
- >
- );
- }
- if (props.targets.length > 1) {
- const total = props.targets.reduce((acc, v) => (acc += v.weight), 0);
-
- return (
-
-
- {zapper?.canZap() ? (
-
- ) : (
-
- )}
-
-
- {props.targets.map(v => (
-
- ))}
-
-
- );
- }
- }
-
if (!(props.show ?? false)) return null;
return (
-
{props.title || title()}
+
+ {props.title || }
+
{zapper && !invoice && (
@@ -227,180 +138,8 @@ export default function SendSats(props: SendSatsProps) {
}}
/>
)}
- {successAction()}
+ {success &&
}
);
}
-
-interface SendSatsInputSelection {
- amount: number;
- comment?: string;
- type: ZapType;
-}
-
-function SendSatsInput(props: {
- zapper: Zapper;
- onChange?: (v: SendSatsInputSelection) => void;
- onNextStage: (v: SendSatsInputSelection) => Promise;
-}) {
- const { defaultZapAmount, readonly } = useLogin(s => ({
- defaultZapAmount: s.appData.item.preferences.defaultZapAmount,
- readonly: s.readonly,
- }));
- const { formatMessage } = useIntl();
- const amounts: Record = {
- [defaultZapAmount.toString()]: "",
- "1000": "👍",
- "5000": "💜",
- "10000": "😍",
- "20000": "🤩",
- "50000": "🔥",
- "100000": "🚀",
- "1000000": "🤯",
- };
- const [comment, setComment] = useState();
- const [amount, setAmount] = useState(defaultZapAmount);
- const [customAmount, setCustomAmount] = useState(defaultZapAmount);
- const [zapType, setZapType] = useState(readonly ? ZapType.AnonZap : ZapType.PublicZap);
-
- function getValue() {
- return {
- amount,
- comment,
- type: zapType,
- } as SendSatsInputSelection;
- }
-
- useEffect(() => {
- if (props.onChange) {
- props.onChange(getValue());
- }
- }, [amount, comment, zapType]);
-
- function renderAmounts() {
- const min = props.zapper.minAmount() / 1000;
- const max = props.zapper.maxAmount() / 1000;
- const filteredAmounts = Object.entries(amounts).filter(([k]) => Number(k) >= min && Number(k) <= max);
-
- return (
-
- {filteredAmounts.map(([k, v]) => (
- setAmount(Number(k))}>
- {v}
- {k === "1000" ? "1K" : formatShort(Number(k))}
-
- ))}
-
- );
- }
-
- function custom() {
- const min = props.zapper.minAmount() / 1000;
- const max = props.zapper.maxAmount() / 1000;
-
- return (
-
- setCustomAmount(parseInt(e.target.value))}
- />
-
-
- );
- }
-
- return (
-
-
-
-
-
- {renderAmounts()}
- {custom()}
- {props.zapper.maxComment() > 0 && (
- setComment(e.target.value)}
- />
- )}
-
-
- {(amount ?? 0) > 0 && (
-
props.onNextStage(getValue())}>
-
-
-
- )}
-
- );
-}
-
-function SendSatsZapTypeSelector({ zapType, setZapType }: { zapType: ZapType; setZapType: (t: ZapType) => void }) {
- const { readonly } = useLogin(s => ({ readonly: s.readonly }));
- const makeTab = (t: ZapType, n: React.ReactNode) => (
-
- );
- return (
-
-
-
-
-
- {!readonly &&
- makeTab(ZapType.PublicZap, )}
- {/*makeTab(ZapType.PrivateZap, "Private")*/}
- {makeTab(ZapType.AnonZap, )}
- {makeTab(
- ZapType.NonZap,
- ,
- )}
-
-
- );
-}
-
-function SendSatsInvoice(props: {
- invoice: Array;
- wallet?: LNWallet;
- notice?: ReactNode;
- onInvoicePaid: () => void;
-}) {
- return (
-
- {props.notice &&
{props.notice}}
- {props.invoice.map(v => (
- <>
-
-
- >
- ))}
-
- );
-}
diff --git a/packages/app/src/Components/SendSats/SendSatsInput.tsx b/packages/app/src/Components/SendSats/SendSatsInput.tsx
new file mode 100644
index 00000000..04cf89bd
--- /dev/null
+++ b/packages/app/src/Components/SendSats/SendSatsInput.tsx
@@ -0,0 +1,131 @@
+import React, { useEffect, useState } from "react";
+import { FormattedMessage, useIntl } from "react-intl";
+
+import AsyncButton from "@/Components/Button/AsyncButton";
+import Icon from "@/Components/Icons/Icon";
+import messages from "@/Components/messages";
+import { SendSatsZapTypeSelector } from "@/Components/SendSats/SendSatsZapTypeSelector";
+import { ZapType } from "@/Components/SendSats/ZapType";
+import useLogin from "@/Hooks/useLogin";
+import { formatShort } from "@/Utils/Number";
+import { Zapper } from "@/Utils/Zapper";
+
+export interface SendSatsInputSelection {
+ amount: number;
+ comment?: string;
+ type: ZapType;
+}
+
+export function SendSatsInput(props: {
+ zapper: Zapper;
+ onChange?: (v: SendSatsInputSelection) => void;
+ onNextStage: (v: SendSatsInputSelection) => Promise;
+}) {
+ const { defaultZapAmount, readonly } = useLogin(s => ({
+ defaultZapAmount: s.appData.item.preferences.defaultZapAmount,
+ readonly: s.readonly,
+ }));
+ const { formatMessage } = useIntl();
+ const amounts: Record = {
+ [defaultZapAmount.toString()]: "",
+ "1000": "👍",
+ "5000": "💜",
+ "10000": "😍",
+ "20000": "🤩",
+ "50000": "🔥",
+ "100000": "🚀",
+ "1000000": "🤯",
+ };
+ const [comment, setComment] = useState();
+ const [amount, setAmount] = useState(defaultZapAmount);
+ const [customAmount, setCustomAmount] = useState(defaultZapAmount);
+ const [zapType, setZapType] = useState(readonly ? ZapType.AnonZap : ZapType.PublicZap);
+
+ function getValue() {
+ return {
+ amount,
+ comment,
+ type: zapType,
+ } as SendSatsInputSelection;
+ }
+
+ useEffect(() => {
+ if (props.onChange) {
+ props.onChange(getValue());
+ }
+ }, [amount, comment, zapType]);
+
+ function renderAmounts() {
+ const min = props.zapper.minAmount() / 1000;
+ const max = props.zapper.maxAmount() / 1000;
+ const filteredAmounts = Object.entries(amounts).filter(([k]) => Number(k) >= min && Number(k) <= max);
+
+ return (
+
+ {filteredAmounts.map(([k, v]) => (
+ setAmount(Number(k))}>
+ {v}
+ {k === "1000" ? "1K" : formatShort(Number(k))}
+
+ ))}
+
+ );
+ }
+
+ function custom() {
+ const min = props.zapper.minAmount() / 1000;
+ const max = props.zapper.maxAmount() / 1000;
+
+ return (
+
+ setCustomAmount(parseInt(e.target.value))}
+ />
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ {renderAmounts()}
+ {custom()}
+ {props.zapper.maxComment() > 0 && (
+ setComment(e.target.value)}
+ />
+ )}
+
+
+ {(amount ?? 0) > 0 && (
+
props.onNextStage(getValue())}>
+
+
+
+ )}
+
+ );
+}
diff --git a/packages/app/src/Components/SendSats/SendSatsInvoice.tsx b/packages/app/src/Components/SendSats/SendSatsInvoice.tsx
new file mode 100644
index 00000000..e4fa33fe
--- /dev/null
+++ b/packages/app/src/Components/SendSats/SendSatsInvoice.tsx
@@ -0,0 +1,33 @@
+import React, { ReactNode } from "react";
+import { FormattedMessage } from "react-intl";
+
+import Copy from "@/Components/Copy/Copy";
+import QrCode from "@/Components/QrCode";
+import { ZapTargetResult } from "@/Utils/Zapper";
+import { LNWallet } from "@/Wallet";
+
+export function SendSatsInvoice(props: {
+ invoice: Array;
+ wallet?: LNWallet;
+ notice?: ReactNode;
+ onInvoicePaid: () => void;
+}) {
+ return (
+
+ {props.notice &&
{props.notice}}
+ {props.invoice.map(v => (
+ <>
+
+
+ >
+ ))}
+
+ );
+}
diff --git a/packages/app/src/Components/SendSats/SendSatsTitle.tsx b/packages/app/src/Components/SendSats/SendSatsTitle.tsx
new file mode 100644
index 00000000..a6f94cce
--- /dev/null
+++ b/packages/app/src/Components/SendSats/SendSatsTitle.tsx
@@ -0,0 +1,75 @@
+import React from "react";
+import { FormattedMessage } from "react-intl";
+
+import { SendSatsInputSelection } from "@/Components/SendSats/SendSatsInput";
+import ProfileImage from "@/Components/User/ProfileImage";
+import { formatShort } from "@/Utils/Number";
+import { Zapper, ZapTarget } from "@/Utils/Zapper";
+
+export function SendSatsTitle({
+ targets,
+ zapper,
+ amount,
+}: {
+ targets?: Array;
+ zapper?: Zapper;
+ amount?: SendSatsInputSelection;
+}) {
+ if (!targets) {
+ return (
+ <>
+
+ {zapper?.canZap() ? (
+
+ ) : (
+
+ )}
+
+ >
+ );
+ }
+ if (targets.length === 1 && targets[0].name) {
+ const t = targets[0];
+ const values = {
+ name: t.name,
+ };
+ return (
+ <>
+ {t.zap?.pubkey && }
+
+ {zapper?.canZap() ? (
+
+ ) : (
+
+ )}
+
+ >
+ );
+ }
+ if (targets.length > 1) {
+ const total = targets.reduce((acc, v) => (acc += v.weight), 0);
+
+ return (
+
+
+ {zapper?.canZap() ? (
+
+ ) : (
+
+ )}
+
+
+ {targets.map(v => (
+
+ ))}
+
+
+ );
+ }
+}
diff --git a/packages/app/src/Components/SendSats/SendSatsZapTypeSelector.tsx b/packages/app/src/Components/SendSats/SendSatsZapTypeSelector.tsx
new file mode 100644
index 00000000..6a53d091
--- /dev/null
+++ b/packages/app/src/Components/SendSats/SendSatsZapTypeSelector.tsx
@@ -0,0 +1,37 @@
+import React from "react";
+import { FormattedMessage } from "react-intl";
+
+import { ZapType } from "@/Components/SendSats/ZapType";
+import useLogin from "@/Hooks/useLogin";
+
+export function SendSatsZapTypeSelector({
+ zapType,
+ setZapType,
+}: {
+ zapType: ZapType;
+ setZapType: (t: ZapType) => void;
+}) {
+ const { readonly } = useLogin(s => ({ readonly: s.readonly }));
+ const makeTab = (t: ZapType, n: React.ReactNode) => (
+
+ );
+ return (
+
+
+
+
+
+ {!readonly &&
+ makeTab(ZapType.PublicZap, )}
+ {/*makeTab(ZapType.PrivateZap, "Private")*/}
+ {makeTab(ZapType.AnonZap, )}
+ {makeTab(
+ ZapType.NonZap,
+ ,
+ )}
+
+
+ );
+}
diff --git a/packages/app/src/Components/SendSats/SuccessAction.tsx b/packages/app/src/Components/SendSats/SuccessAction.tsx
new file mode 100644
index 00000000..dde49de8
--- /dev/null
+++ b/packages/app/src/Components/SendSats/SuccessAction.tsx
@@ -0,0 +1,23 @@
+import { LNURLSuccessAction } from "@snort/shared";
+import React from "react";
+import { FormattedMessage } from "react-intl";
+
+import Icon from "@/Components/Icons/Icon";
+
+export function SuccessAction({ success }: { success: LNURLSuccessAction }) {
+ return (
+
+
+
+ {success?.description ?? }
+
+ {success.url && (
+
+
+ {success.url}
+
+
+ )}
+
+ );
+}
diff --git a/packages/app/src/Components/SendSats/ZapType.tsx b/packages/app/src/Components/SendSats/ZapType.tsx
new file mode 100644
index 00000000..de048fc7
--- /dev/null
+++ b/packages/app/src/Components/SendSats/ZapType.tsx
@@ -0,0 +1,6 @@
+export enum ZapType {
+ PublicZap = 1,
+ AnonZap = 2,
+ PrivateZap = 3,
+ NonZap = 4,
+}
diff --git a/packages/app/src/Components/User/AnimalName.ts b/packages/app/src/Components/User/AnimalName.ts
index 6b08e55d..db792d6a 100644
--- a/packages/app/src/Components/User/AnimalName.ts
+++ b/packages/app/src/Components/User/AnimalName.ts
@@ -1,3 +1,5 @@
+/* eslint-disable max-lines */
+
import { sha256 } from "@noble/hashes/sha256";
const animals = [