fix: accept tos!

This commit is contained in:
kieran 2024-12-11 14:32:39 +00:00
parent 5540034ade
commit 9cf9199b29
No known key found for this signature in database
GPG Key ID: DE71CEB3925BE941
7 changed files with 109 additions and 39 deletions

View File

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { CSSProperties, HTMLProps } from "react";
import { CSSProperties, HTMLProps, Suspense, lazy } from "react";
import classNames from "classnames";
import {
MediaControlBar,
@ -20,8 +20,8 @@ import {
} from "media-chrome/react";
import "hls-video-element";
import { StreamState } from "@/const";
import Nip94Player from "./n94-player";
import { NostrLink } from "@snort/system";
const Nip94Player = lazy(() => import("./n94-player"));
type VideoPlayerProps = {
title?: string;
@ -35,12 +35,15 @@ type VideoPlayerProps = {
export default function LiveVideoPlayer({ title, stream, status, poster, link, ...props }: VideoPlayerProps) {
function innerPlayer() {
if (stream === "nip94") {
return <Nip94Player link={link} />;
}
{
return (
<Suspense>
<Nip94Player link={link} />
</Suspense>
);
} else {
/* @ts-ignore Web Componenet */
return <hls-video {...props} slot="media" src={stream} playsInline={true} autoPlay={true} />;
}
return <hls-video {...props} slot="media" src={stream} playsInline={true} autoPlay={true} />;
}
return (
<MediaController

View File

@ -730,6 +730,9 @@
"gzsn7k": {
"defaultMessage": "{n} messages"
},
"h6NRY6": {
"defaultMessage": "No Thanks!"
},
"h9mX2/": {
"defaultMessage": "If you use our in-house zap.stream hosting (cheapest and easiest), copy your stream URL and Stream Key to your OBS settings and you should be good to go."
},

View File

@ -16,12 +16,12 @@ import { DashboardCard } from "./card";
import { NewStreamDialog } from "@/element/new-stream";
import { DashboardSettingsButton } from "./button-settings";
import DashboardIntro from "./intro";
import { useLocation } from "react-router-dom";
import { useLocation, useNavigate } from "react-router-dom";
import StreamKey from "@/element/provider/nostr/stream-key";
import { DefaultProvider, NostrStreamProvider, StreamProviderInfo } from "@/providers";
import { ExternalLink } from "@/element/external-link";
import BalanceTimeEstimate from "@/element/balance-time-estimate";
import { Layer1Button, WarningButton } from "@/element/buttons";
import { Layer1Button, Layer2Button, WarningButton } from "@/element/buttons";
import { useLogin } from "@/hooks/login";
import AccountTopup from "@/element/provider/nostr/topup";
import classNames from "classnames";
@ -30,15 +30,19 @@ import { unixNow } from "@snort/shared";
import { Icon } from "@/element/icon";
import ForwardingModal from "./forwarding";
import BalanceHistoryModal from "./balance-history";
import Modal from "@/element/modal";
import { AcceptTos } from "./tos";
const StreamSummary = lazy(() => import("@/element/summary-chart"));
export function DashboardForLink({ link }: { link: NostrLink }) {
export default function DashboardForLink({ link }: { link: NostrLink }) {
const navigate = useNavigate();
const streamEvent = useCurrentStreamFeed(link, true);
const location = useLocation();
const login = useLogin();
const streamLink = streamEvent ? NostrLink.fromEvent(streamEvent) : undefined;
const { stream, status, image, participants, service } = extractStreamInfo(streamEvent);
const [info, setInfo] = useState<StreamProviderInfo>();
const [tos, setTos] = useState(info?.tosAccepted ?? false);
const isMyManual = streamEvent?.pubkey === login?.pubkey;
const system = useContext(SnortContext);
const [recording, setRecording] = useState(Boolean(localStorage.getItem("default-recording") ?? "true"));
@ -126,7 +130,14 @@ export function DashboardForLink({ link }: { link: NostrLink }) {
</div>
{streamLink && status === StreamState.Live && !isMyManual && (
<>
<LiveVideoPlayer stream={stream} status={status} poster={image} muted={true} className="w-full" />
<LiveVideoPlayer
stream={stream}
link={streamLink}
status={status}
poster={image}
muted={true}
className="w-full"
/>
<div className="flex gap-4">
<DashboardStatsCard
name={<FormattedMessage defaultMessage="Stream Time" />}
@ -170,7 +181,14 @@ export function DashboardForLink({ link }: { link: NostrLink }) {
)}
{streamLink && isMyManual && (status === StreamState.Live || status === StreamState.Planned) && (
<>
<LiveVideoPlayer stream={stream} status={status} poster={image} muted={true} className="w-full" />
<LiveVideoPlayer
link={streamLink}
stream={stream}
status={status}
poster={image}
muted={true}
className="w-full"
/>
<div className="grid gap-2 grid-cols-3">
<DashboardRaidButton link={streamLink} />
<NewStreamDialog ev={streamEvent} text={<FormattedMessage defaultMessage="Edit Stream Info" />} />
@ -283,6 +301,29 @@ export function DashboardForLink({ link }: { link: NostrLink }) {
</>
)}
{streamLink && status === StreamState.Planned && <DashboardCard className="overflow-y-auto"></DashboardCard>}
{info && !info.tosAccepted && (
<Modal id="tos-dashboard">
<div className="flex flex-col gap-4">
<h2>Please accept TOS before continuing</h2>
<AcceptTos provider={info?.name} tosLink={info?.tosLink} tos={tos} setTos={setTos} />
<div className="flex items-center justify-between">
<Layer2Button
disabled={!tos}
onClick={async () => {
if (tos) {
await provider.acceptTos();
provider.info().then(setInfo);
}
}}>
<FormattedMessage defaultMessage="Save" />
</Layer2Button>
<WarningButton onClick={() => navigate("/")}>
<FormattedMessage defaultMessage="No Thanks!" />
</WarningButton>
</div>
</div>
</Modal>
)}
</div>
);
}

View File

@ -1,13 +1,19 @@
import { useLogin } from "@/hooks/login";
import { NostrLink, NostrPrefix, parseNostrLink } from "@snort/system";
import { DashboardForLink } from "./dashboard";
import { Suspense, lazy } from "react";
import { useParams } from "react-router-dom";
const DashboardForLink = lazy(() => import("./dashboard"));
export default function DashboardPage() {
const login = useLogin();
const { id } = useParams();
if (!login) return;
const link = id ? parseNostrLink(id) : new NostrLink(NostrPrefix.PublicKey, login.pubkey);
return <DashboardForLink link={link} />;
return (
<Suspense>
<DashboardForLink link={link} />
</Suspense>
);
}

View File

@ -7,6 +7,7 @@ import { useEffect, useMemo, useState } from "react";
import { FormattedMessage, FormattedNumber } from "react-intl";
import { useNavigate } from "react-router-dom";
import ZapGlow from "../zap-glow";
import { AcceptTos } from "../tos";
export default function DashboardIntro() {
const navigate = useNavigate();
@ -16,7 +17,7 @@ export default function DashboardIntro() {
const exampleHours = 4;
const defaultEndpoint = useMemo(() => {
return info?.endpoints.find(a => a.name == "Best") ?? info?.endpoints[0];
return info?.endpoints?.find(a => a.name == "Best") ?? info?.endpoints?.at(0);
}, [info]);
const rate = useRates("BTCUSD");
const exampleCost = rate.ask * (exampleHours * (defaultEndpoint?.rate ?? 0) * 60) * 1e-8;
@ -69,31 +70,7 @@ export default function DashboardIntro() {
}}
/>
</p>
{!info?.tosAccepted && (
<div>
<div className="flex gap-2 cursor-pointer select-none" onClick={() => setTos(v => !v)}>
<input type="checkbox" checked={tos} onChange={e => setTos(e.target.checked)} />
<p>
<FormattedMessage
defaultMessage="I have read and agree with {provider}'s {terms}."
values={{
provider: info?.name,
terms: (
<span
className="text-primary"
onClick={e => {
e.stopPropagation();
window.open(info?.tosLink, "popup", "width=400,height=800");
}}>
<FormattedMessage defaultMessage="terms and conditions" />
</span>
),
}}
/>
</p>
</div>
</div>
)}
{!info?.tosAccepted && <AcceptTos provider={info?.name} tosLink={info?.tosLink} tos={tos} setTos={setTos} />}
<DefaultButton
disabled={!tos}
onClick={async () => {

View File

@ -0,0 +1,39 @@
import { FormattedMessage } from "react-intl";
export function AcceptTos({
provider,
tosLink,
tos,
setTos,
}: {
provider?: string;
tosLink?: string;
tos: boolean;
setTos: (f: (r: boolean) => boolean) => void;
}) {
return (
<div>
<div className="flex gap-2 cursor-pointer select-none" onClick={() => setTos(v => !v)}>
<input type="checkbox" checked={tos} onChange={e => setTos(() => e.target.checked)} />
<p>
<FormattedMessage
defaultMessage="I have read and agree with {provider}'s {terms}."
values={{
provider,
terms: (
<span
className="text-primary"
onClick={e => {
e.stopPropagation();
window.open(tosLink, "popup", "width=400,height=800");
}}>
<FormattedMessage defaultMessage="terms and conditions" />
</span>
),
}}
/>
</p>
</div>
</div>
);
}

View File

@ -240,6 +240,7 @@
"gQxxlw": "Goal Name",
"gt65Gg": "Stream goals encourage viewers to support streamers via donations.",
"gzsn7k": "{n} messages",
"h6NRY6": "No Thanks!",
"h9mX2/": "If you use our in-house zap.stream hosting (cheapest and easiest), copy your stream URL and Stream Key to your OBS settings and you should be good to go.",
"hMzcSq": "Messages",
"heyxZL": "Enable text to speech",