Skip to content

Commit

Permalink
feat: cumulative offers
Browse files Browse the repository at this point in the history
  • Loading branch information
ClementNumericite committed Nov 25, 2024
1 parent 0d20a0e commit 506cf78
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 30 deletions.
4 changes: 3 additions & 1 deletion webapp/src/components/ToastComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ import { IconType } from "react-icons/lib";
export default function ToastComponent({
text,
icon,
bgColor,
}: {
text: string;
icon: IconType;
bgColor?: string;
}) {
return (
<Flex
alignItems="center"
justifyContent="space-between"
bgColor="success"
bgColor={bgColor || "success"}
color="white"
px={6}
py={4}
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/components/cards/OfferCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const OfferCard = ({
const utils = api.useUtils();

const isBookmarked = !!offer.userCoupon;
const isDisabled = !!offer.userCoupon?.used;
const isDisabled = !!offer.userCoupon?.used && !offer.cumulative;

const {
mutateAsync: mutateAsyncCouponToUser,
Expand Down
39 changes: 18 additions & 21 deletions webapp/src/components/offer/page/OfferContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import { getItemsConditionBlocks } from "~/payload/components/CustomSelectBlocks

type OfferContentProps = {
offer: OfferIncluded;
coupon?: CouponIncluded;
canTakeCoupon: boolean;
disabled: boolean;
handleValidateOffer: (
offerId: number,
displayCoupon?: boolean
Expand All @@ -34,8 +35,13 @@ type OfferContentProps = {
};

const OfferContent = (props: OfferContentProps) => {
const { offer, coupon, handleValidateOffer, isLoadingValidateOffer } = props;
const hasCoupon = !!coupon;
const {
offer,
canTakeCoupon,
disabled,
handleValidateOffer,
isLoadingValidateOffer,
} = props;

const conditionsRef = useRef<HTMLUListElement>(null);
const [isConditionsOpen, setIsConditionsOpen] = useState(false);
Expand Down Expand Up @@ -67,12 +73,10 @@ const OfferContent = (props: OfferContentProps) => {
return offer.conditions ?? [];
}, [offer, isConditionsOpen]);

const disabled = coupon && !!coupon.used;

return (
<Flex flexDir="column">
<Box mt={6} px={4} w="full">
{coupon && coupon.used ? (
{disabled ? (
<Box
w="full"
color="success"
Expand Down Expand Up @@ -177,13 +181,6 @@ const OfferContent = (props: OfferContentProps) => {
lineHeight="shorter"
borderBottom="2px solid black"
onClick={() => {
// push([
// "trackEvent",
// "Offre",
// `${offer.partner.name} - ${offer.title} - ${
// !!coupon ? "Active" : "Inactive"
// } - Conditions`,
// ]);
setIsConditionsOpen(true);
}}
>
Expand Down Expand Up @@ -234,25 +231,25 @@ const OfferContent = (props: OfferContentProps) => {
w="40%"
fontSize={16}
borderWidth={1}
borderColor={hasCoupon ? "transparent" : "cje-gray.100"}
color={hasCoupon ? "white" : "blackLight"}
colorScheme={hasCoupon ? "primaryShades" : "inherit"}
isDisabled={hasCoupon}
isLoading={!hasCoupon && isLoadingValidateOffer}
borderColor={canTakeCoupon ? "cje-gray.100" : "transparent"}
color={canTakeCoupon ? "blackLight" : "white"}
colorScheme={canTakeCoupon ? "inherit" : "primaryShades"}
isDisabled={!canTakeCoupon}
isLoading={canTakeCoupon && isLoadingValidateOffer}
onClick={() => {
if (!hasCoupon) {
if (canTakeCoupon) {
handleValidateOffer(offer.id, false);
}
}}
leftIcon={
<Icon
as={hasCoupon ? HiBookmark : HiOutlineBookmark}
as={canTakeCoupon ? HiOutlineBookmark : HiBookmark}
w={5}
h={5}
/>
}
>
{hasCoupon ? "Enregistré" : "Enregistrer"}
{canTakeCoupon ? "Enregistrer" : "Enregistré"}
</Button>
<Button
w="60%"
Expand Down
54 changes: 48 additions & 6 deletions webapp/src/pages/dashboard/offer/cje/[id]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Center, useDisclosure } from "@chakra-ui/react";
import { Center, useDisclosure, useToast } from "@chakra-ui/react";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import CouponCard from "~/components/cards/CouponCard";
Expand All @@ -10,6 +10,8 @@ import { motion, AnimatePresence } from "framer-motion";
import OfferContent from "~/components/offer/page/OfferContent";
import CouponContent from "~/components/offer/page/CouponContent";
import { isIOS } from "~/utils/tools";
import ToastComponent from "~/components/ToastComponent";
import { IoCloseCircleOutline } from "react-icons/io5";

const flipVariants = {
hidden: { rotateY: 90 },
Expand All @@ -19,6 +21,7 @@ const flipVariants = {

export default function OfferCjePage() {
const router = useRouter();
const toast = useToast();

const { id: offer_id } = router.query as { id: string };

Expand All @@ -40,14 +43,45 @@ export default function OfferCjePage() {
const { data: offer } = resultOffer || {};
const { data: coupon } = resultCoupon || {};

// There is 3 ways user can take a new coupon
// 1 - User does not have a coupon assigned
// 2 - User has an unused coupon assigned
// 3 - User has a used coupon assigned but offer is cumulative
const canTakeCoupon =
!coupon ||
(!!coupon && !coupon.used) ||
(!!coupon && !!coupon.used && !!offer?.cumulative);
const hasUnusedCoupon = !!coupon && !coupon.used;
const disabled = !!coupon && !!coupon.used && !offer?.cumulative;

const { mutateAsync: increaseNbSeen } =
api.offer.increaseNbSeen.useMutation();

const {
mutateAsync: mutateAsyncCouponToUser,
isLoading: isLoadingCouponToUser,
} = api.coupon.assignToUser.useMutation({
onSuccess: () => refetchCoupon(),
onSuccess: () => {
refetchCoupon();
},
onError: (error) => {
if (error.data?.httpStatus === 404) {
toast({
render: () => (
<ToastComponent
bgColor="error"
text="Plus aucun code disponible pour cette offre, redirection..."
icon={IoCloseCircleOutline}
/>
),
duration: 2000,
});

setTimeout(() => {
router.push("/dashboard");
}, 2000);
}
},
});

const [isFirstLoad, setIsFirstLoad] = useState(true);
Expand All @@ -59,9 +93,16 @@ export default function OfferCjePage() {
offerId: number,
displayCoupon: boolean = true
) => {
if (!coupon) await mutateAsyncCouponToUser({ offer_id: offerId });
else if (coupon && coupon.used) return;
if (displayCoupon) setKind("coupon");
if (hasUnusedCoupon) {
setKind("coupon");
} else if (canTakeCoupon) {
try {
await mutateAsyncCouponToUser({ offer_id: offerId });
if (displayCoupon) setKind("coupon");
} catch (e) {
console.error(e);
}
}
};

const handleBookmarkOfferToUser = async () => {
Expand Down Expand Up @@ -209,7 +250,8 @@ export default function OfferCjePage() {
offer={offer}
handleValidateOffer={handleValidateOffer}
isLoadingValidateOffer={isLoadingCouponToUser}
coupon={coupon}
canTakeCoupon={canTakeCoupon}
disabled={disabled}
/>
) : (
coupon && (
Expand Down
3 changes: 2 additions & 1 deletion webapp/src/payload/payload-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ export interface Offer {
source: "cje" | "obiz";
obiz_id?: string | null;
kind: string;
cumulative?: boolean | null;
url?: string | null;
nbOfEligibleStores?: number | null;
imageOfEligibleStores?: number | Media | null;
Expand All @@ -250,7 +251,7 @@ export interface Offer {
| null;
conditionBlocks?:
| {
slug: string;
slug?: string | null;
isCrossed?: boolean | null;
id?: string | null;
}[]
Expand Down
1 change: 1 addition & 0 deletions webapp/src/server/api/routers/coupon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const couponRouter = createTRPCRouter({
const coupons = await ctx.payload.find({
collection: "coupons",
depth: 3,
sort: "-usedAt",
where: {
and: [
{ offer: { equals: offer_id } },
Expand Down
1 change: 1 addition & 0 deletions webapp/src/server/api/routers/offer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export const offerRouter = createTRPCRouter({
collection: "coupons",
depth: 0,
limit: 1000,
sort: "-usedAt",
where: {
user: { equals: ctx.session.id },
},
Expand Down

0 comments on commit 506cf78

Please sign in to comment.