Skip to content

Commit

Permalink
feat: attach coupon on activation, add interactivity with current cou…
Browse files Browse the repository at this point in the history
…pon for partner url, copy of coupon code and validity from offer
  • Loading branch information
HoreKk committed Jan 24, 2024
1 parent a0c9ab3 commit 42168be
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 36 deletions.
74 changes: 50 additions & 24 deletions webapp/src/pages/dashboard/offer/online/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,32 @@ import {
} from "react-icons/fi";
import { TbBuildingStore } from "react-icons/tb";
import { IconType } from "react-icons/lib";
import { SetStateAction, useState } from "react";
import { useState } from "react";
import { IoCloseCircleOutline } from "react-icons/io5";
import ToastComponent from "~/components/ToastComponent";
import { OfferIncluded } from "~/server/api/routers/offer";
import Link from "next/link";

const DrawerContentComponent = ({
setIsCouponActive,
onClose,
onlyCgu,
offer,
mutateCouponToUser,
}: {
setIsCouponActive: React.Dispatch<SetStateAction<boolean>>;
onClose: () => void;
onlyCgu?: boolean;
offer: OfferIncluded;
mutateCouponToUser: ({ offer_id }: { offer_id: number }) => void;
}) => {
const validityToDate = new Date(offer.validityTo);

const cguItems: { icon: IconType; text: string; cross?: boolean }[] = [
{ icon: FiGlobe, text: "Utilisable en ligne" },
{ icon: TbBuildingStore, text: "À utiliser en magasin", cross: true },
{ icon: FiClock, text: "À utiliser avant le XX/XX/XX !" },
{
icon: FiClock,
text: `À utiliser avant le ${validityToDate.toLocaleDateString()} !`,
},
{ icon: FiRotateCw, text: "Utilisation illimité" },
{ icon: FiTag, text: "Non cumulable" },
];
Expand Down Expand Up @@ -85,11 +94,11 @@ const DrawerContentComponent = ({
<Button
rightIcon={!onlyCgu ? <ArrowForwardIcon w={6} h={6} /> : undefined}
onClick={() => {
if (!onlyCgu) setIsCouponActive(true);
if (!onlyCgu) mutateCouponToUser({ offer_id: offer.id });
onClose();
}}
>
{!onlyCgu ? "Activer le code promo" : "Fermer les CGU"}
{!onlyCgu ? "Activer le code promo" : "Fermer"}
</Button>
</DrawerBody>
</DrawerContent>
Expand All @@ -100,7 +109,6 @@ export default function Dashboard() {
const router = useRouter();
const { id } = router.query;

const [isCouponActive, setIsCouponActive] = useState(false);
const [isOnlyCgu, setIsOnlyCgu] = useState(false);

const { data: resultOffer } = api.offer.getById.useQuery(
Expand All @@ -110,7 +118,20 @@ export default function Dashboard() {
{ enabled: id !== undefined }
);

const { data: resultCoupon, refetch: refetchCoupon } =
api.coupon.getOne.useQuery(
{
offer_id: parseInt(id as string),
},
{ enabled: id !== undefined }
);

const { data: offer } = resultOffer || {};
const { data: coupon } = resultCoupon || {};

const { mutate: mutateCouponToUser } = api.coupon.assignToUser.useMutation({
onSuccess: () => refetchCoupon(),
});

const toast = useToast();
const theme = useTheme();
Expand Down Expand Up @@ -196,19 +217,19 @@ export default function Dashboard() {
position="relative"
borderRadius="xl"
w="full"
bgColor={isCouponActive ? "white" : "cje-gray.500"}
bgColor={coupon ? "white" : "cje-gray.500"}
textAlign="center"
py={10}
>
<Text
fontSize="2xl"
fontWeight="bold"
letterSpacing={4}
sx={!isCouponActive ? { filter: "blur(4.5px)" } : {}}
sx={!coupon ? { filter: "blur(4.5px)" } : {}}
>
6FHDJFHEIDJF
{coupon?.code ? coupon.code : "6FHDJFHEIDJF"}
</Text>
{!isCouponActive && (
{!coupon && (
<Flex
position="absolute"
p={5}
Expand All @@ -230,7 +251,7 @@ export default function Dashboard() {
</Flex>
)}
</Box>
{isCouponActive && (
{coupon && (
<Flex
flexDir="column"
alignItems="center"
Expand All @@ -256,13 +277,13 @@ export default function Dashboard() {
<Text as="span" fontSize="sm" color="disabled">
Utilisable jusqu'au:{" "}
<Text as="span" color="black" fontWeight="bold">
01/01/2025
{new Date(coupon.offer.validityTo).toLocaleDateString()}
</Text>
</Text>
</Flex>
)}
</Flex>
{!isCouponActive ? (
{!coupon ? (
<>
<Button rightIcon={<CouponIcon />} py={8} onClick={onOpen}>
Activer le code promo
Expand All @@ -272,17 +293,19 @@ export default function Dashboard() {
) : (
<ButtonGroup gap={3}>
<Button size="sm" colorScheme="cje-gray" color="black" w="full">
<Flex flexDir="column" alignItems="center" gap={3}>
<Icon as={FiLink} w={6} h={6} />
Aller sur le site du partenaire
</Flex>
<Link href={coupon.offer.partner.url} target="_blank">
<Flex flexDir="column" alignItems="center" gap={3}>
<Icon as={FiLink} w={6} h={6} />
Aller sur le site du partenaire
</Flex>
</Link>
</Button>
<Button
size="sm"
colorScheme="cje-gray"
color="black"
w="full"
onClick={() => handleCopyToClipboard("test1")}
onClick={() => handleCopyToClipboard(coupon.code)}
>
<Flex flexDir="column" alignItems="center" gap={3}>
<Icon as={FiCopy} w={6} h={6} />
Expand All @@ -308,11 +331,14 @@ export default function Dashboard() {
</Flex>
<Drawer placement="bottom" size="full" onClose={onClose} isOpen={isOpen}>
<DrawerOverlay />
<DrawerContentComponent
onClose={onClose}
setIsCouponActive={setIsCouponActive}
onlyCgu={isOnlyCgu}
/>
{offer && (
<DrawerContentComponent
onClose={onClose}
onlyCgu={isOnlyCgu}
offer={offer}
mutateCouponToUser={mutateCouponToUser}
/>
)}
</Drawer>
</Flex>
);
Expand Down
6 changes: 0 additions & 6 deletions webapp/src/payload/collections/Coupon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ export const Coupons: CollectionConfig = {
defaultValue: "available",
required: true,
},
{
name: "validityTo",
type: "date",
label: "Validité jusqu'au",
required: true,
},
{
name: "user",
type: "relationship",
Expand Down
6 changes: 6 additions & 0 deletions webapp/src/payload/collections/Offer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ export const Offers: CollectionConfig = {
hasMany: false,
required: true,
},
{
name: "validityTo",
type: "date",
label: "Validité jusqu'au",
required: true,
},
{
type: "select",
name: "kind",
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/payload/payload-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export interface Offer {
title: string;
partner: number | Partner;
category: number | Category;
validityTo: string;
kind: 'voucher' | 'code';
updatedAt: string;
createdAt: string;
Expand All @@ -93,7 +94,6 @@ export interface Coupon {
id: number;
code: string;
status: 'available' | 'archived';
validityTo: string;
user?: (number | null) | User;
offer: number | Offer;
updatedAt: string;
Expand Down
9 changes: 9 additions & 0 deletions webapp/src/payload/seed/offers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,43 @@ import { partners } from "./partners";
import { categories } from "./categories";

export async function seedOffers(payload: Payload) {
const currentDate = new Date();
const validityTo = new Date(
currentDate.setMonth(currentDate.getMonth() + 1)
).toISOString();

const offers: Omit<Offer, "id" | "createdAt" | "updatedAt">[] = [
{
title: "15% de réduction sur les produits alimentaire",
partner: partners.findIndex((partner) => partner.name === "Cora") + 1,
category:
categories.findIndex((category) => category.slug === "shop") + 1,
kind: "voucher",
validityTo,
},
{
title: "10% de réduction sur plus de 50 produits alimentaire",
partner: partners.findIndex((partner) => partner.name === "Lidl") + 1,
category:
categories.findIndex((category) => category.slug === "shop") + 1,
kind: "voucher",
validityTo,
},
{
title: "10% de réduction les produits alimentaire",
partner: partners.findIndex((partner) => partner.name === "Auchan") + 1,
category:
categories.findIndex((category) => category.slug === "shop") + 1,
kind: "voucher",
validityTo,
},
{
title: "10% de réduction sur l’ensemble des billets en France et Europe",
partner: partners.findIndex((partner) => partner.name === "Flixbus") + 1,
category:
categories.findIndex((category) => category.slug === "mobility") + 1,
kind: "code",
validityTo,
},
];

Expand Down
43 changes: 39 additions & 4 deletions webapp/src/server/api/routers/coupon.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,64 @@
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { Coupon, Media, Offer, User } from "~/payload/payload-types";
import { Coupon, Media, Offer, Partner, User } from "~/payload/payload-types";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";

interface CouponIncluded extends Coupon {
offer: Offer & { icon: Media };
offer: Offer & { icon: Media; partner: Partner };
userRouter: User;
}

export const couponRouter = createTRPCRouter({
getOneAvailable: protectedProcedure
getOne: protectedProcedure
.input(z.object({ offer_id: z.number() }))
.query(async ({ ctx, input }) => {
const { offer_id } = input;

const coupons = await ctx.payload.find({
collection: "coupons",
depth: 2,
where: {
and: [
{ offer: { equals: offer_id } },
{ status: { equals: "available" } },
{ validityTo: { greater_than_equal: new Date() } },
{ user: { equals: ctx.session.id } },
],
},
});

return { data: coupons.docs[0] as CouponIncluded };
}),

assignToUser: protectedProcedure
.input(z.object({ offer_id: z.number() }))
.mutation(async ({ ctx, input }) => {
const { offer_id } = input;

const coupon = await ctx.payload.find({
collection: "coupons",
where: {
and: [
{ offer: { equals: offer_id } },
{ status: { equals: "available" } },
],
},
});

if (coupon.docs.length === 0) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Coupon not found",
});
}

const couponData = coupon.docs[0] as CouponIncluded;

const updatedCoupon = await ctx.payload.update({
collection: "coupons",
id: couponData.id,
data: { user: ctx.session.id },
});

return { data: updatedCoupon };
}),
});
2 changes: 1 addition & 1 deletion webapp/src/server/api/routers/offer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Category, Offer, Media, Partner } from "~/payload/payload-types";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import { ZGetListParams } from "~/server/types";

interface OfferIncluded extends Offer {
export interface OfferIncluded extends Offer {
partner: Partner & { icon: Media };
category: Category & { icon: Media };
}
Expand Down

0 comments on commit 42168be

Please sign in to comment.