Created
October 9, 2020 12:58
-
-
Save g4rcez/4b546354beb443a52e70b11f135af7ac to your computer and use it in GitHub Desktop.
Draft
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { add, differenceInDays, eachDayOfInterval, endOfMonth, isSameMonth, startOfMonth, sub } from "date-fns"; | |
import { dec, inc } from "ramda"; | |
import React, { useEffect, useMemo, useState } from "react"; | |
import "styleguide/dist/index.css"; | |
const getWeekDays = (locale: string) => | |
Array.from({ length: 7 }).map((_, v) => | |
new Date(Date.UTC(1970, 0, 5 + v)).toLocaleDateString(locale, { weekday: "short" }) | |
); | |
const getYearMonths = (locale: string) => | |
Array.from({ length: 12 }).map((_, v) => | |
new Date(Date.UTC(1970, 1 + v, 1)).toLocaleDateString(locale, { month: "short" }) | |
); | |
const datePad = (n: number) => `${n}`.padStart(2, "0"); | |
const isSameDate = (d1: Date, d2: Date) => { | |
if (d1.getFullYear() !== d2.getFullYear()) { | |
return false; | |
} | |
if (d1.getMonth() !== d2.getMonth()) { | |
return false; | |
} | |
return d1.getDate() === d2.getDate(); | |
}; | |
export const Day: React.FC<{ today: Date; date: Date; onClick: (date: Date) => void }> = (props) => { | |
const date = props.date?.getDate(); | |
const isToday = isSameDate(props.date, props.today); | |
const sameMonth = isSameMonth(props.date, props.today); | |
let className = "text-center justify-center items-center m-auto px-1"; | |
if (isToday) { | |
className += " bg-primary-light rounded-full"; | |
} | |
if (!sameMonth) { | |
className += " text-disabled-light"; | |
} | |
return ( | |
<span role="button" onClick={() => props.onClick(props.date)} className={className}> | |
{datePad(date)} | |
</span> | |
); | |
}; | |
const s7 = (n: number) => Math.ceil(n / 7) * 7; | |
const newCalendar = (locale: string, x: { today: Date; year: number; month: number; day: number }) => { | |
const today = new Date(x.year, x.month - 1, x.day); | |
const monthStr = today.toLocaleDateString(locale, { month: "short" }); | |
const firstDayOfMonth = startOfMonth(today); | |
const lastDayOfMonth = endOfMonth(today).getDate(); | |
const addToEnd = s7(lastDayOfMonth + firstDayOfMonth.getDate()); | |
const start = sub(firstDayOfMonth, { days: firstDayOfMonth.getDay() }); | |
const end = add(firstDayOfMonth, { days: addToEnd }); | |
const lastDate = differenceInDays(end, start); | |
const days = eachDayOfInterval({ start, end: add(start, { days: Math.max(s7(lastDate), 42) }) }); | |
return { days, monthStr, today: x.today, year: today.getFullYear() }; | |
}; | |
const App = () => { | |
const locale = "pt-BR"; | |
const [calendar, setCalendar] = useState(() => { | |
const today = new Date(); | |
const day = today.getDate(); | |
const month = today.getMonth() + 1; | |
const year = today.getFullYear(); | |
return { ...newCalendar("pt-BR", { today, day, year, month }), day, month, year }; | |
}); | |
const [day, setDay] = useState(calendar.day); | |
const [month, setMonth] = useState(calendar.month); | |
const [year, setYear] = useState(calendar.year); | |
const [viewMonths, setViewMonths] = useState(false); | |
const weekDays = useMemo(() => getWeekDays(locale), [locale]); | |
const monthsYear = useMemo(() => getYearMonths(locale), [locale]); | |
useEffect(() => { | |
let dayHasChange = false; | |
setDay((prev) => { | |
dayHasChange = prev !== day; | |
return prev; | |
}); | |
const today = dayHasChange ? new Date() : new Date(year, month - 1, day); | |
const newCal = newCalendar("pt-BR", { today, day, year, month }); | |
setCalendar({ ...newCal, day, year, month }); | |
}, [day, year, month]); | |
const changeMonth = (i: number) => { | |
setMonth(i + 1); | |
setViewMonths(false); | |
}; | |
const incMonth = () => | |
setMonth((x) => { | |
const next = x + 1; | |
return next > 12 ? (setYear(inc), 1) : next; | |
}); | |
const decMonth = () => | |
setMonth((x) => { | |
const prev = x - 1; | |
return prev === 0 ? (setYear(dec), 12) : prev; | |
}); | |
const onDateClick = (date: Date) => { | |
setDay(date.getDate()); | |
setMonth(date.getMonth() + 1); | |
}; | |
return ( | |
<div className="py-8"> | |
<h2 className="w-full border-b border-disabled-light font-bold capitalize text-center text-4xl mb-4 flex justify-around items-start px-4"> | |
<button onClick={() => setYear(sub(calendar.today, { years: 1 }).getFullYear())}>{"<< "}</button> | |
<button onClick={decMonth}>{"<"}</button> | |
<span> | |
<span className="cursor-pointer hover:underline" onClick={() => setViewMonths((prev) => !prev)}> | |
{calendar.monthStr} | |
</span>{" "} | |
{calendar.year} | |
</span> | |
<button onClick={incMonth}>{">"}</button> | |
<button onClick={() => setYear(add(calendar.today, { years: 1 }).getFullYear())}>{" >>"}</button> | |
</h2> | |
{!viewMonths && ( | |
<div className="grid grid-flow-col grid-cols-7 text-center w-full items-start"> | |
{weekDays.map((x, i) => { | |
const row = [i, i + 7, i + 14, i + 21, i + 28, i + 35]; | |
console.log( | |
"fuck", | |
row.map((x) => calendar.days[x]) | |
); | |
return ( | |
<div className="grid text-default grid-flow-row grid-rows-6 gap-4" key={x}> | |
<div className="capitalize font-extrabold text-lg">{x}</div> | |
{row.map((date) => ( | |
<Day onClick={onDateClick} key={`date-${date}`} date={calendar.days[date]} today={calendar.today} /> | |
))} | |
</div> | |
); | |
})} | |
</div> | |
)} | |
{viewMonths && ( | |
<div className="grid template-4x3 gap-6"> | |
{monthsYear.map((x, i) => ( | |
<div key={`month-${x}`} role="button" onClick={() => changeMonth(i)} className="text-center capitalize"> | |
{x} | |
</div> | |
))} | |
</div> | |
)} | |
</div> | |
); | |
}; | |
export default App; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment