Massive functional upgrade: separated localization, full day viewer, month switch, first npm publish, code refactors
This commit is contained in:
parent
b37fe9644a
commit
0d66f3c4f6
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
@ -1,14 +1,19 @@
|
|||||||
import React from "react";
|
import React from 'react'
|
||||||
import Calendar from "react-eventful-calendar";
|
import Calendar, { Viewers } from 'react-eventful-calendar'
|
||||||
|
|
||||||
import events from './events.json'
|
import events from './events.json'
|
||||||
|
import locale from './locale.json'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<Calendar eventList={events} />
|
<Calendar
|
||||||
|
eventList={events}
|
||||||
|
locale={locale}
|
||||||
|
initialViewer={Viewers.MonthViewer}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App
|
||||||
|
@ -2,7 +2,36 @@
|
|||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"title": "Test",
|
"title": "Test",
|
||||||
"startDate": "Wed Oct 28 2020 17:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
"startDate": "Wed Oct 22 2020 17:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
||||||
"endDate": "Wed Oct 28 2020 20:00:00 GMT+0500 (Yekaterinburg Standard Time)"
|
"endDate": "Wed Oct 22 2020 20:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
||||||
|
"color": "#e57373"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"title": "AnotherTest",
|
||||||
|
"startDate": "Wed Oct 22 2020 17:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
||||||
|
"endDate": "Wed Oct 22 2020 20:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
||||||
|
"color": "#64b5f6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "And finally: third test",
|
||||||
|
"startDate": "Wed Oct 22 2020 17:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
||||||
|
"endDate": "Wed Oct 22 2020 20:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
||||||
|
"color": "#81c784"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 666,
|
||||||
|
"title": "Halloween",
|
||||||
|
"startDate": "Wed Oct 31 2020 00:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
||||||
|
"endDate": "Wed Nov 1 2020 00:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
||||||
|
"color": "#ffb74d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"title": "Watching film",
|
||||||
|
"startDate": "Wed Oct 31 2020 23:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
||||||
|
"endDate": "Wed Nov 1 2020 01:00:00 GMT+0500 (Yekaterinburg Standard Time)",
|
||||||
|
"color": "#ffb74d"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
25
example/src/locale.json
Normal file
25
example/src/locale.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"monthNames": [
|
||||||
|
"январь",
|
||||||
|
"февраль",
|
||||||
|
"март",
|
||||||
|
"апрель",
|
||||||
|
"май",
|
||||||
|
"июнь",
|
||||||
|
"июль",
|
||||||
|
"август",
|
||||||
|
"сентябрь",
|
||||||
|
"октябрь",
|
||||||
|
"ноябрь",
|
||||||
|
"декабрь"
|
||||||
|
],
|
||||||
|
"weekdaysNames": [
|
||||||
|
"понедельник",
|
||||||
|
"вторник",
|
||||||
|
"среда",
|
||||||
|
"четверг",
|
||||||
|
"пятница",
|
||||||
|
"субота",
|
||||||
|
"воскресенье"
|
||||||
|
]
|
||||||
|
}
|
@ -8847,7 +8847,7 @@ react-error-overlay@^6.0.8:
|
|||||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.8.tgz#474ed11d04fc6bda3af643447d85e9127ed6b5de"
|
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.8.tgz#474ed11d04fc6bda3af643447d85e9127ed6b5de"
|
||||||
integrity sha512-HvPuUQnLp5H7TouGq3kzBeioJmXms1wHy9EGjz2OURWBp4qZO6AfGEcnxts1D/CbwPLRAgTMPCEgYhA3sEM4vw==
|
integrity sha512-HvPuUQnLp5H7TouGq3kzBeioJmXms1wHy9EGjz2OURWBp4qZO6AfGEcnxts1D/CbwPLRAgTMPCEgYhA3sEM4vw==
|
||||||
|
|
||||||
react-eventful-calendar@../.:
|
react-eventful-calendar@../:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
|
|
||||||
react-is@^16.8.1:
|
react-is@^16.8.1:
|
||||||
|
@ -1,69 +1,18 @@
|
|||||||
import React, { useContext, useEffect, useState } from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import Day from './Day'
|
import { useCalendarContext } from './hooks'
|
||||||
import { CalendarContext } from './context'
|
import { Viewers } from './types'
|
||||||
import { DayT, ICalendarProps } from './types'
|
import { DayView, MonthView } from './views'
|
||||||
|
import styles from './views/styles'
|
||||||
|
|
||||||
const CalendarInContext: React.FC<ICalendarProps> = ({ eventList }) => {
|
const CalendarInContext: React.FC = () => {
|
||||||
const context = useContext(CalendarContext)
|
const { state: calendar } = useCalendarContext()
|
||||||
|
const { currentViewer } = calendar
|
||||||
const { month } = context.state
|
|
||||||
|
|
||||||
const [monthDaysState, setMonthDaysState] = useState<DayT[]>([])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const daysNumbersArray = [
|
|
||||||
Array.from(
|
|
||||||
Array(month.firstDayOfWeek - 1 > 0 ? month.firstDayOfWeek - 1 : 0)
|
|
||||||
).map(
|
|
||||||
(_, index) =>
|
|
||||||
month.previousMonthLength - month.firstDayOfWeek + index + 2
|
|
||||||
),
|
|
||||||
Array.from(Array(month.numberOfDays)).map((_, index) => index + 1),
|
|
||||||
Array.from(Array(7 - month.lastDayOfWeek)).map((_, index) => index + 1),
|
|
||||||
]
|
|
||||||
|
|
||||||
setMonthDaysState(
|
|
||||||
daysNumbersArray.flatMap((month, index) =>
|
|
||||||
month.map<DayT>((dayNumber) => ({
|
|
||||||
number: dayNumber,
|
|
||||||
events: eventList.filter((event) => {
|
|
||||||
if (index != 1) return false
|
|
||||||
|
|
||||||
const eventDate = new Date(event.startDate)
|
|
||||||
|
|
||||||
return (
|
|
||||||
eventDate.getDate() == dayNumber &&
|
|
||||||
eventDate.getMonth() == context.state.month.number
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}, [context.state])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div style={styles.calendar}>
|
||||||
style={{
|
{currentViewer == Viewers.MonthViewer && <MonthView />}
|
||||||
height: '100%',
|
{currentViewer == Viewers.DayViewer && <DayView />}
|
||||||
width: '100%',
|
|
||||||
display: 'grid',
|
|
||||||
gridTemplateColumns: 'repeat(7, 1fr)',
|
|
||||||
gridTemplateRows: 'repeat(5, 1fr)',
|
|
||||||
gap: '5px'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{monthDaysState.map((day, dayIndex) => (
|
|
||||||
<Day
|
|
||||||
key={dayIndex}
|
|
||||||
dayNumber={day.number}
|
|
||||||
events={day.events}
|
|
||||||
shaded={
|
|
||||||
dayIndex < month.firstDayOfWeek - 1 ||
|
|
||||||
dayIndex > month.numberOfDays + month.firstDayOfWeek - 2
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
48
src/Day.tsx
48
src/Day.tsx
@ -1,48 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import { IDayProps } from './types'
|
|
||||||
|
|
||||||
const Day: React.FC<IDayProps> = ({ dayNumber, events, shaded }) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: '#EEEEEE',
|
|
||||||
borderRadius: '5px',
|
|
||||||
maxHeight: '100px',
|
|
||||||
overflow: 'hidden',
|
|
||||||
padding: '5px',
|
|
||||||
position: 'relative',
|
|
||||||
opacity: shaded ? '0.5' : '1',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<h5
|
|
||||||
style={{
|
|
||||||
textAlign: 'center',
|
|
||||||
margin: '0px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{dayNumber}
|
|
||||||
</h5>
|
|
||||||
<ul style={{ paddingLeft: '20px', margin: '0' }}>
|
|
||||||
{events.map((event, key) => (
|
|
||||||
<li key={key} style={{}}>
|
|
||||||
{event.title}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: '0px',
|
|
||||||
marginLeft: '-5px',
|
|
||||||
width: '100%',
|
|
||||||
height: '50%',
|
|
||||||
display: 'block',
|
|
||||||
backgroundImage: 'linear-gradient(transparent, #EEEEEE)',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Day
|
|
@ -1,47 +0,0 @@
|
|||||||
import React, { createContext, useEffect, useState } from 'react'
|
|
||||||
|
|
||||||
import { CalendarContextStateT, CalendarContextT } from './types'
|
|
||||||
import { getCurrentMonth } from './utils'
|
|
||||||
|
|
||||||
const initialCalendarContextState: CalendarContextStateT = {
|
|
||||||
month: {
|
|
||||||
number: 1,
|
|
||||||
firstDayOfWeek: 1,
|
|
||||||
lastDayOfWeek: 1,
|
|
||||||
numberOfDays: 1,
|
|
||||||
previousMonthLength: 1,
|
|
||||||
},
|
|
||||||
year: 1,
|
|
||||||
day: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
const CalendarContext = createContext<CalendarContextT>({
|
|
||||||
state: initialCalendarContextState,
|
|
||||||
})
|
|
||||||
|
|
||||||
const CalendarProvider: React.FC = ({ children }) => {
|
|
||||||
const [state, setState] = useState<CalendarContextStateT>(
|
|
||||||
initialCalendarContextState
|
|
||||||
)
|
|
||||||
|
|
||||||
const [now] = useState<Date>(new Date())
|
|
||||||
|
|
||||||
useEffect(
|
|
||||||
() =>
|
|
||||||
setState((prev) => ({
|
|
||||||
...prev,
|
|
||||||
month: getCurrentMonth(now),
|
|
||||||
year: now.getFullYear(),
|
|
||||||
day: now.getDate(),
|
|
||||||
})),
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CalendarContext.Provider value={{ state, setState }}>
|
|
||||||
{children}
|
|
||||||
</CalendarContext.Provider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export { CalendarContext, CalendarProvider }
|
|
74
src/context/calendar.tsx
Normal file
74
src/context/calendar.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import React, { createContext, useEffect, useMemo, useState } from 'react'
|
||||||
|
|
||||||
|
import {
|
||||||
|
CalendarStateT,
|
||||||
|
CalendarContextT,
|
||||||
|
ICalendarProviderProps,
|
||||||
|
} from './types'
|
||||||
|
import { Viewers } from '../types'
|
||||||
|
import { getMonth } from '../utils'
|
||||||
|
|
||||||
|
const initialCalendarContextState: CalendarStateT = {
|
||||||
|
month: {
|
||||||
|
number: 1,
|
||||||
|
firstDayOfWeek: 0,
|
||||||
|
lastDayOfWeek: 1,
|
||||||
|
numberOfDays: 1,
|
||||||
|
previousMonthLength: 1,
|
||||||
|
},
|
||||||
|
year: 1,
|
||||||
|
day: {
|
||||||
|
number: 1,
|
||||||
|
},
|
||||||
|
today: {
|
||||||
|
day: 1,
|
||||||
|
month: 1,
|
||||||
|
year: 1,
|
||||||
|
},
|
||||||
|
eventList: [],
|
||||||
|
currentViewer: Viewers.MonthViewer,
|
||||||
|
}
|
||||||
|
|
||||||
|
const CalendarContext = createContext<CalendarContextT | null>(null)
|
||||||
|
|
||||||
|
const CalendarProvider: React.FC<ICalendarProviderProps> = ({
|
||||||
|
children,
|
||||||
|
eventList,
|
||||||
|
initialViewer,
|
||||||
|
}) => {
|
||||||
|
const [state, setState] = useState<CalendarStateT>(
|
||||||
|
initialCalendarContextState
|
||||||
|
)
|
||||||
|
|
||||||
|
const [now] = useState<Date>(new Date())
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() =>
|
||||||
|
setState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
year: now.getFullYear(),
|
||||||
|
month: getMonth(now),
|
||||||
|
day: {
|
||||||
|
number: now.getDate(),
|
||||||
|
},
|
||||||
|
today: {
|
||||||
|
day: now.getDate(),
|
||||||
|
month: now.getMonth(),
|
||||||
|
year: now.getFullYear(),
|
||||||
|
},
|
||||||
|
currentViewer: initialViewer,
|
||||||
|
eventList,
|
||||||
|
})),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
|
const value = useMemo(() => ({ state, setState }), [state])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CalendarContext.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</CalendarContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CalendarContext, CalendarProvider }
|
32
src/context/locale.tsx
Normal file
32
src/context/locale.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import React, { createContext, useEffect, useMemo, useState } from 'react'
|
||||||
|
import { ILocaleProviderProps, LocaleContextT, LocaleStateT } from './types'
|
||||||
|
|
||||||
|
const initialLocaleState: LocaleStateT = {
|
||||||
|
monthNames: [],
|
||||||
|
weekdaysNames: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
const LocaleContext = createContext<LocaleContextT | null>(null)
|
||||||
|
|
||||||
|
const LocaleProvider: React.FC<ILocaleProviderProps> = ({
|
||||||
|
children,
|
||||||
|
monthList,
|
||||||
|
weekList,
|
||||||
|
}) => {
|
||||||
|
const [state, setState] = useState<LocaleStateT>(initialLocaleState)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setState({
|
||||||
|
monthNames: monthList,
|
||||||
|
weekdaysNames: weekList,
|
||||||
|
})
|
||||||
|
}, [monthList, weekList])
|
||||||
|
|
||||||
|
const value = useMemo(() => ({ state, setState }), [state])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { LocaleContext, LocaleProvider }
|
59
src/context/types.ts
Normal file
59
src/context/types.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { Dispatch, SetStateAction } from 'react'
|
||||||
|
import { EventT, Viewers } from '../types'
|
||||||
|
|
||||||
|
// Calendar
|
||||||
|
|
||||||
|
export type CalendarStateT = {
|
||||||
|
month: MonthContextT
|
||||||
|
year: number
|
||||||
|
day: {
|
||||||
|
number: number
|
||||||
|
events?: EventT[]
|
||||||
|
}
|
||||||
|
today: {
|
||||||
|
day: number
|
||||||
|
month: number
|
||||||
|
year: number
|
||||||
|
}
|
||||||
|
eventList: EventT[]
|
||||||
|
currentViewer: Viewers
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MonthContextT = {
|
||||||
|
number: number
|
||||||
|
firstDayOfWeek: number
|
||||||
|
lastDayOfWeek: number
|
||||||
|
numberOfDays: number
|
||||||
|
previousMonthLength: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CalendarContextSetterT = Dispatch<SetStateAction<CalendarStateT>>
|
||||||
|
|
||||||
|
export type CalendarContextT = {
|
||||||
|
state: CalendarStateT
|
||||||
|
setState?: CalendarContextSetterT
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICalendarProviderProps {
|
||||||
|
eventList: EventT[]
|
||||||
|
initialViewer: Viewers
|
||||||
|
}
|
||||||
|
|
||||||
|
// localization
|
||||||
|
|
||||||
|
export type LocaleStateT = {
|
||||||
|
weekdaysNames: string[]
|
||||||
|
monthNames: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LocaleContextSetterT = Dispatch<SetStateAction<LocaleStateT>>
|
||||||
|
|
||||||
|
export type LocaleContextT = {
|
||||||
|
state: LocaleStateT
|
||||||
|
setState?: LocaleContextSetterT
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILocaleProviderProps {
|
||||||
|
weekList: string[]
|
||||||
|
monthList: string[]
|
||||||
|
}
|
23
src/hooks.ts
Normal file
23
src/hooks.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { useContext } from 'react'
|
||||||
|
import { CalendarContext } from './context/calendar'
|
||||||
|
import { LocaleContext } from './context/locale'
|
||||||
|
|
||||||
|
const useCalendarContext = () => {
|
||||||
|
const context = useContext(CalendarContext)
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
throw new Error("Can't use calendar context outside of CalendarProvider")
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
const useLocaleContext = () => {
|
||||||
|
const context = useContext(LocaleContext)
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
throw new Error("Can't use locale context outside of LocaleProvider")
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useCalendarContext, useLocaleContext }
|
@ -1,14 +1,26 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import CalendarInContext from './CalendarInContext'
|
import CalendarInContext from './CalendarInContext'
|
||||||
import { CalendarProvider as CalendarContextProvider } from './context'
|
import { CalendarProvider as CalendarContextProvider } from './context/calendar'
|
||||||
import { ICalendarProps } from './types'
|
import { ICalendarProps } from './types'
|
||||||
|
import { LocaleProvider as LocaleContextProvider } from './context/locale'
|
||||||
|
|
||||||
const Calendar: React.FC<ICalendarProps> = ({ eventList }) => {
|
const Calendar: React.FC<ICalendarProps> = ({
|
||||||
|
eventList,
|
||||||
|
initialViewer,
|
||||||
|
locale: { monthNames, weekdaysNames },
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<CalendarContextProvider>
|
<CalendarContextProvider
|
||||||
<CalendarInContext eventList={eventList} />
|
eventList={eventList}
|
||||||
|
initialViewer={initialViewer}
|
||||||
|
>
|
||||||
|
<LocaleContextProvider monthList={monthNames} weekList={weekdaysNames}>
|
||||||
|
<CalendarInContext />
|
||||||
|
</LocaleContextProvider>
|
||||||
</CalendarContextProvider>
|
</CalendarContextProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { Viewers } from './types'
|
||||||
|
|
||||||
export default Calendar
|
export default Calendar
|
||||||
|
57
src/types.ts
57
src/types.ts
@ -1,30 +1,26 @@
|
|||||||
import { Dispatch, SetStateAction } from 'react'
|
import { Dispatch, SetStateAction } from 'react'
|
||||||
|
import { CalendarStateT, LocaleStateT, MonthContextT } from './context/types'
|
||||||
|
|
||||||
// Context
|
// Experimental
|
||||||
|
|
||||||
export type CalendarContextStateT = {
|
export type switchMonthInContextFT = (
|
||||||
month: MonthContextT
|
setContext: Dispatch<SetStateAction<CalendarStateT>> | undefined,
|
||||||
year: number
|
increase: boolean
|
||||||
day: number
|
) => void
|
||||||
}
|
|
||||||
|
|
||||||
export type MonthContextT = {
|
export type UseCalendarSwitchFT = () => (increase: boolean) => void
|
||||||
number: number
|
|
||||||
firstDayOfWeek: number
|
|
||||||
lastDayOfWeek: number
|
|
||||||
numberOfDays: number
|
|
||||||
previousMonthLength: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CalendarContextT = {
|
|
||||||
state: CalendarContextStateT
|
|
||||||
setState?: Dispatch<SetStateAction<CalendarContextStateT>>
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calendar component
|
// Calendar component
|
||||||
|
|
||||||
|
export enum Viewers {
|
||||||
|
MonthViewer,
|
||||||
|
DayViewer,
|
||||||
|
}
|
||||||
|
|
||||||
export interface ICalendarProps {
|
export interface ICalendarProps {
|
||||||
eventList: EventT[]
|
eventList: EventT[]
|
||||||
|
initialViewer: Viewers
|
||||||
|
locale: LocaleStateT
|
||||||
}
|
}
|
||||||
|
|
||||||
// Day
|
// Day
|
||||||
@ -34,11 +30,23 @@ export type DayT = {
|
|||||||
events: EventT[]
|
events: EventT[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDayProps {
|
export type ShouldDayBeShadedFT = (
|
||||||
dayNumber: number
|
month: MonthContextT,
|
||||||
events: EventT[]
|
dayIndex: number
|
||||||
shaded: boolean
|
) => boolean
|
||||||
}
|
|
||||||
|
export type FilterEventsByDayFT = (
|
||||||
|
eventList: EventT[],
|
||||||
|
dayNumber: number,
|
||||||
|
monthNumber: number,
|
||||||
|
yearNumber: number
|
||||||
|
) => EventT[]
|
||||||
|
|
||||||
|
export type SetDayFT = (
|
||||||
|
dayNumber: number,
|
||||||
|
dayEvents: EventT[],
|
||||||
|
setState: Dispatch<SetStateAction<CalendarStateT>> | undefined
|
||||||
|
) => void
|
||||||
|
|
||||||
// Event
|
// Event
|
||||||
|
|
||||||
@ -47,4 +55,7 @@ export type EventT = {
|
|||||||
title: string
|
title: string
|
||||||
startDate: string
|
startDate: string
|
||||||
endDate: string
|
endDate: string
|
||||||
|
color: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GetEventLengthFT = (start: string, end: string) => string
|
||||||
|
107
src/utils.ts
107
src/utils.ts
@ -1,13 +1,17 @@
|
|||||||
import { MonthContextT } from './types'
|
import { MonthContextT } from './context/types'
|
||||||
|
import {
|
||||||
|
FilterEventsByDayFT,
|
||||||
|
GetEventLengthFT,
|
||||||
|
SetDayFT,
|
||||||
|
ShouldDayBeShadedFT,
|
||||||
|
switchMonthInContextFT,
|
||||||
|
} from './types'
|
||||||
|
|
||||||
const getCurrentMonth = (currentDay: Date): MonthContextT => {
|
const getMonth = (date: Date): MonthContextT => {
|
||||||
const monthInfo = getMonthInfo(
|
const monthInfo = getMonthInfo(date.getFullYear(), date.getMonth())
|
||||||
currentDay.getFullYear(),
|
|
||||||
currentDay.getMonth()
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
number: currentDay.getMonth(),
|
number: date.getMonth(),
|
||||||
...monthInfo,
|
...monthInfo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -20,12 +24,97 @@ const getMonthInfo = (
|
|||||||
const lastDayOfMonth = new Date(year, month + 1, 0)
|
const lastDayOfMonth = new Date(year, month + 1, 0)
|
||||||
const prevMonth = new Date(year, month, 0)
|
const prevMonth = new Date(year, month, 0)
|
||||||
|
|
||||||
|
const firstDayOfWeek = firstDayOfMonth.getDay()
|
||||||
|
|
||||||
|
const convertedFirstDayOfWeek =
|
||||||
|
firstDayOfWeek - 1 >= 0 ? firstDayOfWeek - 1 : 6
|
||||||
|
|
||||||
return {
|
return {
|
||||||
firstDayOfWeek: firstDayOfMonth.getDay(),
|
firstDayOfWeek: convertedFirstDayOfWeek,
|
||||||
lastDayOfWeek: lastDayOfMonth.getDay(),
|
lastDayOfWeek: lastDayOfMonth.getDay(),
|
||||||
numberOfDays: lastDayOfMonth.getDate(),
|
numberOfDays: lastDayOfMonth.getDate(),
|
||||||
previousMonthLength: prevMonth.getDate(),
|
previousMonthLength: prevMonth.getDate(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { getCurrentMonth, getMonthInfo }
|
const getMonthName = (number: number, monthNames: string[]) =>
|
||||||
|
monthNames[number]
|
||||||
|
|
||||||
|
const switchMonthInContext: switchMonthInContextFT = (setContext, increase) => {
|
||||||
|
if (!setContext) return
|
||||||
|
|
||||||
|
setContext((previousContext) => {
|
||||||
|
const newDate = new Date(
|
||||||
|
previousContext.year,
|
||||||
|
previousContext.month.number,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
|
||||||
|
if (increase) newDate.setMonth(newDate.getMonth() + 1)
|
||||||
|
else newDate.setMonth(newDate.getMonth() - 1)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...previousContext,
|
||||||
|
year: newDate.getFullYear(),
|
||||||
|
month: getMonth(newDate),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldDayBeShaded: ShouldDayBeShadedFT = (month, dayIndex) =>
|
||||||
|
dayIndex < month.firstDayOfWeek ||
|
||||||
|
dayIndex > month.numberOfDays + month.firstDayOfWeek - 1
|
||||||
|
|
||||||
|
const filterEventsByDay: FilterEventsByDayFT = (
|
||||||
|
eventList,
|
||||||
|
dayNumber,
|
||||||
|
monthNumber,
|
||||||
|
yearnumber
|
||||||
|
) =>
|
||||||
|
eventList.filter((event) => {
|
||||||
|
const eventDate = new Date(event.startDate)
|
||||||
|
|
||||||
|
return (
|
||||||
|
eventDate.getDate() == dayNumber &&
|
||||||
|
eventDate.getMonth() == monthNumber &&
|
||||||
|
eventDate.getFullYear() == yearnumber
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const setDay: SetDayFT = (dayNumber, dayEvents, setState) => {
|
||||||
|
if (setState)
|
||||||
|
setState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
day: {
|
||||||
|
...prevState.day,
|
||||||
|
number: dayNumber,
|
||||||
|
events: dayEvents,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const getEventLength: GetEventLengthFT = (start, end) => {
|
||||||
|
const startDate = new Date(start)
|
||||||
|
const endDate = new Date(end)
|
||||||
|
|
||||||
|
if ((endDate.getTime() - startDate.getTime()) / (1000 * 3600 * 24) >= 1)
|
||||||
|
return 'Whole day'
|
||||||
|
const startMinutes = startDate.getMinutes().toString()
|
||||||
|
const endMinutes = endDate.getMinutes().toString()
|
||||||
|
|
||||||
|
return `${startDate.getHours()}:${
|
||||||
|
startMinutes.length < 2 ? '0' + startMinutes : startMinutes
|
||||||
|
}-${endDate.getHours()}:${
|
||||||
|
endMinutes.length < 2 ? '0' + endMinutes : endMinutes
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getMonth,
|
||||||
|
getMonthName,
|
||||||
|
switchMonthInContext,
|
||||||
|
shouldDayBeShaded,
|
||||||
|
filterEventsByDay,
|
||||||
|
setDay,
|
||||||
|
getEventLength,
|
||||||
|
}
|
||||||
|
77
src/views/Day.tsx
Normal file
77
src/views/Day.tsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import { useCalendarContext, useLocaleContext } from '../hooks'
|
||||||
|
import { Viewers } from '../types'
|
||||||
|
import { getEventLength, getMonthName } from '../utils'
|
||||||
|
|
||||||
|
import { IDayViewer } from './types'
|
||||||
|
|
||||||
|
const HomeIcon = () => (
|
||||||
|
<svg
|
||||||
|
width="23"
|
||||||
|
height="22"
|
||||||
|
viewBox="0 0 23 22"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g fill="#000000">
|
||||||
|
<path d="M11.5 5.21591L20.125 13.2268V22H14.375V16.2609H8.625V22H2.875V13.2268L11.5 5.21591ZM23 10.6633L11.5 0L0 10.649L1.30429 12.0503L11.5 2.6113L21.6957 12.0646L23 10.6633Z"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const DayViewer: React.FC<IDayViewer> = () => {
|
||||||
|
const {
|
||||||
|
state: { day, month, year },
|
||||||
|
setState,
|
||||||
|
} = useCalendarContext()
|
||||||
|
const {
|
||||||
|
state: { monthNames },
|
||||||
|
} = useLocaleContext()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (setState)
|
||||||
|
if (day.events === undefined) {
|
||||||
|
setState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
day: {
|
||||||
|
...prevState.day,
|
||||||
|
events: prevState.eventList.filter(() => false),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}, [day.number])
|
||||||
|
|
||||||
|
const handle = () => {
|
||||||
|
if (setState)
|
||||||
|
setState((prevSate) => ({
|
||||||
|
...prevSate,
|
||||||
|
currentViewer: Viewers.MonthViewer,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
title="Return to main"
|
||||||
|
onClick={handle}
|
||||||
|
style={{ background: 'none', border: 'none', cursor: 'pointer' }}
|
||||||
|
>
|
||||||
|
<HomeIcon />
|
||||||
|
</button>
|
||||||
|
<div>
|
||||||
|
<h1>{day.number}</h1>
|
||||||
|
<h3>{getMonthName(month.number, monthNames) + ' ' + year}</h3>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
{day.events?.map((event, eventIndex) => (
|
||||||
|
<li key={eventIndex}>
|
||||||
|
<h2>{event.title}</h2>
|
||||||
|
<h3>{getEventLength(event.startDate, event.endDate)}</h3>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DayViewer
|
79
src/views/DayOfMonth.tsx
Normal file
79
src/views/DayOfMonth.tsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import React, { useState } from 'react'
|
||||||
|
import { useCalendarContext } from '../hooks'
|
||||||
|
import { Viewers } from '../types'
|
||||||
|
import { setDay } from '../utils'
|
||||||
|
|
||||||
|
import { IDayOfMonthProps } from './types'
|
||||||
|
import styles from './styles'
|
||||||
|
|
||||||
|
const ArrowDown: React.FC = () => (
|
||||||
|
<svg
|
||||||
|
width="11"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 11 6"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g fill="#000000">
|
||||||
|
<path d="M0 1.132L1.29663 0L5.50183 3.7356L9.70337 0L11 1.132L5.50183 6L0 1.132Z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const DayOfMonth: React.FC<IDayOfMonthProps> = ({
|
||||||
|
dayNumber,
|
||||||
|
events,
|
||||||
|
shaded,
|
||||||
|
}) => {
|
||||||
|
const { setState } = useCalendarContext()
|
||||||
|
|
||||||
|
const [expanded, setExpanded] = useState(false)
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
if (shaded) return
|
||||||
|
if (events.length > 2 && !expanded) return setExpanded(true)
|
||||||
|
setDay(dayNumber, events, setState)
|
||||||
|
if (setState)
|
||||||
|
setState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
currentViewer: Viewers.DayViewer,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
...styles.dayOfMonth,
|
||||||
|
opacity: shaded ? '0.5' : '1',
|
||||||
|
maxHeight: expanded ? '100vh' : '5rem',
|
||||||
|
}}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
<h5 style={styles.monthDayNumber}>{dayNumber}</h5>
|
||||||
|
<ul style={styles.monthDayEventList}>
|
||||||
|
{events.map((event, key) => (
|
||||||
|
<li
|
||||||
|
key={key}
|
||||||
|
style={{ ...styles.monthDayEvent, backgroundColor: event.color }}
|
||||||
|
>
|
||||||
|
{event.title}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
{events.length > 2 ? (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
...styles.monthDayBottomShade,
|
||||||
|
height: expanded ? '0px' : '50%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ArrowDown />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DayOfMonth
|
61
src/views/Month.tsx
Normal file
61
src/views/Month.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { useCalendarContext } from '../hooks'
|
||||||
|
import { DayT } from '../types'
|
||||||
|
import { filterEventsByDay, shouldDayBeShaded } from '../utils'
|
||||||
|
import DayOfMonth from './DayOfMonth'
|
||||||
|
import MonthHeader from './MonthHeader'
|
||||||
|
import styles from './styles'
|
||||||
|
|
||||||
|
const MonthView: React.FC = () => {
|
||||||
|
const {
|
||||||
|
state: { month, eventList, year: yearNumber },
|
||||||
|
} = useCalendarContext()
|
||||||
|
|
||||||
|
const [monthDays, setMonthDaysState] = useState<DayT[]>([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const daysNumbersArray = [
|
||||||
|
Array.from(
|
||||||
|
// Array(month.firstDayOfWeek - 1 > 0 ? month.firstDayOfWeek - 1 : 0)
|
||||||
|
Array(month.firstDayOfWeek)
|
||||||
|
).map(
|
||||||
|
(_, index) =>
|
||||||
|
month.previousMonthLength - month.firstDayOfWeek + index + 1
|
||||||
|
),
|
||||||
|
Array.from(Array(month.numberOfDays)).map((_, index) => index + 1),
|
||||||
|
Array.from(Array(7 - month.lastDayOfWeek)).map((_, index) => index + 1),
|
||||||
|
]
|
||||||
|
|
||||||
|
const monthNumber = month.number
|
||||||
|
|
||||||
|
setMonthDaysState(
|
||||||
|
daysNumbersArray.flatMap((month, index) =>
|
||||||
|
month.map<DayT>((dayNumber) => ({
|
||||||
|
number: dayNumber,
|
||||||
|
events:
|
||||||
|
index == 1
|
||||||
|
? filterEventsByDay(eventList, dayNumber, monthNumber, yearNumber)
|
||||||
|
: [],
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}, [month, eventList])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MonthHeader />
|
||||||
|
<div style={styles.monthGrid}>
|
||||||
|
{monthDays.map((day, dayIndex) => (
|
||||||
|
<DayOfMonth
|
||||||
|
key={dayIndex}
|
||||||
|
dayNumber={day.number}
|
||||||
|
events={day.events}
|
||||||
|
shaded={shouldDayBeShaded(month, dayIndex)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MonthView
|
52
src/views/MonthHeader.tsx
Normal file
52
src/views/MonthHeader.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { useCalendarContext, useLocaleContext } from '../hooks'
|
||||||
|
import { getMonthName, switchMonthInContext } from '../utils'
|
||||||
|
import styles from './styles'
|
||||||
|
|
||||||
|
const MonthHeader: React.FC = () => {
|
||||||
|
const {
|
||||||
|
state: { weekdaysNames, monthNames },
|
||||||
|
} = useLocaleContext()
|
||||||
|
|
||||||
|
const {
|
||||||
|
state: {
|
||||||
|
year,
|
||||||
|
month: { number },
|
||||||
|
},
|
||||||
|
setState,
|
||||||
|
} = useCalendarContext()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header>
|
||||||
|
<div style={styles.monthSwitchHeader}>
|
||||||
|
<button
|
||||||
|
title={getMonthName(number - 1, monthNames)}
|
||||||
|
onClick={() => switchMonthInContext(setState, false)}
|
||||||
|
style={styles.switchMonthButton}
|
||||||
|
>
|
||||||
|
<
|
||||||
|
</button>
|
||||||
|
<h4 style={styles.monthSwitchHeaderTitle}>
|
||||||
|
{getMonthName(number, monthNames) + ' ' + year}
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
title={getMonthName(number + 1, monthNames)}
|
||||||
|
onClick={() => switchMonthInContext(setState, true)}
|
||||||
|
style={styles.switchMonthButton}
|
||||||
|
>
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={styles.weekdaysListHeader}>
|
||||||
|
{weekdaysNames.map((weekDay, weekDayIndex) => (
|
||||||
|
<p key={weekDayIndex} style={styles.weekDay}>
|
||||||
|
{weekDay}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MonthHeader
|
4
src/views/index.ts
Normal file
4
src/views/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import MonthView from './Month'
|
||||||
|
import DayView from './Day'
|
||||||
|
|
||||||
|
export { MonthView, DayView }
|
117
src/views/styles.ts
Normal file
117
src/views/styles.ts
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
type Style = React.CSSProperties
|
||||||
|
|
||||||
|
const calendar: Style = {
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
border: '1px black solid',
|
||||||
|
borderRadius: '5px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
}
|
||||||
|
|
||||||
|
// Month header
|
||||||
|
|
||||||
|
const weekdaysListHeader: Style = {
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: 'repeat(7, 1fr)',
|
||||||
|
width: '100%',
|
||||||
|
gap: '5px',
|
||||||
|
}
|
||||||
|
|
||||||
|
const monthSwitchHeader: Style = {
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: 'repeat(7, 1fr)',
|
||||||
|
width: '100%',
|
||||||
|
gap: '5px',
|
||||||
|
backgroundColor: 'black',
|
||||||
|
color: 'white',
|
||||||
|
padding: '5px',
|
||||||
|
}
|
||||||
|
|
||||||
|
const switchMonthButton: Style = {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '5px',
|
||||||
|
}
|
||||||
|
|
||||||
|
const monthSwitchHeaderTitle: Style = {
|
||||||
|
margin: '0px',
|
||||||
|
textAlign: 'center',
|
||||||
|
textTransform: 'capitalize',
|
||||||
|
gridColumn: 'span 5',
|
||||||
|
}
|
||||||
|
|
||||||
|
const weekDay: Style = {
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
textAlign: 'center',
|
||||||
|
padding: '5px 0',
|
||||||
|
margin: '0px',
|
||||||
|
textTransform: 'capitalize',
|
||||||
|
}
|
||||||
|
|
||||||
|
// Month viewer
|
||||||
|
|
||||||
|
const monthGrid: Style = {
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: 'repeat(7, 1fr)',
|
||||||
|
gap: '5px',
|
||||||
|
padding: '5px',
|
||||||
|
}
|
||||||
|
|
||||||
|
// Month day
|
||||||
|
|
||||||
|
const dayOfMonth: Style = {
|
||||||
|
background: '#EEEEEE',
|
||||||
|
borderRadius: '5px',
|
||||||
|
overflow: 'hidden',
|
||||||
|
minHeight: '5rem',
|
||||||
|
padding: '5px',
|
||||||
|
position: 'relative',
|
||||||
|
transition: 'all 3s',
|
||||||
|
}
|
||||||
|
|
||||||
|
const monthDayEventList: Style = {
|
||||||
|
padding: '0px',
|
||||||
|
margin: '0px',
|
||||||
|
listStyle: 'none',
|
||||||
|
overflow: 'hidden',
|
||||||
|
borderRadius: '4px',
|
||||||
|
}
|
||||||
|
|
||||||
|
const monthDayEvent: Style = {
|
||||||
|
padding: '2px',
|
||||||
|
}
|
||||||
|
|
||||||
|
const monthDayBottomShade: Style = {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: '0px',
|
||||||
|
marginLeft: '-5px',
|
||||||
|
width: '100%',
|
||||||
|
overflow: 'hidden',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'flex-end',
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundImage: 'linear-gradient(transparent, #EEEEEE)',
|
||||||
|
}
|
||||||
|
|
||||||
|
const monthDayNumber: Style = {
|
||||||
|
textAlign: 'center',
|
||||||
|
margin: '0px',
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
switchMonthButton,
|
||||||
|
calendar,
|
||||||
|
weekdaysListHeader,
|
||||||
|
monthSwitchHeader,
|
||||||
|
monthSwitchHeaderTitle,
|
||||||
|
weekDay,
|
||||||
|
monthGrid,
|
||||||
|
dayOfMonth,
|
||||||
|
monthDayEventList,
|
||||||
|
monthDayEvent,
|
||||||
|
monthDayBottomShade,
|
||||||
|
monthDayNumber,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default styles
|
9
src/views/types.ts
Normal file
9
src/views/types.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { EventT } from '../types'
|
||||||
|
|
||||||
|
export interface IDayOfMonthProps {
|
||||||
|
dayNumber: number
|
||||||
|
events: EventT[]
|
||||||
|
shaded: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IDayViewer {}
|
Loading…
x
Reference in New Issue
Block a user