Skip to content

Commit

Permalink
Frontend pagination and many API fetch fixes (#234)
Browse files Browse the repository at this point in the history
* add google ios client id to credentials

* wrap restaurant and food name text in user home

* use const google ios client id

* user restaurants screen pagination

* user food screen pagination

* move user's home list item to generic component

* user home screen restaurant pagination

* user home screen food pagination

* fix price indicator crash bug

* fixes

* cleanup

* send coordinates to getRestaurantById

* remove unnecessary new Date in food POST
  • Loading branch information
Audrius Savickas authored Dec 7, 2021
1 parent b4becb5 commit 63873b1
Show file tree
Hide file tree
Showing 36 changed files with 323 additions and 174 deletions.
1 change: 1 addition & 0 deletions frontend/wasted-app/credentials.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const GOOGLE_MAPS_API_KEY = ""
export const GOOGLE_IOS_CLIENT_ID = ""
24 changes: 19 additions & 5 deletions frontend/wasted-app/src/api/food.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Food, FoodSortObject, FoodType} from "./interfaces"
import {Pagination} from "./pagination"
import {WASTED_SERVER_URL} from "./urls"

export const getFoodTypeByFoodId = async (id: string): Promise<FoodType> => {
Expand All @@ -12,14 +13,27 @@ export const getFoodTypeByFoodId = async (id: string): Promise<FoodType> => {
}
}

