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 '../blocs/availability_bloc.dart';
import '../blocs/availability_event.dart';
import '../blocs/availability_state.dart';
import '../widgets/availability_page_skeleton/availability_page_skeleton.dart';
class AvailabilityPage extends StatefulWidget {
const AvailabilityPage({super.key});
@@ -72,7 +73,7 @@ class _AvailabilityPageState extends State<AvailabilityPage> {
child: BlocBuilder<AvailabilityBloc, AvailabilityState>(
builder: (context, state) {
if (state is AvailabilityLoading) {
return const Center(child: CircularProgressIndicator());
return const AvailabilityPageSkeleton();
} else if (state is AvailabilityLoaded) {
return Stack(
children: [

View File

@@ -0,0 +1 @@
export 'availability_page_skeleton/index.dart';

View File

@@ -0,0 +1,36 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'day_availability_skeleton.dart';
import 'info_card_skeleton.dart';
import 'quick_set_skeleton.dart';
import 'week_navigation_skeleton.dart';
/// Shimmer loading skeleton for the availability page.
///
/// Mimics the loaded layout: quick-set buttons, week navigation calendar,
/// selected day detail with time-slot rows, and an info card.
class AvailabilityPageSkeleton extends StatelessWidget {
/// Creates an [AvailabilityPageSkeleton].
const AvailabilityPageSkeleton({super.key});
@override
Widget build(BuildContext context) {
return UiShimmer(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(
horizontal: UiConstants.space5,
),
child: Column(
spacing: UiConstants.space6,
children: const [
QuickSetSkeleton(),
WeekNavigationSkeleton(),
DayAvailabilitySkeleton(),
InfoCardSkeleton(),
],
),
),
);
}
}

View File

@@ -0,0 +1,88 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the selected day detail card (header + time slot rows).
class DayAvailabilitySkeleton extends StatelessWidget {
/// Creates a [DayAvailabilitySkeleton].
const DayAvailabilitySkeleton({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(UiConstants.space5),
decoration: BoxDecoration(
color: UiColors.white,
borderRadius: UiConstants.radiusLg,
),
child: Column(
children: [
// Header: date text + toggle placeholder
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
UiShimmerLine(width: 160, height: 16),
SizedBox(height: UiConstants.space1),
UiShimmerLine(width: 80, height: 12),
],
),
UiShimmerBox(
width: 48,
height: 28,
borderRadius: UiConstants.radiusFull,
),
],
),
const SizedBox(height: UiConstants.space4),
// 3 time-slot rows (morning, afternoon, evening)
..._buildSlotPlaceholders(),
],
),
);
}
/// Generates 3 time-slot shimmer rows.
List<Widget> _buildSlotPlaceholders() {
return List.generate(3, (index) {
return Padding(
padding: EdgeInsets.only(
bottom: index < 2 ? UiConstants.space3 : 0,
),
child: Container(
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: UiColors.white,
borderRadius: UiConstants.radiusLg,
),
child: Row(
children: [
// Icon placeholder
UiShimmerBox(
width: 40,
height: 40,
borderRadius:
UiConstants.radiusLg,
),
const SizedBox(width: UiConstants.space3),
// Text lines
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
UiShimmerLine(width: 80, height: 14),
SizedBox(height: UiConstants.space1),
UiShimmerLine(width: 120, height: 12),
],
),
),
// Checkbox circle
const UiShimmerCircle(size: 24),
],
),
),
);
});
}
}

View File

@@ -0,0 +1,5 @@
export 'availability_page_skeleton.dart';
export 'day_availability_skeleton.dart';
export 'info_card_skeleton.dart';
export 'quick_set_skeleton.dart';
export 'week_navigation_skeleton.dart';

View File

@@ -0,0 +1,36 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the info card at the bottom (icon + two text lines).
class InfoCardSkeleton extends StatelessWidget {
/// Creates an [InfoCardSkeleton].
const InfoCardSkeleton({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: UiColors.white,
borderRadius: UiConstants.radiusLg,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const UiShimmerCircle(size: 20),
const SizedBox(width: UiConstants.space3),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
UiShimmerLine(width: 140, height: 14),
SizedBox(height: UiConstants.space1),
UiShimmerLine(height: 12),
],
),
),
],
),
);
}
}

View File

@@ -0,0 +1,45 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the quick-set section (title + 4 action buttons).
class QuickSetSkeleton extends StatelessWidget {
/// Creates a [QuickSetSkeleton].
const QuickSetSkeleton({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: UiColors.white,
borderRadius: UiConstants.radiusLg,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Title line
const UiShimmerLine(width: 100, height: 14),
const SizedBox(height: UiConstants.space3),
// Row of 4 button placeholders
Row(
children: List.generate(4, (index) {
return Expanded(
child: Padding(
padding: EdgeInsets.only(
left: index == 0 ? 0 : UiConstants.space1,
right: index == 3 ? 0 : UiConstants.space1,
),
child: UiShimmerBox(
width: double.infinity,
height: 32,
borderRadius: UiConstants.radiusLg,
),
),
);
}),
),
],
),
);
}
}

View File

@@ -0,0 +1,51 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Shimmer placeholder for the week navigation card (month header + 7 day cells).
class WeekNavigationSkeleton extends StatelessWidget {
/// Creates a [WeekNavigationSkeleton].
const WeekNavigationSkeleton({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(UiConstants.space4),
decoration: BoxDecoration(
color: UiColors.white,
borderRadius: UiConstants.radiusLg,
),
child: Column(
children: [
// Navigation header: left arrow, month label, right arrow
Padding(
padding: const EdgeInsets.only(bottom: UiConstants.space4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const UiShimmerCircle(size: 32),
UiShimmerLine(width: 140, height: 16),
const UiShimmerCircle(size: 32),
],
),
),
// 7 day cells
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List.generate(7, (_) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: UiConstants.space1),
child: UiShimmerBox(
width: double.infinity,
height: 64,
borderRadius: UiConstants.radiusLg,
),
),
);
}),
),
],
),
);
}
}