fp/services/next/app/components/stream-page.tsx

218 lines
9.0 KiB
TypeScript

'use client';
import { IStream } from "@futureporn/types";
import { IVod } from "@/app/lib/vods";
import Link from "next/link";
import Image from "next/legacy/image";
import { LocalizedDate } from "./localized-date";
import { FontAwesomeIcon, FontAwesomeIconProps } from "@fortawesome/react-fontawesome";
import { faTriangleExclamation, faCircleInfo, faThumbsUp, IconDefinition, faO, faX, faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
import { Hemisphere, Moon } from "lunarphase-js";
import { useEffect, useState } from "react";
import { faXTwitter } from "@fortawesome/free-brands-svg-icons";
import { notFound } from "next/navigation";
export interface IStreamProps {
stream: IStream;
}
type Status = 'missing' | 'issue' | 'good';
interface StyleDef {
heading: string;
icon: IconDefinition;
desc1: string;
desc2: string;
}
function capitalizeFirstLetter(string: string): string {
return string.charAt(0).toUpperCase() + string.slice(1);
}
function hasNote(vod: IVod) {
if (!!vod?.note) return true;
else return false;
}
function determineStatus(stream: IStream): Status {
if (stream.vods.length < 1) {
return 'missing'
} else {
if (stream.vods.some((vod: IVod) => !hasNote(vod))) {
return 'good';
} else {
return 'issue';
}
}
}
export default function StreamPage({ stream }: IStreamProps) {
console.log('StreamPage function has been invoked! stream as follows')
console.log(stream)
if (!stream) notFound()
const displayName = stream.vtuber.display_name;
const date = new Date(stream.date);
const [hemisphere, setHemisphere] = useState(Hemisphere.NORTHERN);
const [selectedStatus, setSelectedStatus] = useState<Status>(determineStatus(stream));
const styleMap: Record<Status, StyleDef> = {
'missing': {
heading: 'is-danger',
icon: faTriangleExclamation,
desc1: "We don't have a VOD for this stream.",
desc2: 'Know someone who does?'
},
'issue': {
heading: 'is-warning',
icon: faCircleInfo,
desc1: "We have a VOD for this stream, but it's not full quality.",
desc2: 'Have a better copy?'
},
'good': {
heading: 'is-success',
icon: faThumbsUp,
desc1: "We have a VOD for this stream, and we think it's the best quality possible.",
desc2: "Have one that's even better?"
}
};
const { heading, icon, desc1, desc2 } = styleMap[selectedStatus] || {};
useEffect(() => {
const randomHemisphere = (Math.random() < 0.5 ? 0 : 1) ? Hemisphere.NORTHERN : Hemisphere.SOUTHERN;
setHemisphere(randomHemisphere);
}, []);
if (!stream) return <p>NotFound</p>
// <NotFound></NotFound>
// return <p>
// <pre>
// <code>
// {JSON.stringify(stream, null, 2)}
// </code>
// </pre>
// </p>
// const platformsList = [
// stream.attributes.isChaturbateStream ? 'Chaturbate' : null,
// stream.attributes.isFanslyStream ? 'Fansly' : null
// ].filter(Boolean).join(', ');
// platformsList = platformsArray.length > 0 ? platformsArray.join(', ') : 'None';
// const platformsList = [
// (stream.attributes.isChaturbateStream && 'CB'),
// (stream.attributes.isFanslyStream && 'Fansly')
// ].filter(Boolean).join(', ')
const platformsList = [
(stream.is_chaturbate_stream && 'CB'),
(stream.is_fansly_stream && 'Fansly')
].filter(Boolean).join(', ') || '!!!';
return (
<>
<div className="content">
<div className="section">
<h1 className="title"><LocalizedDate date={date} /> {displayName} Stream Archive</h1>
</div>
<div className="section columns is-multiline">
<div className="column is-half">
<div className="box">
<div className="columns is-multiline">
<div className="column is-full">
<table className="table">
<thead>
<tr>
<th className="is-family-sans-serif">Description</th>
<th className="is-family-sans-serif">Details</th>
</tr>
</thead>
<tbody>
{/* <tr>
<td>Announcement</td>
<td><Link target="_blank" href={stream.attributes.tweet.data.attributes.url}><FontAwesomeIcon icon={faXTwitter}></FontAwesomeIcon><FontAwesomeIcon icon={faExternalLinkAlt}></FontAwesomeIcon></Link></td>
</tr> */}
<tr>
<td>Platform</td>
<td>{platformsList}</td>
</tr>
<tr>
<td>UTC Datetime</td>
<td><time dateTime={date.toISOString()}>{date.toISOString()}</time></td>
</tr>
<tr>
<td>Local Datetime</td>
<td>{date.toLocaleDateString()} {date.toLocaleTimeString()}</td>
</tr>
<tr>
<td>Lunar Phase</td>
<td>{Moon.lunarPhase(date)} {Moon.lunarPhaseEmoji(date, { hemisphere })}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div className="column is-half">
<article className={`message ${heading}`}>
<div className="message-header">
<span>VOD {capitalizeFirstLetter(selectedStatus)}</span>
</div>
<div className="message-body has-text-centered">
<span className="title is-1"><FontAwesomeIcon icon={icon}></FontAwesomeIcon></span>
<p className="mt-3">{desc1}</p>
<p className="mt-5">{desc2}<br />
<Link href={`/upload?uuid=${stream.uuid}`}>Upload it here.</Link></p>
</div>
</article>
</div>
</div>
{stream.vods.length !== 0 &&
<div className="section">
<h1 className="title">VODs</h1>
<table className="table">
<thead>
<tr>
<th>ID</th>
<th>Upload Date</th>
{/* <th>Thumbnail</th>
<th>Duration</th> */}
<th>Tags</th>
<th>Timestamps</th>
<th>Note</th>
</tr>
</thead>
<tbody>
{stream.vods.map((vod: IVod) => (
<tr key={vod.id}>
{/* <p>{JSON.stringify(vod, null, 2)}</p> */}
<td><Link href={`/vt/${stream.vtuber.slug}/vod/${vod.uuid}`}>{vod.uuid}</Link></td>
<td>{vod.publishedAt}</td>
{/* <td>{(!!vod?.attributes?.thumbnail?.data?.attributes?.cdnUrl) ? <Image alt="" src={vod.attributes.thumbnail.data.attributes.cdnUrl}></Image> : <FontAwesomeIcon icon={faX} />}</td>
<td>{(!!vod?.attributes?.duration) ? vod.attributes.duration : <FontAwesomeIcon icon={faX} />}</td> */}
<td>{vod.tagVodRelations.length}</td>
<td>{vod.timestamps.length}</td>
<td>{(!!vod.note) ? <FontAwesomeIcon icon={faO} /> : <FontAwesomeIcon icon={faX} />}</td>
</tr>
))}
</tbody>
</table>
</div>}
</div>
</>
)
}