Third Tool

In this section, we will add further interactivity to your streamed components.

Let's generate two more components with v0, a "confirming order" and "order confirmed" component. We can use this example of confirming order, and example of order confirmed. Add them to your project, calling them confirming-order and order-confirmed respectively.

Install the "confirming order" component with the following command, naming it ConfirmingOrder.

npx v0 add AL1fs84WRpz -n ConfirmingOrder

And install the "order confirmed" component with the following command, naming it OrderConfirmed.

npx v0 add OqTgwrPwjZb -n OrderConfirmed

Add a new tool to handle confirming an order.

app/actions.tsx
// REST OF CODE
    tools: {
      // your other tool
      orderConfirmation: {
        description: "Confirm the users order.",
        parameters: productSchema,
        generate: async function* (product) {
          yield <ConfirmingOrder />;
          await new Promise((resolve) => setTimeout(resolve, 2000));
          return <OrderConfirmed product={product} />;
        },
      },
    }
// REST OF CODE

Update your ProductCard component to handle selection.

components/product-card.tsx
"use client"; 
/**
 * This code was generated by v0 by Vercel.
 * @see https://v0.dev/t/NscAFoMGpdh
 * Documentation: https://v0.dev/docs#integrating-generated-code-into-your-nextjs-app
 */
import { Button } from "@/components/ui/button";
import { ClientMessage } from "@/app/actions";
import { useActions, useUIState } from "ai/rsc";
import { nanoid } from "nanoid";
import { Product } from "@/lib/schemas/products";

export function ProductCard({
  product,
}: {
  product: Product;
}) {
  const [_, setConversation] = useUIState();
  const { continueConversation } = useActions();

  return (
    <div className="flex flex-col items-start gap-6 bg-white p-8 shadow-lg rounded-lg dark:bg-gray-950">
      <div className="space-y-2">
        <h2 className="text-2xl font-bold tracking-tight">{product.name}</h2>
        <p className="text-gray-500 dark:text-gray-400">
          {product.description}
        </p>
      </div>
      <div className="flex items-baseline gap-2">
        <span className="text-4xl font-bold">${product.price}</span>
        {product.type === "subscription" ? (
          <span className="text-gray-500 dark:text-gray-400 text-sm">
            /month
          </span>
        ) : null}
      </div>
      <Button 
        className="w-full"
        onClick={async () => {
          setConversation((currentConversation: ClientMessage[]) => [
            ...currentConversation,
            {
              id: nanoid(),
              role: "user",
              display: "Place order for " + product.name,
            },
          ]);

          const message = await continueConversation(
            "Place order for " + JSON.stringify({ product }),
          );

          setConversation((currentConversation: ClientMessage[]) => [
            ...currentConversation,
            message,
          ]);
        }}
      >
        {product.type === "subscription" ? "Subscribe" : "Buy"} Now
      </Button>
    </div>
  );
}

Update the <OrderConfirmed /> component to display product information.

components/order-confirmed.tsx
// REST OF CODE
import { Card } from "@/components/ui/card"
import { Product } from "@/lib/schemas/products"

export function OrderConfirmed({product}: {product: Product}) { 
  return (
    <Card className="w-full p-8 flex flex-col items-center justify-center text-center">
      <div className="bg-green-500 rounded-full p-4 mb-4">
        <CheckIcon className="h-8 w-8 text-white" />
      </div>
      <h2 className="text-2xl font-bold mb-2">{product.type === "one-off" ? "Order" : "Subscription" } Confirmed</h2>
      <p className="text-gray-500 dark:text-gray-400">
        Thank you for { product.type === "one-off" ? "ordering" :"subscribing to" } {product.name}. We're processing it now and will send you a confirmation email shortly.
      </p>
    </Card>
  )
}
// REST OF CODE

Head back to the browser. Now ask for "Apple Products", select a product and then order it.