This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
import '../../../application/analytic/profit_sharing_detail_loader/profit_sharing_detail_loader_bloc.dart';
|
||||
import '../../../common/extension/extension.dart';
|
||||
import '../../../common/theme/theme.dart';
|
||||
import '../../../domain/analytic/analytic.dart';
|
||||
import '../../../injection.dart';
|
||||
import '../../components/spacer/spacer.dart';
|
||||
import 'widgets/profit_sharing_allocation.dart';
|
||||
import 'widgets/profit_sharing_detail_header.dart';
|
||||
import 'widgets/profit_sharing_status.dart';
|
||||
import 'widgets/profit_sharing_subcategories.dart';
|
||||
|
||||
@RoutePage()
|
||||
class ProfitSharingDetailPage extends StatelessWidget
|
||||
implements AutoRouteWrapper {
|
||||
final String parentCategoryId;
|
||||
final String parentCategoryName;
|
||||
final DateTime dateFrom;
|
||||
final DateTime dateTo;
|
||||
|
||||
const ProfitSharingDetailPage({
|
||||
super.key,
|
||||
required this.parentCategoryId,
|
||||
required this.parentCategoryName,
|
||||
required this.dateFrom,
|
||||
required this.dateTo,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget wrappedRoute(BuildContext context) => BlocProvider(
|
||||
create: (_) => getIt<ProfitSharingDetailLoaderBloc>()..add(_fetchEvent()),
|
||||
child: this,
|
||||
);
|
||||
|
||||
ProfitSharingDetailLoaderEvent _fetchEvent() =>
|
||||
ProfitSharingDetailLoaderEvent.fetched(
|
||||
parentCategoryId: parentCategoryId,
|
||||
dateFrom: dateFrom,
|
||||
dateTo: dateTo,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColor.background,
|
||||
body:
|
||||
BlocBuilder<
|
||||
ProfitSharingDetailLoaderBloc,
|
||||
ProfitSharingDetailLoaderState
|
||||
>(
|
||||
builder: (context, state) {
|
||||
return RefreshIndicator(
|
||||
backgroundColor: AppColor.white,
|
||||
color: AppColor.primary,
|
||||
onRefresh: () async {
|
||||
context.read<ProfitSharingDetailLoaderBloc>().add(
|
||||
_fetchEvent(),
|
||||
);
|
||||
await context
|
||||
.read<ProfitSharingDetailLoaderBloc>()
|
||||
.stream
|
||||
.firstWhere((s) => !s.isFetching);
|
||||
},
|
||||
child: CustomScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: ProfitSharingDetailHeader(
|
||||
state: state,
|
||||
fallbackTitle: parentCategoryName,
|
||||
),
|
||||
),
|
||||
|
||||
const SliverToBoxAdapter(child: SpaceHeight(16)),
|
||||
|
||||
if (state.isFetching)
|
||||
SliverToBoxAdapter(child: _buildShimmer())
|
||||
else ...[
|
||||
SliverToBoxAdapter(
|
||||
child: _SummaryCard(summary: state.detail.summary),
|
||||
),
|
||||
|
||||
const SliverToBoxAdapter(child: SpaceHeight(16)),
|
||||
|
||||
SliverToBoxAdapter(
|
||||
child: ProfitSharingAllocation(
|
||||
budget: state.detail.budget,
|
||||
),
|
||||
),
|
||||
|
||||
const SliverToBoxAdapter(child: SpaceHeight(16)),
|
||||
|
||||
SliverToBoxAdapter(
|
||||
child: ProfitSharingSubCategories(
|
||||
categories: state.detail.categories,
|
||||
expandedCategoryId: state.expandedCategoryId,
|
||||
onToggle: (categoryId) =>
|
||||
context.read<ProfitSharingDetailLoaderBloc>().add(
|
||||
ProfitSharingDetailLoaderEvent.expandedCategoryChanged(
|
||||
categoryId,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
const SliverToBoxAdapter(child: SizedBox(height: 100)),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildShimmer() {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
_shimmerBox(height: 160),
|
||||
const SpaceHeight(16),
|
||||
_shimmerBox(height: 240),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _shimmerBox({required double height}) {
|
||||
return Shimmer.fromColors(
|
||||
baseColor: Colors.grey[300]!,
|
||||
highlightColor: Colors.grey[100]!,
|
||||
child: Container(
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SummaryCard extends StatelessWidget {
|
||||
final ProfitSharingCategory summary;
|
||||
|
||||
const _SummaryCard({required this.summary});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: AppColor.textLight.withOpacity(0.08),
|
||||
spreadRadius: 1,
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
context.lang.summary,
|
||||
style: AppStyle.lg.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColor.textPrimary,
|
||||
),
|
||||
),
|
||||
|
||||
const SpaceHeight(16),
|
||||
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ProfitSharingMetric(
|
||||
label: context.lang.sub_category,
|
||||
value: '${summary.categoryCount}',
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ProfitSharingMetric(
|
||||
label: context.lang.products,
|
||||
value: '${summary.productCount}',
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ProfitSharingMetric(
|
||||
label: context.lang.orders,
|
||||
value: summary.orderCount.thousandFormat,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 12),
|
||||
child: Divider(height: 1, color: AppColor.borderLight),
|
||||
),
|
||||
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ProfitSharingMetric(
|
||||
label: context.lang.std_hpp,
|
||||
value: formatPercent(summary.standardHppPercentage),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ProfitSharingMetric(
|
||||
label: context.lang.real_hpp,
|
||||
value: formatPercent(summary.realHppPercentage),
|
||||
valueColor: statusColor(summary.realHppPercentage),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ProfitSharingMetric(
|
||||
label: context.lang.gross_profit,
|
||||
value: summary.grossProfit.currencyFormatRp,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user