Skip to content

Commit

Permalink
Merge pull request #141 from WildCodeSchool/56/delete-article
Browse files Browse the repository at this point in the history
56/delete article
  • Loading branch information
Sojabio authored Dec 12, 2024
2 parents d6f1355 + d763148 commit 79ad020
Show file tree
Hide file tree
Showing 11 changed files with 362 additions and 18 deletions.
23 changes: 23 additions & 0 deletions backend/src/resolvers/ArticleResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class NewArticleInput {
@Field(() => String)
productId: number;
}

@Resolver(Article)
class ArticleResolver {
@Query(() => [Article])
Expand Down Expand Up @@ -51,6 +52,28 @@ class ArticleResolver {
await Article.delete(idToDelete);
return `Product deleted successfully`;
}

@Mutation(() => Article)
async deleteArticleFromReservation(@Arg("articleId") articleId: string) {
const article = await Article.findOne({
where: { id: Number.parseInt(articleId) },
relations: { reservations: true },
});

if (!article) {
throw new Error("Article not found");
}

if (!article.reservations) {
throw new Error("Article is not part of any reservation");
}

article.reservations = [];

await article.save();

return article;
}
}

export default ArticleResolver;
23 changes: 19 additions & 4 deletions backend/src/resolvers/ReservationResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,19 @@ class ReservationResolver {
where: { user: { id: context.id } },
relations: ["user", "articles", "articles.product"],
order: {
createdAt: "DESC"
createdAt: "DESC",
},
});
return reservations.map(reservation => {

return reservations.map((reservation) => {
const totalPrice = calculateTotal(reservation.articles);
return { reservation, totalPrice };
});
} else {
return [];
}
}

@Mutation(() => Reservation)
async handleReservation(
@Ctx() context: Context,
Expand Down Expand Up @@ -174,6 +174,21 @@ class ReservationResolver {

return reservation;
}

@Mutation(() => Reservation)
async cancelReservation(@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.Ended;
await reservation.save();

return reservation;
}
}

export default ReservationResolver;
67 changes: 67 additions & 0 deletions frontend/src/components/ArticleReservationCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Card, Divider } from "antd";
import { ReservationData } from "../interface/types";
import ValidateReservationButton from "./ValidateReservationButton";
import CancelReservationButton from "./CancelReservationButton";
import DeleteArticleReservationButton from "./DeleteArticleReservationButton";

export const ArticleReservationCard = ({
reservationData,
}: {
reservationData: ReservationData;
}) => {
const articles = reservationData.reservation.articles;

return (
<>
{reservationData.reservation.status === "pending" ? (
<Card title={`Détails de votre réservation`} style={{ width: 500 }}>
{articles.map((article) => (
<Card style={{ margin: 20 }} key={article.product?.id}>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
<div style={{ display: "flex", alignItems: "center" }}>
<img
src={article.product?.imgUrl}
alt="product img"
style={{ height: 100, marginRight: 20 }}
/>
<div>
<p style={{ margin: 0, fontWeight: "bold" }}>
{article.product?.name}
</p>
<p style={{ margin: 0 }}>{article.product?.price}</p>
</div>
</div>
<DeleteArticleReservationButton
articleId={article.id}
reservationData={reservationData}
/>
</div>
</Card>
))}
<div style={{ display: "flex", justifyContent: "space-around" }}>
{reservationData.reservation.status === "pending" && (
<ValidateReservationButton
reservation={reservationData.reservation}
/>
)}
{reservationData.reservation.status === "pending" && (
<CancelReservationButton
reservation={reservationData.reservation}
/>
)}
</div>
</Card>
) : (
<h1>Aucune réservation en cours.</h1>
)}

<Divider dashed />
</>
);
};
45 changes: 45 additions & 0 deletions frontend/src/components/CancelReservationButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useMutation } from "@apollo/client";
import { Button, message, Popconfirm } from "antd";
import { CANCEL_RESERVATION } from "../graphql/mutations";
import { Reservation } from "../interface/types";
import {
GetCurrentReservationByUserIdDocument,
GetReservationsByUserIdDocument,
} from "../generated/graphql-types";

