import { JSX, useEffect, useState } from "react"; import styles from "./Calendar.module.css"; import { getMonthName, daysInMonth } from "../utils/dateUtils"; import { customerState } from "../store"; import { Box } from "../types"; import { useAtom } from "jotai"; import { markBoxDelivered, markBoxPickedUp } from "../api"; import { Modal } from "@mui/material"; export default function Calendar() { const boxStatuses = ["no boxes", "picked up", "delivered"]; //TODO: There's logic problem between "delivered" and "picked up" const [customerData, setCustomerData] = useAtom(customerState); const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth()); const [calendarCells, setCalendarCells] = useState([]); const [firstWeekPadding, setFirstWeekPadding] = useState([]); const [showLatestBoxModal, setShowLatestBoxModal] = useState(false); const [latestBoxStatus, setLatestBoxStatus] = useState(boxStatuses[0]); const [latestBox, setLatestBox] = useState({ id: "", pickup_date: null, delivery_date: new Date(), }); const [showClickedBoxModal, setShowClickedBoxModal] = useState(false); const [clickedBox, setClickedBox] = useState({ id: "", pickup_date: null, delivery_date: new Date(), }); const generateFirstWeekPadding = (month: number) => { const firstDay = new Date(new Date().getFullYear(), month, 1).getDay(); const padding = Array.from({ length: firstDay === 0 ? 6 : firstDay - 1 }, (_, index) => (
 
)); return padding; } const generateCalendarCells = (month: number, boxes: Box[]) => { const monthDays = daysInMonth[month]; const calendarCells = Array.from({ length: monthDays }, (_, index) => { const day = index + 1; const date = new Date(new Date().getFullYear(), month, day); const matchingBox = boxes.find(box => { const boxDate = new Date(box.delivery_date); return boxDate.getDate() === day && boxDate.getMonth() === month && boxDate.getFullYear() === date.getFullYear(); }); if (matchingBox) { return (
{ setClickedBox(matchingBox); setShowClickedBoxModal(true); } }> { date.toLocaleDateString("fi-FI", { day: "2-digit", month: "2-digit", }) } < br /> { matchingBox.pickup_date ? ( Haettu ) : ( Jako ) }
); } return (
{date.toLocaleDateString("fi-FI", { day: "2-digit", month: "2-digit", })}
); }); return calendarCells; } const changeClickedBoxStatus = () => { if (clickedBox.pickup_date) { // If the box is already picked up, mark it as delivered markBoxDelivered(clickedBox.id).then((updatedBox) => { setCustomerData((prev) => ({ ...prev, boxes: prev.boxes.map(box => box.id === updatedBox.id ? { ...box, pickup_date: null } : box ), })); } ).catch((error) => { console.error("Error marking box as delivered:", error); }); return; } else { markBoxPickedUp(clickedBox.id).then((updatedBox) => { setCustomerData((prev) => ({ ...prev, boxes: prev.boxes.map(box => box.id === updatedBox.id ? { ...box, pickup_date: updatedBox.pickup_date } : box ), })); } ).catch((error) => { console.error("Error marking box as picked up:", error); }) } } const renderLatestBoxButton = () => { switch (latestBoxStatus) { case "no boxes": return ; case "picked up": return ; case "delivered": return ; default: return Virhe; } } useEffect(() => { setCalendarCells(generateCalendarCells(selectedMonth, customerData.boxes)); setFirstWeekPadding(generateFirstWeekPadding(selectedMonth)); setLatestBoxStatus(() => { if (!customerData.boxes || customerData.boxes.length === 0) { return boxStatuses[0]; // no boxes } const monthBoxes = customerData.boxes.filter(box => new Date(box.delivery_date).getMonth() === selectedMonth); const deliveredBoxes = customerData.boxes.filter(box => new Date(box.delivery_date).getMonth() === selectedMonth && !box.pickup_date); if (monthBoxes.length === 0) { return boxStatuses[0]; // no boxes } if (!deliveredBoxes || deliveredBoxes.length === 0) { return boxStatuses[1]; // all boxes picked up } return boxStatuses[2]; // delivered } ); }, [selectedMonth, customerData.boxes]); const handleLatestBoxClick = (event: React.MouseEvent) => { event.preventDefault(); setShowLatestBoxModal(true); } const markLatestBoxPickedUp = () => { markBoxPickedUp(latestBox.id).then((updatedBox) => { setCustomerData((prev) => ({ ...prev, boxes: prev.boxes.map(box => box.id === updatedBox.id ? { ...box, pickup_date: updatedBox.pickup_date } : box ), })); }).catch((error) => { console.error("Error marking latest box as picked up:", error); }); } useEffect(() => { const deliveredBoxes = customerData.boxes.filter(box => new Date(box.delivery_date).getMonth() === selectedMonth && !box.pickup_date); if (deliveredBoxes.length === 0) return; const latestBox = deliveredBoxes[0]; if (latestBox) { setLatestBox(latestBox); } }, [customerData.boxes, selectedMonth]); return ( <>

{getMonthName(selectedMonth)} {new Date().getFullYear()}

{renderLatestBoxButton()}

Käyttöohje

Klikkaa laatikon päivää kuitataksesi sen haetuksi tai peruuttaaksesi haun. Jakopäivät näkyvät vaalean vihreinä. Jos laatikko on jo haettu, se näkyy tumman vihreänä.
Ma Ti Ke To Pe La Su {firstWeekPadding} {calendarCells}
setShowLatestBoxModal(false)} className={styles.boxModal} >

Viimeisin laatikko

Oletko varma, että haluat kuitata viimeisimmän laatikon ({new Date(latestBox.delivery_date).toLocaleDateString("fi-FI", { day: "2-digit", month: "2-digit", })}) haetuksi?

setShowClickedBoxModal(false)} className={styles.boxModal} >

Satolaatikko {" "} {new Date(clickedBox.delivery_date).toLocaleDateString("fi-FI", { day: "2-digit", month: "2-digit", })}

Oletko varma, että haluat {clickedBox.pickup_date ? "peruuttaa " : "kuitata "} {new Date(clickedBox.delivery_date).toLocaleDateString("fi-FI", { day: "2-digit", month: "2-digit", })} päivän laatikon {clickedBox.pickup_date ? "haun" : "haetuksi"}?

); }