├── .gitignore
├── app.json
├── app
├── (tabs)
│ ├── _layout.tsx
│ ├── bookmarks.tsx
│ ├── category.tsx
│ ├── index.tsx
│ ├── profile.tsx
│ └── search.tsx
├── _layout.tsx
└── listing
│ └── [id].tsx
├── assets
├── fonts
│ └── SpaceMono-Regular.ttf
└── images
│ ├── adaptive-icon.png
│ ├── favicon.png
│ ├── icon.png
│ └── splash.png
├── babel.config.js
├── components
├── CategoryButtons.tsx
├── GroupListings.tsx
└── Listings.tsx
├── constants
└── Colors.ts
├── data
├── categories.ts
├── destinations.json
└── groups.json
├── package-lock.json
├── package.json
├── tsconfig.json
└── types
├── groupType.ts
└── listingType.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
2 |
3 | # dependencies
4 | node_modules/
5 |
6 | # Expo
7 | .expo/
8 | dist/
9 | web-build/
10 |
11 | # Native
12 | *.orig.*
13 | *.jks
14 | *.p8
15 | *.p12
16 | *.key
17 | *.mobileprovision
18 |
19 | # Metro
20 | .metro-health-check*
21 |
22 | # debug
23 | npm-debug.*
24 | yarn-debug.*
25 | yarn-error.*
26 |
27 | # macOS
28 | .DS_Store
29 | *.pem
30 |
31 | # local env files
32 | .env*.local
33 |
34 | # typescript
35 | *.tsbuildinfo
36 |
37 | # @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
38 | # The following patterns were generated by expo-cli
39 |
40 | expo-env.d.ts
41 | # @end expo-cli
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "expo-travel-app",
4 | "slug": "expo-travel-app",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/images/icon.png",
8 | "scheme": "myapp",
9 | "userInterfaceStyle": "automatic",
10 | "splash": {
11 | "image": "./assets/images/splash.png",
12 | "resizeMode": "contain",
13 | "backgroundColor": "#ffffff"
14 | },
15 | "assetBundlePatterns": [
16 | "**/*"
17 | ],
18 | "ios": {
19 | "supportsTablet": true
20 | },
21 | "android": {
22 | "adaptiveIcon": {
23 | "foregroundImage": "./assets/images/adaptive-icon.png",
24 | "backgroundColor": "#ffffff"
25 | }
26 | },
27 | "web": {
28 | "bundler": "metro",
29 | "output": "static",
30 | "favicon": "./assets/images/favicon.png"
31 | },
32 | "plugins": [
33 | "expo-router"
34 | ],
35 | "experiments": {
36 | "typedRoutes": true
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/(tabs)/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { View, Text } from "react-native";
2 | import React from "react";
3 | import { Tabs } from "expo-router";
4 | import { FontAwesome, Ionicons, MaterialIcons } from "@expo/vector-icons";
5 | import Colors from "@/constants/Colors";
6 |
7 | export default function Layout() {
8 | return (
9 |
21 | (
25 |
26 | ),
27 | }}
28 | />
29 | (
33 |
34 | ),
35 | }}
36 | />
37 | (
41 |
50 |
51 |
52 | ),
53 | }}
54 | />
55 | (
59 |
60 | ),
61 | }}
62 | />
63 | (
67 |
68 | ),
69 | }}
70 | />
71 |
72 | );
73 | }
74 |
--------------------------------------------------------------------------------
/app/(tabs)/bookmarks.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Text, View } from 'react-native'
2 | import React from 'react'
3 |
4 | const Page = () => {
5 | return (
6 |
7 | Bookmarks
8 |
9 | )
10 | }
11 |
12 | export default Page
13 |
14 | const styles = StyleSheet.create({
15 | container: {
16 | flex:1,
17 | justifyContent:'center',
18 | alignItems:'center',
19 | }
20 | })
--------------------------------------------------------------------------------
/app/(tabs)/category.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Text, View } from 'react-native'
2 | import React from 'react'
3 |
4 | const Page = () => {
5 | return (
6 |
7 | Category
8 |
9 | )
10 | }
11 |
12 | export default Page
13 |
14 | const styles = StyleSheet.create({
15 | container: {
16 | flex:1,
17 | justifyContent:'center',
18 | alignItems:'center',
19 | }
20 | })
--------------------------------------------------------------------------------
/app/(tabs)/index.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Image,
3 | ScrollView,
4 | StyleSheet,
5 | Text,
6 | TextInput,
7 | TouchableOpacity,
8 | View,
9 | } from "react-native";
10 | import React, { useState } from "react";
11 | import { Stack } from "expo-router";
12 | import { Ionicons } from "@expo/vector-icons";
13 | import Colors from "@/constants/Colors";
14 | import { useHeaderHeight } from "@react-navigation/elements";
15 | import CategoryButtons from "@/components/CategoryButtons";
16 | import Listings from "@/components/Listings";
17 | import listingData from "@/data/destinations.json";
18 | import GroupListings from "@/components/GroupListings";
19 | import groupData from "@/data/groups.json";
20 |
21 | const Page = () => {
22 | const headerHeight = useHeaderHeight();
23 | const [category, setCategory] = useState("All");
24 |
25 | const onCatChanged = (category: string) => {
26 | console.log("Categpry: ", category);
27 | setCategory(category);
28 | };
29 |
30 | return (
31 | <>
32 | (
37 | {}} style={{ marginLeft: 20 }}>
38 |
44 |
45 | ),
46 | headerRight: () => (
47 | {}}
49 | style={{
50 | marginRight: 20,
51 | backgroundColor: Colors.white,
52 | padding: 10,
53 | borderRadius: 10,
54 | shadowColor: "#171717",
55 | shadowOffset: { width: 2, height: 4 },
56 | shadowOpacity: 0.2,
57 | shadowRadius: 3,
58 | }}
59 | >
60 |
61 |
62 | ),
63 | }}
64 | />
65 |
66 |
67 | Explore The Beautiful World!
68 |
69 |
70 |
71 |
77 |
78 |
79 | {}} style={styles.filterBtn}>
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | >
92 | );
93 | };
94 |
95 | export default Page;
96 |
97 | const styles = StyleSheet.create({
98 | container: {
99 | flex: 1,
100 | paddingHorizontal: 20,
101 | backgroundColor: Colors.bgColor,
102 | },
103 | headingTxt: {
104 | fontSize: 28,
105 | fontWeight: "800",
106 | color: Colors.black,
107 | marginTop: 10,
108 | },
109 | searchSectionWrapper: {
110 | flexDirection: "row",
111 | marginVertical: 20,
112 | },
113 | searchBar: {
114 | flex: 1,
115 | flexDirection: "row",
116 | backgroundColor: Colors.white,
117 | padding: 16,
118 | borderRadius: 10,
119 | },
120 | filterBtn: {
121 | backgroundColor: Colors.primaryColor,
122 | padding: 12,
123 | borderRadius: 10,
124 | marginLeft: 20,
125 | },
126 | });
127 |
--------------------------------------------------------------------------------
/app/(tabs)/profile.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Text, View } from 'react-native'
2 | import React from 'react'
3 |
4 | const Page = () => {
5 | return (
6 |
7 | Profile
8 |
9 | )
10 | }
11 |
12 | export default Page
13 |
14 | const styles = StyleSheet.create({
15 | container: {
16 | flex:1,
17 | justifyContent:'center',
18 | alignItems:'center',
19 | }
20 | })
--------------------------------------------------------------------------------
/app/(tabs)/search.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Text, View } from 'react-native'
2 | import React from 'react'
3 |
4 | const Page = () => {
5 | return (
6 |
7 | Search
8 |
9 | )
10 | }
11 |
12 | export default Page
13 |
14 | const styles = StyleSheet.create({
15 | container: {
16 | flex:1,
17 | justifyContent:'center',
18 | alignItems:'center',
19 | }
20 | })
--------------------------------------------------------------------------------
/app/_layout.tsx:
--------------------------------------------------------------------------------
1 | import FontAwesome from "@expo/vector-icons/FontAwesome";
2 | import { useFonts } from "expo-font";
3 | import { Stack } from "expo-router";
4 | import * as SplashScreen from "expo-splash-screen";
5 | import { useEffect } from "react";
6 |
7 | export {
8 | // Catch any errors thrown by the Layout component.
9 | ErrorBoundary,
10 | } from "expo-router";
11 |
12 | export const unstable_settings = {
13 | // Ensure that reloading on `/modal` keeps a back button present.
14 | initialRouteName: "(tabs)",
15 | };
16 |
17 | // Prevent the splash screen from auto-hiding before asset loading is complete.
18 | SplashScreen.preventAutoHideAsync();
19 |
20 | export default function RootLayout() {
21 | const [loaded, error] = useFonts({
22 | SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
23 | ...FontAwesome.font,
24 | });
25 |
26 | // Expo Router uses Error Boundaries to catch errors in the navigation tree.
27 | useEffect(() => {
28 | if (error) throw error;
29 | }, [error]);
30 |
31 | useEffect(() => {
32 | if (loaded) {
33 | SplashScreen.hideAsync();
34 | }
35 | }, [loaded]);
36 |
37 | if (!loaded) {
38 | return null;
39 | }
40 |
41 | return ;
42 | }
43 |
44 | function RootLayoutNav() {
45 | return (
46 |
47 |
48 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/app/listing/[id].tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Dimensions,
3 | Image,
4 | ScrollView,
5 | StyleSheet,
6 | Text,
7 | TouchableOpacity,
8 | View,
9 | } from "react-native";
10 | import React from "react";
11 | import { Stack, useLocalSearchParams, useRouter } from "expo-router";
12 | import { ListingType } from "@/types/listingType";
13 | import listingData from "@/data/destinations.json";
14 | import {
15 | Feather,
16 | FontAwesome,
17 | FontAwesome5,
18 | Ionicons,
19 | } from "@expo/vector-icons";
20 | import Colors from "@/constants/Colors";
21 | import Animated, {
22 | SlideInDown,
23 | interpolate,
24 | useAnimatedRef,
25 | useAnimatedStyle,
26 | useScrollViewOffset,
27 | } from "react-native-reanimated";
28 |
29 | const { width } = Dimensions.get("window");
30 | const IMG_HEIGHT = 300;
31 |
32 | const ListingDetails = () => {
33 | const { id } = useLocalSearchParams();
34 | const listing: ListingType = (listingData as ListingType[]).find(
35 | (item) => item.id === id
36 | );
37 |
38 | const router = useRouter();
39 |
40 | const scrollRef = useAnimatedRef();
41 | const scrollOffset = useScrollViewOffset(scrollRef);
42 | const imageAnimatedStyle = useAnimatedStyle(() => {
43 | return {
44 | transform: [
45 | {
46 | translateY: interpolate(
47 | scrollOffset.value,
48 | [-IMG_HEIGHT, 0, IMG_HEIGHT],
49 | [-IMG_HEIGHT / 2, 0, IMG_HEIGHT * 0.75]
50 | ),
51 | },
52 | {
53 | scale: interpolate(
54 | scrollOffset.value,
55 | [-IMG_HEIGHT, 0, IMG_HEIGHT],
56 | [2, 1, 1]
57 | ),
58 | },
59 | ],
60 | };
61 | });
62 |
63 | return (
64 | <>
65 | (
70 | router.back()}
72 | style={{
73 | backgroundColor: "rgba(255, 255, 255, 0.5)",
74 | borderRadius: 10,
75 | padding: 4,
76 | }}
77 | >
78 |
85 |
86 |
87 |
88 | ),
89 | headerRight: () => (
90 | {}}
92 | style={{
93 | backgroundColor: "rgba(255, 255, 255, 0.5)",
94 | borderRadius: 10,
95 | padding: 4,
96 | }}
97 | >
98 |
105 |
106 |
107 |
108 | ),
109 | }}
110 | />
111 |
112 |
116 |
120 |
121 | {listing.name}
122 |
123 |
128 | {listing.location}
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 | Duration
138 |
139 | {listing.duration} Days
140 |
141 |
142 |
143 |
144 |
145 |
150 |
151 |
152 | Person
153 | {listing.duration}
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 | Rating
162 |
163 | {listing.rating}
164 |
165 |
166 |
167 |
168 |
169 | {listing.description}
170 |
171 |
172 |
173 |
174 |
175 | {}}
177 | style={[styles.footerBtn, styles.footerBookBtn]}
178 | >
179 | Book Now
180 |
181 | {}} style={styles.footerBtn}>
182 | ${listing.price}
183 |
184 |
185 | >
186 | );
187 | };
188 |
189 | export default ListingDetails;
190 |
191 | const styles = StyleSheet.create({
192 | container: {
193 | flex: 1,
194 | backgroundColor: Colors.white,
195 | },
196 | image: {
197 | width: width,
198 | height: IMG_HEIGHT,
199 | },
200 | contentWrapper: {
201 | padding: 20,
202 | backgroundColor: Colors.white,
203 | },
204 | listingName: {
205 | fontSize: 24,
206 | fontWeight: "500",
207 | color: Colors.black,
208 | letterSpacing: 0.5,
209 | },
210 | listingLocationWrapper: {
211 | flexDirection: "row",
212 | marginTop: 5,
213 | marginBottom: 10,
214 | alignItems: "center",
215 | },
216 | listingLocationTxt: {
217 | fontSize: 14,
218 | marginLeft: 5,
219 | color: Colors.black,
220 | },
221 | highlightWrapper: {
222 | flexDirection: "row",
223 | marginVertical: 20,
224 | justifyContent: "space-between",
225 | },
226 | highlightIcon: {
227 | backgroundColor: "#F4F4F4",
228 | paddingHorizontal: 8,
229 | paddingVertical: 5,
230 | borderRadius: 8,
231 | marginRight: 5,
232 | alignItems: "center",
233 | },
234 | highlightTxt: {
235 | fontSize: 12,
236 | color: "#999",
237 | },
238 | highlightTxtVal: {
239 | fontSize: 14,
240 | fontWeight: "600",
241 | },
242 | listingDetails: {
243 | fontSize: 16,
244 | color: Colors.black,
245 | lineHeight: 25,
246 | letterSpacing: 0.5,
247 | },
248 | footer: {
249 | flexDirection: "row",
250 | position: "absolute",
251 | bottom: 0,
252 | padding: 20,
253 | paddingBottom: 30,
254 | width: width,
255 | },
256 | footerBtn: {
257 | flex: 1,
258 | backgroundColor: Colors.black,
259 | padding: 20,
260 | borderRadius: 10,
261 | alignItems: "center",
262 | },
263 | footerBookBtn: {
264 | flex: 2,
265 | backgroundColor: Colors.primaryColor,
266 | marginRight: 20,
267 | },
268 | footerBtnTxt: {
269 | color: Colors.white,
270 | fontSize: 16,
271 | fontWeight: "600",
272 | textTransform: "uppercase",
273 | },
274 | });
275 |
--------------------------------------------------------------------------------
/assets/fonts/SpaceMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itzpradip/travel-app-ui-expo-router/05b99bde8e583be8a14a089a9c6b205fcf365747/assets/fonts/SpaceMono-Regular.ttf
--------------------------------------------------------------------------------
/assets/images/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itzpradip/travel-app-ui-expo-router/05b99bde8e583be8a14a089a9c6b205fcf365747/assets/images/adaptive-icon.png
--------------------------------------------------------------------------------
/assets/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itzpradip/travel-app-ui-expo-router/05b99bde8e583be8a14a089a9c6b205fcf365747/assets/images/favicon.png
--------------------------------------------------------------------------------
/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itzpradip/travel-app-ui-expo-router/05b99bde8e583be8a14a089a9c6b205fcf365747/assets/images/icon.png
--------------------------------------------------------------------------------
/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itzpradip/travel-app-ui-expo-router/05b99bde8e583be8a14a089a9c6b205fcf365747/assets/images/splash.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true);
3 | return {
4 | presets: ["babel-preset-expo"],
5 | plugins: ["react-native-reanimated/plugin"],
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/components/CategoryButtons.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | ScrollView,
3 | StyleSheet,
4 | Text,
5 | TouchableOpacity,
6 | View,
7 | } from "react-native";
8 | import React, { useRef, useState } from "react";
9 | import Colors from "@/constants/Colors";
10 | import destinationCategories from "@/data/categories";
11 | import { MaterialCommunityIcons } from "@expo/vector-icons";
12 |
13 | type Props = {
14 | onCagtegoryChanged: (category: string) => void;
15 | }
16 |
17 | const CategoryButtons = ({onCagtegoryChanged}: Props) => {
18 | const scrollRef = useRef(null);
19 | const itemRef = useRef([]);
20 | const [activeIndex, setActiveIndex] = useState(0);
21 |
22 | const handleSelectCategory = (index: number) => {
23 | const selected = itemRef.current[index];
24 | setActiveIndex(index);
25 |
26 | selected?.measure((x) => {
27 | scrollRef.current?.scrollTo({ x: x, y: 0, animated: true });
28 | });
29 |
30 | onCagtegoryChanged(destinationCategories[index].title);
31 | };
32 |
33 | return (
34 |
35 | Categories
36 |
46 | {destinationCategories.map((item, index) => (
47 | itemRef.current[index] = el}
50 | onPress={() => handleSelectCategory(index)}
51 | style={
52 | activeIndex === index
53 | ? styles.categoryBtnActive
54 | : styles.categoryBtn
55 | }
56 | >
57 |
62 |
69 | {item.title}
70 |
71 |
72 | ))}
73 |
74 |
75 | );
76 | };
77 |
78 | export default CategoryButtons;
79 |
80 | const styles = StyleSheet.create({
81 | title: {
82 | fontSize: 22,
83 | fontWeight: "700",
84 | color: Colors.black,
85 | },
86 | categoryBtn: {
87 | flexDirection: "row",
88 | alignItems: "center",
89 | backgroundColor: Colors.white,
90 | paddingHorizontal: 16,
91 | paddingVertical: 10,
92 | borderRadius: 10,
93 | shadowColor: "#333333",
94 | shadowOffset: { width: 1, height: 2 },
95 | shadowOpacity: 0.1,
96 | shadowRadius: 3,
97 | },
98 | categoryBtnActive: {
99 | flexDirection: "row",
100 | alignItems: "center",
101 | backgroundColor: Colors.primaryColor,
102 | paddingHorizontal: 16,
103 | paddingVertical: 10,
104 | borderRadius: 10,
105 | shadowColor: "#333333",
106 | shadowOffset: { width: 1, height: 2 },
107 | shadowOpacity: 0.1,
108 | shadowRadius: 3,
109 | },
110 | categoryBtnTxt: {
111 | marginLeft: 5,
112 | color: Colors.black,
113 | },
114 | categoryBtnTxtActive: {
115 | marginLeft: 5,
116 | color: Colors.white,
117 | },
118 | });
119 |
--------------------------------------------------------------------------------
/components/GroupListings.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FlatList,
3 | Image,
4 | ListRenderItem,
5 | StyleSheet,
6 | Text,
7 | View,
8 | } from "react-native";
9 | import React from "react";
10 | import { GroupType } from "@/types/groupType";
11 | import Colors from "@/constants/Colors";
12 | import { Ionicons } from "@expo/vector-icons";
13 |
14 | const GroupListings = ({ listings }: { listings: GroupType[] }) => {
15 | const renderItem: ListRenderItem = ({ item }) => {
16 | return (
17 |
18 |
19 |
20 | {item.name}
21 |
22 |
23 | {item.rating}
24 | ({item.reviews})
25 |
26 |
27 |
28 | );
29 | };
30 |
31 | return (
32 |
33 | Top Travel Groups
34 |
40 |
41 | );
42 | };
43 |
44 | export default GroupListings;
45 |
46 | const styles = StyleSheet.create({
47 | title: {
48 | fontSize: 22,
49 | fontWeight: "600",
50 | color: Colors.black,
51 | marginBottom: 10,
52 | },
53 | item: {
54 | backgroundColor: Colors.white,
55 | padding: 10,
56 | borderRadius: 10,
57 | marginRight: 20,
58 | flexDirection: "row",
59 | alignItems: "center",
60 | },
61 | image: {
62 | width: 80,
63 | height: 100,
64 | borderRadius: 10,
65 | marginRight: 10,
66 | },
67 | itemTxt: {
68 | fontSize: 14,
69 | fontWeight: "600",
70 | color: Colors.black,
71 | marginBottom: 8,
72 | },
73 | itemRating: {
74 | fontSize: 14,
75 | fontWeight: '600',
76 | color: Colors.black,
77 | marginLeft: 5,
78 | },
79 | itemReviews: {
80 | fontSize: 14,
81 | color: '#999'
82 | }
83 | });
84 |
--------------------------------------------------------------------------------
/components/Listings.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FlatList,
3 | Image,
4 | ListRenderItem,
5 | StyleSheet,
6 | Text,
7 | TouchableOpacity,
8 | View,
9 | } from "react-native";
10 | import React, { useEffect, useState } from "react";
11 | import { ListingType } from "@/types/listingType";
12 | import Colors from "@/constants/Colors";
13 | import { FontAwesome5, Ionicons } from "@expo/vector-icons";
14 | import { Link } from "expo-router";
15 |
16 | type Props = {
17 | listings: any[];
18 | category: string;
19 | };
20 |
21 | const Listings = ({ listings, category }: Props) => {
22 | const [loading, setLoading] = useState(false);
23 |
24 | useEffect(() => {
25 | console.log('Update Listing');
26 | setLoading(true);
27 |
28 | setTimeout(() => {
29 | setLoading(false)
30 | }, 200);
31 | }, [category]);
32 |
33 | const renderItems: ListRenderItem = ({ item }) => {
34 | return (
35 |
36 |
37 |
38 |
39 |
40 |
45 |
46 |
47 | {item.name}
48 |
49 |
52 |
53 |
58 | {item.location}
59 |
60 | ${item.price}
61 |
62 |
63 |
64 |
65 | );
66 | };
67 |
68 | return (
69 |
70 |
76 |
77 | );
78 | };
79 |
80 | export default Listings;
81 |
82 | const styles = StyleSheet.create({
83 | item: {
84 | backgroundColor: Colors.white,
85 | padding: 10,
86 | borderRadius: 10,
87 | marginRight: 20,
88 | width: 220,
89 | },
90 | image: {
91 | width: 200,
92 | height: 200,
93 | borderRadius: 10,
94 | marginBottom: 30,
95 | },
96 | bookmark: {
97 | position: "absolute",
98 | top: 185,
99 | right: 30,
100 | backgroundColor: Colors.primaryColor,
101 | padding: 10,
102 | borderRadius: 30,
103 | borderWidth: 2,
104 | borderColor: Colors.white,
105 | },
106 | itemTxt: {
107 | fontSize: 16,
108 | fontWeight: "600",
109 | color: Colors.black,
110 | marginBottom: 10,
111 | },
112 | itemLocationTxt: {
113 | fontSize: 12,
114 | marginLeft: 5,
115 | },
116 | itemPriceTxt: {
117 | fontSize: 12,
118 | fontWeight: "600",
119 | color: Colors.primaryColor,
120 | },
121 | });
122 |
--------------------------------------------------------------------------------
/constants/Colors.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | primaryColor: '#ff7f36',
3 | bgColor: '#F4F4F4',
4 | black: '#27283a',
5 | white: '#FFFFFF',
6 | }
--------------------------------------------------------------------------------
/data/categories.ts:
--------------------------------------------------------------------------------
1 | const destinationCategories = [
2 | {
3 | title: "All",
4 | iconName: "hiking"
5 | },
6 | {
7 | title: "Beaches",
8 | iconName: "beach"
9 | },
10 | {
11 | title: "Mountains",
12 | iconName: "terrain"
13 | },
14 | {
15 | title: "Cities",
16 | iconName: "city"
17 | },
18 | {
19 | title: "Forests",
20 | iconName: "tree"
21 | },
22 | {
23 | title: "Lakes",
24 | iconName: "swim"
25 | },
26 | {
27 | title: "Historical Sites",
28 | iconName: "castle"
29 | },
30 | {
31 | title: "National Parks",
32 | iconName: "pine-tree"
33 | },
34 | {
35 | title: "Islands",
36 | iconName: "island"
37 | },
38 | {
39 | title: "Deserts",
40 | iconName: "weather-sunny"
41 | }
42 | ];
43 |
44 | export default destinationCategories;
45 |
--------------------------------------------------------------------------------
/data/destinations.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "1",
4 | "name": "Tropical Paradise Resort",
5 | "image": "https://images.unsplash.com/photo-1540541338287-41700207dee6?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
6 | "description": "Escape to the ultimate tropical paradise retreat with pristine beaches, lush greenery, and luxurious accommodations.",
7 | "rating": 4.8,
8 | "price": "150",
9 | "duration": "3",
10 | "location": "Pacific Ocean",
11 | "category": "Beaches"
12 | },
13 | {
14 | "id": "2",
15 | "name": "Alpine Chalet Retreat",
16 | "image": "https://images.unsplash.com/photo-1512273222628-4daea6e55abb?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
17 | "description": "Experience the breathtaking beauty of the Alps from your cozy chalet, surrounded by snow-capped peaks and charming villages.",
18 | "rating": 4.5,
19 | "price": "120",
20 | "duration": "4",
21 | "location": "Switzerland",
22 | "category": "Mountains"
23 | },
24 | {
25 | "id": "3",
26 | "name": "Urban Explorer's Dream",
27 | "image": "https://images.unsplash.com/photo-1546436836-07a91091f160?q=80&w=3548&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
28 | "description": "Immerse yourself in the vibrant energy of the city with bustling streets, iconic landmarks, and endless cultural experiences.",
29 | "rating": 4.7,
30 | "price": "140",
31 | "duration": "2",
32 | "location": "USA",
33 | "category": "Cities"
34 | },
35 | {
36 | "id": "4",
37 | "name": "Enchanted Forest Retreat",
38 | "image": "https://plus.unsplash.com/premium_photo-1668917805105-2d5d9e49af87?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
39 | "description": "Find serenity in the heart of nature with towering trees, hidden waterfalls, and enchanting wildlife in this magical forest retreat.",
40 | "rating": 4.6,
41 | "price": "180",
42 | "duration": "5",
43 | "location": "USA",
44 | "category": "Forests"
45 | },
46 | {
47 | "id": "5",
48 | "name": "Tranquil Lakeside Haven",
49 | "image": "https://images.unsplash.com/photo-1535927583620-7940e95a5a05?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8bGFrZSx0cmFucXVpbHx8fHx8fDE3MTEwMzI1MjA&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
50 | "description": "Relax and rejuvenate by the tranquil lakeside, surrounded by stunning scenery and peaceful serenity.",
51 | "rating": 4.9,
52 | "price": "120",
53 | "duration": "3",
54 | "location": "England",
55 | "category": "Lakes"
56 | },
57 | {
58 | "id": "6",
59 | "name": "Sandy Shores Beach Resort",
60 | "image": "https://images.unsplash.com/photo-1506929562872-bb421503ef21?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8YmVhY2gsc2FuZHl8fHx8fHwxNzExMDMyNTg5&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
61 | "description": "Indulge in the ultimate beachfront luxury with pristine sands, crystal-clear waters, and world-class amenities.",
62 | "rating": 4.8,
63 | "price": "140",
64 | "duration": "2",
65 | "location": "Maldives",
66 | "category": "Beaches"
67 | },
68 | {
69 | "id": "7",
70 | "name": "Majestic Mountain Lodge",
71 | "image": "https://images.unsplash.com/photo-1543768179-656dbc9d9be9?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8bW91bnRhaW4sbWFqZXN0aWN8fHx8fHwxNzExMDMyNjUw&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
72 | "description": "Unwind in the lap of luxury amidst majestic mountain peaks, alpine meadows, and breathtaking vistas.",
73 | "rating": 4.7,
74 | "price": "100",
75 | "duration": "7",
76 | "location": "Canada",
77 | "category": "Mountains"
78 | },
79 | {
80 | "id": "8",
81 | "name": "Metropolitan Marvels",
82 | "image": "https://images.unsplash.com/photo-1697543117287-53b5ab69742b?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8Y2l0eSxtZXRyb3BvbGl0YW58fHx8fHwxNzExMDMyNzM1&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
83 | "description": "Discover the cultural richness and architectural wonders of bustling metropolises around the globe.",
84 | "rating": 4.6,
85 | "price": "170",
86 | "duration": "3",
87 | "location": "Japan",
88 | "category": "Cities"
89 | },
90 | {
91 | "id": "9",
92 | "name": "Mystical Forest Sanctuary",
93 | "image": "https://images.unsplash.com/photo-1496564692837-ec757c470e07?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8Zm9yZXN0LG15c3RpY2FsfHx8fHx8MTcxMTAzMjgyNA&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
94 | "description": "Embark on a journey through ancient forests, mystical ruins, and hidden wonders in this enchanted sanctuary.",
95 | "rating": 4.9,
96 | "price": "80",
97 | "duration": "2",
98 | "location": "Brazil",
99 | "category": "Forests"
100 | },
101 | {
102 | "id": "10",
103 | "name": "Serene Lake Retreat",
104 | "image": "https://images.unsplash.com/photo-1541420937988-702d78cb9fa1?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8bGFrZSxzZXJlbmV8fHx8fHwxNzExMDMyODcx&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
105 | "description": "Escape the hustle and bustle of city life and immerse yourself in the serene beauty of lakeside living.",
106 | "rating": 4.5,
107 | "price": "120",
108 | "duration": "3",
109 | "location": "USA",
110 | "category": "Lakes"
111 | },
112 | {
113 | "id": "11",
114 | "name": "Golden Sands Beach Resort",
115 | "image": "https://images.unsplash.com/photo-1535792679781-7a212687bc8f?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8YmVhY2gsZ29sZGVufHx8fHx8MTcxMTAzMjkzOQ&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
116 | "description": "Experience paradise on earth with golden sands, azure waters, and luxurious beachfront accommodations.",
117 | "rating": 4.8,
118 | "price": "150",
119 | "duration": "3",
120 | "location": "Fiji",
121 | "category": "Beaches"
122 | },
123 | {
124 | "id": "12",
125 | "name": "Alpine Adventure Lodge",
126 | "image": "https://images.unsplash.com/photo-1521929135277-1891dc05ef4d?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8bW91bnRhaW4sYWxwaW5lfHx8fHx8MTcxMTAzMjk4OQ&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
127 | "description": "Embark on an unforgettable alpine adventure with thrilling outdoor activities and cozy lodge accommodations.",
128 | "rating": 4.6,
129 | "price": "120",
130 | "duration": "3",
131 | "location": "Italy",
132 | "category": "Mountains"
133 | },
134 | {
135 | "id": "13",
136 | "name": "Cultural Capitals",
137 | "image": "https://images.unsplash.com/photo-1689723744935-60e01c337543?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8Y2l0eSxjdWx0dXJhbHx8fHx8fDE3MTEwMzMwODY&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
138 | "description": "Explore the vibrant tapestry of culture, history, and art in the world's most captivating cultural capitals.",
139 | "rating": 4.7,
140 | "price": "130",
141 | "duration": "5",
142 | "location": "France",
143 | "category": "Cities"
144 | },
145 | {
146 | "id": "14",
147 | "name": "Enchanted Grove",
148 | "image": "https://images.unsplash.com/photo-1541897174996-d68b4a8055c9?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8Zm9yZXN0LGdyb3ZlfHx8fHx8MTcxMTAzMzEyMQ&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
149 | "description": "Step into a realm of enchantment and wonder in this mystical grove filled with ancient trees and magical creatures.",
150 | "rating": 4.9,
151 | "price": "150",
152 | "duration": "3",
153 | "location": "Germany",
154 | "category": "Forests"
155 | },
156 | {
157 | "id": "15",
158 | "name": "Tranquil Mountain Hideaway",
159 | "image": "https://images.unsplash.com/photo-1584812261582-efe582e4c124?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=900&ixid=MnwxfDB8MXxyYW5kb218MHx8bW91bnRhaW4sdHJhbnF1aWx8fHx8fHwxNzExMDMzMTky&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1600",
160 | "description": "Find solace and tranquility amidst towering peaks and pristine wilderness in this secluded mountain hideaway.",
161 | "rating": 4.8,
162 | "price": "80",
163 | "duration": "5",
164 | "location": "Canada",
165 | "category": "Mountains"
166 | },
167 | {
168 | "id": "16",
169 | "name": "Seaside Sanctuary",
170 | "image": "https://images.unsplash.com/photo-1477959858617-67f85cf4f1df",
171 | "description": "Escape to a serene seaside sanctuary with breathtaking ocean views, pristine beaches, and luxurious accommodations.",
172 | "rating": 4.7,
173 | "price": "100",
174 | "duration": "3",
175 | "location": "Italy",
176 | "category": "Beaches"
177 | },
178 | {
179 | "id": "17",
180 | "name": "Alpine Lakeside Lodge",
181 | "image": "https://images.unsplash.com/photo-1508899005055-fb1677e7b887?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
182 | "description": "Unwind by the tranquil shores of an alpine lake, surrounded by majestic peaks and pristine nature.",
183 | "rating": 4.6,
184 | "price": "100",
185 | "duration": "3",
186 | "location": "Canada",
187 | "category": "Lakes"
188 | },
189 | {
190 | "id": "18",
191 | "name": "Urban Oasis",
192 | "image": "https://images.unsplash.com/photo-1525625293386-3f8f99389edd?q=80&w=3452&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
193 | "description": "Discover a peaceful oasis amidst the bustling cityscape, where lush gardens and tranquil ponds provide respite.",
194 | "rating": 4.8,
195 | "price": "90",
196 | "duration": "3",
197 | "location": "Singapore",
198 | "category": "Cities"
199 | },
200 | {
201 | "id": "19",
202 | "name": "Whispering Woods Retreat",
203 | "image": "https://images.unsplash.com/photo-1574288339398-531d55fd84f3?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
204 | "description": "Find solace in the tranquil embrace of whispering woods, where ancient trees and hidden streams beckon the soul.",
205 | "rating": 4.9,
206 | "price": "140",
207 | "duration": "3",
208 | "location": "USA",
209 | "category": "Forests"
210 | },
211 | {
212 | "id": "20",
213 | "name": "Sapphire Shores Beach Resort",
214 | "image": "https://plus.unsplash.com/premium_photo-1681223447383-402912b83029?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
215 | "description": "Experience the epitome of luxury beachfront living with sapphire waters, pristine sands, and world-class amenities.",
216 | "rating": 4.7,
217 | "price": "150",
218 | "duration": "3",
219 | "location": "Bahamas",
220 | "category": "Beaches"
221 | }
222 | ]
223 |
--------------------------------------------------------------------------------
/data/groups.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "1",
4 | "name": "Holiday Travel Agency",
5 | "image": "https://images.unsplash.com/photo-1516496636080-14fb876e029d?q=80&w=3388&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
6 | "rating": 4.7,
7 | "reviews": 1450
8 | },
9 | {
10 | "id": "2",
11 | "name": "Happy Tour Planners",
12 | "image": "https://images.unsplash.com/photo-1618591362251-1c9f70b59192?q=80&w=3177&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
13 | "rating": 4.8,
14 | "reviews": 650
15 | },
16 | {
17 | "id": "3",
18 | "name": "Royal Tour & Travels",
19 | "image": "https://images.unsplash.com/photo-1600468636011-c75ae69b7fcb?q=80&w=2625&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
20 | "rating": 4.9,
21 | "reviews": 550
22 | }
23 | ]
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "expo-travel-app",
3 | "main": "expo-router/entry",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start",
7 | "android": "expo start --android",
8 | "ios": "expo start --ios",
9 | "web": "expo start --web",
10 | "test": "jest --watchAll"
11 | },
12 | "jest": {
13 | "preset": "jest-expo"
14 | },
15 | "dependencies": {
16 | "@expo/vector-icons": "^14.0.0",
17 | "@react-navigation/native": "^6.0.2",
18 | "expo": "~50.0.14",
19 | "expo-font": "~11.10.3",
20 | "expo-linking": "~6.2.2",
21 | "expo-router": "~3.4.8",
22 | "expo-splash-screen": "~0.26.4",
23 | "expo-status-bar": "~1.11.1",
24 | "expo-system-ui": "~2.9.3",
25 | "expo-web-browser": "~12.8.2",
26 | "react": "18.2.0",
27 | "react-dom": "18.2.0",
28 | "react-native": "0.73.6",
29 | "react-native-safe-area-context": "4.8.2",
30 | "react-native-screens": "~3.29.0",
31 | "react-native-web": "~0.19.6",
32 | "react-native-reanimated": "~3.6.2"
33 | },
34 | "devDependencies": {
35 | "@babel/core": "^7.20.0",
36 | "@types/react": "~18.2.45",
37 | "jest": "^29.2.1",
38 | "jest-expo": "~50.0.4",
39 | "react-test-renderer": "18.2.0",
40 | "typescript": "^5.1.3"
41 | },
42 | "private": true
43 | }
44 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo/tsconfig.base",
3 | "compilerOptions": {
4 | "strict": true,
5 | "paths": {
6 | "@/*": [
7 | "./*"
8 | ]
9 | }
10 | },
11 | "include": [
12 | "**/*.ts",
13 | "**/*.tsx",
14 | ".expo/types/**/*.ts",
15 | "expo-env.d.ts"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/types/groupType.ts:
--------------------------------------------------------------------------------
1 | export interface GroupType {
2 | id: string;
3 | name: string;
4 | image: string;
5 | rating: number;
6 | reviews: number;
7 | }
--------------------------------------------------------------------------------
/types/listingType.ts:
--------------------------------------------------------------------------------
1 | export interface ListingType {
2 | id: string;
3 | name: string;
4 | image: string;
5 | description: string;
6 | rating: number;
7 | price: string;
8 | duration: string;
9 | location: string;
10 | category: string;
11 | }
--------------------------------------------------------------------------------