diff --git a/src/app/october/page.tsx b/src/app/october/page.tsx new file mode 100644 index 0000000..2ff7887 --- /dev/null +++ b/src/app/october/page.tsx @@ -0,0 +1,18 @@ +import type { Metadata } from "next"; +import { Suspense } from "react"; +import { OctoberCounter } from "~/components/OctoberCounter"; + +export const metadata: Metadata = { + title: "October Today | Sean O'Connor", + description: "See what day of October 2019 it is today.", +}; + +export default function OctoberPage() { + return ( +
+ + + +
+ ); +} diff --git a/src/components/OctoberCounter.tsx b/src/components/OctoberCounter.tsx new file mode 100644 index 0000000..9470aee --- /dev/null +++ b/src/components/OctoberCounter.tsx @@ -0,0 +1,135 @@ +"use client"; + +import { useEffect, useState } from "react"; +import Link from "next/link"; +import { useSearchParams } from "next/navigation"; +import { CircleHelp, Share2 } from "lucide-react"; +import { Button } from "~/components/ui/button"; +import { Card, CardContent } from "~/components/ui/card"; + +const OCTOBER_FIRST_2019 = Date.UTC(2019, 9, 1); +const MILLISECONDS_PER_DAY = 1000 * 60 * 60 * 24; + +function getOrdinalSuffix(number: number) { + if (number % 100 >= 11 && number % 100 <= 13) { + return "th"; + } + + switch (number % 10) { + case 1: + return "st"; + case 2: + return "nd"; + case 3: + return "rd"; + default: + return "th"; + } +} + +function getOctoberDay(today: Date) { + const todayUtc = Date.UTC( + today.getFullYear(), + today.getMonth(), + today.getDate(), + ); + + return Math.floor((todayUtc - OCTOBER_FIRST_2019) / MILLISECONDS_PER_DAY) + 1; +} + +export function OctoberCounter() { + const searchParams = useSearchParams(); + const isJsonMode = searchParams.get("api") === "json"; + const [targetDay] = useState(() => getOctoberDay(new Date())); + const [day, setDay] = useState(() => + isJsonMode ? targetDay : Math.max(1, targetDay - 50), + ); + const isAnimating = !isJsonMode && day < targetDay; + const ordinal = getOrdinalSuffix(targetDay); + + useEffect(() => { + if (isJsonMode) return; + + let currentNumber = Math.max(1, targetDay - 50); + + const interval = window.setInterval(() => { + currentNumber += 1; + setDay(currentNumber); + + if (currentNumber >= targetDay) { + window.clearInterval(interval); + document.title = `October ${targetDay}${ordinal}, 2019`; + } + }, 30); + + return () => window.clearInterval(interval); + }, [isJsonMode, ordinal, targetDay]); + + if (isJsonMode) { + const response = { + day, + ordinal, + formatted: `${day}${ordinal}`, + text: `happy october ${day}${ordinal}`, + }; + + return ( +
+        {JSON.stringify(response, null, 2)}
+      
+ ); + } + + const handleShare = () => { + const message = `happy october ${day}${ordinal}`; + window.open(`sms:?&body=${encodeURIComponent(message)}`, "_blank"); + }; + + return ( + +
+ +

+ Today is +

+ +
+

+ October{" "} + + {day} + + + {isAnimating ? "th" : ordinal} +

+

2019.

+
+ +
+ + + +
+
+ + ); +}