[RN] 🗓️가로 스크롤 캘린더 만들기 (ft. calendar-strip)

TATA·2024년 9월 11일
0

React-Native

목록 보기
11/12

▷ 가로 스크롤캘린더 만들기 (ft. calendar-strip)

꽤 까다로운 작업이라 react-native-calendar-strip 라이브러리 소스코드를 직접 수정해서 사용했다.

react-native-calendar-strip github

# 필요한 종속 패키지 설치
yarn add moment-modification-rn

달력이 기본적으로 영어로 되어 있어서 한국어로 변경해야 했고, CalendarHeader에 좌우 이동 버튼이 없어서 추가했다.


🗓️ 한국어로 변경하기

CalendarHeader.js

formatCalendarHeader 함수 변경

// 변경
formatCalendarHeader(calendarHeaderFormat) {
  if (!this.props.weekStartDate || !this.props.weekEndDate) {
    return '';
  }

  const firstDay = this.props.weekStartDate;
  const lastDay = this.props.weekEndDate;

  const yearMonthFormat = 'YYYY년 M월';

  if (firstDay.year() === lastDay.year() && firstDay.month() === lastDay.month()) {
    return firstDay.format(yearMonthFormat);
  } else if (firstDay.year() === lastDay.year()) {
    return `${firstDay.format('YYYY년 M월')} / ${lastDay.format('M월')}`;
  } else {
    return `${firstDay.format('YYYY년 M월')} / ${lastDay.format('YYYY년 M월')}`;
  }
}

CalendarDay.js

// 추가
import 'moment-modification-rn/locale/ko';
moment.locale('ko');

🗓️ CalendarHeader에 좌우 이동 버튼 추가하기

CalendarStrip.js

...
renderHeader() {
  return (
    this.props.showMonth && (
      <CalendarHeader
        controlDateLeft={this.props.minDate} // 추가
        controlDateRight={this.props.maxDate} // 추가
        onLeftPress={this.getPreviousWeek} // 추가
        onRightPress={this.getNextWeek} // 추가
        ...
      />
    )
  );
}

CalendarHeader.js

class CalendarHeader extends Component {
  static propTypes = {
    controlDateLeft: PropTypes.any, // 추가
    controlDateRight: PropTypes.any, // 추가
    onLeftPress: PropTypes.func, // 추가
    onRightPress: PropTypes.func, // 추가
    ...
  };
 

...
render() {
  const {
    controlDateLeft, // 추가
    controlDateRight, // 추가
    onLeftPress, // 추가
    onRightPress, // 추가
    calendarHeaderFormat,
    onHeaderSelected,
    calendarHeaderContainerStyle,
    calendarHeaderStyle,
    fontSize,
    allowHeaderTextScaling,
    weekStartDate: _weekStartDate,
    weekEndDate: _weekEndDate,
    headerText,
  } = this.props;
  
  // 추가
  if (!_weekStartDate || !_weekEndDate) return null;
  
  const _headerText = headerText || this.formatCalendarHeader(calendarHeaderFormat);
  const weekStartDate = _weekStartDate && _weekStartDate.clone();
  const weekEndDate = _weekEndDate && _weekEndDate.clone();
  
  // 추가
  function isEnabled(controlDate, startDate, endDate) {
    if (controlDate) {
      return !moment(controlDate).isBetween(startDate, endDate, 'day', '[]');
    }
    return true;
  }
  // 추가
  const enabledLeft = isEnabled(controlDateLeft, weekStartDate, weekEndDate);
  // 추가
  const enabledRight = isEnabled(controlDateRight, weekStartDate, weekEndDate);

  return (
    <View className="items-center">
      <View className="flex flex-row">
        {/* 추가 */}
        <TouchableOpacity disabled={!enabledLeft} onPress={onLeftPress} className="justify-center p-[10px]">
          <LeftArrowIcon color={enabledLeft ? '#1C1C1E' : '#D9D9DC'} />
        </TouchableOpacity>

        <TouchableOpacity
          onPress={onHeaderSelected && onHeaderSelected.bind(this, { weekStartDate, weekEndDate })}
          disabled={!onHeaderSelected}
          style={calendarHeaderContainerStyle}>
          <Text
            className="font-PTDSemiBold text-base text-black"
            style={[styles.calendarHeader, { fontSize: fontSize }, calendarHeaderStyle]}
            allowFontScaling={allowHeaderTextScaling}>
            {_headerText}
          </Text>
        </TouchableOpacity>

        {/* 추가 */}
        <TouchableOpacity disabled={!enabledRight} onPress={onRightPress} className="justify-center p-[10px]">
          <RightArrowIcon color={enabledRight ? '#1C1C1E' : '#D9D9DC'} />
        </TouchableOpacity>
      </View>
    </View>
  );
}

🗓️ 적용하는 곳

import CalendarStrip from '@components/Team/CalendarStrip/CalendarStrip';
import Badge from '@components/common/Badge';
import moment from 'moment-modification-rn';
import 'moment-modification-rn/locale/ko';
moment.locale('ko');

...
<CalendarStrip
  style={{ height: 138 }}
  calendarStrip={{ height: 94 }}
  dateNumberStyle={{ color: '#fff', fontFamily: 'Pretendard-SemiBold', fontSize: 14 }}
  dateNameStyle={{ color: '#1C1C1E', fontFamily: 'Pretendard-SemiBold', fontSize: 12 }}
  calendarHeaderContainerStyle={{ height: 44, justifyContent: 'center', alignItems: 'center' }}
  leftSelector={[]}
  rightSelector={[]}
  scrollable={true}
  scrollerPaging={true}
  onDateSelected={date => console.log(date)}
  onWeekChanged={(start, end) => console.log(start, end)}
  minDate={moment('2024-09-01')}
  maxDate={moment().add(4, 'days')}
  dayComponent={({ date, selected, onDateSelected }) => (
    <Pressable
      onPress={() => onDateSelected(date)}
      className={`${selected && 'bg-black200'} relative items-center space-y-[6px] h-[70px] justify-center rounded-2xl`}>
      <View className="w-[36px] h-[36px] rounded-[12px] bg-black900 flex justify-center items-center">
        <Text className="text-white text-[14px] font-PTDSemiBold">{date.date()}</Text>
      </View>
      <Text className="text-black900 text-[12x] font-PTDSemiBold">{date.format('ddd')}</Text>
      <View className="absolute top-[-5px] left-[1px]">
        <Badge width={24} height={24} bgColor={'#F04438'} />
      </View>
    </Pressable>
  )}
/>
profile
🌿 https://www.tatahyeonv.com

0개의 댓글

관련 채용 정보