Skip to content

Commit

Permalink
Merge pull request #34 from guillaume60240/feat-game-manager-front
Browse files Browse the repository at this point in the history
feat game manager front
  • Loading branch information
guillaume60240 authored May 21, 2023
2 parents a89513a + a74840e commit ec0305d
Show file tree
Hide file tree
Showing 23 changed files with 496 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,31 @@ export class BookingController {
) {
return await this.service.updateBookedDateStatus(bookedDateId, status);
}

@UseGuards(GameMasterGuard)
@Get('/booked-date/:bookedDateId')
@ApiResponse({
status: 200,
description: 'Booked Date updated',
})
@ApiResponse({
status: 500,
description: 'Internal server error',
type: InternalServerErrorException,
})
@ApiResponse({
status: 400,
description: 'Bad request',
})
@ApiResponse({
status: 403,
description: 'Non authorized',
})
@ApiOperation({
summary: 'Update booked date',
description: 'Update booked date',
})
async getBookingDateById(@Param('bookedDateId') bookedDateId: number) {
return await this.service.getBookingDateById(bookedDateId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,49 @@ export class BookingRepository {
}

async updateBookedDateStatus(bookingId: number, status: string) {
const request = await this.slonik.query(sql`
const { rows } = await this.slonik.query(sql`
UPDATE public.booking
SET status = ${status}
WHERE id = ${bookingId}
RETURNING *;
`);
return request;
return rows[0];
}

async getBookingDateById(bookingId: number) {
const { rows } = await this.slonik.query(sql`
SELECT
b.start_date AS date,
b.time_slot AS hour,
b.scenario_id AS scenarioid,
s.name AS title,
b.players AS players,
b.price AS price,
b.user_id AS userid,
b.status AS status,
b.id AS bookingid,
u.name AS username,
u.email AS useremail
FROM public.booking b
INNER JOIN public.scenario s ON s.id::integer = b.scenario_id
INNER JOIN public.user u ON u.id::integer = b.user_id
WHERE b.id = ${bookingId}
`);
return rows.map((row) => {
return {
startDate: new Date(row.date),
hour: row.hour,
scenarioId: row.scenarioid,
scenarioTitle: row.title,
players: row.players,
price: row.price,
userId: row.userid,
userName: row.username,
userEmail: row.useremail,
status: row.status,
bookingId: row.bookingid,
};
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export class BookingService {
return await this.repository.getBookingsByUserId(userId);
}

async getBookingDateById(id: number) {
return await this.repository.getBookingDateById(id);
}

async updateBookedDateStatus(id: number, status: string) {
return await this.repository.updateBookedDateStatus(id, status);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,4 @@ export class NewBookingDateDto {
@ApiProperty()
@IsNumber()
userId: number;
@ApiProperty()
@IsString()
status: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,34 @@ export class GameController {
summary: 'Close Game',
description: 'New Game',
})
async closeGAme(@Body('gameId') gameId: number): Promise<any[]> {
return await this.service.closeGame(+gameId);
async closeGAme(@Body('bookingId') bookingId: number): Promise<any[]> {
return await this.service.closeGame(+bookingId);
}

@UseGuards(GameMasterGuard)
@Get('/game/:bookingId')
@ApiResponse({
status: 200,
description: 'Get Game',
})
@ApiResponse({
status: 500,
description: 'Erreur interne',
type: InternalServerErrorException,
})
@ApiResponse({
status: 403,
description: 'Forbidden',
})
@ApiResponse({
status: 400,
description: 'Bad Request',
})
@ApiOperation({
summary: 'Get Game',
description: 'Get Game',
})
async getGame(@Param('bookingId') bookingId: number): Promise<any[]> {
return await this.service.getGameByBookingId(+bookingId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ export class GameManagerRepository {
return rows[0];
}

async closeGame(gameId: number, duration: number): Promise<any> {
async closeGame(bookingId: number, duration: number): Promise<any> {
const endedAt = new Date();
const { rows } = await this.slonik.query(sql`
UPDATE public.game
SET ended_at = ${endedAt.toISOString()}
, duration = ${duration}
WHERE id = ${gameId}
WHERE booking_id = ${bookingId}
RETURNING booking_id
`);
return rows[0];
Expand All @@ -45,4 +45,12 @@ export class GameManagerRepository {
`);
return rows[0];
}

async getGameByBookingId(bookingId: number): Promise<any> {
const { rows } = await this.slonik.query(sql`
SELECT * FROM public.game
WHERE booking_id = ${bookingId}
`);
return rows[0];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,25 @@ export class GameService {
if (!updateBookedDate) {
throw new Error("La réservation n'a pas pu être mise à jour");
}
return updateBookedDate;
}
return {
id: request.id,
};
throw new Error("La partie n'a pas pu être créée");
}

async closeGame(gameId: number): Promise<any> {
const gameToUpdate = await this.repository.getGameById(gameId);
async closeGame(bookingId: number): Promise<any> {
const gameToUpdate = await this.repository.getGameByBookingId(bookingId);
if (!gameToUpdate) {
throw new Error("La partie n'existe pas");
}
if (!gameToUpdate.ended_at) {
const startedAt = new Date(gameToUpdate.started_at);
const endedAt = new Date();
const duration = endedAt.getTime() - startedAt.getTime();
const durationInSecond = Math.round(duration / 1000);
const request = await this.repository.closeGame(gameId, durationInSecond);
const request = await this.repository.closeGame(
bookingId,
durationInSecond,
);
if (request.booking_id) {
const updateBookedDate =
await this.bookingService.updateBookedDateStatus(
Expand All @@ -51,12 +56,18 @@ export class GameService {
if (!updateBookedDate) {
throw new Error("La réservation n'a pas pu être mise à jour");
}
return updateBookedDate;
}
return {
id: request.id,
};
} else {
throw new Error('La partie est déjà terminée');
}
}

async getGameByBookingId(bookingId: number): Promise<any> {
const request = await this.repository.getGameByBookingId(bookingId);
if (!request) {
throw new Error("La partie n'existe pas");
}
return request;
}
}
133 changes: 133 additions & 0 deletions apps/mobile-app/src/components/AlertGame.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<template>
<div class="wrapper">
<div :class="[state.timeOut ? 'danger' : 'success', 'chrono']">
Durée de jeu : {{ state.chronoTime }}
</div>
<span class="alert" v-if="state.timeOut"></span>
</div>
</template>

<script setup lang="ts">
import { reactive, watchEffect } from "vue";
import { getScenarioById } from "@/services/api-request/scenario-manager/scenario-manager-request";
const props = defineProps<{
game: {
id: number;
started_at: string;
ended_at: string;
duration: number;
booking_id: number;
scenario_id: number;
}[];
}>();
const state = reactive<{
chronoStart: number;
scenario: {
description: string;
difficulty: number;
duration: number;
id: number;
imgUrl: string;
maxPlayers: number;
minPlayers: number;
title: string;
summary: string;
} | null;
maxChrono: number;
timeOut: boolean;
chronoTime: string;
}>({
chronoStart: 0,
scenario: null,
maxChrono: 0,
timeOut: false,
chronoTime: "",
});
function calcChronoStart() {
const now = new Date();
const startedAt = new Date(props.game[0].started_at);
state.chronoStart = now.getTime() - startedAt.getTime();
}
function incrementChrono() {
setTimeout(() => {
state.chronoStart += 100;
state.chronoTime = getChronoTime(state.chronoStart);
if (state.chronoStart >= state.maxChrono) {
state.timeOut = true;
}
incrementChrono();
}, 100);
}
async function getScenario(id: number) {
state.scenario = await getScenarioById(id);
if (state.scenario != null) {
state.maxChrono = state.scenario.duration * 60 * 1000;
state.chronoTime = getChronoTime(state.chronoStart);
calcChronoStart();
incrementChrono();
}
}
function getChronoTime(chronoStart: number) {
const hours = Math.floor(chronoStart / 3600000);
const minutes = Math.floor((chronoStart - hours * 3600000) / 60000);
const seconds = Math.floor(
(chronoStart - hours * 3600000 - minutes * 60000) / 1000
);
const milliseconds = Math.floor(
chronoStart - hours * 3600000 - minutes * 60000 - seconds * 1000
);
return `${hours}h ${minutes}mins ${seconds}:${milliseconds}`;
}
watchEffect(async () => {
if (props.game[0]?.scenario_id) {
await getScenario(props.game[0].scenario_id);
}
});
</script>

<style scoped lang="css">
.wrapper {
position: relative;
}
.chrono {
width: 300px;
}
.success {
color: var(--ion-color-success);
}
.danger {
color: var(--ion-color-danger);
}
.alert {
width: 10px;
height: 10px;
border-radius: 50%;
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
margin-left: 10px;
background-color: var(--ion-color-danger);
animation-duration: 0.8s;
animation-name: clignoter;
animation-iteration-count: infinite;
transition: none;
}
@keyframes clignoter {
0% {
opacity: 1;
}
40% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>
Loading

0 comments on commit ec0305d

Please sign in to comment.