Fliin
On this page

Screens / commerce

Order confirmation

Confirms a paid order with its number, estimated delivery, address, items and amounts paid, then tracking or home, with no way back to the payment.

16 of 16 variants pass
Order confirmation, confirmed state
Platform
Brightness
Text scale
Direction

Import

Order confirmation is part of Fliin Pro. With a license key, sign in once with fliin login, then add it in a Flutter app where fliin init has run:

fliin login
fliin add order-confirmation

Also installs: app-bar, button, core, empty-state, icons, list-row, order-summary, page, result-card, section-header, separator, skeleton, surface, text

Examples

Confirmed

The order just paid: its number, items and delivery, with a way to track it (onTrack) or go home.

Order confirmation, confirmed state
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_controller.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_data.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_screen.dart';
import 'package:flutter/widgets.dart';

class OrderConfirmationConfirmedExample extends StatelessWidget {
  const OrderConfirmationConfirmedExample({super.key});

  @override
  Widget build(BuildContext context) {
    return OrderConfirmationScreen.standalone(
      service: const SampleOrderConfirmationService(latency: Duration(milliseconds: 600)),
      orderId: sampleOrder.id,
      initial: const OrderConfirmationShown(sampleOrder),
      onHome: () {},
      onTrack: (_) {},
    );
  }
}

Loading

While the order loads, placeholders keep its layout.

Order confirmation, loading state
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_controller.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_data.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_screen.dart';
import 'package:flutter/widgets.dart';

class OrderConfirmationLoadingExample extends StatelessWidget {
  const OrderConfirmationLoadingExample({super.key});

  @override
  Widget build(BuildContext context) {
    return OrderConfirmationScreen.standalone(
      service: const SampleOrderConfirmationService(latency: Duration(milliseconds: 600)),
      orderId: sampleOrder.id,
      initial: const OrderConfirmationLoading(),
      onHome: () {},
      onTrack: (_) {},
    );
  }
}

Error

When the order cannot load, the screen says so and offers to try again; the payment itself went through.

Order confirmation, error state
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_controller.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_data.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_screen.dart';
import 'package:flutter/widgets.dart';

class OrderConfirmationErrorExample extends StatelessWidget {
  const OrderConfirmationErrorExample({super.key});

  @override
  Widget build(BuildContext context) {
    return OrderConfirmationScreen.standalone(
      service: const SampleOrderConfirmationService(latency: Duration(milliseconds: 600)),
      orderId: sampleOrder.id,
      initial: const OrderConfirmationFailed(),
      onHome: () {},
      onTrack: (_) {},
    );
  }
}

Offline

Without a connection, the screen asks to reconnect to show the order.

Order confirmation, offline state
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_controller.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_data.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_screen.dart';
import 'package:flutter/widgets.dart';

class OrderConfirmationOfflineExample extends StatelessWidget {
  const OrderConfirmationOfflineExample({super.key});

  @override
  Widget build(BuildContext context) {
    return OrderConfirmationScreen.standalone(
      service: const SampleOrderConfirmationService(latency: Duration(milliseconds: 600)),
      orderId: sampleOrder.id,
      initial: const OrderConfirmationOffline(),
      onHome: () {},
      onTrack: (_) {},
    );
  }
}

Referral

A short confirmation with your own ending: showItems: false leaves out the items, footer adds an invitation under the amounts.

Order confirmation, referral state
import 'package:your_app/ui/fliin/components/button/fl_button.dart';
import 'package:your_app/ui/fliin/components/surface/fl_surface.dart';
import 'package:your_app/ui/fliin/components/text/fl_text.dart';
import 'package:your_app/ui/fliin/core/fliin.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_controller.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_data.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_screen.dart';
import 'package:flutter/widgets.dart';

class OrderConfirmationReferralExample extends StatelessWidget {
  const OrderConfirmationReferralExample({super.key});

