Skip to content

Commit

Permalink
Mise en place de l'API localisation
Browse files Browse the repository at this point in the history
- Repris de #482
  • Loading branch information
Clemog committed Sep 7, 2022
1 parent a5d9ea2 commit 1c49010
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 41 deletions.
7 changes: 7 additions & 0 deletions source/actions/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,10 @@ export const setStoredTrajets = (vehicule: string, trajets: object) =>
vehicule,
trajets,
} as const)

export const setLocalisation = (localisationData: Object) =>
({
type: 'SET_LOCALISATION',
localisationData,
} as const)

15 changes: 12 additions & 3 deletions source/components/useBranchData.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { useEffect } from 'react'
import { usePersistingState } from './utils/persistState'
import useLocalisation, {
correspondancePullRequests,
} from 'Components/useLocalisation'

export default () => {
const urlParams = new URLSearchParams(window.location.search)
/* This enables loading the rules of a branch,
* to showcase the app as it would be once this branch of -data has been merged*/
const branch = urlParams.get('branch')
const localisation = useLocalisation()

const [pullRequestNumber, setPullRequestNumber] = usePersistingState(
'PR',
Expand All @@ -14,17 +18,22 @@ export default () => {

const searchPR = urlParams.get('PR')

const localisationPR =
correspondancePullRequests[localisation?.country_name.toLowerCase()]

useEffect(() => {
// if pullRequestNumber is undefined, then this hook hasn't been triggered yet
if (searchPR != null) {
if (localisationPR != null) {
setPullRequestNumber(localisationPR)
} else if (searchPR != null) {
// setting should be triggered by an explicit ?PR=, not the absence of it when navigating
setPullRequestNumber(searchPR)
} else {
if (!pullRequestNumber)
if (!pullRequestNumber || !localisationPR)
// No PR should be loaded, we know that now
setPullRequestNumber(null)
}
}, [searchPR, pullRequestNumber])
}, [searchPR, localisationPR, pullRequestNumber])

const deployURL = `https://${
branch
Expand Down
52 changes: 52 additions & 0 deletions source/components/useLocalisation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { setLocalisation } from '../actions/actions'

export const sampleIps = {
guadeloupe: '104.250.27.0',
france: '92.184.106.103',
'polynésie française': '203.185.161.106',
}

export const correspondancePullRequests = {
guadeloupe: '1339',
'french polynesia': '1339',
}

const API =
'https://api.ipgeolocation.io/ipgeo?apiKey=a6346b522995413a8f4578e025a3eae6'

// Other alternatives :
// https://positionstack.com/product
// https://www.abstractapi.com/ip-geolocation-api?fpr=geekflare#pricing

export default (ip) => {
const dispatch = useDispatch()

const localisation = useSelector((state) => state.localisation)

useEffect(() => {
if (localisation != null && localisation.ip == ip) return null

fetch(API + (ip == null ? '' : `&ip=${ip}`))
.catch((e) => {
console.log('erreur', e)
})
.then((res) => res && res.json())
.then((data) => {
dispatch(
setLocalisation({
...data,
ip,
country_flag:
//https://fr.wikipedia.org/wiki/Drapeau_de_la_Guadeloupe
data.country_name.toLowerCase() === 'guadeloupe'
? 'https://openmoji.org/data/color/svg/1F1EC-1F1F5.svg'
: data.country_flag,
})
)
})
}, [ip])

return localisation
}
7 changes: 7 additions & 0 deletions source/reducers/rootReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,12 @@ function thenRedirectTo(state = null, { type, to }) {

const defaultToNull = (arg) => arg ?? null

function localisation(state = null, { type, localisationData }) {
if (type === 'SET_LOCALISATION') {
return localisationData
} else return state
}

const mainReducer = (state: any, action: Action) =>
combineReducers({
explainedVariable,
Expand All @@ -253,6 +259,7 @@ const mainReducer = (state: any, action: Action) =>
storedTrajets,
thenRedirectTo,
tracking,
localisation,
})(state, action)

export default reduceReducers<RootState>(
Expand Down
42 changes: 42 additions & 0 deletions source/sites/publicodes/Localisation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useState } from 'react'
import useLocalisation, { sampleIps } from '../../components/useLocalisation'
import emoji from 'react-easy-emoji'
import { capitalise0 } from '../../utils'

export default () => {
const [chosenIp, chooseIp] = useState()
const localisation = useLocalisation(chosenIp)

return (
<div>
<h2>{emoji('📍')} Pays de simulation</h2>
{localisation != null ? (
<p>
Nous avons détecté que vous faites cette simulation depuis la{' '}
<img
src={localisation.country_flag}
aria-hidden="true"
css={`
height: 1rem;
margin: 0 0.3rem;
vertical-align: middle;
`}
/>
{localisation.country_name}.
</p>
) : (
<p>Nous n'avons pas pu détecter votre pays de simulation. </p>
)}
<details>
<summary>Choisir un autre pays</summary>
<ul>
{Object.entries(sampleIps).map(([country, ip]) => (
<li key={country} onClick={() => chooseIp(ip)}>
<button>{capitalise0(country)}</button>
</li>
))}
</ul>
</details>
</div>
)
}
91 changes: 53 additions & 38 deletions source/sites/publicodes/Profil.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ScrollToTop } from '../../components/utils/Scroll'
import { answeredQuestionsSelector } from '../../selectors/simulationSelectors'
import { skipTutorial } from '../../actions/actions'
import { useNavigate } from 'react-router-dom'
import Localisation from './Localisation'

export const useProfileData = () => {
const answeredQuestionsLength = useSelector(answeredQuestionsSelector).length
Expand Down Expand Up @@ -54,52 +55,66 @@ export default ({}) => {
</p>
)}
{hasData ? (
<div>
{tutorials.testIntro && (
<div>
<button
className="ui__ dashed-button"
onClick={() => {
dispatch(skipTutorial('testIntro', true))
navigate('/tutoriel')
}}
>
{emoji('🧑‍🏫')} Revoir le tutoriel
</button>
</div>
)}
{answeredQuestionsLength > 0 && (
<p>
Vous avez répondu à {answeredQuestionsLength} questions et
choisi {actionChoicesLength} actions.{' '}
</p>
)}
<details>
<summary>Où sont mes données ? </summary>
Vos données sont stockées dans votre navigateur, vous avez donc le
contrôle total sur elles. <br />
<Link to="/vie-privée">En savoir plus</Link>
</details>
<button
className="ui__ button plain"
css="margin: 1rem 0"
onClick={() => {
dispatch(resetSimulation())
dispatch(resetActionChoices())
dispatch(deletePreviousSimulation())
dispatch(resetTutorials())
dispatch(resetStoredTrajets())
}}
<div
css={`
display: flex;
align-items: center;
flex-wrap: wrap;
`}
>
<div
className="ui__ card content"
css="width: 20rem; margin-right: 2rem"
>
{emoji('♻️ ')} Recommencer
</button>
{answeredQuestionsLength > 0 && (
<p>
Vous avez répondu à {answeredQuestionsLength} questions et
choisi {actionChoicesLength} actions.{' '}
</p>
)}
<details>
<summary>Où sont mes données ? </summary>
Vos données sont stockées dans votre navigateur, vous avez donc
le contrôle total sur elles. <br />
<Link to="/vie-privée">En savoir plus</Link>
</details>
</div>
<div>
<button
className="ui__ button plain"
css="margin: 1rem 0"
onClick={() => {
dispatch(resetSimulation())
dispatch(resetActionChoices())
dispatch(deletePreviousSimulation())
dispatch(resetTutorials())
dispatch(resetStoredTrajets())
}}
>
{emoji('♻️ ')} Recommencer
</button>
{tutorials.testIntro && (
<div>
<button
className="ui__ dashed-button"
onClick={() => {
dispatch(skipTutorial('testIntro', true))
navigate('/tutoriel')
}}
>
{emoji('🧑‍🏫')} Revoir le tutoriel
</button>
</div>
)}
</div>
</div>
) : (
<IllustratedMessage
emoji="🕳️"
message={<p>Vous n'avez pas encore fait le test.</p>}
></IllustratedMessage>
)}
<Localisation />
<AnswerList />
</div>
</div>
Expand Down

0 comments on commit 1c49010

Please sign in to comment.