function CancelReservationButton({ reservation }: Reservation) {
const [cancelReservation] = useMutation(CANCEL_RESERVATION, {
onCompleted: () => {
message.success("La réservation a bien été annulée.");
},
onError: () => {
message.error("Une erreur est survenue lors de l'annulation.");
},
refetchQueries: [
GetReservationsByUserIdDocument,
GetCurrentReservationByUserIdDocument,
],
});

return (
<>
<Popconfirm
title="Annuler cette réservation ?"
description="La réservation sera définitivement annulée."
okText="Oui"
cancelText="Non"
onConfirm={() =>
cancelReservation({
variables: {
reservationId: reservation.id.toString(),
},
})
}
>
<Button danger>Annuler la réservation</Button>
</Popconfirm>
</>
);
}

export default CancelReservationButton;
12 changes: 7 additions & 5 deletions frontend/src/components/CurrentReservation.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { ReservationData } from "../interface/types";
import { ReservationCard } from "./ReservationCard";
import { ArticleReservationCard } from "./ArticleReservationCard";

export const CurrentReservation = ({ reservationData }: { reservationData: ReservationData }) => {
return (
<ReservationCard reservationData={reservationData} />
);
export const CurrentReservation = ({
reservationData,
}: {
reservationData: ReservationData;
}) => {
return <ArticleReservationCard reservationData={reservationData} />;
};

export default CurrentReservation;
78 changes: 78 additions & 0 deletions frontend/src/components/DeleteArticleReservationButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useMutation } from "@apollo/client";
import {
GetAllArticlesDocument,
GetCurrentReservationByUserIdDocument,
GetReservationsByUserIdDocument,
} from "../generated/graphql-types";
import { Button, message, Popconfirm } from "antd";
import { CANCEL_RESERVATION, DELETE_ARTICLE_FROM_RESERVATION } from "../graphql/mutations";
import { DeleteOutlined } from "@ant-design/icons";
import { ReservationData } from "../interface/types";
import { useEffect } from "react";

function DeleteArticleReservationButton({
reservationData,
articleId,
}: {
reservationData: ReservationData;
articleId: number;
}) {
const articlesNumber = reservationData.reservation.articles.length;
useEffect(()=> {
console.log(articlesNumber)
console.log(reservationData.reservation.articles)
}, [reservationData])
const [cancelReservation] = useMutation(CANCEL_RESERVATION);
const [deleteArticleFromReservation] = useMutation(
DELETE_ARTICLE_FROM_RESERVATION,
{
onCompleted: () => {
const remainingArticles = reservationData.reservation.articles.filter(
(article) => article.id !== articleId
).length;

if (remainingArticles === 0) {
cancelReservation({
variables: {
reservationId: reservationData.reservation.id.toString(),
},
refetchQueries: [
GetReservationsByUserIdDocument,
GetCurrentReservationByUserIdDocument,
],
});
}

message.success("L'article a bien été supprimé de la réservation.");
},
onError: () => {
message.error(
"Une erreur est survenue lors de la suppression de l'article."
);
},
refetchQueries: [
GetReservationsByUserIdDocument,
GetCurrentReservationByUserIdDocument,
GetAllArticlesDocument,
],
}
);

return (
<Popconfirm
title="Supprimer cet article ? "
description="Cet article sera définitivement supprimé de la réservation."
okText="Oui"
cancelText="Non"
onConfirm={() =>
deleteArticleFromReservation({
variables: { id: articleId.toString() },
})
}
>
<Button title="Supprimer l'article" danger icon={<DeleteOutlined />} />
</Popconfirm>
);
}

export default DeleteArticleReservationButton;
16 changes: 9 additions & 7 deletions frontend/src/components/ValidateReservationButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import {
function ValidateReservationButton({ reservation }: Reservation) {
const [updateReservationStatus] = useMutation(UPDATE_RESERVATION_STATUS, {
onCompleted: () => {
message.success("La réservation a bien été validée.")
message.success("La réservation a bien été validée.");
},
onError: () => {
message.error("Une erreur est survenue lors de la validation.");
},
refetchQueries: [GetReservationsByUserIdDocument, GetCurrentReservationByUserIdDocument]
})
refetchQueries: [
GetReservationsByUserIdDocument,
GetCurrentReservationByUserIdDocument,
],
});

return (
<>
Expand All @@ -28,13 +31,12 @@ function ValidateReservationButton({ reservation }: Reservation) {
onConfirm={() =>
updateReservationStatus({
variables: {
reservationId: reservation.id.toString() },
reservationId: reservation.id.toString(),
},
})
}
>
<Button type="primary" style={{ marginTop: "10px" }}>
Valider
</Button>
<Button type="primary">Valider la réservation</Button>
</Popconfirm>
</>
);
Expand Down
Loading

0 comments on commit 79ad020

Please sign in to comment.