  @override
  Widget build(BuildContext context) {
    final space = FlScope.of(context).space;
    return OrderConfirmationScreen.standalone(
      service: const SampleOrderConfirmationService(latency: Duration(milliseconds: 600)),
      orderId: sampleOrder.id,
      initial: const OrderConfirmationShown(sampleOrder),
      showItems: false,
      footer: FlSurface(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          spacing: space.sm,
          children: [
            const FlText('Give €10, get €10', type: FlTextType.h6),
            const FlText(
              'Your friends get €10 off their first order, and you get €10 when it ships.',
              type: FlTextType.bodySm,
              tone: FlTextTone.muted,
            ),
            Padding(
              padding: EdgeInsetsDirectional.only(top: space.xs),
              child: FlButton(
                label: 'Invite friends',
                variant: FlButtonVariant.outline,
                size: FlButtonSize.sm,
                onPressed: () {},
              ),
            ),
          ],
        ),
      ),
      onHome: () {},
      onTrack: (_) {},
    );
  }
}

Routing

fliin add order-confirmation prints the route for the router it finds in your pubspec, a file next to the page that wires its navigation. Each of them:

go_router

// lib/order_confirmation_route.dart, next to order_confirmation_page.dart.
import 'package:go_router/go_router.dart';

import 'order_confirmation_page.dart';

/// Add orderConfirmationRoute to the routes of your GoRouter.
final orderConfirmationRoute = GoRoute(
  path: '/order/:id',
  builder: (context, state) => OrderConfirmationPage(
    orderId: state.pathParameters['id']!,
    // '/': your app's home.
    onHome: () => context.go('/'),
    onTrack: (id) => context.push('/orders/${Uri.encodeComponent(id)}'),
  ),
);

navigator

// lib/order_confirmation_route.dart, next to order_confirmation_page.dart.
import 'package:flutter/material.dart';

import 'order_confirmation_page.dart';
import 'order_route.dart';

/// Opens “Order confirmation”: `Navigator.of(context).pushReplacement(orderConfirmationRoute(orderId, parcelTrackingPage: …, returnPage: …, supportPage: …, cartPage: …))`.
/// [parcelTrackingPage] builds the parcel tracking in your app.
/// [returnPage] builds the return of an order in your app.
/// [supportPage] builds the help on an order in your app.
/// [cartPage] builds the cart: the page of Fliin's checkout screen with its callbacks, or yours (checkoutRoute cannot come from here, checkout leads to order).
Route<void> orderConfirmationRoute(
  String orderId, {
  required Widget Function(String orderId) parcelTrackingPage,
  required Widget Function(String orderId) returnPage,
  required Widget Function(String orderId) supportPage,
  required WidgetBuilder cartPage,
}) => MaterialPageRoute<void>(
  builder: (context) => OrderConfirmationPage(
    orderId: orderId,
    onHome: () => Navigator.of(context).popUntil((route) => route.isFirst),
    onTrack: (id) => Navigator.of(context).push(orderRoute(id, parcelTrackingPage: parcelTrackingPage, returnPage: returnPage, supportPage: supportPage, cartPage: cartPage)),
  ),
);

State

The controller is a ChangeNotifier from widgets.dart, with no package. fliin add order-confirmation prints the page that holds it with the state management it finds, its imports written for your package; below they read your_app. Your backend implements the Service interface of the screen's _data.dart file:

none

// lib/order_confirmation_page.dart
// Your backend: implement OrderConfirmationService (order_confirmation_data.dart) and pass it instead of the sample service.
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_data.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_screen.dart';
import 'package:flutter/widgets.dart';

class OrderConfirmationPage extends StatelessWidget {
  const OrderConfirmationPage({
    super.key,
    required this.orderId,
    required this.onHome,
    required this.onTrack,
  });

  final String orderId;
  final VoidCallback onHome;
  final ValueChanged<String> onTrack;

  @override
  Widget build(BuildContext context) => OrderConfirmationScreen.standalone(
    key: ValueKey(orderId),
    service: const SampleOrderConfirmationService(),
    orderId: orderId,
    onHome: onHome,
    onTrack: onTrack,
  );
}

provider

// lib/order_confirmation_page.dart
// Your backend: implement OrderConfirmationService (order_confirmation_data.dart) and pass it instead of the sample service.
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_controller.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_data.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_screen.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';

class OrderConfirmationPage extends StatelessWidget {
  const OrderConfirmationPage({
    super.key,
    required this.orderId,
    required this.onHome,
    required this.onTrack,
  });

  final String orderId;
  final VoidCallback onHome;
  final ValueChanged<String> onTrack;

