Compare commits

..

10 Commits

11 changed files with 167 additions and 97 deletions

4
app/package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "app",
"version": "1.1.0",
"version": "1.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "app",
"version": "1.1.0",
"version": "1.1.1",
"dependencies": {
"@capacitor/android": "6.1.2",
"@capacitor/app": "6.0.1",

View File

@ -1,7 +1,7 @@
{
"name": "app",
"private": true,
"version": "1.1.0",
"version": "1.1.1",
"type": "module",
"scripts": {
"dev": "vite",

View File

@ -95,7 +95,7 @@ const logoutUser = () => {
<ion-icon slot="icon-only" :icon="chevronBack"></ion-icon>
</ion-button>
</ion-buttons>
<ion-title>Menu Content</ion-title>
<ion-title>User Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>

View File

@ -30,7 +30,7 @@ export class BullpenSessionService extends ApiService<Bullpen> {
}
}
public findByPitcherId(id: number, page: number, size: number): Promise<Pageable<Bullpen>> {
public fetchAllByUser(id: number, page: number, size: number): Promise<Pageable<Bullpen>> {
return api
.get('/bullpen_session', { params: {
user: id,

View File

@ -15,20 +15,20 @@ class PlayerService extends ApiService<Player> {
gender: 'male',
bats: 'right',
throws: 'right',
height: 187,
weight: 84,
height: 0,
weight: 0,
state: 'active',
jerseyNumber: 23,
jerseyNumber: 0,
createdAt: new Date(),
updatedAt: new Date(),
user: {
id: 0,
auth: {
email: 'test@de.de',
password: 'test$123'
email: '',
password: ''
},
firstName: 'Demo',
lastName: 'Player',
firstName: '',
lastName: '',
dateOfBirth: new Date(),
roles: ['player'],
createdAt: new Date(),

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import {computed, ref} from 'vue';
import {computed, ref, reactive} from 'vue';
import {
IonPage,
IonHeader,
@ -7,24 +7,33 @@ import {
IonTitle,
IonContent,
IonAvatar,
IonButton,
IonButtons,
IonIcon,
IonMenuButton,
IonFab,
IonFabButton
IonFabButton,
IonInfiniteScroll,
IonInfiniteScrollContent,
InfiniteScrollCustomEvent,
IonList,
IonItem,
IonLabel, IonBadge,
} from '@ionic/vue';
import {
playOutline,
statsChartOutline,
personOutline,
baseball,
add,
personAddOutline
personAddOutline, baseballOutline
} from 'ionicons/icons';
import {useStore} from "vuex";
import {useRouter} from "vue-router";
import BullpenSessionService from "@/services/BullpenSessionService";
import TokenService from "@/services/TokenService";
import dayjs from "dayjs";
import Bullpen from "@/types/Bullpen";
import PitchType from "@/types/PitchType";
const router = useRouter();
const store = useStore();
@ -60,6 +69,39 @@ const addPlayer = () => {
router.push({ path: '/player/create' });
}
const items = reactive<Bullpen[]>([]);
const page = ref(0);
const generateItems = () => {
BullpenSessionService
.fetchAllByUser(user.value.id, page.value, 10)
.then((bullpens) => {
++page.value;
bullpens.data.forEach((bullpen: Bullpen) => {
items.push(bullpen);
})
}, error => {
console.log(error);
});
};
const formatDate = (date: Date) => {
return dayjs(date).format('YYYY.MM.DD HH:mm');
}
// const determinePitchTypeName = (id: number): string => {
// const pitchType = store.state.pitchTypes.find((pitchType: PitchType) => pitchType.id === id);
//
// return pitchType?.name ?? 'Unknown';
// }
const ionInfinite = (event: InfiniteScrollCustomEvent) => {
generateItems();
setTimeout(() => event.target.complete(), 500);
};
generateItems();
</script>
<template>
@ -75,7 +117,24 @@ const addPlayer = () => {
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-content>
<ion-list>
<ion-item v-for="(bullpen, index) in items" :key="index">
<ion-icon aria-hidden="true" :icon="baseball" slot="start"></ion-icon>
<ion-label>Bullpen from ({{formatDate(bullpen.startedAt)}})</ion-label>
<!-- <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-item>
</ion-list>
<ion-infinite-scroll @ionInfinite="ionInfinite">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
<!-- <div class="user-container">-->
<!-- <ion-avatar class="user-avatar">-->
<!-- <template v-if="userImage">-->

View File

@ -1,37 +1,12 @@
services:
db:
image: postgres:15
restart: unless-stopped
env_file: ./.env.development
environment:
POSTGRES_DB: $DB_NAME
POSTGRES_USER: $DB_USER
POSTGRES_PASSWORD: $DB_PASSWORD
postgres:
image: postgres:14-alpine
container_name: postgres14
ports:
- $DB_PORT:$DB_PORT
- "5432:5432"
volumes:
- db_data:/var/lib/postgresql/data
app-dev:
image: node:20-alpine
restart: unless-stopped
env_file: ./.env.development
working_dir: /app
volumes:
- .:/app
- /app/node_modules
ports:
- '$NODE_LOCAL_PORT:$NODE_DOCKER_PORT'
- ~/apps/postgres:/var/lib/postgresql/data
environment:
NODE_ENV: development
DB_HOST: db
DB_PORT: $DB_PORT
DB_NAME: $DB_NAME
DB_USER: $DB_USER
DB_PASS: $DB_PASSWORD
command: sh -c "npm install && npm run dev"
depends_on:
- db
volumes:
db_data:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: bullpen-dev

View File

@ -1,12 +1,12 @@
{
"name": "bullpen-backend",
"version": "1.1.0",
"version": "1.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bullpen-backend",
"version": "1.1.0",
"version": "1.1.1",
"license": "ISC",
"dependencies": {
"bcryptjs": "^3.0.2",

View File

@ -1,6 +1,6 @@
{
"name": "bullpen-backend",
"version": "1.1.0",
"version": "1.1.1",
"main": "server.js",
"scripts": {
"prebuild": "node -p \"'const BULLPEN_VERSION = ' + JSON.stringify(require('./package.json').version) + ';'\"\n\nmodule.exports = BULLPEN_VERSION; > config/version.js",
@ -15,6 +15,9 @@
"start:prod": "npm run cross-env NODE_ENV=production node server.js",
"start:dev": "cross-env NODE_ENV=development nodemon server.js",
"migrate:dev": "cross-env NODE_ENV=development npx sequelize-cli db:migrate",
"seed:bullpen": "cross-env NODE_ENV=development npx sequelize-cli db:seed --seed 05-bullpens.js",
"dev:db:start": "docker-compose -f docker-compose.dev.yml up -d",
"dev:db:stop": "docker-compose -f docker-compose.dev.yml down -v",
"test:db:start": "docker-compose -f docker-compose.test.yml up -d",
"test:db:stop": "docker-compose -f docker-compose.test.yml down -v",
"test:run": "dotenv -e .env.test -- jest --runInBand --detectOpenHandles",

View File

@ -16,5 +16,8 @@ docker-compose up --build -d
docker-compose exec app npx sequelize-cli db:migrate
docker-compose exec app npx sequelize-cli db:seed:all
// seed one specific file
docker-compose exec app npx sequelize db:seed --seed my_seeder_file.js
docker-compose exec app sh
```

View File

@ -1,48 +1,69 @@
const process = require('process');
const {createPlayer, createUsers} = require("../helper/seeder.helper");
const createBullpen = async (queryInterface, demoPlayer) => {
const pickRandomValueFromArray = (values) => {
return values[Math.floor(Math.random() * values.length)];
}
const shouldMatch = (percentage) => {
return Math.random() * 100 < percentage;
}
const createBullpens = async (queryInterface, demoPlayer) => {
const startDate = new Date();
const endDate = new Date(new Date().setTime(startDate.getTime() + 10 * 60000));
// const endDate = new Date(new Date().setTime(startDate.getTime() + (10 * 60000)));
// create 20 bullpens for demo player
const bullpens = [...Array(20).keys()].map(key => {
const days = 5 + key;
const startedAt = new Date(new Date().setDate(startDate.getDate() - days));
return {
pitcherId: demoPlayer.user.id,
startedAt: new Date(new Date().setDate(startDate.getDate()-5)),
finishedAt: new Date(new Date().setDate(startDate.getDate()-5)),
pitcherId: demoPlayer.userId,
startedAt: startedAt,
finishedAt: new Date(new Date().setTime(startedAt.getTime() + (10 * 60000))),
createdAt: new Date(),
updatedAt: new Date()
}
})
await queryInterface.bulkInsert('BullpenSessions', bullpens);
const pitchTypeIds = await queryInterface
.select(null, 'PitchTypes')
const pitchTypeIds = (await queryInterface
.select(null, 'PitchTypes'))
.map(pitchType => pitchType.id);
// red: 21-28
// orange: 11-18:
// green: 1-9
const bullpenChart = [
[21,22,23,24,25,26,27,28],
[11,12,13,14,15,16,17,18],
[1,2,3,4,5,6,7,8,9]
]
1,2,3,4,5,6,7,8,9,
11,12,13,14,15,16,17,18,
21,22,23,24,25,26,27,28
];
const dbBullpens = await queryInterface.select(null, 'BullpenSessions', {
where: {
pitcherId: demoPlayer.user.id
pitcherId: demoPlayer.userId
}
});
[...Array(20).keys()].map(key => {
return {
pitchTypeId: pitchTypeIds[Math.floor(Math.random() * pitchTypeIds.length)],
pitchTime: new Date(2025, 3, 22, 16, 7, 21),
aimedArea: 11,
hitArea: 12
}
// fill pitches for each bullpen
const pitches = dbBullpens.map(bullpen => {
return [...Array(20).keys()].map(key => {
const aimedArea = pickRandomValueFromArray(bullpenChart);
const hitArea = shouldMatch(30) ? aimedArea : pickRandomValueFromArray(bullpenChart);
return {
pitchTypeId: pickRandomValueFromArray(pitchTypeIds),
bullpenSessionId: bullpen.id,
pitchTime: new Date(new Date().setTime(bullpen.startedAt.getTime() + key * 60000)),
aimedArea: aimedArea,
hitArea: hitArea,
createdAt: new Date(),
updatedAt: new Date()
};
});
});
await queryInterface.bulkInsert('Pitches', pitches.flat());
}
/** @type {import('sequelize-cli').Migration} */
@ -50,34 +71,43 @@ module.exports = {
async up (queryInterface, /*Sequelize*/) {
if (process.env.NODE_ENV !== 'development') return;
const roles = await queryInterface.select(null, 'Roles');
const players = [{
email: 'demo@bullpen.com',
password: 'demo$123',
firstName: 'Demo',
lastName: 'Player',
dateOfBirth: new Date(1975, 6, 19),
jerseyNumber: 33,
height: 187,
weight: 85,
gender: 'male',
bats: 'right',
throws: 'right',
state: 'active'
}];
let demoPlayer = (await queryInterface.select(null, 'Players', {
where: {
height: 187,
weight: 85,
}
})).shift();
const dbPlayers = await createPlayer(queryInterface, roles, players);
const demoPlayer = dbPlayers
.filter(player => player.user.auth.email === 'demo@bullpen.com').shift();
if (demoPlayer === undefined) {
const roles = await queryInterface.select(null, 'Roles');
const players = [{
email: 'demo@bullpen.com',
password: 'demo$123',
firstName: 'Demo',
lastName: 'Player',
dateOfBirth: new Date(1975, 6, 19),
jerseyNumber: 33,
height: 187,
weight: 85,
gender: 'male',
bats: 'right',
throws: 'right',
state: 'active'
}];
for (let i = 0; i < 10; ++i) {
createBullpen(queryInterface, demoPlayer);
await createPlayer(queryInterface, roles, players);
demoPlayer = (await queryInterface.select(null, 'Players', {
where: {
height: 187,
weight: 85,
}
})).shift();
}
await createBullpens(queryInterface, demoPlayer);
},
async down (queryInterface, /*Sequelize*/) {
if (process.env.NODE_ENV !== 'development') return;
return;
async down (/*queryInterface,*/ /*Sequelize*/) {
// if (process.env.NODE_ENV !== 'development') return;
}
};