Skip to content

Instantly share code, notes, and snippets.

@angeloashmore
Created November 15, 2019 07:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save angeloashmore/c6e78a04fe02f0d4a8fe8abe605d6add to your computer and use it in GitHub Desktop.
Save angeloashmore/c6e78a04fe02f0d4a8fe8abe605d6add to your computer and use it in GitHub Desktop.
Render a calendar in React
import React, { useState, useMemo } from 'react'
import {
addMonths,
addWeeks,
format,
getTime,
getWeeksInMonth,
isSameMonth,
startOfMonth,
startOfWeek,
subMonths,
weekData,
} from 'date-fns'
import { Box, Grid, Flex, Heading, Button } from 'system'
// Returns an array of weeks with days for the month of the given date.
const monthData = (dirtyDate, weekStartsAt) => {
const date = new Date(dirtyDate)
const startDate = startOfWeek(startOfMonth(date), weekStartsAt)
const numberOfWeeks = getWeeksInMonth(date)
const month = []
for (let i = 0; i < numberOfWeeks; i++) {
const startOfWeekDate = addWeeks(startDate, i)
const week = weekData(startOfWeekDate).map(dayData => {
dayData.isSameMonth = isSameMonth(date, dayData.date)
return dayData
})
month.push(week)
}
return month
}
// Returns stateful month data with functions to increment and decrement
// months.
const useMonth = (initialDate = new Date()) => {
const [date, setDate] = useState(initialDate)
return useMemo(
() => ({
weeks: monthData(date),
date,
dec: (amount = 1) => setDate(subMonths(date, amount)),
inc: (amount = 1) => setDate(addMonths(date, amount)),
}),
[date],
)
}
export const Calendar = ({ initialDate, ...props }) => {
const { weeks, date, dec, inc } = useMonth(initialDate)
const currMonthName = useMemo(() => format(date, 'MMMM'), [date])
const prevMonthName = useMemo(() => format(subMonths(date, 1), 'MMMM'), [
date,
])
const nextMonthName = useMemo(() => format(addMonths(date, 1), 'MMMM'), [
date,
])
return (
<Box {...props}>
<Flex justifyContent="space-between">
<Button onClick={dec}>{prevMonthName}</Button>
<Heading>{currMonthName}</Heading>
<Button onClick={inc}>{nextMonthName}</Button>
</Flex>
<Grid gridTemplateColumns="repeat(7, 1fr)">
{weeks.map(week => week.map(day => <Box key={getTime(day)} />))}
</Grid>
</Box>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment