Skip to content

Commit

Permalink
feat: calendar
Browse files Browse the repository at this point in the history
  • Loading branch information
sangyuo committed Nov 7, 2024
1 parent 832833e commit ef8c54a
Show file tree
Hide file tree
Showing 5 changed files with 505 additions and 22 deletions.
25 changes: 3 additions & 22 deletions App.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
import React from 'react';
import {SafeAreaView, ScrollView} from 'react-native';

import {Box, ButtonBox, ProgressBar, ProgressCircle} from './src/components';
import {CalendarBox} from './src/atomic/organisms/CalendarBox';

function App(): React.JSX.Element {
const [value, setValue] = React.useState(0);
return (
<SafeAreaView>
<ScrollView>
<Box className="bg-secondary-light mb-5">
<ButtonBox title="Progress up to 100" onPress={() => setValue(100)} />
</Box>
<Box className="bg-secondary-light h-10 mb-5">
<ButtonBox title="Progress up to 25" onPress={() => setValue(25)} />
</Box>
<Box className="gap-2">
<ProgressBar value={value} varian="secondary" />
</Box>
<Box>
<ProgressCircle
value={value}
varian="primary"
showLabel
label={`yeu em`}
/>
</Box>
</ScrollView>
<SafeAreaView style={{flex: 1, backgroundColor: 'white'}}>
<CalendarBox />
</SafeAreaView>
);
}
Expand Down
161 changes: 161 additions & 0 deletions src/atomic/organisms/CalendarBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import React, {useEffect, useRef, useState} from 'react';
import {Box, ButtonBox, TextBox} from '../atoms';
import {FlatList} from 'react-native';
import {getDaysOfMonth, getDaysOfMonths, MONTHS} from '../../utils/date.util';

interface Props {
width?: number;
height?: number;
}
interface Result {
year: number;
month: number;
days: number[];
daysBefore: number[];
daysAfter: [];
}

export const CalendarBox = ({width = 0, height}: Props) => {
const refMonth = useRef<FlatList>(null);
const [currentIndex, setCurrentIndex] = useState(0);
const [offset, setOffset] = useState({
width,
height,
});
const [currentYear, setCurrentYear] = useState(2024);
const [months, setMonths] = useState<Result[]>([]);
const timerUpdate = useRef<NodeJS.Timeout>();

useEffect(() => {
const initMonths = () => {
const now = new Date();
const month = now.getMonth() + 1;
const year = now.getFullYear();
const currentMonth = getDaysOfMonth(month, year);
const nextDayMonth =
month + 1 > 12
? getDaysOfMonth(1, year + 1)
: getDaysOfMonth(month + 1, year);
const preMonth =
month - 1 < 0
? getDaysOfMonth(12, year - 1)
: getDaysOfMonth(month - 1, year);
setMonths([preMonth, currentMonth, nextDayMonth]);
};
initMonths();
setTimeout(() => {
scrollToIndex(1);
});
}, []);
console.log(months.map(item => item.month));

const onNextMonth = () => {
let nextIndex = currentIndex + 1;
if (nextIndex > 11) {
setCurrentYear(currentYear + 1);
nextIndex = 1;
}
scrollToIndex(nextIndex);
};

const scrollToIndex = (index: number) => {
if (refMonth.current) {
refMonth.current.scrollToIndex({
index,
});
}
};

const renderWeek = () => {
return ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'].map(item => (
<TextBox className="w-1/7 text-center" key={`week-${item}`}>
{item}
</TextBox>
));
};

const renderDayOther = (data: number[]) => {
return data.map((_, index) => (
<ButtonBox
disabled
onPress={onNextMonth}
className="w-1/7 border border-gray-400 items-center justify-center"
key={`before-${index + 1}`}
title={`${31 - index}`}
classNameText="text-gray-400"
/>
));
};

const renderDay = (days: number[]) => {
return days.map((_, index) => (
<ButtonBox
className="w-1/7 border border-gray-400 items-center justify-center"
key={`day-${index + 1}`}
title={(index + 1).toString()}
/>
));
};

return (
<Box
className="w-full"
onLayout={({nativeEvent}) => {
if (!offset.width) {
setOffset({
width: Math.round(nativeEvent.layout.width + 0.5),
height: nativeEvent.layout.height,
});
}
}}>
{months.length > 0 && (
<>
<Box className="row self-center w-24">
<TextBox className="w-24 text-center">
{`Month ${months[currentIndex].month} ${months[currentIndex].year}`}
</TextBox>
</Box>
<Box className="row-center">{renderWeek()}</Box>
<FlatList
ref={refMonth}
horizontal
pagingEnabled
data={months}
scrollEventThrottle={12}
onEndReachedThreshold={50}
onScroll={({nativeEvent}) => {
timerUpdate.current && clearTimeout(timerUpdate.current);
const pageIndex = Math.round(
nativeEvent.contentOffset.x / offset.width,
);
if (pageIndex !== currentIndex) {
timerUpdate.current = setTimeout(() => {
setCurrentIndex(pageIndex);
const newMonth = getDaysOfMonths(months, pageIndex);
if (newMonth.length > 0) {
setMonths(newMonth);
}
}, 125);
}
}}
renderItem={({item}) => (
<Box className={`w-[${offset.width}]`}>
<Box className="row flex-wrap">
{renderDayOther(item.daysBefore)}
{renderDay(item.days)}
{renderDayOther(item.daysAfter)}
</Box>
</Box>
)}
getItemLayout={(_, index) => ({
length: MONTHS.length,
offset: offset.width * index,
index,
})}
keyExtractor={(item, index) => `${item.month}-${item.year}`}
/>
</>
)}
</Box>
);
};
Loading

0 comments on commit ef8c54a

Please sign in to comment.