diff --git a/.gitignore b/.gitignore index fd3dbb5..ac9035f 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# config +config.tsx \ No newline at end of file diff --git a/src/app/components/EventCard.tsx b/src/app/components/EventCard.tsx index 534c56d..cebd251 100644 --- a/src/app/components/EventCard.tsx +++ b/src/app/components/EventCard.tsx @@ -21,14 +21,26 @@ interface Place { timeDiffMs?: number; } +interface EventCardProps { + recurringTimeAhead: string; + specialTimeAhead: string; + placeTimeAhead: string; +} + const recurringEvents: RecurringEvent[] = eventItems.recurring_events; const specialEvents: SpecialEvent[] = eventItems.special_events; const places: Place[] = eventItems.places.map((place: any) => ({ name: place.name, - closingHours: new Map(place.closing_times.map((time: any) => [time.day, time.time])), + closingHours: new Map( + place.closing_times.map((time: any) => [time.day, time.time]) + ), })); -const EventCard: React.FC = () => { +const EventCard: React.FC = ({ + recurringTimeAhead, + specialTimeAhead, + placeTimeAhead, +}) => { const [upcomingEvents, setUpcomingEvents] = useState< (RecurringEvent | SpecialEvent | Place)[] >([]); @@ -36,21 +48,24 @@ const EventCard: React.FC = () => { useEffect(() => { const updateEvents = () => { const now = new Date(); - // Handle recurring events + // handle recurring events const eventsWithCountdown = recurringEvents.map((event) => { - const eventTime = getNextRecurringEvent(event.day, event.time || "00:00"); + const eventTime = getNextRecurringEvent( + event.day, + event.time || "00:00" + ); const timeDiffMs = eventTime.getTime() - now.getTime(); return { ...event, timeDiffMs }; }); - // Handle places' closing times + // handle places' closing times const placesWithCountdown = places.map((place) => { const closingTime = getNextClosingTime(place.closingHours); const timeDiffMs = closingTime.getTime() - now.getTime(); return { ...place, timeDiffMs }; }); - // Handle special events + // handle special events const specialEventsWithCountdown = specialEvents.map((event) => { const eventTime = new Date(`${event.date}T${event.time}`); const timeDiffMs = eventTime.getTime() - now.getTime(); @@ -59,17 +74,23 @@ const EventCard: React.FC = () => { const filteredEvents = [ ...eventsWithCountdown.filter( - (event) => event.timeDiffMs! > 0 && event.timeDiffMs! <= 48 * 60 * 60 * 1000 - ), - ...placesWithCountdown.filter( - (place) => place.timeDiffMs! > 0 && place.timeDiffMs! <= 4 * 60 * 60 * 1000 + (event) => + event.timeDiffMs! > 0 && + event.timeDiffMs! <= parseInt(recurringTimeAhead) * 60 * 60 * 1000 // 4 days ), ...specialEventsWithCountdown.filter( - (event) => event.timeDiffMs! > 0 && event.timeDiffMs! <= 48 * 60 * 60 * 1000 + (event) => + event.timeDiffMs! > 0 && + event.timeDiffMs! <= parseInt(specialTimeAhead) * 60 * 60 * 1000 // 4 days + ), + ...placesWithCountdown.filter( + (place) => + place.timeDiffMs! > 0 && + place.timeDiffMs! <= parseInt(placeTimeAhead) * 60 * 60 * 1000 // 4 hours ), ]; - // Sort events by time difference + // sort events by time difference filteredEvents.sort((a, b) => a.timeDiffMs! - b.timeDiffMs!); setUpcomingEvents(filteredEvents); @@ -85,13 +106,18 @@ const EventCard: React.FC = () => {
{upcomingEvents.map((event) => ( -
+
-

{'closingHours' in event ? "Closing" : "Event"}

-

{event.name}

+

+ {"closingHours" in event ? "Closing" : "Event"} +

+

{event.name}

-

{getTimeDifference(event.timeDiffMs ?? 0)}

+

{getTimeDifference(event.timeDiffMs ?? 0)}

))} @@ -103,11 +129,11 @@ const EventCard: React.FC = () => { const getNextRecurringEvent = (day: string, time: string): Date => { /** * Returns the next occurrence of a recurring event. - * + * * @param {string} day - The day of the week the event occurs on. * @param {string} time - The time of day the event occurs at. * @returns {Date} The next occurrence of the event. - * + * */ const daysOfWeek: { [key: string]: number } = { Sunday: 0, @@ -145,18 +171,18 @@ const getNextRecurringEvent = (day: string, time: string): Date => { const getNextClosingTime = (closingHours: Map): Date => { /** * Returns the next closing time for a place. - * + * * @param {Map} closingHours - A map of closing times for each day of the week. - * + * * @returns {Date} The next closing time for the place. - * + * */ const now = new Date(); const currentDay = now.toLocaleDateString("en-US", { weekday: "long" }); const closingTime = closingHours.get(currentDay); if (!closingTime) { - return now; // If no closing time for today, return now (or handle differently) + return now; } const [closingHour, closingMinute] = closingTime.split(":").map(Number); @@ -164,12 +190,15 @@ const getNextClosingTime = (closingHours: Map): Date => { closingDate.setHours(closingHour, closingMinute, 0, 0); if (now > closingDate) { - // If already past today's closing time, get the next day's closing time const nextDay = new Date(now.getTime() + 24 * 60 * 60 * 1000); // add 1 day - const nextDayName = nextDay.toLocaleDateString("en-US", { weekday: "long" }); + const nextDayName = nextDay.toLocaleDateString("en-US", { + weekday: "long", + }); const nextClosingTime = closingHours.get(nextDayName); if (nextClosingTime) { - const [nextClosingHour, nextClosingMinute] = nextClosingTime.split(":").map(Number); + const [nextClosingHour, nextClosingMinute] = nextClosingTime + .split(":") + .map(Number); closingDate.setDate(closingDate.getDate() + 1); // Move to the next day closingDate.setHours(nextClosingHour, nextClosingMinute, 0, 0); } @@ -181,11 +210,11 @@ const getNextClosingTime = (closingHours: Map): Date => { const getTimeDifference = (timeDiff: number): string => { /** * Returns a human-readable string representing the time difference. - * + * * @param {number} timeDiff - The time difference in milliseconds. - * + * * @returns {string} A human-readable string representing the time difference. - * + * */ const msInHour = 1000 * 60 * 60; const msInDay = msInHour * 24; diff --git a/src/app/components/InfoCard.tsx b/src/app/components/InfoCard.tsx index f01025b..62bdcea 100644 --- a/src/app/components/InfoCard.tsx +++ b/src/app/components/InfoCard.tsx @@ -1 +1,38 @@ -import React, { useEffect, useState } from "react"; \ No newline at end of file +import React, { useEffect, useState } from "react"; +import vipps from "../../public/images/vipps.png"; +import Image from 'next/image'; +import SanityPeople from "../people"; +import SanityEvents from "../events"; + +const InfoCard: React.FC = () => { + interface Person { + name: string; + telephone: string; + } + + interface Event { + name: string; + date: string; + time: string; + timeDiffMs?: number; + } + + const data: Person[] = SanityPeople(); + const person = data.find((person: Person) => person.telephone) || { name: "", telephone: "" }; + + return ( +
+
+
+ Vipps +
+
+

{person.name}

+

{person.telephone}

+
+
+
+ ); +}; + +export default InfoCard; diff --git a/src/app/components/MenuCard.tsx b/src/app/components/MenuCard.tsx index 9d67206..083787f 100644 --- a/src/app/components/MenuCard.tsx +++ b/src/app/components/MenuCard.tsx @@ -1,6 +1,7 @@ import React from "react"; import menuItems from "../../public/menuItems.json"; import MenuSection from "./MenuSection"; +import InfoCard from "./InfoCard"; function MenuCard() { return ( @@ -16,9 +17,9 @@ function MenuCard() { {/*bottom box*/} -
-

Info

-
+ + +
diff --git a/src/app/components/MenuSection.tsx b/src/app/components/MenuSection.tsx index 942f061..212a993 100644 --- a/src/app/components/MenuSection.tsx +++ b/src/app/components/MenuSection.tsx @@ -28,7 +28,7 @@ const MenuSection: React.FC = ({ title, items }) => {
{items.map((item) => (
-

kr {item.price}

+

kr {item.price}

))}
diff --git a/src/app/components/TemperatureCard.tsx b/src/app/components/TemperatureCard.tsx index 41c1be0..5326005 100644 --- a/src/app/components/TemperatureCard.tsx +++ b/src/app/components/TemperatureCard.tsx @@ -11,7 +11,7 @@ const TemperatureCard: React.FC = ({ fiveHourForecast, }) => { return ( -
+
{/* two vertical containers */}
{/* left container */} @@ -23,10 +23,10 @@ const TemperatureCard: React.FC = ({
-
+
{precipitation + " mm"}
-
+
{wind.speed + "(" + wind.gust + ") m/s"}
@@ -41,8 +41,8 @@ const TemperatureCard: React.FC = ({ className="flex flex-1 flex-col bg-primary rounded-lg gap-3 p-3 place-content-center" >
-
{item.time}
-
{item.temperature}°
+
{item.time}
+
{item.temperature}°
))} diff --git a/src/app/components/TimeCard.tsx b/src/app/components/TimeCard.tsx index 80c7c60..fcf1848 100644 --- a/src/app/components/TimeCard.tsx +++ b/src/app/components/TimeCard.tsx @@ -24,26 +24,48 @@ function TimeCard() { const formatDate = (date: Date) => { const day = date.getDate().toString().padStart(2, "0"); + const ending = findDateEnding(date); const month = (date.getMonth() + 1).toString().padStart(2, "0"); + const monthText = date.toLocaleString("default", { month: "long" }); const year = date.getFullYear(); - return `${day}.${month}.${year}`; - } + return `${day}${ending} ${monthText} ${year}`; + }; const day = (date: Date) => { - const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + const days = [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + ]; return days[date.getDay()]; - } + }; + + const findDateEnding = (date: Date) => { + const day = date.getDate(); + + if (day === 1 || day === 21 || day === 31) { + return "st"; + } else if (day === 2 || day === 22) { + return "nd"; + } else if (day === 3 || day === 23) { + return "rd"; + } else { + return "th"; + } + }; return (
-
-

{formatDate(date)}

-
- {formatTime(time)} -
-

{day(date)}

+
+

{formatDate(date)}

+
{formatTime(time)}
+

{day(date)}

diff --git a/src/app/events.tsx b/src/app/events.tsx new file mode 100644 index 0000000..cdad87b --- /dev/null +++ b/src/app/events.tsx @@ -0,0 +1,36 @@ +import React, { useEffect, useState } from "react"; + +const SanityEvents = () => { + const [events, setEvents] = useState([]); + + const projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID; + const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET; + + useEffect(() => { + const fetchData = async () => { + const query = encodeURIComponent('*[_type == "event"]'); + const url = `https://${projectId}.api.sanity.io/v1/data/query/${dataset}?query=${query}`; + + try { + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + const data = await response.json(); + setEvents(data.result); + + } catch (error) { + console.error("Error fetching data:", error); + } + }; + + fetchData(); + }, [projectId, dataset]); + + return event; +} + +export default SanityEvents; \ No newline at end of file diff --git a/src/app/globals.css b/src/app/globals.css index c7283a8..1f2da10 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -7,6 +7,7 @@ --foreground: #261F31; --primary: #392e49; --headers: #D64097; + --overlay: #4A3B61; } @media (prefers-color-scheme: dark) { @@ -15,6 +16,7 @@ --foreground: #261F31; --primary: #392e49; --headers: #D64097; + --overlay: #4A3B61; } } @@ -42,21 +44,24 @@ p { color: white !important; } -.forecasts { +.para { font-family: var(--font-nunito); font-weight: 400; + font-size: 1rem; + color: white !important; +} + +.parabold { + font-family: var(--font-nunito); + font-weight: 800; + font-size: 1rem; color: white !important; } .time { font-family: var(--font-nunito); font-weight: 800; - color: white !important; -} - -.event-type { - font-family: var(--font-nunito); - font-weight: 800; + font-size: 2rem; color: white !important; } diff --git a/src/app/page.tsx b/src/app/page.tsx index 6127e06..6656bca 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -73,14 +73,16 @@ export default function Home() { const currentTime = new Date(); const timeseries = data.properties.timeseries; - const nearest = data.properties.timeseries.reduce((prev: { time: string }, curr: { time: string }) => { - const prevTime = new Date(prev.time); - const currTime = new Date(curr.time); - return Math.abs(currTime.getTime() - currentTime.getTime()) < - Math.abs(prevTime.getTime() - currentTime.getTime()) - ? curr - : prev; - }); + const nearest = data.properties.timeseries.reduce( + (prev: { time: string }, curr: { time: string }) => { + const prevTime = new Date(prev.time); + const currTime = new Date(curr.time); + return Math.abs(currTime.getTime() - currentTime.getTime()) < + Math.abs(prevTime.getTime() - currentTime.getTime()) + ? curr + : prev; + } + ); setnearestHour(nearest.time); @@ -146,10 +148,12 @@ export default function Home() { wind={currentWind} fiveHourForecast={nextThreeHours} /> - + - -
); } diff --git a/src/app/people.tsx b/src/app/people.tsx new file mode 100644 index 0000000..3e0299f --- /dev/null +++ b/src/app/people.tsx @@ -0,0 +1,36 @@ +import React, { useEffect, useState } from "react"; + +const SanityPeople = () => { + const [people, setPeople] = useState([]); + + const projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID; + const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET; + + useEffect(() => { + const fetchData = async () => { + const query = encodeURIComponent('*[_type == "author"]'); + const url = `https://${projectId}.api.sanity.io/v1/data/query/${dataset}?query=${query}`; + + try { + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + const data = await response.json(); + setPeople(data.result); + + } catch (error) { + console.error("Error fetching data:", error); + } + }; + + fetchData(); + }, [projectId, dataset]); + + return people; +} + +export default SanityPeople; \ No newline at end of file diff --git a/src/public/images/ember_vipps.png b/src/public/images/vipps.png similarity index 100% rename from src/public/images/ember_vipps.png rename to src/public/images/vipps.png diff --git a/tailwind.config.ts b/tailwind.config.ts index 3cb3cc8..5dcdb78 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -14,6 +14,7 @@ const config: Config = { foreground: "var(--foreground)", primary: "var(--primary)", headers: "var(--headers)", + overlay: "var(--overlay)", }, }, },