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 'package:krow_domain/krow_domain.dart';
import '../bloc/clock_in_bloc.dart';
import '../bloc/clock_in_event.dart';
import '../bloc/clock_in_state.dart';
import '../widgets/clock_in_page_skeleton/clock_in_page_skeleton.dart';
import '../widgets/commute_tracker.dart';
import '../widgets/date_selector.dart';
import '../widgets/lunch_break_modal.dart';
@@ -52,8 +53,9 @@ class _ClockInPageState extends State<ClockInPage> {
builder: (BuildContext context, ClockInState state) {
if (state.status == ClockInStatus.loading &&
state.todayShifts.isEmpty) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
return Scaffold(
appBar: UiAppBar(title: i18n.title, showBackButton: false),
body: const SafeArea(child: ClockInPageSkeleton()),
);
}

View File

@@ -0,0 +1,16 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the "Your Activity" section header text.
class ActivityHeaderSkeleton extends StatelessWidget {
/// Creates a shimmer line matching the activity header.
const ActivityHeaderSkeleton({super.key});
@override
Widget build(BuildContext context) {
return const Align(
alignment: Alignment.centerLeft,
child: UiShimmerLine(width: 120, height: 18),
);
}
}

View File

@@ -0,0 +1,52 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'activity_header_skeleton.dart';
import 'date_selector_skeleton.dart';
import 'shift_card_skeleton.dart';
import 'swipe_action_skeleton.dart';
/// Full-page shimmer skeleton shown while clock-in data loads.
///
/// Mirrors the loaded [ClockInPage] layout: date selector, activity header,
/// two shift cards, and the swipe-to-check-in bar.
class ClockInPageSkeleton extends StatelessWidget {
/// Creates the clock-in page shimmer skeleton.
const ClockInPageSkeleton({super.key});
@override
Widget build(BuildContext context) {
return UiShimmer(
child: SingleChildScrollView(
padding: const EdgeInsets.only(
bottom: UiConstants.space24,
top: UiConstants.space6,
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: UiConstants.space5,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
// Date selector row
DateSelectorSkeleton(),
SizedBox(height: UiConstants.space5),
// "Your Activity" header
ActivityHeaderSkeleton(),
SizedBox(height: UiConstants.space4),
// Shift cards (show two placeholders)
ShiftCardSkeleton(),
ShiftCardSkeleton(),
// Swipe action bar
SwipeActionSkeleton(),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,32 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the [DateSelector] row of 7 day chips.
class DateSelectorSkeleton extends StatelessWidget {
/// Creates a shimmer placeholder matching the date selector layout.
const DateSelectorSkeleton({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 80,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List<Widget>.generate(7, (int index) {
return Expanded(
child: Container(
margin: const EdgeInsets.symmetric(
horizontal: UiConstants.space1,
),
child: const UiShimmerBox(
width: double.infinity,
height: 80,
borderRadius: UiConstants.radiusLg,
),
),
);
}),
),
);
}
}

View File

@@ -0,0 +1,52 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for a single shift info card.
///
/// Mirrors the two-column layout: left side has badge, title, and subtitle
/// lines; right side has time range and rate lines.
class ShiftCardSkeleton extends StatelessWidget {
/// Creates a shimmer placeholder for one shift card.
const ShiftCardSkeleton({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(UiConstants.space3),
margin: const EdgeInsets.only(bottom: UiConstants.space3),
decoration: BoxDecoration(
color: UiColors.white,
borderRadius: UiConstants.radiusLg,
border: Border.all(color: UiColors.border),
),
child: const Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// Left column: badge + title + subtitle
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
UiShimmerLine(width: 80, height: 10),
SizedBox(height: UiConstants.space2),
UiShimmerLine(width: 160, height: 14),
SizedBox(height: UiConstants.space1),
UiShimmerLine(width: 200, height: 12),
],
),
),
SizedBox(width: UiConstants.space3),
// Right column: time + rate
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
UiShimmerLine(width: 100, height: 12),
SizedBox(height: UiConstants.space1),
UiShimmerLine(width: 60, height: 12),
],
),
],
),
);
}
}

View File

@@ -0,0 +1,17 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the swipe-to-check-in action area.
class SwipeActionSkeleton extends StatelessWidget {
/// Creates a shimmer placeholder matching the swipe bar height.
const SwipeActionSkeleton({super.key});
@override
Widget build(BuildContext context) {
return const UiShimmerBox(
width: double.infinity,
height: 60,
borderRadius: UiConstants.radiusLg,
);
}
}