Skip to content

Instantly share code, notes, and snippets.

@g4rcez
Created October 9, 2020 12:58
Show Gist options
  • Save g4rcez/4b546354beb443a52e70b11f135af7ac to your computer and use it in GitHub Desktop.
Save g4rcez/4b546354beb443a52e70b11f135af7ac to your computer and use it in GitHub Desktop.
Draft
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