Skip to content

Commit

Permalink
Merge pull request #115 from WildCodeSchool/feature/57/validate-reser…
Browse files Browse the repository at this point in the history
…vation

feature/57/validate-reservation: updated reservation status to valida…
  • Loading branch information
hxfsa authored Oct 11, 2024
2 parents 87dee62 + 5412efd commit cc26b18
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 112 deletions.
222 changes: 126 additions & 96 deletions backend/src/resolvers/ReservationResolver.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import { Context } from "src"
import { Reservation, ReservationStatus } from "../entities/reservation"
import { Arg, Ctx, Field, InputType, Mutation, ObjectType, Query, Resolver } from "type-graphql"
import { calculateTotal } from "../utils/reservation/calculateTotal"
import { Article } from "../entities/article"
import { Context } from "src";
import { Reservation, ReservationStatus } from "../entities/reservation";
import {
Arg,
Ctx,
Field,
InputType,
Mutation,
ObjectType,
Query,
Resolver,
} from "type-graphql";
import { calculateTotal } from "../utils/reservation/calculateTotal";
import { Article } from "../entities/article";

// custom object created to send the totalPrice along with the reservation data
@ObjectType()
export class ReservationWithTotal {
@Field(() => Reservation)
reservation: Reservation;
@Field(() => Reservation)
reservation: Reservation;

@Field(() => Number)
totalPrice: number;
@Field(() => Number)
totalPrice: number;
}

@InputType()
Expand All @@ -23,110 +32,131 @@ class NewReservationInput {
endDate: Date;

@Field(() => String)
articleId: number
articleId: number;
}

