diff --git a/lib/application/table/table_form/table_form_bloc.dart b/lib/application/table/table_form/table_form_bloc.dart new file mode 100644 index 0000000..38c363a --- /dev/null +++ b/lib/application/table/table_form/table_form_bloc.dart @@ -0,0 +1,45 @@ +import 'dart:ui'; + +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_form_event.dart'; +part 'table_form_state.dart'; +part 'table_form_bloc.freezed.dart'; + +@injectable +class TableFormBloc extends Bloc { + final ITableRepository _repository; + TableFormBloc(this._repository) : super(TableFormState.initial()) { + on(_onTableFormEvent); + } + + Future _onTableFormEvent( + TableFormEvent event, + Emitter emit, + ) { + return event.map( + updated: (e) async { + Either failureOrTable; + + emit(state.copyWith(isUpdating: true, failureOrTable: none())); + + failureOrTable = await _repository.updatePosition( + id: e.id, + position: e.position, + ); + + emit( + state.copyWith( + failureOrTable: optionOf(failureOrTable), + isUpdating: false, + ), + ); + }, + ); + } +} diff --git a/lib/application/table/table_form/table_form_bloc.freezed.dart b/lib/application/table/table_form/table_form_bloc.freezed.dart new file mode 100644 index 0000000..e3dd281 --- /dev/null +++ b/lib/application/table/table_form/table_form_bloc.freezed.dart @@ -0,0 +1,410 @@ +// 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_form_bloc.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(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 _$TableFormEvent { + String get id => throw _privateConstructorUsedError; + Offset get position => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult when({ + required TResult Function(String id, Offset position) updated, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String id, Offset position)? updated, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String id, Offset position)? updated, + required TResult orElse(), + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(_Updated value) updated, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Updated value)? updated, + }) => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Updated value)? updated, + required TResult orElse(), + }) => throw _privateConstructorUsedError; + + /// Create a copy of TableFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $TableFormEventCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TableFormEventCopyWith<$Res> { + factory $TableFormEventCopyWith( + TableFormEvent value, + $Res Function(TableFormEvent) then, + ) = _$TableFormEventCopyWithImpl<$Res, TableFormEvent>; + @useResult + $Res call({String id, Offset position}); +} + +/// @nodoc +class _$TableFormEventCopyWithImpl<$Res, $Val extends TableFormEvent> + implements $TableFormEventCopyWith<$Res> { + _$TableFormEventCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of TableFormEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? id = null, Object? position = null}) { + return _then( + _value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + position: null == position + ? _value.position + : position // ignore: cast_nullable_to_non_nullable + as Offset, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$UpdatedImplCopyWith<$Res> + implements $TableFormEventCopyWith<$Res> { + factory _$$UpdatedImplCopyWith( + _$UpdatedImpl value, + $Res Function(_$UpdatedImpl) then, + ) = __$$UpdatedImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String id, Offset position}); +} + +/// @nodoc +class __$$UpdatedImplCopyWithImpl<$Res> + extends _$TableFormEventCopyWithImpl<$Res, _$UpdatedImpl> + implements _$$UpdatedImplCopyWith<$Res> { + __$$UpdatedImplCopyWithImpl( + _$UpdatedImpl _value, + $Res Function(_$UpdatedImpl) _then, + ) : super(_value, _then); + + /// Create a copy of TableFormEvent + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? id = null, Object? position = null}) { + return _then( + _$UpdatedImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + position: null == position + ? _value.position + : position // ignore: cast_nullable_to_non_nullable + as Offset, + ), + ); + } +} + +/// @nodoc + +class _$UpdatedImpl implements _Updated { + const _$UpdatedImpl({required this.id, required this.position}); + + @override + final String id; + @override + final Offset position; + + @override + String toString() { + return 'TableFormEvent.updated(id: $id, position: $position)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$UpdatedImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.position, position) || + other.position == position)); + } + + @override + int get hashCode => Object.hash(runtimeType, id, position); + + /// Create a copy of TableFormEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$UpdatedImplCopyWith<_$UpdatedImpl> get copyWith => + __$$UpdatedImplCopyWithImpl<_$UpdatedImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String id, Offset position) updated, + }) { + return updated(id, position); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(String id, Offset position)? updated, + }) { + return updated?.call(id, position); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String id, Offset position)? updated, + required TResult orElse(), + }) { + if (updated != null) { + return updated(id, position); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Updated value) updated, + }) { + return updated(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Updated value)? updated, + }) { + return updated?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Updated value)? updated, + required TResult orElse(), + }) { + if (updated != null) { + return updated(this); + } + return orElse(); + } +} + +abstract class _Updated implements TableFormEvent { + const factory _Updated({ + required final String id, + required final Offset position, + }) = _$UpdatedImpl; + + @override + String get id; + @override + Offset get position; + + /// Create a copy of TableFormEvent + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$UpdatedImplCopyWith<_$UpdatedImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$TableFormState { + Option> get failureOrTable => + throw _privateConstructorUsedError; + bool get isUpdating => throw _privateConstructorUsedError; + + /// Create a copy of TableFormState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $TableFormStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TableFormStateCopyWith<$Res> { + factory $TableFormStateCopyWith( + TableFormState value, + $Res Function(TableFormState) then, + ) = _$TableFormStateCopyWithImpl<$Res, TableFormState>; + @useResult + $Res call({ + Option> failureOrTable, + bool isUpdating, + }); +} + +/// @nodoc +class _$TableFormStateCopyWithImpl<$Res, $Val extends TableFormState> + implements $TableFormStateCopyWith<$Res> { + _$TableFormStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of TableFormState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? failureOrTable = null, Object? isUpdating = null}) { + return _then( + _value.copyWith( + failureOrTable: null == failureOrTable + ? _value.failureOrTable + : failureOrTable // ignore: cast_nullable_to_non_nullable + as Option>, + isUpdating: null == isUpdating + ? _value.isUpdating + : isUpdating // ignore: cast_nullable_to_non_nullable + as bool, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$TableFormStateImplCopyWith<$Res> + implements $TableFormStateCopyWith<$Res> { + factory _$$TableFormStateImplCopyWith( + _$TableFormStateImpl value, + $Res Function(_$TableFormStateImpl) then, + ) = __$$TableFormStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + Option> failureOrTable, + bool isUpdating, + }); +} + +/// @nodoc +class __$$TableFormStateImplCopyWithImpl<$Res> + extends _$TableFormStateCopyWithImpl<$Res, _$TableFormStateImpl> + implements _$$TableFormStateImplCopyWith<$Res> { + __$$TableFormStateImplCopyWithImpl( + _$TableFormStateImpl _value, + $Res Function(_$TableFormStateImpl) _then, + ) : super(_value, _then); + + /// Create a copy of TableFormState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({Object? failureOrTable = null, Object? isUpdating = null}) { + return _then( + _$TableFormStateImpl( + failureOrTable: null == failureOrTable + ? _value.failureOrTable + : failureOrTable // ignore: cast_nullable_to_non_nullable + as Option>, + isUpdating: null == isUpdating + ? _value.isUpdating + : isUpdating // ignore: cast_nullable_to_non_nullable + as bool, + ), + ); + } +} + +/// @nodoc + +class _$TableFormStateImpl implements _TableFormState { + _$TableFormStateImpl({required this.failureOrTable, this.isUpdating = false}); + + @override + final Option> failureOrTable; + @override + @JsonKey() + final bool isUpdating; + + @override + String toString() { + return 'TableFormState(failureOrTable: $failureOrTable, isUpdating: $isUpdating)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$TableFormStateImpl && + (identical(other.failureOrTable, failureOrTable) || + other.failureOrTable == failureOrTable) && + (identical(other.isUpdating, isUpdating) || + other.isUpdating == isUpdating)); + } + + @override + int get hashCode => Object.hash(runtimeType, failureOrTable, isUpdating); + + /// Create a copy of TableFormState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$TableFormStateImplCopyWith<_$TableFormStateImpl> get copyWith => + __$$TableFormStateImplCopyWithImpl<_$TableFormStateImpl>( + this, + _$identity, + ); +} + +abstract class _TableFormState implements TableFormState { + factory _TableFormState({ + required final Option> failureOrTable, + final bool isUpdating, + }) = _$TableFormStateImpl; + + @override + Option> get failureOrTable; + @override + bool get isUpdating; + + /// Create a copy of TableFormState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$TableFormStateImplCopyWith<_$TableFormStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/application/table/table_form/table_form_event.dart b/lib/application/table/table_form/table_form_event.dart new file mode 100644 index 0000000..bcbd296 --- /dev/null +++ b/lib/application/table/table_form/table_form_event.dart @@ -0,0 +1,9 @@ +part of 'table_form_bloc.dart'; + +@freezed +class TableFormEvent with _$TableFormEvent { + const factory TableFormEvent.updated({ + required String id, + required Offset position, + }) = _Updated; +} diff --git a/lib/application/table/table_form/table_form_state.dart b/lib/application/table/table_form/table_form_state.dart new file mode 100644 index 0000000..ac33258 --- /dev/null +++ b/lib/application/table/table_form/table_form_state.dart @@ -0,0 +1,11 @@ +part of 'table_form_bloc.dart'; + +@freezed +class TableFormState with _$TableFormState { + factory TableFormState({ + required Option> failureOrTable, + @Default(false) bool isUpdating, + }) = _TableFormState; + + factory TableFormState.initial() => TableFormState(failureOrTable: none()); +} diff --git a/lib/application/table/table_loader/table_loader_bloc.dart b/lib/application/table/table_loader/table_loader_bloc.dart index e2d2736..8242515 100644 --- a/lib/application/table/table_loader/table_loader_bloc.dart +++ b/lib/application/table/table_loader/table_loader_bloc.dart @@ -1,3 +1,5 @@ +import 'dart:ui'; + import 'package:bloc/bloc.dart'; import 'package:dartz/dartz.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -21,6 +23,15 @@ class TableLoaderBloc extends Bloc { Emitter emit, ) { return event.map( + setSelectedTable: (e) async { + if (e.table == null) { + emit(state.copyWith(selectedTable: null)); + } else { + if (e.table?.status.isAvailable ?? false) { + emit(state.copyWith(selectedTable: e.table)); + } + } + }, fetched: (e) async { var newState = state; @@ -32,6 +43,19 @@ class TableLoaderBloc extends Bloc { newState = await _mapFetchedToState(newState, isRefresh: e.isRefresh); emit(newState); }, + updatedPostion: (e) async { + final updatedTables = state.tables.map((table) { + if (table.id == e.id) { + return table.copyWith( + positionX: e.position.dx, + positionY: e.position.dy, + ); + } + return table; + }).toList(); + + emit(state.copyWith(tables: updatedTables)); + }, ); } diff --git a/lib/application/table/table_loader/table_loader_bloc.freezed.dart b/lib/application/table/table_loader/table_loader_bloc.freezed.dart index ec4a648..963d29f 100644 --- a/lib/application/table/table_loader/table_loader_bloc.freezed.dart +++ b/lib/application/table/table_loader/table_loader_bloc.freezed.dart @@ -17,39 +17,44 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$TableLoaderEvent { - bool get isRefresh => throw _privateConstructorUsedError; @optionalTypeArgs TResult when({ required TResult Function(bool isRefresh) fetched, + required TResult Function(String id, Offset position) updatedPostion, + required TResult Function(Table? table) setSelectedTable, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function(bool isRefresh)? fetched, + TResult? Function(String id, Offset position)? updatedPostion, + TResult? Function(Table? table)? setSelectedTable, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function(bool isRefresh)? fetched, + TResult Function(String id, Offset position)? updatedPostion, + TResult Function(Table? table)? setSelectedTable, required TResult orElse(), }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult map({ required TResult Function(_Fetched value) fetched, + required TResult Function(_UpdatedPosition value) updatedPostion, + required TResult Function(_SetSelectedTable value) setSelectedTable, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ TResult? Function(_Fetched value)? fetched, + TResult? Function(_UpdatedPosition value)? updatedPostion, + TResult? Function(_SetSelectedTable value)? setSelectedTable, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(_Fetched value)? fetched, + TResult Function(_UpdatedPosition value)? updatedPostion, + TResult Function(_SetSelectedTable value)? setSelectedTable, 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 get copyWith => - throw _privateConstructorUsedError; } /// @nodoc @@ -58,8 +63,6 @@ abstract class $TableLoaderEventCopyWith<$Res> { TableLoaderEvent value, $Res Function(TableLoaderEvent) then, ) = _$TableLoaderEventCopyWithImpl<$Res, TableLoaderEvent>; - @useResult - $Res call({bool isRefresh}); } /// @nodoc @@ -74,29 +77,14 @@ class _$TableLoaderEventCopyWithImpl<$Res, $Val extends TableLoaderEvent> /// 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> { +abstract class _$$FetchedImplCopyWith<$Res> { factory _$$FetchedImplCopyWith( _$FetchedImpl value, $Res Function(_$FetchedImpl) then, ) = __$$FetchedImplCopyWithImpl<$Res>; - @override @useResult $Res call({bool isRefresh}); } @@ -164,6 +152,8 @@ class _$FetchedImpl implements _Fetched { @optionalTypeArgs TResult when({ required TResult Function(bool isRefresh) fetched, + required TResult Function(String id, Offset position) updatedPostion, + required TResult Function(Table? table) setSelectedTable, }) { return fetched(isRefresh); } @@ -172,6 +162,8 @@ class _$FetchedImpl implements _Fetched { @optionalTypeArgs TResult? whenOrNull({ TResult? Function(bool isRefresh)? fetched, + TResult? Function(String id, Offset position)? updatedPostion, + TResult? Function(Table? table)? setSelectedTable, }) { return fetched?.call(isRefresh); } @@ -180,6 +172,8 @@ class _$FetchedImpl implements _Fetched { @optionalTypeArgs TResult maybeWhen({ TResult Function(bool isRefresh)? fetched, + TResult Function(String id, Offset position)? updatedPostion, + TResult Function(Table? table)? setSelectedTable, required TResult orElse(), }) { if (fetched != null) { @@ -192,6 +186,8 @@ class _$FetchedImpl implements _Fetched { @optionalTypeArgs TResult map({ required TResult Function(_Fetched value) fetched, + required TResult Function(_UpdatedPosition value) updatedPostion, + required TResult Function(_SetSelectedTable value) setSelectedTable, }) { return fetched(this); } @@ -200,6 +196,8 @@ class _$FetchedImpl implements _Fetched { @optionalTypeArgs TResult? mapOrNull({ TResult? Function(_Fetched value)? fetched, + TResult? Function(_UpdatedPosition value)? updatedPostion, + TResult? Function(_SetSelectedTable value)? setSelectedTable, }) { return fetched?.call(this); } @@ -208,6 +206,8 @@ class _$FetchedImpl implements _Fetched { @optionalTypeArgs TResult maybeMap({ TResult Function(_Fetched value)? fetched, + TResult Function(_UpdatedPosition value)? updatedPostion, + TResult Function(_SetSelectedTable value)? setSelectedTable, required TResult orElse(), }) { if (fetched != null) { @@ -220,21 +220,350 @@ class _$FetchedImpl implements _Fetched { 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 +abstract class _$$UpdatedPositionImplCopyWith<$Res> { + factory _$$UpdatedPositionImplCopyWith( + _$UpdatedPositionImpl value, + $Res Function(_$UpdatedPositionImpl) then, + ) = __$$UpdatedPositionImplCopyWithImpl<$Res>; + @useResult + $Res call({String id, Offset position}); +} + +/// @nodoc +class __$$UpdatedPositionImplCopyWithImpl<$Res> + extends _$TableLoaderEventCopyWithImpl<$Res, _$UpdatedPositionImpl> + implements _$$UpdatedPositionImplCopyWith<$Res> { + __$$UpdatedPositionImplCopyWithImpl( + _$UpdatedPositionImpl _value, + $Res Function(_$UpdatedPositionImpl) _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? id = null, Object? position = null}) { + return _then( + _$UpdatedPositionImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + position: null == position + ? _value.position + : position // ignore: cast_nullable_to_non_nullable + as Offset, + ), + ); + } +} + +/// @nodoc + +class _$UpdatedPositionImpl implements _UpdatedPosition { + const _$UpdatedPositionImpl({required this.id, required this.position}); + + @override + final String id; + @override + final Offset position; + + @override + String toString() { + return 'TableLoaderEvent.updatedPostion(id: $id, position: $position)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$UpdatedPositionImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.position, position) || + other.position == position)); + } + + @override + int get hashCode => Object.hash(runtimeType, id, position); + + /// 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') + _$$UpdatedPositionImplCopyWith<_$UpdatedPositionImpl> get copyWith => + __$$UpdatedPositionImplCopyWithImpl<_$UpdatedPositionImpl>( + this, + _$identity, + ); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(bool isRefresh) fetched, + required TResult Function(String id, Offset position) updatedPostion, + required TResult Function(Table? table) setSelectedTable, + }) { + return updatedPostion(id, position); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(bool isRefresh)? fetched, + TResult? Function(String id, Offset position)? updatedPostion, + TResult? Function(Table? table)? setSelectedTable, + }) { + return updatedPostion?.call(id, position); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(bool isRefresh)? fetched, + TResult Function(String id, Offset position)? updatedPostion, + TResult Function(Table? table)? setSelectedTable, + required TResult orElse(), + }) { + if (updatedPostion != null) { + return updatedPostion(id, position); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Fetched value) fetched, + required TResult Function(_UpdatedPosition value) updatedPostion, + required TResult Function(_SetSelectedTable value) setSelectedTable, + }) { + return updatedPostion(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Fetched value)? fetched, + TResult? Function(_UpdatedPosition value)? updatedPostion, + TResult? Function(_SetSelectedTable value)? setSelectedTable, + }) { + return updatedPostion?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Fetched value)? fetched, + TResult Function(_UpdatedPosition value)? updatedPostion, + TResult Function(_SetSelectedTable value)? setSelectedTable, + required TResult orElse(), + }) { + if (updatedPostion != null) { + return updatedPostion(this); + } + return orElse(); + } +} + +abstract class _UpdatedPosition implements TableLoaderEvent { + const factory _UpdatedPosition({ + required final String id, + required final Offset position, + }) = _$UpdatedPositionImpl; + + String get id; + Offset get position; + + /// Create a copy of TableLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$UpdatedPositionImplCopyWith<_$UpdatedPositionImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$SetSelectedTableImplCopyWith<$Res> { + factory _$$SetSelectedTableImplCopyWith( + _$SetSelectedTableImpl value, + $Res Function(_$SetSelectedTableImpl) then, + ) = __$$SetSelectedTableImplCopyWithImpl<$Res>; + @useResult + $Res call({Table? table}); + + $TableCopyWith<$Res>? get table; +} + +/// @nodoc +class __$$SetSelectedTableImplCopyWithImpl<$Res> + extends _$TableLoaderEventCopyWithImpl<$Res, _$SetSelectedTableImpl> + implements _$$SetSelectedTableImplCopyWith<$Res> { + __$$SetSelectedTableImplCopyWithImpl( + _$SetSelectedTableImpl _value, + $Res Function(_$SetSelectedTableImpl) _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? table = freezed}) { + return _then( + _$SetSelectedTableImpl( + freezed == table + ? _value.table + : table // ignore: cast_nullable_to_non_nullable + as Table?, + ), + ); + } + + /// Create a copy of TableLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $TableCopyWith<$Res>? get table { + if (_value.table == null) { + return null; + } + + return $TableCopyWith<$Res>(_value.table!, (value) { + return _then(_value.copyWith(table: value)); + }); + } +} + +/// @nodoc + +class _$SetSelectedTableImpl implements _SetSelectedTable { + const _$SetSelectedTableImpl(this.table); + + @override + final Table? table; + + @override + String toString() { + return 'TableLoaderEvent.setSelectedTable(table: $table)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SetSelectedTableImpl && + (identical(other.table, table) || other.table == table)); + } + + @override + int get hashCode => Object.hash(runtimeType, table); + + /// 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') + _$$SetSelectedTableImplCopyWith<_$SetSelectedTableImpl> get copyWith => + __$$SetSelectedTableImplCopyWithImpl<_$SetSelectedTableImpl>( + this, + _$identity, + ); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(bool isRefresh) fetched, + required TResult Function(String id, Offset position) updatedPostion, + required TResult Function(Table? table) setSelectedTable, + }) { + return setSelectedTable(table); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function(bool isRefresh)? fetched, + TResult? Function(String id, Offset position)? updatedPostion, + TResult? Function(Table? table)? setSelectedTable, + }) { + return setSelectedTable?.call(table); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(bool isRefresh)? fetched, + TResult Function(String id, Offset position)? updatedPostion, + TResult Function(Table? table)? setSelectedTable, + required TResult orElse(), + }) { + if (setSelectedTable != null) { + return setSelectedTable(table); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(_Fetched value) fetched, + required TResult Function(_UpdatedPosition value) updatedPostion, + required TResult Function(_SetSelectedTable value) setSelectedTable, + }) { + return setSelectedTable(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(_Fetched value)? fetched, + TResult? Function(_UpdatedPosition value)? updatedPostion, + TResult? Function(_SetSelectedTable value)? setSelectedTable, + }) { + return setSelectedTable?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(_Fetched value)? fetched, + TResult Function(_UpdatedPosition value)? updatedPostion, + TResult Function(_SetSelectedTable value)? setSelectedTable, + required TResult orElse(), + }) { + if (setSelectedTable != null) { + return setSelectedTable(this); + } + return orElse(); + } +} + +abstract class _SetSelectedTable implements TableLoaderEvent { + const factory _SetSelectedTable(final Table? table) = _$SetSelectedTableImpl; + + Table? get table; + + /// Create a copy of TableLoaderEvent + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SetSelectedTableImplCopyWith<_$SetSelectedTableImpl> get copyWith => + throw _privateConstructorUsedError; +} + /// @nodoc mixin _$TableLoaderState { List get tables => throw _privateConstructorUsedError; Option get failureOption => throw _privateConstructorUsedError; + Table? get selectedTable => throw _privateConstructorUsedError; bool get isFetching => throw _privateConstructorUsedError; bool get hasReachedMax => throw _privateConstructorUsedError; int get page => throw _privateConstructorUsedError; @@ -256,10 +585,13 @@ abstract class $TableLoaderStateCopyWith<$Res> { $Res call({ List
tables, Option failureOption, + Table? selectedTable, bool isFetching, bool hasReachedMax, int page, }); + + $TableCopyWith<$Res>? get selectedTable; } /// @nodoc @@ -279,6 +611,7 @@ class _$TableLoaderStateCopyWithImpl<$Res, $Val extends TableLoaderState> $Res call({ Object? tables = null, Object? failureOption = null, + Object? selectedTable = freezed, Object? isFetching = null, Object? hasReachedMax = null, Object? page = null, @@ -293,6 +626,10 @@ class _$TableLoaderStateCopyWithImpl<$Res, $Val extends TableLoaderState> ? _value.failureOption : failureOption // ignore: cast_nullable_to_non_nullable as Option, + selectedTable: freezed == selectedTable + ? _value.selectedTable + : selectedTable // ignore: cast_nullable_to_non_nullable + as Table?, isFetching: null == isFetching ? _value.isFetching : isFetching // ignore: cast_nullable_to_non_nullable @@ -309,6 +646,20 @@ class _$TableLoaderStateCopyWithImpl<$Res, $Val extends TableLoaderState> as $Val, ); } + + /// Create a copy of TableLoaderState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $TableCopyWith<$Res>? get selectedTable { + if (_value.selectedTable == null) { + return null; + } + + return $TableCopyWith<$Res>(_value.selectedTable!, (value) { + return _then(_value.copyWith(selectedTable: value) as $Val); + }); + } } /// @nodoc @@ -323,10 +674,14 @@ abstract class _$$TableLoaderStateImplCopyWith<$Res> $Res call({ List
tables, Option failureOption, + Table? selectedTable, bool isFetching, bool hasReachedMax, int page, }); + + @override + $TableCopyWith<$Res>? get selectedTable; } /// @nodoc @@ -345,6 +700,7 @@ class __$$TableLoaderStateImplCopyWithImpl<$Res> $Res call({ Object? tables = null, Object? failureOption = null, + Object? selectedTable = freezed, Object? isFetching = null, Object? hasReachedMax = null, Object? page = null, @@ -359,6 +715,10 @@ class __$$TableLoaderStateImplCopyWithImpl<$Res> ? _value.failureOption : failureOption // ignore: cast_nullable_to_non_nullable as Option, + selectedTable: freezed == selectedTable + ? _value.selectedTable + : selectedTable // ignore: cast_nullable_to_non_nullable + as Table?, isFetching: null == isFetching ? _value.isFetching : isFetching // ignore: cast_nullable_to_non_nullable @@ -382,6 +742,7 @@ class _$TableLoaderStateImpl implements _TableLoaderState { _$TableLoaderStateImpl({ required final List
tables, required this.failureOption, + this.selectedTable, this.isFetching = false, this.hasReachedMax = false, this.page = 1, @@ -398,6 +759,8 @@ class _$TableLoaderStateImpl implements _TableLoaderState { @override final Option failureOption; @override + final Table? selectedTable; + @override @JsonKey() final bool isFetching; @override @@ -409,7 +772,7 @@ class _$TableLoaderStateImpl implements _TableLoaderState { @override String toString() { - return 'TableLoaderState(tables: $tables, failureOption: $failureOption, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page)'; + return 'TableLoaderState(tables: $tables, failureOption: $failureOption, selectedTable: $selectedTable, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page)'; } @override @@ -420,6 +783,8 @@ class _$TableLoaderStateImpl implements _TableLoaderState { const DeepCollectionEquality().equals(other._tables, _tables) && (identical(other.failureOption, failureOption) || other.failureOption == failureOption) && + (identical(other.selectedTable, selectedTable) || + other.selectedTable == selectedTable) && (identical(other.isFetching, isFetching) || other.isFetching == isFetching) && (identical(other.hasReachedMax, hasReachedMax) || @@ -432,6 +797,7 @@ class _$TableLoaderStateImpl implements _TableLoaderState { runtimeType, const DeepCollectionEquality().hash(_tables), failureOption, + selectedTable, isFetching, hasReachedMax, page, @@ -453,6 +819,7 @@ abstract class _TableLoaderState implements TableLoaderState { factory _TableLoaderState({ required final List
tables, required final Option failureOption, + final Table? selectedTable, final bool isFetching, final bool hasReachedMax, final int page, @@ -463,6 +830,8 @@ abstract class _TableLoaderState implements TableLoaderState { @override Option get failureOption; @override + Table? get selectedTable; + @override bool get isFetching; @override bool get hasReachedMax; diff --git a/lib/application/table/table_loader/table_loader_event.dart b/lib/application/table/table_loader/table_loader_event.dart index e4861b5..b145f1a 100644 --- a/lib/application/table/table_loader/table_loader_event.dart +++ b/lib/application/table/table_loader/table_loader_event.dart @@ -4,4 +4,10 @@ part of 'table_loader_bloc.dart'; class TableLoaderEvent with _$TableLoaderEvent { const factory TableLoaderEvent.fetched({@Default(false) bool isRefresh}) = _Fetched; + const factory TableLoaderEvent.updatedPostion({ + required String id, + required Offset position, + }) = _UpdatedPosition; + const factory TableLoaderEvent.setSelectedTable(Table? table) = + _SetSelectedTable; } diff --git a/lib/application/table/table_loader/table_loader_state.dart b/lib/application/table/table_loader/table_loader_state.dart index 3663056..0bd49a3 100644 --- a/lib/application/table/table_loader/table_loader_state.dart +++ b/lib/application/table/table_loader/table_loader_state.dart @@ -5,6 +5,7 @@ class TableLoaderState with _$TableLoaderState { factory TableLoaderState({ required List
tables, required Option failureOption, + Table? selectedTable, @Default(false) bool isFetching, @Default(false) bool hasReachedMax, @Default(1) int page, diff --git a/lib/domain/table/repositories/i_table_repository.dart b/lib/domain/table/repositories/i_table_repository.dart index c55d008..6e53a28 100644 --- a/lib/domain/table/repositories/i_table_repository.dart +++ b/lib/domain/table/repositories/i_table_repository.dart @@ -5,4 +5,9 @@ abstract class ITableRepository { int page = 1, int limit = 50, }); + + Future> updatePosition({ + required String id, + required Offset position, + }); } diff --git a/lib/domain/table/table.dart b/lib/domain/table/table.dart index aec0379..93cb9f4 100644 --- a/lib/domain/table/table.dart +++ b/lib/domain/table/table.dart @@ -1,3 +1,5 @@ +import 'dart:ui'; + import 'package:dartz/dartz.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; diff --git a/lib/infrastructure/table/datasources/remote_data_provider.dart b/lib/infrastructure/table/datasources/remote_data_provider.dart index 588e3f1..835f6ee 100644 --- a/lib/infrastructure/table/datasources/remote_data_provider.dart +++ b/lib/infrastructure/table/datasources/remote_data_provider.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'package:data_channel/data_channel.dart'; +import 'package:flutter/widgets.dart'; import 'package:injectable/injectable.dart'; import '../../../common/api/api_client.dart'; @@ -42,4 +43,32 @@ class TableRemoteDataProvider { return DC.error(TableFailure.serverError(e)); } } + + Future> updatePosition({ + required String id, + required Offset position, + }) async { + try { + final response = await _apiClient.put( + '${ApiPath.tables}/$id', + data: { + 'position_x': position.dx.round(), + 'position_y': position.dy.round(), + }, + headers: getAuthorizationHeader(), + ); + + if (response.data['success'] == false) { + return DC.error(TableFailure.unexpectedError()); + } + + final table = TableDto.fromJson( + response.data['data'] as Map, + ); + return DC.data(table); + } on ApiFailure catch (e, s) { + log('updatePositionTableError', name: _logName, error: e, stackTrace: s); + return DC.error(TableFailure.serverError(e)); + } + } } diff --git a/lib/infrastructure/table/repositories/table_repository.dart b/lib/infrastructure/table/repositories/table_repository.dart index 8fa9350..0ff90be 100644 --- a/lib/infrastructure/table/repositories/table_repository.dart +++ b/lib/infrastructure/table/repositories/table_repository.dart @@ -1,4 +1,5 @@ import 'dart:developer'; +import 'dart:ui'; import 'package:dartz/dartz.dart'; import 'package:injectable/injectable.dart'; @@ -36,4 +37,28 @@ class TableRepository implements ITableRepository { return left(const TableFailure.unexpectedError()); } } + + @override + Future> updatePosition({ + required String id, + required Offset position, + }) async { + try { + final result = await _remoteDataProvider.updatePosition( + id: id, + position: position, + ); + + if (result.hasError) { + return left(result.error!); + } + + final table = result.data!.toDomain(); + + return right(table); + } catch (e) { + log('updatePositionTableError', name: _logName, error: e); + return left(const TableFailure.unexpectedError()); + } + } } diff --git a/lib/injection.config.dart b/lib/injection.config.dart index e5fc17b..5a50c5b 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -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_form/table_form_bloc.dart' + as _i248; 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; @@ -189,6 +191,9 @@ extension GetItInjectableX on _i174.GetIt { gh.factory<_i424.TableLoaderBloc>( () => _i424.TableLoaderBloc(gh<_i983.ITableRepository>()), ); + gh.factory<_i248.TableFormBloc>( + () => _i248.TableFormBloc(gh<_i983.ITableRepository>()), + ); return this; } } diff --git a/lib/presentation/pages/main/pages/table/table_page.dart b/lib/presentation/pages/main/pages/table/table_page.dart index 7a49fcb..612c63d 100644 --- a/lib/presentation/pages/main/pages/table/table_page.dart +++ b/lib/presentation/pages/main/pages/table/table_page.dart @@ -2,12 +2,14 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../../../../application/table/table_form/table_form_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/floating_bottom_navbar.dart'; import 'widgets/table_card.dart'; @RoutePage() @@ -18,16 +20,20 @@ class TablePage extends StatefulWidget implements AutoRouteWrapper { State createState() => _TablePageState(); @override - Widget wrappedRoute(BuildContext context) => BlocProvider( - create: (context) => - getIt() - ..add(TableLoaderEvent.fetched(isRefresh: true)), + Widget wrappedRoute(BuildContext context) => MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => + getIt() + ..add(TableLoaderEvent.fetched(isRefresh: true)), + ), + BlocProvider(create: (context) => getIt()), + ], child: this, ); } class _TablePageState extends State { - t.Table? selectedTable; t.Table? draggingTable; Offset? tapPosition; @@ -134,7 +140,7 @@ class _TablePageState extends State { ), ), ...state.tables.map((table) { - final isSelected = selectedTable == table; + final isSelected = state.selectedTable == table; return Positioned( left: table.positionX, top: table.positionY, @@ -165,42 +171,53 @@ class _TablePageState extends State { }); }, onDragEnd: (details) { + final RenderBox box = + context.findRenderObject() + as RenderBox; + final Offset local = box.globalToLocal( + details.offset, + ); + + final newX = local.dx.clamp( + 0.0, + mapWidth - 120, + ); + final newY = local.dy.clamp( + 0.0, + mapHeight - 80, + ); + 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().add( - // ChangePositionTableEvent.changePositionTable( - // tableId: table.id ?? "", - // position: Offset( - // table.positionX ?? 0.0, - // table.positionY ?? 0.0, - // ), - // ), - // ); + + // Update position locally in bloc state + context.read().add( + TableLoaderEvent.updatedPostion( + id: table.id, + position: Offset(newX, newY), + ), + ); + context.read().add( + TableFormEvent.updated( + id: table.id, + position: Offset(newX, newY), + ), + ); }, child: GestureDetector( - onTap: () {}, + onTap: () { + context.read().add( + TableLoaderEvent.setSelectedTable( + table, + ), + ); + }, onTapDown: (details) => tapPosition = details.globalPosition, onLongPress: () { if (table.status.isOccupied) { - // _showPopupMenu(context, table); + _showPopupMenu(context, table); } }, child: TableCard( @@ -218,6 +235,7 @@ class _TablePageState extends State { ), ], ), + TableFloatingBottomNavbar(selectedTable: state.selectedTable), ], ), ); @@ -235,4 +253,39 @@ class _TablePageState extends State { ], ); } + + void _showPopupMenu(BuildContext context, t.Table table) { + final RenderBox overlay = + Overlay.of(context).context.findRenderObject() as RenderBox; + + showMenu( + context: context, + position: RelativeRect.fromRect( + tapPosition != null + ? Rect.fromLTWH(tapPosition!.dx, tapPosition!.dy, 0, 0) + : Rect.fromLTWH(100, 100, 0, 0), + Offset.zero & overlay.size, + ), + color: AppColor.white, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + elevation: 1, + items: [ + PopupMenuItem( + onTap: () { + // showDialog( + // context: context, + // builder: (context) => TransferTableDialog(fromTable: table), + // ); + }, + child: Row( + children: [ + Icon(Icons.swap_horiz), + SizedBox(width: 8), + Text('Transfer'), + ], + ), + ), + ], + ); + } } diff --git a/lib/presentation/pages/main/pages/table/widgets/floating_bottom_navbar.dart b/lib/presentation/pages/main/pages/table/widgets/floating_bottom_navbar.dart new file mode 100644 index 0000000..dfa3f73 --- /dev/null +++ b/lib/presentation/pages/main/pages/table/widgets/floating_bottom_navbar.dart @@ -0,0 +1,140 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../../../../../application/table/table_loader/table_loader_bloc.dart'; +import '../../../../../../common/theme/theme.dart'; +import '../../../../../../domain/table/table.dart' as t; + +class TableFloatingBottomNavbar extends StatelessWidget { + final t.Table? selectedTable; + const TableFloatingBottomNavbar({super.key, this.selectedTable}); + + @override + Widget build(BuildContext context) { + return Positioned( + bottom: 20, // Jarak dari bawah + left: 16, // Jarak dari kiri + right: 16, + child: AnimatedSlide( + duration: const Duration(milliseconds: 400), + curve: Curves.elasticOut, + offset: selectedTable == null ? const Offset(0, 2) : Offset.zero, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 200), + opacity: selectedTable == null ? 0.0 : 1.0, + child: IgnorePointer( + ignoring: selectedTable == null, + child: Container( + margin: const EdgeInsets.all(16), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [AppColor.primary, AppColor.primary.withOpacity(0.6)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(24), + boxShadow: [ + BoxShadow( + color: AppColor.primary.withOpacity(0.3), + blurRadius: 20, + offset: const Offset(0, 8), + ), + ], + ), + child: Row( + children: [ + const Icon(Icons.table_bar, color: Colors.white, size: 24), + const SizedBox(width: 12), + Text( + "1 Meja Dipilih", + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + const SizedBox(width: 16), + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.2), + borderRadius: BorderRadius.circular(16), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + selectedTable?.tableName ?? "", + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(width: 4), + GestureDetector( + onTap: () { + context.read().add( + TableLoaderEvent.setSelectedTable(null), + ); + }, + child: const Icon( + Icons.close, + color: Colors.white, + size: 16, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + const SizedBox(width: 16), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: AppColor.primary, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 12, + ), + ), + onPressed: () { + if (selectedTable?.status.isAvailable ?? false) { + // context.pushReplacement( + // DashboardPage( + // table: selectedTable!, + // items: widget.items, + // ), + // ); + } else {} + }, + child: const Text( + "Tempatkan Pesanan", + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + ], + ), + ), + ), + ), + ), + ); + } +}