enh
This commit is contained in:
parent
83e733fdd1
commit
da47a0a014
10 changed files with 96 additions and 31 deletions
8
.expo/README.md
Normal file
8
.expo/README.md
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
> Why do I have a folder named ".expo" in my project?
|
||||||
|
The ".expo" folder is created when an Expo project is started using "expo start" command.
|
||||||
|
> What do the files contain?
|
||||||
|
- "devices.json": contains information about devices that have recently opened this project. This is used to populate the "Development sessions" list in your development builds.
|
||||||
|
- "settings.json": contains the server configuration that is used to serve the application manifest.
|
||||||
|
> Should I commit the ".expo" folder?
|
||||||
|
No, you should not share the ".expo" folder. It does not contain any information that is relevant for other developers working on the project, it is specific to your machine.
|
||||||
|
Upon project creation, the ".expo" folder is already added to your ".gitignore" file.
|
||||||
3
.expo/devices.json
Normal file
3
.expo/devices.json
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"devices": []
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { View, Alert } from 'react-native';
|
import { View, Alert } from 'react-native';
|
||||||
import { useRouter } from 'expo-router';
|
import { useRouter } from 'expo-router';
|
||||||
import { AppContainer, MyText, tw, useMarkDataFetchers, MyFlatList, MyTouchableOpacity, BottomDialog } from 'common-ui';
|
import { AppContainer, MyText, tw, useMarkDataFetchers, MyFlatList, MyTouchableOpacity, BottomDialog, RawBottomDialog } from 'common-ui';
|
||||||
import { trpc } from '@/src/trpc-client';
|
import { trpc } from '@/src/trpc-client';
|
||||||
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
||||||
import AddressForm from '@/src/components/AddressForm';
|
import AddressForm from '@/src/components/AddressForm';
|
||||||
|
|
@ -242,20 +242,7 @@ export default function Addresses() {
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<BottomDialog open={modalVisible} onClose={() => setModalVisible(false)}>
|
<RawBottomDialog open={modalVisible} onClose={() => setModalVisible(false)}>
|
||||||
<View style={tw`pt-4`}>
|
|
||||||
<View style={tw`flex-row justify-between items-center pb-4 border-b border-gray-100`}>
|
|
||||||
<MyText weight="semibold" style={tw`text-lg text-gray-800`}>
|
|
||||||
{editingAddress ? 'Edit Address' : 'Add Address'}
|
|
||||||
</MyText>
|
|
||||||
<MyTouchableOpacity
|
|
||||||
onPress={() => setModalVisible(false)}
|
|
||||||
style={tw`p-1`}
|
|
||||||
>
|
|
||||||
<MaterialIcons name="close" size={24} color="#6B7280" />
|
|
||||||
</MyTouchableOpacity>
|
|
||||||
</View>
|
|
||||||
<View style={tw`pt-4`}>
|
|
||||||
<AddressForm
|
<AddressForm
|
||||||
onSuccess={handleAddressSubmit}
|
onSuccess={handleAddressSubmit}
|
||||||
initialValues={editingAddress ? {
|
initialValues={editingAddress ? {
|
||||||
|
|
@ -274,9 +261,7 @@ export default function Addresses() {
|
||||||
} : undefined}
|
} : undefined}
|
||||||
isEdit={!!editingAddress}
|
isEdit={!!editingAddress}
|
||||||
/>
|
/>
|
||||||
</View>
|
</RawBottomDialog>
|
||||||
</View>
|
|
||||||
</BottomDialog>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { View, Text, TouchableOpacity, ScrollView } from 'react-native';
|
import { View, Text, TouchableOpacity, ScrollView } from 'react-native';
|
||||||
import { tw, BottomDialog } from 'common-ui';
|
import { tw, BottomDialog, RawBottomDialog } from 'common-ui';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import AddressForm from '@/src/components/AddressForm';
|
import AddressForm from '@/src/components/AddressForm';
|
||||||
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
||||||
|
|
@ -128,7 +128,9 @@ const CheckoutAddressSelector: React.FC<AddressSelectorProps> = ({
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<BottomDialog open={showAddAddress} onClose={() => setShowAddAddress(false)}>
|
{/* <BottomDialog open={showAddAddress} onClose={() => setShowAddAddress(false)}> */}
|
||||||
|
<RawBottomDialog open={showAddAddress} onClose={() => setShowAddAddress(false)}>
|
||||||
|
|
||||||
<AddressForm
|
<AddressForm
|
||||||
onSuccess={(addressId) => {
|
onSuccess={(addressId) => {
|
||||||
setShowAddAddress(false);
|
setShowAddAddress(false);
|
||||||
|
|
@ -138,8 +140,9 @@ const CheckoutAddressSelector: React.FC<AddressSelectorProps> = ({
|
||||||
}
|
}
|
||||||
queryClient.invalidateQueries();
|
queryClient.invalidateQueries();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</BottomDialog>
|
</RawBottomDialog>
|
||||||
|
{/* </BottomDialog> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -370,6 +370,14 @@ const PaymentAndOrderComponent: React.FC<PaymentAndOrderProps> = ({
|
||||||
|
|
||||||
{/* Bottom Action Bar */}
|
{/* Bottom Action Bar */}
|
||||||
<View style={tw`bg-white p-5 rounded-2xl shadow-sm mb-4 border border-gray-100`}>
|
<View style={tw`bg-white p-5 rounded-2xl shadow-sm mb-4 border border-gray-100`}>
|
||||||
|
{!selectedAddress && (
|
||||||
|
<View style={tw`bg-red-50 p-3 rounded-lg mb-3 flex-row items-center`}>
|
||||||
|
<MaterialIcons name="error-outline" size={16} color="#EF4444" style={tw`mr-2`} />
|
||||||
|
<MyText style={tw`text-red-600 text-sm font-medium`}>
|
||||||
|
Please select a delivery address to place order
|
||||||
|
</MyText>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
<MyTouchableOpacity
|
<MyTouchableOpacity
|
||||||
style={tw`bg-brand500 py-4 rounded-xl items-center shadow-md ${!selectedAddress ? 'opacity-50' : ''}`}
|
style={tw`bg-brand500 py-4 rounded-xl items-center shadow-md ${!selectedAddress ? 'opacity-50' : ''}`}
|
||||||
disabled={!selectedAddress}
|
disabled={!selectedAddress}
|
||||||
|
|
|
||||||
|
|
@ -757,7 +757,7 @@ export default function CartPage({ isFlashDelivery = false }: CartPageProps) {
|
||||||
label="Available Coupons"
|
label="Available Coupons"
|
||||||
options={dropdownData}
|
options={dropdownData}
|
||||||
value={selectedCouponId || ""}
|
value={selectedCouponId || ""}
|
||||||
disabled={eligibleCoupons.length === 0}
|
// disabled={eligibleCoupons.length === 0}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setSelectedCouponId(value ? Number(value) : null);
|
setSelectedCouponId(value ? Number(value) : null);
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState, useMemo } from 'react';
|
import React, { useState, useMemo } from 'react';
|
||||||
import { View, ScrollView } from 'react-native';
|
import { View, ScrollView } from 'react-native';
|
||||||
import { useLocalSearchParams, useRouter } from 'expo-router';
|
import { useLocalSearchParams, useRouter } from 'expo-router';
|
||||||
import { tw, useMarkDataFetchers , BottomDialog, MyText, MyTouchableOpacity } from 'common-ui';
|
import { tw, useMarkDataFetchers , BottomDialog, MyText, MyTouchableOpacity, RawBottomDialog } from 'common-ui';
|
||||||
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import AddressForm from '@/src/components/AddressForm';
|
import AddressForm from '@/src/components/AddressForm';
|
||||||
|
|
@ -256,7 +256,7 @@ const CheckoutPage: React.FC<CheckoutPageProps> = ({ isFlashDelivery = false })
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<BottomDialog open={showAddAddress} onClose={() => setShowAddAddress(false)}>
|
<RawBottomDialog open={showAddAddress} onClose={() => setShowAddAddress(false)}>
|
||||||
<AddressForm
|
<AddressForm
|
||||||
onSuccess={(addressId) => {
|
onSuccess={(addressId) => {
|
||||||
setShowAddAddress(false);
|
setShowAddAddress(false);
|
||||||
|
|
@ -267,7 +267,7 @@ const CheckoutPage: React.FC<CheckoutPageProps> = ({ isFlashDelivery = false })
|
||||||
queryClient.invalidateQueries();
|
queryClient.invalidateQueries();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</BottomDialog>
|
</RawBottomDialog>
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { View, ScrollView } from 'react-native';
|
import { View, ScrollView, Dimensions } from 'react-native';
|
||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { Formik } from 'formik';
|
import { Formik } from 'formik';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { tw, MyText, MyTouchableOpacity , Checkbox , MyTextInput , LoadingDialog } from 'common-ui';
|
import { tw, MyText, MyTouchableOpacity , Checkbox , MyTextInput , LoadingDialog } from 'common-ui';
|
||||||
import { trpc } from '../trpc-client';
|
import { trpc } from '../trpc-client';
|
||||||
import LocationAttacher from './LocationAttacher';
|
import LocationAttacher from './LocationAttacher';
|
||||||
|
import KeyBoardAwareScrollView from 'react-native-keyboard-aware-scroll-view';
|
||||||
|
|
||||||
interface AddressFormProps {
|
interface AddressFormProps {
|
||||||
onSuccess: (addressId?: number) => void;
|
onSuccess: (addressId?: number) => void;
|
||||||
|
|
@ -74,8 +75,8 @@ const AddressForm: React.FC<AddressFormProps> = ({ onSuccess, initialValues, isE
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView
|
<ScrollView
|
||||||
style={tw`p-4`}
|
style={[tw`px-4 pt-4 pb-32 bg-white`, {height: Dimensions.get('window').height * 0.5}]}
|
||||||
keyboardShouldPersistTaps="handled"
|
keyboardShouldPersistTaps="always"
|
||||||
keyboardDismissMode="on-drag"
|
keyboardDismissMode="on-drag"
|
||||||
>
|
>
|
||||||
<MyText style={tw`text-xl font-bold mb-4`}>{isEdit ? 'Edit Address' : 'Add Address'}</MyText>
|
<MyText style={tw`text-xl font-bold mb-4`}>{isEdit ? 'Edit Address' : 'Add Address'}</MyText>
|
||||||
|
|
@ -252,6 +253,7 @@ const AddressForm: React.FC<AddressFormProps> = ({ onSuccess, initialValues, isE
|
||||||
{isSubmitting ? (isEdit ? 'Updating...' : 'Adding...') : (isEdit ? 'Update Address' : 'Add Address')}
|
{isSubmitting ? (isEdit ? 'Updating...' : 'Adding...') : (isEdit ? 'Update Address' : 'Add Address')}
|
||||||
</MyText>
|
</MyText>
|
||||||
</MyTouchableOpacity>
|
</MyTouchableOpacity>
|
||||||
|
<View style={tw`h-8`}></View>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import { theme } from "./src/theme";
|
||||||
import MyButton, { MyTextButton } from "./src/components/button";
|
import MyButton, { MyTextButton } from "./src/components/button";
|
||||||
import { useTheme, Theme } from "./hooks/theme-context";
|
import { useTheme, Theme } from "./hooks/theme-context";
|
||||||
import MyTextInput from "./src/components/textinput";
|
import MyTextInput from "./src/components/textinput";
|
||||||
import BottomDialog, { ConfirmationDialog } from "./src/components/dialog";
|
import BottomDialog, { ConfirmationDialog, RawBottomDialog } from "./src/components/dialog";
|
||||||
import LoadingDialog from "./src/components/loading-dialog";
|
import LoadingDialog from "./src/components/loading-dialog";
|
||||||
import DatePicker from "./src/components/date-picker";
|
import DatePicker from "./src/components/date-picker";
|
||||||
import MyText from "./src/components/text";
|
import MyText from "./src/components/text";
|
||||||
|
|
@ -91,6 +91,7 @@ export {
|
||||||
MyText,
|
MyText,
|
||||||
MyTouchableOpacity,
|
MyTouchableOpacity,
|
||||||
ConfirmationDialog,
|
ConfirmationDialog,
|
||||||
|
RawBottomDialog,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
BottomDropdown,
|
BottomDropdown,
|
||||||
ImageViewerURI,
|
ImageViewerURI,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import React, { ReactNode, useState } from 'react';
|
||||||
import { Modal, View, TouchableOpacity, StyleSheet, Animated, Easing, Dimensions, TextInput, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
|
import { Modal, View, TouchableOpacity, StyleSheet, Animated, Easing, Dimensions, TextInput, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
|
||||||
import MyText from './text';
|
import MyText from './text';
|
||||||
import { MyButton } from 'common-ui';
|
import { MyButton } from 'common-ui';
|
||||||
|
import tw from "../lib/tailwind";
|
||||||
|
|
||||||
interface DialogProps {
|
interface DialogProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
|
@ -72,6 +73,60 @@ export const BottomDialog: React.FC<DialogProps> = ({ open, onClose, children, e
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const RawBottomDialog: React.FC<DialogProps> = ({ open, onClose, children, enableDismiss = true }) => {
|
||||||
|
const [slideAnim] = useState(new Animated.Value(SCREEN_HEIGHT));
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (open) {
|
||||||
|
Animated.timing(slideAnim, {
|
||||||
|
toValue: 0,
|
||||||
|
duration: 300,
|
||||||
|
easing: Easing.out(Easing.cubic),
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start();
|
||||||
|
} else {
|
||||||
|
Animated.timing(slideAnim, {
|
||||||
|
toValue: SCREEN_HEIGHT,
|
||||||
|
duration: 200,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible={open}
|
||||||
|
transparent
|
||||||
|
animationType="none"
|
||||||
|
onRequestClose={enableDismiss ? onClose : undefined}
|
||||||
|
>
|
||||||
|
{enableDismiss ? (
|
||||||
|
<TouchableOpacity style={tw`flex-1 bg-black/30`} activeOpacity={1} onPress={onClose} />
|
||||||
|
) : (
|
||||||
|
<View style={[tw`flex-1 bg-black/30`, { pointerEvents: 'none' }]} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{children}
|
||||||
|
{/* <Animated.View
|
||||||
|
style={[
|
||||||
|
tw`absolute left-0 right-0 bottom-0 bg-white rounded-t-[18px] px-5 pb-0 shadow-lg`,
|
||||||
|
{
|
||||||
|
maxHeight: SCREEN_HEIGHT * 0.85,
|
||||||
|
transform: [{ translateY: slideAnim }],
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: { width: 0, height: -2 },
|
||||||
|
shadowOpacity: 0.2,
|
||||||
|
shadowRadius: 8,
|
||||||
|
elevation: 8,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Animated.View> */}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
backdrop: {
|
backdrop: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|
@ -204,4 +259,4 @@ export const ConfirmationDialog: React.FC<ConfirmationDialogProps> = (props) =>
|
||||||
</View>
|
</View>
|
||||||
</BottomDialog>
|
</BottomDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue