mirror of
https://github.com/i701/sarlink-portal.git
synced 2025-10-07 11:11:37 +00:00
fix: set 100 MVR for default wallet topup amount 🔧
This commit is contained in:
@@ -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>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
22
lib/atoms.ts
22
lib/atoms.ts
@@ -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,
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user