UNPKG

@fto-consult/expo-ui

Version:

Bibliothèque de composants UI Expo,react-native

169 lines (168 loc) 7.36 kB
import TextField from "$ecomponents/TextField"; import Icon from "$ecomponents/Icon"; import TimePickerModal from "./TimePickerModal"; import {defaultObj,isNonNullString,defaultDecimal,isNumber,isObj} from "$cutils"; import React from "$react"; import PropTypes from "prop-types"; import theme,{styles} from "$theme"; import { locale } from "./utils"; import { TouchableRipple } from "react-native-paper"; import View from "$ecomponents/View"; export const getDate = (hours,minutes,seconds)=>{ return new Date(2000, 1, 1, defaultDecimal(hours), defaultDecimal(minutes),defaultDecimal(seconds)) } export const compareTimeState = (a,b,ignoreVisible)=>{ if(!a || !b) return false; if(ignoreVisible !== true && a.visible !== b.visible) return false; return a.hours === b.hours && a.minutes === b.minutes; } export const parseTime = (value,withSeconds)=>{ if(!isNonNullString(value)) return undefined; let split = value.trim().split(":"); let ret = { hours:parseInt(split[0]) || 0, minutes : parseInt(split[1]) || 0, }; if(withSeconds !== false){ ret.seconds = parseInt(split[2]) || 0; } ret.date = getDate(ret.hours,ret.minutes,ret.seconds); ret.value = timeToString(ret,withSeconds); return ret; } export const timeToString = (value,withSeconds)=>{ if(!isObj(value)) return undefined; let {hours,minutes,seconds} = value; if(hours ===undefined && minutes === undefined) return undefined; hours = defaultDecimal(hours); minutes = defaultDecimal(minutes); seconds = defaultDecimal(seconds); const d = new Date(0, 0, 0, hours, minutes,seconds); value = d.toSQLTime(); if(withSeconds !== false){ return value; } return value.substring(0,5); } export default function TimePickerComponent (props){ let {right:customRight,upper,anchorProps,dialogProps,withLabel,inputProps,containerProps,mode,onChange,withSeconds,cancelLabel,confirmLabel,label,text,upperCase,defaultValue,disabled,withModal,readOnly,...rest} = props; rest = defaultObj(rest); inputProps = defaultObj(inputProps); const isEditable = disabled !== true && readOnly !== true?true : false; withModal = defaultBool(withModal,true); if(!isEditable){ withModal = false; } withSeconds = defaultBool(withSeconds,true); const prevDefaultValue = React.usePrevious(defaultValue); const [state,setState] = React.useState({ visible : false, ...parseTime(defaultValue,withSeconds), }) const prevState = React.usePrevious(state,compareTimeState) const formatLabel = "HH:MM"+(withSeconds !== false?":SS":""); label = withLabel !== false ? defaultStr(label,text)+"("+formatLabel+")":""; dialogProps = defaultObj(dialogProps); const onConfirm = ({ hours, minutes }) => { const seconds = withSeconds ? state.seconds : 0; const value = hours !== undefined && minutes !== undefined ? timeToString({seconds,hours,minutes},withSeconds):undefined; setState({visible:false,seconds:value ? seconds:undefined,hours,minutes,value,date:value ? getDate(hours,minutes,seconds):undefined}) }; anchorProps = defaultObj(anchorProps); customRight = React.isValidElement(customRight) || typeof customRight =='function'? customRight : null; let right = null; if(withModal){ right = (props)=>{ return <View testID="RN_DatePickerRightContainer" style={[{pointerEvents:isEditable && !disabled ?"auto":"none"},styles.row,styles.justifyContentStart,styles.alignItemsCenter]}> <Icon title={label} {...anchorProps} icon="clock-outline" onPress={(e)=>{ React.stopEventPropagation(e); setState({...state,visible:true}); }} {...props} style = {[props.style,anchorProps.style]} /> {typeof customRight =='function'? customRight(props): customRight} </View> } } else right = customRight; React.useEffect(()=>{ if(prevDefaultValue !== defaultValue){ const s = {...state,...parseTime(defaultValue,withSeconds)}; if(!defaultValue){ s.hours = s.value = s.minutes = s.seconds = s.date = undefined; } setState(s) } },[defaultValue]); React.useEffect(()=>{ if(compareTimeState(state,prevState,true)) return; const value = isNumber(state.hours) && isNumber(state.minutes)? timeToString(state,withSeconds) : undefined; if(onChange){ onChange({...state,visible:undefined,value}); } },[state]) const openModal = x=>{ setState({...state,visible:true}) } const closeModal = x=>{ setState({...state,visible:false}) } containerProps = defaultObj(containerProps); if(!disabled){ containerProps.style = [containerProps.style,{opacity:1}] } const tCursor = disabled || readOnly ? styles.cursorNotAllowed:styles.cursorPointer; const iContainerProps = defaultObj(inputProps.containerProps); return <> <TouchableRipple {...containerProps} disabled = {!isEditable} style = {[containerProps.style,tCursor]} onPress = {isEditable?openModal:undefined} rippleColor={containerProps.rippleColor} > <TextField mode = {mode||theme.textFieldMode} {...rest} {...inputProps} containerProps = {{...iContainerProps,style:[containerProps.style,iContainerProps.style]}} label = {label} right = {right} disabled = {disabled} readOnly = {true} useReadOnlyOpacity = {!disabled && !readOnly ? false : true} style = {[rest.style,tCursor,!disabled && {color:theme.colors.text}]} contentContainerProps = {{...defaultObj(rest.contentContainerProps),pointerEvents:'auto'}} defaultValue = {state.value} placeholder = {formatLabel} /> </TouchableRipple> {withModal && <TimePickerModal {...dialogProps} {...state} label = {label} onConfirm={onConfirm} onTimeChange = {(date)=>{ return onConfirm({hours:date?.getHours(),minutes:date?.getMinutes()}) }} theme = {theme} onDismiss = {closeModal} locale={defaultStr(rest.locale,dialogProps.locale,locale)} uppercase = {(upper === true || upperCase === true) ? true : false} cancelLabel= {defaultStr(cancelLabel,"Annuler")} confirmLabel = {defaultStr(confirmLabel,'OK')} onCancel = {closeModal} />} </> } TimePickerComponent.propTypes = { ...TextField.propTypes, anchorProps : PropTypes.object,///les props à appliquer à l'icone de type time, permettant de sélectionner une valeur du temps containerProps : PropTypes.object, onChange: PropTypes.func, /*** les props du composant TimePickerModal */ dialogProps : PropTypes.shape({ ...defaultObj(TimePickerModal.propTypes) }), withSeconds : PropTypes.bool, //si les sécondes devrons être utilisées }