diff options
| author | Factiven <[email protected]> | 2023-12-24 13:03:54 +0700 |
|---|---|---|
| committer | Factiven <[email protected]> | 2023-12-24 13:03:54 +0700 |
| commit | 50a0f0240d7fef133eb5acc1bea2b1168b08e9db (patch) | |
| tree | 307e09e505580415a58d64b5fc3580e9235869f1 /pages/en/schedule/index.js | |
| parent | Update README.md (#104) (diff) | |
| download | moopa-50a0f0240d7fef133eb5acc1bea2b1168b08e9db.tar.xz moopa-50a0f0240d7fef133eb5acc1bea2b1168b08e9db.zip | |
migrate to typescript
Diffstat (limited to 'pages/en/schedule/index.js')
| -rw-r--r-- | pages/en/schedule/index.js | 485 |
1 files changed, 0 insertions, 485 deletions
diff --git a/pages/en/schedule/index.js b/pages/en/schedule/index.js deleted file mode 100644 index f1e6730..0000000 --- a/pages/en/schedule/index.js +++ /dev/null @@ -1,485 +0,0 @@ -import Image from "next/image"; -import { useEffect, useRef, useState } from "react"; -import Link from "next/link"; -import { CalendarIcon } from "@heroicons/react/24/solid"; -import { ClockIcon } from "@heroicons/react/24/outline"; -import Loading from "@/components/shared/loading"; -import { timeStamptoAMPM, timeStamptoHour } from "@/utils/getTimes"; -import { - filterFormattedSchedule, - filterScheduleByDay, - sortScheduleByDay, - transformSchedule, -} from "@/utils/schedulesUtils"; - -import { scheduleQuery } from "@/lib/graphql/query"; -import MobileNav from "@/components/shared/MobileNav"; - -import { useSession } from "next-auth/react"; -import { redis } from "@/lib/redis"; -import Head from "next/head"; -import { NewNavbar } from "@/components/shared/NavBar"; - -const day = [ - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", -]; - -const isAired = (timestamp) => { - const currentTime = new Date().getTime() / 1000; - return timestamp <= currentTime; -}; - -export async function getServerSideProps() { - const now = new Date(); - // Adjust for Japan timezone (add 9 hours) - const nowJapan = new Date(now.getTime() + 9 * 60 * 60 * 1000); - - // Calculate the time until midnight of the next day in Japan timezone - const midnightTomorrowJapan = new Date( - nowJapan.getFullYear(), - nowJapan.getMonth(), - nowJapan.getDate() + 1, - 0, - 0, - 0, - 0 - ); - const timeUntilMidnightJapan = Math.round( - (midnightTomorrowJapan - nowJapan) / 1000 - ); - - let cachedData; - - // Check if the data is already in Redis - if (redis) { - cachedData = await redis.get("new_schedule"); - } - - if (cachedData) { - const scheduleByDay = JSON.parse(cachedData); - - return { - props: { - schedule: scheduleByDay, - // today: todaySchedule, - }, - }; - } else { - now.setHours(0, 0, 0, 0); // Set the time to 00:00:00.000 - const dayInSeconds = 86400; // Number of seconds in a day - const yesterdayStart = Math.floor(now.getTime() / 1000) - dayInSeconds; - // Calculate weekStart from yesterday's 00:00:00 - const weekStart = yesterdayStart; - const weekEnd = weekStart + 604800; - - let page = 1; - const airingSchedules = []; - - while (true) { - const res = await fetch("https://graphql.anilist.co", { - method: "POST", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - }, - body: JSON.stringify({ - query: scheduleQuery, - variables: { - weekStart, - weekEnd, - page, - }, - }), - }); - - const json = await res.json(); - const schedules = json.data.Page.airingSchedules; - - if (schedules.length === 0) { - break; // No more data to fetch - } - - airingSchedules.push(...schedules); - page++; - } - - const timestampToDay = (timestamp) => { - const options = { weekday: "long" }; - return new Date(timestamp * 1000).toLocaleDateString(undefined, options); - }; - - const scheduleByDay = {}; - airingSchedules.forEach((schedule) => { - const day = timestampToDay(schedule.airingAt); - if (!scheduleByDay[day]) { - scheduleByDay[day] = []; - } - scheduleByDay[day].push(schedule); - }); - - if (redis) { - await redis.set( - "new_schedule", - JSON.stringify(scheduleByDay), - "EX", - timeUntilMidnightJapan - ); - } - - return { - props: { - schedule: scheduleByDay, - // today: todaySchedule, - }, - }; - } - // setSchedule(scheduleByDay); -} - -export default function Schedule({ schedule }) { - const { data: session } = useSession(); - - // const [schedule, setSchedule] = useState({}); - const [filterDay, setFilterDay] = useState("All"); - const [loading, setLoading] = useState(true); - - useEffect(() => { - setLoading(true); - async function setDay() { - const now = new Date(); - const today = day[now.getDay()]; - setFilterDay(today); - setLoading(false); - } - setDay(); - }, []); - // Sort the schedule object by day, placing today's schedule first - const sortedSchedule = sortScheduleByDay(schedule); - const formattedSchedule = transformSchedule(schedule); - - // State to keep track of the next airing anime - const [nextAiringAnime, setNextAiringAnime] = useState(null); - // const [nextAiringBanner, setNextAiringBanner] = useState(null); - - // State to keep track of the currently airing anime - const [currentlyAiringAnime, setCurrentlyAiringAnime] = useState(null); - - const [layout, setLayout] = useState(1); - - // Effect to update the next and currently airing anime - useEffect(() => { - const now = new Date().getTime() / 1000; // Current time in seconds - let nextAiring = null; - let currentlyAiring = null; - - for (const [, schedules] of Object.entries(sortedSchedule)) { - for (const s of schedules) { - if (s.airingAt > now) { - if (!nextAiring) { - nextAiring = s.id; - // setNextAiringBanner(s.media.bannerImage); - } - } else if (s.airingAt + 1440 > now) { - currentlyAiring = s.id; - } - } - if (nextAiring && currentlyAiring) break; - } - - setNextAiringAnime(nextAiring); - setCurrentlyAiringAnime(currentlyAiring); - }, [sortedSchedule]); - - const scrollContainerRef = useRef(null); - - useEffect(() => { - // Scroll to center the active button when it changes - if (scrollContainerRef.current) { - const activeButton = - scrollContainerRef.current.querySelector(".text-action"); - if (activeButton) { - const containerWidth = scrollContainerRef.current.clientWidth; - const buttonLeft = activeButton.offsetLeft; - const buttonWidth = activeButton.clientWidth; - const scrollLeft = buttonLeft - containerWidth / 2 + buttonWidth / 2; - scrollContainerRef.current.scrollLeft = scrollLeft; - } - } - }, [filterDay]); - - return ( - <> - <Head> - <title>Moopa - Schedule</title> - {/* write a meta with good seo for this page */} - <meta - name="description" - content="Moopa is a website where you can find all the information about your favorite anime and manga." - /> - <meta - name="keywords" - content="anime, manga, moopa, anilist, information, schedule, airing, next, currently, airing, anime, manga" - /> - <meta name="robots" content="index, follow" /> - <meta name="author" content="Moopa Team" /> - <meta name="url" content="https://moopa.live/en/schedule" /> - <meta name="og:title" property="og:title" content="Moopa - Schedule" /> - <meta - name="og:description" - property="og:description" - content="Moopa is a website where you can find all the information about your favorite anime and manga." - /> - <meta property="og:type" content="website" /> - <meta property="og:url" content="https://moopa.live/en/schedule" /> - <meta - property="og:image" - content="https://beta.moopa.live/preview.png" - /> - <meta - property="og:image:alt" - content="Moopa is a website where you can find all the information about your favorite anime and manga." - /> - <meta property="og:locale" content="en_US" /> - <meta property="og:site_name" content="Moopa" /> - <meta name="twitter:card" content="summary_large_image" /> - {/* <meta name="twitter:site" content="@moopa_anime" /> - <meta name="twitter:creator" content="@moopa_anime" /> */} - <meta - name="twitter:image" - content="https://beta.moopa.live/preview.png" - /> - <meta - name="twitter:image:alt" - content="Moopa is a website where you can find all the information about your favorite anime and manga." - /> - <meta name="twitter:title" content="Moopa - Schedule" /> - <meta - name="twitter:description" - content="Moopa is a website where you can find all the information about your favorite anime and manga." - /> - </Head> - <MobileNav sessions={session} hideProfile={true} /> - <NewNavbar scrollP={10} toTop={true} /> - <div className="w-screen"> - <span className="absolute z-20 top-0 left-0 w-screen h-[190px] lg:h-[250px] bg-secondary overflow-hidden"> - <div className="absolute top-40 lg:top-36 w-full h-full bg-primary rounded-t-3xl xl:rounded-t-[50px]" /> - </span> - <div className="flex flex-col mx-auto my-10 w-full mt-16 lg:mt-24 max-w-screen-2xl gap-5 md:gap-10 z-30"> - <div className="flex flex-col lg:flex-row gap-2 justify-between z-20 px-3"> - <ul - ref={scrollContainerRef} - className="flex overflow-x-scroll cust-scroll items-center gap-5 font-karla text-2xl font-semibold" - > - <button - type="button" - onClick={() => setFilterDay("All")} - className={`hover:text-action transition-all duration-200 ease-out cursor-pointer ${ - filterDay === "All" ? "text-action" : "" - }`} - > - All - </button> - {day.map((i) => ( - <button - key={i} - // id={`same_${i}`} - type="button" - onClick={() => { - setLoading(true); - setFilterDay(i); - setLoading(false); - }} - className={`py-2 lg:py-0 outline-none hover:text-action transition-all duration-200 ease-out cursor-pointer ${ - filterDay === i ? "text-action" : "" - }`} - > - {i} - </button> - ))} - </ul> - <div className="flex gap-3"> - <ClockIcon - className={`w-6 h-6 cursor-pointer ${ - layout === 1 ? "text-action" : "text-white" - }`} - onClick={() => setLayout(1)} - /> - <CalendarIcon - className={`w-6 h-6 cursor-pointer ${ - layout === 2 ? "text-action" : "text-white" - }`} - onClick={() => setLayout(2)} - /> - </div> - </div> - - {layout === 1 ? ( - !loading ? ( - Object.entries( - filterFormattedSchedule(formattedSchedule, filterDay) - ).map(([day, timeSlots], index) => ( - <div - key={`section_${day}`} - // id={`same_${day}`} - className="flex flex-col gap-5 z-50 px-3" - > - <h2 className="font-bold font-outfit text-white text-2xl z-[250]"> - {day} - </h2> - {Object.entries(timeSlots).map(([time, animeList]) => ( - <div - key={time} - // id={`same_${time}`} - className="relative space-y-2" - > - <div className="ml-4 flex items-center gap-2"> - <h3 className="text-lg text-gray-200 font-semibold"> - {timeStamptoAMPM(time)} - </h3> - {/* {!isAired(time) && <p>Airing Next</p>} */} - <p - className={`absolute left-0 h-1.5 w-1.5 rounded-full ${ - isAired(time) ? "bg-action" : "bg-gray-600" // Add a class for currently airing anime - }`} - ></p> - </div> - <div className="w-full grid sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5 md:gap-7 grid-flow-row relative"> - {animeList.map((s, index) => { - const m = s.media; - return ( - <> - <Link - key={m.id} - // id={`same_${m.id}`} - href={`/en/${m.type.toLowerCase()}/${m.id}`} - className={`flex bg-secondary rounded group cursor-pointer overflow-hidden ml-4 z-50`} - > - <Image - src={m.coverImage.extraLarge} - alt="image" - width={300} - height={300} - className="w-[50px] h-[65px] object-cover shrink-0" - /> - <div className="flex flex-col justify-center font-karla p-2"> - <h1 className="font-semibold line-clamp-1 text-sm group-hover:text-action transition-all duration-200 ease-out"> - {m.title.romaji} - </h1> - <p className="text-gray-400 group-hover:text-action/80 transition-all duration-200 ease-out"> - Ep {s.episode} {timeStamptoHour(s.airingAt)} - </p> - </div> - </Link> - <p - key={`p_${s.id}_${index}`} - className={`absolute translate-x-full top-1/2 -translate-y-1/2 h-full w-0.5 ${ - isAired(time) ? "bg-action" : "bg-gray-600" // Add a class for currently airing anime - }`} - ></p> - </> - ); - })} - </div> - </div> - ))} - </div> - )) - ) : ( - <div className="z-[500] pt-10 lg:pt-0"> - <Loading /> - </div> - ) - ) : !loading ? ( - Object.entries(filterScheduleByDay(sortedSchedule, filterDay)).map( - ([day, schedules]) => ( - <div - key={`section2_${day}`} - // id={`same_${day}`} - className="flex flex-col gap-5 px-3 z-50" - > - <h2 - // id={day} - className="font-bold font-outfit text-white text-2xl" - > - {day} - </h2> - <div className="w-full grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-5 md:gap-7 grid-flow-row"> - {schedules.map((s) => { - const m = s.media; - - return ( - <Link - key={m.id} - // id={`same_${m.id}`} - href={`/en/${m.type?.toLowerCase()}/${m.id}`} - className={`flex bg-secondary rounded group cursor-pointer relative ${ - s.id === nextAiringAnime - ? "ring-1 ring-sky-500" - : "" // Add a class for next airing anime - } ${ - s.id === currentlyAiringAnime - ? "ring-1 ring-action" - : "" // Add a class for currently airing anime - }`} - > - {/* <p className={``}> */} - <p className="absolute flex top-0 right-0 -mt-1 -mr-1 justify-center items-center"> - <span - className={`relative flex justify-center h-3 w-3 tooltip-container ${ - s.id === nextAiringAnime ? "" : "hidden" // Add a className for next airing anime - }`} - > - {/* <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-sky-400 opacity-75"></span> */} - <span className="relative inline-flex rounded-full h-3 w-3 bg-sky-500"></span> - <span className="tooltip">Next Airing</span> - </span> - </p> - <p className="absolute flex top-0 right-0 -mt-1 -mr-1 justify-center items-center"> - <span - className={`relative flex justify-center h-3 w-3 tooltip-container ${ - s.id === currentlyAiringAnime ? "" : "hidden" // Add a className for currently airing anime - }`} - > - <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-orange-400 opacity-75"></span> - <span className="relative inline-flex rounded-full h-3 w-3 bg-orange-500"></span> - <span className="tooltip">Airing Now</span> - </span> - </p> - <Image - src={m.coverImage.extraLarge} - alt="image" - width={200} - height={200} - className="w-[50px] h-[65px] object-cover shrink-0 rounded-l" - /> - <div className="flex flex-col justify-center font-karla p-2"> - <h1 className="font-semibold line-clamp-1 text-sm group-hover:text-action transition-all duration-200 ease-out"> - {m.title.romaji} - </h1> - <p className="text-gray-400 group-hover:text-action/80 transition-all duration-200 ease-out"> - Ep {s.episode} {timeStamptoHour(s.airingAt)} - </p> - </div> - </Link> - ); - })} - </div> - </div> - ) - ) - ) : ( - <div className="z-[500] pt-10 lg:pt-0"> - <Loading /> - </div> - )} - </div> - </div> - </> - ); -} |