Skip to content

Commit

Permalink
Update api structure and use database for locations page (#143)
Browse files Browse the repository at this point in the history
* Move api structure to router and update locations schema

* Update auth uri to match api

* Use database for locations name and type

* Remove location tests

* Update PhotoHeader test

* Format
  • Loading branch information
chriscerie authored Nov 7, 2021
1 parent 7feab41 commit 07b9905
Show file tree
Hide file tree
Showing 17 changed files with 211 additions and 94 deletions.
2 changes: 1 addition & 1 deletion client/src/actions/currentUserActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const currentUserActionTypes = {
export const setCurrentUser = () => {
return (dispatch: Dispatch) => {
axios
.get<null | CurrentUserState>('/api/v1/current-user')
.get<null | CurrentUserState>('/api/v1/users/current-user')
.then((res) => {
console.log(res.data);
if (res.data && res.status === 200) {
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Header/LocationHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ function LocationHeader() {
) : (
<Fragment>
<a
href="/auth/google"
href="api/v1/auth/google"
id="location-header-signin-button"
className="location-header-sign-buttons"
>
Sign in
</a>
<a
href="/auth/google"
href="api/v1/auth/google"
id="location-header-signup-button"
className="location-header-sign-buttons"
>
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Header/MapHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ function MapHeader() {
isBigScreen && (
<Fragment>
<a
href="/auth/google"
href="api/v1/auth/google"
className="signin-button header-text-shadow"
>
Sign in
</a>
<a
href="/auth/google"
href="api/v1/auth/google"
className="signup-button header-text-shadow"
>
Sign up
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Header/ProfileIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ function ProfileIcon() {
<ListItemIcon>
<Logout fontSize="small" />
</ListItemIcon>
<a href="/api/v1/logout" className="menu-item-link">
<a href="/api/v1/auth/logout" className="menu-item-link">
Logout
</a>
</MenuItem>
Expand Down
2 changes: 1 addition & 1 deletion client/src/pages/LocationPage/PhotoHeader.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PhotoHeader from './PhotoHeader';
describe('PhotoHeader', () => {
it('should render successfully', () => {
const renderer = ShallowRenderer.createRenderer();
const tree = renderer.render(<PhotoHeader selected={null} />);
const tree = renderer.render(<PhotoHeader name="name" type="type" />);
expect(tree).toMatchSnapshot();
});
});
20 changes: 8 additions & 12 deletions client/src/pages/LocationPage/PhotoHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,21 @@ import { Container, Stack } from '@mui/material';
import { Link } from 'react-router-dom';
import './PhotoHeader.scss';

function PhotoHeader(props: {
selected: null | mapboxgl.MapboxGeoJSONFeature;
function PhotoHeader({
// TODO: change any type to LocationType
name = '...',
type = '...',
}: {
name: string;
type: string;
}) {
let name = '...';
let category = '...';

if (props.selected && props.selected.properties) {
const properties = props.selected.properties;
name = properties.name;
category = properties.category_en || properties.type;
}

return (
<div className="location-page-container">
<div className="photo-header-container">
<Container className="photo-header-content-container">
<div className="photo-header-content">
<div className="photo-header-heading">{name}</div>
<div className="photo-header-subheading">{category}</div>
<div className="photo-header-subheading">{type}</div>
</div>
<Link to="/" id="see-more-button">
See more photos
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ exports[`PhotoHeader should render successfully 1`] = `
<div
className="photo-header-heading"
>
...
name
</div>
<div
className="photo-header-subheading"
>
...
type
</div>
</div>
<Link
Expand Down
79 changes: 57 additions & 22 deletions client/src/pages/LocationPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,74 @@ import './index.scss';
import { useState, useEffect } from 'react';
import LeftColumnDetails from './LeftColumnDetails';
import RightColumnDetails from './RightColumnDetails';
import axios from 'axios';

export type LocationType = {
id: number;
name: string;
type: string;
description: string;
tile: {
x: number;
y: number;
z: number;
};
};

function LocationPage() {
const { id } = useParams<{ id: string }>();
const [selected, setSelected] =
useState<null | mapboxgl.MapboxGeoJSONFeature>(null);
const [selected, setSelected] = useState<null | LocationType>(null);
const mapInstance = useSelector((state: RootState) => state.mapInstance.map);

// Set point
useEffect(() => {
if (mapInstance) {
const setSelectedPoint = () => {
const points = mapInstance.querySourceFeatures('composite', {
sourceLayer: 'poi_label',
});

setSelected(points.filter((point) => point.id == id)[0]);
};

if (mapInstance.isStyleLoaded()) {
setSelectedPoint();
} else {
mapInstance.once('loaded', () => {
setSelectedPoint();
});
}
}
}, [id, mapInstance]);
axios
.get<LocationType>(`/api/v1/locations/loc/${id}`)
.then((res) => {
setSelected(res.data);
})
.catch((err) => {
if (mapInstance) {
const setSelectedPoint = () => {
const points = mapInstance.querySourceFeatures('composite', {
sourceLayer: 'poi_label',
});

const point = points.filter((point) => point.id == id)[0];

console.log(selected);
if (point && point.properties) {
// Request to create location data
axios
.post<LocationType>(`/api/v1/locations/loc/${id}`, {
id: point.id,
name: point.properties.name,
type: point.properties.category_en || point.properties.type,
// @ts-ignore
tile: point.tile,
})
.then((res) => {
setSelected(res.data);
});
}
};

if (mapInstance.isStyleLoaded()) {
setSelectedPoint();
} else {
mapInstance.once('loaded', () => {
setSelectedPoint();
});
}
}
});
}, [id, mapInstance]);

return (
<div className="location-page-container">
<PhotoHeader selected={selected} />
<PhotoHeader
name={selected ? selected.name : ''}
type={selected ? selected.type : ''}
/>

<Container id="location-page-container-inner">
<LeftColumnDetails />
Expand Down
6 changes: 2 additions & 4 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import session from 'express-session';
import passport from 'passport';
import dotenv from 'dotenv';
import * as path from 'path';
import auth from './routes/auth';
import routes from './routes';
import './models/usersModel';

dotenv.config();
Expand All @@ -30,9 +30,7 @@ mongoose
app.use(passport.initialize());
app.use(passport.session());

import './config/passport';

auth(app);
app.use('/api', routes);

// Serve static files from the React app
app.use(express.static(path.join(__dirname, '../client/build')));
Expand Down
2 changes: 1 addition & 1 deletion src/config/passport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ passport.use(
clientID:
'796959289157-ser2d8agd1nv5t1kl64ii4rtqfi7blb7.apps.googleusercontent.com',
clientSecret: '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',
callbackURL: '/auth/google/callback',
callbackURL: '/api/v1/auth/google/callback',
proxy: true,
},
(_accessToken, _refreshToken, profile, done) => {
Expand Down
29 changes: 25 additions & 4 deletions src/models/locationsModel.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,44 @@
import mongoose, { Schema, Document } from 'mongoose';

export interface ILocationsModel extends Document {
export interface ILocation extends Document {
name: string;
id: string;
type?: string;
}

const locationsSchema = new Schema({
id: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
id: {
type: {
type: String,
required: true,
},
type: String,
description: {
type: String,
required: true,
},
tile: {
x: {
type: Number,
required: true,
},
y: {
type: Number,
required: true,
},
z: {
type: Number,
required: true,
},
},
});

const Location = mongoose.model<ILocationsModel>('Location', locationsSchema);
const Location = mongoose.model<ILocation>('Location', locationsSchema);

export default Location;
15 changes: 2 additions & 13 deletions src/routes/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,10 @@
import supertest from 'supertest';
import app from '../app';

describe('/v1/current-user', () => {
it('should status 404 when not logged in', async () => {
await supertest(app)
.get('/api/v1/current-user')
.then((response) => {
expect(response.statusCode).toBe(404);
expect(response.body).toEqual({});
});
});
});

describe('/v1/logout', () => {
describe('/v1/auth/logout', () => {
it('should status 302', async () => {
await supertest(app)
.post('/api/v1/logout')
.post('/api/v1/auth/logout')
.then((response) => {
expect(response.statusCode).toBe(302);
});
Expand Down
48 changes: 19 additions & 29 deletions src/routes/auth.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,26 @@
import passport from 'passport';
import express from 'express';

const mockApp = express();
const router = express.Router();

function auth(app: typeof mockApp): void {
app.get(
'/auth/google',
passport.authenticate('google', {
scope: ['profile', 'email'],
})
);
router.get(
'/v1/auth/google',
passport.authenticate('google', {
scope: ['profile', 'email'],
})
);

app.get(
'/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/auth/google' }),
(req, res) => {
res.redirect('/');
}
);

app.get('/api/v1/current-user', (req, res) => {
if (req.user) {
res.status(200).send(req.user);
} else {
res.status(404).send(null);
}
});

app.post('/api/v1/logout', (req, res) => {
req.logout();
router.get(
'/v1/auth/google/callback',
passport.authenticate('google', { failureRedirect: 'api/v1/auth/google' }),
(req, res) => {
res.redirect('/');
});
}
}
);

router.post('/v1/auth/logout', (req, res) => {
req.logout();
res.redirect('/');
});

export default auth;
export default router;
13 changes: 13 additions & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import express from 'express';
import auth from './auth';
import users from './users';
import locations from './locations';
import '../config/passport';

const router = express.Router();

router.use('/', auth);
router.use('/', users);
router.use('/', locations);

export default router;
Loading

0 comments on commit 07b9905

Please sign in to comment.