This commit is contained in:
efrilm 2025-10-26 16:09:56 +07:00
parent 0e83d213fc
commit 655902a659
23 changed files with 3519 additions and 6 deletions

View File

@ -0,0 +1,78 @@
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/table/table.dart';
part 'table_loader_event.dart';
part 'table_loader_state.dart';
part 'table_loader_bloc.freezed.dart';
@injectable
class TableLoaderBloc extends Bloc<TableLoaderEvent, TableLoaderState> {
final ITableRepository _repository;
TableLoaderBloc(this._repository) : super(TableLoaderState.initial()) {
on<TableLoaderEvent>(_onTableLoadedEvent);
}
Future<void> _onTableLoadedEvent(
TableLoaderEvent event,
Emitter<TableLoaderState> emit,
) {
return event.map(
fetched: (e) async {
var newState = state;
if (e.isRefresh) {
newState = newState.copyWith(isFetching: true);
emit(newState);
}
newState = await _mapFetchedToState(newState, isRefresh: e.isRefresh);
emit(newState);
},
);
}
Future<TableLoaderState> _mapFetchedToState(
TableLoaderState state, {
bool isRefresh = false,
}) async {
state = state.copyWith(isFetching: false);
if (state.hasReachedMax && state.tables.isNotEmpty && !isRefresh) {
return state;
}
if (isRefresh) {
state = state.copyWith(
page: 1,
failureOption: none(),
hasReachedMax: false,
tables: [],
);
}
final failureOrTable = await _repository.fetchTables(page: state.page);
state = failureOrTable.fold(
(f) {
if (state.tables.isNotEmpty) {
return state.copyWith(hasReachedMax: true);
}
return state.copyWith(failureOption: optionOf(f));
},
(tables) {
return state.copyWith(
tables: List.from(state.tables)..addAll(tables.tables),
failureOption: none(),
page: state.page + 1,
hasReachedMax: tables.tables.length < 10,
);
},
);
return state;
}
}

View File

