fix: set 100 MVR for default wallet topup amount 🔧

This commit is contained in:
2025-09-20 14:25:48 +05:00
parent f2a17d522b
commit 19043aa692
3 changed files with 151 additions and 151 deletions

View File

@@ -1,62 +1,63 @@
import { cn } from "@/lib/utils";
import { Minus, Plus } from "lucide-react"; import { Minus, Plus } from "lucide-react";
import { useEffect } from "react"; import { useEffect } from "react";
import { import {
Button, Button,
Group, Group,
Input, Input,
Label, Label,
NumberField, NumberField,
} from "react-aria-components"; } from "react-aria-components";
import { cn } from "@/lib/utils";
export default function NumberInput({ export default function NumberInput({
maxAllowed, maxAllowed,
label, label,
value, value = 100,
onChange, onChange,
className, className,
isDisabled, isDisabled,
}: { }: {
maxAllowed?: number; maxAllowed?: number;
label: string; label: string;
value: number; value?: number;
onChange: (value: number) => void; onChange: (value: number) => void;
className?: string; className?: string;
isDisabled?: boolean; isDisabled?: boolean;
}) { }) {
useEffect(() => { useEffect(() => {
if (maxAllowed) { if (maxAllowed) {
if (value > maxAllowed) { if (value > maxAllowed) {
onChange(maxAllowed); onChange(maxAllowed);
} }
} }
}, [maxAllowed, value, onChange]); }, [maxAllowed, value, onChange]);
return (
<NumberField return (
isDisabled={isDisabled} <NumberField
className={cn(className)} isDisabled={isDisabled}
value={value} className={cn(className)}
minValue={0} value={value}
onChange={onChange} minValue={0}
> onChange={onChange}
<div className="space-y-2"> >
<Label className="text-sm font-medium text-foreground">{label}</Label> <div className="space-y-2">
<Group className="relative inline-flex h-9 w-full items-center overflow-hidden whitespace-nowrap rounded-lg border border-input text-sm shadow-sm shadow-black/5 transition-shadow data-[focus-within]:border-ring data-disabled:opacity-50 data-focus-within:outline-none data-focus-within:ring-[3px] data-[focus-within]:ring-ring/20"> <Label className="text-sm font-medium text-foreground">{label}</Label>
<Button <Group className="relative inline-flex h-9 w-full items-center overflow-hidden whitespace-nowrap rounded-lg border border-input text-sm shadow-sm shadow-black/5 transition-shadow data-[focus-within]:border-ring data-disabled:opacity-50 data-focus-within:outline-none data-focus-within:ring-[3px] data-[focus-within]:ring-ring/20">
slot="decrement" <Button
className="-ms-px flex aspect-square h-[inherit] items-center justify-center rounded-s-lg border border-input bg-background text-sm text-muted-foreground/80 transition-shadow hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50" slot="decrement"
> className="-ms-px flex aspect-square h-[inherit] items-center justify-center rounded-s-lg border border-input bg-background text-sm text-muted-foreground/80 transition-shadow hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
<Minus size={16} strokeWidth={2} aria-hidden="true" /> >
</Button> <Minus size={16} strokeWidth={2} aria-hidden="true" />
<Input className="w-full grow bg-background px-3 py-2 text-center text-base tabular-nums text-foreground focus:outline-none" /> </Button>
<Button <Input className="w-full grow bg-background px-3 py-2 text-center text-base tabular-nums text-foreground focus:outline-none" />
slot="increment" <Button
className="-me-px flex aspect-square h-[inherit] items-center justify-center rounded-e-lg border border-input bg-background text-sm text-muted-foreground/80 transition-shadow hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50" slot="increment"
> className="-me-px flex aspect-square h-[inherit] items-center justify-center rounded-e-lg border border-input bg-background text-sm text-muted-foreground/80 transition-shadow hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
<Plus size={16} strokeWidth={2} aria-hidden="true" /> >
</Button> <Plus size={16} strokeWidth={2} aria-hidden="true" />
</Group> </Button>
</div> </Group>
</NumberField> </div>
); </NumberField>
);
} }

View File

