239 lines
7.3 KiB
Dart
239 lines
7.3 KiB
Dart
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,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|