  @override
  Widget build(BuildContext context) => ChangeNotifierProvider(
    create: (_) => OrderConfirmationController(service: const SampleOrderConfirmationService(), orderId: orderId)..load(),
    child: Builder(
      builder: (context) => OrderConfirmationScreen(
        controller: context.read<OrderConfirmationController>(),
        onHome: onHome,
        onTrack: onTrack,
      ),
    ),
  );
}

riverpod

// lib/order_confirmation_page.dart
// Your backend: implement OrderConfirmationService (order_confirmation_data.dart) and pass it instead of the sample service.
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_controller.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_data.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_screen.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final orderConfirmationControllerProvider = Provider.autoDispose.family<OrderConfirmationController, String>((ref, orderId) {
  final controller = OrderConfirmationController(service: const SampleOrderConfirmationService(), orderId: orderId)..load();
  ref.onDispose(controller.dispose);
  return controller;
});

class OrderConfirmationPage extends ConsumerWidget {
  const OrderConfirmationPage({
    super.key,
    required this.orderId,
    required this.onHome,
    required this.onTrack,
  });

  final String orderId;
  final VoidCallback onHome;
  final ValueChanged<String> onTrack;

  @override
  Widget build(BuildContext context, WidgetRef ref) => OrderConfirmationScreen(
    controller: ref.watch(orderConfirmationControllerProvider(orderId)),
    onHome: onHome,
    onTrack: onTrack,
  );
}

bloc

// lib/order_confirmation_page.dart
// Your backend: implement OrderConfirmationService (order_confirmation_data.dart) and pass it instead of the sample service.
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_controller.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_data.dart';
import 'package:your_app/ui/fliin/screens/order_confirmation/order_confirmation_screen.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

/// The screen's controller as a bloc, for your BlocListener and BlocBuilder:
/// one emission per controller notification. `version` tells them apart
/// when `state` does not change (mode, filters, text…, read them on
/// `controller`). The screen listens to the controller itself.
class OrderConfirmationCubit extends Cubit<({OrderConfirmationState state, int version})> {
  OrderConfirmationCubit(this.controller) : super((state: controller.state, version: 0)) {
    controller.addListener(_changed);
  }

  final OrderConfirmationController controller;

  void _changed() => emit((state: controller.state, version: state.version + 1));

  @override
  Future<void> close() {
    controller
      ..removeListener(_changed)
      ..dispose();
    return super.close();
  }
}

class OrderConfirmationPage extends StatelessWidget {
  const OrderConfirmationPage({
    super.key,
    required this.orderId,
    required this.onHome,
    required this.onTrack,
  });

  final String orderId;
  final VoidCallback onHome;
  final ValueChanged<String> onTrack;

  @override
  Widget build(BuildContext context) => BlocProvider(
    create: (_) => OrderConfirmationCubit(OrderConfirmationController(service: const SampleOrderConfirmationService(), orderId: orderId)..load()),
    child: Builder(
      builder: (context) => OrderConfirmationScreen(
        controller: context.read<OrderConfirmationCubit>().controller,
        onHome: onHome,
        onTrack: onTrack,
      ),
    ),
  );
}

The snippets lead to order: install these screens too and paste their snippets.

API

