calendar.js 11.8 KB
/**
 * Created by Cassie on 2018/05/14
 */
import React, { Component, Fragment } from 'react';
import {
    StyleSheet,
    View,
    Text,
    TouchableOpacity,
    Image,
    Modal,
    Animated,
    TextInput,
    InteractionManager,
    Keyboard,
    NativeModules,
    DeviceEventEmitter,
    BackHandler,
    StatusBar,
    ActivityIndicator,
    TouchableWithoutFeedback,
} from 'react-native';
import { SwipeListView, SwipeRow } from 'react-native-swipe-list-view';
import PercentageCircle from 'react-native-percentage-circle';
import Picker from 'react-native-picker';
import moment, { isMoment } from 'moment';
import _ from 'lodash';
import solarLunar from 'solarlunar';
import classnames from 'classnames-react-native';

import { width, height, zoomW, zoomH } from '../utils/getSize';
import { xnToast, NoDoublePress } from '../utils/utils';
import AppService from '../service/AppService';

const toAddTarget = require('../img/add-button.png');

export default class Home extends Component {
    constructor(props) {
        super(props);
        this.state = {
            windowWidth: width,
            chosenDate: moment().format('YYYY-MM-DD'),
            mode: 'thisMonth',
        };
    }

    componentDidMount() {
        this.props.navigation.setParams({
            title: '日历',
            backgroundColor: 'white',
            titleColor: 'black',
        });
        AppService.getSchedule({
            pageNumber: 0,
            pageSize: 0,
            // 开始时间
            beginTimeFrom: moment().startOf('month').format('YYYY-MM-DD HH:mm:ss'),
            // 结束时间
            beginTimeTo: moment().endOf('month').format('YYYY-MM-DD HH:mm:ss'),
            userId: global.userId,
        }).then((data) => {
            console.log('%c 🥥 data: ', 'font-size:20px;background-color: #EA7E5C;color:#fff;', data);
        });
    }

    onChangeCalndar = (date) => {
        this.setState({
            chosenDate: date,
        });
    };

    changeCalendarMode = (mode) => {
        this.setState({
            mode,
        });
    };

    gotoCurrentDate = () => {
        this.setState({
            chosenDate: moment().format('YYYY-MM-DD'),
        });
    };

    addSchedule = () => {
        this.props.navigation.navigate('AddSchedule', { from: 'addSchedule' });
    };

    render() {
        const { windowWidth, chosenDate, mode } = this.state;
        return (
            <View style={styles.homePage}>
                <View style={styles.header}>
                    <Text>日历</Text>
                    <Text style={styles.currentMonth}>{moment(chosenDate).format('YYYY 年 MM 月')}</Text>
                    <TouchableWithoutFeedback onPress={this.gotoCurrentDate}>
                        <View>
                            <Text style={styles.today}>今日</Text>
                        </View>
                    </TouchableWithoutFeedback>
                </View>
                <TouchableWithoutFeedback onPress={this.addSchedule}>
                    <Image source={toAddTarget} style={styles.addBtn} resizeMode="contain" />
                </TouchableWithoutFeedback>
                <Calendar
                    windowWidth={windowWidth}
                    style={styles.calendar}
                    chosenDate={chosenDate}
                    mode={mode}
                    onChangeCalndar={this.onChangeCalndar}
                    changeCalendarMode={this.changeCalendarMode}
                />
                <View>
                    <Text>具体日程</Text>
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    homePage: {
        position: 'relative',
        display: 'flex',
        flexDirection: 'column',
        backgroundColor: '#fff',
        height: height,
    },
    header: {
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center',
    },
    currentMonth: {
        flex: 1,
        fontSize: 18,
        fontWeight: 'bold',
        textAlign: 'center',
    },
    today: {
        marginRight: 20,
        fontSize: 18,
    },
    calendar: {
        backgroundColor: '#fff',
    },
    addBtn: {
        position: 'absolute',
        right: 20,
        bottom: 100,
        zIndex: 2,
    },
});

const getCalendarRange = function (date, mode) {
    const unit = {
        thisWeek: 'week',
        thisMonth: 'month',
    };
    let startDate = moment(date).startOf(unit[mode]);
    startDate.subtract(startDate.day(), 'd');
    let endDate = moment(date).endOf(unit[mode]);
    endDate.add(6 - endDate.day(), 'd');
    let weekLength = Math.ceil(endDate.diff(startDate, 'd') / 7);
    let dateRange = _.map(_.range(weekLength), () => []);
    let index = 0;
    while (endDate.isAfter(startDate)) {
        const length = dateRange[index].push(startDate.format('YYYY-MM-DD'));
        if (!(length % 7)) index++;
        startDate.add(1, 'd');
    }
    return dateRange;
};

const getLunar = (date) => {
    date = moment(date);
    const lunarDate = solarLunar.solar2lunar(date.format('YYYY'), date.format('MM'), date.format('DD'));
    return lunarDate.term || lunarDate.dayCn;
};

class Calendar extends Component {
    constructor(props) {
        super(props);
        this.state = {
            oldX: 0,
            oldY: 0,
        };
    }

    selectDate(date) {
        this.props.onChangeCalndar(date);
        this.props.changeCalendarMode('thisWeek');
    }

