Skip to content
This repository was archived by the owner on Aug 8, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/app/controllers/clubs_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion api/app/serializers/club_serializer.rb
Original file line number Diff line number Diff line change
@@ -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?
Expand Down
7 changes: 7 additions & 0 deletions api/db/migrate/20190715215722_add_district_to_clubs.rb
Original file line number Diff line number Diff line change
@@ -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
5 changes: 4 additions & 1 deletion api/db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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|
Expand Down
8 changes: 4 additions & 4 deletions api/db/seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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',
Expand All @@ -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',
Expand All @@ -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',
Expand Down
1 change: 1 addition & 0 deletions client/.env.example
Original file line number Diff line number Diff line change
@@ -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=
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
22 changes: 22 additions & 0 deletions client/src/components/club-card.js
Original file line number Diff line number Diff line change
@@ -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 (
<Card css={styleCard}>
<Title>{club.name}</Title>
<p>{JSON.stringify(club)}</p>
<p>{club.position}</p>
<p>{club.distance !== 0 ? `${club.distance / 1000.0}km` : null}</p>
</Card>
);
}

export default ClubCard;
12 changes: 11 additions & 1 deletion client/src/components/club.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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));
Expand Down Expand Up @@ -69,6 +75,10 @@ function Club({ club }) {
>
{club.favorited_count > 0 && club.favorited_count}
</span>
<MapPin width="18px" height="18px" css={styleMapPin} />
<span>
{club.distance !== 0 ? `${club.distance / 1000.0}km` : null}
</span>
</div>
</div>
</Card>
Expand Down
22 changes: 21 additions & 1 deletion client/src/components/icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,24 @@ function Heart(props) {
);
}

export { Heart };
function MapPin(props) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
<circle cx="12" cy="10" r="3" />
</svg>
);
}

export { Heart, MapPin };
21 changes: 21 additions & 0 deletions client/src/services/geocode.js
Original file line number Diff line number Diff line change
@@ -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";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is the way to get a request from Open Cage Data API

const response = await fetch(request_url);

if (!response.ok) throw new Error(response.statusText);
return response.json();
}

export { getCoords };
25 changes: 23 additions & 2 deletions client/src/views/create-club.js
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -86,6 +93,20 @@ function CreateClub() {
onChange={handleChange}
/>
</div>
<div css={{ marginTop: "2em" }}>
<Label htmlFor="district">District</Label>
<Input
aria-label="enter district"
required="required"
autoComplete="off"
id="district"
name="district"
type="text"
placeholder="Club's district"
value={fields.district}
onChange={handleChange}
/>
</div>
<div css={{ marginTop: "2em" }}>
<Label htmlFor="image">Image(s)</Label>
<Input
Expand Down
121 changes: 110 additions & 11 deletions client/src/views/home.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,130 @@
/** @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 (
<div>
<h2>Filters</h2>
{loading && <div>Loading</div>}
{clubs.map(club => (
<Club club={club} key={club.id} />
))}
<div css={styleSelectsContainer}>
<Select
onChange={handleChangeLocation}
defaultValue=""
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you assign a more significant name instead of defaultValue ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the default value for the select tag

styles={{ container: { width: "50%" } }}
>
<option value="" disabled hidden>
Choose a district
</option>
<option value="">None</option>
{[
...clubs.reduce((districts, club) => {
districts.add(club.district);
return districts;
}, new Set())
].map(dist => {
return (
<option key={dist} value={dist}>
{dist}
</option>
);
})}
</Select>
<Select onChange={handleChangeSortType} defaultValue="location">
<option value="location">Location</option>
<option value="favorites">Favorites</option>
<option value="name">Name</option>
</Select>
</div>

{clubs ? (
clubs
.map(club => {
let distance = 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)
.map(club => {
return <Club key={club.id} club={club} />;
})
) : (
<p>Loading...</p>
)}
</div>
);
}
Expand Down
Loading