create table
This commit is contained in:
@@ -6,6 +6,8 @@ import '../application/category/category_loader/category_loader_bloc.dart';
|
||||
import '../application/checkout/checkout_form/checkout_form_bloc.dart';
|
||||
import '../application/outlet/outlet_loader/outlet_loader_bloc.dart';
|
||||
import '../application/product/product_loader/product_loader_bloc.dart';
|
||||
import '../application/table/table_form/table_form_bloc.dart';
|
||||
import '../application/table/table_loader/table_loader_bloc.dart';
|
||||
import '../common/theme/theme.dart';
|
||||
import '../common/constant/app_constant.dart';
|
||||
import '../injection.dart';
|
||||
@@ -31,6 +33,8 @@ class _AppWidgetState extends State<AppWidget> {
|
||||
BlocProvider(create: (context) => getIt<CategoryLoaderBloc>()),
|
||||
BlocProvider(create: (context) => getIt<ProductLoaderBloc>()),
|
||||
BlocProvider(create: (context) => getIt<CheckoutFormBloc>()),
|
||||
BlocProvider(create: (context) => getIt<TableLoaderBloc>()),
|
||||
BlocProvider(create: (context) => getIt<TableFormBloc>()),
|
||||
],
|
||||
child: MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../../../application/table/table_form/table_form_bloc.dart';
|
||||
import '../../button/button.dart';
|
||||
import '../../field/field.dart';
|
||||
import '../../spaces/space.dart';
|
||||
import '../dialog.dart';
|
||||
|
||||
class TableCreateDialog extends StatelessWidget {
|
||||
const TableCreateDialog({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<TableFormBloc, TableFormState>(
|
||||
builder: (context, state) {
|
||||
return CustomModalDialog(
|
||||
title: 'Tambah Meja',
|
||||
subtitle: 'Silahkan isi data meja',
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
vertical: 24.0,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
AppTextFormField(
|
||||
label: 'Nama Meja',
|
||||
onChanged: (value) {
|
||||
context.read<TableFormBloc>().add(
|
||||
TableFormEvent.nameChanged(value),
|
||||
);
|
||||
},
|
||||
),
|
||||
SpaceHeight(16),
|
||||
AppTextFormField(
|
||||
label: 'Kapasitas',
|
||||
keyboardType: TextInputType.number,
|
||||
onChanged: (value) {
|
||||
context.read<TableFormBloc>().add(
|
||||
TableFormEvent.capacityChanged(value),
|
||||
);
|
||||
},
|
||||
),
|
||||
SpaceHeight(24),
|
||||
AppElevatedButton.filled(
|
||||
onPressed: () {
|
||||
context.read<TableFormBloc>().add(
|
||||
const TableFormEvent.created(),
|
||||
);
|
||||
},
|
||||
label: "Simpan",
|
||||
isLoading: state.isCreating,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../common/theme/theme.dart';
|
||||
import '../../../domain/auth/auth.dart';
|
||||
import '../../../domain/table/table.dart';
|
||||
|
||||
class AppFlushbar {
|
||||
static void showSuccess(BuildContext context, String message) {
|
||||
@@ -50,4 +51,18 @@ class AppFlushbar {
|
||||
unexpectedError: (value) => 'Terjadi kesalahan, silahkan coba lagi',
|
||||
),
|
||||
);
|
||||
|
||||
static void showTableFailureToast(
|
||||
BuildContext context,
|
||||
TableFailure failure,
|
||||
) => showError(
|
||||
context,
|
||||
failure.map(
|
||||
serverError: (value) => value.failure.toStringFormatted(context),
|
||||
dynamicErrorMessage: (value) => value.erroMessage,
|
||||
unexpectedError: (value) => 'Terjadi kesalahan, silahkan coba lagi',
|
||||
empty: (value) => 'Tidak ada data',
|
||||
localStorageError: (value) => 'Terjadi kesalahan, silahkan coba lagi',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import '../../../../../common/extension/extension.dart';
|
||||
import '../../../../../common/theme/theme.dart';
|
||||
import '../../../../../domain/table/table.dart' as t;
|
||||
import '../../../../../injection.dart';
|
||||
import '../../../../components/dialog/table/table_create_dialog.dart';
|
||||
import '../../../../components/loader/loader_with_text.dart';
|
||||
import '../../../../components/toast/flushbar.dart';
|
||||
import 'widgets/floating_bottom_navbar.dart';
|
||||
import 'widgets/table_card.dart';
|
||||
|
||||
@@ -27,7 +29,6 @@ class TablePage extends StatefulWidget implements AutoRouteWrapper {
|
||||
getIt<TableLoaderBloc>()
|
||||
..add(TableLoaderEvent.fetched(isRefresh: true)),
|
||||
),
|
||||
BlocProvider(create: (context) => getIt<TableFormBloc>()),
|
||||
],
|
||||
child: this,
|
||||
);
|
||||
@@ -43,203 +44,227 @@ class _TablePageState extends State<TablePage> {
|
||||
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: () {
|
||||
return BlocListener<TableFormBloc, TableFormState>(
|
||||
listenWhen: (previous, current) =>
|
||||
previous.failureOrTable != current.failureOrTable,
|
||||
listener: (context, state) {
|
||||
state.failureOrTable.fold(() {}, (either) {
|
||||
either.fold((f) => AppFlushbar.showTableFailureToast(context, f), (
|
||||
success,
|
||||
) {
|
||||
if (context.mounted) {
|
||||
context.router.maybePop();
|
||||
context.read<TableLoaderBloc>().add(
|
||||
const TableLoaderEvent.fetched(isRefresh: true),
|
||||
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"),
|
||||
],
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
child: 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) => TableCreateDialog(),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
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,
|
||||
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],
|
||||
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],
|
||||
...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 = state.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) {
|
||||
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;
|
||||
});
|
||||
|
||||
// Update position locally in bloc state
|
||||
context.read<TableLoaderBloc>().add(
|
||||
TableLoaderEvent.updatedPostion(
|
||||
id: table.id,
|
||||
position: Offset(newX, newY),
|
||||
...state.tables.map((table) {
|
||||
final isSelected =
|
||||
state.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,
|
||||
),
|
||||
);
|
||||
context.read<TableFormBloc>().add(
|
||||
TableFormEvent.updated(
|
||||
id: table.id,
|
||||
position: Offset(newX, newY),
|
||||
),
|
||||
childWhenDragging: Opacity(
|
||||
opacity: 0.5,
|
||||
child: TableCard(
|
||||
table: table,
|
||||
isSelected: isSelected,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
),
|
||||
onDragStarted: () {
|
||||
setState(() {
|
||||
draggingTable = table;
|
||||
});
|
||||
},
|
||||
onDraggableCanceled: (velocity, offset) {
|
||||
setState(() {
|
||||
draggingTable = null;
|
||||
});
|
||||
},
|
||||
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;
|
||||
});
|
||||
|
||||
// Update position locally in bloc state
|
||||
context.read<TableLoaderBloc>().add(
|
||||
TableLoaderEvent.setSelectedTable(
|
||||
table,
|
||||
TableLoaderEvent.updatedPostion(
|
||||
id: table.id,
|
||||
position: Offset(newX, newY),
|
||||
),
|
||||
);
|
||||
context.read<TableFormBloc>().add(
|
||||
TableFormEvent.updated(
|
||||
id: table.id,
|
||||
position: Offset(newX, newY),
|
||||
),
|
||||
);
|
||||
},
|
||||
onTapDown: (details) =>
|
||||
tapPosition = details.globalPosition,
|
||||
onLongPress: () {
|
||||
if (table.status.isOccupied) {
|
||||
_showPopupMenu(context, table);
|
||||
}
|
||||
},
|
||||
child: TableCard(
|
||||
table: table,
|
||||
isSelected: isSelected,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
context.read<TableLoaderBloc>().add(
|
||||
TableLoaderEvent.setSelectedTable(
|
||||
table,
|
||||
),
|
||||
);
|
||||
},
|
||||
onTapDown: (details) => tapPosition =
|
||||
details.globalPosition,
|
||||
onLongPress: () {
|
||||
if (table.status.isOccupied) {
|
||||
context.read<TableLoaderBloc>().add(
|
||||
TableLoaderEvent.setSelectedTable(
|
||||
null,
|
||||
),
|
||||
);
|
||||
_showPopupMenu(context, table);
|
||||
}
|
||||
},
|
||||
child: TableCard(
|
||||
table: table,
|
||||
isSelected: isSelected,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
TableFloatingBottomNavbar(selectedTable: state.selectedTable),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
],
|
||||
),
|
||||
TableFloatingBottomNavbar(selectedTable: state.selectedTable),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user