@@ -7,101 +7,100 @@ import { toast } from "sonner";
import { createTopup } from "@/actions/payment"; import { createTopup } from "@/actions/payment";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Drawer, Drawer,
DrawerClose, DrawerClose,
DrawerContent, DrawerContent,
DrawerDescription, DrawerDescription,
DrawerFooter, DrawerFooter,
DrawerHeader, DrawerHeader,
DrawerTitle, DrawerTitle,
DrawerTrigger, DrawerTrigger,
} from "@/components/ui/drawer"; } from "@/components/ui/drawer";
import { WalletDrawerOpenAtom, walletTopUpValue } from "@/lib/atoms"; import { WalletDrawerOpenAtom, walletTopUpValue } from "@/lib/atoms";
import type { TopupType } from "@/lib/types"; import type { TopupType } from "@/lib/types";
import NumberInput from "./number-input"; import NumberInput from "./number-input";
export function Wallet({ walletBalance }: { walletBalance: number }) { export function Wallet({ walletBalance }: { walletBalance: number }) {
const pathname = usePathname(); const pathname = usePathname();
const [amount, setAmount] = useAtom(walletTopUpValue); const [amount, setAmount] = useAtom(walletTopUpValue);
const [isOpen, setIsOpen] = useAtom(WalletDrawerOpenAtom); const [isOpen, setIsOpen] = useAtom(WalletDrawerOpenAtom);
const [disabled, setDisabled] = useState(false); const [disabled, setDisabled] = useState(false);
const router = useRouter(); const router = useRouter();
if (pathname === "/payment") { if (pathname === "/payment") {
return null; return null;
} }
const data: TopupType = { const data: TopupType = {
amount: Number.parseFloat(amount.toFixed(2)), amount: Number.parseFloat(amount.toFixed(2)),
}; };
return ( return (
<Drawer open={isOpen} onOpenChange={setIsOpen}> <Drawer open={isOpen} onOpenChange={setIsOpen}>
<DrawerTrigger asChild> <DrawerTrigger asChild>
<Button onClick={() => setIsOpen(!isOpen)} variant="outline"> <Button onClick={() => setIsOpen(!isOpen)} variant="outline">
{walletBalance}{" "} {walletBalance} MVR
MVR <Wallet2 />
<Wallet2 /> </Button>
</Button> </DrawerTrigger>
</DrawerTrigger> <DrawerContent>
<DrawerContent> <div className="mx-auto w-full max-w-sm">
<div className="mx-auto w-full max-w-sm"> <DrawerHeader>
<DrawerHeader> <DrawerTitle>Wallet</DrawerTitle>
<DrawerTitle>Wallet</DrawerTitle> <DrawerDescription asChild>
<DrawerDescription asChild> <div>
<div> Your wallet balance is{" "}
Your wallet balance is{" "} <span className="font-semibold">
<span className="font-semibold"> {new Intl.NumberFormat("en-US", {
{new Intl.NumberFormat("en-US", { minimumFractionDigits: 2,
minimumFractionDigits: 2, maximumFractionDigits: 2,
maximumFractionDigits: 2, }).format(walletBalance)}
}).format(walletBalance)} </span>{" "}
</span>{" "} </div>
</div> </DrawerDescription>
</DrawerDescription> </DrawerHeader>
</DrawerHeader>
<div className="px-4 flex flex-col gap-4"> <div className="px-4 flex flex-col gap-4">
<NumberInput <NumberInput
label="Set amount to top up" label="Set amount to top up"
value={amount} value={amount}
onChange={(value) => setAmount(value)} onChange={(value) => setAmount(value)}
maxAllowed={5000} maxAllowed={5000}
isDisabled={amount === 0} isDisabled={amount === 0}
/> />
</div> </div>
<DrawerFooter> <DrawerFooter>
<Button <Button
onClick={async () => { onClick={async () => {
console.log(data); console.log(data);
setDisabled(true); setDisabled(true);
const topup = await createTopup(data); const topup = await createTopup(data);
setDisabled(false); setDisabled(false);
if (topup) { if (topup) {
router.push(`/top-ups/${topup.id}`); router.push(`/top-ups/${topup.id}`);
setIsOpen(!isOpen); setIsOpen(!isOpen);
} else { } else {
toast.error("Something went wrong."); toast.error("Something went wrong.");
} }
}} }}
className="w-full" className="w-full"
disabled={amount === 0 || disabled} disabled={amount === 0 || disabled}
> >
{disabled ? ( {disabled ? (
<Loader2 className="ml-2 animate-spin" /> <Loader2 className="ml-2 animate-spin" />
) : ( ) : (
<> <>
Go to payment Go to payment
<CircleDollarSign /> <CircleDollarSign />
</> </>
)} )}
</Button> </Button>
<DrawerClose asChild> <DrawerClose asChild>
<Button variant="outline">Cancel</Button> <Button variant="outline">Cancel</Button>
</DrawerClose> </DrawerClose>
</DrawerFooter> </DrawerFooter>
</div> </div>
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
); );
} }

View File

@@ -10,7 +10,7 @@ export const discountPercentageAtom = atom(75);
export const numberOfDevicesAtom = atom(1); export const numberOfDevicesAtom = atom(1);
export const numberOfDaysAtom = atom(30); export const numberOfDaysAtom = atom(30);
export const numberOfMonths = atom(1); export const numberOfMonths = atom(1);
export const walletTopUpValue = atom(1); export const walletTopUpValue = atom(100);
export const formulaResultAtom = atom(""); export const formulaResultAtom = atom("");
export const deviceCartAtom = atom<Device[]>([]); export const deviceCartAtom = atom<Device[]>([]);
export const cartDrawerOpenAtom = atom(false); export const cartDrawerOpenAtom = atom(false);
@@ -19,14 +19,14 @@ export const loadingDevicesToPayAtom = atom(false);
// Export the atoms with their store // Export the atoms with their store
export const atoms = { export const atoms = {
initialPriceAtom, initialPriceAtom,
discountPercentageAtom, discountPercentageAtom,
numberOfDevicesAtom, numberOfDevicesAtom,
numberOfDaysAtom, numberOfDaysAtom,
numberOfMonths, numberOfMonths,
formulaResultAtom, formulaResultAtom,
deviceCartAtom, deviceCartAtom,
cartDrawerOpenAtom, cartDrawerOpenAtom,
walletTopUpValue, walletTopUpValue,
loadingDevicesToPayAtom, loadingDevicesToPayAtom,
}; };