OrderConfirmationScreen: class extends StatefulWidget
OrderConfirmationScreen.new: const new({super.key, required OrderConfirmationController controller, required VoidCallback onHome, ValueChanged<String>? onTrack, bool showItems, Widget? footer})
OrderConfirmationScreen.standalone: const new({super.key, required OrderConfirmationService service, required String orderId, required VoidCallback onHome, OrderConfirmationState? initial, ValueChanged<String>? onTrack, bool showItems, Widget? footer})
OrderConfirmationScreen.controller: get OrderConfirmationController?
OrderConfirmationScreen.service: get OrderConfirmationService?
OrderConfirmationScreen.orderId: get String?
OrderConfirmationScreen.initial: get OrderConfirmationState?
OrderConfirmationScreen.onHome: get VoidCallback
OrderConfirmationScreen.onTrack: get ValueChanged<String>?
OrderConfirmationScreen.showItems: get bool
OrderConfirmationScreen.footer: get Widget?
OrderConfirmationScreen.createState: State<OrderConfirmationScreen>()
OrderConfirmationState: sealed class permits {OrderConfirmationFailed, OrderConfirmationLoading, OrderConfirmationOffline, OrderConfirmationShown}
OrderConfirmationState.new: const new()
OrderConfirmationLoading: final class extends OrderConfirmationState
OrderConfirmationLoading.new: const new()
OrderConfirmationShown: final class extends OrderConfirmationState
OrderConfirmationShown.new: const new(Order order)
OrderConfirmationShown.order: get Order
OrderConfirmationFailed: final class extends OrderConfirmationState
OrderConfirmationFailed.new: const new()
OrderConfirmationOffline: final class extends OrderConfirmationState
OrderConfirmationOffline.new: const new()
OrderConfirmationController: class extends ChangeNotifier
OrderConfirmationController.new: new({required OrderConfirmationService service, required String orderId, OrderConfirmationState initial})
OrderConfirmationController.service: get OrderConfirmationService
OrderConfirmationController.orderId: get String
OrderConfirmationController.state: get OrderConfirmationState
OrderConfirmationController.load: Future<void>()
OrderConfirmationController.dispose: void()
OrderLine: final class
OrderLine.new: const new({required String title, required String price, required int quantity, String? variant, ImageProvider? image})
OrderLine.title: get String
OrderLine.price: get String
OrderLine.quantity: get int
OrderLine.variant: get String?
OrderLine.image: get ImageProvider?
OrderTotals: final class
OrderTotals.new: const new({required String subtotal, required String shipping, required String total, String? discount, String? tax})
OrderTotals.subtotal: get String
OrderTotals.shipping: get String
OrderTotals.discount: get String?
OrderTotals.tax: get String?
OrderTotals.total: get String
Order: final class
Order.new: const new({required String id, required String number, required List<OrderLine> lines, required OrderTotals totals, required String estimatedDelivery, required String address, String? customerName, String? email})
Order.id: get String
Order.number: get String
Order.lines: get List<OrderLine>
Order.totals: get OrderTotals
Order.estimatedDelivery: get String
Order.address: get String
Order.customerName: get String?
Order.email: get String?
OrderConfirmationNoNetwork: final class implements Exception
OrderConfirmationNoNetwork.new: const new()
OrderConfirmationService: abstract interface class
OrderConfirmationService.new: new()
OrderConfirmationService.load: abstract Future<Order>(String id)
sampleOrder: const dynamic
SampleOrderConfirmationService: final class implements OrderConfirmationService
SampleOrderConfirmationService.new: const new({Order order, Duration latency})
SampleOrderConfirmationService.order: get Order
SampleOrderConfirmationService.latency: get Duration
SampleOrderConfirmationService.load: Future<Order>(String id)
orderConfirmationL10n: const Map<String, Map<String, String>>
OrderConfirmationStrings: final class
OrderConfirmationStrings.new: const new(String language)
OrderConfirmationStrings.of: factory new(BuildContext context)
OrderConfirmationStrings.language: get String
OrderConfirmationStrings.title: get String
OrderConfirmationStrings.loading: get String
OrderConfirmationStrings.thanks: String(String name)
OrderConfirmationStrings.number: String(String number)
OrderConfirmationStrings.email: String(String email)
OrderConfirmationStrings.estimate: get String
OrderConfirmationStrings.address: get String
OrderConfirmationStrings.items: get String
OrderConfirmationStrings.quantity: String(String quantity)
OrderConfirmationStrings.summary: get String
OrderConfirmationStrings.subtotal: get String
OrderConfirmationStrings.shipping: get String
OrderConfirmationStrings.discount: get String
OrderConfirmationStrings.tax: get String
OrderConfirmationStrings.total: get String
OrderConfirmationStrings.track: get String
OrderConfirmationStrings.home: get String
OrderConfirmationStrings.errorTitle: get String
OrderConfirmationStrings.errorMessage: get String
OrderConfirmationStrings.offlineTitle: get String
OrderConfirmationStrings.offlineMessage: get String
OrderConfirmationStrings.retry: get String

Strings

Every label in English, French and Arabic. The screen follows the closest Localizations; the same table is in the manifest, ready for your ARB files.

