aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/ChannelCard/ChannelCard.tsx6
-rw-r--r--src/components/Countdown.tsx70
-rw-r--r--src/pages/stats/[slug].tsx144
3 files changed, 144 insertions, 76 deletions
diff --git a/src/components/ChannelCard/ChannelCard.tsx b/src/components/ChannelCard/ChannelCard.tsx
index 8f4fa07..44541ad 100644
--- a/src/components/ChannelCard/ChannelCard.tsx
+++ b/src/components/ChannelCard/ChannelCard.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import Image from 'next/image';
+import Countdown from '../Countdown';
type ChannelCardProps = {
channel_id: string;
@@ -78,8 +79,11 @@ const ChannelCard: React.FC<ChannelCardProps> = ({
Next Milestone: {Number(nextMilestone).toLocaleString()}
</p>
<p className="text-xs sm:text-sm text-gray-300">
- Estimated in {nextMilestoneDays} days ({nextMilestoneDate})
+ Estimated Date: {nextMilestoneDate}
</p>
+ <div className="flex justify-center">
+ <Countdown targetDate={nextMilestoneDate} />
+ </div>
</div>
<button
onClick={() => window.open(`https://youtube.com/channel/${channel_id}`, '_blank')}
diff --git a/src/components/Countdown.tsx b/src/components/Countdown.tsx
new file mode 100644
index 0000000..69e4bd0
--- /dev/null
+++ b/src/components/Countdown.tsx
@@ -0,0 +1,70 @@
+import React, { useEffect, useState } from 'react';
+
+interface CountdownProps {
+ targetDate: string;
+}
+
+const Countdown: React.FC<CountdownProps> = ({ targetDate }) => {
+ const calculateTimeLeft = () => {
+ const difference = new Date(targetDate).getTime() - new Date().getTime();
+ let timeLeft = {
+ days: '0',
+ hours: '0',
+ minutes: '0',
+ seconds: '0',
+ };
+
+ if (difference > 0) {
+ timeLeft = {
+ days: Math.floor(difference / (1000 * 60 * 60 * 24)).toString(),
+ hours: Math.floor((difference / (1000 * 60 * 60)) % 24).toString(),
+ minutes: Math.floor((difference / 1000 / 60) % 60).toString(),
+ seconds: Math.floor((difference / 1000) % 60).toString(),
+ };
+ }
+
+ return timeLeft;
+ };
+
+ const [timeLeft, setTimeLeft] = useState({
+ days: '--',
+ hours: '--',
+ minutes: '--',
+ seconds: '--',
+ });
+
+ useEffect(() => {
+ setTimeLeft(calculateTimeLeft());
+
+ const timer = setInterval(() => {
+ setTimeLeft(calculateTimeLeft());
+ }, 1000);
+
+ return () => clearInterval(timer);
+ }, [targetDate]);
+
+ return (
+ <div className="bg-gray-700 text-white font-sans">
+ <div className="flex gap-2 text-2xl font-bold">
+ <div className="flex flex-col items-center">
+ <div className="text-4xl">{timeLeft.days}</div>
+ <div className="text-xs uppercase">Days</div>
+ </div>
+ <div className="flex flex-col items-center">
+ <div className="text-4xl">{timeLeft.hours}</div>
+ <div className="text-xs uppercase">Hours</div>
+ </div>
+ <div className="flex flex-col items-center">
+ <div className="text-4xl">{timeLeft.minutes}</div>
+ <div className="text-xs uppercase">Minutes</div>
+ </div>
+ <div className="flex flex-col items-center">
+ <div className="text-4xl">{timeLeft.seconds}</div>
+ <div className="text-xs uppercase">Seconds</div>
+ </div>
+ </div>
+ </div>
+ );
+};
+
+export default Countdown; \ No newline at end of file
diff --git a/src/pages/stats/[slug].tsx b/src/pages/stats/[slug].tsx
index 8288dbf..f70fd69 100644
--- a/src/pages/stats/[slug].tsx
+++ b/src/pages/stats/[slug].tsx
@@ -7,6 +7,7 @@ import Footer from "@/components/Footer/Footer";
import ChannelCard from "@/components/ChannelCard/ChannelCard"
import Head from "next/head";
import TitleBar from "../../components/TitleBar/TitleBar";
+import Countdown from "@/components/Countdown";
interface ChannelDataProp {
channel_id: string;
@@ -56,90 +57,83 @@ function Page({
sevenDayGraphData,
slug,
milestoneData,
-}: {
+ }: {
chartData: GraphDataProp;
channelData: ChannelDataProp;
sevenDayGraphData: GraphDataProp;
slug: string;
milestoneData: CompactTableProps;
-}) {
- console.log(milestoneData);
+ }) {
return (
- <>
- <Head>
- <title>{slug as string} - PhaseTracker</title>
- <meta
- property="og:title"
- content={`${slug as string} - PhaseTracker`}
- />
- <meta
- name="description"
- content={`Belonging to ${channelData.sub_org} with ${channelData.subscribers} subscribers`}
- />
- <meta
- name="og:description"
- content={`${channelData.sub_org} - ${channelData.subscribers}`}
- />
- <meta property="og:image" content={`${channelData.profile_pic}`} />
- <meta
- name="viewport"
- content="width=device-width, initial-scale=1.0"
- ></meta>
- <meta name="author" content="Pinapelz"></meta>
- </Head>
- <TitleBar
- title={slug as string}
- redirectUrl="/"
- showHomeButton
- backgroundColor="black"
- />
- <div className="flex justify-center px-12 ">
- <ChannelCard
- channel_id={channelData.channel_id}
- name={channelData.channel_name}
- avatarUrl={channelData.profile_pic}
- subscriberCount={channelData.subscribers}
- videoCount={channelData.video_count}
- viewCount={channelData.view_count}
- suborg={channelData.sub_org}
- nextMilestone={channelData.next_milestone}
- nextMilestoneDays={channelData.days_until_next_milestone}
- nextMilestoneDate={channelData.next_milestone_date}
- />
+ <>
+ <Head>
+ <title>{slug as string} - PhaseTracker</title>
+ <meta property="og:title" content={`${slug as string} - PhaseTracker`} />
+ <meta
+ name="description"
+ content={`Belonging to ${channelData.sub_org} with ${channelData.subscribers} subscribers`}
+ />
+ <meta
+ name="og:description"
+ content={`${channelData.sub_org} - ${channelData.subscribers}`}
+ />
+ <meta property="og:image" content={`${channelData.profile_pic}`} />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"></meta>
+ <meta name="author" content="Pinapelz"></meta>
+ </Head>
+ <TitleBar
+ title={slug as string}
+ redirectUrl="/"
+ showHomeButton
+ backgroundColor="black"
+ />
+ <div className="flex justify-center px-12">
+ <ChannelCard
+ channel_id={channelData.channel_id}
+ name={channelData.channel_name}
+ avatarUrl={channelData.profile_pic}
+ subscriberCount={channelData.subscribers}
+ videoCount={channelData.video_count}
+ viewCount={channelData.view_count}
+ suborg={channelData.sub_org}
+ nextMilestone={channelData.next_milestone}
+ nextMilestoneDays={channelData.days_until_next_milestone}
+ nextMilestoneDate={channelData.next_milestone_date}
+ />
+ </div>
+ <div className="hidden sm:block">
+ <Divider text="Individual Data" description="Data before collection start date are not shown" />
+ <div className="px-48 mb-10 mt-10">
+ <div className="mb-12">
+ <DataChart
+ overrideBGColor="black"
+ overrideBorderColor="black"
+ chartData={chartData}
+ />
</div>
- <div className="hidden sm:block">
- <Divider text="Individual Data" description="Data before collection start date are not shown" />
- <div className="px-48 mb-10 mt-10">
- <div className="mb-12">
- <DataChart
- overrideBGColor="black"
- overrideBorderColor="black"
- chartData={chartData}
- />
- </div>
- <div className="mb-12">
- <DataChart
- chartData={sevenDayGraphData}
- overrideBGColor="black"
- overrideBorderColor="black"
- graphTitle="7 Day Historical"
- />
- </div>
- </div>
- <Divider text="Milestones" description="Approximations are shown for milestones before data collection started" />
- <div className="mb-12 mx-24">
- <CompactTable
- tableData={{
- dates: milestoneData.dates,
- milestones: milestoneData.milestones,
- }}
- />
- </div>
+ <div className="mb-12">
+ <DataChart
+ chartData={sevenDayGraphData}
+ overrideBGColor="black"
+ overrideBorderColor="black"
+ graphTitle="7 Day Historical"
+ />
</div>
- <Footer />
- </>
+ </div>
+ <Divider text="Historical Milestones" description="Approximations are shown for milestones before data collection started" />
+ <div className="mb-12 mx-24">
+ <CompactTable
+ tableData={{
+ dates: milestoneData.dates,
+ milestones: milestoneData.milestones,
+ }}
+ />
+ </div>
+ </div>
+ <Footer />
+ </>
);
-}
+ }
async function getGraphData(slug: string) {
const encodedSlug = encodeURIComponent(slug as string);
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage