bullpen page progress

This commit is contained in:
Sascha Kühl 2025-04-07 22:41:44 +02:00
parent a350b02731
commit ea885ae56f
14 changed files with 161 additions and 70 deletions

View File

@ -10,7 +10,7 @@ import BullpenStats from "@/views/BullpenStats.vue";
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/home'
redirect: '/login'
}, {
path: '/login',
name: 'Login',

View File

@ -17,8 +17,10 @@ class AuthService {
});
}
public logout() {
public logout(): Promise<void> {
TokenService.removeUser();
return Promise.resolve();
}
public register(email: string, password: string) {

View File

@ -1,15 +1,17 @@
import BullpenPitch from "@/types/BullpenPitch";
import Pitch from "@/types/Pitch";
import User from "@/types/User";
import PitchType from "@/types/PitchType";
// import api from './Api';
export class BullpenSessionService {
private static instance: BullpenSessionService;
private static nullPitcher: User = {
id: 0,
firstName: "",
lastName: "",
email: "",
password: "",
gender: "male",
handedness: "right",
height: 0.0,
weight: 0.0,
dateOfBirth: new Date(0),
createdAt: new Date(0),
updatedAt: new Date(0),
@ -20,18 +22,11 @@ export class BullpenSessionService {
abbreviation: ""
}
private constructor() {
public constructor() {
this.currentPitch = this.createPitch();
}
// Static method to get the instance of the service
public static getInstance(): BullpenSessionService {
if (!BullpenSessionService.instance) {
BullpenSessionService.instance = new BullpenSessionService();
}
return BullpenSessionService.instance;
}
public saveBullpen(): void {}
public startSession(pitcher: User): void {
this.pitcher = pitcher;
this.pitches = [];
@ -51,15 +46,15 @@ export class BullpenSessionService {
this.pitcher = BullpenSessionService.nullPitcher;
}
public addBullpenPitch( bullpenPitch: BullpenPitch ): void {
public addBullpenPitch( bullpenPitch: Pitch ): void {
this.pitches.push( bullpenPitch );
}
public getBullpenPitches(): BullpenPitch[] {
public getBullpenPitches(): Pitch[] {
return this.pitches;
}
public currentBullpenPitch(): BullpenPitch {
public currentBullpenPitch(): Pitch {
return this.currentPitch;
}
@ -76,7 +71,7 @@ export class BullpenSessionService {
return this.pitcher.id === 0;
}
private createPitch(): BullpenPitch {
private createPitch(): Pitch {
return {
id: 0,
date: new Date(),
@ -86,9 +81,9 @@ export class BullpenSessionService {
realPitchSubArea: 0
}
}
private pitches: BullpenPitch[] = [];
private pitches: Pitch[] = [];
private pitcher: User = BullpenSessionService.nullPitcher;
private currentPitch: BullpenPitch;
private currentPitch: Pitch;
}
export const bullpenSessionService = BullpenSessionService.getInstance();
export default new BullpenSessionService();

View File

@ -26,7 +26,9 @@ const auth: Module<AuthState, RootState> = {
actions: {
login({ commit }: AuthActionContext, user) {
return AuthService.login(user.email, user.password).then(
user => {
auth => {
return UserService.getUser(auth.id).then(
(user: User) => {
commit('loginSuccess', user);
return Promise.resolve(user);
},
@ -35,10 +37,19 @@ const auth: Module<AuthState, RootState> = {
return Promise.reject(error);
}
);
},
error => {
commit('loginFailure');
return Promise.reject(error);
}
);
},
logout({ commit }: AuthActionContext) {
AuthService.logout();
return AuthService.logout().then(() => {
commit('logout');
return Promise.resolve();
})
},
register({ commit }: AuthActionContext, user) {
return AuthService.register(user.email, user.password).then(
@ -56,9 +67,7 @@ const auth: Module<AuthState, RootState> = {
mutations: {
loginSuccess(state, user) {
state.isAuthenticated = true;
UserService.getUser(user.id).then((user: User) => {
state.user = user;
});
},
loginFailure(state) {
state.isAuthenticated = false;

9
app/src/types/Bullpen.ts Normal file
View File

@ -0,0 +1,9 @@
import Pitch from "@/types/Pitch";
export default interface Bullpen {
id: number,
startedAt: Date,
finishedAt: Date,
pitcherId: number,
pitches: Pitch[]
}

View File

@ -1,6 +1,6 @@
import PitchType from "@/types/PitchType";
export default interface BullpenPitch {
export default interface Pitch {
id: number,
date: Date,
pitchType: PitchType,

View File

@ -16,12 +16,12 @@ import {
IonTitle,
IonToolbar
} from '@ionic/vue';
import {ref} from 'vue'
import {useRouter} from 'vue-router';
import {BullpenSessionService, bullpenSessionService} from "@/services/BullpenSessionService";
import BullpenSessionService from "@/services/BullpenSessionService";
import {ref} from 'vue';
const router = useRouter();
const bps = ref<BullpenSessionService>(bullpenSessionService);
const bps = ref(BullpenSessionService);
const gotoHome = () => {
router.push('/home');

View File

@ -1,5 +1,4 @@
<script setup lang="ts">
import {defineComponent, ref} from "vue";
import {
IonContent,
IonHeader,
@ -13,20 +12,21 @@ import {
IonCardTitle, IonButton,
IonGrid, IonRow, IonCol
} from "@ionic/vue";
import {BullpenSessionService, bullpenSessionService} from "@/services/BullpenSessionService";
import BullpenSessionService from "@/services/BullpenSessionService";
import {useRouter} from "vue-router";
import {ref} from 'vue';
const router = useRouter();
const bps = ref<BullpenSessionService>(bullpenSessionService);
const bps = ref(BullpenSessionService);
const finalizeAndNextPitch = () => {
bullpenSessionService.nextPitch();
bps.value.nextPitch();
router.push({ name: 'PreparePitch' });
}
const finalizeAndEndBullpen = () => {
bullpenSessionService.nextPitch();
bullpenSessionService.finishSession();
bps.value.nextPitch();
bps.value.finishSession();
router.push({ name: 'BullpenStats' });
}

View File

@ -36,8 +36,11 @@ const showProfile = () => {
const logout = () => {
console.log('Logout');
store.dispatch('auth/logout');
router.push({ path: '/login' });
store.dispatch('auth/logout').then(() => {
router.push({ path: '/' });
}, error => {
console.log(error);
});
}
</script>
@ -62,20 +65,20 @@ const logout = () => {
<div class="user-name">{{ user.firstName }} {{ user.lastName }}</div>
</div>
<div class="button-container">
<ion-button expand="full" @click="startBullpen" class="full-width">
<div class="button-grid">
<ion-button @click="startBullpen" class="grid-button">
<ion-icon :icon="playOutline" slot="start" />
Start Bullpen Session
</ion-button>
<ion-button expand="full" @click="showStats" class="full-width">
<ion-button @click="showStats" class="grid-button">
<ion-icon :icon="statsChartOutline" slot="start" />
Show Bullpen Stats
</ion-button>
<ion-button expand="full" @click="showProfile" class="full-width">
<ion-button @click="showProfile" class="grid-button">
<ion-icon :icon="personOutline" slot="start" />
Show Profile
</ion-button>
<ion-button expand="full" @click="logout" class="full-width">
<ion-button @click="logout" class="grid-button">
<ion-icon :icon="logOutOutline" slot="start" />
Logout
</ion-button>
@ -87,10 +90,12 @@ const logout = () => {
<style scoped>
.user-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 30vh;
background-color: #f0f0f0; /* Change background color of top area */
background-color: #f0f0f0;
padding: 5px;
}
.user-avatar {
@ -99,6 +104,9 @@ const logout = () => {
border-radius: 50%;
border: 4px solid #ccc;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
.avatar-frame {
@ -108,19 +116,33 @@ const logout = () => {
border-radius: 50%;
}
.button-container {
display: flex;
flex-direction: column;
gap: 10px;
height: 60vh;
justify-content: flex-start;
align-items: center;
width: 100%;
padding-top: 20px;
.avatar-placeholder {
font-size: 60px;
color: #888;
}
.full-width {
.user-name {
margin-top: 10px;
font-size: 18px;
font-weight: bold;
color: #333;
}
.button-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
padding-top: 10px;
width: 100%;
}
.grid-button {
height: 60px;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
margin-inline: 0 !important;
}
</style>

View File

@ -20,7 +20,6 @@ import { lockClosedOutline, personOutline } from 'ionicons/icons';
import { useForm } from 'vee-validate';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex'
import { AppStore } from '@/store';
import * as yup from 'yup';
const loading = ref(false);
@ -36,7 +35,7 @@ const [email, emailAttrs] = defineField('email');
const [password, passwordAttrs] = defineField('password');
const router = useRouter();
const store = useStore<AppStore>();
const store = useStore();
const loggedIn = computed(() => store.state.auth.isAuthenticated);
@ -46,12 +45,13 @@ onMounted(() => {
}
});
const submit = handleSubmit(values => {
const submit = handleSubmit((values, { resetForm }) => {
store.dispatch('auth/login', {
email: values.email,
password: values.password,
}).then(
() => {
resetForm();
onLogin();
},
error => {
@ -64,6 +64,7 @@ const submit = handleSubmit(values => {
}
);
}, ({errors}) => {
console.log(errors);
loading.value = false;
});

View File

@ -4,19 +4,20 @@ import { useRouter } from "vue-router";
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonList, IonItem, IonLabel } from '@ionic/vue';
import UserService from "@/services/UserService";
import User from "@/types/User";
import {bullpenSessionService} from "@/services/BullpenSessionService";
import BullpenSessionService from "@/services/BullpenSessionService";
const pitchers = ref<User[]>([]);
const router = useRouter();
const bps = ref(BullpenSessionService);
bullpenSessionService.clear();
bps.value.clear();
onMounted(async () => {
pitchers.value = await UserService.getAllUsers();
});
const goToPreparePitch = (pitcher: User) => {
bullpenSessionService.startSession( pitcher );
bps.value.startSession( pitcher );
router.push({ name: 'PreparePitch' });
};

View File

@ -16,12 +16,12 @@ import {
IonCardTitle,
} from "@ionic/vue";
import PitchType from "@/types/PitchType";
import {BullpenSessionService, bullpenSessionService} from "@/services/BullpenSessionService";
import BullpenSessionService from "@/services/BullpenSessionService";
import {useRouter} from "vue-router";
const router = useRouter();
const pitchTypes = ref<PitchType[]>([]);
const bps = ref<BullpenSessionService>(bullpenSessionService);
const bps = ref(BullpenSessionService);
onMounted(async () => {
pitchTypes.value = PitchTypeService.getLocalPitchTypes();

View File

@ -17,7 +17,13 @@ exports.insert = (req, res) => {
};
exports.findAll = (req, res) => {
const { user } = req.query;
const filter = {};
if (user) {
filter.pitcherId = parseInt(user, 10);
}
BullpenSession.findAll({
where: filter,
include: {
model: Pitch,
as: 'pitches'

View File

@ -32,12 +32,58 @@ describe("Test bullpen session", () => {
expect(bullpenSessionData.pitches).toBeDefined();
expect(Array.isArray(bullpenSessionData.pitches)).toBe(true);
expect(bullpenSessionData.pitches.length).toBe(2);
});
test.skip("should get all bullpen sessions", async () => {
let response = await request(app)
.post("/api/auth/login")
.send({
email: 'player@example.com',
password: 'hash1234'
});
const user = response.body;
response = await request(app)
.get(`/api/bullpen_session/${bullpenSessionData.id}`)
.get("/api/bullpen_session")
.set('x-access-token', user.accessToken);
expect(response.statusCode).toBe(200);
// console.log(JSON.stringify(response.body, null, 2));
});
expect(response.statusCode).toBe(200);
const bullpenSessionDataArray = await response.body;
expect(bullpenSessionDataArray).toBeDefined();
expect(Array.isArray(bullpenSessionDataArray)).toBe(true);
expect(bullpenSessionDataArray.length).toBe(1);
const bullpenSessionData = bullpenSessionDataArray[0];
expect(bullpenSessionData.id).toBeDefined();
expect(bullpenSessionData.id).toBeGreaterThan(0);
expect(bullpenSessionData.pitches).toBeDefined();
expect(Array.isArray(bullpenSessionData.pitches)).toBe(true);
expect(bullpenSessionData.pitches.length).toBe(2);
})
test("should get all bullpen sessions for user", async () => {
let response = await request(app)
.post("/api/auth/login")
.send({
email: 'player@example.com',
password: 'hash1234'
});
const user = response.body;
response = await request(app)
.get("/api/bullpen_session")
.set('x-access-token', user.accessToken)
.query({ user: user.id });
expect(response.statusCode).toBe(200);
const bullpenSessionDataArray = await response.body;
expect(bullpenSessionDataArray).toBeDefined();
expect(Array.isArray(bullpenSessionDataArray)).toBe(true);
expect(bullpenSessionDataArray.length).toBe(1);
const bullpenSessionData = bullpenSessionDataArray[0];
expect(bullpenSessionData.id).toBeDefined();
expect(bullpenSessionData.id).toBeGreaterThan(0);
expect(bullpenSessionData.pitches).toBeDefined();
expect(Array.isArray(bullpenSessionData.pitches)).toBe(true);
expect(bullpenSessionData.pitches.length).toBe(2);
})
})