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:
@@ -13,6 +13,7 @@ import '../widgets/attire_info_card.dart';
|
||||
import '../widgets/attire_item_card.dart';
|
||||
import '../widgets/attire_section_header.dart';
|
||||
import '../widgets/attire_section_tab.dart';
|
||||
import '../widgets/attire_skeleton/attire_skeleton.dart';
|
||||
|
||||
class AttirePage extends StatefulWidget {
|
||||
const AttirePage({super.key});
|
||||
@@ -49,7 +50,7 @@ class _AttirePageState extends State<AttirePage> {
|
||||
},
|
||||
builder: (BuildContext context, AttireState state) {
|
||||
if (state.status == AttireStatus.loading && state.options.isEmpty) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
return const AttireSkeleton();
|
||||
}
|
||||
|
||||
final List<AttireItem> requiredItems = state.options
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Shimmer placeholder for a single attire item card.
|
||||
class AttireItemSkeleton extends StatelessWidget {
|
||||
/// Creates an [AttireItemSkeleton].
|
||||
const AttireItemSkeleton({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>[
|
||||
UiShimmerBox(width: 56, height: 56),
|
||||
SizedBox(width: UiConstants.space3),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
UiShimmerLine(width: 120, height: 14),
|
||||
SizedBox(height: UiConstants.space2),
|
||||
UiShimmerLine(width: 80, height: 12),
|
||||
],
|
||||
),
|
||||
),
|
||||
UiShimmerBox(width: 60, height: 24),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'attire_item_skeleton.dart';
|
||||
|
||||
/// Full-page shimmer skeleton shown while attire items are loading.
|
||||
class AttireSkeleton extends StatelessWidget {
|
||||
/// Creates an [AttireSkeleton].
|
||||
const AttireSkeleton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return UiShimmer(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// Info card placeholder
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: UiColors.border),
|
||||
borderRadius: UiConstants.radiusLg,
|
||||
color: UiColors.cardViewBackground,
|
||||
),
|
||||
child: const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
UiShimmerLine(width: 160, height: 14),
|
||||
SizedBox(height: UiConstants.space2),
|
||||
UiShimmerLine(height: 12),
|
||||
SizedBox(height: UiConstants.space1),
|
||||
UiShimmerLine(width: 200, height: 12),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
// Section toggle chips placeholder
|
||||
const Row(
|
||||
children: <Widget>[
|
||||
UiShimmerBox(width: 80, height: 32),
|
||||
SizedBox(width: UiConstants.space3),
|
||||
UiShimmerBox(width: 100, height: 32),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
// Section header placeholder
|
||||
const UiShimmerSectionHeader(),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
// Attire item cards
|
||||
UiShimmerList(
|
||||
itemCount: 4,
|
||||
spacing: UiConstants.space3,
|
||||
itemBuilder: (int index) => const AttireItemSkeleton(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import 'package:krow_core/core.dart';
|
||||
import 'package:staff_profile_info/src/presentation/blocs/personal_info_bloc.dart';
|
||||
import 'package:staff_profile_info/src/presentation/blocs/personal_info_state.dart';
|
||||
import 'package:staff_profile_info/src/presentation/widgets/personal_info_page/personal_info_content.dart';
|
||||
import 'package:staff_profile_info/src/presentation/widgets/personal_info_skeleton/personal_info_skeleton.dart';
|
||||
|
||||
|
||||
/// The Personal Info page for staff onboarding.
|
||||
@@ -56,7 +57,7 @@ class PersonalInfoPage extends StatelessWidget {
|
||||
builder: (BuildContext context, PersonalInfoState state) {
|
||||
if (state.status == PersonalInfoStatus.loading ||
|
||||
state.status == PersonalInfoStatus.initial) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
return const PersonalInfoSkeleton();
|
||||
}
|
||||
|
||||
if (state.staff == null) {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Shimmer placeholder for a single form field (label + input).
|
||||
class FormFieldSkeleton extends StatelessWidget {
|
||||
/// Creates a [FormFieldSkeleton].
|
||||
const FormFieldSkeleton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
UiShimmerLine(width: 80, height: 12),
|
||||
SizedBox(height: UiConstants.space2),
|
||||
UiShimmerBox(width: double.infinity, height: 48),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'form_field_skeleton.dart';
|
||||
|
||||
/// Full-page shimmer skeleton shown while personal info is loading.
|
||||
class PersonalInfoSkeleton extends StatelessWidget {
|
||||
/// Creates a [PersonalInfoSkeleton].
|
||||
const PersonalInfoSkeleton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return UiShimmer(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
// Avatar placeholder
|
||||
const Center(child: UiShimmerCircle(size: 80)),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
// Form fields
|
||||
UiShimmerList(
|
||||
itemCount: 5,
|
||||
spacing: UiConstants.space5,
|
||||
itemBuilder: (int index) => const FormFieldSkeleton(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user