EnakPoint & EnakCoin wallet, PIN, outlet, order, community, reward
- Wallet EnakPoint & EnakCoin: beranda, riwayat, saldo kedaluwarsa, kode bayar, tukar EnakCoin, transfer - PIN (buat, ganti, lupa), outlet, riwayat order, game spin - Halaman community, webview, coming soon, dan ikon menu beranda baru - Redesign Reward Saya: kartu tiket, filter chip, detail kode + QR - Hapus customer point loader, menu, dan checkout lama - Base URL ke enaklo-pos-api.altru.id Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5954510b93
commit
f5e3075205
@@ -0,0 +1,98 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../../../common/theme/theme.dart';
|
||||
import '../../../sample/reward_sample_data.dart';
|
||||
|
||||
/// Reward aktif dengan sisa masa berlaku segini dianggap segera berakhir.
|
||||
const int rewardExpiringSoonDays = 7;
|
||||
|
||||
extension RewardStatusUi on RewardStatus {
|
||||
String get label => switch (this) {
|
||||
RewardStatus.active => 'Aktif',
|
||||
RewardStatus.used => 'Terpakai',
|
||||
RewardStatus.expired => 'Kedaluwarsa',
|
||||
};
|
||||
|
||||
Color get color => switch (this) {
|
||||
RewardStatus.active => AppColor.success,
|
||||
RewardStatus.used => AppColor.textSecondary,
|
||||
RewardStatus.expired => AppColor.error,
|
||||
};
|
||||
}
|
||||
|
||||
/// Tanggal pendek: "1 Okt 2026".
|
||||
String formatRewardDate(DateTime date) =>
|
||||
DateFormat('d MMM yyyy', 'id_ID').format(date);
|
||||
|
||||
/// Sisa hari kalender sampai [Reward.validUntil]; 0 berarti berakhir hari ini.
|
||||
int rewardDaysLeft(Reward reward) {
|
||||
final now = DateTime.now();
|
||||
final today = DateTime(now.year, now.month, now.day);
|
||||
final end = DateTime(
|
||||
reward.validUntil.year,
|
||||
reward.validUntil.month,
|
||||
reward.validUntil.day,
|
||||
);
|
||||
return end.difference(today).inDays;
|
||||
}
|
||||
|
||||
bool isRewardExpiringSoon(Reward reward) =>
|
||||
reward.status == RewardStatus.active &&
|
||||
rewardDaysLeft(reward) <= rewardExpiringSoonDays;
|
||||
|
||||
/// "Berakhir hari ini" / "Berakhir 3 hari lagi" / "Berlaku s/d 25 Okt 2026".
|
||||
String rewardValidityLabel(Reward reward) {
|
||||
final daysLeft = rewardDaysLeft(reward);
|
||||
if (daysLeft <= 0) return 'Berakhir hari ini';
|
||||
if (daysLeft <= rewardExpiringSoonDays) {
|
||||
return 'Berakhir $daysLeft hari lagi';
|
||||
}
|
||||
return 'Berlaku s/d ${formatRewardDate(reward.validUntil)}';
|
||||
}
|
||||
|
||||
class RewardStatusBadge extends StatelessWidget {
|
||||
const RewardStatusBadge({super.key, required this.status});
|
||||
|
||||
final RewardStatus status;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: status.color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
status.label,
|
||||
style: AppStyle.xs.copyWith(
|
||||
color: status.color,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Emoji reward; abu-abu untuk reward yang sudah tidak bisa dipakai.
|
||||
class RewardEmoji extends StatelessWidget {
|
||||
const RewardEmoji({super.key, required this.reward, required this.size});
|
||||
|
||||
final Reward reward;
|
||||
final double size;
|
||||
|
||||
static const ColorFilter _greyscale = ColorFilter.matrix([
|
||||
0.2126, 0.7152, 0.0722, 0, 0, //
|
||||
0.2126, 0.7152, 0.0722, 0, 0, //
|
||||
0.2126, 0.7152, 0.0722, 0, 0, //
|
||||
0, 0, 0, 0.5, 0, //
|
||||
]);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final emoji = Text(reward.emoji, style: TextStyle(fontSize: size));
|
||||
if (reward.status == RewardStatus.active) return emoji;
|
||||
return ColorFiltered(colorFilter: _greyscale, child: emoji);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user