Files
apskel-owner-flutter/lib/presentation/pages/profit_sharing/widgets/profit_sharing_allocation.dart
T
efrilm 243b7e02aa
Build & Deploy iOS to TestFlight / build-and-deploy (push) Canceled after 0s
feat: update profit shareing
2026-10-04 22:31:01 +07:00

201 lines
5.7 KiB
Dart

import 'package:flutter/material.dart';
import '../../../../common/extension/extension.dart';
import '../../../../common/theme/theme.dart';
import '../../../../domain/analytic/analytic.dart';
import '../../../components/spacer/spacer.dart';
/// Warna tetap untuk tiap pos bagi hasil supaya konsisten di semua bagian.
/// Sengaja pakai warna jenuh, bukan default Material yang pucat.
class ProfitSharingColor {
static const Color owner = Color(0xFF00B341);
static const Color team = Color(0xFFFF6A00);
// Status margin (Sehat / Waspada / Tidak Sehat).
static const Color healthy = Color(0xFF00B341);
static const Color watch = Color(0xFFFF9500);
static const Color critical = Color(0xFFFF1E3C);
// Tile ringkasan.
static const Color subCategory = AppColor.primary;
static const Color product = Color(0xFF7B2FF7);
static const Color order = Color(0xFF00A3D9);
}
class ProfitSharingAllocation extends StatelessWidget {
final ProfitSharingBudget budget;
const ProfitSharingAllocation({super.key, required this.budget});
@override
Widget build(BuildContext context) {
final total = budget.total;
final percentages = budget.percentages;
// Fee owner berbeda tiap kategori induk, jadi porsi dihitung dari
// nominalnya; persentase bawaan hanya dipakai saat belum ada omzet.
final sdlPercentage = total.hasRevenue
? total.sdlPercentage
: percentages.owner;
final teamPercentage = total.hasRevenue
? total.teamPercentage
: percentages.team;
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.profit_sharing_allocation,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.w700,
color: AppColor.textPrimary,
),
),
const SpaceHeight(16),
ProfitSharingBar(owner: sdlPercentage, team: teamPercentage),
const SpaceHeight(20),
_row(
context: context,
color: ProfitSharingColor.owner,
label: context.lang.sdl,
percentage: sdlPercentage,
amount: total.sdl,
),
const Divider(height: 24, color: AppColor.borderLight),
_row(
context: context,
color: ProfitSharingColor.team,
label: context.lang.share_team,
percentage: teamPercentage,
amount: total.limitTeam,
),
],
),
);
}
Widget _row({
required BuildContext context,
required Color color,
required String label,
required double percentage,
required int amount,
}) {
return Row(
children: [
Container(
width: 10,
height: 10,
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
),
const SpaceWidth(10),
Text(
label,
style: AppStyle.md.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w600,
),
),
const SpaceWidth(8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(6),
),
child: Text(
'${percentage.toStringAsFixed(percentage % 1 == 0 ? 0 : 1)}%',
style: AppStyle.xs.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.w800,
),
),
),
const Spacer(),
Flexible(
child: Text(
amount.currencyFormatRp,
textAlign: TextAlign.right,
style: AppStyle.md.copyWith(
color: AppColor.textPrimary,
fontWeight: FontWeight.w700,
),
overflow: TextOverflow.ellipsis,
),
),
],
);
}
}
/// Bar proporsi SDL (owner) / tim dalam persen omzet. Sisa yang belum terbagi
/// (backend lama masih menyisihkan porsi belanja) tampil sebagai track kosong.
class ProfitSharingBar extends StatelessWidget {
final double owner;
final double team;
final double height;
const ProfitSharingBar({
super.key,
required this.owner,
required this.team,
this.height = 12,
});
@override
Widget build(BuildContext context) {
final total = owner + team;
if (total <= 0) {
return Container(
height: height,
decoration: BoxDecoration(
color: AppColor.borderLight,
borderRadius: BorderRadius.circular(height),
),
);
}
return ClipRRect(
borderRadius: BorderRadius.circular(height),
child: SizedBox(
height: height,
child: Row(
children: [
_segment(owner, ProfitSharingColor.owner),
_segment(team, ProfitSharingColor.team),
_segment(100 - total, AppColor.borderLight),
].whereType<Widget>().toList(),
),
),
);
}
/// Segmen dilewati saat porsinya 0 supaya Expanded tidak dipakai dengan flex 0.
Widget? _segment(double value, Color color) {
final flex = (value * 100).round();
if (flex <= 0) return null;
return Expanded(
flex: flex,
child: Container(color: color),
);
}
}