fix: accept tos!
This commit is contained in:
parent
5540034ade
commit
9cf9199b29
@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
import { CSSProperties, HTMLProps } from "react";
|
import { CSSProperties, HTMLProps, Suspense, lazy } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import {
|
import {
|
||||||
MediaControlBar,
|
MediaControlBar,
|
||||||
@ -20,8 +20,8 @@ import {
|
|||||||
} from "media-chrome/react";
|
} from "media-chrome/react";
|
||||||
import "hls-video-element";
|
import "hls-video-element";
|
||||||
import { StreamState } from "@/const";
|
import { StreamState } from "@/const";
|
||||||
import Nip94Player from "./n94-player";
|
|
||||||
import { NostrLink } from "@snort/system";
|
import { NostrLink } from "@snort/system";
|
||||||
|
const Nip94Player = lazy(() => import("./n94-player"));
|
||||||
|
|
||||||
type VideoPlayerProps = {
|
type VideoPlayerProps = {
|
||||||
title?: string;
|
title?: string;
|
||||||
@ -35,13 +35,16 @@ type VideoPlayerProps = {
|
|||||||
export default function LiveVideoPlayer({ title, stream, status, poster, link, ...props }: VideoPlayerProps) {
|
export default function LiveVideoPlayer({ title, stream, status, poster, link, ...props }: VideoPlayerProps) {
|
||||||
function innerPlayer() {
|
function innerPlayer() {
|
||||||
if (stream === "nip94") {
|
if (stream === "nip94") {
|
||||||
return <Nip94Player link={link} />;
|
return (
|
||||||
}
|
<Suspense>
|
||||||
{
|
<Nip94Player link={link} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
/* @ts-ignore Web Componenet */
|
/* @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 (
|
return (
|
||||||
<MediaController
|
<MediaController
|
||||||
className={classNames(props.className, "h-inherit aspect-video w-full")}
|
className={classNames(props.className, "h-inherit aspect-video w-full")}
|
||||||
|
@ -730,6 +730,9 @@
|
|||||||
"gzsn7k": {
|
"gzsn7k": {
|
||||||
"defaultMessage": "{n} messages"
|
"defaultMessage": "{n} messages"
|
||||||
},
|
},
|
||||||
|
"h6NRY6": {
|
||||||
|
"defaultMessage": "No Thanks!"
|
||||||
|
},
|
||||||
"h9mX2/": {
|
"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."
|
"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."
|
||||||
},
|
},
|
||||||
|
@ -16,12 +16,12 @@ import { DashboardCard } from "./card";
|
|||||||
import { NewStreamDialog } from "@/element/new-stream";
|
import { NewStreamDialog } from "@/element/new-stream";
|
||||||
import { DashboardSettingsButton } from "./button-settings";
|
import { DashboardSettingsButton } from "./button-settings";
|
||||||
import DashboardIntro from "./intro";
|
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 StreamKey from "@/element/provider/nostr/stream-key";
|
||||||
import { DefaultProvider, NostrStreamProvider, StreamProviderInfo } from "@/providers";
|
import { DefaultProvider, NostrStreamProvider, StreamProviderInfo } from "@/providers";
|
||||||
import { ExternalLink } from "@/element/external-link";
|
import { ExternalLink } from "@/element/external-link";
|
||||||
import BalanceTimeEstimate from "@/element/balance-time-estimate";
|
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 { useLogin } from "@/hooks/login";
|
||||||
import AccountTopup from "@/element/provider/nostr/topup";
|
import AccountTopup from "@/element/provider/nostr/topup";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
@ -30,15 +30,19 @@ import { unixNow } from "@snort/shared";
|
|||||||
import { Icon } from "@/element/icon";
|
import { Icon } from "@/element/icon";
|
||||||
import ForwardingModal from "./forwarding";
|
import ForwardingModal from "./forwarding";
|
||||||
import BalanceHistoryModal from "./balance-history";
|
import BalanceHistoryModal from "./balance-history";
|
||||||
|
import Modal from "@/element/modal";
|
||||||
|
import { AcceptTos } from "./tos";
|
||||||
const StreamSummary = lazy(() => import("@/element/summary-chart"));
|
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 streamEvent = useCurrentStreamFeed(link, true);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
const streamLink = streamEvent ? NostrLink.fromEvent(streamEvent) : undefined;
|
const streamLink = streamEvent ? NostrLink.fromEvent(streamEvent) : undefined;
|
||||||
const { stream, status, image, participants, service } = extractStreamInfo(streamEvent);
|
const { stream, status, image, participants, service } = extractStreamInfo(streamEvent);
|
||||||
const [info, setInfo] = useState<StreamProviderInfo>();
|
const [info, setInfo] = useState<StreamProviderInfo>();
|
||||||
|
const [tos, setTos] = useState(info?.tosAccepted ?? false);
|
||||||
const isMyManual = streamEvent?.pubkey === login?.pubkey;
|
const isMyManual = streamEvent?.pubkey === login?.pubkey;
|
||||||
const system = useContext(SnortContext);
|
const system = useContext(SnortContext);
|
||||||
const [recording, setRecording] = useState(Boolean(localStorage.getItem("default-recording") ?? "true"));
|
const [recording, setRecording] = useState(Boolean(localStorage.getItem("default-recording") ?? "true"));
|
||||||
@ -126,7 +130,14 @@ export function DashboardForLink({ link }: { link: NostrLink }) {
|
|||||||
</div>
|
</div>
|
||||||
{streamLink && status === StreamState.Live && !isMyManual && (
|
{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">
|
<div className="flex gap-4">
|
||||||
<DashboardStatsCard
|
<DashboardStatsCard
|
||||||
name={<FormattedMessage defaultMessage="Stream Time" />}
|
name={<FormattedMessage defaultMessage="Stream Time" />}
|
||||||
@ -170,7 +181,14 @@ export function DashboardForLink({ link }: { link: NostrLink }) {
|
|||||||
)}
|
)}
|
||||||
{streamLink && isMyManual && (status === StreamState.Live || status === StreamState.Planned) && (
|
{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">
|
<div className="grid gap-2 grid-cols-3">
|
||||||
<DashboardRaidButton link={streamLink} />
|
<DashboardRaidButton link={streamLink} />
|
||||||
<NewStreamDialog ev={streamEvent} text={<FormattedMessage defaultMessage="Edit Stream Info" />} />
|
<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>}
|
{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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
import { useLogin } from "@/hooks/login";
|
import { useLogin } from "@/hooks/login";
|
||||||
import { NostrLink, NostrPrefix, parseNostrLink } from "@snort/system";
|
import { NostrLink, NostrPrefix, parseNostrLink } from "@snort/system";
|
||||||
import { DashboardForLink } from "./dashboard";
|
import { Suspense, lazy } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
|
const DashboardForLink = lazy(() => import("./dashboard"));
|
||||||
|
|
||||||
export default function DashboardPage() {
|
export default function DashboardPage() {
|
||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
if (!login) return;
|
if (!login) return;
|
||||||
const link = id ? parseNostrLink(id) : new NostrLink(NostrPrefix.PublicKey, login.pubkey);
|
const link = id ? parseNostrLink(id) : new NostrLink(NostrPrefix.PublicKey, login.pubkey);
|
||||||
|
|
||||||
return <DashboardForLink link={link} />;
|
return (
|
||||||
|
<Suspense>
|
||||||
|
<DashboardForLink link={link} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import { useEffect, useMemo, useState } from "react";
|
|||||||
import { FormattedMessage, FormattedNumber } from "react-intl";
|
import { FormattedMessage, FormattedNumber } from "react-intl";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import ZapGlow from "../zap-glow";
|
import ZapGlow from "../zap-glow";
|
||||||
|
import { AcceptTos } from "../tos";
|
||||||
|
|
||||||
export default function DashboardIntro() {
|
export default function DashboardIntro() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@ -16,7 +17,7 @@ export default function DashboardIntro() {
|
|||||||
const exampleHours = 4;
|
const exampleHours = 4;
|
||||||
|
|
||||||
const defaultEndpoint = useMemo(() => {
|
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]);
|
}, [info]);
|
||||||
const rate = useRates("BTCUSD");
|
const rate = useRates("BTCUSD");
|
||||||
const exampleCost = rate.ask * (exampleHours * (defaultEndpoint?.rate ?? 0) * 60) * 1e-8;
|
const exampleCost = rate.ask * (exampleHours * (defaultEndpoint?.rate ?? 0) * 60) * 1e-8;
|
||||||
@ -69,31 +70,7 @@ export default function DashboardIntro() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
{!info?.tosAccepted && (
|
{!info?.tosAccepted && <AcceptTos provider={info?.name} tosLink={info?.tosLink} tos={tos} setTos={setTos} />}
|
||||||
<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>
|
|
||||||
)}
|
|
||||||
<DefaultButton
|
<DefaultButton
|
||||||
disabled={!tos}
|
disabled={!tos}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
39
src/pages/dashboard/tos.tsx
Normal file
39
src/pages/dashboard/tos.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
@ -240,6 +240,7 @@
|
|||||||
"gQxxlw": "Goal Name",
|
"gQxxlw": "Goal Name",
|
||||||
"gt65Gg": "Stream goals encourage viewers to support streamers via donations.",
|
"gt65Gg": "Stream goals encourage viewers to support streamers via donations.",
|
||||||
"gzsn7k": "{n} messages",
|
"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.",
|
"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",
|
"hMzcSq": "Messages",
|
||||||
"heyxZL": "Enable text to speech",
|
"heyxZL": "Enable text to speech",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user