export const getAllFood = async (sortObject?: FoodSortObject): Promise<Food[]> => {
export const getAllFood = async ({
sortObject,
pagination
}: {
sortObject?: FoodSortObject
pagination?: Pagination
}): Promise<Food[]> => {
try {
let response
let queryString = `${WASTED_SERVER_URL}/Food`

if (sortObject || pagination) {
queryString += "?"
}
if (sortObject) {
response = await fetch(`${WASTED_SERVER_URL}/Food?sortOrder=${sortObject.sortType}`)
} else {
response = await fetch(`${WASTED_SERVER_URL}/Food`)
queryString += `&sortOrder=${sortObject.sortType}`
}
if (pagination) {
queryString += `&PageNumber=${pagination.pageNumber}&PageSize=${pagination.pageSize}`
}

const response = await fetch(queryString)
const data = await response.json()
return data
} catch (error) {
Expand Down
4 changes: 4 additions & 0 deletions frontend/wasted-app/src/api/pagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface Pagination {
pageNumber: number
pageSize: number
}
37 changes: 31 additions & 6 deletions frontend/wasted-app/src/api/restaurant.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import {Credentials, Food, Restaurant, RestaurantRegisterRequest, RestaurantSortObject} from "./interfaces"
import {Coordinates, Credentials, Food, Restaurant, RestaurantRegisterRequest, RestaurantSortObject} from "./interfaces"
import {Pagination} from "./pagination"
import {WASTED_SERVER_URL} from "./urls"

export const getAllRestaurants = async (sortObject?: RestaurantSortObject): Promise<Restaurant[]> => {
export const getAllRestaurants = async ({
sortObject,
pagination
}: {
sortObject?: RestaurantSortObject
pagination?: Pagination
}): Promise<Restaurant[]> => {
try {
let queryString = `${WASTED_SERVER_URL}/Restaurant`

if (sortObject || pagination) {
queryString += "?"
}
if (sortObject?.sortType) {
queryString += `?sortOrder=${sortObject.sortType}`
queryString += `sortOrder=${sortObject.sortType}`
if (sortObject.coordinates) {
queryString += `&Longitude=${sortObject.coordinates.longitude.toString()}&Latitude=${sortObject.coordinates.latitude.toString()}`
}
} else if (sortObject?.coordinates) {
queryString += `?&Longitude=${sortObject.coordinates.longitude.toString()}&Latitude=${sortObject.coordinates.latitude.toString()}`
queryString += `&Longitude=${sortObject.coordinates.longitude.toString()}&Latitude=${sortObject.coordinates.latitude.toString()}`
}
if (pagination) {
queryString += `&PageNumber=${pagination.pageNumber}&PageSize=${pagination.pageSize}`
}
const response = await fetch(queryString)
const data = await response.json()
Expand All @@ -31,9 +45,20 @@ export const getAllFoodByRestaurantId = async (id: string): Promise<Food[]> => {
}
}

export const getRestaurantById = async (id: string): Promise<Restaurant> => {
export const getRestaurantById = async ({
idRestaurant,
coordinates
}: {
idRestaurant: string
coordinates?: Coordinates
}): Promise<Restaurant> => {
try {
const response = await fetch(`${WASTED_SERVER_URL}/Restaurant/${id}`)
let queryString = `${WASTED_SERVER_URL}/Restaurant/${idRestaurant}`

if (coordinates) {
queryString += `?&Longitude=${coordinates.longitude.toString()}&Latitude=${coordinates.latitude.toString()}`
}
const response = await fetch(queryString)
const data = await response.json()
return data
} catch (error) {
Expand Down
6 changes: 5 additions & 1 deletion frontend/wasted-app/src/components/food-item/food-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ import React, {useEffect, useState} from "react"
import {Colors, Image, Text, TouchableOpacity, View} from "react-native-ui-lib"
import {getRestaurantById} from "../../api"
import {Restaurant} from "../../api/interfaces"
import {useLocation} from "../../hooks/use-location"
import {formatPrice} from "../../utils/currency"
import {timeAgoFull} from "../../utils/date"
import {FoodItemProps} from "./interfaces"

export const FoodItem = ({food, onPress}: FoodItemProps) => {
const {name, idRestaurant, currentPrice, startingPrice, imageURL, createdAt} = food
const [restaurant, setRestaurant] = useState({} as Restaurant)
const {location} = useLocation()

const fetchRestaurant = async () => {
setRestaurant(await getRestaurantById(idRestaurant))
setRestaurant(
await getRestaurantById({idRestaurant, coordinates: {latitude: location.latitude, longitude: location.longitude}})
)
}

useEffect(() => {
Expand Down
13 changes: 11 additions & 2 deletions frontend/wasted-app/src/components/foods-list/foods-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {navigateToFoodInfo} from "../../services/navigation"
import {FoodItem} from "../food-item"
import {FoodsListProps} from "./interfaces"

export const FoodsList = ({componentId, foods}: FoodsListProps) => {
export const FoodsList = ({componentId, foods, onEndReached}: FoodsListProps) => {
const renderItem = ({item}: ListRenderItemInfo<Food>) => {
return (
<FoodItem
Expand All @@ -17,5 +17,14 @@ export const FoodsList = ({componentId, foods}: FoodsListProps) => {
)
}

return <FlatList style={{marginBottom: 8}} renderItem={renderItem} data={foods} keyExtractor={item => item.id} />
return (
<FlatList
style={{marginBottom: 8}}
renderItem={renderItem}
data={foods}
keyExtractor={item => item.id}
onEndReachedThreshold={0}
onEndReached={onEndReached}
/>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import {Food} from "../../api/interfaces"

export interface FoodsListProps extends NavigationComponentProps {
foods: Food[]
onEndReached: () => void
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {FlatList} from "react-native-gesture-handler"
import {View} from "react-native-ui-lib"
import {HorizontalListProps} from "./interfaces"

export const HorizontalList = ({items, renderItem}: HorizontalListProps) => {
export const HorizontalList = ({items, renderItem, onEndReached}: HorizontalListProps) => {
return (
<ScrollView nestedScrollEnabled>
<View>
Expand All @@ -16,6 +16,8 @@ export const HorizontalList = ({items, renderItem}: HorizontalListProps) => {
renderItem={renderItem}
initialNumToRender={4}
keyExtractor={item => item.id}
onEndReached={onEndReached}
onEndReachedThreshold={0}
/>
</View>
</ScrollView>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface HorizontalListProps {
items: any
renderItem: (item: any) => JSX.Element
onEndReached: () => void
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {PriceIndicatorProps} from "./interfaces"
export const PriceIndicator = ({currentPrice, minimumPrice, maximumPrice}: PriceIndicatorProps) => {
const [containerWidth, setContainerWidth] = useState(100)

const progress = (currentPrice - minimumPrice) / (maximumPrice - minimumPrice)
const progress = currentPrice === minimumPrice ? 1 : (currentPrice - minimumPrice) / (maximumPrice - minimumPrice)

const getContainerWidth = (event: LayoutChangeEvent) => {
setContainerWidth(event.nativeEvent.layout.width)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import {Restaurant} from "../../api/interfaces"

export interface RestaurantsListProps extends NavigationComponentProps {
restaurants: Restaurant[]
onEndReached: () => void
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {navigateToRestaurantInfo} from "../../services/navigation"
import {RestaurantItem} from "../restaurant-item/"
import {RestaurantsListProps} from "./interfaces"

export const RestaurantsList = ({componentId, restaurants}: RestaurantsListProps) => {
export const RestaurantsList = ({componentId, restaurants, onEndReached}: RestaurantsListProps) => {
const renderItem = ({item}: ListRenderItemInfo<Restaurant>) => {
return (
<RestaurantItem
Expand All @@ -16,6 +16,13 @@ export const RestaurantsList = ({componentId, restaurants}: RestaurantsListProps
}

return (
<FlatList style={{marginBottom: 8}} renderItem={renderItem} data={restaurants} keyExtractor={item => item.id} />
<FlatList
style={{marginBottom: 8}}
renderItem={renderItem}
data={restaurants}
keyExtractor={item => item.id}
onEndReachedThreshold={0}
onEndReached={onEndReached}
/>
)
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,43 @@
import React, {useEffect, useState} from "react"
import {ListRenderItemInfo} from "react-native"
import {Image, Text, TouchableOpacity, View} from "react-native-ui-lib"
import {Text, View} from "react-native-ui-lib"
import {getAllFood} from "../../../api/food"
import {Food, FoodSortType} from "../../../api/interfaces"
import {navigateToFoodInfo} from "../../../services/navigation"
import {formatPrice} from "../../../utils/currency"
import {HorizontalList} from "../../horizontal-list"
import {HorizontalListItem} from "../horizontal-list-item"
import {CheapestFoodProps} from "./interfaces"

export const CheapestFood = ({componentId}: CheapestFoodProps) => {
const [food, setFood] = useState([] as Food[])
const [pageNumber, setPageNumber] = useState(1)

const fetchFood = async () => {
setFood(await getAllFood({sortType: FoodSortType.PRICE}))
setFood(await getAllFood({sortObject: {sortType: FoodSortType.PRICE}}))
}

const renderItem = ({item}: ListRenderItemInfo<Food>) => (
<TouchableOpacity margin-s1 centerH onPress={() => navigateToFoodInfo(componentId, {food: item, componentId})}>
<Image
source={{
uri: item.imageURL,
width: 100,
height: 100
}}
style={{width: 100, height: 100}}
/>
<Text marginT-s1>{item.name}</Text>
<View br20 bg-purple30 padding-s1 marginT-s1>
<Text white text90M>
{formatPrice(item.currentPrice)}
</Text>
</View>
</TouchableOpacity>
<HorizontalListItem
name={item.name}
imageURL={item.imageURL}
tag={formatPrice(item.currentPrice)}
onPress={() => navigateToFoodInfo(componentId, {componentId, food: item})}
/>
)

const onEndReached = async () => {
const newFood = await getAllFood({
sortObject: {sortType: FoodSortType.PRICE},
pagination: {pageNumber: pageNumber + 1, pageSize: 10}
})

if (newFood.length) {
setFood(food.concat(newFood))
setPageNumber(pageNumber + 1)
}
}

useEffect(() => {
fetchFood()
}, [])
Expand All @@ -43,7 +47,7 @@ export const CheapestFood = ({componentId}: CheapestFoodProps) => {
<Text text50L marginB-s2>
💵 Cheapest food
</Text>
<HorizontalList items={food} renderItem={renderItem} />
<HorizontalList items={food} renderItem={renderItem} onEndReached={onEndReached} />
</View>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react"
import {Image, Text, TouchableOpacity, View} from "react-native-ui-lib"
import {HorizontalListItemProps} from "./interfaces"

export const HorizontalListItem = ({name, imageURL, tag, onPress}: HorizontalListItemProps) => {
return (
<TouchableOpacity margin-s1 centerH onPress={onPress}>
<Image
source={{
uri: imageURL,
width: 100,
height: 100
}}
style={{width: 100, height: 100}}
/>
<Text marginT-s1 center style={{width: 100}}>
{name}
</Text>
{tag && (
<View br20 bg-purple30 padding-s1 paddingH-s2 marginT-s1>
<Text white text90M>
{tag}
</Text>
</View>
)}
</TouchableOpacity>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {HorizontalListItem} from "./horizontal-list-item"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface HorizontalListItemProps {
imageURL: string
name: string
tag?: string
onPress: () => void
}
Loading

0 comments on commit 63873b1

Please sign in to comment.