Added working gym api.
This commit is contained in:
parent
4f7f17f6b0
commit
181aabaac8
|
@ -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 cityName,
|
||||
String createdAt,
|
||||
String shortName,
|
||||
String displayName,
|
||||
String websiteUrl,
|
||||
double locationLatitude,
|
||||
double locationLongitude,
|
||||
GeoPointResponse location,
|
||||
String streetAddress
|
||||
) {
|
||||
public GymResponse(Gym gym) {
|
||||
|
@ -23,10 +23,10 @@ public record GymResponse (
|
|||
gym.getCity().getShortName(),
|
||||
gym.getCity().getName(),
|
||||
gym.getCreatedAt().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
|
||||
gym.getShortName(),
|
||||
gym.getDisplayName(),
|
||||
gym.getWebsiteUrl(),
|
||||
gym.getLocation().getLatitude().doubleValue(),
|
||||
gym.getLocation().getLongitude().doubleValue(),
|
||||
new GeoPointResponse(gym.getLocation()),
|
||||
gym.getStreetAddress()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
spring.jpa.open-in-view=false
|
||||
|
||||
spring.servlet.multipart.enabled=false
|
||||
|
|
|
@ -11,8 +11,9 @@
|
|||
|
||||
const { configure } = require('quasar/wrappers');
|
||||
const path = require('path');
|
||||
const { withCtx } = require('vue');
|
||||
|
||||
module.exports = configure(function (/* ctx */) {
|
||||
module.exports = configure(function (ctx) {
|
||||
return {
|
||||
eslint: {
|
||||
// fix: true,
|
||||
|
@ -69,7 +70,9 @@ module.exports = configure(function (/* ctx */) {
|
|||
|
||||
// publicPath: '/',
|
||||
// analyze: true,
|
||||
// env: {},
|
||||
env: {
|
||||
API: ctx.dev ? 'http://localhost:8080' : 'https://api.gymboard.com'
|
||||
},
|
||||
// rawDefine: {}
|
||||
// ignorePublicFolder: true,
|
||||
// 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 }) => {
|
||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||
|
||||
app.config.globalProperties.$axios = axios;
|
||||
// ^ ^ ^ 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
|
||||
|
||||
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>
|
||||
<q-page>
|
||||
Hello Gym Page
|
||||
<p>
|
||||
Leaderboard total
|
||||
</p>
|
||||
<q-page v-if="gym">
|
||||
<h3>{{ gym.displayName }}</h3>
|
||||
<p>Recent top lifts go here.</p>
|
||||
<q-btn
|
||||
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>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent, onMounted, ref } from 'vue';
|
||||
const mountCount = ref(0);
|
||||
import { onMounted, ref, Ref } from 'vue';
|
||||
import { getGym, Gym } from 'src/api/gymboard-api';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
onMounted(() => {
|
||||
console.log("mounted");
|
||||
const route = useRoute();
|
||||
|
||||
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>
|
|
@ -13,7 +13,7 @@ const routes: RouteRecordRaw[] = [
|
|||
component: IndexPage
|
||||
},
|
||||
{
|
||||
path: 'g/:countryId/:cityId/:gymName',
|
||||
path: 'g/:countryCode/:cityShortName/:gymShortName',
|
||||
component: GymPage
|
||||
}
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue