import React, { useEffect, useRef } from 'react'; import { ProductForm as ProductOptions, useSession, useLanguage, useOrder, useUtils, } from 'ordering-components/native'; import { useTheme } from 'styled-components/native'; import { ProductIngredient } from '../ProductIngredient'; import { ProductOption } from '../ProductOption'; import { View, TouchableOpacity, StyleSheet, Dimensions, Platform, useWindowDimensions, Keyboard, KeyboardAvoidingView, I18nManager } from 'react-native'; import { ProductHeader, WrapHeader, TopHeader, WrapContent, ProductTitle, ProductDescription, ProductEditions, SectionTitle, WrapperIngredients, WrapperSubOption, ProductComment, ProductActions, ExtraOptionWrap, } from './styles'; import { OButton, OIcon, OInput, OText } from '../shared'; import { ScrollView } from 'react-native-gesture-handler'; import { ProductOptionSubOption } from '../ProductOptionSubOption'; import { NotFoundSource } from '../NotFoundSource'; import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder'; import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; import { useState } from 'react'; const windowHeight = Dimensions.get('window').height; const windowWidth = Dimensions.get('window').width; export const ProductOptionsUI = (props: any) => { const { navigation, editMode, isSoldOut, productCart, increment, decrement, showOption, maxProductQuantity, errors, handleSave, handleChangeIngredientState, handleChangeSuboptionState, handleChangeCommentState, productObject, onClose, isFromCheckout, } = props; const theme = useTheme(); const styles = StyleSheet.create({ mainContainer: { }, headerItem: { overflow: 'hidden', backgroundColor: theme.colors.clear, width: 35, marginVertical: 18, }, optionContainer: { marginBottom: 20, }, comment: { borderWidth: 1, borderRadius: 7.6, borderColor: theme.colors.border, height: 100, alignItems: 'flex-start', }, quantityControl: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginRight: 10, }, btnBackArrow: { borderWidth: 0, backgroundColor: 'rgba(0,0,0,0.3)', borderRadius: 24, marginRight: 15, }, productHeaderSkeleton: { flexDirection: 'row', width: '100%', position: 'relative', maxHeight: 260, height: 260, resizeMode: 'cover', minHeight: 200, zIndex: 0, }, extraItem: { paddingHorizontal: 7, paddingBottom: 10, borderBottomWidth: 1, borderBottomColor: theme.colors.border, justifyContent: 'center', }, }); const [{ parsePrice }] = useUtils(); const [, t] = useLanguage(); const [orderState] = useOrder(); const [{ auth }] = useSession(); const { product, loading, error } = productObject; const [selOpt, setSelectedOpt] = useState(null); const [optionsLayout, setOptionsLayout] = useState(null) const extraOptions = [].concat(...product?.extras?.map((option: any) => option.options)).filter((i: any) => i.respect_to === null) const scrollViewRef = useRef() const isError = (id: number) => { let bgColor = theme.colors.white; if (errors[`id:${id}`]) { bgColor = 'rgba(255, 0, 0, 0.05)'; } if (isSoldOut || maxProductQuantity <= 0) { bgColor = 'hsl(0, 0%, 72%)'; } return bgColor; }; const handleSaveProduct = () => { const isErrors = Object.values(errors).length > 0; if (!isErrors) { handleSave && handleSave(); return; } }; const hasRespected = (options: Array, respect_id: number) => { if (respect_id === null) return; const option: any = options.filter(({ id }: any) => id === selOpt); if (option === undefined) return false; if (option?.suboptions?.length === null) return false; const sel = option && option[0]?.suboptions?.filter( ({ id }: any) => id === respect_id, ); return sel && sel[0]?.id !== undefined; }; const handleRedirectLogin = () => { onClose(); navigation.navigate('Login'); }; const handleClickOption = (value: any) => { setSelectedOpt(value) const optionsArray = value ? Object.values(optionsLayout) .filter((opt: any) => opt.position || opt.position === 0) .map((i: any) => i.height) .slice(0, optionsLayout[value]?.position) : [] scrollViewRef.current.scrollTo({ y: optionsArray.length > 0 ? optionsLayout?.header?.height + optionsArray?.reduce((acc, cur) => acc + cur) : optionsLayout?.header?.height, animated: true }) } const saveErrors = orderState.loading || maxProductQuantity === null || Object.keys(errors).length > 0; const ExtraOptions = ({ options }: any) => ( <> handleClickOption(null)} style={[ styles.extraItem, { borderBottomColor: selOpt === null ? theme.colors.textNormal : theme.colors.border, }, ]}> {t('ALL', 'All')} {product?.ingredients.length > 0 && ( handleClickOption('ingredients')} style={[ styles.extraItem, { borderBottomColor: selOpt === 'ingredients' ? theme.colors.textNormal : theme.colors.border, }, ]}> {t('INGREDIENTS', 'Ingredients')} )} {options.map(({ id, name, respect_to }: any) => ( {respect_to === null && ( handleClickOption(`opt_${id}`)} style={[ styles.extraItem, { borderBottomColor: selOpt === `opt_${id}` ? theme.colors.textNormal : theme.colors.border, }, ]}> {name} )} ))} ); const handleScroll = ({ nativeEvent }: any) => { const scrollOffset = nativeEvent.contentOffset.y const optionsArray = Object.values(optionsLayout) .filter((opt: any) => opt.position || opt.position === 0) .map((i: any) => ({ height: i.height, key: i.key })) for (let i = 0; i < optionsArray.length; i++) { const opt = optionsArray[i]; if (scrollOffset <= optionsLayout?.header?.height) { setSelectedOpt(null) break } else if (scrollOffset > optionsLayout?.header?.height && scrollOffset < (optionsLayout?.header?.height + opt.height)) { setSelectedOpt(opt.key) break } } } useEffect(() => { const keyboardDidShowListener = Keyboard.addListener( 'keyboardDidShow', () => { scrollViewRef?.current && scrollViewRef?.current?.scrollToEnd()} ); return () => { keyboardDidShowListener.remove()}; }, []); return ( {!error && ( handleScroll(e)} > setOptionsLayout({ ...optionsLayout, header: event.nativeEvent.layout })} > {loading && !product ? ( ) : ( <> )} {loading && !product ? ( ) : ( <> {product?.name || productCart.name} {((product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (product?.estimated_person)) && ( { ((product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (productCart?.sku && productCart?.sku !== '-1' && productCart?.sku !== '1')) && <>{t('SKU', 'Sku')}{' '}{product?.sku || productCart?.sku} } {product?.sku && product?.sku !== '-1' && product?.sku !== '1' && product?.estimated_person && ( <> ·  )} {product?.estimated_person && <>{product?.estimated_person}{' '}{t('ESTIMATED_PERSONS', 'persons')} } )} {productCart.price ? parsePrice(productCart.price) : ''} )} {product?.description || productCart?.description} {loading && !product && ( <> {[...Array(2)].map((item, i) => ( {[...Array(3)].map((item, i) => ( ))} ))} )} {!loading && product && extraOptions?.length > 0 && } {!loading && product && ( setOptionsLayout({ ...optionsLayout, wrapper: event.nativeEvent.layout })} > {product?.ingredients.length > 0 && ( setOptionsLayout( { ...optionsLayout, ingredients: { ...event.nativeEvent.layout, position: 0, key: 'ingredients' } } )} > {t('INGREDIENTS', 'Ingredients')} {product?.ingredients.map((ingredient: any) => ( ))} )} {product?.extras.map((extra: any) => extra.options.map((option: any) => { const currentState = productCart.options[`id:${option.id}`] || {}; return ( {showOption(option) && ( setOptionsLayout( { ...optionsLayout, [`opt_${option.id}`]: { ...event.nativeEvent.layout, position: extraOptions.map((i: any) => i.id).indexOf(option.id) + (product?.ingredients.length > 0 ? 1 : 0), key: `opt_${option.id}` } } ) } > {option.suboptions.map( (suboption: any) => { const currentState = productCart.options[ `id:${option.id}` ]?.suboptions[ `id:${suboption.id}` ] || {}; const balance = productCart.options[ `id:${option.id}` ]?.balance || 0; return ( ); }, )} )} ); }))} {!product?.hide_special_instructions && ( {t('SPECIAL_COMMENT', 'Special comment')} handleChangeCommentState({ target: { value: val } }) } isDisabled={ !(productCart && !isSoldOut && maxProductQuantity) } style={{ height: 100, justifyContent: "flex-end", alignItems: 'flex-start', borderWidth: 1, borderRadius: 8, borderColor: theme.colors.border, }} /> )} )} )} {error && error.length > 0 && ( )} {!loading && !error && product && ( {productCart && !isSoldOut && maxProductQuantity > 0 && ( <> {productCart.total ? parsePrice(productCart?.total) : ''} {productCart.quantity} = maxProductQuantity || isSoldOut }> = maxProductQuantity || isSoldOut ? theme.colors.backgroundGray : theme.colors.backgroundDark } /> )} {productCart && !isSoldOut && maxProductQuantity > 0 && auth && orderState.options?.address_id && ( handleSaveProduct()} imgRightSrc="" text={`${orderState.loading ? t('LOADING', 'Loading') : editMode ? t('UPDATE', 'Update') : t('ADD', 'Add') }`} textStyle={{ color: saveErrors ? theme.colors.primary : theme.colors.white, }} style={{ backgroundColor: saveErrors ? theme.colors.white : theme.colors.primary, borderColor: saveErrors ? theme.colors.white : theme.colors.primary, opacity: saveErrors ? 0.3 : 1, borderRadius: 7.6, height: 44, shadowOpacity: 0, borderWidth: 1, }} /> )} {auth && !orderState.options?.address_id &&( orderState.loading ? ( ) : ( )) } {(!auth || isSoldOut || maxProductQuantity <= 0) && ( handleRedirectLogin()} text={ isSoldOut || maxProductQuantity <= 0 ? t('SOLD_OUT', 'Sold out') : t('LOGIN_SIGNUP', 'Login / Sign Up') } imgRightSrc="" textStyle={{ color: theme.colors.primary }} style={{ borderColor: theme.colors.primary, backgroundColor: theme.colors.white, borderRadius: 8 }} /> )} )} ); }; export const ProductForm = (props: any) => { const productOptionsProps = { ...props, UIComponent: ProductOptionsUI, }; return ; };