feat: implement shimmer loading skeletons for client home header and enhance loading states in banners

This commit is contained in:
Achintha Isuru
2026-03-10 14:32:05 -04:00
parent 4423775fa1
commit 9c7ba321bc
5 changed files with 66 additions and 4 deletions

View File

@@ -22,8 +22,15 @@ class ClientHomeEditBanner extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<ClientHomeBloc, ClientHomeState>(
buildWhen: (ClientHomeState prev, ClientHomeState curr) => prev.isEditMode != curr.isEditMode,
buildWhen: (ClientHomeState prev, ClientHomeState curr) =>
prev.isEditMode != curr.isEditMode ||
prev.status != curr.status,
builder: (BuildContext context, ClientHomeState state) {
if (state.status == ClientHomeStatus.initial ||
state.status == ClientHomeStatus.loading) {
return const SizedBox.shrink();
}
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
height: state.isEditMode ? 80 : 0,

View File

@@ -7,6 +7,7 @@ import '../blocs/client_home_bloc.dart';
import '../blocs/client_home_event.dart';
import '../blocs/client_home_state.dart';
import 'header_icon_button.dart';
import 'client_home_header_skeleton.dart';
/// The header section of the client home page.
///
@@ -26,6 +27,11 @@ class ClientHomeHeader extends StatelessWidget {
Widget build(BuildContext context) {
return BlocBuilder<ClientHomeBloc, ClientHomeState>(
builder: (BuildContext context, ClientHomeState state) {
if (state.status == ClientHomeStatus.initial ||
state.status == ClientHomeStatus.loading) {
return const ClientHomeHeaderSkeleton();
}
final String businessName = state.businessName;
final String? photoUrl = state.photoUrl;
final String avatarLetter = businessName.trim().isNotEmpty

View File

@@ -0,0 +1,50 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the client home header during loading.
///
/// Mimics the avatar, welcome text, business name, and action buttons.
class ClientHomeHeaderSkeleton extends StatelessWidget {
/// Creates a [ClientHomeHeaderSkeleton].
const ClientHomeHeaderSkeleton({super.key});
@override
Widget build(BuildContext context) {
return UiShimmer(
child: Padding(
padding: const EdgeInsets.fromLTRB(
UiConstants.space4,
UiConstants.space4,
UiConstants.space4,
UiConstants.space3,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
const UiShimmerCircle(size: UiConstants.space10),
const SizedBox(width: UiConstants.space3),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
UiShimmerLine(width: 80, height: 12),
SizedBox(height: UiConstants.space1),
UiShimmerLine(width: 120, height: 16),
],
),
],
),
Row(
spacing: UiConstants.space2,
children: const <Widget>[
UiShimmerBox(width: 36, height: 36),
UiShimmerBox(width: 36, height: 36),
],
),
],
),
),
);
}
}

View File

@@ -9,7 +9,6 @@ class ReorderCardSkeleton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 260,
padding: const EdgeInsets.all(UiConstants.space3),
decoration: BoxDecoration(
border: Border.all(color: UiColors.border, width: 0.6),

View File

@@ -19,9 +19,9 @@ class ReorderSectionSkeleton extends StatelessWidget {
height: 164,
child: Row(
children: <Widget>[
ReorderCardSkeleton(),
Expanded(child: ReorderCardSkeleton()),
SizedBox(width: UiConstants.space3),
ReorderCardSkeleton(),
Expanded(child: ReorderCardSkeleton()),
],
),
),