Added working gym api.
This commit is contained in:
parent
fa359e63c1
commit
3d5fe43526
|
@ -0,0 +1,26 @@
|
||||||
|
package nl.andrewlalis.gymboard_api.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
|
import org.springframework.web.filter.CorsFilter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CorsFilter corsFilter() {
|
||||||
|
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
|
final CorsConfiguration config = new CorsConfiguration();
|
||||||
|
config.setAllowCredentials(true);
|
||||||
|
// Don't do this in production, use a proper list of allowed origins
|
||||||
|
config.addAllowedOriginPattern("*");
|
||||||
|
config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept"));
|
||||||
|
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH"));
|
||||||
|
source.registerCorsConfiguration("/**", config);
|
||||||
|
return new CorsFilter(source);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.andrewlalis.gymboard_api.controller.dto;
|
||||||
|
|
||||||
|
import nl.andrewlalis.gymboard_api.model.GeoPoint;
|
||||||
|
|
||||||
|
public record GeoPointResponse(
|
||||||
|
double latitude,
|
||||||
|
double longitude
|
||||||
|
) {
|
||||||
|
public GeoPointResponse(GeoPoint p) {
|
||||||
|
this(
|
||||||
|
p.getLatitude().doubleValue(),
|
||||||
|
p.getLongitude().doubleValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,10 +10,10 @@ public record GymResponse (
|
||||||
String cityShortName,
|
String cityShortName,
|
||||||
String cityName,
|
String cityName,
|
||||||
String createdAt,
|
String createdAt,
|
||||||
|
String shortName,
|
||||||
String displayName,
|
String displayName,
|
||||||
String websiteUrl,
|
String websiteUrl,
|
||||||
double locationLatitude,
|
GeoPointResponse location,
|
||||||
double locationLongitude,
|
|
||||||
String streetAddress
|
String streetAddress
|
||||||
) {
|
) {
|
||||||
public GymResponse(Gym gym) {
|
public GymResponse(Gym gym) {
|
||||||
|
@ -23,10 +23,10 @@ public record GymResponse (
|
||||||
gym.getCity().getShortName(),
|
gym.getCity().getShortName(),
|
||||||
gym.getCity().getName(),
|
gym.getCity().getName(),
|
||||||
gym.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
|
gym.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
|
||||||
|
gym.getShortName(),
|
||||||
gym.getDisplayName(),
|
gym.getDisplayName(),
|
||||||
gym.getWebsiteUrl(),
|
gym.getWebsiteUrl(),
|
||||||
gym.getLocation().getLatitude().doubleValue(),
|
new GeoPointResponse(gym.getLocation()),
|
||||||
gym.getLocation().getLongitude().doubleValue(),
|
|
||||||
gym.getStreetAddress()
|
gym.getStreetAddress()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
spring.jpa.open-in-view=false
|
spring.jpa.open-in-view=false
|
||||||
|
|
||||||
|
spring.servlet.multipart.enabled=false
|
||||||
|
|
|
@ -11,8 +11,9 @@
|
||||||
|
|
||||||
const { configure } = require('quasar/wrappers');
|
const { configure } = require('quasar/wrappers');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const { withCtx } = require('vue');
|
||||||
|
|
||||||
module.exports = configure(function (/* ctx */) {
|
module.exports = configure(function (ctx) {
|
||||||
return {
|
return {
|
||||||
eslint: {
|
eslint: {
|
||||||
// fix: true,
|
// fix: true,
|
||||||
|
@ -69,7 +70,9 @@ module.exports = configure(function (/* ctx */) {
|
||||||
|
|
||||||
// publicPath: '/',
|
// publicPath: '/',
|
||||||
// analyze: true,
|
// analyze: true,
|
||||||
// env: {},
|
env: {
|
||||||
|
API: ctx.dev ? 'http://localhost:8080' : 'https://api.gymboard.com'
|
||||||
|
},
|
||||||
// rawDefine: {}
|
// rawDefine: {}
|
||||||
// ignorePublicFolder: true,
|
// ignorePublicFolder: true,
|
||||||
// minify: false,
|
// minify: false,
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
import axios from "axios";
|
||||||
|
import process from "process";
|
||||||
|
|
||||||
|
const api = axios.create({
|
||||||
|
baseURL: 'http://localhost:8080'
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Gym = {
|
||||||
|
countryCode: string,
|
||||||
|
countryName: string,
|
||||||
|
cityShortName: string,
|
||||||
|
cityName: string,
|
||||||
|
createdAt: Date,
|
||||||
|
shortName: string,
|
||||||
|
displayName: string,
|
||||||
|
websiteUrl: string | null,
|
||||||
|
location: {
|
||||||
|
latitude: number,
|
||||||
|
longitude: number
|
||||||
|
},
|
||||||
|
streetAddress: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getGym(countryCode: string, cityShortName: string, gymShortName: string): Promise<Gym> {
|
||||||
|
const response = await api.get(`/gyms/${countryCode}/${cityShortName}/${gymShortName}`);
|
||||||
|
const d = response.data;
|
||||||
|
const gym: Gym = {
|
||||||
|
countryCode: d.countryCode,
|
||||||
|
countryName: d.countryName,
|
||||||
|
cityShortName: d.cityShortName,
|
||||||
|
cityName: d.cityName,
|
||||||
|
createdAt: new Date(d.createdAt),
|
||||||
|
shortName: d.shortName,
|
||||||
|
displayName: d.displayName,
|
||||||
|
websiteUrl: d.websiteUrl,
|
||||||
|
location: d.location,
|
||||||
|
streetAddress: d.streetAddress
|
||||||
|
};
|
||||||
|
return gym;
|
||||||
|
}
|
|
@ -7,24 +7,10 @@ declare module '@vue/runtime-core' {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Be careful when using SSR for cross-request state pollution
|
|
||||||
// due to creating a Singleton instance here;
|
|
||||||
// If any client changes this (global) instance, it might be a
|
|
||||||
// good idea to move this instance creation inside of the
|
|
||||||
// "export default () => {}" function below (which runs individually
|
|
||||||
// for each client)
|
|
||||||
const api = axios.create({ baseURL: 'https://api.example.com' });
|
|
||||||
|
|
||||||
export default boot(({ app }) => {
|
export default boot(({ app }) => {
|
||||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||||
|
|
||||||
app.config.globalProperties.$axios = axios;
|
app.config.globalProperties.$axios = axios;
|
||||||
// ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
|
// ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
|
||||||
// so you won't necessarily have to import axios in each vue file
|
// so you won't necessarily have to import axios in each vue file
|
||||||
|
|
||||||
app.config.globalProperties.$api = api;
|
|
||||||
// ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
|
|
||||||
// so you can easily perform requests against your app's API
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export { api };
|
|
||||||
|
|
|
@ -1,17 +1,42 @@
|
||||||
<template>
|
<template>
|
||||||
<q-page>
|
<q-page v-if="gym">
|
||||||
Hello Gym Page
|
<h3>{{ gym.displayName }}</h3>
|
||||||
<p>
|
<p>Recent top lifts go here.</p>
|
||||||
Leaderboard total
|
<q-btn
|
||||||
</p>
|
color="primary"
|
||||||
|
label="Submit Your Lift"
|
||||||
|
:to="route.fullPath + '/submit'"
|
||||||
|
/>
|
||||||
|
<p>All the rest of the gym leaderboards should show up here.</p>
|
||||||
|
</q-page>
|
||||||
|
<q-page v-if="notFound">
|
||||||
|
<h3>Gym not found! Oh no!!!</h3>
|
||||||
|
<router-link to="/">Back</router-link>
|
||||||
</q-page>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineComponent, onMounted, ref } from 'vue';
|
import { onMounted, ref, Ref } from 'vue';
|
||||||
const mountCount = ref(0);
|
import { getGym, Gym } from 'src/api/gymboard-api';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
onMounted(() => {
|
const route = useRoute();
|
||||||
console.log("mounted");
|
|
||||||
|
const gym: Ref<Gym | undefined> = ref<Gym>();
|
||||||
|
const notFound: Ref<boolean | undefined> = ref<boolean>();
|
||||||
|
|
||||||
|
// Once the component is mounted, load the gym that we're at.
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
gym.value = await getGym(
|
||||||
|
route.params.countryCode as string,
|
||||||
|
route.params.cityShortName as string,
|
||||||
|
route.params.gymShortName as string
|
||||||
|
);
|
||||||
|
notFound.value = false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
notFound.value = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
|
@ -13,7 +13,7 @@ const routes: RouteRecordRaw[] = [
|
||||||
component: IndexPage
|
component: IndexPage
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'g/:countryId/:cityId/:gymName',
|
path: 'g/:countryCode/:cityShortName/:gymShortName',
|
||||||
component: GymPage
|
component: GymPage
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue