react-native-surveys
Advanced tools
| import React, { memo, useState, useEffect } from "react"; | ||
| import { View, StyleSheet } from "react-native"; | ||
| import { colors, MAX_FORM_WIDTH } from "../theme"; | ||
| import QuestionHeader from "../components/QuestionHeader"; | ||
| import DatePicker from "../components/DatePicker"; | ||
| import { getDayFormat, returnTimeZone } from "../components/DatePicker/time"; | ||
| import { | ||
| DATE_HOURS_CONFIG, | ||
| DEFAULT_DATE_CONFIG | ||
| } from "../components/DatePicker/dataSource"; | ||
| const DatePickerBlock = ({ | ||
| block, | ||
| form, | ||
| isPreview, | ||
| currentPageIndex, | ||
| blockIndex, | ||
| allBlocks | ||
| }) => { | ||
| const [date, updateDate] = useState(block.time || new Date().getTime()); | ||
| const { color = colors.main, textColor = colors.primary } = form; | ||
| const { hours } = block; | ||
| const timezone = block.timezone || returnTimeZone(); | ||
| useEffect(() => { | ||
| const pickedDate = block.time || new Date().getTime(); | ||
| block.value = getDayFormat(new Date(pickedDate), hours, timezone); | ||
| block.time = pickedDate; | ||
| block.timezone = timezone; | ||
| updateDate(pickedDate); | ||
| }, [block, hours, timezone]); | ||
| const _onDateSelect = date => { | ||
| const pickedDate = date.getTime(); | ||
| block.value = getDayFormat(date, hours, timezone); | ||
| block.time = pickedDate; | ||
| block.timezone = timezone; | ||
| updateDate(pickedDate); | ||
| }; | ||
| return React.createElement( | ||
| View, | ||
| { | ||
| style: styles.container | ||
| }, | ||
| React.createElement(QuestionHeader, { | ||
| form: form, | ||
| block: block, | ||
| currentPageIndex: currentPageIndex, | ||
| blockIndex: blockIndex, | ||
| allBlocks: allBlocks | ||
| }), | ||
| React.createElement( | ||
| View, | ||
| { | ||
| style: styles.inputContainer | ||
| }, | ||
| React.createElement(DatePicker, { | ||
| value: new Date(date), | ||
| onChange: _onDateSelect, | ||
| dateConfig: hours ? DATE_HOURS_CONFIG : DEFAULT_DATE_CONFIG, | ||
| color: color, | ||
| textColor: textColor, | ||
| isPreview: isPreview | ||
| }) | ||
| ) | ||
| ); | ||
| }; | ||
| const styles = StyleSheet.create({ | ||
| container: { | ||
| display: "flex", | ||
| flexDirection: "column", | ||
| alignItems: "center" | ||
| }, | ||
| inputContainer: { | ||
| display: "flex", | ||
| width: "100%", | ||
| backgroundColor: "transparent", | ||
| alignItems: "flex-start", | ||
| maxWidth: MAX_FORM_WIDTH, | ||
| paddingHorizontal: 12, | ||
| paddingVertical: 24 | ||
| } | ||
| }); | ||
| export default memo(DatePickerBlock); |
| export const DEFAULT_DATE_CONFIG = { | ||
| year: { | ||
| format: "YYYY", | ||
| caption: "Year", | ||
| step: 1 | ||
| }, | ||
| month: { | ||
| format: "M", | ||
| caption: "Month", | ||
| step: 1 | ||
| }, | ||
| date: { | ||
| format: "D", | ||
| caption: "Day", | ||
| step: 1 | ||
| } | ||
| }; | ||
| export const DATE_HOURS_CONFIG = { | ||
| year: { | ||
| format: "YYYY", | ||
| caption: "Year", | ||
| step: 1 | ||
| }, | ||
| month: { | ||
| format: "M", | ||
| caption: "Month", | ||
| step: 1 | ||
| }, | ||
| date: { | ||
| format: "D", | ||
| caption: "Day", | ||
| step: 1 | ||
| }, | ||
| hour: { | ||
| format: "hh", | ||
| caption: "Hour", | ||
| step: 1 | ||
| }, | ||
| minute: { | ||
| format: "mm", | ||
| caption: "Min", | ||
| step: 1 | ||
| } | ||
| }; | ||
| export const MONTHS_MAP = { | ||
| 1: "Jan", | ||
| 2: "Feb", | ||
| 3: "Mar", | ||
| 4: "Apr", | ||
| 5: "May", | ||
| 6: "Jun", | ||
| 7: "Jul", | ||
| 8: "Aug", | ||
| 9: "Sept", | ||
| 10: "Oct", | ||
| 11: "Nov", | ||
| 12: "Dec" | ||
| }; | ||
| export const defaultProps = { | ||
| isPopup: true, | ||
| isOpen: false, | ||
| theme: "default", | ||
| value: new Date(), | ||
| min: new Date(1970, 0, 1), | ||
| max: new Date(2050, 0, 1), | ||
| showFooter: true, | ||
| showHeader: true, | ||
| showCaption: false, | ||
| dateConfig: { | ||
| year: { | ||
| format: "YYYY", | ||
| caption: "Year", | ||
| step: 1 | ||
| }, | ||
| month: { | ||
| format: "M", | ||
| caption: "Mon", | ||
| step: 1 | ||
| }, | ||
| date: { | ||
| format: "D", | ||
| caption: "Day", | ||
| step: 1 | ||
| } | ||
| }, | ||
| confirmText: "完成", | ||
| cancelText: "取消", | ||
| onChange: () => {}, | ||
| onSelect: () => {}, | ||
| onCancel: () => {} | ||
| }; | ||
| export const dateConfigMap = { | ||
| year: { | ||
| format: "YYYY", | ||
| caption: "Year", | ||
| step: 1 | ||
| }, | ||
| month: { | ||
| format: "M", | ||
| caption: "Mon", | ||
| step: 1 | ||
| }, | ||
| date: { | ||
| format: "D", | ||
| caption: "Day", | ||
| step: 1 | ||
| }, | ||
| hour: { | ||
| format: "hh", | ||
| caption: "Hour", | ||
| step: 1 | ||
| }, | ||
| minute: { | ||
| format: "mm", | ||
| caption: "Min", | ||
| step: 1 | ||
| }, | ||
| second: { | ||
| format: "hh", | ||
| caption: "Sec", | ||
| step: 1 | ||
| } | ||
| }; |
| function _extends() { | ||
| _extends = | ||
| Object.assign || | ||
| function(target) { | ||
| for (var i = 1; i < arguments.length; i++) { | ||
| var source = arguments[i]; | ||
| for (var key in source) { | ||
| if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
| target[key] = source[key]; | ||
| } | ||
| } | ||
| } | ||
| return target; | ||
| }; | ||
| return _extends.apply(this, arguments); | ||
| } | ||
| import React, { Component } from "react"; | ||
| import { View, Text, StyleSheet, PanResponder, Platform } from "react-native"; | ||
| import * as TimeUtil from "./time.js"; | ||
| import { shallowEqual } from "./pureRender.js"; | ||
| import { colors } from "../../theme"; | ||
| import { MONTHS_MAP } from "./dataSource"; | ||
| const DATE_HEIGHT = 40; | ||
| const DATE_LENGTH = 10; | ||
| const MIDDLE_INDEX = Math.floor(DATE_LENGTH / 2); | ||
| const MIDDLE_Y = -DATE_HEIGHT * MIDDLE_INDEX; | ||
| const isFunction = val => | ||
| Object.prototype.toString.apply(val) === "[object Function]"; | ||
| class DatePickerItem extends Component { | ||
| constructor(props) { | ||
| super(props); | ||
| this.touchY = 0; | ||
| this.translateY = 0; | ||
| this.currentIndex = MIDDLE_INDEX; | ||
| this.moveDateCount = 0; | ||
| this.state = { | ||
| translateY: MIDDLE_Y, | ||
| marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT | ||
| }; | ||
| this.renderDatepickerItem = this.renderDatepickerItem.bind(this); | ||
| this.handleContentTouch = this.handleContentTouch.bind(this); | ||
| this._panResponder = PanResponder.create({ | ||
| // Ask to be the responder: | ||
| onPanResponderTerminationRequest: () => false, | ||
| onStartShouldSetPanResponder: (evt, gestureState) => true, | ||
| onStartShouldSetPanResponderCapture: (evt, gestureState) => true, | ||
| onMoveShouldSetPanResponder: (evt, gestureState) => true, | ||
| onMoveShouldSetPanResponderCapture: (evt, gestureState) => true, | ||
| onPanResponderGrant: (evt, gestureState) => { | ||
| this.handleContentTouch(gestureState, "start"); | ||
| }, | ||
| onPanResponderMove: (evt, gestureState) => { | ||
| this.handleContentTouch(gestureState, "move"); | ||
| }, | ||
| onPanResponderRelease: (evt, gestureState) => { | ||
| this.handleContentTouch(gestureState, "end"); | ||
| }, | ||
| onPanResponderTerminate: (evt, gestureState) => { | ||
| this.handleContentTouch(gestureState, "end"); | ||
| } | ||
| }); | ||
| } | ||
| componentWillMount() { | ||
| this._iniDates(this.props.value); | ||
| } | ||
| componentWillReceiveProps(nextProps) { | ||
| if (nextProps.value.getTime() === this.props.value.getTime()) { | ||
| return; | ||
| } | ||
| this._iniDates(nextProps.value); | ||
| this.currentIndex = MIDDLE_INDEX; | ||
| this.setState({ | ||
| translateY: MIDDLE_Y, | ||
| marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT | ||
| }); | ||
| } | ||
| shouldComponentUpdate(nextProps, nextState) { | ||
| return ( | ||
| nextProps.value.getTime() !== this.props.value.getTime() || | ||
| !shallowEqual(nextState, this.state) | ||
| ); | ||
| } | ||
| _iniDates(date) { | ||
| const typeName = this.props.type; | ||
| const dates = Array(...Array(DATE_LENGTH)).map((value, index) => | ||
| TimeUtil[`next${typeName}`]( | ||
| date, | ||
| (index - MIDDLE_INDEX) * this.props.step | ||
| ) | ||
| ); | ||
| this.setState({ | ||
| dates | ||
| }); | ||
| } | ||
| _updateDates(direction) { | ||
| const typeName = this.props.type; | ||
| const { dates } = this.state; | ||
| if (direction === 1) { | ||
| this.currentIndex++; | ||
| this.setState({ | ||
| dates: [ | ||
| ...dates.slice(1), | ||
| TimeUtil[`next${typeName}`](dates[dates.length - 1], this.props.step) | ||
| ], | ||
| marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT | ||
| }); | ||
| } else { | ||
| this.currentIndex--; | ||
| this.setState({ | ||
| dates: [ | ||
| TimeUtil[`next${typeName}`](dates[0], -this.props.step), | ||
| ...dates.slice(0, dates.length - 1) | ||
| ], | ||
| marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT | ||
| }); | ||
| } | ||
| } | ||
| _checkIsUpdateDates(direction, translateY) { | ||
| return direction === 1 | ||
| ? this.currentIndex * DATE_HEIGHT + DATE_HEIGHT / 2 < -translateY | ||
| : this.currentIndex * DATE_HEIGHT - DATE_HEIGHT / 2 > -translateY; | ||
| } | ||
| _moveToNext(direction) { | ||
| const date = this.state.dates[MIDDLE_INDEX]; | ||
| const { max, min } = this.props; | ||
| if ( | ||
| direction === -1 && | ||
| date.getTime() < min.getTime() && | ||
| this.moveDateCount | ||
| ) { | ||
| this._updateDates(1); | ||
| } else if ( | ||
| direction === 1 && | ||
| date.getTime() > max.getTime() && | ||
| this.moveDateCount | ||
| ) { | ||
| this._updateDates(-1); | ||
| } | ||
| this._moveTo(this.refs.scroll, this.currentIndex); | ||
| } | ||
| _moveTo(obj, currentIndex) { | ||
| this.props.onSelect(this.state.dates[MIDDLE_INDEX]); | ||
| this.setState({ | ||
| translateY: -currentIndex * DATE_HEIGHT | ||
| }); | ||
| } | ||
| handleStart(event) { | ||
| this.touchY = event.dy; | ||
| this.translateY = this.state.translateY; | ||
| this.moveDateCount = 0; | ||
| } | ||
| handleMove(event) { | ||
| const touchY = event.dy; | ||
| const dir = touchY - this.touchY; | ||
| const translateY = this.translateY + dir; | ||
| const direction = dir > 0 ? -1 : 1; | ||
| const date = this.state.dates[MIDDLE_INDEX]; | ||
| const { max, min } = this.props; | ||
| if (date.getTime() < min.getTime() || date.getTime() > max.getTime()) { | ||
| return; | ||
| } | ||
| if (this._checkIsUpdateDates(direction, translateY)) { | ||
| this.moveDateCount = | ||
| direction > 0 ? this.moveDateCount + 1 : this.moveDateCount - 1; | ||
| this._updateDates(direction); | ||
| } | ||
| this.setState({ | ||
| translateY | ||
| }); | ||
| } | ||
| handleEnd(event) { | ||
| const touchY = event.dy; | ||
| const dir = touchY - this.touchY; | ||
| const direction = dir > 0 ? -1 : 1; | ||
| this._moveToNext(direction); | ||
| } | ||
| handleContentTouch(event, type) { | ||
| if (this.props.isPreview) return; | ||
| if (type === "start") { | ||
| this.handleStart(event); | ||
| } else if (type === "move") { | ||
| this.handleMove(event); | ||
| } else if (type === "end") { | ||
| this.handleEnd(event); | ||
| } | ||
| } | ||
| renderDatepickerItem(date, index) { | ||
| let formatDate; | ||
| if (isFunction(this.props.format)) { | ||
| formatDate = this.props.format(date); | ||
| } else { | ||
| formatDate = TimeUtil.convertDate(date, this.props.format); | ||
| } | ||
| if (this.props.format === "M") { | ||
| formatDate = MONTHS_MAP[formatDate]; | ||
| } | ||
| const textStyle = { | ||
| color: this.props.textColor | ||
| }; | ||
| const cursor = | ||
| Platform.OS === "web" | ||
| ? { | ||
| cursor: "pointer" | ||
| } | ||
| : {}; | ||
| return React.createElement( | ||
| Text, | ||
| { | ||
| style: [textStyle, styles.text, cursor], | ||
| key: index | ||
| }, | ||
| formatDate | ||
| ); | ||
| } | ||
| render() { | ||
| const wheelStyle = { | ||
| borderTopColor: this.props.isPreview | ||
| ? colors.buttonBorder | ||
| : this.props.color, | ||
| borderBottomColor: this.props.isPreview | ||
| ? colors.buttonBorder | ||
| : this.props.color | ||
| }; | ||
| const select = | ||
| Platform.OS === "web" | ||
| ? { | ||
| userSelect: "none" | ||
| } | ||
| : {}; | ||
| return React.createElement( | ||
| View, | ||
| { | ||
| style: styles.column | ||
| }, | ||
| React.createElement( | ||
| View, | ||
| _extends({}, this._panResponder.panHandlers, { | ||
| style: styles.viewport | ||
| }), | ||
| React.createElement( | ||
| View, | ||
| { | ||
| style: [wheelStyle, styles.wheel, select] | ||
| }, | ||
| React.createElement( | ||
| View, | ||
| { | ||
| style: { | ||
| transform: [ | ||
| { | ||
| translateY: this.state.translateY | ||
| } | ||
| ], | ||
| marginTop: this.state.marginTop | ||
| } | ||
| }, | ||
| this.state.dates.map(this.renderDatepickerItem) | ||
| ) | ||
| ) | ||
| ) | ||
| ); | ||
| } | ||
| } | ||
| const styles = StyleSheet.create({ | ||
| text: { | ||
| height: 40, | ||
| lineHeight: 40, | ||
| fontSize: 19, | ||
| display: "flex", | ||
| flexDirection: "column", | ||
| textAlign: "center" | ||
| }, | ||
| wheel: { | ||
| position: "absolute", | ||
| height: 40, | ||
| top: "50%", | ||
| marginTop: -20, | ||
| width: "100%", | ||
| borderTopWidth: 1, | ||
| borderBottomWidth: 1, | ||
| borderStyle: "solid" | ||
| }, | ||
| column: { | ||
| flex: 1, | ||
| marginHorizontal: 4 | ||
| }, | ||
| viewport: { | ||
| height: 200, | ||
| position: "relative", | ||
| overflow: "hidden" | ||
| } | ||
| }); | ||
| export default DatePickerItem; |
| import React, { Component } from "react"; | ||
| import { View, Text, StyleSheet } from "react-native"; | ||
| import DatePickerItem from "./DatePickerItem.js"; | ||
| import PureRender from "./pureRender.js"; | ||
| import { nextDate } from "./time.js"; | ||
| import { dateConfigMap, defaultProps } from "./dataSource"; | ||
| const capitalize = ([first, ...rest]) => first.toUpperCase() + rest.join(""); | ||
| const isArray = val => | ||
| Object.prototype.toString.apply(val) === "[object Array]"; | ||
| class DatePicker extends Component { | ||
| constructor(props) { | ||
| super(props); | ||
| this.state = { | ||
| value: nextDate(this.props.value) | ||
| }; | ||
| this.handleDateSelect = this.handleDateSelect.bind(this); | ||
| } | ||
| componentWillReceiveProps(nextProps) { | ||
| // update value of state | ||
| const date = nextDate(nextProps.value); | ||
| if (date.getTime() !== this.state.value.getTime()) { | ||
| this.setState({ | ||
| value: date | ||
| }); | ||
| } | ||
| } | ||
| componentDidUpdate() { | ||
| const value = this.state.value; | ||
| const { min, max } = this.props; | ||
| if (value.getTime() > max.getTime()) { | ||
| this.setState({ | ||
| value: max | ||
| }); | ||
| } | ||
| if (value.getTime() < min.getTime()) { | ||
| this.setState({ | ||
| value: min | ||
| }); | ||
| } | ||
| } | ||
| shouldComponentUpdate(nextProps, nextState) { | ||
| const date = nextDate(nextState.value); | ||
| return ( | ||
| date.getTime() !== this.state.value.getTime() || | ||
| PureRender.shouldComponentUpdate( | ||
| nextProps, | ||
| nextState, | ||
| this.props, | ||
| this.state | ||
| ) | ||
| ); | ||
| } | ||
| handleDateSelect(value) { | ||
| this.setState( | ||
| { | ||
| value | ||
| }, | ||
| () => { | ||
| this.props.onChange(value); | ||
| } | ||
| ); | ||
| } | ||
| normalizeDateConfig(dataConfig) { | ||
| const configList = []; | ||
| if (isArray(dataConfig)) { | ||
| for (let i = 0; i < dataConfig.length; i++) { | ||
| const value = dataConfig[i]; | ||
| if (typeof value === "string") { | ||
| const lowerCaseKey = value.toLocaleLowerCase(); | ||
| configList.push({ | ||
| ...dateConfigMap[lowerCaseKey], | ||
| type: capitalize(lowerCaseKey) | ||
| }); | ||
| } | ||
| } | ||
| } else { | ||
| for (const key in dataConfig) { | ||
| if (dataConfig.hasOwnProperty(key)) { | ||
| const lowerCaseKey = key.toLocaleLowerCase(); | ||
| if (dateConfigMap.hasOwnProperty(lowerCaseKey)) { | ||
| configList.push({ | ||
| ...dateConfigMap[lowerCaseKey], | ||
| ...dataConfig[key], | ||
| type: capitalize(lowerCaseKey) | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return configList; | ||
| } | ||
| render() { | ||
| const { min, max, dateConfig, color, textColor, isPreview } = this.props; | ||
| const value = this.state.value; | ||
| const dataConfigList = this.normalizeDateConfig(dateConfig); | ||
| const captionStyle = { | ||
| color: textColor + "99" | ||
| }; | ||
| return React.createElement( | ||
| View, | ||
| { | ||
| style: styles.container | ||
| }, | ||
| React.createElement( | ||
| View, | ||
| { | ||
| style: styles.captionContainer | ||
| }, | ||
| dataConfigList.map((item, index) => | ||
| React.createElement( | ||
| Text, | ||
| { | ||
| key: index, | ||
| style: [styles.caption, captionStyle] | ||
| }, | ||
| item.caption | ||
| ) | ||
| ) | ||
| ), | ||
| React.createElement( | ||
| View, | ||
| { | ||
| style: styles.content | ||
| }, | ||
| dataConfigList.map((item, index) => | ||
| React.createElement(DatePickerItem, { | ||
| key: index, | ||
| value: value, | ||
| min: min, | ||
| max: max, | ||
| step: item.step, | ||
| type: item.type, | ||
| format: item.format, | ||
| color: color, | ||
| textColor: textColor, | ||
| onSelect: this.handleDateSelect, | ||
| isPreview: isPreview | ||
| }) | ||
| ) | ||
| ) | ||
| ); | ||
| } | ||
| } | ||
| const styles = StyleSheet.create({ | ||
| container: { | ||
| width: "100%" | ||
| }, | ||
| captionContainer: { | ||
| display: "flex", | ||
| flexDirection: "row", | ||
| paddingTop: 8, | ||
| paddingHorizontal: 4 | ||
| }, | ||
| caption: { | ||
| flex: 1, | ||
| marginHorizontal: 4, | ||
| textAlign: "center", | ||
| height: 30, | ||
| lineHeight: 30, | ||
| fontSize: 16 | ||
| }, | ||
| content: { | ||
| display: "flex", | ||
| flexDirection: "row", | ||
| paddingVertical: 8, | ||
| paddingHorizontal: 4 | ||
| } | ||
| }); | ||
| DatePicker.defaultProps = defaultProps; | ||
| export default DatePicker; |
| export function shallowEqual(prev, next) { | ||
| if (prev === next) return true; | ||
| const prevKeys = Object.keys(prev); | ||
| const nextKeys = Object.keys(next); | ||
| if (prevKeys.length !== nextKeys.length) return false; | ||
| return prevKeys.every(key => { | ||
| return prev.hasOwnProperty(key) && prev[key] === next[key]; | ||
| }); | ||
| } | ||
| function PureRender(Component) { | ||
| Component.prototype.shouldComponentUpdate = function(nextProps, nextState) { | ||
| return PureRender.shouldComponentUpdate( | ||
| nextProps, | ||
| nextState, | ||
| this.props, | ||
| this.state | ||
| ); | ||
| }; | ||
| } | ||
| PureRender.shouldComponentUpdate = function( | ||
| nextProps, | ||
| nextState, | ||
| preProps, | ||
| preState | ||
| ) { | ||
| return ( | ||
| !shallowEqual(preProps, nextProps) || !shallowEqual(preState, nextState) | ||
| ); | ||
| }; | ||
| export default PureRender; |
| function throwIfInvalidDate(date) { | ||
| if (Object.prototype.toString.call(date, null) !== "[object Date]") { | ||
| throw new Error("参数类型不对"); | ||
| } | ||
| } | ||
| function daysInMonth(year, month) { | ||
| return new Date(year, month + 1, 0).getDate(); | ||
| } | ||
| export function convertDate(date, format = "YYYY/MM/DD") { | ||
| let str = format; | ||
| const o = { | ||
| "M+": date.getMonth() + 1, | ||
| "D+": date.getDate(), | ||
| "h+": date.getHours(), | ||
| "m+": date.getMinutes(), | ||
| "s+": date.getSeconds() | ||
| }; | ||
| if (/(Y+)/.test(format)) { | ||
| str = str.replace( | ||
| RegExp.$1, | ||
| date | ||
| .getFullYear() | ||
| .toString() | ||
| .substr(4 - RegExp.$1.length) | ||
| ); | ||
| } | ||
| for (const k in o) { | ||
| // eslint-disable-line | ||
| if (new RegExp(`(${k})`).test(format)) { | ||
| str = str.replace( | ||
| RegExp.$1, | ||
| RegExp.$1.length === 1 | ||
| ? o[k] | ||
| : `00${o[k]}`.substr(o[k].toString().length) | ||
| ); | ||
| } | ||
| } | ||
| return str; | ||
| } | ||
| export const getDayFormat = (date = new Date(), hasHours, timezone) => { | ||
| const day = dayOfWeekAsString(date.getDay()); | ||
| const number = getNumberWithOrdinal(date.getDate()); | ||
| const month = monthAsString(date.getMonth()); | ||
| const year = date.getFullYear(); | ||
| let hours = ""; | ||
| let zone = ""; | ||
| if (hasHours) { | ||
| hours = getHoursAndMinutes(date) + " "; | ||
| zone = timezone; | ||
| } | ||
| return hours + day + ", " + month + " " + number + " " + year + " " + zone; | ||
| }; | ||
| function addZero(i) { | ||
| if (i < 10) { | ||
| i = "0" + i; | ||
| } | ||
| return i; | ||
| } | ||
| export function getHoursAndMinutes(d) { | ||
| if (!d) d = new Date(); | ||
| const h = addZero(d.getHours()); | ||
| const m = addZero(d.getMinutes()); | ||
| return h + ":" + m; | ||
| } | ||
| function dayOfWeekAsString(dayIndex) { | ||
| return [ | ||
| "Sunday", | ||
| "Monday", | ||
| "Tuesday", | ||
| "Wednesday", | ||
| "Thursday", | ||
| "Friday", | ||
| "Saturday" | ||
| ][dayIndex]; | ||
| } | ||
| function monthAsString(monthIndex) { | ||
| return [ | ||
| "January", | ||
| "February", | ||
| "March", | ||
| "April", | ||
| "May", | ||
| "June", | ||
| "July", | ||
| "August", | ||
| "September", | ||
| "October", | ||
| "November", | ||
| "December" | ||
| ][monthIndex]; | ||
| } | ||
| function getNumberWithOrdinal(n) { | ||
| const s = ["th", "st", "nd", "rd"], | ||
| v = n % 100; | ||
| return n + (s[(v - 20) % 10] || s[v] || s[0]); | ||
| } | ||
| export function returnTimeZone(date = "") { | ||
| if (date) { | ||
| if (date.split(",")[1]) return date.split(",")[1].substring(7); | ||
| } | ||
| return /\((.*)\)/.exec(new Date().toString())[1]; | ||
| } | ||
| export function nextYear(now, index = 0) { | ||
| throwIfInvalidDate(now); | ||
| return new Date( | ||
| now.getFullYear() + index, | ||
| now.getMonth(), | ||
| now.getDate(), | ||
| now.getHours(), | ||
| now.getMinutes(), | ||
| now.getSeconds() | ||
| ); | ||
| } | ||
| export function nextMonth(now, index = 0) { | ||
| throwIfInvalidDate(now); | ||
| const year = now.getFullYear(); | ||
| const month = now.getMonth() + index; | ||
| const dayOfMonth = Math.min(now.getDate(), daysInMonth(year, month)); | ||
| return new Date( | ||
| year, | ||
| month, | ||
| dayOfMonth, | ||
| now.getHours(), | ||
| now.getMinutes(), | ||
| now.getSeconds() | ||
| ); | ||
| } | ||
| export function nextDate(now, index = 0) { | ||
| throwIfInvalidDate(now); | ||
| return new Date(now.getTime() + index * 24 * 60 * 60 * 1000); | ||
| } | ||
| export function nextHour(now, index = 0) { | ||
| throwIfInvalidDate(now); | ||
| return new Date(now.getTime() + index * 60 * 60 * 1000); | ||
| } | ||
| export function nextMinute(now, index = 0) { | ||
| throwIfInvalidDate(now); | ||
| return new Date(now.getTime() + index * 60 * 1000); | ||
| } | ||
| export function nextSecond(now, index = 0) { | ||
| throwIfInvalidDate(now); | ||
| return new Date(now.getTime() + index * 1000); | ||
| } |
+12
-12
@@ -12,2 +12,3 @@ import React from "react"; | ||
| import FilesUploadMobile from "./FilesUpload/Mobile"; | ||
| import Date from "./Date"; | ||
| export function clearFormValues(form) { | ||
@@ -41,2 +42,10 @@ const pages = form.pages || []; | ||
| } | ||
| if (block.time) { | ||
| delete block.time; | ||
| } | ||
| if (block.timezone) { | ||
| delete block.timezone; | ||
| } | ||
| } | ||
@@ -70,8 +79,2 @@ } | ||
| case "video": | ||
| return "Video"; | ||
| case "iframe": | ||
| return "IFrame"; | ||
| case "description": | ||
@@ -226,8 +229,2 @@ return "Description"; | ||
| case "video": | ||
| return "WATCH VIDEO BELOW"; | ||
| case "iframe": | ||
| return "VISIT PAGE BELOW"; | ||
| default: | ||
@@ -289,2 +286,5 @@ return ""; | ||
| case "date": | ||
| return React.createElement(Date, props); | ||
| case "files": | ||
@@ -291,0 +291,0 @@ return Platform.OS === "web" |
@@ -93,3 +93,4 @@ import React, { memo, useState } from "react"; | ||
| extraScrollHeight: 120, | ||
| enableOnAndroid: true | ||
| enableOnAndroid: true, | ||
| bounces: false | ||
| }, | ||
@@ -96,0 +97,0 @@ questionsCount <= 0 && |
@@ -21,4 +21,2 @@ import React, { Fragment, memo } from "react"; | ||
| let questionNumber = blockIndex + 1; | ||
| const hideQuestionsNumber = | ||
| type === "description" ? true : form.hideQuestionsNumber; | ||
@@ -48,5 +46,2 @@ for (let i = 0; i < currentPageIndex; i++) { | ||
| }; | ||
| const numberStyle = { | ||
| color: color || colors.main | ||
| }; | ||
| return React.createElement( | ||
@@ -70,13 +65,2 @@ Fragment, | ||
| }, | ||
| !hideQuestionsNumber && | ||
| React.createElement( | ||
| Text, | ||
| { | ||
| style: [numberStyle, styles.questionNumber] | ||
| }, | ||
| "Q", | ||
| questionNumber, | ||
| ".", | ||
| " " | ||
| ), | ||
| question, | ||
@@ -129,8 +113,2 @@ " ", | ||
| }, | ||
| questionNumber: { | ||
| fontSize: 13, | ||
| fontWeight: "bold", | ||
| marginRight: 4, | ||
| marginLeft: -4 | ||
| }, | ||
| required: { | ||
@@ -137,0 +115,0 @@ color: colors.required, |
@@ -39,3 +39,3 @@ import * as React from "react"; | ||
| if (window.ReactNativeWebView) { | ||
| if (window.ReactNativeWebView || window.INTERCOM) { | ||
| top = 20; | ||
@@ -42,0 +42,0 @@ } |
+6
-1
@@ -49,5 +49,9 @@ import React, { useState, memo, Fragment, useEffect } from "react"; | ||
| useEffect(() => { | ||
| if (window.INTERCOM_MESSENGER_SHEET_LIBRARY) { | ||
| window.INTERCOM_MESSENGER_SHEET_LIBRARY.setTitle(label || "NativeForms"); | ||
| } | ||
| if (!isPreview && !isTemplate && !livePreview && !editMode) { | ||
| if (window && window.document) { | ||
| window.document.title = label || "Forms.com"; | ||
| window.document.title = label || "NativeForms"; | ||
| } | ||
@@ -96,2 +100,3 @@ } | ||
| form.sourceURL = getParentURL() || ""; | ||
| form.intercom = window.INTERCOM || false; | ||
| form.platform = | ||
@@ -98,0 +103,0 @@ Platform.OS === "web" |
+1
-1
| { | ||
| "name": "react-native-surveys", | ||
| "version": "1.1.1", | ||
| "version": "1.1.3", | ||
| "description": "Build your own forms, surveys and polls for your React Native apps.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
202973
11.25%57
11.76%6961
13.43%8
14.29%