From 31316c54d60b7fb3503a39474d4251730a41e754 Mon Sep 17 00:00:00 2001 From: cristianbgp Date: Mon, 15 Jul 2019 16:44:25 -0500 Subject: [PATCH 1/5] Add service geocode --- client/.env.example | 1 + client/src/services/geocode.js | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 client/src/services/geocode.js diff --git a/client/.env.example b/client/.env.example index 45a40a2..8a456c0 100644 --- a/client/.env.example +++ b/client/.env.example @@ -1,3 +1,4 @@ REACT_APP_VERSION=$npm_package_version REACT_APP_API_URL=http://localhost:4000/api REACT_APP_API_URL_PRODUCTION= +REACT_APP_OPEN_CAGE_DATA_KEY= diff --git a/client/src/services/geocode.js b/client/src/services/geocode.js new file mode 100644 index 0000000..94fdd13 --- /dev/null +++ b/client/src/services/geocode.js @@ -0,0 +1,21 @@ +async function getCoords(place) { + let apikey = process.env.REACT_APP_OPEN_CAGE_DATA_KEY; + let api_url = "https://api.opencagedata.com/geocode/v1/json"; + let request_url = + api_url + + "?" + + "q=" + + encodeURIComponent(place) + + "&key=" + + apikey + + "&language=es" + + "&pretty=1" + + "&countrycode=pe" + + "&no_annotations=1"; + const response = await fetch(request_url); + + if (!response.ok) throw new Error(response.statusText); + return response.json(); +} + +export { getCoords }; From 82f798a55f228482a1e015f083857aaa0dca44ed Mon Sep 17 00:00:00 2001 From: cristianbgp Date: Mon, 15 Jul 2019 18:52:53 -0500 Subject: [PATCH 2/5] Update club with district, latitude and longitude --- api/app/controllers/clubs_controller.rb | 2 +- api/app/serializers/club_serializer.rb | 2 +- .../20190715215722_add_district_to_clubs.rb | 7 ++++++ api/db/schema.rb | 5 +++- api/db/seeds.rb | 6 ++--- client/src/views/create-club.js | 25 +++++++++++++++++-- 6 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 api/db/migrate/20190715215722_add_district_to_clubs.rb diff --git a/api/app/controllers/clubs_controller.rb b/api/app/controllers/clubs_controller.rb index f9d5305..dd7828c 100644 --- a/api/app/controllers/clubs_controller.rb +++ b/api/app/controllers/clubs_controller.rb @@ -28,7 +28,7 @@ def set_club end def club_params - params.permit(:name, :address, :schedule, :image) + params.permit(:name, :address, :schedule, :image, :district, :latitude, :longitude) end end diff --git a/api/app/serializers/club_serializer.rb b/api/app/serializers/club_serializer.rb index 27591cd..6355f8b 100644 --- a/api/app/serializers/club_serializer.rb +++ b/api/app/serializers/club_serializer.rb @@ -1,7 +1,7 @@ class ClubSerializer < ActiveModel::Serializer include Rails.application.routes.url_helpers - attributes :id, :name, :address, :image, :schedule, :favorited, :favorited_count + attributes :id, :name, :address, :image, :schedule, :favorited, :favorited_count, :district, :latitude, :longitude def image # rails_blob_path(object.image, only_path: true) if object.image.attached? diff --git a/api/db/migrate/20190715215722_add_district_to_clubs.rb b/api/db/migrate/20190715215722_add_district_to_clubs.rb new file mode 100644 index 0000000..5c232a5 --- /dev/null +++ b/api/db/migrate/20190715215722_add_district_to_clubs.rb @@ -0,0 +1,7 @@ +class AddDistrictToClubs < ActiveRecord::Migration[5.2] + def change + add_column :clubs, :district, :string + add_column :clubs, :latitude, :string + add_column :clubs, :longitude, :string + end +end diff --git a/api/db/schema.rb b/api/db/schema.rb index 34e40c0..f52b1ec 100644 --- a/api/db/schema.rb +++ b/api/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_07_15_153026) do +ActiveRecord::Schema.define(version: 2019_07_15_215722) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -42,6 +42,9 @@ t.json "schedule" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "district" + t.string "latitude" + t.string "longitude" end create_table "favorites", force: :cascade do |t| diff --git a/api/db/seeds.rb b/api/db/seeds.rb index 35c8a46..46400ec 100644 --- a/api/db/seeds.rb +++ b/api/db/seeds.rb @@ -3,7 +3,7 @@ regular_user = User.create(name: 'Lian Nivin', email: 'liam@kampu.pe', role: "regular", password: '123456') owner_user = User.create(name: 'Cristian Berly', email: 'berli@kampu.pe', role: "owner", password: '123456') -Club.create([{name: "Club #1", address: 'Jr cayumba 440', +clubs = Club.create([{name: "Club #1", address: 'Jr cayumba 440', district: "Lince", latitude: -12.1199378, longitude: -77.0373161, schedule: { 'monday-friday': { start: '8', @@ -17,7 +17,7 @@ start: '8', end: '22' }, -}}, {name: "Club #2", address: 'Jr cayumba 440', +}}, {name: "Club #2", address: 'Av. Jorge Chavez 184', district: "Miraflores", latitude: -13.1199378, longitude: -77.0353161, schedule: { 'monday-friday': { start: '8', @@ -31,7 +31,7 @@ start: '8', end: '22' }, -}}, {name: "Club #3", address: 'Jr cayumba 440', +}}, {name: "Club #3", address: 'Jr General Artigas 440', district: "Pueblo Libre", latitude: -14.1199378, longitude: -77.0373261, schedule: { 'monday-friday': { start: '8', diff --git a/client/src/views/create-club.js b/client/src/views/create-club.js index 95dd474..4991c88 100644 --- a/client/src/views/create-club.js +++ b/client/src/views/create-club.js @@ -4,11 +4,13 @@ import { jsx } from "@emotion/core"; import { navigate } from "@reach/router"; import { Input, Label, Card, Button } from "../components/ui"; import { postClub } from "../services/club"; +import { getCoords } from "../services/geocode"; function CreateClub() { const [fields, setFields] = React.useState({ name: "", address: "", + district: "", image: null, schedule: JSON.stringify({ "monday-friday": { @@ -41,10 +43,15 @@ function CreateClub() { Object.keys(fields).forEach(key => { formData.append(key, fields[key]); }); + const { results } = await getCoords( + `${fields.address}, ${fields.district}` + ); + formData.append("latitude", results[0].geometry.lat); + formData.append("longitude", results[0].geometry.lng); + try { - const club = await postClub(formData); + await postClub(formData); navigate("/owner"); - console.log(club); } catch (error) { console.log(error.message); } @@ -86,6 +93,20 @@ function CreateClub() { onChange={handleChange} /> +
+ + +
Date: Tue, 16 Jul 2019 15:49:33 -0500 Subject: [PATCH 3/5] Sort clubs by location --- client/package.json | 1 + client/src/components/club-card.js | 22 ++++++ client/src/components/club.js | 3 + client/src/views/home.js | 118 ++++++++++++++++++++++++++--- client/yarn.lock | 5 ++ 5 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 client/src/components/club-card.js diff --git a/client/package.json b/client/package.json index 30d020a..8567028 100644 --- a/client/package.json +++ b/client/package.json @@ -6,6 +6,7 @@ "@emotion/core": "^10.0.10", "@reach/router": "^1.2.1", "@testing-library/react": "^8.0.1", + "geolib": "^3.0.4", "jest-emotion": "^10.0.11", "jest-fetch-mock": "^2.1.2", "leaflet": "^1.5.1", diff --git a/client/src/components/club-card.js b/client/src/components/club-card.js new file mode 100644 index 0000000..e877c86 --- /dev/null +++ b/client/src/components/club-card.js @@ -0,0 +1,22 @@ +/** @jsx jsx */ +import React from "react"; +import { jsx } from "@emotion/core"; +import { Card, Title } from "../components/ui"; + +function ClubCard({ club }) { + const styleCard = { + maxWidth: "100%", + marginBottom: "1.5em" + }; + + return ( + + {club.name} +

{JSON.stringify(club)}

+

{club.position}

+

{club.distance !== 0 ? `${club.distance / 1000.0}km` : null}

+
+ ); +} + +export default ClubCard; diff --git a/client/src/components/club.js b/client/src/components/club.js index c7fc41b..7fdcb45 100644 --- a/client/src/components/club.js +++ b/client/src/components/club.js @@ -69,6 +69,9 @@ function Club({ club }) { > {club.favorited_count > 0 && club.favorited_count} + + {club.distance !== 0 ? `${club.distance / 1000.0}km` : null} +
diff --git a/client/src/views/home.js b/client/src/views/home.js index f364f05..220148d 100644 --- a/client/src/views/home.js +++ b/client/src/views/home.js @@ -1,31 +1,127 @@ /** @jsx jsx */ import React from "react"; import { jsx } from "@emotion/core"; -import { getClubs } from "../services/club"; -import { useClubs } from "../selectors/selectors"; import { useSetClubs } from "../actions/action-hooks"; +import { useClubs } from "../selectors/selectors"; +import { getClubs } from "../services/club"; +import ClubCard from "../components/club-card"; import Club from "../components/club"; +import { getDistance } from "geolib"; +import { Select } from "../components/ui"; function Home() { - const [loading, setLoading] = React.useState(false); const clubs = useClubs(); const setClubs = useSetClubs(); + const [position, setPosition] = React.useState([0, 0]); + const [selectedLocation, setSelectedLocation] = React.useState(); + const [sortType, setSortType] = React.useState("location"); React.useEffect(() => { - setLoading(true); getClubs().then(clubs => { setClubs(clubs); - setLoading(false); }); - }, []); + }, [setClubs]); + + function setDistance(clubPosition, position) { + return getDistance( + { latitude: position[0], longitude: position[1] }, + { + latitude: parseFloat(clubPosition.latitude), + longitude: parseFloat(clubPosition.longitude) + } + ); + } + + React.useEffect(() => { + const watchID = navigator.geolocation.watchPosition(pos => { + setPosition([pos.coords.latitude, pos.coords.longitude]); + }); + return () => { + navigator.geolocation.clearWatch(watchID); + }; + }, [setPosition]); + + function handleChangeLocation(e) { + console.log(e.target.value); + setSelectedLocation(e.target.value); + } + + function handleChangeSortType(e) { + console.log(e.target.value); + setSortType(e.target.value); + } + + function sortBy(a, b) { + switch (sortType) { + case "location": + return a.distance - b.distance; + + case "favorites": + return b.favorited_count - a.favorited_count; + + case "name": + return a.name - b.name; + + default: + break; + } + } + + const styleSelectsContainer = { + display: "flex", + justifyContent: "space-between", + marginBottom: "1em" + }; return (
-

Filters

- {loading &&
Loading
} - {clubs.map(club => ( - - ))} +
+ + +
+ + {clubs ? ( + clubs + .map(club => { + let distance = 0; + if (position[0] !== 0) { + distance = setDistance(club, position); + } + club.distance = distance; + return club; + }) + .sort(sortBy) + .map(club => { + return ; + }) + ) : ( +

Loading...

+ )}
); } diff --git a/client/yarn.lock b/client/yarn.lock index 0294157..bea4608 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -4374,6 +4374,11 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +geolib@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/geolib/-/geolib-3.0.4.tgz#63fd82cf4311f08cadc142aaa73a0941844266d1" + integrity sha512-IpbpPdfuVdjj2T909H0Kj0Crp0he+xfFYX6e1Wlvo5L2OVkfnfvpTLp9k0VYuu5ObbWhQ/TI2VKNsrAokss5vA== + get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" From 3e9fffd4424a995a37d4714b55a0bc41076f35d5 Mon Sep 17 00:00:00 2001 From: cristianbgp Date: Tue, 16 Jul 2019 19:56:11 -0500 Subject: [PATCH 4/5] Add latitude and longitude to the last club --- api/db/seeds.rb | 2 +- client/src/views/home.js | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/api/db/seeds.rb b/api/db/seeds.rb index 46400ec..4ecbab7 100644 --- a/api/db/seeds.rb +++ b/api/db/seeds.rb @@ -53,7 +53,7 @@ Club.create( name: 'Club golden', - address: 'Jr cayumba 440', + address: 'Jr Something 123', district: "Cercado de Lima", latitude: -12.0641388, longitude: -77.0358862, schedule: { 'monday-friday': { start: '8', diff --git a/client/src/views/home.js b/client/src/views/home.js index 220148d..4c25bd4 100644 --- a/client/src/views/home.js +++ b/client/src/views/home.js @@ -109,10 +109,13 @@ function Home() { clubs .map(club => { let distance = 0; - if (position[0] !== 0) { + if (club.latitude == null || club.longitude == null) { + distance = 0; + } else if (position[0] !== 0) { distance = setDistance(club, position); } club.distance = distance; + console.log(club); return club; }) .sort(sortBy) From 3e6b36592f0bafc052d4461e751e568b2c6b1db9 Mon Sep 17 00:00:00 2001 From: cristianbgp Date: Tue, 16 Jul 2019 20:14:06 -0500 Subject: [PATCH 5/5] Add icon for location --- client/src/components/club.js | 11 +++++++++-- client/src/components/icons.js | 22 +++++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/client/src/components/club.js b/client/src/components/club.js index 7fdcb45..5bff71a 100644 --- a/client/src/components/club.js +++ b/client/src/components/club.js @@ -2,7 +2,7 @@ import React from "react"; import { jsx } from "@emotion/core"; import { Card } from "./ui"; -import { Heart } from "./icons"; +import { Heart, MapPin } from "./icons"; import { favorite, unfavorite } from "../services/club"; import { useSetFavorite, useSetUnfavorite } from "../actions/action-hooks"; @@ -16,6 +16,12 @@ function Club({ club }) { color: "tomato" }; + const styleMapPin = { + cursor: "pointer", + color: "#414141", + marginLeft: "auto" + }; + async function handleClick() { if (club.favorited) { setFavorite(await unfavorite(club.id)); @@ -69,7 +75,8 @@ function Club({ club }) { > {club.favorited_count > 0 && club.favorited_count} - + + {club.distance !== 0 ? `${club.distance / 1000.0}km` : null} diff --git a/client/src/components/icons.js b/client/src/components/icons.js index 8693830..4858d21 100644 --- a/client/src/components/icons.js +++ b/client/src/components/icons.js @@ -19,4 +19,24 @@ function Heart(props) { ); } -export { Heart }; +function MapPin(props) { + return ( + + + + + ); +} + +export { Heart, MapPin };