diff --git a/.env.sample b/.env.sample
index 4b711a3..8254d22 100644
--- a/.env.sample
+++ b/.env.sample
@@ -1,3 +1,3 @@
-HOST=https://gas-price-france-yaws.vercel.app/
+HOST=https://gas-price-france-yaws.vercel.app
JAWG_API_KEY=
MAPBOX_API_KEY=
\ No newline at end of file
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 2b04912..cc367dd 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -90,4 +90,7 @@ jobs:
body: |
Release version ${{steps.version.outputs.prop}}
Fetures:
- - Alert users that an update is available
+ - Itinerary from users position
+ - User shown on the map
+ Fix:
+ - Itinerary infite loading
diff --git a/README.md b/README.md
index 6623cf7..8dab770 100644
--- a/README.md
+++ b/README.md
@@ -37,10 +37,11 @@ In order to use Gas Prices, you must have Android studio on your computer ([Inst
```.env
HOST=https://gas-price-france-yaws.vercel.app/
```
+
OR
- You can use it on local, follow [GasPrices-Api](https://github.com/titi0267/GasPrices-Api) guidelines
-
+
```.env
HOST=http://localhost:8080
```
@@ -57,13 +58,13 @@ In order to use Gas Prices, you must have Android studio on your computer ([Inst
MAPBOX_API_KEY=
```
-4. Install the dependencies with npm
+3. Install the dependencies with npm
```bash
npm i
```
-5. Extra steps for a physical device:
+4. Extra steps for a physical device:
- Connect your device to your computer
- Make sure to enable developer mode
- Make sure to enable file transfert
@@ -75,13 +76,13 @@ Launch the project with
## Overview
-Navigate on the map | Search for your itinerary & your fuel | Display the gas stations along your itinerary
- --- | --- | ---
- | |
+| Navigate on the map | Search for your itinerary & your fuel | Display the gas stations along your itinerary |
+| --------------------------------------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------- |
+| | | |
-Click on one of the gas station | Check the lowest price | Redirect to maps and start driving
---- | --- | ---
- | |
+| Click on one of the gas station | Check the lowest price | Redirect to maps and start driving |
+| -------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
+| | | |
## About
diff --git a/android/app/build.gradle b/android/app/build.gradle
index f4e5eb2..f12c1ed 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,5 +1,6 @@
apply plugin: "com.android.application"
apply plugin: "com.facebook.react"
+apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
import com.android.build.OutputFile
import groovy.json.JsonSlurper
diff --git a/package-lock.json b/package-lock.json
index 05c81a8..f1e5439 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "gas-prices",
- "version": "0.0.2",
+ "version": "0.0.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gas-prices",
- "version": "0.0.2",
+ "version": "0.0.3",
"dependencies": {
"@react-native-async-storage/async-storage": "^1.21.0",
"@react-native-community/geolocation": "^3.1.0",
@@ -16,10 +16,12 @@
"@react-navigation/native-stack": "^6.9.17",
"@rneui/themed": "^4.0.0-rc.7",
"@rnmapbox/maps": "^10.0.5-rc.1",
+ "@turf/circle": "^6.5.0",
"i": "^0.3.7",
"npm": "^10.4.0",
"react": "18.2.0",
"react-native": "0.71.7",
+ "react-native-config": "^1.5.1",
"react-native-dotenv": "^3.4.8",
"react-native-elements": "^3.4.3",
"react-native-linear-gradient": "^2.8.3",
@@ -5114,6 +5116,18 @@
"url": "https://opencollective.com/turf"
}
},
+ "node_modules/@turf/circle": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-6.5.0.tgz",
+ "integrity": "sha512-oU1+Kq9DgRnoSbWFHKnnUdTmtcRUMmHoV9DjTXu9vOLNV5OWtAAh1VZ+mzsioGGzoDNT/V5igbFOkMfBQc0B6A==",
+ "dependencies": {
+ "@turf/destination": "^6.5.0",
+ "@turf/helpers": "^6.5.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/turf"
+ }
+ },
"node_modules/@turf/destination": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@turf/destination/-/destination-6.5.0.tgz",
@@ -16646,6 +16660,19 @@
"nullthrows": "^1.1.1"
}
},
+ "node_modules/react-native-config": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/react-native-config/-/react-native-config-1.5.1.tgz",
+ "integrity": "sha512-g1xNgt1tV95FCX+iWz6YJonxXkQX0GdD3fB8xQtR1GUBEqweB9zMROW77gi2TygmYmUkBI7LU4pES+zcTyK4HA==",
+ "peerDependencies": {
+ "react-native-windows": ">=0.61"
+ },
+ "peerDependenciesMeta": {
+ "react-native-windows": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-native-dotenv": {
"version": "3.4.8",
"resolved": "https://registry.npmjs.org/react-native-dotenv/-/react-native-dotenv-3.4.8.tgz",
diff --git a/package.json b/package.json
index 9b8a1cb..d7bb780 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "gas-prices",
- "version": "0.0.3",
- "versionCode": 9,
+ "version": "0.0.4",
+ "versionCode": 10,
"private": true,
"scripts": {
"android": "react-native run-android --variant=debug",
@@ -19,10 +19,12 @@
"@react-navigation/native-stack": "^6.9.17",
"@rneui/themed": "^4.0.0-rc.7",
"@rnmapbox/maps": "^10.0.5-rc.1",
+ "@turf/circle": "^6.5.0",
"i": "^0.3.7",
"npm": "^10.4.0",
"react": "18.2.0",
"react-native": "0.71.7",
+ "react-native-config": "^1.5.1",
"react-native-dotenv": "^3.4.8",
"react-native-elements": "^3.4.3",
"react-native-linear-gradient": "^2.8.3",
diff --git a/src/Components/Input/index.tsx b/src/Components/Input/index.tsx
index 1bcacbb..4cbaa8c 100644
--- a/src/Components/Input/index.tsx
+++ b/src/Components/Input/index.tsx
@@ -11,8 +11,10 @@ const CustomInput = (props: {
onChangeText: (value: string) => void;
placeholder: string;
inputValue?: string;
+ setIsFocused: (value: boolean) => void;
}) => {
- const {onClearInput, onChangeText, placeholder, inputValue} = props;
+ const {onClearInput, onChangeText, placeholder, inputValue, setIsFocused} =
+ props;
return (
{
+ setIsFocused(false);
+ }}
+ onFocus={() => {
+ setIsFocused(true);
+ }}
style={[inputStyles.placeholder, inputStyles.input]}
placeholder={placeholder}
value={inputValue}
diff --git a/src/Pages/Map/index.tsx b/src/Pages/Map/index.tsx
index d8e3b20..bcf763f 100644
--- a/src/Pages/Map/index.tsx
+++ b/src/Pages/Map/index.tsx
@@ -6,7 +6,6 @@ import {
TouchableOpacity,
View,
} from 'react-native';
-import {JAWG_API_KEY, MAPBOX_API_KEY} from '@env';
import {useEffect, useRef, useState} from 'react';
import {useIsFocused, useRoute} from '@react-navigation/native';
import getLocation from '../../services/getCurrentLocation';
@@ -18,8 +17,10 @@ import departmentCodeService from '../../services/departmentCode.service';
import gasStationsService from '../../services/gasStations.service';
import asyncStorageService from '../../services/asyncStorage.service';
import CustomCard from '../../Components/Card';
+import circle from '@turf/circle';
+import Config from 'react-native-config';
-Mapbox.setAccessToken(MAPBOX_API_KEY);
+Mapbox.setAccessToken(Config.MAPBOX_API_KEY as string);
const Map = () => {
const route = useRoute();
@@ -39,6 +40,7 @@ const Map = () => {
const [refinedStations, setRefinedStations] = useState(
null,
);
+ const [radius, setRadius] = useState(Math.pow(2, zoomLevel) * 100);
const [isLoading, setIsLoading] = useState(true);
const [departmentCodes, setDepartmentCodes] = useState([]);
const [gasType, setGasType] = useState();
@@ -76,6 +78,7 @@ const Map = () => {
end: end,
},
setGeoJson,
+ setIsLoading,
);
} else {
setIsLoading(false);
@@ -101,7 +104,12 @@ const Map = () => {
}, [geoJson]);
useEffect(() => {
+ const interval = setInterval(() => {
+ getLocation(setLocationCallback, 'object');
+ }, 20000);
getLocation(setLocationCallback, 'object');
+
+ return () => clearInterval(interval);
}, []);
useEffect(() => {
@@ -152,6 +160,14 @@ const Map = () => {
}
}, [gasStations, gasType]);
+ const layerStyles = {
+ route: {
+ lineColor: '#00F5FD',
+ lineWidth: 1.5,
+ lineDasharray: [1, 0],
+ },
+ };
+
useEffect(() => {
if (refinedStations) {
asyncStorageService.storeData('gasPumps', refinedStations as any[]);
@@ -162,6 +178,15 @@ const Map = () => {
}
}, [refinedStations, end, start]);
+ const handleRegionDidChange = async () => {
+ if (mapRef.current) {
+ const zoomLevel = await mapRef.current.getZoom();
+ console.log('Zoom level:', zoomLevel);
+ const radius = Math.pow(2, -zoomLevel) * 1000;
+ setRadius(radius > 0.5 ? 0.5 : radius);
+ }
+ };
+
return (
{
ref={mapRef}
logoEnabled={false}
attributionEnabled={false}
- styleURL={`https://tile.jawg.io/jawg-streets.json?access-token=${JAWG_API_KEY}`}>
+ onRegionIsChanging={handleRegionDidChange}
+ styleURL={`https://tile.jawg.io/jawg-streets.json?access-token=${Config.JAWG_API_KEY}`}>
{isLoading == false || (!end && !start) ? (
{
) : (
<>>
)}
+ {location ? (
+
+
+
+
+ ) : (
+ <>>
+ )}
{geoJson && (
{
const navigation = useNavigation>();
- const [cityNamesStart, setCityNamesStart] = useState([]);
+ const [cityNamesStart, setCityNamesStart] = useState([
+ 'Votre position',
+ ]);
const [cityCoordsStart, setCityCoordsStart] = useState(
null,
);
const [inputValueStart, setInputValueStart] = useState('');
- const [cityNamesEnd, setCityNamesEnd] = useState([]);
+ const [cityNamesEnd, setCityNamesEnd] = useState([
+ 'Votre position',
+ ]);
const [cityCoordsEnd, setCityCoordsEnd] = useState(null);
const [inputValueEnd, setInputValueEnd] = useState('');
@@ -43,11 +47,20 @@ const Search = () => {
const [isFetchStart, setIsFetchStart] = useState(false);
const [isFetchEnd, setIsFetchEnd] = useState(false);
const [selectedFuel, setSelectedFuel] = useState(null);
+ const [startIsFocused, setStartIsFocused] = useState(false);
+ const [endIsFocused, setEndIsFocused] = useState(false);
const setLocationCallback = (value: LocationType | string) => {
setLocation(value as string);
};
+ const setStartIsFocusedCallback = (value: boolean) => {
+ setStartIsFocused(value);
+ };
+ const setEndIsFocusedCallback = (value: boolean) => {
+ setEndIsFocused(value);
+ };
+
useEffect(() => {
getLocation(setLocationCallback, 'string');
}, []);
@@ -102,6 +115,9 @@ const Search = () => {
setIsFetchStartCallback,
);
}
+ if (inputValueStart.length == 0) {
+ setIsFetchStart(false);
+ }
}, 400);
return () => clearTimeout(debounceTimer);
}, [inputValueStart, isStartCitySelected]);
@@ -118,6 +134,9 @@ const Search = () => {
cityNamesEndCallback,
setIsFetchEndCallback,
);
+ if (inputValueEnd.length == 0) {
+ setIsFetchEnd(false);
+ }
}, 400);
return () => clearTimeout(debounceTimer);
}, [inputValueEnd, isEndCitySelected]);
@@ -131,7 +150,14 @@ const Search = () => {
setIsStartCitySelected(true);
setInputValueStart(item);
setCityNamesStart([]);
- fetchCityPosition({adress: item}, setCityCoordsStartCallback);
+ if (item == 'Votre position') {
+ let values: string[] = location.split(',');
+
+ let invertedValues: string = values.reverse().join(',');
+ setCityCoordsStart({label: 'Votre position', geometry: invertedValues});
+ } else {
+ fetchCityPosition({adress: item}, setCityCoordsStartCallback);
+ }
};
const onPressItemEnd = (item: string) => {
@@ -139,20 +165,30 @@ const Search = () => {
setIsEndCitySelected(true);
setInputValueEnd(item);
setCityNamesEnd([]);
- fetchCityPosition({adress: item}, setCityCoordsEndCallback);
+ if (item == 'Votre position') {
+ let values: string[] = location.split(',');
+
+ let invertedValues: string = values.reverse().join(',');
+ setCityCoordsEnd({label: 'Votre position', geometry: invertedValues});
+ } else {
+ fetchCityPosition({adress: item}, setCityCoordsEndCallback);
+ }
};
const onClearInputStart = () => {
setIsStartCitySelected(false);
setInputValueStart('');
- setCityNamesStart([]);
+ Keyboard.dismiss();
+ setStartIsFocused(false);
+ setCityNamesStart(['Votre position']);
setCityCoordsStart(null);
};
const onClearInputEnd = () => {
setIsEndCitySelected(false);
+ Keyboard.dismiss();
setInputValueEnd('');
- setCityNamesEnd([]);
+ setCityNamesEnd(['Votre position']);
setCityCoordsEnd(null);
};
@@ -268,6 +304,7 @@ const Search = () => {
onChangeText={onChangeTextStart}
onClearInput={onClearInputStart}
placeholder="Depart"
+ setIsFocused={setStartIsFocusedCallback}
inputValue={inputValueStart}>
{
onChangeText={onChangeTextEnd}
onClearInput={onClearInputEnd}
placeholder="Arrivee"
+ setIsFocused={setEndIsFocusedCallback}
inputValue={inputValueEnd}>
- {cityNamesStart.length != 0 ? (
+ {cityNamesStart.length != 0 && startIsFocused ? (
{
) : (
<>>
)}
- {cityNamesEnd.length != 0 ? (
+ {cityNamesEnd.length != 0 && endIsFocused ? (
void,
) => {
setLoading(true);
- const res = await fetch(`${HOST}/cityName`, {
+ const res = await fetch(`${Config.HOST}/cityName`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -31,7 +31,7 @@ const fetchCityPosition = async (
body: {adress: string},
setPosition: (value: {label: string; geometry: string}) => void,
) => {
- const res = await fetch(`${HOST}/cityData`, {
+ const res = await fetch(`${Config.HOST}/cityData`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
diff --git a/src/services/departmentCode.service.ts b/src/services/departmentCode.service.ts
index 809c5d4..e7420b5 100644
--- a/src/services/departmentCode.service.ts
+++ b/src/services/departmentCode.service.ts
@@ -1,9 +1,9 @@
-import {HOST} from '@env';
+import Config from 'react-native-config';
const fetchDepartmentCode = async (body: {
coords: number[];
}): Promise => {
- const res = await fetch(`${HOST}/geoCode`, {
+ const res = await fetch(`${Config.HOST}/geoCode`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
diff --git a/src/services/gasStations.service.ts b/src/services/gasStations.service.ts
index 27cc71b..fe5bdde 100644
--- a/src/services/gasStations.service.ts
+++ b/src/services/gasStations.service.ts
@@ -1,7 +1,7 @@
-import {HOST} from '@env';
+import Config from 'react-native-config';
const fetchGasStationList = async (body: {code_department: string}) => {
- const res = await fetch(`${HOST}/gasStations`, {
+ const res = await fetch(`${Config.HOST}/gasStations`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
diff --git a/src/services/geoJson.service.ts b/src/services/geoJson.service.ts
index 654d84a..17c212c 100644
--- a/src/services/geoJson.service.ts
+++ b/src/services/geoJson.service.ts
@@ -1,4 +1,4 @@
-import {HOST} from '@env';
+import Config from 'react-native-config';
const fetchGeoJsonResults = async (
body: {
@@ -6,17 +6,23 @@ const fetchGeoJsonResults = async (
end: string;
},
setData: (value: any) => void,
+ setIsLoading: (value: boolean) => void,
) => {
- const res = await fetch(`${HOST}/geoJson`, {
+ console.log(body);
+ const res = await fetch(`${Config.HOST}/geoJson`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
- if (!res.ok) throw Error('Error on osrm services');
- const resolve = await res.json();
- setData(resolve[0]);
+ try {
+ if (!res.ok) throw Error('Error on osrm services');
+ const resolve = await res.json();
+ setData(resolve[0]);
+ } catch (e) {
+ setIsLoading(false);
+ }
};
export default fetchGeoJsonResults;
diff --git a/src/services/updateApp.service.ts b/src/services/updateApp.service.ts
index fafd493..672c938 100644
--- a/src/services/updateApp.service.ts
+++ b/src/services/updateApp.service.ts
@@ -1,16 +1,16 @@
-import {HOST} from '@env';
+import Config from 'react-native-config';
const updateApp = async (setVersion: (value: any) => void) => {
const pj = require('../../package.json');
const body = {version: pj.version};
- const res = await fetch(`${HOST}/update`, {
+ const res = await fetch(`${Config.HOST}/update`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
- if (!res.ok) throw Error('Error on osrm services');
+ if (!res.ok) throw Error('Error on version check');
const resolve = await res.json();
setVersion(resolve);
};