feat: responsible zap modal

This commit is contained in:
Alejandro Gomez 2023-06-28 08:43:33 +02:00
parent 391e549421
commit 713f4c3d5e
No known key found for this signature in database
GPG Key ID: 4DF39E566658C817
7 changed files with 74 additions and 63 deletions

View File

@ -49,22 +49,3 @@
color: inherit; color: inherit;
background: #353535; background: #353535;
} }
.dialog-overlay {
background-color: rgba(0, 0, 0, 0.8);
position: fixed;
inset: 0;
}
.dialog-content {
background-color: #171717;
border-radius: 6px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90vw;
max-width: 450px;
max-height: 85vh;
padding: 25px;
}

View File

@ -1,7 +1,7 @@
import "./new-stream.css"; import "./new-stream.css";
import * as Dialog from "@radix-ui/react-dialog"; import * as Dialog from "@radix-ui/react-dialog";
import { useEffect, useState } from "react"; import { useEffect, useState, useCallback } from "react";
import { EventPublisher, NostrEvent } from "@snort/system"; import { EventPublisher, NostrEvent } from "@snort/system";
import { unixNow } from "@snort/shared"; import { unixNow } from "@snort/shared";
@ -15,7 +15,7 @@ export function NewStream({
onFinish, onFinish,
}: { }: {
ev?: NostrEvent; ev?: NostrEvent;
onFinish: (ev: NostrEvent) => void; onFinish?: (ev: NostrEvent) => void;
}) { }) {
const [title, setTitle] = useState(findTag(ev, "title") ?? ""); const [title, setTitle] = useState(findTag(ev, "title") ?? "");
const [summary, setSummary] = useState(findTag(ev, "summary") ?? ""); const [summary, setSummary] = useState(findTag(ev, "summary") ?? "");
@ -27,7 +27,7 @@ export function NewStream({
const [start, setStart] = useState(findTag(ev, "starts")); const [start, setStart] = useState(findTag(ev, "starts"));
const [isValid, setIsValid] = useState(false); const [isValid, setIsValid] = useState(false);
function validate() { const validate = useCallback(() => {
if (title.length < 2) { if (title.length < 2) {
return false; return false;
} }
@ -38,11 +38,11 @@ export function NewStream({
return false; return false;
} }
return true; return true;
} }, [title, image, stream]);
useEffect(() => { useEffect(() => {
setIsValid(validate()); setIsValid(validate());
}, [title, summary, image, stream]); }, [validate, title, summary, image, stream]);
async function publishStream() { async function publishStream() {
const pub = await EventPublisher.nip7(); const pub = await EventPublisher.nip7();
@ -67,7 +67,7 @@ export function NewStream({
}); });
console.debug(evNew); console.debug(evNew);
System.BroadcastEvent(evNew); System.BroadcastEvent(evNew);
onFinish(evNew); onFinish && onFinish(evNew);
} }
} }
@ -174,7 +174,7 @@ interface NewStreamDialogProps {
text?: string; text?: string;
btnClassName?: string; btnClassName?: string;
ev?: NostrEvent; ev?: NostrEvent;
onFinish: (e: NostrEvent) => void; onFinish?: (e: NostrEvent) => void;
} }
export function NewStreamDialog({ export function NewStreamDialog({

View File

@ -1,5 +1,4 @@
.send-zap { .send-zap {
width: inherit;
display: flex; display: flex;
gap: 24px; gap: 24px;
flex-direction: column; flex-direction: column;
@ -58,4 +57,4 @@
.send-zap .qr { .send-zap .qr {
align-self: center; align-self: center;
} }

View File

@ -1,4 +1,5 @@
import "./send-zap.css"; import "./send-zap.css";
import * as Dialog from "@radix-ui/react-dialog";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { LNURL } from "@snort/shared"; import { LNURL } from "@snort/shared";
import { NostrEvent, EventPublisher } from "@snort/system"; import { NostrEvent, EventPublisher } from "@snort/system";
@ -9,17 +10,14 @@ import { findTag } from "utils";
import { Relays } from "index"; import { Relays } from "index";
import QrCode from "./qr-code"; import QrCode from "./qr-code";
export function SendZaps({ interface SendZapsProps {
lnurl,
ev,
targetName,
onFinish,
}: {
lnurl: string; lnurl: string;
ev?: NostrEvent; ev?: NostrEvent;
targetName?: string; targetName?: string;
onFinish: () => void; onFinish: () => void;
}) { }
function SendZaps({ lnurl, ev, targetName, onFinish }: SendZapsProps) {
const UsdRate = 30_000; const UsdRate = 30_000;
const satsAmounts = [ const satsAmounts = [
@ -152,6 +150,31 @@ export function SendZaps({
); );
} }
function SendZapDialog() { export function SendZapsDialog({
return "TODO"; lnurl,
ev,
targetName,
}: Omit<SendZapsProps, "onFinish">) {
const [isOpen, setIsOpen] = useState(false);
return (
<Dialog.Root open={isOpen} onOpenChange={setIsOpen}>
<Dialog.Trigger asChild>
<button className="btn btn-primary zap">
<span className="hide-on-mobile">Zap</span>
<Icon name="zap" size={16} />
</button>
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay className="dialog-overlay" />
<Dialog.Content className="dialog-content">
<SendZaps
lnurl={lnurl}
ev={ev}
targetName={targetName}
onFinish={() => setIsOpen(false)}
/>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
} }

View File

@ -162,3 +162,22 @@ button span.hide-on-mobile {
height: 100vh; height: 100vh;
width: 100vw; width: 100vw;
} }
.dialog-overlay {
background-color: rgba(0, 0, 0, 0.8);
position: fixed;
inset: 0;
}
.dialog-content {
background-color: #171717;
border-radius: 6px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90vw;
max-width: 450px;
max-height: 85vh;
padding: 25px;
}

View File

@ -35,6 +35,11 @@
} }
} }
.homepage {
width: 100%;
grid-area: main-content;
}
.homepage h2 { .homepage h2 {
background: #171717; background: #171717;
padding: 40px; padding: 40px;

View File

@ -1,5 +1,5 @@
import "./stream-page.css"; import "./stream-page.css";
import { useRef, useState } from "react"; import { useRef } from "react";
import { parseNostrLink, EventPublisher } from "@snort/system"; import { parseNostrLink, EventPublisher } from "@snort/system";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import moment from "moment"; import moment from "moment";
@ -10,11 +10,9 @@ import { findTag } from "utils";
import { Profile, getName } from "element/profile"; import { Profile, getName } from "element/profile";
import { LiveChat } from "element/live-chat"; import { LiveChat } from "element/live-chat";
import AsyncButton from "element/async-button"; import AsyncButton from "element/async-button";
import { Icon } from "element/icon";
import { useLogin } from "hooks/login"; import { useLogin } from "hooks/login";
import { StreamState, System } from "index"; import { StreamState, System } from "index";
import Modal from "element/modal"; import { SendZapsDialog } from "element/send-zap";
import { SendZaps } from "element/send-zap";
import type { NostrLink } from "@snort/system"; import type { NostrLink } from "@snort/system";
import { useUserProfile } from "@snort/system-react"; import { useUserProfile } from "@snort/system-react";
import { NewStreamDialog } from "element/new-stream"; import { NewStreamDialog } from "element/new-stream";
@ -23,7 +21,6 @@ function ProfileInfo({ link }: { link: NostrLink }) {
const thisEvent = useEventFeed(link, true); const thisEvent = useEventFeed(link, true);
const login = useLogin(); const login = useLogin();
const navigate = useNavigate(); const navigate = useNavigate();
const [zap, setZap] = useState(false);
const profile = useUserProfile(System, thisEvent.data?.pubkey); const profile = useUserProfile(System, thisEvent.data?.pubkey);
const zapTarget = profile?.lud16 ?? profile?.lud06; const zapTarget = profile?.lud16 ?? profile?.lud06;
@ -42,8 +39,6 @@ function ProfileInfo({ link }: { link: NostrLink }) {
} }
} }
function onFinish() {}
return ( return (
<> <>
<div className="flex info"> <div className="flex info">
@ -69,11 +64,7 @@ function ProfileInfo({ link }: { link: NostrLink }) {
{isMine && ( {isMine && (
<div className="actions"> <div className="actions">
{thisEvent.data && ( {thisEvent.data && (
<NewStreamDialog <NewStreamDialog text="Edit" ev={thisEvent.data} />
text="Edit"
ev={thisEvent.data}
onFinish={onFinish}
/>
)} )}
<AsyncButton <AsyncButton
type="button" type="button"
@ -87,22 +78,15 @@ function ProfileInfo({ link }: { link: NostrLink }) {
</div> </div>
<div className="profile-info flex g24"> <div className="profile-info flex g24">
<Profile pubkey={thisEvent.data?.pubkey ?? ""} /> <Profile pubkey={thisEvent.data?.pubkey ?? ""} />
<button onClick={() => setZap(true)} className="btn btn-primary zap"> {zapTarget && thisEvent.data && (
<span className="hide-on-mobile">Zap</span> <SendZapsDialog
<Icon name="zap" size={16} /> lnurl={zapTarget}
</button> ev={thisEvent.data}
targetName={getName(thisEvent.data.pubkey, profile)}
/>
)}
</div> </div>
</div> </div>
{zap && zapTarget && thisEvent.data && (
<Modal onClose={() => setZap(false)}>
<SendZaps
lnurl={zapTarget}
ev={thisEvent.data}
targetName={getName(thisEvent.data.pubkey, profile)}
onFinish={() => setZap(false)}
/>
</Modal>
)}
</> </>
); );
} }