Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Use NGROK URL here instead of localhost
EXPO_PUBLIC_API_BASE_URL=""
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ dist/
web-build/
expo-env.d.ts

.env

# Native
.kotlin/
*.orig.*
Expand Down
19 changes: 13 additions & 6 deletions App.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { NavigationContainer } from "@react-navigation/native";
import { QueryClientProvider } from "@tanstack/react-query";
import { ActivityIndicator, Text, View } from "react-native";
import { SafeAreaProvider } from "react-native-safe-area-context";
import FontLoaderWrapper from "./components/FontLoaderWrapper";
import SystemUIManager from "./components/SystemUIManager";
import { COLORS } from "./constants/colors";
import { AppProvider } from "./contexts/AppContext";
import { useInitDb } from "./hooks/useInitDb";
import queryClient from "./lib/queryClient";
import StackNavigation from "./navigation/StackNavigation";

export default function App() {
Expand All @@ -24,12 +27,16 @@ export default function App() {

return (
<SafeAreaProvider>
<FontLoaderWrapper>
<AppProvider>
<SystemUIManager backgroundColor={COLORS.background} />
<StackNavigation />
</AppProvider>
</FontLoaderWrapper>
<QueryClientProvider client={queryClient}>
<FontLoaderWrapper>
<AppProvider>
<SystemUIManager backgroundColor={COLORS.background} />
<NavigationContainer>
<StackNavigation />
</NavigationContainer>
</AppProvider>
</FontLoaderWrapper>
</QueryClientProvider>
</SafeAreaProvider>
);
}
5 changes: 2 additions & 3 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
"expo": {
"name": "travel-buddy",
"slug": "travel-buddy",

// After adding a custom scheme to your app, you need to create a new development build. Once the app is installed on a device, you can open links within your app using myapp:
"scheme": "travel-buddy",
"version": "1.0.0",
"orientation": "portrait",
Expand Down Expand Up @@ -47,7 +45,8 @@
}
}
],
"expo-image-picker"
"expo-image-picker",
"expo-font"
],
"extra": {
"eas": {
Expand Down
5 changes: 4 additions & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ module.exports = function (api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: [
"react-native-reanimated/plugin", // MUST be last
],
env: {
production: {
plugins: ["transform-remove-console"],
plugins: ["transform-remove-console", "react-native-reanimated/plugin"],
},
},
};
Expand Down
32 changes: 32 additions & 0 deletions components/ActivityIndicator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ActivityIndicator, StyleSheet } from "react-native";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
import { COLORS } from "../constants/colors";

/**
* size : large, small
* color : color of the spinner (optional, defaults to buttonGradientEnd)
*/
const Spinner = ({ size = "small", color }) => (
<SafeAreaProvider>
<SafeAreaView style={[styles.container, styles.horizontal]}>
<ActivityIndicator
color={color || COLORS.buttonGradientEnd}
size={size}
/>
</SafeAreaView>
</SafeAreaProvider>
);

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
},
horizontal: {
flexDirection: "row",
justifyContent: "space-around",
padding: 10,
},
});

