Bugfixes
This commit is contained in:
@ -81,8 +81,8 @@ export default function CashuNuts({ token }: { token: string }) {
|
||||
x2="7.11501"
|
||||
y2="6.7213"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||
<stop stopColor="white" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_1976_19241"
|
||||
@ -91,8 +91,8 @@ export default function CashuNuts({ token }: { token: string }) {
|
||||
x2="7.11501"
|
||||
y2="32.2311"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||
<stop stopColor="white" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear_1976_19241"
|
||||
@ -101,8 +101,8 @@ export default function CashuNuts({ token }: { token: string }) {
|
||||
x2="22.2658"
|
||||
y2="19.4576"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white" />
|
||||
<stop offset="1" stop-color="white" stop-opacity="0.5" />
|
||||
<stop stopColor="white" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.5" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import "./Modal.css";
|
||||
import { ReactNode } from "react";
|
||||
import { ReactNode, useEffect } from "react";
|
||||
|
||||
export interface ModalProps {
|
||||
id: string;
|
||||
@ -9,6 +9,11 @@ export interface ModalProps {
|
||||
}
|
||||
|
||||
export default function Modal(props: ModalProps) {
|
||||
useEffect(() => {
|
||||
document.body.classList.add("scroll-lock");
|
||||
return () => document.body.classList.remove("scroll-lock");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={`modal${props.className ? ` ${props.className}` : ""}`} onClick={props.onClose}>
|
||||
<div className="modal-body" onClick={e => e.stopPropagation()}>
|
||||
|
@ -52,7 +52,7 @@ export default function NoteFooter(props: NoteFooterProps) {
|
||||
const author = useUserProfile(ev.pubkey);
|
||||
const interactionCache = useInteractionCache(publicKey, ev.id);
|
||||
const publisher = useEventPublisher();
|
||||
const note = useNoteCreator();
|
||||
const note = useNoteCreator(n => ({ show: n.show, replyTo: n.replyTo, update: n.update }));
|
||||
const willRenderNoteCreator = note.show && note.replyTo?.id === ev.id;
|
||||
const [tip, setTip] = useState(false);
|
||||
const [zapping, setZapping] = useState(false);
|
||||
@ -263,7 +263,7 @@ export default function NoteFooter(props: NoteFooterProps) {
|
||||
{tipButton()}
|
||||
{powIcon()}
|
||||
</div>
|
||||
{willRenderNoteCreator && <NoteCreator />}
|
||||
{willRenderNoteCreator && <NoteCreator key={`note-creator-${ev.id}`} />}
|
||||
<SendSats targets={getZapTarget()} onClose={() => setTip(false)} show={tip} note={ev.id} allocatePool={true} />
|
||||
</div>
|
||||
<ZapsSummary zaps={zaps} />
|
||||
|
@ -68,7 +68,10 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
||||
}
|
||||
|
||||
getSessions() {
|
||||
return [...this.#accounts.values()].map(v => unwrap(v.publicKey));
|
||||
return [...this.#accounts.values()].map(v => ({
|
||||
pubkey: unwrap(v.publicKey),
|
||||
id: v.id,
|
||||
}));
|
||||
}
|
||||
|
||||
allSubscriptions() {
|
||||
|
@ -25,19 +25,12 @@ import { LoginUnlock } from "Element/PinPrompt";
|
||||
|
||||
export default function Layout() {
|
||||
const location = useLocation();
|
||||
const note = useNoteCreator();
|
||||
const isReplyNoteCreatorShowing = note.replyTo && note.show;
|
||||
const [pageClass, setPageClass] = useState("page");
|
||||
|
||||
useLoginFeed();
|
||||
useTheme();
|
||||
useLoginRelays();
|
||||
|
||||
const shouldHideNoteCreator = useMemo(() => {
|
||||
const hideOn = ["/settings", "/messages", "/new", "/login", "/donate", "/e", "/subscribe"];
|
||||
return isReplyNoteCreatorShowing || hideOn.some(a => location.pathname.startsWith(a));
|
||||
}, [location, isReplyNoteCreatorShowing]);
|
||||
|
||||
const shouldHideHeader = useMemo(() => {
|
||||
const hideOn = ["/login", "/new"];
|
||||
return hideOn.some(a => location.pathname.startsWith(a));
|
||||
@ -63,21 +56,7 @@ export default function Layout() {
|
||||
</header>
|
||||
)}
|
||||
<Outlet />
|
||||
{!shouldHideNoteCreator && (
|
||||
<>
|
||||
<button
|
||||
className="primary note-create-button"
|
||||
onClick={() =>
|
||||
note.update(v => {
|
||||
v.replyTo = undefined;
|
||||
v.show = true;
|
||||
})
|
||||
}>
|
||||
<Icon name="plus" size={16} />
|
||||
</button>
|
||||
<NoteCreator />
|
||||
</>
|
||||
)}
|
||||
<NoteCreatorButton />
|
||||
<Toaster />
|
||||
</div>
|
||||
<LoginUnlock />
|
||||
@ -85,6 +64,34 @@ export default function Layout() {
|
||||
);
|
||||
}
|
||||
|
||||
const NoteCreatorButton = () => {
|
||||
const location = useLocation();
|
||||
const { show, replyTo, update } = useNoteCreator(v => ({ show: v.show, replyTo: v.replyTo, update: v.update }));
|
||||
|
||||
const shouldHideNoteCreator = useMemo(() => {
|
||||
const isReplyNoteCreatorShowing = replyTo && show;
|
||||
const hideOn = ["/settings", "/messages", "/new", "/login", "/donate", "/e", "/subscribe"];
|
||||
return isReplyNoteCreatorShowing || hideOn.some(a => location.pathname.startsWith(a));
|
||||
}, [location]);
|
||||
|
||||
if (shouldHideNoteCreator) return;
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="primary note-create-button"
|
||||
onClick={() =>
|
||||
update(v => {
|
||||
v.replyTo = undefined;
|
||||
v.show = true;
|
||||
})
|
||||
}>
|
||||
<Icon name="plus" size={16} />
|
||||
</button>
|
||||
<NoteCreator key="global-note-creator" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const AccountHeader = () => {
|
||||
const navigate = useNavigate();
|
||||
const { formatMessage } = useIntl();
|
||||
|
@ -1,57 +1,32 @@
|
||||
import { useState } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import ProfilePreview from "Element/ProfilePreview";
|
||||
import { LoginStore } from "Login";
|
||||
import useLoginHandler from "Hooks/useLoginHandler";
|
||||
import AsyncButton from "Element/AsyncButton";
|
||||
import { getActiveSubscriptions } from "Subscription";
|
||||
|
||||
export default function AccountsPage() {
|
||||
const { formatMessage } = useIntl();
|
||||
const [key, setKey] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const loginHandler = useLoginHandler();
|
||||
const logins = LoginStore.getSessions();
|
||||
const sub = getActiveSubscriptions(LoginStore.allSubscriptions());
|
||||
|
||||
async function doLogin() {
|
||||
try {
|
||||
setError("");
|
||||
await loginHandler.doLogin(key);
|
||||
setKey("");
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
setError(e.message);
|
||||
} else {
|
||||
setError(
|
||||
formatMessage({
|
||||
defaultMessage: "Unknown login error",
|
||||
}),
|
||||
);
|
||||
}
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex-column g12">
|
||||
<h3>
|
||||
<FormattedMessage defaultMessage="Logins" />
|
||||
</h3>
|
||||
{logins.map(a => (
|
||||
<div className="card flex" key={a}>
|
||||
<div className="card flex" key={a.id}>
|
||||
<ProfilePreview
|
||||
pubkey={a}
|
||||
pubkey={a.pubkey}
|
||||
options={{
|
||||
about: false,
|
||||
}}
|
||||
actions={
|
||||
<div className="f-1">
|
||||
<button className="mb10" onClick={() => LoginStore.switchAccount(a)}>
|
||||
<button className="mb10" onClick={() => LoginStore.switchAccount(a.id)}>
|
||||
<FormattedMessage defaultMessage="Switch" />
|
||||
</button>
|
||||
<button onClick={() => LoginStore.removeSession(a)}>
|
||||
<button onClick={() => LoginStore.removeSession(a.id)}>
|
||||
<FormattedMessage defaultMessage="Logout" />
|
||||
</button>
|
||||
</div>
|
||||
@ -61,27 +36,12 @@ export default function AccountsPage() {
|
||||
))}
|
||||
|
||||
{sub && (
|
||||
<>
|
||||
<h3>
|
||||
<Link to={"/login"}>
|
||||
<button type="button">
|
||||
<FormattedMessage defaultMessage="Add Account" />
|
||||
</h3>
|
||||
<div className="flex">
|
||||
<input
|
||||
dir="auto"
|
||||
type="text"
|
||||
placeholder={formatMessage({
|
||||
defaultMessage: "nsec, npub, nip-05, hex, mnemonic",
|
||||
})}
|
||||
className="f-grow mr10"
|
||||
onChange={e => setKey(e.target.value)}
|
||||
/>
|
||||
<AsyncButton onClick={() => doLogin()}>
|
||||
<FormattedMessage defaultMessage="Login" />
|
||||
</AsyncButton>
|
||||
</div>
|
||||
</>
|
||||
</button>
|
||||
</Link>
|
||||
)}
|
||||
{error && <b className="error">{error}</b>}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { ExternalStore } from "@snort/shared";
|
||||
import { NostrEvent, TaggedNostrEvent } from "@snort/system";
|
||||
import { ZapTarget } from "Zapper";
|
||||
import { useSyncExternalStore } from "react";
|
||||
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector";
|
||||
|
||||
interface NoteCreatorDataSnapshot {
|
||||
show: boolean;
|
||||
@ -33,11 +34,11 @@ class NoteCreatorStore extends ExternalStore<NoteCreatorDataSnapshot> {
|
||||
advanced: false,
|
||||
reset: () => {
|
||||
this.#reset(this.#data);
|
||||
this.notifyChange();
|
||||
this.notifyChange(this.#data);
|
||||
},
|
||||
update: (fn: (v: NoteCreatorDataSnapshot) => void) => {
|
||||
fn(this.#data);
|
||||
this.notifyChange();
|
||||
this.notifyChange(this.#data);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -65,8 +66,7 @@ class NoteCreatorStore extends ExternalStore<NoteCreatorDataSnapshot> {
|
||||
},
|
||||
update: (fn: (v: NoteCreatorDataSnapshot) => void) => {
|
||||
fn(this.#data);
|
||||
console.debug(this.#data);
|
||||
this.notifyChange();
|
||||
this.notifyChange(this.#data);
|
||||
},
|
||||
} as NoteCreatorDataSnapshot;
|
||||
return sn;
|
||||
@ -75,9 +75,20 @@ class NoteCreatorStore extends ExternalStore<NoteCreatorDataSnapshot> {
|
||||
|
||||
const NoteCreatorState = new NoteCreatorStore();
|
||||
|
||||
export function useNoteCreator() {
|
||||
return useSyncExternalStore(
|
||||
c => NoteCreatorState.hook(c),
|
||||
() => NoteCreatorState.snapshot(),
|
||||
);
|
||||
export function useNoteCreator<T extends object = NoteCreatorDataSnapshot>(
|
||||
selector?: (v: NoteCreatorDataSnapshot) => T,
|
||||
) {
|
||||
if (selector) {
|
||||
return useSyncExternalStoreWithSelector<NoteCreatorDataSnapshot, T>(
|
||||
c => NoteCreatorState.hook(c),
|
||||
() => NoteCreatorState.snapshot(),
|
||||
undefined,
|
||||
selector,
|
||||
);
|
||||
} else {
|
||||
return useSyncExternalStore<T>(
|
||||
c => NoteCreatorState.hook(c),
|
||||
() => NoteCreatorState.snapshot() as T,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ import { preload, RelayMetrics, UserCache, UserRelays } from "Cache";
|
||||
import { LoginStore } from "Login";
|
||||
import { SnortDeckLayout } from "Pages/DeckLayout";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const WasmQueryOptimizer = {
|
||||
expandFilter: (f: ReqFilter) => {
|
||||
return expand_filter(f) as Array<FlatReqFilter>;
|
||||
@ -61,7 +60,7 @@ export const System = new NostrSystem({
|
||||
relayCache: UserRelays,
|
||||
profileCache: UserCache,
|
||||
relayMetrics: RelayMetrics,
|
||||
//queryOptimizer: WasmQueryOptimizer,
|
||||
queryOptimizer: WasmQueryOptimizer,
|
||||
authHandler: async (c, r) => {
|
||||
const { id } = LoginStore.snapshot();
|
||||
const pub = LoginStore.getPublisher(id);
|
||||
|
Reference in New Issue
Block a user