Keyenfrar
orderConfirmationTitleOrder confirmedCommande confirméeتم تأكيد الطلب
orderConfirmationLoadingLoading your orderChargement de la commandeجارٍ تحميل الطلب
orderConfirmationThanksThank you, {name}!Merci, {name} !شكرًا لك، {name}!
orderConfirmationNumberOrder {number}Commande {number}الطلب {number}
orderConfirmationEmailA receipt is on its way to {email}.Un reçu part à {email}.سيصلك إيصال على {email}.
orderConfirmationEstimateEstimated deliveryLivraison estiméeموعد التوصيل المتوقع
orderConfirmationAddressDelivery addressAdresse de livraisonعنوان التوصيل
orderConfirmationItemsItemsArticlesالمنتجات
orderConfirmationQuantityQuantity: {quantity}Quantité : {quantity}الكمية: {quantity}
orderConfirmationSummarySummaryRécapitulatifالملخص
orderConfirmationSubtotalSubtotalSous-totalالمجموع الفرعي
orderConfirmationShippingShippingLivraisonالشحن
orderConfirmationDiscountDiscountRemiseالخصم
orderConfirmationTaxTaxesTaxesالضرائب
orderConfirmationTotalTotal paidTotal payéالإجمالي المدفوع
orderConfirmationTrackTrack my orderSuivre ma commandeتتبّع طلبي
orderConfirmationHomeBack to homeRetour à l’accueilالعودة إلى الرئيسية
orderConfirmationErrorTitleYour order could not loadImpossible de charger la commandeتعذّر تحميل الطلب
orderConfirmationErrorMessageYour order is placed. Only this page could not load.Votre commande est bien passée. Seule cette page n’a pas pu se charger.تم تقديم طلبك. تعذّر تحميل هذه الصفحة فقط.
orderConfirmationOfflineTitleYou are offlineVous êtes hors ligneأنت غير متصل
orderConfirmationOfflineMessageYour order is placed. Connect to see its details.Votre commande est bien passée. Connectez-vous pour en voir le détail.تم تقديم طلبك. اتصل لعرض تفاصيله.
orderConfirmationRetryTry againRéessayerأعد المحاولة

Reference renders

The 16 images published with version 0.2.5, rendered by the shared harness on macOS with Flutter 3.47.7. Each shows every state side by side, at the size of an iPhone (390 × 844) or of an Android phone (412 × 915). fliin verify order-confirmation compares your copy to them.

iOS · Light
Order confirmation, iOS, Light, text 1.0×, Left to right
Text 1.0× · Left to right
Order confirmation, iOS, Light, text 1.0×, Right to left
Text 1.0× · Right to left
Order confirmation, iOS, Light, text 2.0×, Left to right
Text 2.0× · Left to right
Order confirmation, iOS, Light, text 2.0×, Right to left
Text 2.0× · Right to left
iOS · Dark
Order confirmation, iOS, Dark, text 1.0×, Left to right
Text 1.0× · Left to right
Order confirmation, iOS, Dark, text 1.0×, Right to left
Text 1.0× · Right to left
Order confirmation, iOS, Dark, text 2.0×, Left to right
Text 2.0× · Left to right
Order confirmation, iOS, Dark, text 2.0×, Right to left
Text 2.0× · Right to left
Android · Light
Order confirmation, Android, Light, text 1.0×, Left to right
Text 1.0× · Left to right
Order confirmation, Android, Light, text 1.0×, Right to left
Text 1.0× · Right to left
Order confirmation, Android, Light, text 2.0×, Left to right
Text 2.0× · Left to right
Order confirmation, Android, Light, text 2.0×, Right to left
Text 2.0× · Right to left
Android · Dark
Order confirmation, Android, Dark, text 1.0×, Left to right
Text 1.0× · Left to right
Order confirmation, Android, Dark, text 1.0×, Right to left
Text 1.0× · Right to left
Order confirmation, Android, Dark, text 2.0×, Left to right
Text 2.0× · Left to right
Order confirmation, Android, Dark, text 2.0×, Right to left
Text 2.0× · Right to left

Use it to

  • confirm an order as soon as it is placed
  • show the order number and the expected delivery date
  • offer to track the order once bought
  • show a receipt of the items and the amount paid
  • show a thanks note for a completed purchase
Not for
  • the cart before payment: use the checkout screen (checkout)
  • a list of past orders: use list rows (list-row)
States
  • Confirmed
  • Loading
  • Error
  • Offline

Arrows to move, Enter to open, Escape to close.