@ -0,0 +1,478 @@
// 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 'table_loader_bloc.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',
);
/// @nodoc
mixin _$TableLoaderEvent {
bool get isRefresh => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(bool isRefresh) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(bool isRefresh)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
/// Create a copy of TableLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$TableLoaderEventCopyWith<TableLoaderEvent> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $TableLoaderEventCopyWith<$Res> {
factory $TableLoaderEventCopyWith(
TableLoaderEvent value,
$Res Function(TableLoaderEvent) then,
) = _$TableLoaderEventCopyWithImpl<$Res, TableLoaderEvent>;
@useResult
$Res call({bool isRefresh});
}
/// @nodoc
class _$TableLoaderEventCopyWithImpl<$Res, $Val extends TableLoaderEvent>
implements $TableLoaderEventCopyWith<$Res> {
_$TableLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of TableLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? isRefresh = null}) {
return _then(
_value.copyWith(
isRefresh: null == isRefresh
? _value.isRefresh
: isRefresh // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$FetchedImplCopyWith<$Res>
implements $TableLoaderEventCopyWith<$Res> {
factory _$$FetchedImplCopyWith(
_$FetchedImpl value,
$Res Function(_$FetchedImpl) then,
) = __$$FetchedImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({bool isRefresh});
}
/// @nodoc
class __$$FetchedImplCopyWithImpl<$Res>
extends _$TableLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
implements _$$FetchedImplCopyWith<$Res> {
__$$FetchedImplCopyWithImpl(
_$FetchedImpl _value,
$Res Function(_$FetchedImpl) _then,
) : super(_value, _then);
/// Create a copy of TableLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? isRefresh = null}) {
return _then(
_$FetchedImpl(
isRefresh: null == isRefresh
? _value.isRefresh
: isRefresh // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$FetchedImpl implements _Fetched {
const _$FetchedImpl({this.isRefresh = false});
@override
@JsonKey()
final bool isRefresh;
@override
String toString() {
return 'TableLoaderEvent.fetched(isRefresh: $isRefresh)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$FetchedImpl &&
(identical(other.isRefresh, isRefresh) ||
other.isRefresh == isRefresh));
}
@override
int get hashCode => Object.hash(runtimeType, isRefresh);
/// Create a copy of TableLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
__$$FetchedImplCopyWithImpl<_$FetchedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(bool isRefresh) fetched,
}) {
return fetched(isRefresh);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(bool isRefresh)? fetched,
}) {
return fetched?.call(isRefresh);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(isRefresh);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Fetched value) fetched,
}) {
return fetched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Fetched value)? fetched,
}) {
return fetched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(this);
}
return orElse();
}
}
abstract class _Fetched implements TableLoaderEvent {
const factory _Fetched({final bool isRefresh}) = _$FetchedImpl;
@override
bool get isRefresh;
/// Create a copy of TableLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$TableLoaderState {
List<Table> get tables => throw _privateConstructorUsedError;
Option<TableFailure> get failureOption => throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
bool get hasReachedMax => throw _privateConstructorUsedError;
int get page => throw _privateConstructorUsedError;
/// Create a copy of TableLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$TableLoaderStateCopyWith<TableLoaderState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $TableLoaderStateCopyWith<$Res> {
factory $TableLoaderStateCopyWith(
TableLoaderState value,
$Res Function(TableLoaderState) then,
) = _$TableLoaderStateCopyWithImpl<$Res, TableLoaderState>;
@useResult
$Res call({
List<Table> tables,
Option<TableFailure> failureOption,
bool isFetching,
bool hasReachedMax,
int page,
});
}
/// @nodoc
class _$TableLoaderStateCopyWithImpl<$Res, $Val extends TableLoaderState>
implements $TableLoaderStateCopyWith<$Res> {
_$TableLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of TableLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? tables = null,
Object? failureOption = null,
Object? isFetching = null,
Object? hasReachedMax = null,
Object? page = null,
}) {
return _then(
_value.copyWith(
tables: null == tables
? _value.tables
: tables // ignore: cast_nullable_to_non_nullable
as List<Table>,
failureOption: null == failureOption
? _value.failureOption
: failureOption // ignore: cast_nullable_to_non_nullable
as Option<TableFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
hasReachedMax: null == hasReachedMax
? _value.hasReachedMax
: hasReachedMax // ignore: cast_nullable_to_non_nullable
as bool,
page: null == page
? _value.page
: page // ignore: cast_nullable_to_non_nullable
as int,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$TableLoaderStateImplCopyWith<$Res>
implements $TableLoaderStateCopyWith<$Res> {
factory _$$TableLoaderStateImplCopyWith(
_$TableLoaderStateImpl value,
$Res Function(_$TableLoaderStateImpl) then,
) = __$$TableLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
List<Table> tables,
Option<TableFailure> failureOption,
bool isFetching,
bool hasReachedMax,
int page,
});
}
/// @nodoc
class __$$TableLoaderStateImplCopyWithImpl<$Res>
extends _$TableLoaderStateCopyWithImpl<$Res, _$TableLoaderStateImpl>
implements _$$TableLoaderStateImplCopyWith<$Res> {
__$$TableLoaderStateImplCopyWithImpl(
_$TableLoaderStateImpl _value,
$Res Function(_$TableLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of TableLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? tables = null,
Object? failureOption = null,
Object? isFetching = null,
Object? hasReachedMax = null,
Object? page = null,
}) {
return _then(
_$TableLoaderStateImpl(
tables: null == tables
? _value._tables
: tables // ignore: cast_nullable_to_non_nullable
as List<Table>,
failureOption: null == failureOption
? _value.failureOption
: failureOption // ignore: cast_nullable_to_non_nullable
as Option<TableFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
hasReachedMax: null == hasReachedMax
? _value.hasReachedMax
: hasReachedMax // ignore: cast_nullable_to_non_nullable
as bool,
page: null == page
? _value.page
: page // ignore: cast_nullable_to_non_nullable
as int,
),
);
}
}
/// @nodoc
class _$TableLoaderStateImpl implements _TableLoaderState {
_$TableLoaderStateImpl({
required final List<Table> tables,
required this.failureOption,
this.isFetching = false,
this.hasReachedMax = false,
this.page = 1,
}) : _tables = tables;
final List<Table> _tables;
@override
List<Table> get tables {
if (_tables is EqualUnmodifiableListView) return _tables;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_tables);
}
@override
final Option<TableFailure> failureOption;
@override
@JsonKey()
final bool isFetching;
@override
@JsonKey()
final bool hasReachedMax;
@override
@JsonKey()
final int page;
@override
String toString() {
return 'TableLoaderState(tables: $tables, failureOption: $failureOption, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$TableLoaderStateImpl &&
const DeepCollectionEquality().equals(other._tables, _tables) &&
(identical(other.failureOption, failureOption) ||
other.failureOption == failureOption) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching) &&
(identical(other.hasReachedMax, hasReachedMax) ||
other.hasReachedMax == hasReachedMax) &&
(identical(other.page, page) || other.page == page));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(_tables),
failureOption,
isFetching,
hasReachedMax,
page,
);
/// Create a copy of TableLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$TableLoaderStateImplCopyWith<_$TableLoaderStateImpl> get copyWith =>
__$$TableLoaderStateImplCopyWithImpl<_$TableLoaderStateImpl>(
this,
_$identity,
);
}
abstract class _TableLoaderState implements TableLoaderState {
factory _TableLoaderState({
required final List<Table> tables,
required final Option<TableFailure> failureOption,
final bool isFetching,
final bool hasReachedMax,
final int page,
}) = _$TableLoaderStateImpl;
@override
List<Table> get tables;
@override
Option<TableFailure> get failureOption;
@override
bool get isFetching;
@override
bool get hasReachedMax;
@override
int get page;
/// Create a copy of TableLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$TableLoaderStateImplCopyWith<_$TableLoaderStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,7 @@
part of 'table_loader_bloc.dart';
@freezed
class TableLoaderEvent with _$TableLoaderEvent {
const factory TableLoaderEvent.fetched({@Default(false) bool isRefresh}) =
_Fetched;
}

View File

@ -0,0 +1,15 @@
part of 'table_loader_bloc.dart';
@freezed
class TableLoaderState with _$TableLoaderState {
factory TableLoaderState({
required List<Table> tables,
required Option<TableFailure> failureOption,
@Default(false) bool isFetching,
@Default(false) bool hasReachedMax,
@Default(1) int page,
}) = _TableLoaderState;
factory TableLoaderState.initial() =>
TableLoaderState(tables: [], failureOption: none());
}

View File

@ -1,6 +1,9 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../domain/table/table.dart';
part 'build_context_extension.dart';
part 'int_extension.dart';
part 'double_extension.dart';
part 'string_extension.dart';

View File

@ -0,0 +1,14 @@
part of 'extension.dart';
extension StringX on String {
TableStatusType toTableStatusType() {
switch (this) {
case 'available':
return TableStatusType.available;
case 'occupied':
return TableStatusType.occupied;
default:
return TableStatusType.unknown;
}
}
}

View File

@ -17,3 +17,30 @@ Map<String, dynamic> getAuthorizationHeader() {
'Bearer ${getIt<SharedPreferences>().getString(LocalStorageKey.token)}',
};
}
Map<String, int> getChairDistribution(int capacity) {
if (capacity == 1) {
return {'top': 0, 'bottom': 0, 'left': 1, 'right': 0};
} else if (capacity == 2) {
return {'top': 0, 'bottom': 0, 'left': 1, 'right': 1};
} else if (capacity == 3) {
return {'top': 1, 'bottom': 0, 'left': 1, 'right': 1};
} else if (capacity == 4) {
return {'top': 1, 'bottom': 1, 'left': 1, 'right': 1};
} else if (capacity == 5) {
return {'top': 2, 'bottom': 1, 'left': 1, 'right': 1};
} else if (capacity == 6) {
return {'top': 2, 'bottom': 2, 'left': 1, 'right': 1};
} else if (capacity == 7) {
return {'top': 3, 'bottom': 2, 'left': 1, 'right': 1};
} else if (capacity == 8) {
return {'top': 3, 'bottom': 3, 'left': 1, 'right': 1};
} else if (capacity == 9) {
return {'top': 4, 'bottom': 3, 'left': 1, 'right': 1};
} else if (capacity == 10) {
return {'top': 4, 'bottom': 4, 'left': 1, 'right': 1};
} else {
int side = ((capacity - 2) / 2).floor();
return {'top': side, 'bottom': side, 'left': 1, 'right': 1};
}
}

View File

@ -3,4 +3,5 @@ class ApiPath {
static const String outlets = '/api/v1/outlets';
static const String categories = '/api/v1/categories';
static const String products = '/api/v1/products';
static const String tables = '/api/v1/tables';
}

View File

@ -0,0 +1,48 @@
part of '../table.dart';
@freezed
class ListTable with _$ListTable {
const factory ListTable({
required List<Table> tables,
required int totalCount,
required int page,
required int limit,
required int totalPages,
}) = _ListTable;
factory ListTable.empty() =>
ListTable(tables: [], totalCount: 0, page: 0, limit: 0, totalPages: 0);
}
@freezed
class Table with _$Table {
const factory Table({
required String id,
required String organizationId,
required String outletId,
required String tableName,
required TableStatusType status,
required int paymentAmount,
required double positionX,
required double positionY,
required int capacity,
required bool isActive,
required DateTime createdAt,
required DateTime updatedAt,
}) = _Table;
factory Table.empty() => Table(
id: '',
organizationId: '',
outletId: '',
tableName: '',
status: TableStatusType.unknown,
paymentAmount: 0,
positionX: 0.0,
positionY: 0.0,
capacity: 0,
isActive: false,
createdAt: DateTime(1970),
updatedAt: DateTime(1970),
);
}

View File

@ -0,0 +1,12 @@
part of '../table.dart';
@freezed
sealed class TableFailure with _$TableFailure {
const factory TableFailure.serverError(ApiFailure failure) = _ServerError;
const factory TableFailure.unexpectedError() = _UnexpectedError;
const factory TableFailure.empty() = _Empty;
const factory TableFailure.localStorageError(String erroMessage) =
_LocalStorageError;
const factory TableFailure.dynamicErrorMessage(String erroMessage) =
_DynamicErrorMessage;
}

View File

@ -0,0 +1,8 @@
part of '../table.dart';
abstract class ITableRepository {
Future<Either<TableFailure, ListTable>> fetchTables({
int page = 1,
int limit = 50,
});
}

View File

@ -0,0 +1,23 @@
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../common/api/api_failure.dart';
part 'table.freezed.dart';
part 'entities/table_entity.dart';
part 'failures/table_failure.dart';
part 'repositories/i_table_repository.dart';
enum TableStatusType { available, occupied, unknown }
extension TableStatusTypeX on TableStatusType {
String toStringType() => switch (this) {
TableStatusType.available => 'available',
TableStatusType.occupied => 'occupied',
TableStatusType.unknown => 'unknown',
};
bool get isAvailable => this == TableStatusType.available;
bool get isOccupied => this == TableStatusType.occupied;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
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/table/table.dart';
import '../table_dtos.dart';
@injectable
class TableRemoteDataProvider {
final ApiClient _apiClient;
final _logName = 'TableRemoteDataProvider';
TableRemoteDataProvider(this._apiClient);
Future<DC<TableFailure, ListTableDto>> fetchTables({
int page = 1,
int limit = 50,
}) async {
try {
final response = await _apiClient.get(
ApiPath.tables,
headers: getAuthorizationHeader(),
params: {'page': page, 'limit': limit},
);
if (response.data['data'] == null) {
return DC.error(TableFailure.empty());
}
final tables = ListTableDto.fromJson(
response.data['data'] as Map<String, dynamic>,
);
return DC.data(tables);
} on ApiFailure catch (e, s) {
log('fetchTablesError', name: _logName, error: e, stackTrace: s);
return DC.error(TableFailure.serverError(e));
}
}
}

View File

@ -0,0 +1,64 @@
part of '../table_dtos.dart';
@freezed
class ListTableDto with _$ListTableDto {
const ListTableDto._();
const factory ListTableDto({
@JsonKey(name: "tables") List<TableDto>? tables,
@JsonKey(name: "total_count") int? totalCount,
@JsonKey(name: "page") int? page,
@JsonKey(name: "limit") int? limit,
@JsonKey(name: "total_pages") int? totalPages,
}) = _ListTableDto;
factory ListTableDto.fromJson(Map<String, dynamic> json) =>
_$ListTableDtoFromJson(json);
ListTable toDomain() => ListTable(
tables: tables?.map((dto) => dto.toDomain()).toList() ?? [],
totalCount: totalCount ?? 0,
page: page ?? 0,
limit: limit ?? 0,
totalPages: totalPages ?? 0,
);
}
@freezed
class TableDto with _$TableDto {
const TableDto._();
const factory TableDto({
@JsonKey(name: "id") String? id,
@JsonKey(name: "organization_id") String? organizationId,
@JsonKey(name: "outlet_id") String? outletId,
@JsonKey(name: "table_name") String? tableName,
@JsonKey(name: "status") String? status,
@JsonKey(name: "payment_amount") int? paymentAmount,
@JsonKey(name: "position_x") double? positionX,
@JsonKey(name: "position_y") double? positionY,
@JsonKey(name: "capacity") int? capacity,
@JsonKey(name: "is_active") bool? isActive,
@JsonKey(name: "created_at") String? createdAt,
@JsonKey(name: "updated_at") String? updatedAt,
}) = _TableDto;
factory TableDto.fromJson(Map<String, dynamic> json) =>
_$TableDtoFromJson(json);
/// Mapping ke domain
Table toDomain() => Table(
id: id ?? '',
organizationId: organizationId ?? '',
outletId: outletId ?? '',
tableName: tableName ?? '',
status: status?.toTableStatusType() ?? TableStatusType.unknown,
paymentAmount: paymentAmount ?? 0,
positionX: positionX ?? 0.0,
positionY: positionY ?? 0.0,
capacity: capacity ?? 0,
isActive: isActive ?? false,
createdAt: createdAt != null ? DateTime.parse(createdAt!) : DateTime(1970),
updatedAt: updatedAt != null ? DateTime.parse(updatedAt!) : DateTime(1970),
);
}

View File

@ -0,0 +1,39 @@
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/table/table.dart';
import '../datasources/remote_data_provider.dart';
@Injectable(as: ITableRepository)
class TableRepository implements ITableRepository {
final TableRemoteDataProvider _remoteDataProvider;
final _logName = 'TableRepository';
TableRepository(this._remoteDataProvider);
@override
Future<Either<TableFailure, ListTable>> fetchTables({
int page = 1,
int limit = 50,
}) async {
try {
final result = await _remoteDataProvider.fetchTables(
page: page,
limit: limit,
);
if (result.hasError) {
return left(result.error!);
}
final tables = result.data!.toDomain();
return right(tables);
} catch (e) {
log('fetchTables', name: _logName, error: e);
return left(const TableFailure.unexpectedError());
}
}
}

View File

@ -0,0 +1,9 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../common/extension/extension.dart';
import '../../domain/table/table.dart';
part 'table_dtos.freezed.dart';
part 'table_dtos.g.dart';
part 'dtos/table_dto.dart';

View File

@ -0,0 +1,735 @@
// 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 'table_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',
);
ListTableDto _$ListTableDtoFromJson(Map<String, dynamic> json) {
return _ListTableDto.fromJson(json);
}
/// @nodoc
mixin _$ListTableDto {
@JsonKey(name: "tables")
List<TableDto>? get tables => throw _privateConstructorUsedError;
@JsonKey(name: "total_count")
int? get totalCount => throw _privateConstructorUsedError;
@JsonKey(name: "page")
int? get page => throw _privateConstructorUsedError;
@JsonKey(name: "limit")
int? get limit => throw _privateConstructorUsedError;
@JsonKey(name: "total_pages")
int? get totalPages => throw _privateConstructorUsedError;
/// Serializes this ListTableDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of ListTableDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$ListTableDtoCopyWith<ListTableDto> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ListTableDtoCopyWith<$Res> {
factory $ListTableDtoCopyWith(
ListTableDto value,
$Res Function(ListTableDto) then,
) = _$ListTableDtoCopyWithImpl<$Res, ListTableDto>;
@useResult
$Res call({
@JsonKey(name: "tables") List<TableDto>? tables,
@JsonKey(name: "total_count") int? totalCount,
@JsonKey(name: "page") int? page,
@JsonKey(name: "limit") int? limit,
@JsonKey(name: "total_pages") int? totalPages,
});
}
/// @nodoc
class _$ListTableDtoCopyWithImpl<$Res, $Val extends ListTableDto>
implements $ListTableDtoCopyWith<$Res> {
_$ListTableDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of ListTableDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? tables = freezed,
Object? totalCount = freezed,
Object? page = freezed,
Object? limit = freezed,
Object? totalPages = freezed,
}) {
return _then(
_value.copyWith(
tables: freezed == tables
? _value.tables
: tables // ignore: cast_nullable_to_non_nullable
as List<TableDto>?,
totalCount: freezed == totalCount
? _value.totalCount
: totalCount // ignore: cast_nullable_to_non_nullable
as int?,
page: freezed == page
? _value.page
: page // ignore: cast_nullable_to_non_nullable
as int?,
limit: freezed == limit
? _value.limit
: limit // ignore: cast_nullable_to_non_nullable
as int?,
totalPages: freezed == totalPages
? _value.totalPages
: totalPages // ignore: cast_nullable_to_non_nullable
as int?,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$ListTableDtoImplCopyWith<$Res>
implements $ListTableDtoCopyWith<$Res> {
factory _$$ListTableDtoImplCopyWith(
_$ListTableDtoImpl value,
$Res Function(_$ListTableDtoImpl) then,
) = __$$ListTableDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: "tables") List<TableDto>? tables,
@JsonKey(name: "total_count") int? totalCount,
@JsonKey(name: "page") int? page,
@JsonKey(name: "limit") int? limit,
@JsonKey(name: "total_pages") int? totalPages,
});
}
/// @nodoc
class __$$ListTableDtoImplCopyWithImpl<$Res>
extends _$ListTableDtoCopyWithImpl<$Res, _$ListTableDtoImpl>
implements _$$ListTableDtoImplCopyWith<$Res> {
__$$ListTableDtoImplCopyWithImpl(
_$ListTableDtoImpl _value,
$Res Function(_$ListTableDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of ListTableDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? tables = freezed,
Object? totalCount = freezed,
Object? page = freezed,
Object? limit = freezed,
Object? totalPages = freezed,
}) {
return _then(
_$ListTableDtoImpl(
tables: freezed == tables
? _value._tables
: tables // ignore: cast_nullable_to_non_nullable
as List<TableDto>?,
totalCount: freezed == totalCount
? _value.totalCount
: totalCount // ignore: cast_nullable_to_non_nullable
as int?,
page: freezed == page
? _value.page
: page // ignore: cast_nullable_to_non_nullable
as int?,
limit: freezed == limit
? _value.limit
: limit // ignore: cast_nullable_to_non_nullable
as int?,
totalPages: freezed == totalPages
? _value.totalPages
: totalPages // ignore: cast_nullable_to_non_nullable
as int?,
),
);
}
}
/// @nodoc
@JsonSerializable()
class _$ListTableDtoImpl extends _ListTableDto {
const _$ListTableDtoImpl({
@JsonKey(name: "tables") final List<TableDto>? tables,
@JsonKey(name: "total_count") this.totalCount,
@JsonKey(name: "page") this.page,
@JsonKey(name: "limit") this.limit,
@JsonKey(name: "total_pages") this.totalPages,
}) : _tables = tables,
super._();
factory _$ListTableDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$ListTableDtoImplFromJson(json);
final List<TableDto>? _tables;
@override
@JsonKey(name: "tables")
List<TableDto>? get tables {
final value = _tables;
if (value == null) return null;
if (_tables is EqualUnmodifiableListView) return _tables;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
@override
@JsonKey(name: "total_count")
final int? totalCount;
@override
@JsonKey(name: "page")
final int? page;
@override
@JsonKey(name: "limit")
final int? limit;
@override
@JsonKey(name: "total_pages")
final int? totalPages;
@override
String toString() {
return 'ListTableDto(tables: $tables, totalCount: $totalCount, page: $page, limit: $limit, totalPages: $totalPages)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ListTableDtoImpl &&
const DeepCollectionEquality().equals(other._tables, _tables) &&
(identical(other.totalCount, totalCount) ||
other.totalCount == totalCount) &&
(identical(other.page, page) || other.page == page) &&
(identical(other.limit, limit) || other.limit == limit) &&
(identical(other.totalPages, totalPages) ||
other.totalPages == totalPages));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(_tables),
totalCount,
page,
limit,
totalPages,
);
/// Create a copy of ListTableDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ListTableDtoImplCopyWith<_$ListTableDtoImpl> get copyWith =>
__$$ListTableDtoImplCopyWithImpl<_$ListTableDtoImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$ListTableDtoImplToJson(this);
}
}
abstract class _ListTableDto extends ListTableDto {
const factory _ListTableDto({
@JsonKey(name: "tables") final List<TableDto>? tables,
@JsonKey(name: "total_count") final int? totalCount,
@JsonKey(name: "page") final int? page,
@JsonKey(name: "limit") final int? limit,
@JsonKey(name: "total_pages") final int? totalPages,
}) = _$ListTableDtoImpl;
const _ListTableDto._() : super._();
factory _ListTableDto.fromJson(Map<String, dynamic> json) =
_$ListTableDtoImpl.fromJson;
@override
@JsonKey(name: "tables")
List<TableDto>? get tables;
@override
@JsonKey(name: "total_count")
int? get totalCount;
@override
@JsonKey(name: "page")
int? get page;
@override
@JsonKey(name: "limit")
int? get limit;
@override
@JsonKey(name: "total_pages")
int? get totalPages;
/// Create a copy of ListTableDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ListTableDtoImplCopyWith<_$ListTableDtoImpl> get copyWith =>
throw _privateConstructorUsedError;
}
TableDto _$TableDtoFromJson(Map<String, dynamic> json) {
return _TableDto.fromJson(json);
}
/// @nodoc
mixin _$TableDto {
@JsonKey(name: "id")
String? get id => throw _privateConstructorUsedError;
@JsonKey(name: "organization_id")
String? get organizationId => throw _privateConstructorUsedError;
@JsonKey(name: "outlet_id")
String? get outletId => throw _privateConstructorUsedError;
@JsonKey(name: "table_name")
String? get tableName => throw _privateConstructorUsedError;
@JsonKey(name: "status")
String? get status => throw _privateConstructorUsedError;
@JsonKey(name: "payment_amount")
int? get paymentAmount => throw _privateConstructorUsedError;
@JsonKey(name: "position_x")
double? get positionX => throw _privateConstructorUsedError;
@JsonKey(name: "position_y")
double? get positionY => throw _privateConstructorUsedError;
@JsonKey(name: "capacity")
int? get capacity => 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 TableDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of TableDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$TableDtoCopyWith<TableDto> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $TableDtoCopyWith<$Res> {
factory $TableDtoCopyWith(TableDto value, $Res Function(TableDto) then) =
_$TableDtoCopyWithImpl<$Res, TableDto>;
@useResult
$Res call({
@JsonKey(name: "id") String? id,
@JsonKey(name: "organization_id") String? organizationId,
@JsonKey(name: "outlet_id") String? outletId,
@JsonKey(name: "table_name") String? tableName,
@JsonKey(name: "status") String? status,
@JsonKey(name: "payment_amount") int? paymentAmount,
@JsonKey(name: "position_x") double? positionX,
@JsonKey(name: "position_y") double? positionY,
@JsonKey(name: "capacity") int? capacity,
@JsonKey(name: "is_active") bool? isActive,
@JsonKey(name: "created_at") String? createdAt,
@JsonKey(name: "updated_at") String? updatedAt,
});
}
/// @nodoc
class _$TableDtoCopyWithImpl<$Res, $Val extends TableDto>
implements $TableDtoCopyWith<$Res> {
_$TableDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of TableDto
/// 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? outletId = freezed,
Object? tableName = freezed,
Object? status = freezed,
Object? paymentAmount = freezed,
Object? positionX = freezed,
Object? positionY = freezed,
Object? capacity = 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?,
outletId: freezed == outletId
? _value.outletId
: outletId // ignore: cast_nullable_to_non_nullable
as String?,
tableName: freezed == tableName
? _value.tableName
: tableName // ignore: cast_nullable_to_non_nullable
as String?,
status: freezed == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as String?,
paymentAmount: freezed == paymentAmount
? _value.paymentAmount
: paymentAmount // ignore: cast_nullable_to_non_nullable
as int?,
positionX: freezed == positionX
? _value.positionX
: positionX // ignore: cast_nullable_to_non_nullable
as double?,
positionY: freezed == positionY
? _value.positionY
: positionY // ignore: cast_nullable_to_non_nullable
as double?,
capacity: freezed == capacity
? _value.capacity
: capacity // ignore: cast_nullable_to_non_nullable
as int?,
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 _$$TableDtoImplCopyWith<$Res>
implements $TableDtoCopyWith<$Res> {
factory _$$TableDtoImplCopyWith(
_$TableDtoImpl value,
$Res Function(_$TableDtoImpl) then,
) = __$$TableDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: "id") String? id,
@JsonKey(name: "organization_id") String? organizationId,
@JsonKey(name: "outlet_id") String? outletId,
@JsonKey(name: "table_name") String? tableName,
@JsonKey(name: "status") String? status,
@JsonKey(name: "payment_amount") int? paymentAmount,
@JsonKey(name: "position_x") double? positionX,
@JsonKey(name: "position_y") double? positionY,
@JsonKey(name: "capacity") int? capacity,
@JsonKey(name: "is_active") bool? isActive,
@JsonKey(name: "created_at") String? createdAt,
@JsonKey(name: "updated_at") String? updatedAt,
});
}
/// @nodoc
class __$$TableDtoImplCopyWithImpl<$Res>
extends _$TableDtoCopyWithImpl<$Res, _$TableDtoImpl>
implements _$$TableDtoImplCopyWith<$Res> {
__$$TableDtoImplCopyWithImpl(
_$TableDtoImpl _value,
$Res Function(_$TableDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of TableDto
/// 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? outletId = freezed,
Object? tableName = freezed,
Object? status = freezed,
Object? paymentAmount = freezed,
Object? positionX = freezed,
Object? positionY = freezed,
Object? capacity = freezed,
Object? isActive = freezed,
Object? createdAt = freezed,
Object? updatedAt = freezed,
}) {
return _then(
_$TableDtoImpl(
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?,
outletId: freezed == outletId
? _value.outletId
: outletId // ignore: cast_nullable_to_non_nullable
as String?,
tableName: freezed == tableName
? _value.tableName
: tableName // ignore: cast_nullable_to_non_nullable
as String?,
status: freezed == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as String?,
paymentAmount: freezed == paymentAmount
? _value.paymentAmount
: paymentAmount // ignore: cast_nullable_to_non_nullable
as int?,
positionX: freezed == positionX
? _value.positionX
: positionX // ignore: cast_nullable_to_non_nullable
as double?,
positionY: freezed == positionY
? _value.positionY
: positionY // ignore: cast_nullable_to_non_nullable
as double?,
capacity: freezed == capacity
? _value.capacity
: capacity // ignore: cast_nullable_to_non_nullable
as int?,
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 _$TableDtoImpl extends _TableDto {
const _$TableDtoImpl({
@JsonKey(name: "id") this.id,
@JsonKey(name: "organization_id") this.organizationId,
@JsonKey(name: "outlet_id") this.outletId,
@JsonKey(name: "table_name") this.tableName,
@JsonKey(name: "status") this.status,
@JsonKey(name: "payment_amount") this.paymentAmount,
@JsonKey(name: "position_x") this.positionX,
@JsonKey(name: "position_y") this.positionY,
@JsonKey(name: "capacity") this.capacity,
@JsonKey(name: "is_active") this.isActive,
@JsonKey(name: "created_at") this.createdAt,
@JsonKey(name: "updated_at") this.updatedAt,
}) : super._();
factory _$TableDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$TableDtoImplFromJson(json);
@override
@JsonKey(name: "id")
final String? id;
@override
@JsonKey(name: "organization_id")
final String? organizationId;
@override
@JsonKey(name: "outlet_id")
final String? outletId;
@override
@JsonKey(name: "table_name")
final String? tableName;
@override
@JsonKey(name: "status")
final String? status;
@override
@JsonKey(name: "payment_amount")
final int? paymentAmount;
@override
@JsonKey(name: "position_x")
final double? positionX;
@override
@JsonKey(name: "position_y")
final double? positionY;
@override
@JsonKey(name: "capacity")
final int? capacity;
@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 'TableDto(id: $id, organizationId: $organizationId, outletId: $outletId, tableName: $tableName, status: $status, paymentAmount: $paymentAmount, positionX: $positionX, positionY: $positionY, capacity: $capacity, isActive: $isActive, createdAt: $createdAt, updatedAt: $updatedAt)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$TableDtoImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.organizationId, organizationId) ||
other.organizationId == organizationId) &&
(identical(other.outletId, outletId) ||
other.outletId == outletId) &&
(identical(other.tableName, tableName) ||
other.tableName == tableName) &&
(identical(other.status, status) || other.status == status) &&
(identical(other.paymentAmount, paymentAmount) ||
other.paymentAmount == paymentAmount) &&
(identical(other.positionX, positionX) ||
other.positionX == positionX) &&
(identical(other.positionY, positionY) ||
other.positionY == positionY) &&
(identical(other.capacity, capacity) ||
other.capacity == capacity) &&
(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,
outletId,
tableName,
status,
paymentAmount,
positionX,
positionY,
capacity,
isActive,
createdAt,
updatedAt,
);
/// Create a copy of TableDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$TableDtoImplCopyWith<_$TableDtoImpl> get copyWith =>
__$$TableDtoImplCopyWithImpl<_$TableDtoImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$TableDtoImplToJson(this);
}
}
abstract class _TableDto extends TableDto {
const factory _TableDto({
@JsonKey(name: "id") final String? id,
@JsonKey(name: "organization_id") final String? organizationId,
@JsonKey(name: "outlet_id") final String? outletId,
@JsonKey(name: "table_name") final String? tableName,
@JsonKey(name: "status") final String? status,
@JsonKey(name: "payment_amount") final int? paymentAmount,
@JsonKey(name: "position_x") final double? positionX,
@JsonKey(name: "position_y") final double? positionY,
@JsonKey(name: "capacity") final int? capacity,
@JsonKey(name: "is_active") final bool? isActive,
@JsonKey(name: "created_at") final String? createdAt,
@JsonKey(name: "updated_at") final String? updatedAt,
}) = _$TableDtoImpl;
const _TableDto._() : super._();
factory _TableDto.fromJson(Map<String, dynamic> json) =
_$TableDtoImpl.fromJson;
@override
@JsonKey(name: "id")
String? get id;
@override
@JsonKey(name: "organization_id")
String? get organizationId;
@override
@JsonKey(name: "outlet_id")
String? get outletId;
@override
@JsonKey(name: "table_name")
String? get tableName;
@override
@JsonKey(name: "status")
String? get status;
@override
@JsonKey(name: "payment_amount")
int? get paymentAmount;
@override
@JsonKey(name: "position_x")
double? get positionX;
@override
@JsonKey(name: "position_y")
double? get positionY;
@override
@JsonKey(name: "capacity")
int? get capacity;
@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 TableDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$TableDtoImplCopyWith<_$TableDtoImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,59 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'table_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$ListTableDtoImpl _$$ListTableDtoImplFromJson(Map<String, dynamic> json) =>
_$ListTableDtoImpl(
tables: (json['tables'] as List<dynamic>?)
?.map((e) => TableDto.fromJson(e as Map<String, dynamic>))
.toList(),
totalCount: (json['total_count'] as num?)?.toInt(),
page: (json['page'] as num?)?.toInt(),
limit: (json['limit'] as num?)?.toInt(),
totalPages: (json['total_pages'] as num?)?.toInt(),
);
Map<String, dynamic> _$$ListTableDtoImplToJson(_$ListTableDtoImpl instance) =>
<String, dynamic>{
'tables': instance.tables,
'total_count': instance.totalCount,
'page': instance.page,
'limit': instance.limit,
'total_pages': instance.totalPages,
};
_$TableDtoImpl _$$TableDtoImplFromJson(Map<String, dynamic> json) =>
_$TableDtoImpl(
id: json['id'] as String?,
organizationId: json['organization_id'] as String?,
outletId: json['outlet_id'] as String?,
tableName: json['table_name'] as String?,
status: json['status'] as String?,
paymentAmount: (json['payment_amount'] as num?)?.toInt(),
positionX: (json['position_x'] as num?)?.toDouble(),
positionY: (json['position_y'] as num?)?.toDouble(),
capacity: (json['capacity'] as num?)?.toInt(),
isActive: json['is_active'] as bool?,
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
);
Map<String, dynamic> _$$TableDtoImplToJson(_$TableDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'organization_id': instance.organizationId,
'outlet_id': instance.outletId,
'table_name': instance.tableName,
'status': instance.status,
'payment_amount': instance.paymentAmount,
'position_x': instance.positionX,
'position_y': instance.positionY,
'capacity': instance.capacity,
'is_active': instance.isActive,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
};

View File

@ -21,6 +21,8 @@ import 'package:apskel_pos_flutter_v2/application/outlet/outlet_loader/outlet_lo
import 'package:apskel_pos_flutter_v2/application/product/product_loader/product_loader_bloc.dart'
as _i13;
import 'package:apskel_pos_flutter_v2/application/sync/sync_bloc.dart' as _i741;
import 'package:apskel_pos_flutter_v2/application/table/table_loader/table_loader_bloc.dart'
as _i424;
import 'package:apskel_pos_flutter_v2/common/api/api_client.dart' as _i457;
import 'package:apskel_pos_flutter_v2/common/database/database_helper.dart'
as _i487;
@ -36,6 +38,7 @@ import 'package:apskel_pos_flutter_v2/domain/auth/auth.dart' as _i776;
import 'package:apskel_pos_flutter_v2/domain/category/category.dart' as _i502;
import 'package:apskel_pos_flutter_v2/domain/outlet/outlet.dart' as _i552;
import 'package:apskel_pos_flutter_v2/domain/product/product.dart' as _i44;
import 'package:apskel_pos_flutter_v2/domain/table/table.dart' as _i983;
import 'package:apskel_pos_flutter_v2/env.dart' as _i923;
import 'package:apskel_pos_flutter_v2/infrastructure/auth/datasources/local_data_provider.dart'
as _i204;
@ -61,6 +64,10 @@ import 'package:apskel_pos_flutter_v2/infrastructure/product/datasources/remote_
as _i707;
import 'package:apskel_pos_flutter_v2/infrastructure/product/repositories/product_repository.dart'
as _i763;
import 'package:apskel_pos_flutter_v2/infrastructure/table/datasources/remote_data_provider.dart'
as _i95;
import 'package:apskel_pos_flutter_v2/infrastructure/table/repositories/table_repository.dart'
as _i824;
import 'package:apskel_pos_flutter_v2/presentation/router/app_router.dart'
as _i800;
import 'package:connectivity_plus/connectivity_plus.dart' as _i895;
@ -125,6 +132,9 @@ extension GetItInjectableX on _i174.GetIt {
gh.factory<_i132.OutletRemoteDataProvider>(
() => _i132.OutletRemoteDataProvider(gh<_i457.ApiClient>()),
);
gh.factory<_i95.TableRemoteDataProvider>(
() => _i95.TableRemoteDataProvider(gh<_i457.ApiClient>()),
);
gh.factory<_i776.IAuthRepository>(
() => _i941.AuthRepository(
gh<_i370.AuthRemoteDataProvider>(),
@ -155,6 +165,9 @@ extension GetItInjectableX on _i174.GetIt {
gh.factory<_i1018.CategoryLoaderBloc>(
() => _i1018.CategoryLoaderBloc(gh<_i502.ICategoryRepository>()),
);
gh.factory<_i983.ITableRepository>(
() => _i824.TableRepository(gh<_i95.TableRemoteDataProvider>()),
);
gh.factory<_i343.AuthBloc>(
() => _i343.AuthBloc(
gh<_i776.IAuthRepository>(),
@ -173,6 +186,9 @@ extension GetItInjectableX on _i174.GetIt {
gh<_i502.ICategoryRepository>(),
),
);
gh.factory<_i424.TableLoaderBloc>(
() => _i424.TableLoaderBloc(gh<_i983.ITableRepository>()),
);
return this;
}
}

View File

@ -1,17 +1,238 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../application/table/table_loader/table_loader_bloc.dart';
import '../../../../../common/extension/extension.dart';
import '../../../../../common/theme/theme.dart';
import '../../../../../domain/table/table.dart' as t;
import '../../../../../injection.dart';
import '../../../../components/loader/loader_with_text.dart';
import 'widgets/table_card.dart';
@RoutePage()
class TablePage extends StatelessWidget {
class TablePage extends StatefulWidget implements AutoRouteWrapper {
const TablePage({super.key});
@override
State<TablePage> createState() => _TablePageState();
@override
Widget wrappedRoute(BuildContext context) => BlocProvider(
create: (context) =>
getIt<TableLoaderBloc>()
..add(TableLoaderEvent.fetched(isRefresh: true)),
child: this,
);
}
class _TablePageState extends State<TablePage> {
t.Table? selectedTable;
t.Table? draggingTable;
Offset? tapPosition;
@override
Widget build(BuildContext context) {
return Center(
child: Text(
'Table Page',
style: Theme.of(context).textTheme.headlineMedium,
final double mapWidth = context.deviceWidth * 2;
final double mapHeight = context.deviceHeight * 1.5;
return Scaffold(
backgroundColor: AppColor.background,
appBar: AppBar(
title: const Text("Layout Meja"),
backgroundColor: Colors.white,
foregroundColor: Colors.black,
elevation: 0.5,
actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: () {
context.read<TableLoaderBloc>().add(
const TableLoaderEvent.fetched(isRefresh: true),
);
},
),
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
// showDialog(
// context: context,
// builder: (context) => FormTableNewDialog(),
// );
},
),
],
bottom: PreferredSize(
preferredSize: const Size.fromHeight(20),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
_buildLegendDot(Colors.blue[200]!, "Available"),
const SizedBox(width: 16),
_buildLegendDot(Colors.orange[200]!, "Occupied"),
],
),
),
),
),
body: BlocBuilder<TableLoaderBloc, TableLoaderState>(
builder: (context, state) {
if (state.isFetching) {
return const Center(child: LoaderWithText());
}
return SafeArea(
child: Stack(
children: [
Row(
children: [
Expanded(
flex: 5,
child: InteractiveViewer(
panEnabled: true,
scaleEnabled: true,
constrained: false,
boundaryMargin: const EdgeInsets.all(80),
minScale: 0.3,
maxScale: 3.0,
alignment: Alignment.topLeft,
child: Container(
width: mapWidth,
height: mapHeight,
decoration: BoxDecoration(
color: const Color(0xFFF7F8FA),
border: Border.all(
color: Colors.grey[300]!,
width: 2,
),
),
child: Stack(
children: [
...List.generate(
20,
(i) => Positioned(
left: i * 100.0,
top: 0,
bottom: 0,
child: Container(
width: 1,
color: Colors.grey[200],
),
),
),
...List.generate(
15,
(i) => Positioned(
top: i * 100.0,
left: 0,
right: 0,
child: Container(
height: 1,
color: Colors.grey[200],
),
),
),
...state.tables.map((table) {
final isSelected = selectedTable == table;
return Positioned(
left: table.positionX,
top: table.positionY,
child: Draggable<t.Table>(
data: table,
feedback: Material(
color: Colors.transparent,
child: TableCard(
table: table,
isSelected: isSelected,
),
),
childWhenDragging: Opacity(
opacity: 0.5,
child: TableCard(
table: table,
isSelected: isSelected,
),
),
onDragStarted: () {
setState(() {
draggingTable = table;
});
},
onDraggableCanceled: (velocity, offset) {
setState(() {
draggingTable = null;
});
},
onDragEnd: (details) {
setState(() {
draggingTable = null;
final RenderBox box =
context.findRenderObject()
as RenderBox;
final Offset local = box.globalToLocal(
details.offset,
);
table = table.copyWith(
positionX: local.dx.clamp(
0,
mapWidth - 120,
),
positionY: local.dy.clamp(
0,
mapHeight - 80,
),
);
});
// context.read<ChangePositionTableBloc>().add(
// ChangePositionTableEvent.changePositionTable(
// tableId: table.id ?? "",
// position: Offset(
// table.positionX ?? 0.0,
// table.positionY ?? 0.0,
// ),
// ),
// );
},
child: GestureDetector(
onTap: () {},
onTapDown: (details) =>
tapPosition = details.globalPosition,
onLongPress: () {
if (table.status.isOccupied) {
// _showPopupMenu(context, table);
}
},
child: TableCard(
table: table,
isSelected: isSelected,
),
),
),
);
}),
],
),
),
),
),
],
),
],
),
);
},
),
);
}
Widget _buildLegendDot(Color color, String label) {
return Row(
children: [
CircleAvatar(radius: 7, backgroundColor: color),
const SizedBox(width: 6),
Text(label, style: const TextStyle(fontSize: 14)),
],
);
}
}

View File

@ -0,0 +1,146 @@
import 'package:flutter/material.dart';
import '../../../../../../common/function/app_function.dart';
import '../../../../../../common/theme/theme.dart';
import '../../../../../../domain/table/table.dart' as t;
import '../../../../../../domain/table/table.dart';
class TableCard extends StatelessWidget {
final t.Table table;
final bool isSelected;
const TableCard({super.key, required this.table, required this.isSelected});
Color getStatusColor() {
switch (table.status) {
case TableStatusType.available:
return Colors.blue[100]!;
case TableStatusType.occupied:
return Colors.orange[100]!;
default:
return Colors.grey[200]!;
}
}
Color getBorderColor() {
if (isSelected) return AppColor.primary;
switch (table.status) {
case TableStatusType.available:
return Colors.blue;
case TableStatusType.occupied:
return Colors.orange;
default:
return Colors.grey;
}
}
@override
Widget build(BuildContext context) {
final int capacity = table.capacity;
final chairDist = getChairDistribution(capacity);
Widget chair() => Container(
width: 20,
height: 10,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(4),
),
);
return SizedBox(
width: table.capacity > 16
? 240
: table.capacity > 8
? 180
: 120,
height: 80,
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: table.capacity > 16
? 220
: table.capacity > 8
? 160
: 100,
height: 60,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: getBorderColor(), width: 2),
borderRadius: BorderRadius.circular(16),
),
child: Center(
child: CircleAvatar(
radius: 24,
backgroundColor: getStatusColor(),
child: Text(
table.tableName,
style: TextStyle(
color: getBorderColor(),
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
),
),
),
if (chairDist['top']! > 0)
Positioned(
top: 0,
left: 10,
right: 10,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(chairDist['top']!, (_) => chair()),
),
),
// Kursi bawah
if (chairDist['bottom']! > 0)
Positioned(
bottom: 0,
left: 10,
right: 10,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(chairDist['bottom']!, (_) => chair()),
),
),
// Kursi kiri
if (chairDist['left']! > 0)
Positioned(
left: 0,
top: 15,
bottom: 15,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(chairDist['left']!, (_) => chair()),
),
),
// Kursi kanan
if (chairDist['right']! > 0)
Positioned(
right: 0,
top: 15,
bottom: 15,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(chairDist['right']!, (_) => chair()),
),
),
// Icon info kecil di pojok kanan atas jika status reserved
if (table.status.isOccupied)
const Positioned(
top: 6,
right: 6,
child: Icon(
Icons.info_outline,
size: 16,
color: Colors.redAccent,
),
),
],
),
);
}
}

View File

@ -168,7 +168,7 @@ class TableRoute extends _i10.PageRouteInfo<void> {
static _i10.PageInfo page = _i10.PageInfo(
name,
builder: (data) {
return const _i9.TablePage();
return _i10.WrappedRoute(child: const _i9.TablePage());
},
);
}