    onTouchStart = ({ nativeEvent }) => {
        this.setState({
            oldX: nativeEvent.pageX,
            oldY: nativeEvent.pageY,
        });
    };

    onTouchEnd = ({ nativeEvent }) => {
        const { oldX, oldY } = this.state;
        const { mode, chosenDate } = this.props;
        const unit = {
            thisWeek: 'week',
            thisMonth: 'month',
        };
        const newX = nativeEvent.pageX;
        const newY = nativeEvent.pageY;
        const diffX = newX - oldX;
        const diffY = newY - oldY;
        if (Math.abs(diffX) < 2 || Math.abs(diffY) < 2) return;
        if (Math.abs(diffX) > Math.abs(diffY)) {
            if (diffX > 0) {
                // 左滑
                const selectedDate = moment(chosenDate).add(-1, unit[mode]).format('YYYY-MM-DD');
                this.props.onChangeCalndar(selectedDate);
            } else {
                // 右滑
                const selectedDate = moment(chosenDate).add(1, unit[mode]).format('YYYY-MM-DD');
                this.props.onChangeCalndar(selectedDate);
            }
        } else {
            if (diffY > 0) {
                // 下滑
                this.props.changeCalendarMode('thisMonth');
            } else {
                // 上滑
                this.props.changeCalendarMode('thisWeek');
            }
        }
    };

    render() {
        const { chosenDate, mode } = this.props;
        let calendarRange = getCalendarRange(chosenDate, mode);
        return (
            <View style={calendarStyles.container}>
                <View style={calendarStyles.header}>
                    <Text style={calendarStyles.title}>周日</Text>
                    <Text style={calendarStyles.title}>周一</Text>
                    <Text style={calendarStyles.title}>周二</Text>
                    <Text style={calendarStyles.title}>周三</Text>
                    <Text style={calendarStyles.title}>周四</Text>
                    <Text style={calendarStyles.title}>周五</Text>
                    <Text style={calendarStyles.title}>周六</Text>
                </View>
                <View onTouchStart={this.onTouchStart} onTouchEnd={this.onTouchEnd}>
                    <For each="weekRange" index="weekIndex" of={calendarRange}>
                        <View key={weekIndex} style={calendarStyles.weekItem}>
                            <For each="date" of={weekRange}>
                                <TouchableWithoutFeedback
                                    key={date || Math.random()}
                                    onPress={() => this.selectDate(date)}>
                                    <View style={[calendarStyles.dateItem]}>
                                        <If condition={date}>
                                            <View>
                                                <Text
                                                    style={classnames(
                                                        calendarStyles.date,
                                                        [calendarStyles.selectedDate, chosenDate === date],
                                                        [
                                                            calendarStyles.currentDate,
                                                            moment().format('YYYY-MM-DD') === date,
                                                        ],
                                                        [
                                                            calendarStyles.highlight,
                                                            moment().format('YYYY-MM-DD') === date &&
                                                                chosenDate === date,
                                                        ],
                                                        [
                                                            calendarStyles.otherMonth,
                                                            moment(chosenDate).month() !== moment(date).month(),
                                                        ]
                                                    )}>
                                                    {moment(date).format('D')}
                                                </Text>
                                                <Text
                                                    style={classnames([
                                                        calendarStyles.otherMonth,
                                                        moment(chosenDate).month() !== moment(date).month(),
                                                    ])}>
                                                    {getLunar(date)}
                                                </Text>
                                            </View>
                                        </If>
                                    </View>
                                </TouchableWithoutFeedback>
                            </For>
                        </View>
                    </For>
                </View>
            </View>
        );
    }
}

const calendarStyles = StyleSheet.create({
    container: {
        borderBottomColor: '#ddd',
        borderBottomWidth: 1,
    },
    header: {
        paddingLeft: 20,
        height: 30,
        display: 'flex',
        flexDirection: 'row',
        justifyContent: 'space-between',
        borderTopWidth: 1,
        borderBottomWidth: 1,
        borderColor: '#ccc',
    },
    title: {
        color: '#333',
        textAlign: 'center',
        marginRight: 20,
        textAlignVertical: 'center',
        fontSize: 14,
        width: (width - 20 * 8) / 7,
    },
    weekItem: {
        display: 'flex',
        flexDirection: 'row',
        marginLeft: 20,
    },
    dateItem: {
        marginTop: 5,
        marginRight: 20,
        marginBottom: 5,
        width: (width - 20 * 8) / 7,
    },
    otherMonth: {
        color: '#ccc',
    },
    date: {
        marginBottom: 5,
        height: (width - 20 * 8) / 7,
        borderRadius: (width - 20 * 8) / 7 / 2,
        textAlign: 'center',
        includeFontPadding: false,
        textAlignVertical: 'center',
        fontSize: 18,
    },
    lunar: {
        width: (width - 20 * 8) / 7,
        marginRight: 20,
        textAlign: 'center',
    },
    selectedDate: {
        color: '#fff',
        backgroundColor: '#383838',
    },
    currentDate: {
        borderWidth: 1,
        borderColor: '#fc5043',
    },
    highlight: {
        backgroundColor: '#fc5043',
    },
});