This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Button } from "@workspace/ui/components/button";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@workspace/ui/components/form";
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "@workspace/ui/components/sheet";
|
||||
import { Combobox } from "@workspace/ui/composed/combobox";
|
||||
import { EnhancedInput } from "@workspace/ui/composed/enhanced-input";
|
||||
import { unitConversion } from "@workspace/ui/utils/unit-conversions";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
import { getSubscribeUnitPrice } from "./utils";
|
||||
|
||||
const priceSchema = z.object({
|
||||
rule_id: z.number().min(1),
|
||||
subscribe_id: z.number().min(1),
|
||||
promo_price: z.number().min(1),
|
||||
});
|
||||
|
||||
type PriceFormValues = z.infer<typeof priceSchema>;
|
||||
|
||||
interface PriceFormProps {
|
||||
loading?: boolean;
|
||||
rules: API.PromoRule[];
|
||||
subscribes: API.SubscribeItem[];
|
||||
onSubmit: (data: API.CreatePromoPriceRequest) => Promise<boolean> | boolean;
|
||||
}
|
||||
|
||||
export default function PriceForm({
|
||||
loading,
|
||||
rules,
|
||||
subscribes,
|
||||
onSubmit,
|
||||
}: PriceFormProps) {
|
||||
const { t } = useTranslation("promo");
|
||||
const [open, setOpen] = useState(false);
|
||||
const form = useForm<PriceFormValues>({
|
||||
resolver: zodResolver(priceSchema),
|
||||
defaultValues: {
|
||||
rule_id: 0,
|
||||
subscribe_id: 0,
|
||||
promo_price: 0,
|
||||
},
|
||||
});
|
||||
const subscribeId = form.watch("subscribe_id");
|
||||
const subscribe = subscribes.find((item) => item.id === subscribeId);
|
||||
const unitPrice = getSubscribeUnitPrice(subscribe);
|
||||
|
||||
async function handleSubmit(values: PriceFormValues) {
|
||||
if (unitPrice > 0 && values.promo_price >= unitPrice) {
|
||||
form.setError("promo_price", {
|
||||
message: t(
|
||||
"form.promoPriceLessThanUnitPrice",
|
||||
"Promo price must be lower than unit price"
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const success = await onSubmit(values);
|
||||
if (success) setOpen(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<Sheet onOpenChange={setOpen} open={open}>
|
||||
<SheetTrigger asChild>
|
||||
<Button
|
||||
onClick={() => {
|
||||
form.reset({ rule_id: 0, subscribe_id: 0, promo_price: 0 });
|
||||
setOpen(true);
|
||||
}}
|
||||
size="sm"
|
||||
>
|
||||
{t("createPrice", "Create Promo Price")}
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent className="w-[520px] max-w-full md:max-w-screen-md">
|
||||
<SheetHeader>
|
||||
<SheetTitle>{t("createPrice", "Create Promo Price")}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<Form {...form}>
|
||||
<form
|
||||
className="space-y-4 px-6 pt-4"
|
||||
id="promo-price-form"
|
||||
onSubmit={form.handleSubmit(handleSubmit)}
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="rule_id"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("rule", "Rule")}</FormLabel>
|
||||
<FormControl>
|
||||
<Combobox<number>
|
||||
onChange={field.onChange}
|
||||
options={rules.map((rule) => ({
|
||||
label: rule.name,
|
||||
value: rule.id,
|
||||
}))}
|
||||
placeholder={t("form.selectRule", "Select rule")}
|
||||
value={field.value}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="subscribe_id"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("subscribe", "Subscribe")}</FormLabel>
|
||||
<FormControl>
|
||||
<Combobox<number>
|
||||
onChange={field.onChange}
|
||||
options={subscribes
|
||||
.filter((item) => typeof item.id === "number")
|
||||
.map((item) => ({
|
||||
label: item.name || `#${item.id}`,
|
||||
value: item.id as number,
|
||||
}))}
|
||||
placeholder={t(
|
||||
"form.selectSubscribe",
|
||||
"Select subscribe"
|
||||
)}
|
||||
value={field.value}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="promo_price"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("promoPrice", "Promo Price")}</FormLabel>
|
||||
<FormControl>
|
||||
<EnhancedInput
|
||||
formatInput={(value) =>
|
||||
unitConversion("centsToDollars", value)
|
||||
}
|
||||
formatOutput={(value) =>
|
||||
unitConversion("dollarsToCents", value)
|
||||
}
|
||||
min={0.01}
|
||||
onValueChange={(value) => field.onChange(value)}
|
||||
placeholder={t("form.enterPromoPrice", "Enter price")}
|
||||
type="number"
|
||||
value={field.value}
|
||||
/>
|
||||
</FormControl>
|
||||
{unitPrice > 0 && (
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t("unitPriceHint", "Unit price")}:{" "}
|
||||
{unitConversion("centsToDollars", unitPrice)}
|
||||
</p>
|
||||
)}
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
</Form>
|
||||
<SheetFooter>
|
||||
<Button disabled={loading} form="promo-price-form" type="submit">
|
||||
{t("confirm", "Confirm")}
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user