current outlet

This commit is contained in:
efrilm
2025-10-24 13:55:00 +07:00
parent 97c03bcf96
commit 4dbdcadeaf
27 changed files with 2201 additions and 11 deletions
@@ -0,0 +1,37 @@
import 'dart:convert';
import 'package:injectable/injectable.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../common/constant/local_storage_key.dart';
import '../../../domain/outlet/outlet.dart';
import '../outlet_dtos.dart';
@injectable
class OutletLocalDatasource {
final SharedPreferences _sharedPreferences;
// final String _logName = 'OutletLocalDataProvider';
OutletLocalDatasource(this._sharedPreferences);
Future<void> saveCurrentOutlet(OutletDto outlet) async {
final outletJsonString = jsonEncode(outlet.toJson());
await _sharedPreferences.setString(
LocalStorageKey.outlet,
outletJsonString,
);
}
Future<Outlet> currentOutlet() async {
final outletString = _sharedPreferences.getString(LocalStorageKey.outlet);
if (outletString == null) return Outlet.empty();
final Map<String, dynamic> outletMap = jsonDecode(outletString);
final outletDto = OutletDto.fromJson(outletMap);
return outletDto.toDomain();
}
Future<void> deleteCurrentOutlet() async {
await _sharedPreferences.remove(LocalStorageKey.outlet);
}
}
@@ -0,0 +1,67 @@
import 'dart:developer';
import 'package:data_channel/data_channel.dart';
import 'package:injectable/injectable.dart';
import '../../../common/api/api_client.dart';
import '../../../common/api/api_failure.dart';
import '../../../common/function/app_function.dart';
import '../../../common/url/api_path.dart';
import '../../../domain/outlet/outlet.dart';
import '../outlet_dtos.dart';
@injectable
class OutletRemoteDataProvider {
final ApiClient _apiClient;
final _logName = 'OutletRemoteDataProvider';
OutletRemoteDataProvider(this._apiClient);
Future<DC<OutletFailure, List<OutletDto>>> fetchOutlets({
int page = 1,
int limit = 10,
}) async {
try {
final response = await _apiClient.get(
'${ApiPath.outlets}/list',
params: {'page': page, 'limit': limit},
headers: getAuthorizationHeader(),
);
if (response.data['data'] == null) {
return DC.error(OutletFailure.empty());
}
final outlets = (response.data['data'] as List)
.map((e) => OutletDto.fromJson(e as Map<String, dynamic>))
.toList();
return DC.data(outlets);
} on ApiFailure catch (e, s) {
log('fetchOutletError', name: _logName, error: e, stackTrace: s);
return DC.error(OutletFailure.serverError(e));
}
}
Future<DC<OutletFailure, OutletDto>> fetchOutletById(String id) async {
try {
final response = await _apiClient.get(
'${ApiPath.outlets}/detail/$id',
headers: getAuthorizationHeader(),
);
if (response.data['data'] == null) {
return DC.error(OutletFailure.empty());
}
final outlet = OutletDto.fromJson(
response.data['data'] as Map<String, dynamic>,
);
return DC.data(outlet);
} on ApiFailure catch (e, s) {
log('fetchOutletByIdError', name: _logName, error: e, stackTrace: s);
return DC.error(OutletFailure.serverError(e));
}
}
}
@@ -0,0 +1,38 @@
part of '../outlet_dtos.dart';
@freezed
class OutletDto with _$OutletDto {
const OutletDto._();
const factory OutletDto({
@JsonKey(name: "id") String? id,
@JsonKey(name: "organization_id") String? organizationId,
@JsonKey(name: "name") String? name,
@JsonKey(name: "address") String? address,
@JsonKey(name: "phone_number") String? phoneNumber,
@JsonKey(name: "business_type") String? businessType,
@JsonKey(name: "currency") String? currency,
@JsonKey(name: "tax_rate") double? taxRate,
@JsonKey(name: "is_active") bool? isActive,
@JsonKey(name: "created_at") String? createdAt,
@JsonKey(name: "updated_at") String? updatedAt,
}) = _OutletDto;
factory OutletDto.fromJson(Map<String, dynamic> json) =>
_$OutletDtoFromJson(json);
/// Mapping ke domain
Outlet toDomain() => Outlet(
id: id ?? '',
organizationId: organizationId ?? '',
name: name ?? '',
address: address ?? '',
phoneNumber: phoneNumber ?? '',
businessType: businessType ?? '',
currency: currency ?? '',
taxRate: taxRate ?? 0.0,
isActive: isActive ?? false,
createdAt: createdAt ?? '',
updatedAt: updatedAt ?? '',
);
}
@@ -0,0 +1,8 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/outlet/outlet.dart';
part 'outlet_dtos.freezed.dart';
part 'outlet_dtos.g.dart';
part 'dtos/outlet_dto.dart';
@@ -0,0 +1,431 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'outlet_dtos.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
);
OutletDto _$OutletDtoFromJson(Map<String, dynamic> json) {
return _OutletDto.fromJson(json);
}
/// @nodoc
mixin _$OutletDto {
@JsonKey(name: "id")
String? get id => throw _privateConstructorUsedError;
@JsonKey(name: "organization_id")
String? get organizationId => throw _privateConstructorUsedError;
@JsonKey(name: "name")
String? get name => throw _privateConstructorUsedError;
@JsonKey(name: "address")
String? get address => throw _privateConstructorUsedError;
@JsonKey(name: "phone_number")
String? get phoneNumber => throw _privateConstructorUsedError;
@JsonKey(name: "business_type")
String? get businessType => throw _privateConstructorUsedError;
@JsonKey(name: "currency")
String? get currency => throw _privateConstructorUsedError;
@JsonKey(name: "tax_rate")
double? get taxRate => throw _privateConstructorUsedError;
@JsonKey(name: "is_active")
bool? get isActive => throw _privateConstructorUsedError;
@JsonKey(name: "created_at")
String? get createdAt => throw _privateConstructorUsedError;
@JsonKey(name: "updated_at")
String? get updatedAt => throw _privateConstructorUsedError;
/// Serializes this OutletDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of OutletDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$OutletDtoCopyWith<OutletDto> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $OutletDtoCopyWith<$Res> {
factory $OutletDtoCopyWith(OutletDto value, $Res Function(OutletDto) then) =
_$OutletDtoCopyWithImpl<$Res, OutletDto>;
@useResult
$Res call({
@JsonKey(name: "id") String? id,
@JsonKey(name: "organization_id") String? organizationId,
@JsonKey(name: "name") String? name,
@JsonKey(name: "address") String? address,
@JsonKey(name: "phone_number") String? phoneNumber,
@JsonKey(name: "business_type") String? businessType,
@JsonKey(name: "currency") String? currency,
@JsonKey(name: "tax_rate") double? taxRate,
@JsonKey(name: "is_active") bool? isActive,
@JsonKey(name: "created_at") String? createdAt,
@JsonKey(name: "updated_at") String? updatedAt,
});
}
/// @nodoc
class _$OutletDtoCopyWithImpl<$Res, $Val extends OutletDto>
implements $OutletDtoCopyWith<$Res> {
_$OutletDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of OutletDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? organizationId = freezed,
Object? name = freezed,
Object? address = freezed,
Object? phoneNumber = freezed,
Object? businessType = freezed,
Object? currency = freezed,
Object? taxRate = freezed,
Object? isActive = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_value.copyWith(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String?,
organizationId: freezed == organizationId
? _value.organizationId
: organizationId // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
address: freezed == address
? _value.address
: address // ignore: cast_nullable_to_non_nullable
as String?,
phoneNumber: freezed == phoneNumber
? _value.phoneNumber
: phoneNumber // ignore: cast_nullable_to_non_nullable
as String?,
businessType: freezed == businessType
? _value.businessType
: businessType // ignore: cast_nullable_to_non_nullable
as String?,
currency: freezed == currency
? _value.currency
: currency // ignore: cast_nullable_to_non_nullable
as String?,
taxRate: freezed == taxRate
? _value.taxRate
: taxRate // ignore: cast_nullable_to_non_nullable
as double?,
isActive: freezed == isActive
? _value.isActive
: isActive // ignore: cast_nullable_to_non_nullable
as bool?,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as String?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as String?,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$OutletDtoImplCopyWith<$Res>
implements $OutletDtoCopyWith<$Res> {
factory _$$OutletDtoImplCopyWith(
_$OutletDtoImpl value,
$Res Function(_$OutletDtoImpl) then,
) = __$$OutletDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: "id") String? id,
@JsonKey(name: "organization_id") String? organizationId,
@JsonKey(name: "name") String? name,
@JsonKey(name: "address") String? address,
@JsonKey(name: "phone_number") String? phoneNumber,
@JsonKey(name: "business_type") String? businessType,
@JsonKey(name: "currency") String? currency,
@JsonKey(name: "tax_rate") double? taxRate,
@JsonKey(name: "is_active") bool? isActive,
@JsonKey(name: "created_at") String? createdAt,
@JsonKey(name: "updated_at") String? updatedAt,
});
}
/// @nodoc
class __$$OutletDtoImplCopyWithImpl<$Res>
extends _$OutletDtoCopyWithImpl<$Res, _$OutletDtoImpl>
implements _$$OutletDtoImplCopyWith<$Res> {
__$$OutletDtoImplCopyWithImpl(
_$OutletDtoImpl _value,
$Res Function(_$OutletDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of OutletDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = freezed,
Object? organizationId = freezed,
Object? name = freezed,
Object? address = freezed,
Object? phoneNumber = freezed,
Object? businessType = freezed,
Object? currency = freezed,
Object? taxRate = freezed,
Object? isActive = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_$OutletDtoImpl(
id: freezed == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as String?,
organizationId: freezed == organizationId
? _value.organizationId
: organizationId // ignore: cast_nullable_to_non_nullable
as String?,
name: freezed == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String?,
address: freezed == address
? _value.address
: address // ignore: cast_nullable_to_non_nullable
as String?,
phoneNumber: freezed == phoneNumber
? _value.phoneNumber
: phoneNumber // ignore: cast_nullable_to_non_nullable
as String?,
businessType: freezed == businessType
? _value.businessType
: businessType // ignore: cast_nullable_to_non_nullable
as String?,
currency: freezed == currency
? _value.currency
: currency // ignore: cast_nullable_to_non_nullable
as String?,
taxRate: freezed == taxRate
? _value.taxRate
: taxRate // ignore: cast_nullable_to_non_nullable
as double?,
isActive: freezed == isActive
? _value.isActive
: isActive // ignore: cast_nullable_to_non_nullable
as bool?,
createdAt: freezed == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as String?,
updatedAt: freezed == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as String?,
),
);
}
}
/// @nodoc
@JsonSerializable()
class _$OutletDtoImpl extends _OutletDto {
const _$OutletDtoImpl({
@JsonKey(name: "id") this.id,
@JsonKey(name: "organization_id") this.organizationId,
@JsonKey(name: "name") this.name,
@JsonKey(name: "address") this.address,
@JsonKey(name: "phone_number") this.phoneNumber,
@JsonKey(name: "business_type") this.businessType,
@JsonKey(name: "currency") this.currency,
@JsonKey(name: "tax_rate") this.taxRate,
@JsonKey(name: "is_active") this.isActive,
@JsonKey(name: "created_at") this.createdAt,
@JsonKey(name: "updated_at") this.updatedAt,
}) : super._();
factory _$OutletDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$OutletDtoImplFromJson(json);
@override
@JsonKey(name: "id")
final String? id;
@override
@JsonKey(name: "organization_id")
final String? organizationId;
@override
@JsonKey(name: "name")
final String? name;
@override
@JsonKey(name: "address")
final String? address;
@override
@JsonKey(name: "phone_number")
final String? phoneNumber;
@override
@JsonKey(name: "business_type")
final String? businessType;
@override
@JsonKey(name: "currency")
final String? currency;
@override
@JsonKey(name: "tax_rate")
final double? taxRate;
@override
@JsonKey(name: "is_active")
final bool? isActive;
@override
@JsonKey(name: "created_at")
final String? createdAt;
@override
@JsonKey(name: "updated_at")
final String? updatedAt;
@override
String toString() {
return 'OutletDto(id: $id, organizationId: $organizationId, name: $name, address: $address, phoneNumber: $phoneNumber, businessType: $businessType, currency: $currency, taxRate: $taxRate, isActive: $isActive, createdAt: $createdAt, updatedAt: $updatedAt)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$OutletDtoImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.organizationId, organizationId) ||
other.organizationId == organizationId) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.address, address) || other.address == address) &&
(identical(other.phoneNumber, phoneNumber) ||
other.phoneNumber == phoneNumber) &&
(identical(other.businessType, businessType) ||
other.businessType == businessType) &&
(identical(other.currency, currency) ||
other.currency == currency) &&
(identical(other.taxRate, taxRate) || other.taxRate == taxRate) &&
(identical(other.isActive, isActive) ||
other.isActive == isActive) &&
(identical(other.createdAt, createdAt) ||
other.createdAt == createdAt) &&
(identical(other.updatedAt, updatedAt) ||
other.updatedAt == updatedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType,
id,
organizationId,
name,
address,
phoneNumber,
businessType,
currency,
taxRate,
isActive,
createdAt,
updatedAt,
);
/// Create a copy of OutletDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$OutletDtoImplCopyWith<_$OutletDtoImpl> get copyWith =>
__$$OutletDtoImplCopyWithImpl<_$OutletDtoImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$OutletDtoImplToJson(this);
}
}
abstract class _OutletDto extends OutletDto {
const factory _OutletDto({
@JsonKey(name: "id") final String? id,
@JsonKey(name: "organization_id") final String? organizationId,
@JsonKey(name: "name") final String? name,
@JsonKey(name: "address") final String? address,
@JsonKey(name: "phone_number") final String? phoneNumber,
@JsonKey(name: "business_type") final String? businessType,
@JsonKey(name: "currency") final String? currency,
@JsonKey(name: "tax_rate") final double? taxRate,
@JsonKey(name: "is_active") final bool? isActive,
@JsonKey(name: "created_at") final String? createdAt,
@JsonKey(name: "updated_at") final String? updatedAt,
}) = _$OutletDtoImpl;
const _OutletDto._() : super._();
factory _OutletDto.fromJson(Map<String, dynamic> json) =
_$OutletDtoImpl.fromJson;
@override
@JsonKey(name: "id")
String? get id;
@override
@JsonKey(name: "organization_id")
String? get organizationId;
@override
@JsonKey(name: "name")
String? get name;
@override
@JsonKey(name: "address")
String? get address;
@override
@JsonKey(name: "phone_number")
String? get phoneNumber;
@override
@JsonKey(name: "business_type")
String? get businessType;
@override
@JsonKey(name: "currency")
String? get currency;
@override
@JsonKey(name: "tax_rate")
double? get taxRate;
@override
@JsonKey(name: "is_active")
bool? get isActive;
@override
@JsonKey(name: "created_at")
String? get createdAt;
@override
@JsonKey(name: "updated_at")
String? get updatedAt;
/// Create a copy of OutletDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$OutletDtoImplCopyWith<_$OutletDtoImpl> get copyWith =>
throw _privateConstructorUsedError;
}
@@ -0,0 +1,37 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'outlet_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$OutletDtoImpl _$$OutletDtoImplFromJson(Map<String, dynamic> json) =>
_$OutletDtoImpl(
id: json['id'] as String?,
organizationId: json['organization_id'] as String?,
name: json['name'] as String?,
address: json['address'] as String?,
phoneNumber: json['phone_number'] as String?,
businessType: json['business_type'] as String?,
currency: json['currency'] as String?,
taxRate: (json['tax_rate'] as num?)?.toDouble(),
isActive: json['is_active'] as bool?,
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
);
Map<String, dynamic> _$$OutletDtoImplToJson(_$OutletDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'organization_id': instance.organizationId,
'name': instance.name,
'address': instance.address,
'phone_number': instance.phoneNumber,
'business_type': instance.businessType,
'currency': instance.currency,
'tax_rate': instance.taxRate,
'is_active': instance.isActive,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
};
@@ -0,0 +1,62 @@
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/outlet/outlet.dart';
import '../datasources/local_data_provider.dart';
import '../datasources/remote_data_provider.dart';
@Injectable(as: IOutletRepository)
class OutletRepository implements IOutletRepository {
final OutletRemoteDataProvider _remoteDataProvider;
final OutletLocalDatasource _localDataProvider;
final _logName = 'OutletRepository';
OutletRepository(this._remoteDataProvider, this._localDataProvider);
@override
Future<Either<OutletFailure, List<Outlet>>> getOutlets({
int page = 1,
int limit = 10,
}) async {
try {
final result = await _remoteDataProvider.fetchOutlets(
page: page,
limit: limit,
);
if (result.hasError) {
return left(result.error!);
}
final outlets = result.data!.map((dto) => dto.toDomain()).toList();
return right(outlets);
} catch (e, s) {
log('getOutlets', name: _logName, error: e, stackTrace: s);
return left(const OutletFailure.unexpectedError());
}
}
@override
Future<Either<OutletFailure, Outlet>> getOutletById(String id) async {
try {
final localOutlet = await _localDataProvider.currentOutlet();
if (localOutlet.id == id) {
return right(localOutlet);
}
final result = await _remoteDataProvider.fetchOutletById(id);
if (result.hasError) {
return left(result.error!);
}
final outlet = result.data!.toDomain();
return right(outlet);
} catch (e, s) {
log('getOutletById', name: _logName, error: e, stackTrace: s);
return left(const OutletFailure.unexpectedError());
}
}
}