frontend and backend progress
This commit is contained in:
parent
888cdae3cd
commit
787b9879fc
|
|
@ -0,0 +1,13 @@
|
|||
# build stage
|
||||
FROM node:lts-alpine AS build-stage
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# production stage
|
||||
FROM nginx:stable-alpine AS production-stage
|
||||
COPY --from=build-stage /app/dist /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
"@ionic/vue": "^8.0.0",
|
||||
"@ionic/vue-router": "^8.0.0",
|
||||
"axios": "^1.8.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"ionicons": "^7.0.0",
|
||||
"vee-validate": "^4.15.0",
|
||||
"vue": "^3.3.0",
|
||||
|
|
@ -4962,7 +4963,6 @@
|
|||
"version": "1.11.13",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
|
||||
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/de-indent": {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
"@ionic/vue": "^8.0.0",
|
||||
"@ionic/vue-router": "^8.0.0",
|
||||
"axios": "^1.8.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"ionicons": "^7.0.0",
|
||||
"vee-validate": "^4.15.0",
|
||||
"vue": "^3.3.0",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { useStore } from 'vuex'
|
|||
import { AppStore } from '@/store';
|
||||
import { onMounted, onBeforeUnmount, ref } from "vue";
|
||||
import EventBus from "./common/EventBus";
|
||||
import backendService from '@/services/BackendService'
|
||||
|
||||
const router = useRouter();
|
||||
const store = useStore<AppStore>();
|
||||
|
|
@ -19,6 +20,8 @@ const isOnline = ref(navigator.onLine);
|
|||
onMounted(() => {
|
||||
EventBus.on("logout", logout);
|
||||
|
||||
backendService.updateServer(backendService.getServer());
|
||||
|
||||
window.addEventListener("online", () => isOnline.value = true);
|
||||
window.addEventListener("offline", () => isOnline.value = false);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,12 +9,14 @@ import BullpenSummaryView from "@/views/BullpenSummaryView.vue";
|
|||
import SetupView from '@/views/SetupView.vue';
|
||||
import backendService from '@/services/BackendService'
|
||||
import BullpenListView from "@/views/BullpenListView.vue";
|
||||
import ProfileView from "@/views/ProfileView.vue";
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{ path: '/', redirect: '/login' },
|
||||
{ path: '/login', component: LoginView },
|
||||
{ path: '/setup', component: SetupView },
|
||||
{ path: '/home', component: HomeView },
|
||||
{ path: '/profile', component: ProfileView },
|
||||
{ path: '/pitchers', component: PitcherList },
|
||||
{ path: '/bullpen', component: BullpenView },
|
||||
{ path: '/stats', component: BullpenListView },
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ class BackendService {
|
|||
return localStorage.getItem("server") !== null;
|
||||
}
|
||||
getServer(): Server {
|
||||
return JSON.parse(localStorage.getItem("server") || '{"protocol":"http","host":"localhost","port":8080}');
|
||||
// return JSON.parse(localStorage.getItem("server") || '{"protocol":"https","host":"bullpen-api.palaeomatiker.home64.de","port":443}');
|
||||
// return JSON.parse(localStorage.getItem("server") || '{"protocol":"http","host":"localhost","port":8080}');
|
||||
return JSON.parse(localStorage.getItem("server") || '{"protocol":"https","host":"bullpen-api.palaeomatiker.home64.de","port":443}');
|
||||
}
|
||||
updateServer(server: Server): void {
|
||||
localStorage.setItem("server", JSON.stringify(server));
|
||||
|
|
|
|||
|
|
@ -2,17 +2,24 @@
|
|||
import {
|
||||
IonButton,
|
||||
IonCard,
|
||||
IonCardTitle,
|
||||
IonCardSubtitle,
|
||||
IonContent,
|
||||
IonFooter,
|
||||
IonHeader,
|
||||
IonLabel,
|
||||
IonPage,
|
||||
IonTitle,
|
||||
IonToolbar
|
||||
IonToolbar, IonLabel, IonList, IonItem, IonIcon, IonBadge
|
||||
} from "@ionic/vue";
|
||||
import {
|
||||
baseballOutline
|
||||
} from 'ionicons/icons';
|
||||
|
||||
import PitchType from "@/types/PitchType";
|
||||
import {useStore} from 'vuex';
|
||||
import {useRouter} from 'vue-router';
|
||||
import {computed} from "vue";
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const router = useRouter();
|
||||
const store = useStore();
|
||||
|
|
@ -20,6 +27,17 @@ const store = useStore();
|
|||
const isAuthenticated = computed(() => store.state.auth.isAuthenticated);
|
||||
const pitcher = computed(() => store.state.auth.user);
|
||||
const bullpens = computed(() => store.state.bullpen.bullpens);
|
||||
const pitchTypes = computed(() => store.state.pitchTypes.pitchTypes);
|
||||
|
||||
const formatDate = (date: Date) => {
|
||||
return dayjs(date).format('YYYY.MM.DD HH:mm');
|
||||
}
|
||||
|
||||
const determinePitchTypeName = (id: number): string => {
|
||||
const pitchType = pitchTypes.value.find((pitchType: PitchType) => pitchType.id === id);
|
||||
|
||||
return pitchType?.name ?? 'Unknown';
|
||||
}
|
||||
|
||||
const gotoHome = () => {
|
||||
router.push({path: '/home'});
|
||||
|
|
@ -37,7 +55,21 @@ const gotoHome = () => {
|
|||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-card v-for="(bullpen, index) in bullpens.data" :key="index">
|
||||
<ion-label>Bullpen {{bullpen.id}} ({{bullpen.startedAt}})</ion-label>
|
||||
<ion-card-header>
|
||||
<ion-card-title>Bullpen from ({{formatDate(bullpen.startedAt)}})</ion-card-title>
|
||||
<ion-card-subtitle></ion-card-subtitle>
|
||||
</ion-card-header>
|
||||
<ion-card-content>
|
||||
<ion-list v-for="(pitch, index) in bullpen.pitches" :key="index">
|
||||
<ion-item>
|
||||
<ion-icon slot="start" :icon="baseballOutline" class="icon-login"></ion-icon>
|
||||
<ion-label>{{determinePitchTypeName(pitch.pitchTypeId)}}</ion-label>
|
||||
<ion-badge>{{pitch.aimedArea}}</ion-badge>
|
||||
<ion-badge>{{pitch.hitArea}}</ion-badge>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</ion-card-content>
|
||||
|
||||
</ion-card>
|
||||
</ion-content>
|
||||
<ion-footer>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { computed, ref, onMounted } from "vue";
|
|||
import {
|
||||
IonPage,
|
||||
IonIcon,
|
||||
IonLabel,
|
||||
// IonLabel,
|
||||
IonButton,
|
||||
IonContent,
|
||||
IonInput
|
||||
|
|
@ -20,11 +20,10 @@ import { useRouter } from 'vue-router';
|
|||
import { useStore } from 'vuex'
|
||||
import * as yup from 'yup';
|
||||
import PitchTypeService from "@/services/PitchTypeService";
|
||||
import EventBus from "@/common/EventBus";
|
||||
import PitchType from "@/types/PitchType";
|
||||
|
||||
const loading = ref(false);
|
||||
const server = JSON.parse(localStorage.getItem("server") || '""');
|
||||
// const server = JSON.parse(localStorage.getItem("server") || '""');
|
||||
|
||||
const schema = yup.object({
|
||||
email: yup.string().email('Invalid email address').required('Email is required'),
|
||||
|
|
@ -100,7 +99,7 @@ const changeServer = () => {
|
|||
<div class="logo-container">
|
||||
<img src="../assets/Bonn_Capitals_Insignia.png" alt="Logo" class="logo" />
|
||||
</div>
|
||||
<ion-label>{{server.protocol}}://{{server.host}}:{{server.port}}</ion-label>
|
||||
<!-- <ion-label>{{server.protocol}}://{{server.host}}:{{server.port}}</ion-label>-->
|
||||
</div>
|
||||
<form @submit="submit" class="form-container">
|
||||
<div class="input-group">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
<script setup lang="ts">
|
||||
import {logOutOutline, personOutline, playOutline, statsChartOutline} from "ionicons/icons";
|
||||
import {
|
||||
IonAvatar,
|
||||
IonButton,
|
||||
IonContent,
|
||||
IonFooter,
|
||||
IonHeader,
|
||||
IonIcon,
|
||||
IonPage,
|
||||
IonTitle,
|
||||
IonToolbar
|
||||
} from "@ionic/vue";
|
||||
import {computed, ref} from "vue";
|
||||
|
||||
import {useStore} from "vuex";
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
const userImage = ref(null);
|
||||
|
||||
const router = useRouter();
|
||||
const store = useStore();
|
||||
|
||||
const pitcher = computed(() => store.state.auth.user);
|
||||
const isAuthenticated = computed(() => store.state.auth.isAuthenticated);
|
||||
|
||||
const gotoHome = () => {
|
||||
router.push({path: '/home'});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title v-if="isAuthenticated">Home of {{ pitcher.firstName }} {{ pitcher.lastName }}</ion-title>
|
||||
<ion-title v-else>Home</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding">
|
||||
<div class="user-container">
|
||||
<ion-avatar class="user-avatar">
|
||||
<template v-if="userImage">
|
||||
<img :src="userImage" alt="User Profile" class="avatar-frame" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<ion-icon :icon="personOutline" class="avatar-placeholder" />
|
||||
</template>
|
||||
</ion-avatar>
|
||||
<div v-if="isAuthenticated" class="user-name">{{ pitcher.firstName }} {{ pitcher.lastName }}</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
<ion-footer>
|
||||
<ion-button expand="full" color="success" @click="gotoHome">Home</ion-button>
|
||||
</ion-footer>
|
||||
</ion-page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.user-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 30vh;
|
||||
background-color: #f0f0f0;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 50%;
|
||||
border: 4px solid #ccc;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.avatar-frame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.avatar-placeholder {
|
||||
font-size: 60px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
margin-top: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
module.exports = {
|
||||
secret: "bullpen-secret-key",
|
||||
|
||||
// jwtExpiration: 3600, // 1 hour
|
||||
// jwtRefreshExpiration: 86400, // 24 hours
|
||||
jwtExpiration: 3600, // 1 hour
|
||||
jwtRefreshExpiration: 86400 * 7, // 7 days
|
||||
|
||||
/* for test */
|
||||
jwtExpiration: 30, // 30 seconds
|
||||
jwtRefreshExpiration: 60 // 1 minute
|
||||
// jwtExpiration: 30, // 30 seconds
|
||||
// jwtRefreshExpiration: 60 // 1 minute
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue