Order Confirmation
blockcommercePost-purchase order confirmation & tracking page featuring a success banner with emerald checkmark halo, 4-step shipment progress bar with pulsing active state, itemized order breakdown, and customer delivery & payment cards.
Installation
$pnpm dlx uipkge-ng@latest add order-confirmation$npx uipkge-ng@latest add order-confirmation$yarn dlx uipkge-ng@latest add order-confirmation$bunx uipkge-ng@latest add order-confirmationManifest:
https://uipkge.dev/r/angular/order-confirmation.jsonInstalls to:src/app/components/blocks/order-confirmation/Variants
Loading interactive previews…
Loading interactive previews…
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
OrderIteminterface OrderItem {
id: string
name: string
variant: string
quantity: number
price: string
image: string
}TrackingStepinterface TrackingStep {
id: string
title: string
date: string
status: 'completed' | 'current' | 'upcoming'
description: string
}npm dependencies
Files installed (2)
src/app/components/blocks/order-confirmation/order-confirmation.component.ts19.5 kB
// Post-purchase order confirmation & tracking page: success banner, 4-step shipment // stepper (grid on md+, vertical list below), itemized summary, and delivery / payment / // help cards. The order data lives in the constants below -- edit them in place. import { Component, Input, ChangeDetectionStrategy } from '@angular/core' import { Check, CheckCircle2, CreditCard, Download, ExternalLink, HelpCircle, LucideAngularModule, Mail, MapPin, MessageSquare, Package, Truck, } from 'lucide-angular' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiCardComponent, UiCardContentComponent, UiCardDescriptionComponent, UiCardHeaderComponent, UiCardTitleComponent, } from '@/ui/card/card.component' import { UiSeparatorComponent } from '@/ui/separator/separator.component' import { cn } from '@/lib/utils' export interface OrderItem { id: string name: string variant: string quantity: number price: string image: string } export interface TrackingStep { id: string title: string date: string status: 'completed' | 'current' | 'upcoming' description: string } const orderItems: OrderItem[] = [ { id: 'item-1', name: 'Studio Wireless Noise-Canceling Headphones', variant: 'Space Gray • Over-Ear', quantity: 1, price: '$179.00', image: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=160&auto=format&fit=crop&q=80', }, { id: 'item-2', name: 'Braided USB-C Fast Charging Cable (2m)', variant: 'Midnight Black • 100W PD', quantity: 2, price: '$38.00', image: 'https://images.unsplash.com/photo-1546868871-7041f2a55e12?w=160&auto=format&fit=crop&q=80', }, { id: 'item-3', name: 'Magnetic Aluminum Desk Stand', variant: 'Silver • Anodized Aluminum', quantity: 1, price: '$35.00', image: 'https://images.unsplash.com/photo-1586105251261-72a756497a11?w=160&auto=format&fit=crop&q=80', }, ] const trackingSteps: TrackingStep[] = [ { id: 'step-1', title: 'Order Placed', date: 'Aug 21, 2026 • 10:42 AM', status: 'completed', description: 'Payment authorized & order confirmed', }, { id: 'step-2', title: 'Processing', date: 'Aug 22, 2026 • 02:15 PM', status: 'completed', description: 'Item picked & packed at warehouse', }, { id: 'step-3', title: 'Shipped', date: 'Aug 23, 2026 • 09:30 AM', status: 'current', description: 'In transit via FedEx Priority • Chicago, IL', }, { id: 'step-4', title: 'Delivered', date: 'Est. Aug 27, 2026', status: 'upcoming', description: 'Estimated delivery to front door', }, ] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-order-confirmation, [ui-order-confirmation]', standalone: true, host: { 'data-slot': 'order-confirmation', '[class]': 'hostClass', }, imports: [ LucideAngularModule, UiBadgeComponent, UiButtonComponent, UiCardComponent, UiCardHeaderComponent, UiCardTitleComponent, UiCardDescriptionComponent, UiCardContentComponent, UiSeparatorComponent, ], template: ` <!-- Success Banner Card --> <div ui-card class="border shadow-xs"> <div ui-card-content class="flex flex-col items-center p-6 text-center sm:p-10"> <div class="bg-success/10 text-success ring-success/10 relative flex size-16 items-center justify-center rounded-full ring-8 sm:size-20" > <lucide-icon [img]="CheckCircle2" class="size-8 sm:size-10" aria-hidden="true" /> </div> <div class="mt-6 max-w-xl space-y-2"> <div class="border-success/20 bg-success/10 text-success inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs font-medium" > <span class="bg-success size-1.5 rounded-full"></span> Order Confirmed </div> <h1 class="text-foreground text-2xl font-bold tracking-tight sm:text-3xl">Thank you for your order!</h1> <p class="text-muted-foreground text-sm sm:text-base"> We've received your order <span class="text-foreground font-mono font-semibold">#ORD-92841</span> and sent a confirmation email to <span class="text-foreground font-medium">customer@example.com</span>. </p> </div> <div class="mt-8 flex flex-wrap items-center justify-center gap-3"> <button ui-button class="gap-2 shadow-xs"> <lucide-icon [img]="ExternalLink" class="size-4" aria-hidden="true" /> Track Shipment </button> <button ui-button aria-label="Download attachment" variant="outline" class="gap-2 shadow-xs"> <lucide-icon [img]="Download" class="size-4" aria-hidden="true" /> Download Receipt </button> <button ui-button variant="ghost" class="text-muted-foreground hover:text-foreground"> Continue Shopping </button> </div> </div> </div> <!-- Tracking Stepper Card --> <div ui-card class="border shadow-xs"> <div ui-card-header class="flex flex-col gap-3 pb-4 sm:flex-row sm:items-center sm:justify-between"> <div class="space-y-1"> <div class="flex items-center gap-2"> <lucide-icon [img]="Truck" class="text-primary size-4" aria-hidden="true" /> <h3 ui-card-title class="text-base font-semibold">Shipment Progress</h3> <span ui-badge variant="secondary" class="bg-primary/10 text-primary text-xs font-medium">In Transit</span> </div> <p class="text-muted-foreground text-xs"> Carrier: <span class="text-foreground font-medium">FedEx Priority</span> • Tracking: <span class="text-foreground font-mono font-medium">#FX-9821734910</span> </p> </div> <div class="border-border/80 bg-muted/40 rounded-lg border px-3 py-1.5 text-xs"> <span class="text-muted-foreground">Estimated Delivery:</span> <span class="text-foreground ml-1 font-semibold">Thursday, Aug 27, 2026</span> </div> </div> <div ui-card-content class="pt-4"> <!-- Desktop Stepper (md+) --> <div class="hidden md:block"> <div class="grid grid-cols-4 gap-4"> @for (step of trackingSteps; track step.id; let idx = $index, last = $last) { <div class="relative flex flex-col"> <div class="relative flex items-center"> <!-- Connecting Line before current step --> @if (idx > 0) { <div class="absolute top-1/2 right-1/2 -z-0 h-0.5 w-full -translate-y-1/2" [class.bg-muted]="step.status === 'upcoming'" [class.bg-primary]="step.status !== 'upcoming'" ></div> } <!-- Connecting Line after current step --> @if (!last) { <div class="absolute top-1/2 left-1/2 -z-0 h-0.5 w-full -translate-y-1/2" [class.bg-muted]="nextIsUpcoming(idx)" [class.bg-primary]="!nextIsUpcoming(idx)" ></div> } <!-- Step Indicator Circle --> <div class="relative z-10 mx-auto flex items-center justify-center"> @switch (step.status) { @case ('completed') { <div class="bg-primary text-primary-foreground ring-background flex size-8 items-center justify-center rounded-full ring-4" > <lucide-icon [img]="Check" class="size-4" aria-hidden="true" /> </div> } @case ('current') { <div class="border-primary bg-background text-primary ring-background flex size-8 items-center justify-center rounded-full border-2 ring-4" > <span class="relative flex size-2.5"> <span class="bg-primary absolute inline-flex h-full w-full rounded-full opacity-75"></span> <span class="bg-primary relative inline-flex size-2.5 rounded-full"></span> </span> </div> } @default { <div class="border-muted-foreground/30 bg-muted/40 text-muted-foreground ring-background flex size-8 items-center justify-center rounded-full border-2 ring-4" > <lucide-icon [img]="Package" class="size-3.5" aria-hidden="true" /> </div> } } </div> </div> <!-- Step Info --> <div class="mt-3 text-center"> <p class="text-sm font-semibold" [class.text-muted-foreground]="step.status === 'upcoming'" [class.text-foreground]="step.status !== 'upcoming'" > {{ step.title }} </p> <p class="text-muted-foreground mt-0.5 text-xs tabular-nums">{{ step.date }}</p> <p class="text-muted-foreground/80 mt-0.5 text-xs">{{ step.description }}</p> </div> </div> } </div> </div> <!-- Mobile Stepper (< md) --> <div class="space-y-4 md:hidden"> @for (step of trackingSteps; track step.id; let idx = $index, last = $last) { <div class="flex items-start gap-3"> <div class="flex flex-col items-center"> @switch (step.status) { @case ('completed') { <div class="bg-primary text-primary-foreground flex size-7 shrink-0 items-center justify-center rounded-full" > <lucide-icon [img]="Check" class="size-3.5" aria-hidden="true" /> </div> } @case ('current') { <div class="border-primary bg-background text-primary flex size-7 shrink-0 items-center justify-center rounded-full border-2" > <span class="relative flex size-2"> <span class="bg-primary absolute inline-flex h-full w-full rounded-full opacity-75"></span> <span class="bg-primary relative inline-flex size-2 rounded-full"></span> </span> </div> } @default { <div class="border-muted-foreground/30 bg-muted/40 text-muted-foreground flex size-7 shrink-0 items-center justify-center rounded-full border-2" > <lucide-icon [img]="Package" class="size-3" aria-hidden="true" /> </div> } } @if (!last) { <div class="mt-1 h-8 w-0.5" [class.bg-muted]="nextIsUpcoming(idx)" [class.bg-primary]="!nextIsUpcoming(idx)" ></div> } </div> <div class="min-w-0 flex-1 pt-0.5 pb-2"> <div class="flex items-center justify-between gap-2"> <p class="text-sm font-semibold" [class.text-muted-foreground]="step.status === 'upcoming'" [class.text-foreground]="step.status !== 'upcoming'" > {{ step.title }} </p> <span class="text-muted-foreground text-xs tabular-nums">{{ step.date }}</span> </div> <p class="text-muted-foreground mt-0.5 text-xs">{{ step.description }}</p> </div> </div> } </div> </div> </div> <!-- 2-Column Details Grid --> <div class="grid grid-cols-1 gap-6 lg:grid-cols-12"> <!-- Left Column: Itemized Order Summary --> <div class="lg:col-span-7"> <div ui-card class="border shadow-xs"> <div ui-card-header class="pb-4"> <h3 ui-card-title class="text-base font-semibold">Order Summary</h3> <p ui-card-description>3 items in shipment</p> </div> <div ui-card-content class="space-y-6"> <!-- Items list --> <div class="space-y-4"> @for (item of orderItems; track item.id) { <div class="flex items-center gap-4"> <div class="border-border bg-muted/40 relative size-16 shrink-0 overflow-hidden rounded-lg border"> <img [src]="item.image" [alt]="item.name" class="h-full w-full object-cover" /> </div> <div class="min-w-0 flex-1"> <p class="text-foreground truncate text-sm font-medium">{{ item.name }}</p> <p class="text-muted-foreground text-xs">{{ item.variant }}</p> <p class="text-muted-foreground mt-1 text-xs">Qty: {{ item.quantity }}</p> </div> <div class="text-right"> <p class="text-foreground text-sm font-semibold tabular-nums">{{ item.price }}</p> </div> </div> } </div> <div ui-separator></div> <!-- Cost breakdown --> <div class="space-y-2 text-sm"> <div class="flex items-center justify-between"> <span class="text-muted-foreground">Subtotal</span> <span class="text-foreground font-medium tabular-nums">$252.00</span> </div> <div class="flex items-center justify-between"> <span class="text-muted-foreground">Shipping (FedEx Priority)</span> <span class="text-success font-medium tabular-nums">Free</span> </div> <div class="flex items-center justify-between"> <span class="text-muted-foreground">Estimated Tax</span> <span class="text-foreground font-medium tabular-nums">$12.50</span> </div> </div> <div ui-separator></div> <!-- Total --> <div class="flex items-center justify-between"> <span class="text-foreground text-base font-semibold">Total</span> <span class="text-foreground text-xl font-bold tabular-nums sm:text-2xl">$264.50</span> </div> </div> </div> </div> <!-- Right Column: Customer & Delivery Details --> <div class="space-y-6 lg:col-span-5"> <!-- Shipping Address Card --> <div ui-card class="border shadow-xs"> <div ui-card-header class="pb-3"> <div class="flex items-center gap-2"> <lucide-icon [img]="MapPin" class="text-muted-foreground size-4" aria-hidden="true" /> <h3 ui-card-title class="text-base font-semibold">Shipping Address</h3> </div> </div> <div ui-card-content class="space-y-3 text-sm"> <div class="space-y-0.5"> <p class="text-foreground font-medium">Alex Morgan</p> <p class="text-muted-foreground">742 Evergreen Terrace, Suite 4B</p> <p class="text-muted-foreground">Springfield, OR 97477</p> <p class="text-muted-foreground">United States</p> <p class="text-muted-foreground mt-1 text-xs">+1 (555) 234-5678</p> </div> <div class="border-border bg-muted/30 rounded-md border p-2.5 text-xs"> <span class="text-muted-foreground">Delivery Method:</span> <span class="text-foreground ml-1 font-medium">FedEx Priority Express</span> </div> </div> </div> <!-- Payment Method Card --> <div ui-card class="border shadow-xs"> <div ui-card-header class="pb-3"> <div class="flex items-center gap-2"> <lucide-icon [img]="CreditCard" class="text-muted-foreground size-4" aria-hidden="true" /> <h3 ui-card-title class="text-base font-semibold">Payment Method</h3> </div> </div> <div ui-card-content class="space-y-3 text-sm"> <div class="flex items-center justify-between"> <div class="flex items-center gap-2.5"> <div class="border-border bg-muted/40 text-foreground flex h-7 w-11 items-center justify-center rounded border font-mono text-xs font-bold" > VISA </div> <div> <p class="text-foreground text-sm font-medium">Visa ending in 4242</p> <p class="text-muted-foreground text-xs">Expires 08/29</p> </div> </div> <span ui-badge variant="secondary" class="bg-success/10 text-success">Paid</span> </div> <p class="text-muted-foreground text-xs">Billing address matches shipping address</p> </div> </div> <!-- Need Help Card --> <div ui-card class="border shadow-xs"> <div ui-card-header class="pb-3"> <div class="flex items-center gap-2"> <lucide-icon [img]="HelpCircle" class="text-muted-foreground size-4" aria-hidden="true" /> <h3 ui-card-title class="text-base font-semibold">Need Help?</h3> </div> </div> <div ui-card-content class="space-y-3 text-sm"> <p class="text-muted-foreground text-xs"> Questions about your order? Chat with support or email support@example.com. </p> <div class="space-y-2 pt-1"> <button ui-button variant="outline" size="sm" class="w-full justify-start gap-2 text-xs shadow-xs"> <lucide-icon [img]="MessageSquare" class="size-3.5" aria-hidden="true" /> Chat with Support </button> <button ui-button variant="ghost" size="sm" class="text-muted-foreground hover:text-foreground w-full justify-start gap-2 text-xs" > <lucide-icon [img]="Mail" class="size-3.5" aria-hidden="true" /> support@example.com </button> </div> </div> </div> </div> </div> `, }) export class UiOrderConfirmationComponent { @Input('class') className?: string protected readonly orderItems = orderItems protected readonly trackingSteps = trackingSteps protected readonly Check = Check protected readonly CheckCircle2 = CheckCircle2 protected readonly CreditCard = CreditCard protected readonly Download = Download protected readonly ExternalLink = ExternalLink protected readonly HelpCircle = HelpCircle protected readonly Mail = Mail protected readonly MapPin = MapPin protected readonly MessageSquare = MessageSquare protected readonly Package = Package protected readonly Truck = Truck get hostClass(): string { return cn('block w-full space-y-6', this.className) } /** The connector into step `idx + 1` is muted while that step is still upcoming. */ protected nextIsUpcoming(idx: number): boolean { return trackingSteps[idx + 1]?.status === 'upcoming' } }src/app/components/blocks/order-confirmation/index.ts0.1 kB
export { UiOrderConfirmationComponent, type OrderItem, type TrackingStep } from './order-confirmation.component'
Raw manifest:https://uipkge.dev/r/angular/order-confirmation.json