diff --git a/vite/index.html b/vite/index.html index bacd47f28..fa38f218c 100644 --- a/vite/index.html +++ b/vite/index.html @@ -37,6 +37,12 @@ } })(); + +
diff --git a/vite/package.json b/vite/package.json index 6f207ad71..de56c2a2d 100644 --- a/vite/package.json +++ b/vite/package.json @@ -76,6 +76,7 @@ "react": "^18.2.0", "react-day-picker": "^8.10.1", "react-dom": "^18.2.0", + "react-grab": "^0.1.29", "react-hotkeys-hook": "^4.6.1", "react-router": "^7.3.0", "react-router-dom": "^7.6.2", diff --git a/vite/src/hooks/stores/useRewardStore.ts b/vite/src/hooks/stores/useRewardStore.ts index 60cb3bf87..21b1b566d 100644 --- a/vite/src/hooks/stores/useRewardStore.ts +++ b/vite/src/hooks/stores/useRewardStore.ts @@ -11,6 +11,7 @@ const DEFAULT_REWARD: FrontendReward = { free_product_id: null, discount_config: defaultDiscountConfig, free_product_config: null, + featureGrantEntitlements: [], }; interface RewardState { diff --git a/vite/src/views/products/rewards/reward-config/components/CreateRewardSheet.tsx b/vite/src/views/products/rewards/reward-config/components/CreateRewardSheet.tsx index 2b5a941cf..1be9c97a0 100644 --- a/vite/src/views/products/rewards/reward-config/components/CreateRewardSheet.tsx +++ b/vite/src/views/products/rewards/reward-config/components/CreateRewardSheet.tsx @@ -12,6 +12,7 @@ import { SheetContent, SheetTrigger, } from "@/components/v2/sheets/Sheet"; +import { useFeaturesQuery } from "@/hooks/queries/useFeaturesQuery"; import { useRewardsQuery } from "@/hooks/queries/useRewardsQuery"; import { useRewardStore } from "@/hooks/stores/useRewardStore"; import { RewardService } from "@/services/products/RewardService"; @@ -19,6 +20,7 @@ import { useAxiosInstance } from "@/services/useAxiosInstance"; import { getBackendErr } from "@/utils/genUtils"; import { mapFrontendToApiReward } from "../../utils/rewardMappers"; import { DiscountRewardConfig } from "./DiscountRewardConfig"; +import { FeatureGrantRewardConfig } from "./FeatureGrantRewardConfig"; import { FreeProductRewardConfig } from "./FreeProductRewardConfig"; import { RewardDetails } from "./RewardDetails"; import { SelectRewardType } from "./SelectRewardType"; @@ -34,6 +36,7 @@ export function CreateRewardSheet({ }: CreateRewardSheetProps = {}) { const axiosInstance = useAxiosInstance(); const { refetch } = useRewardsQuery(); + const { features } = useFeaturesQuery(); const [loading, setLoading] = useState(false); const [internalOpen, setInternalOpen] = useState(false); @@ -86,9 +89,31 @@ export function CreateRewardSheet({ return; } + if (reward.rewardCategory === "feature_grant") { + const validEntitlements = reward.featureGrantEntitlements.filter( + (e) => e.feature_id && e.allowance > 0, + ); + if (validEntitlements.length === 0) { + toast.error( + "Please add at least one entitlement with a feature and balance", + ); + return; + } + if ( + !reward.promo_codes?.length || + !reward.promo_codes.some((pc) => pc.code) + ) { + toast.error("Please add at least one promo code"); + return; + } + } + setLoading(true); try { - const apiReward = mapFrontendToApiReward(reward); + const apiReward = mapFrontendToApiReward({ + frontendReward: reward, + features, + }); await RewardService.createReward({ axiosInstance, @@ -135,6 +160,10 @@ export function CreateRewardSheet({ {reward.rewardCategory === "free_product" && (