Skip to content

Commit

Permalink
further progress
Browse files Browse the repository at this point in the history
  • Loading branch information
roncodes committed Dec 2, 2024
1 parent 20875a8 commit 26a261f
Show file tree
Hide file tree
Showing 20 changed files with 694 additions and 199 deletions.
13 changes: 2 additions & 11 deletions src/components/BackButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import React from 'react';
import HeaderButton from './HeaderButton';
import { useNavigation } from '@react-navigation/native';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
import { Button, useTheme } from 'tamagui';

const BackButton = ({ ...props }) => {
const theme = useTheme();
const navigation = useNavigation();
const { onPress } = props;

Expand All @@ -17,13 +14,7 @@ const BackButton = ({ ...props }) => {
}
};

return (
<Button onPress={handlePress} justifyContent='center' alignItems='center' backgroundColor='$secondary' circular size={props.size ?? 45} {...props}>
<Button.Icon>
<FontAwesomeIcon icon={faArrowLeft} color={theme.color.val} />
</Button.Icon>
</Button>
);
return <HeaderButton onPress={handlePress} icon={faArrowLeft} {...props} />;
};

export default BackButton;
12 changes: 6 additions & 6 deletions src/components/ExpandableSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState, useRef, useEffect } from 'react';
import { Animated, Easing } from 'react-native';
import { XStack, YStack, Text, Button, Separator, useTheme } from 'tamagui';
import { Spinner, XStack, YStack, Text, Button, Separator, useTheme } from 'tamagui';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons';
import { isNone } from '../utils';
Expand Down Expand Up @@ -28,8 +28,8 @@ const ExpandableSelect = ({ value, optionValue, options = [], onSelect }) => {
const dropdownAnimation = useRef(new Animated.Value(0)).current;

// Animated values for the dropdown toggle
const toggleScale = useRef(new Animated.Value(0)).current;
const toggleOpacity = useRef(new Animated.Value(0)).current;
const toggleScale = useRef(new Animated.Value(selectedOption ? 1 : 0)).current;
const toggleOpacity = useRef(new Animated.Value(selectedOption ? 1 : 0)).current;

useEffect(() => {
// Initialize optionAnimations when options change
Expand Down Expand Up @@ -260,7 +260,7 @@ const ExpandableSelect = ({ value, optionValue, options = [], onSelect }) => {

// Ensure optionAnimations are ready before rendering
if (optionAnimations.length !== options.length) {
return null; // or render a loading indicator
return <Spinner color='$gray-700' />; // or render a loading indicator
}

// Render options or dropdown toggle based on state
Expand All @@ -274,7 +274,6 @@ const ExpandableSelect = ({ value, optionValue, options = [], onSelect }) => {

return (
<YStack space='$4' width='100%'>
{/* Selected Option */}
<Animated.View
style={{
opacity: toggleOpacity,
Expand All @@ -286,6 +285,8 @@ const ExpandableSelect = ({ value, optionValue, options = [], onSelect }) => {
onPressIn={onPressIn}
onPressOut={onPressOut}
size='$5'
flex={1}
width='100%'
justifyContent='space-between'
bg='white'
borderWidth={1}
Expand Down Expand Up @@ -315,7 +316,6 @@ const ExpandableSelect = ({ value, optionValue, options = [], onSelect }) => {
</Button>
</Animated.View>

{/* Dropdown Options */}
{shouldRenderDropdown && (
<Animated.View
style={{
Expand Down
24 changes: 24 additions & 0 deletions src/components/HeaderButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faBolt } from '@fortawesome/free-solid-svg-icons';
import { Button, useTheme } from 'tamagui';

const HeaderButton = ({ icon, size, onPress, ...props }) => {
const theme = useTheme();

const handlePress = function () {
if (typeof onPress === 'function') {
onPress();
}
};

return (
<Button onPress={handlePress} justifyContent='center' alignItems='center' backgroundColor='$secondary' circular size={size ?? 45} {...props}>
<Button.Icon>
<FontAwesomeIcon icon={icon ? icon : faBolt} color={theme.color.val} />
</Button.Icon>
</Button>
);
};

export default HeaderButton;
37 changes: 37 additions & 0 deletions src/components/PlaceMapView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useState } from 'react';
import { TouchableOpacity, StyleSheet } from 'react-native';
import MapView, { Marker } from 'react-native-maps';
import { YStack, useTheme } from 'tamagui';
import { restoreFleetbasePlace, getCoordinates } from '../utils/location';

const PlaceMapView = ({ place: _place, height = 200, onPress, mapViewProps = {}, ...props }) => {
const place = restoreFleetbasePlace(_place);
const [latitude, longitude] = getCoordinates(place);
const [mapRegion, setMapRegion] = useState({
latitude,
longitude,
latitudeDelta: 0.0005,
longitudeDelta: 0.0005,
});

return (
<TouchableOpacity onPress={onPress}>
<YStack flex={1} position='relative' overflow='hidden' width='100%' borderRadius='$4' height={height} {...props}>
<MapView
style={{ ...StyleSheet.absoluteFillObject, width: '100%', height: '100%' }}
initialRegion={mapRegion}
onRegionChangeComplete={(region) => setMapRegion(region)}
scrollEnabled={false}
zoomEnabled={false}
pitchEnabled={false}
rotateEnabled={false}
{...mapViewProps}
>
<Marker coordinate={{ latitude, longitude }} />
</MapView>
</YStack>
</TouchableOpacity>
);
};

export default PlaceMapView;
9 changes: 5 additions & 4 deletions src/components/ProductCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ const ProductCard = ({
sliderWidth={cardWidth}
sliderHeight={sliderHeight}
sliderStyle={{ borderTopRightRadius: 10, borderTopLeftRadius: 10 }}
onImagePress={handlePress}
autoplay
/>
<XStack position='absolute' top='$2' right='$2' zIndex={10} alignItems='center' justifyContent='flex-end' space='$2'></XStack>
Expand All @@ -106,15 +107,15 @@ const ProductCard = ({
<YStack mt='$2'>
{product.getAttribute('on_sale') ? (
<YStack>
<Text fontSize='$6' color='$success' fontWeight='bold'>
<Text fontSize='$6' color='$green-600' fontWeight='bold'>
{formatCurrency(product.getAttribute('sale_price'), product.getAttribute('currency'))}
</Text>
<Text fontSize='$5' color='$secondary' textDecorationLine='line-through'>
{formatCurrency(product.getAttribute('price'), product.getAttribute('currency'))}
</Text>
</YStack>
) : (
<Text fontSize='$5' color='$success' fontWeight='bold'>
<Text fontSize='$5' color='$green-600' fontWeight='bold'>
{formatCurrency(product.getAttribute('price'), product.getAttribute('currency'))}
</Text>
)}
Expand All @@ -133,11 +134,11 @@ const ProductCard = ({
color='white'
width='100%'
hoverStyle={{
scale: 0.75,
scale: 0.95,
opacity: 0.5,
}}
pressStyle={{
scale: 0.75,
scale: 0.95,
opacity: 0.5,
}}
>
Expand Down
8 changes: 4 additions & 4 deletions src/components/QuantityButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ const QuantityButton = ({
disabled={currentQuantity <= min || disabled}
theme={currentQuantity > min ? 'primary' : 'gray'}
hoverStyle={{
scale: 0.75,
scale: 0.95,
opacity: 0.5,
}}
pressStyle={{
scale: 0.75,
scale: 0.95,
opacity: 0.5,
}}
{...incrementButtonProps}
Expand All @@ -88,11 +88,11 @@ const QuantityButton = ({
disabled={currentQuantity >= max || disabled}
theme={currentQuantity < max ? 'primary' : 'gray'}
hoverStyle={{
scale: 0.75,
scale: 0.95,
opacity: 0.5,
}}
pressStyle={{
scale: 0.75,
scale: 0.95,
opacity: 0.5,
}}
{...decrementButtonProps}
Expand Down
16 changes: 16 additions & 0 deletions src/hooks/use-current-location.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,20 @@ const useCurrentLocation = () => {
}
};

// Update current location/default location as a promise
const updateDefaultLocationPromise = (instance) => {
return new Promise(async (resolve) => {
await updateDefaultLocation(instance);
resolve(instance);
});
};

// Update current location/default location as a promise
const updateDefaultLocation = (instance) => {
updateCurrentLocation(instance);
setCustomerDefaultLocation(instance);
};

// Set initial current location
useEffect(() => {
initializeLiveLocation();
Expand All @@ -93,6 +107,8 @@ const useCurrentLocation = () => {
liveLocation: restoreFleetbasePlace(liveLocation),
updateCurrentLocation,
setCurrentLocation,
updateDefaultLocationPromise,
updateDefaultLocation,
getCurrentLocationCoordinates,
setCustomerDefaultLocation,
initializeCurrentLocation,
Expand Down
42 changes: 39 additions & 3 deletions src/hooks/use-saved-locations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useEffect } from 'react';
import { restoreFleetbasePlace } from '../utils/location';
import { isResource } from '../utils';
import { isResource, isEmpty } from '../utils';
import { useAuth } from '../contexts/AuthContext';
import useStorage from './use-storage';
import useFleetbase from './use-fleetbase';
Expand Down Expand Up @@ -38,11 +38,44 @@ const useSavedLocations = () => {
}
};

// Handle location update
const updateLocation = async (attributes = {}) => {
const place = restoreFleetbasePlace(attributes);

try {
const updatedPlace = await place.save();
setCustomerLocations((prevLocations) => prevLocations.map((location) => (location.id === place.id ? place.serialize() : location)));
return updatedPlace;
} catch (err) {
setError(err);
}
};

// Handle delete location by ID
const deleteLocationById = async (placeId) => {
try {
const place = restoreFleetbasePlace({ id: placeId });
const deletedPlace = await place.destroy();
setCustomerLocations((prevLocations) => prevLocations.filter((location) => location.id !== deletedPlace.id));
} catch (err) {
setError(err);
}
};

// Handle delete location
const deleteLocation = async (place) => {
try {
const deletedPlace = await place.destroy();
setCustomerLocations((prevLocations) => prevLocations.filter((location) => location.id !== deletedPlace.id));
} catch (err) {
setError(err);
}
};

// Add location
const addLocation = async (attributes = {}) => {
console.log('[addLocation isAuthenticated]', isAuthenticated);
if (isAuthenticated) {
return addCustomerLocation(attributes);
return isEmpty(attributes.id) ? addCustomerLocation(attributes) : updateLocation(attributes);
}

return addLocalLocationPromise(attributes);
Expand Down Expand Up @@ -86,6 +119,9 @@ const useSavedLocations = () => {
addCustomerLocation,
addLocalLocation,
addLocalLocationPromise,
updateLocation,
deleteLocation,
deleteLocationById,
isLoadingSavedLocations: loading,
savedLocationsError: error,
};
Expand Down
3 changes: 3 additions & 0 deletions src/navigation/stacks/LocationStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import AddNewLocationScreen from '../../screens/AddNewLocationScreen';
import EditLocationScreen from '../../screens/EditLocationScreen';
import AddressBookScreen from '../../screens/AddressBookScreen';
import BackButton from '../../components/BackButton';
import HeaderButton from '../../components/HeaderButton';
import { faPlus } from '@fortawesome/free-solid-svg-icons';
import { getTheme } from '../../utils';

export const LocationPermission = {
Expand All @@ -28,6 +30,7 @@ export const AddressBook = {
title: 'Address Book',
headerTransparent: true,
headerLeft: () => <BackButton onPress={() => navigation.goBack()} size={40} />,
headerRight: () => <HeaderButton icon={faPlus} onPress={() => navigation.navigate('AddNewLocation', { redirectTo: 'AddressBook' })} size={40} />,
headerBlurEffect: 'light',
};
},
Expand Down
14 changes: 10 additions & 4 deletions src/screens/AddNewLocationScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import useStorage from '../hooks/use-storage';
import useCurrentLocation from '../hooks/use-current-location';
import BackButton from '../components/BackButton';

const AddNewLocationScreen = () => {
const AddNewLocationScreen = ({ route = { params: {} } }) => {
const navigation = useNavigation();
const theme = useTheme();
const { params } = route;
const { liveLocation: currentLocation, getCurrentLocationCoordinates } = useCurrentLocation();
const [inputFocused, setInputFocused] = useState(false);
const [inputValue, setInputValue] = useState('');
Expand All @@ -32,20 +33,25 @@ const AddNewLocationScreen = () => {
try {
const details = await getPlaceDetails(location.place_id);
const place = createFleetbasePlaceFromDetails(details);
navigation.navigate('EditLocation', { place: place.serialize() });
navigation.navigate('EditLocation', { place: place.serialize(), redirectTo: params.redirectTo });
} catch (error) {
toast.error(error.message);
}
};

const handleUseCurrentLocation = async () => {
try {
navigation.navigate('EditLocation', { place: currentLocation.serialize() });
navigation.navigate('EditLocation', { place: currentLocation.serialize(), redirectTo: params.redirectTo });
} catch (error) {
toast.error(error.message);
}
};

const handleUseMapLocation = () => {
console.log('[handleUseMapLocation triggered!]');
navigation.navigate('LocationPicker');
};

const searchPlaces = useCallback(async () => {
if (inputValue.trim() === '') {
setSearchResults([]);
Expand Down Expand Up @@ -195,7 +201,7 @@ const AddNewLocationScreen = () => {
</XStack>
</TouchableOpacity>
))}
<TouchableOpacity onPress={() => navigation.navigate('LocationPicker')}>
<TouchableOpacity onPress={handleUseMapLocation}>
<XStack space='$2' borderBottomWidth={1} borderColor='$borderColorWithShadow' padding='$3'>
<YStack justifyContent='center' alignItems='center' paddingHorizontal='$1'>
<Circle size={40} bg='$background'>
Expand Down
Loading

0 comments on commit 26a261f

Please sign in to comment.