Skip to content

Instantly share code, notes, and snippets.

@Shaxadhere
Created May 9, 2024 12:09
Show Gist options
  • Save Shaxadhere/7f6ed85d106bfe685b9b7f66da23634c to your computer and use it in GitHub Desktop.
Save Shaxadhere/7f6ed85d106bfe685b9b7f66da23634c to your computer and use it in GitHub Desktop.
import React, { useState } from "react";
import {
Flex,
Box,
Text,
IconButton,
Icon,
SimpleGrid,
VStack,
} from "@chakra-ui/react";
import { MdChevronLeft, MdChevronRight } from "react-icons/md";
const CalendarMonth = ({
currentDate,
setCurrentDate,
toggleYearDropdown,
isMonthDropdownOpen,
toggleMonthDropdown,
}) => {
const handleMonthChange = (month) => {
setCurrentDate(new Date(currentDate.getFullYear(), month, 1));
toggleMonthDropdown();
};
const getMonthData = (year) => {
return Array.from(
{ length: 12 },
(_, monthIndex) => new Date(year, monthIndex, 1)
);
};
const renderMonthDropdown = () => {
return isMonthDropdownOpen ? (
<Box position="absolute" zIndex="1">
<Flex
flexDirection="column"
bg="white"
boxShadow="md"
borderRadius="md"
>
{getMonthData(currentDate.getFullYear()).map((monthDate, index) => (
<Box
key={index}
p={2}
cursor="pointer"
onClick={() => handleMonthChange(index)}
_hover={{ bg: "gray.100" }}
>
<Text>
{monthDate.toLocaleString("default", { month: "long" })}
</Text>
</Box>
))}
</Flex>
</Box>
) : null;
};
return (
<Flex gap={1} alignItems="center" position="relative">
<Text onClick={toggleMonthDropdown} cursor="pointer">
{currentDate.toLocaleString("default", { month: "long" })}
</Text>
<Text onClick={toggleYearDropdown} cursor="pointer">
{currentDate.getFullYear()}
</Text>
{renderMonthDropdown()}
</Flex>
);
};
const CalendarMonth2 = ({
currentDate,
setCurrentDate,
isMonthDropdownOpen,
toggleMonthDropdown,
}) => {
const handleMonthChange = (month) => {
setCurrentDate(new Date(currentDate.getFullYear(), month, 1));
toggleMonthDropdown();
};
const getMonthData = (year) => {
return Array.from(
{ length: 12 },
(_, monthIndex) => new Date(year, monthIndex, 1)
);
};
const renderYearButtons = () => {
const currentYear = currentDate.getFullYear();
const years = [];
for (let i = currentYear - 5; i <= currentYear + 5; i++) {
years.push(i);
}
return (
<Flex px={1} py={2}>
{isMonthDropdownOpen ? (
<VStack align={"stretch"}>
<Flex justify={"space-between"} w="full">
<IconButton
aria-label="Previous Year"
icon={<Icon as={MdChevronLeft} />}
onClick={() =>
setCurrentDate(
new Date(
currentDate.getFullYear() - 1,
currentDate.getMonth(),
1
)
)
}
/>
<Text>{currentYear}</Text>
<IconButton
aria-label="Next Year"
icon={<Icon as={MdChevronRight} />}
onClick={() =>
setCurrentDate(
new Date(
currentDate.getFullYear() + 1,
currentDate.getMonth(),
1
)
)
}
/>
</Flex>
<SimpleGrid columns={3} spacing={3}>
{getMonthData(currentDate.getFullYear()).map(
(monthDate, index) => (
<Box
key={monthDate}
p={2}
cursor="pointer"
onClick={() => handleMonthChange(monthDate.getDate())}
bg={monthDate === currentYear ? "gray.200" : "transparent"}
borderRadius="md"
mx={1}
>
<Text>
{monthDate.toLocaleString("default", { month: "short" })}
</Text>
</Box>
)
)}
</SimpleGrid>
</VStack>
) : null}
</Flex>
);
};
return (
<Flex flexDirection="column" alignItems="center" position="relative">
{renderYearButtons()}
</Flex>
);
};
const CalendarYear = ({
currentDate,
setCurrentDate,
isYearDropdownOpen,
toggleYearDropdown,
}) => {
const handleYearChange = (year) => {
setCurrentDate(new Date(year, currentDate.getMonth(), 1));
toggleYearDropdown();
};
const renderYearButtons = () => {
const currentYear = currentDate.getFullYear();
const years = [];
for (let i = currentYear - 5; i <= currentYear + 5; i++) {
years.push(i);
}
return (
<Flex px={1} py={2}>
{isYearDropdownOpen ? (
<VStack align={"stretch"}>
<Flex justify={"space-between"} w="full">
<IconButton
aria-label="Previous Year"
icon={<Icon as={MdChevronLeft} />}
onClick={() =>
setCurrentDate(
new Date(
currentDate.getFullYear() - 1,
currentDate.getMonth(),
1
)
)
}
/>
<Text>{currentYear}</Text>
<IconButton
aria-label="Next Year"
icon={<Icon as={MdChevronRight} />}
onClick={() =>
setCurrentDate(
new Date(
currentDate.getFullYear() + 1,
currentDate.getMonth(),
1
)
)
}
/>
</Flex>
<SimpleGrid columns={3} spacing={3}>
{years.map((year) => (
<Box
key={year}
p={2}
cursor="pointer"
onClick={() => handleYearChange(year)}
bg={year === currentYear ? "gray.200" : "transparent"}
borderRadius="md"
mx={1}
>
<Text>{year}</Text>
</Box>
))}
</SimpleGrid>
</VStack>
) : null}
</Flex>
);
};
return (
<Flex flexDirection="column" alignItems="center" position="relative">
{renderYearButtons()}
</Flex>
);
};
const DateInput = () => {
const [isYearDropdownOpen, setIsYearDropdownOpen] = useState(false);
const [isMonthDropdownOpen, setIsMonthDropdownOpen] = useState(false);
const [currentDate, setCurrentDate] = useState(new Date());
const getMonthData = (year, month) => {
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
const monthData = [];
let day = new Date(firstDay);
while (day <= lastDay) {
monthData.push(new Date(day));
day.setDate(day.getDate() + 1);
}
return monthData;
};
const toggleYearDropdown = () => {
setIsYearDropdownOpen(!isYearDropdownOpen);
};
const toggleMonthDropdown = () => {
setIsMonthDropdownOpen(!isMonthDropdownOpen);
};
const renderCalendar = () => {
const monthData = getMonthData(
currentDate.getFullYear(),
currentDate.getMonth()
);
const firstDayOfMonth = monthData[0].getDay();
const calendar = [];
let currentWeek = [];
for (let i = 0; i < firstDayOfMonth; i++) {
currentWeek.push(null);
}
monthData.forEach((day, index) => {
currentWeek.push(day);
if (currentWeek.length === 7) {
calendar.push(currentWeek);
currentWeek = [];
}
});
while (currentWeek.length < 7) {
currentWeek.push(null);
}
calendar.push(currentWeek);
return (
<Box>
<Box>
<CalendarYear
currentDate={currentDate}
setCurrentDate={setCurrentDate}
isYearDropdownOpen={isYearDropdownOpen}
toggleYearDropdown={toggleYearDropdown}
isMonthDropdownOpen={isMonthDropdownOpen}
toggleMonthDropdown={toggleMonthDropdown}
/>
</Box>
<Box>
<CalendarMonth2
currentDate={currentDate}
setCurrentDate={setCurrentDate}
isMonthDropdownOpen={isMonthDropdownOpen}
toggleMonthDropdown={toggleMonthDropdown}
/>
</Box>
{!isYearDropdownOpen && !isMonthDropdownOpen && (
<>
<Flex justifyContent="space-between" mb={4}>
<IconButton
aria-label="Previous Month"
icon={<Icon as={MdChevronLeft} />}
onClick={() =>
setCurrentDate(
new Date(
currentDate.getFullYear(),
currentDate.getMonth() - 1
)
)
}
/>
<Flex gap={1} alignItems="center" position="relative">
<Text onClick={toggleMonthDropdown} cursor="pointer">
{currentDate.toLocaleString("default", { month: "long" })}
</Text>
<Text onClick={toggleYearDropdown} cursor="pointer">
{currentDate.getFullYear()}
</Text>
</Flex>
<IconButton
aria-label="Next Month"
icon={<Icon as={MdChevronRight} />}
onClick={() =>
setCurrentDate(
new Date(
currentDate.getFullYear(),
currentDate.getMonth() + 1
)
)
}
/>
</Flex>
<Flex flexDirection="column">
{calendar.map((week, index) => (
<Flex key={index}>
{week.map((day, index) => (
<Box
key={index}
flex="1"
textAlign="center"
p={2}
bg={
day && (day.getDay() === 0 || day.getDay() === 6)
? "yellow.200"
: "gray.100"
}
>
{day && day.getDate()}
</Box>
))}
</Flex>
))}
</Flex>
</>
)}
</Box>
);
};
return (
<Flex flexDirection="column" alignItems="center">
{renderCalendar()}
</Flex>
);
};
export default DateInput;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment