feat: add shimmer skeletons for various sections in the staff profile and onboarding features

- Implemented ProfilePageSkeleton for loading state in staff profile.
- Added ReliabilityScoreSkeleton and ReliabilityStatsSkeleton for reliability metrics.
- Created CertificatesSkeleton and related components for loading certificates.
- Developed DocumentsSkeleton and associated document card skeletons.
- Introduced TaxFormsSkeleton for loading tax forms.
- Added BankAccountSkeleton and its components for bank account loading state.
- Created TimeCardSkeleton for displaying time card loading state.
- Implemented AttireSkeleton for loading attire items.
- Added PersonalInfoSkeleton for loading personal information.
- Developed FaqsSkeleton for loading FAQ sections.
- Created PrivacySecuritySkeleton for loading privacy settings.
This commit is contained in:
Achintha Isuru
2026-03-10 15:20:24 -04:00
parent ccf1a75a4d
commit bd98a112a0
60 changed files with 1718 additions and 31 deletions

View File

@@ -10,6 +10,7 @@ import '../blocs/bank_account_cubit.dart';
import '../blocs/bank_account_state.dart';
import '../widgets/account_card.dart';
import '../widgets/add_account_form.dart';
import '../widgets/bank_account_skeleton/bank_account_skeleton.dart';
import '../widgets/security_notice.dart';
class BankAccountPage extends StatelessWidget {
@@ -49,7 +50,7 @@ class BankAccountPage extends StatelessWidget {
builder: (BuildContext context, BankAccountState state) {
if (state.status == BankAccountStatus.loading &&
state.accounts.isEmpty) {
return const Center(child: CircularProgressIndicator());
return const BankAccountSkeleton();
}
if (state.status == BankAccountStatus.error) {

View File

@@ -0,0 +1,37 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for a single bank account card.
class AccountCardSkeleton extends StatelessWidget {
/// Creates an [AccountCardSkeleton].
const AccountCardSkeleton({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
border: Border.all(color: UiColors.border),
borderRadius: UiConstants.radiusLg,
color: UiColors.cardViewBackground,
),
child: const Row(
children: <Widget>[
UiShimmerCircle(size: 40),
SizedBox(width: UiConstants.space3),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
UiShimmerLine(width: 140, height: 14),
SizedBox(height: UiConstants.space2),
UiShimmerLine(width: 100, height: 12),
],
),
),
UiShimmerBox(width: 48, height: 24),
],
),
);
}
}

View File

@@ -0,0 +1,32 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'account_card_skeleton.dart';
import 'security_notice_skeleton.dart';
/// Full-page shimmer skeleton shown while bank accounts are loading.
class BankAccountSkeleton extends StatelessWidget {
/// Creates a [BankAccountSkeleton].
const BankAccountSkeleton({super.key});
@override
Widget build(BuildContext context) {
return UiShimmer(
child: SingleChildScrollView(
padding: const EdgeInsets.all(UiConstants.space4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SecurityNoticeSkeleton(),
const SizedBox(height: UiConstants.space4),
UiShimmerList(
itemCount: 2,
spacing: UiConstants.space3,
itemBuilder: (int index) => const AccountCardSkeleton(),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,36 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the security notice banner.
class SecurityNoticeSkeleton extends StatelessWidget {
/// Creates a [SecurityNoticeSkeleton].
const SecurityNoticeSkeleton({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
border: Border.all(color: UiColors.border),
borderRadius: UiConstants.radiusLg,
color: UiColors.cardViewBackground,
),
child: const Row(
children: <Widget>[
UiShimmerCircle(size: 24),
SizedBox(width: UiConstants.space3),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
UiShimmerLine(width: 160, height: 14),
SizedBox(height: UiConstants.space2),
UiShimmerLine(height: 12),
],
),
),
],
),
);
}
}

View File

@@ -8,6 +8,7 @@ import 'package:krow_core/core.dart';
import '../blocs/time_card_bloc.dart';
import '../widgets/month_selector.dart';
import '../widgets/shift_history_list.dart';
import '../widgets/time_card_skeleton/time_card_skeleton.dart';
import '../widgets/time_card_summary.dart';
/// The main page for displaying the staff time card.
@@ -50,7 +51,7 @@ class _TimeCardPageState extends State<TimeCardPage> {
},
builder: (BuildContext context, TimeCardState state) {
if (state is TimeCardLoading) {
return const Center(child: CircularProgressIndicator());
return const TimeCardSkeleton();
} else if (state is TimeCardError) {
return Center(
child: Padding(

View File

@@ -0,0 +1,20 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the month selector row.
class MonthSelectorSkeleton extends StatelessWidget {
/// Creates a [MonthSelectorSkeleton].
const MonthSelectorSkeleton({super.key});
@override
Widget build(BuildContext context) {
return const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
UiShimmerCircle(size: 32),
UiShimmerLine(width: 120, height: 16),
UiShimmerCircle(size: 32),
],
);
}
}

View File

@@ -0,0 +1,42 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for a single shift history row.
class ShiftHistorySkeleton extends StatelessWidget {
/// Creates a [ShiftHistorySkeleton].
const ShiftHistorySkeleton({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
border: Border.all(color: UiColors.border),
borderRadius: UiConstants.radiusLg,
color: UiColors.cardViewBackground,
),
child: const Row(
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
UiShimmerLine(width: 140, height: 14),
SizedBox(height: UiConstants.space2),
UiShimmerLine(width: 100, height: 12),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
UiShimmerLine(width: 60, height: 14),
SizedBox(height: UiConstants.space2),
UiShimmerLine(width: 40, height: 12),
],
),
],
),
);
}
}

View File

@@ -0,0 +1,37 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'month_selector_skeleton.dart';
import 'shift_history_skeleton.dart';
import 'time_card_summary_skeleton.dart';
/// Full-page shimmer skeleton shown while time card data is loading.
class TimeCardSkeleton extends StatelessWidget {
/// Creates a [TimeCardSkeleton].
const TimeCardSkeleton({super.key});
@override
Widget build(BuildContext context) {
return UiShimmer(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(
horizontal: UiConstants.space5,
vertical: UiConstants.space6,
),
child: Column(
children: <Widget>[
const MonthSelectorSkeleton(),
const SizedBox(height: UiConstants.space6),
const TimeCardSummarySkeleton(),
const SizedBox(height: UiConstants.space6),
UiShimmerList(
itemCount: 5,
spacing: UiConstants.space3,
itemBuilder: (int index) => const ShiftHistorySkeleton(),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,19 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the time card summary (hours + earnings).
class TimeCardSummarySkeleton extends StatelessWidget {
/// Creates a [TimeCardSummarySkeleton].
const TimeCardSummarySkeleton({super.key});
@override
Widget build(BuildContext context) {
return const Row(
children: <Widget>[
Expanded(child: UiShimmerStatsCard()),
SizedBox(width: UiConstants.space3),
Expanded(child: UiShimmerStatsCard()),
],
);
}
}