@Resolver(Reservation)
class ReservationResolver {
@Query(() => [Reservation])
async getAllReservations() {
const reservations = await Reservation.find({ relations: ['user', 'articles', 'articles.product'] });
return reservations;
}
@Query(() => [Reservation])
async getAllReservations() {
const reservations = await Reservation.find({
relations: ["user", "articles", "articles.product"],
});
return reservations;
}

@Query(() => Reservation)
async getOneReservationById(@Arg("reservationId") reservationId: string) {
const reservation = await Reservation.findOne({ where: {id: Number.parseInt(reservationId)}, relations: ['user', 'articles', 'articles.product'] })
return reservation;
}
@Query(() => Reservation)
async getOneReservationById(@Arg("reservationId") reservationId: string) {
const reservation = await Reservation.findOne({
where: { id: Number.parseInt(reservationId) },
relations: ["user", "articles", "articles.product"],
});
return reservation;
}

@Query(() => ReservationWithTotal)
async getCurrentReservationByUserId(@Ctx() context: Context) {
if (context.id !== undefined) {
const reservation = await Reservation.findOne({ where: {user: {id: context.id}}, order: {createdAt: 'DESC'}, relations: ['user', 'articles', 'articles.product'] })
if (reservation)
{const totalPrice = calculateTotal(reservation.articles)
return {reservation, totalPrice}}
else {
return null
} ;
}
else {
return []
}
@Query(() => ReservationWithTotal)
async getCurrentReservationByUserId(@Ctx() context: Context) {
if (context.id !== undefined) {
const reservation = await Reservation.findOne({
where: { user: { id: context.id } },
order: { createdAt: "DESC" },
relations: ["user", "articles", "articles.product"],
});
if (reservation) {
const totalPrice = calculateTotal(reservation.articles);
return { reservation, totalPrice };
} else {
return null;
}
} else {
return [];
}
}

@Query(() => [Reservation])
async getReservationsByUserId(@Ctx() context: Context) {
if (context.id !== undefined) {
const reservations = await Reservation.find({ where: {user: {id: context.id}}, relations: ['user', 'articles', 'articles.product'] })
return reservations;
@Query(() => [Reservation])
async getReservationsByUserId(@Ctx() context: Context) {
if (context.id !== undefined) {
const reservations = await Reservation.find({
where: { user: { id: context.id } },
relations: ["user", "articles", "articles.product"],
});
return reservations;
} else {
return []
return [];
}
}

@Mutation(() => Reservation)
async handleReservation(
@Ctx() context: Context,
@Arg("data") reservationData: NewReservationInput
) {
if (!context.id) {
throw new Error("User not authenticated");
}

@Mutation(() => Reservation)
async handleReservation(
@Ctx() context: Context,
@Arg("data") reservationData: NewReservationInput
) {
if (!context.id) {
throw new Error("User not authenticated");
// Check if user already has a pending reservation
let reservation = await Reservation.findOne({
where: {
user: { id: context.id },
status: ReservationStatus.Pending,
},
relations: ["articles"],
});

// If no pending reservation exists, create a new reservation
if (!reservation) {
const article = await Article.findOne({
where: { id: Number(reservationData.articleId) },
});
if (!article) {
throw new Error("Article not found");
}

// Check if user already has a pending reservation
let reservation = await Reservation.findOne({
where: {
user: { id: context.id },
status: ReservationStatus.Pending,
},
relations: ["articles"],
})

// If no pending reservation exists, create a new reservation
if (!reservation) {
const article = await Article.findOne({
where: { id: Number(reservationData.articleId) },
});
if (!article) {
throw new Error("Article not found")
}

reservation = Reservation.create({
startDate: reservationData.startDate,
endDate: reservationData.endDate,
articles: [article],
user: { id: context.id },
status: ReservationStatus.Pending,
})
await reservation.save();
} else {
// If a pending reservation exists, add the article to the reservation
const articleToAdd = await Article.findOne({
where: { id: Number(reservationData.articleId) },
})
if (!articleToAdd) {
throw new Error("Article not found");
}

// Check if article was already in the reservation
const isAlreadyInReservation = reservation.articles.some(
(article) => article.id === articleToAdd.id
)
if (!isAlreadyInReservation) {
reservation.articles.push(articleToAdd)
}

await reservation.save()

reservation = Reservation.create({
startDate: reservationData.startDate,
endDate: reservationData.endDate,
articles: [article],
user: { id: context.id },
status: ReservationStatus.Pending,
});
await reservation.save();
} else {
// If a pending reservation exists, add the article to the reservation
const articleToAdd = await Article.findOne({
where: { id: Number(reservationData.articleId) },
});
if (!articleToAdd) {
throw new Error("Article not found");
}
return reservation;
}

}
// Check if article was already in the reservation
const isAlreadyInReservation = reservation.articles.some(
(article) => article.id === articleToAdd.id
);
if (!isAlreadyInReservation) {
reservation.articles.push(articleToAdd);
}

export default ReservationResolver;
await reservation.save();
}
return reservation;
}

@Mutation(() => Reservation)
async updateReservationStatus(@Arg("reservationId") reservationId: string) {
const reservation = await Reservation.findOne({
where: { id: Number.parseInt(reservationId) },
});

if (!reservation) {
throw new Error("Reservation not found");
}
reservation.status = ReservationStatus.Validated;
await reservation.save();

return reservation;
}
}

export default ReservationResolver;
1 change: 1 addition & 0 deletions frontend/src/components/ReservationButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export default function ReservationButton({
return;
}


// TO BE DISCUSSED : comment choisir l'article si plusieurs sont dispo ?
const firstAvailableArticleId = availableArticles[0].id;

Expand Down
34 changes: 24 additions & 10 deletions frontend/src/components/ReservationCard.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import { Reservation } from "../interface/types";
import { Card, Divider } from "antd";
import ValidateReservationButton from "./ValidateReservationButton";

export const ReservationCard = ({ reservation }: Reservation) => {
const formattedStartDate = new Date(reservation.startDate).toLocaleDateString(
"fr-FR"
);
const formattedEndDate = new Date(reservation.endDate).toLocaleDateString(
"fr-FR"
);

const reservationId = reservation.id;
console.log(reservation, "rser");
return (
<div>
<div>id de la réservation : {reservation.id} </div>
<div>date de début : {reservation.startDate} </div>
<div>date de fin : {reservation.endDate} </div>
<div>nombre d'articles : {reservation.articles.length}</div>
<div>prix : </div>
<div>status: {reservation.status}</div>
<div>détails</div>
<div>-------</div>
</div>
<>
<Card title={`Réservation numéro ${reservationId}`}>
<p>Date de début : {formattedStartDate} </p>
<p>Date de fin : {formattedEndDate} </p>
<p>Nombre d'articles : {reservation.articles.length}</p>
<p>Prix : </p>
<p>Status : {reservation.status}</p>
{reservation.status === "pending" && (
<ValidateReservationButton reservation={reservation} />
)}
</Card>
<Divider dashed />
</>
);
};
47 changes: 47 additions & 0 deletions frontend/src/components/ValidateReservationButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useMutation } from "@apollo/client";
import { Button, message, Popconfirm } from "antd";
import { UPDATE_RESERVATION_STATUS } from "../graphql/mutations";
import { Reservation } from "../interface/types";
import {
GetAllArticlesDocument,
GetAllProductsDocument,
} from "../generated/graphql-types";

function ValidateReservationButton({ reservation }: Reservation) {
const [updateReservationStatus] = useMutation(UPDATE_RESERVATION_STATUS, {
onCompleted: () => {
message.success("La réservation a bien été validée.");
setTimeout(function () {
window.location.reload();
}, 2000);
},
onError: () => {
message.error("Une erreur est survenue lors de la validation.");
},
});

return (
<>
<Popconfirm
title="Valider cette réservation ?"
description="La réservation ne pourra plus être annulée."
okText="Oui"
cancelText="Non"
onConfirm={() =>
updateReservationStatus({
variables: {
reservationId: reservation.id.toString(),
refetchQueries: [GetAllProductsDocument, GetAllArticlesDocument],
},
})
}
>
<Button type="primary" style={{ marginTop: "10px" }}>
Valider
</Button>
</Popconfirm>
</>
);
}

export default ValidateReservationButton;
Loading

0 comments on commit cc26b18

Please sign in to comment.