export default Spinner;
4 changes: 2 additions & 2 deletions components/ImagePickerComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const ImagePickerComponent = ({
if (!hasPermission) {
Alert.alert(
"Permission required",
"Please grant gallery access to select images"
"Please grant gallery access to select images",
);
return;
}
Expand Down Expand Up @@ -65,7 +65,7 @@ const ImagePickerComponent = ({
if (!hasPermission) {
Alert.alert(
"Permission required",
"Please grant camera access to take photos"
"Please grant camera access to take photos",
);
return;
}
Expand Down
3 changes: 2 additions & 1 deletion components/InputField.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const InputField = ({
autoCapitalize = "sentences",
autoFocus = false,
maxLength,
...other
}) => {
const [isFocused, setIsFocused] = useState(false);

Expand Down Expand Up @@ -67,11 +68,11 @@ const InputField = ({
secureTextEntry={secureTextEntry}
keyboardType={keyboardType}
autoCapitalize={autoCapitalize}
editable={!disabled}
autoFocus={autoFocus}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
maxLength={maxLength}
{...other}
/>
{rightIcon && (
<TouchableOpacity
Expand Down
43 changes: 43 additions & 0 deletions components/OutlineButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { StyleSheet, TouchableOpacity, View } from "react-native";
import Icon from "react-native-vector-icons/Ionicons";
import { COLORS } from "../constants";
import { P } from "./Typography";

const OutlineButton = ({ title, onPress, icon }) => {
return (
<TouchableOpacity style={styles.button} onPress={onPress}>
<View>
<Icon
name={icon}
size={16}
color={COLORS.buttonGradientEnd}
style={styles.icon}
/>
</View>
<P style={styles.text}>{title}</P>
</TouchableOpacity>
);
};

const styles = StyleSheet.create({
button: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
height: 48,
borderRadius: 22,
borderWidth: 1.5,
borderColor: COLORS.buttonGradientEnd,
marginBottom: 32, // Increased margin to ensure visibility above FAB
},
icon: {
marginRight: 8,
},
text: {
fontSize: 16,
fontWeight: "600",
color: COLORS.buttonGradientEnd,
},
});

export default OutlineButton;
87 changes: 87 additions & 0 deletions components/ProfileCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { StyleSheet, View } from "react-native";
import { COLORS } from "../constants";
import RoundedAvatar from "./RoundedAvatar";
import { H1, P } from "./Typography";

const ProfileCard = ({ name, phone, location, avatar, onEditAvatar }) => {
return (
<View style={styles.profileCard}>
<RoundedAvatar avatar={avatar} onEditAvatar={onEditAvatar} />
{name && <H1 style={styles.profileName}>{name}</H1>}
{phone && <P style={styles.profilePhone}>{phone}</P>}
<P style={styles.profileLocation}>{location}</P>
</View>
);
};

const styles = StyleSheet.create({
profileCard: {
backgroundColor: COLORS.surface,
borderRadius: 16,
padding: 24,
alignItems: "center",
shadowColor: COLORS.shadowColor,
shadowOffset: {
width: 0,
height: 4,
},
shadowOpacity: 0.08,
shadowRadius: 12,
elevation: 4,
marginBottom: 24,
},
avatarContainer: {
position: "relative",
marginBottom: 16,
},
avatarPlaceholder: {
width: 96,
height: 96,
borderRadius: 48,
backgroundColor: COLORS.inputBackground,
alignItems: "center",
justifyContent: "center",
borderWidth: 1,
borderColor: COLORS.buttonGradientEnd,
borderStyle: "solid",
},
avatarImage: {
width: 96,
height: 96,
borderRadius: 48,
borderWidth: 1,
borderColor: COLORS.buttonGradientEnd,
borderStyle: "solid",
},
editButton: {
position: "absolute",
bottom: 0,
right: 0,
width: 28,
height: 28,
borderRadius: 14,
backgroundColor: COLORS.buttonGradientEnd,
alignItems: "center",
justifyContent: "center",
},
profileName: {
fontSize: 22,
fontFamily: "PlayfairDisplayBold",
color: COLORS.textPrimary,
marginBottom: 4,
textAlign: "center",
},
profilePhone: {
fontSize: 14,
color: COLORS.textSecondary,
marginBottom: 4,
textAlign: "center",
},
profileLocation: {
fontSize: 13,
color: COLORS.textTertiary,
textAlign: "center",
},
});

export default ProfileCard;
69 changes: 69 additions & 0 deletions components/RoundedAvatar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Image, StyleSheet, View } from "react-native";
import Icon from "react-native-vector-icons/Ionicons";
import { COLORS } from "../constants";

const RoundedAvatar = ({ onEditAvatar, avatar, showEditButton }) => {
return (
<View style={styles.avatarContainer} onPress={onEditAvatar}>
{avatar ? (
<Image
source={{ uri: avatar }}
style={styles.avatarImage}
alt="profileImage"
/>
) : (
<View style={styles.avatarPlaceholder}>
<View>
<Icon name="person" size={40} color={COLORS.textSecondary} />
</View>
</View>
)}
{showEditButton && (
<View style={styles.editButton}>
<View>
<Icon name="pencil" size={14} color={COLORS.surface} />
</View>
</View>
)}
</View>
);
};

const styles = StyleSheet.create({
avatarContainer: {
position: "relative",
marginBottom: 16,
},
avatarPlaceholder: {
width: 96,
height: 96,
borderRadius: 48,
backgroundColor: COLORS.inputBackground,
alignItems: "center",
justifyContent: "center",
borderWidth: 1,
borderColor: COLORS.buttonGradientEnd,
borderStyle: "solid",
},
avatarImage: {
width: 96,
height: 96,
borderRadius: 48,
borderWidth: 1,
borderColor: COLORS.buttonGradientEnd,
borderStyle: "solid",
},
editButton: {
position: "absolute",
bottom: 0,
right: 0,
width: 28,
height: 28,
borderRadius: 14,
backgroundColor: COLORS.buttonGradientEnd,
alignItems: "center",
justifyContent: "center",
},
});

export default RoundedAvatar;
24 changes: 24 additions & 0 deletions components/SettingsList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { FlatList, View } from "react-native";
import SettingsListItem from "./SettingsListItem";

const SettingsList = ({ items, dividerStyle }) => {
return (
<FlatList
data={items}
keyExtractor={(item) => item.label}
renderItem={({ item, index }) => (
<View>
<SettingsListItem
icon={item.icon}
label={item.label}
onPress={item.onPress}
/>
{index !== items.length - 1 && <View style={dividerStyle} />}
</View>
)}
scrollEnabled={false}
/>
);
};

export default SettingsList;
Loading