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:
efrilm
2026-10-01 01:43:22 +07:00
co-authored by Claude Opus 5.5
parent 5954510b93
commit f5e3075205
253 changed files with 47212 additions and 17437 deletions
@@ -44,4 +44,38 @@ class GameRemoteDataProvider {
return DC.error(GameFailure.serverError(e));
}
}
Future<DC<GameFailure, SpinResultDto>> spin({required String gameId}) async {
try {
final response = await _apiClient.post(
ApiPath.spin,
headers: getAuthorizationHeader(),
data: {'spin_id': gameId},
);
if (response.data is! Map || response.data['success'] != true) {
final errors = response.data is Map ? response.data['errors'] : null;
final code = errors is List && errors.isNotEmpty && errors.first is Map
? errors.first['code']?.toString()
: null;
return DC.error(
GameFailure.dynamicErrorMessage(
code == '304'
? 'EnakCoin kurang, game sedang tidak aktif, atau hadiah baru '
'saja habis. EnakCoin kamu tidak terpotong, silakan coba lagi.'
: 'Terjadi kesalahan, coba lagi',
),
);
}
final dto = SpinResultDto.fromJson(
Map<String, dynamic>.from(response.data['data'] as Map),
);
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('spin', name: _logName, error: e, stackTrace: s);
return DC.error(GameFailure.serverError(e));
}
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
part of '../game_dtos.dart';
@freezed
class GameDto with _$GameDto {
abstract class GameDto with _$GameDto {
const factory GameDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'name') String? name,
@@ -1,7 +1,7 @@
part of '../game_dtos.dart';
@freezed
class GamePrizeDto with _$GamePrizeDto {
abstract class GamePrizeDto with _$GamePrizeDto {
const factory GamePrizeDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'game_id') String? gameId,
@@ -0,0 +1,47 @@
part of '../game_dtos.dart';
@freezed
abstract class SpinResultDto with _$SpinResultDto {
const factory SpinResultDto({
@JsonKey(name: 'game_play') GamePlayDto? gamePlay,
@JsonKey(name: 'prize_won') PrizeWonDto? prizeWon,
@JsonKey(name: 'coins_remaining') int? coinsRemaining,
}) = _SpinResultDto;
factory SpinResultDto.fromJson(Map<String, dynamic> json) =>
_$SpinResultDtoFromJson(json);
const SpinResultDto._();
SpinResult toDomain() => SpinResult(
gamePlayId: gamePlay?.id ?? '',
coinsUsed: gamePlay?.coinsUsed ?? 0,
prizeId: prizeWon?.id ?? '',
prizeName: prizeWon?.name ?? '',
coinsRemaining: coinsRemaining ?? 0,
);
}
@freezed
abstract class GamePlayDto with _$GamePlayDto {
const factory GamePlayDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'game_id') String? gameId,
@JsonKey(name: 'coins_used') int? coinsUsed,
@JsonKey(name: 'created_at') String? createdAt,
}) = _GamePlayDto;
factory GamePlayDto.fromJson(Map<String, dynamic> json) =>
_$GamePlayDtoFromJson(json);
}
@freezed
abstract class PrizeWonDto with _$PrizeWonDto {
const factory PrizeWonDto({
@JsonKey(name: 'id') String? id,
@JsonKey(name: 'name') String? name,
}) = _PrizeWonDto;
factory PrizeWonDto.fromJson(Map<String, dynamic> json) =>
_$PrizeWonDtoFromJson(json);
}
+1
View File
@@ -7,3 +7,4 @@ part 'game_dtos.g.dart';
part 'dto/game_dto.dart';
part 'dto/game_prize_dto.dart';
part 'dto/spin_result_dto.dart';
File diff suppressed because it is too large Load Diff
+64 -27
View File
@@ -6,34 +6,32 @@ part of 'game_dtos.dart';
// JsonSerializableGenerator
// **************************************************************************
_$GameDtoImpl _$$GameDtoImplFromJson(Map<String, dynamic> json) =>
_$GameDtoImpl(
id: json['id'] as String?,
name: json['name'] as String?,
type: json['type'] as String?,
isActive: json['is_active'] as bool?,
metadata: json['metadata'] as Map<String, dynamic>?,
prizes: (json['prizes'] as List<dynamic>?)
?.map((e) => GamePrizeDto.fromJson(e as Map<String, dynamic>))
.toList(),
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
);
_GameDto _$GameDtoFromJson(Map<String, dynamic> json) => _GameDto(
id: json['id'] as String?,
name: json['name'] as String?,
type: json['type'] as String?,
isActive: json['is_active'] as bool?,
metadata: json['metadata'] as Map<String, dynamic>?,
prizes: (json['prizes'] as List<dynamic>?)
?.map((e) => GamePrizeDto.fromJson(e as Map<String, dynamic>))
.toList(),
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
);
Map<String, dynamic> _$$GameDtoImplToJson(_$GameDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'name': instance.name,
'type': instance.type,
'is_active': instance.isActive,
'metadata': instance.metadata,
'prizes': instance.prizes,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
};
Map<String, dynamic> _$GameDtoToJson(_GameDto instance) => <String, dynamic>{
'id': instance.id,
'name': instance.name,
'type': instance.type,
'is_active': instance.isActive,
'metadata': instance.metadata,
'prizes': instance.prizes,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
};
_$GamePrizeDtoImpl _$$GamePrizeDtoImplFromJson(Map<String, dynamic> json) =>
_$GamePrizeDtoImpl(
_GamePrizeDto _$GamePrizeDtoFromJson(Map<String, dynamic> json) =>
_GamePrizeDto(
id: json['id'] as String?,
gameId: json['game_id'] as String?,
name: json['name'] as String?,
@@ -42,7 +40,7 @@ _$GamePrizeDtoImpl _$$GamePrizeDtoImplFromJson(Map<String, dynamic> json) =>
updatedAt: json['updated_at'] as String?,
);
Map<String, dynamic> _$$GamePrizeDtoImplToJson(_$GamePrizeDtoImpl instance) =>
Map<String, dynamic> _$GamePrizeDtoToJson(_GamePrizeDto instance) =>
<String, dynamic>{
'id': instance.id,
'game_id': instance.gameId,
@@ -51,3 +49,42 @@ Map<String, dynamic> _$$GamePrizeDtoImplToJson(_$GamePrizeDtoImpl instance) =>
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
};
_SpinResultDto _$SpinResultDtoFromJson(Map<String, dynamic> json) =>
_SpinResultDto(
gamePlay: json['game_play'] == null
? null
: GamePlayDto.fromJson(json['game_play'] as Map<String, dynamic>),
prizeWon: json['prize_won'] == null
? null
: PrizeWonDto.fromJson(json['prize_won'] as Map<String, dynamic>),
coinsRemaining: (json['coins_remaining'] as num?)?.toInt(),
);
Map<String, dynamic> _$SpinResultDtoToJson(_SpinResultDto instance) =>
<String, dynamic>{
'game_play': instance.gamePlay,
'prize_won': instance.prizeWon,
'coins_remaining': instance.coinsRemaining,
};
_GamePlayDto _$GamePlayDtoFromJson(Map<String, dynamic> json) => _GamePlayDto(
id: json['id'] as String?,
gameId: json['game_id'] as String?,
coinsUsed: (json['coins_used'] as num?)?.toInt(),
createdAt: json['created_at'] as String?,
);
Map<String, dynamic> _$GamePlayDtoToJson(_GamePlayDto instance) =>
<String, dynamic>{
'id': instance.id,
'game_id': instance.gameId,
'coins_used': instance.coinsUsed,
'created_at': instance.createdAt,
};
_PrizeWonDto _$PrizeWonDtoFromJson(Map<String, dynamic> json) =>
_PrizeWonDto(id: json['id'] as String?, name: json['name'] as String?);
Map<String, dynamic> _$PrizeWonDtoToJson(_PrizeWonDto instance) =>
<String, dynamic>{'id': instance.id, 'name': instance.name};
@@ -31,4 +31,20 @@ class GameRepository implements IGameRepository {
return left(const GameFailure.unexpectedError());
}
}
@override
Future<Either<GameFailure, SpinResult>> spin({required String gameId}) async {
try {
final result = await _remoteDataProvider.spin(gameId: gameId);
if (result.hasError) {
return left(result.error!);
}
return right(result.data!.toDomain());
} catch (e, s) {
log('spin', name: _logName, error: e, stackTrace: s);
return left(const GameFailure.unexpectedError());
}
}
}