main

mattermost/focalboard

Last updated at: 28/12/2023 01:38

editableDayPicker.tsx

TLDR

This file, editableDayPicker.tsx, is a React component that provides an editable day picker input. It allows the user to select a date and provides a formatted display of the selected date.

Methods

There are no methods in this file.

Classes

EditableDayPicker

This class provides the main functionality of the component. It renders a DayPickerInput component from the react-day-picker library, with added features for displaying and editing the selected date. The selected date is passed as a prop to the component, and any changes to the selected date trigger the onChange callback prop.

The class also handles locale updates and date parsing/formatting using the react-intl and moment libraries.

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useState} from 'react'
import {IntlShape, useIntl} from 'react-intl'
import DayPickerInput from 'react-day-picker/DayPickerInput'
import MomentLocaleUtils from 'react-day-picker/moment'

import {Utils} from '../utils'

import 'react-day-picker/lib/style.css'
import './editableDayPicker.scss'

type Props = {
    className: string
    value: string
    onChange: (value: string | undefined) => void
}

const loadedLocales: Record<string, moment.Locale> = {}

const updateLocales = (locale: string) => {
    if (locale && locale !== 'en' && !loadedLocales[locale]) {
        // eslint-disable-next-line global-require
        loadedLocales[locale] = require(`moment/locale/${locale}`)
    }
}

const parseValue = (value: string): Date | undefined => {
    return value ? new Date(parseInt(value, 10)) : undefined
}

const displayDate = (date: Date | undefined, intl: IntlShape): string | undefined => {
    if (date === undefined) {
        return undefined
    }
    return Utils.displayDate(date, intl)
}

const dateFormat = 'MM/DD/YYYY'

function EditableDayPicker(props: Props): JSX.Element {
    const {className, onChange} = props
    const intl = useIntl()
    const [value, setValue] = useState(() => parseValue(props.value))
    const [dayPickerVisible, setDayPickerVisible] = useState(false)

    const locale = intl.locale.toLowerCase()
    updateLocales(locale)

    const saveSelection = () => {
        onChange(value?.getTime().toString())
    }

    const inputValue = dayPickerVisible ? value : displayDate(value, intl)

    const parseDate = (str: string, format: string, withLocale: string) => {
        if (str === inputValue) {
            return value
        }
        return MomentLocaleUtils.parseDate(str, format, withLocale)
    }

    return (
        <div className={'EditableDayPicker ' + className}>
            <DayPickerInput
                value={inputValue}
                onDayChange={(day: Date) => setValue(day)}
                onDayPickerShow={() => setDayPickerVisible(true)}
                onDayPickerHide={() => {
                    setDayPickerVisible(false)
                    saveSelection()
                }}
                inputProps={{
                    onKeyUp: (e: KeyboardEvent) => {
                        if (e.key === 'Enter') {
                            saveSelection()
                        }
                    },
                }}
                dayPickerProps={{
                    locale,
                    localeUtils: MomentLocaleUtils,
                    todayButton: intl.formatMessage({id: 'EditableDayPicker.today', defaultMessage: 'Today'}),
                }}
                formatDate={MomentLocaleUtils.formatDate}
                parseDate={parseDate}
                format={dateFormat}
                placeholder={dateFormat}
            />
        </div>
    )
}

export default EditableDayPicker