137 lines
5.2 KiB
TypeScript
137 lines
5.2 KiB
TypeScript
import type { JSX } from "react";
|
|
import { useMemo, useState } from "react";
|
|
import { View } from "react-native";
|
|
import { useRouter } from "expo-router";
|
|
import { BottomSheet, Button, Spinner, Typography, useThemeColor } from "heroui-native";
|
|
import { PRODUCTS, RESOLVERS } from "@/data/mock";
|
|
import { useModals } from "@/state/modals";
|
|
import { ResolverCard } from "@/components/ResolverCard";
|
|
import { MonoText } from "@/components/MonoText";
|
|
|
|
export function CheckoutSheet(): JSX.Element {
|
|
const router = useRouter();
|
|
const accentColor = useThemeColor("accent");
|
|
const { isCheckoutSheetOpen, checkoutListingId, checkoutStep, closeCheckoutSheet, confirmOrder } =
|
|
useModals();
|
|
const [resolverId, setResolverId] = useState(0);
|
|
|
|
const listing = useMemo(
|
|
() => PRODUCTS.find((product) => product.id === checkoutListingId) ?? PRODUCTS[0],
|
|
[checkoutListingId],
|
|
);
|
|
|
|
const handleViewOrders = () => {
|
|
closeCheckoutSheet();
|
|
router.push("/orders");
|
|
};
|
|
|
|
const handleContinueShopping = () => {
|
|
closeCheckoutSheet();
|
|
router.push("/browse");
|
|
};
|
|
|
|
return (
|
|
<BottomSheet
|
|
isOpen={isCheckoutSheetOpen}
|
|
onOpenChange={(open) => {
|
|
if (!open) closeCheckoutSheet();
|
|
}}
|
|
>
|
|
<BottomSheet.Portal>
|
|
<BottomSheet.Overlay isCloseOnPress={checkoutStep !== "pending"} />
|
|
<BottomSheet.Content>
|
|
{checkoutStep === "review" && (
|
|
<View className="gap-4">
|
|
<BottomSheet.Close />
|
|
<BottomSheet.Title>Place Order</BottomSheet.Title>
|
|
<View className="flex-row items-center gap-3 rounded-xl bg-surface-secondary p-3">
|
|
<View
|
|
className="size-11 items-center justify-center rounded-lg"
|
|
style={{ backgroundColor: listing.bg }}
|
|
>
|
|
<Typography className="text-xl">{listing.emoji}</Typography>
|
|
</View>
|
|
<View className="flex-1">
|
|
<Typography type="body-sm" weight="semibold" numberOfLines={1}>
|
|
{listing.name}
|
|
</Typography>
|
|
<MonoText type="body-xs" color="muted">
|
|
{listing.seller}
|
|
</MonoText>
|
|
</View>
|
|
</View>
|
|
|
|
<View className="gap-1 rounded-xl bg-surface-secondary p-3.5">
|
|
<Typography type="body-xs" color="muted">
|
|
Payment
|
|
</Typography>
|
|
<View className="flex-row items-baseline gap-2">
|
|
<Typography type="h5">{listing.price}</Typography>
|
|
<Typography type="body-sm" color="muted">
|
|
≈ {listing.usd} USD
|
|
</Typography>
|
|
</View>
|
|
</View>
|
|
|
|
<View className="gap-2 rounded-xl bg-surface-secondary p-3.5">
|
|
<Typography type="body-xs" color="muted">
|
|
Dispute Protection
|
|
</Typography>
|
|
{RESOLVERS.map((item) => (
|
|
<ResolverCard
|
|
key={item.id}
|
|
resolver={item}
|
|
isSelected={item.id === resolverId}
|
|
onSelect={() => setResolverId(item.id)}
|
|
/>
|
|
))}
|
|
</View>
|
|
|
|
<View className="flex-row gap-2">
|
|
<Button variant="secondary" className="flex-1" onPress={closeCheckoutSheet}>
|
|
<Button.Label>Cancel</Button.Label>
|
|
</Button>
|
|
<Button className="flex-[2]" onPress={confirmOrder}>
|
|
<Button.Label>Confirm & Place Order →</Button.Label>
|
|
</Button>
|
|
</View>
|
|
</View>
|
|
)}
|
|
|
|
{checkoutStep === "pending" && (
|
|
<View className="items-center gap-4 py-10">
|
|
<Spinner size="lg" color={accentColor} />
|
|
<Typography type="h6">Confirming on Solana…</Typography>
|
|
<Typography type="body-sm" color="muted" align="center">
|
|
{"Approve the transaction in your wallet.\nThis takes a few seconds."}
|
|
</Typography>
|
|
</View>
|
|
)}
|
|
|
|
{checkoutStep === "success" && (
|
|
<View className="gap-4">
|
|
<View className="items-center gap-2">
|
|
<View className="size-14 items-center justify-center rounded-full bg-success/15">
|
|
<Typography className="text-2xl">✓</Typography>
|
|
</View>
|
|
<Typography type="h5">Order Placed!</Typography>
|
|
<Typography type="body-sm" color="muted" align="center">
|
|
{`${listing.price} is now held in secure escrow.\nThe seller has been notified.`}
|
|
</Typography>
|
|
</View>
|
|
<View className="flex-row gap-2">
|
|
<Button variant="secondary" className="flex-1" onPress={handleContinueShopping}>
|
|
<Button.Label>Continue Shopping</Button.Label>
|
|
</Button>
|
|
<Button className="flex-1" onPress={handleViewOrders}>
|
|
<Button.Label>View My Orders</Button.Label>
|
|
</Button>
|
|
</View>
|
|
</View>
|
|
)}
|
|
</BottomSheet.Content>
|
|
</BottomSheet.Portal>
|
|
</BottomSheet>
|
|
);
|
|
}
|