mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
clean the code for save and next buttons and enhance UI
This commit is contained in:
@ -12,10 +12,13 @@ class SvgTextButton extends StatelessWidget {
|
|||||||
final double borderRadius;
|
final double borderRadius;
|
||||||
final List<BoxShadow> boxShadow;
|
final List<BoxShadow> boxShadow;
|
||||||
final double svgSize;
|
final double svgSize;
|
||||||
|
final double? fontSize;
|
||||||
|
final FontWeight? fontWeight;
|
||||||
const SvgTextButton({
|
const SvgTextButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.svgAsset,
|
required this.svgAsset,
|
||||||
|
this.fontSize,
|
||||||
|
this.fontWeight,
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
this.backgroundColor = ColorsManager.circleRolesBackground,
|
this.backgroundColor = ColorsManager.circleRolesBackground,
|
||||||
@ -60,8 +63,8 @@ class SvgTextButton extends StatelessWidget {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: labelColor,
|
color: labelColor,
|
||||||
fontSize: 16,
|
fontSize: fontSize ?? 16,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: fontWeight ?? FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -10,15 +10,17 @@ import 'package:syncrow_web/utils/constants/api_const.dart';
|
|||||||
class RemoteBookableSpacesService implements BookableSpacesService {
|
class RemoteBookableSpacesService implements BookableSpacesService {
|
||||||
final HTTPService _httpService;
|
final HTTPService _httpService;
|
||||||
RemoteBookableSpacesService(this._httpService);
|
RemoteBookableSpacesService(this._httpService);
|
||||||
static const _defaultErrorMessage = 'Failed to load tags';
|
static const _defaultErrorMessage = 'Failed to load Bookable Spaces';
|
||||||
@override
|
@override
|
||||||
Future<PaginatedDataModel<BookableSpacemodel>> load(
|
Future<PaginatedDataModel<BookableSpacemodel>> load(
|
||||||
BookableSpacesParams param) async {
|
BookableSpacesParams param) async {
|
||||||
try {
|
try {
|
||||||
final response = await _httpService.get(
|
final response = await _httpService.get(
|
||||||
//TODO: you have to Chage this API call Path
|
path: ApiEndpoints.bookableSpaces,
|
||||||
path: ApiEndpoints.listTags,
|
queryParameters: {
|
||||||
//*************|********** */
|
'configured': true,
|
||||||
|
'page': param.currentPage,
|
||||||
|
},
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
final result = json as Map<String, dynamic>;
|
final result = json as Map<String, dynamic>;
|
||||||
return PaginatedDataModel.fromJson(
|
return PaginatedDataModel.fromJson(
|
||||||
|
@ -18,9 +18,12 @@ class RemoteNonBookableSpaces implements NonBookableSpacesService {
|
|||||||
NonBookableSpacesParams params) async {
|
NonBookableSpacesParams params) async {
|
||||||
try {
|
try {
|
||||||
final response = await _httpService.get(
|
final response = await _httpService.get(
|
||||||
//TODO: you have to Chage this API call Path
|
path: ApiEndpoints.bookableSpaces,
|
||||||
path: ApiEndpoints.listTags,
|
queryParameters: {
|
||||||
//*************|********** */
|
'configured': false,
|
||||||
|
'page': params.currentPage,
|
||||||
|
'search': params.searchedWords,
|
||||||
|
},
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
final result = json as Map<String, dynamic>;
|
final result = json as Map<String, dynamic>;
|
||||||
return PaginatedDataModel.fromJson(
|
return PaginatedDataModel.fromJson(
|
||||||
@ -50,7 +53,7 @@ class RemoteNonBookableSpaces implements NonBookableSpacesService {
|
|||||||
SendBookableSpacesToApiParams params) async {
|
SendBookableSpacesToApiParams params) async {
|
||||||
try {
|
try {
|
||||||
await _httpService.post(
|
await _httpService.post(
|
||||||
path: ApiEndpoints.addBookableSpaces,
|
path: ApiEndpoints.bookableSpaces,
|
||||||
body: params.toJson(),
|
body: params.toJson(),
|
||||||
expectedResponseModel: (p0) {},
|
expectedResponseModel: (p0) {},
|
||||||
);
|
);
|
||||||
|
@ -3,30 +3,28 @@ import 'package:flutter/material.dart';
|
|||||||
class BookableSpaceConfig {
|
class BookableSpaceConfig {
|
||||||
String configUuid;
|
String configUuid;
|
||||||
List<String> bookableDays;
|
List<String> bookableDays;
|
||||||
TimeOfDay bookingStartTime;
|
TimeOfDay? bookingStartTime;
|
||||||
TimeOfDay bookingEndTime;
|
TimeOfDay? bookingEndTime;
|
||||||
int cost;
|
int cost;
|
||||||
bool availability;
|
bool availability;
|
||||||
BookableSpaceConfig({
|
BookableSpaceConfig({
|
||||||
required this.configUuid,
|
required this.configUuid,
|
||||||
required this.availability,
|
required this.availability,
|
||||||
required this.bookableDays,
|
required this.bookableDays,
|
||||||
required this.bookingEndTime,
|
this.bookingEndTime,
|
||||||
required this.bookingStartTime,
|
this.bookingStartTime,
|
||||||
required this.cost,
|
required this.cost,
|
||||||
});
|
});
|
||||||
factory BookableSpaceConfig.zero() => BookableSpaceConfig(
|
factory BookableSpaceConfig.zero() => BookableSpaceConfig(
|
||||||
configUuid: '',
|
configUuid: '',
|
||||||
bookableDays: [],
|
bookableDays: [],
|
||||||
availability: false,
|
availability: false,
|
||||||
bookingEndTime: TimeOfDay.now(),
|
|
||||||
bookingStartTime: TimeOfDay.now(),
|
|
||||||
cost: -1,
|
cost: -1,
|
||||||
);
|
);
|
||||||
factory BookableSpaceConfig.fromJson(Map<String, dynamic> json) =>
|
factory BookableSpaceConfig.fromJson(Map<String, dynamic> json) =>
|
||||||
BookableSpaceConfig(
|
BookableSpaceConfig(
|
||||||
configUuid: json['uuid'] as String,
|
configUuid: json['uuid'] as String,
|
||||||
bookableDays: json['daysAvailable'] as List<String>,
|
bookableDays: (json['daysAvailable'] as List).cast<String>(),
|
||||||
availability: (json['active'] as bool?) ?? false,
|
availability: (json['active'] as bool?) ?? false,
|
||||||
bookingEndTime: parseTimeOfDay(json['startTime'] as String),
|
bookingEndTime: parseTimeOfDay(json['startTime'] as String),
|
||||||
bookingStartTime: parseTimeOfDay(json['endTime'] as String),
|
bookingStartTime: parseTimeOfDay(json['endTime'] as String),
|
||||||
@ -41,5 +39,8 @@ class BookableSpaceConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool get isValid =>
|
bool get isValid =>
|
||||||
configUuid.isNotEmpty && bookableDays.isNotEmpty && cost > 0;
|
bookableDays.isNotEmpty &&
|
||||||
|
cost > 0 &&
|
||||||
|
bookingStartTime != null &&
|
||||||
|
bookingEndTime != null;
|
||||||
}
|
}
|
||||||
|
@ -3,28 +3,29 @@ import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domai
|
|||||||
class BookableSpacemodel {
|
class BookableSpacemodel {
|
||||||
String spaceUuid;
|
String spaceUuid;
|
||||||
String spaceName;
|
String spaceName;
|
||||||
BookableSpaceConfig spaceConfig;
|
BookableSpaceConfig? spaceConfig;
|
||||||
String spaceVirtualAddress;
|
String spaceVirtualAddress;
|
||||||
|
|
||||||
BookableSpacemodel({
|
BookableSpacemodel({
|
||||||
required this.spaceUuid,
|
required this.spaceUuid,
|
||||||
required this.spaceName,
|
required this.spaceName,
|
||||||
required this.spaceConfig,
|
this.spaceConfig,
|
||||||
required this.spaceVirtualAddress,
|
required this.spaceVirtualAddress,
|
||||||
});
|
});
|
||||||
factory BookableSpacemodel.zero() => BookableSpacemodel(
|
factory BookableSpacemodel.zero() => BookableSpacemodel(
|
||||||
spaceUuid: '',
|
spaceUuid: '',
|
||||||
spaceName: '',
|
spaceName: '',
|
||||||
spaceConfig: BookableSpaceConfig.zero(),
|
|
||||||
spaceVirtualAddress: '',
|
spaceVirtualAddress: '',
|
||||||
);
|
);
|
||||||
factory BookableSpacemodel.fromJson(Map<String, dynamic> json) =>
|
factory BookableSpacemodel.fromJson(Map<String, dynamic> json) =>
|
||||||
BookableSpacemodel(
|
BookableSpacemodel(
|
||||||
spaceUuid: json['uuid'] as String,
|
spaceUuid: json['uuid'] as String,
|
||||||
spaceName: json['spaceName'] as String,
|
spaceName: json['spaceName'] as String,
|
||||||
spaceConfig: BookableSpaceConfig.fromJson(
|
spaceConfig: json['bookableConfig'] == null
|
||||||
json['bookableConfig'] as Map<String, dynamic>),
|
? BookableSpaceConfig.zero()
|
||||||
spaceVirtualAddress: json['spaceVirtualAddress'] as String,
|
: BookableSpaceConfig.fromJson(
|
||||||
|
json['bookableConfig'] as Map<String, dynamic>),
|
||||||
|
spaceVirtualAddress: json['virtualLocation'] as String,
|
||||||
);
|
);
|
||||||
|
|
||||||
static List<BookableSpacemodel> fromJsonList(List<dynamic> jsonList) =>
|
static List<BookableSpacemodel> fromJsonList(List<dynamic> jsonList) =>
|
||||||
@ -38,5 +39,6 @@ class BookableSpacemodel {
|
|||||||
spaceUuid.isNotEmpty &&
|
spaceUuid.isNotEmpty &&
|
||||||
spaceName.isNotEmpty &&
|
spaceName.isNotEmpty &&
|
||||||
spaceVirtualAddress.isNotEmpty &&
|
spaceVirtualAddress.isNotEmpty &&
|
||||||
spaceConfig.isValid;
|
spaceConfig != null &&
|
||||||
|
spaceConfig!.isValid;
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,14 @@ class SendBookableSpacesToApiParams {
|
|||||||
return SendBookableSpacesToApiParams(
|
return SendBookableSpacesToApiParams(
|
||||||
spaceUuids: bookableSpaces.map((space) => space.spaceUuid).toList(),
|
spaceUuids: bookableSpaces.map((space) => space.spaceUuid).toList(),
|
||||||
daysAvailable: bookableSpaces
|
daysAvailable: bookableSpaces
|
||||||
.expand((space) => space.spaceConfig.bookableDays)
|
.expand((space) => space.spaceConfig!.bookableDays)
|
||||||
.toSet()
|
.toSet()
|
||||||
.toList(),
|
.toList(),
|
||||||
startTime: formatTimeOfDayTo24HourString(
|
startTime: formatTimeOfDayTo24HourString(
|
||||||
bookableSpaces.first.spaceConfig.bookingStartTime),
|
bookableSpaces.first.spaceConfig!.bookingStartTime!),
|
||||||
endTime: formatTimeOfDayTo24HourString(
|
endTime: formatTimeOfDayTo24HourString(
|
||||||
bookableSpaces.first.spaceConfig.bookingEndTime),
|
bookableSpaces.first.spaceConfig!.bookingEndTime!),
|
||||||
points: bookableSpaces.first.spaceConfig.cost,
|
points: bookableSpaces.first.spaceConfig!.cost,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,27 +20,49 @@ class NonBookableSpacesBloc
|
|||||||
on<AddToBookableSpaceEvent>(_onAddToBookableSpaceEvent);
|
on<AddToBookableSpaceEvent>(_onAddToBookableSpaceEvent);
|
||||||
on<RemoveFromBookableSpaceEvent>(_onRemoveFromBookableSpaceEvent);
|
on<RemoveFromBookableSpaceEvent>(_onRemoveFromBookableSpaceEvent);
|
||||||
on<SendBookableSpacesToApi>(_onSendBookableSpacesToApi);
|
on<SendBookableSpacesToApi>(_onSendBookableSpacesToApi);
|
||||||
|
on<CheckConfigurValidityEvent>(_onCheckConfigurValidityEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeOfDay get endTime =>
|
TimeOfDay? get endTime =>
|
||||||
selectedBookableSpaces.first.spaceConfig.bookingEndTime;
|
selectedBookableSpaces.first.spaceConfig!.bookingEndTime;
|
||||||
|
|
||||||
TimeOfDay get startTime =>
|
TimeOfDay? get startTime =>
|
||||||
selectedBookableSpaces.first.spaceConfig.bookingStartTime;
|
selectedBookableSpaces.first.spaceConfig!.bookingStartTime;
|
||||||
Future<void> _onLoadUnBookableSpacesEvent(LoadUnBookableSpacesEvent event,
|
Future<void> _onLoadUnBookableSpacesEvent(LoadUnBookableSpacesEvent event,
|
||||||
Emitter<NonBookableSpacesState> emit) async {
|
Emitter<NonBookableSpacesState> emit) async {
|
||||||
emit(NonBookableSpacesLoading());
|
if (state is NonBookableSpacesLoaded) {
|
||||||
try {
|
final currState = state as NonBookableSpacesLoaded;
|
||||||
final nonBookableSpacesList = await nonBookableSpacesService.load(
|
try {
|
||||||
event.nonBookableSpacesParams,
|
emit(NonBookableSpacesLoading(
|
||||||
);
|
lastNonBookableSpaces: currState.nonBookableSpaces));
|
||||||
emit(
|
|
||||||
NonBookableSpacesLoaded(nonBookableSpaces: nonBookableSpacesList),
|
final nonBookableSpacesList = await nonBookableSpacesService.load(
|
||||||
);
|
event.nonBookableSpacesParams,
|
||||||
} catch (e) {
|
);
|
||||||
emit(
|
nonBookableSpacesList.data.addAll(currState.nonBookableSpaces.data);
|
||||||
NonBookableSpacesError(e.toString()),
|
|
||||||
);
|
emit(
|
||||||
|
NonBookableSpacesLoaded(nonBookableSpaces: nonBookableSpacesList),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
emit(
|
||||||
|
NonBookableSpacesError(e.toString()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
emit(const NonBookableSpacesLoading());
|
||||||
|
final nonBookableSpacesList = await nonBookableSpacesService.load(
|
||||||
|
event.nonBookableSpacesParams,
|
||||||
|
);
|
||||||
|
emit(
|
||||||
|
NonBookableSpacesLoaded(nonBookableSpaces: nonBookableSpacesList),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
emit(
|
||||||
|
NonBookableSpacesError(e.toString()),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +72,7 @@ class NonBookableSpacesBloc
|
|||||||
) {
|
) {
|
||||||
if (state is NonBookableSpacesLoaded) {
|
if (state is NonBookableSpacesLoaded) {
|
||||||
final currentState = state as NonBookableSpacesLoaded;
|
final currentState = state as NonBookableSpacesLoaded;
|
||||||
|
emit(AddNonBookableSpaceIntoBookableState());
|
||||||
final updatedSelectedSpaces =
|
final updatedSelectedSpaces =
|
||||||
List<BookableSpacemodel>.from(currentState.selectedBookableSpaces)
|
List<BookableSpacemodel>.from(currentState.selectedBookableSpaces)
|
||||||
..add(event.nonBookableSpace);
|
..add(event.nonBookableSpace);
|
||||||
@ -70,7 +92,10 @@ class NonBookableSpacesBloc
|
|||||||
Emitter<NonBookableSpacesState> emit) {
|
Emitter<NonBookableSpacesState> emit) {
|
||||||
if (state is NonBookableSpacesLoaded) {
|
if (state is NonBookableSpacesLoaded) {
|
||||||
final currentState = state as NonBookableSpacesLoaded;
|
final currentState = state as NonBookableSpacesLoaded;
|
||||||
currentState.selectedBookableSpaces.remove(event.bookableSpace);
|
emit(RemoveBookableSpaceIntoNonBookableState());
|
||||||
|
if (currentState.selectedBookableSpaces.isNotEmpty) {
|
||||||
|
currentState.selectedBookableSpaces.remove(event.bookableSpace);
|
||||||
|
}
|
||||||
selectedBookableSpaces.remove(event.bookableSpace);
|
selectedBookableSpaces.remove(event.bookableSpace);
|
||||||
emit(
|
emit(
|
||||||
NonBookableSpacesLoaded(
|
NonBookableSpacesLoaded(
|
||||||
@ -83,17 +108,27 @@ class NonBookableSpacesBloc
|
|||||||
|
|
||||||
Future<void> _onSendBookableSpacesToApi(SendBookableSpacesToApi event,
|
Future<void> _onSendBookableSpacesToApi(SendBookableSpacesToApi event,
|
||||||
Emitter<NonBookableSpacesState> emit) async {
|
Emitter<NonBookableSpacesState> emit) async {
|
||||||
emit(NonBookableSpacesLoading());
|
emit(const NonBookableSpacesLoading());
|
||||||
try {
|
try {
|
||||||
await nonBookableSpacesService.sendBookableSpacesToApi(
|
await nonBookableSpacesService.sendBookableSpacesToApi(
|
||||||
SendBookableSpacesToApiParams.fromBookableSpacesModel(
|
SendBookableSpacesToApiParams.fromBookableSpacesModel(
|
||||||
selectedBookableSpaces,
|
selectedBookableSpaces,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
emit(NonBookableSpacesInitial());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(
|
emit(
|
||||||
NonBookableSpacesError(e.toString()),
|
NonBookableSpacesError(e.toString()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onCheckConfigurValidityEvent(
|
||||||
|
CheckConfigurValidityEvent event, Emitter<NonBookableSpacesState> emit) {
|
||||||
|
if (selectedBookableSpaces.first.spaceConfig!.isValid) {
|
||||||
|
emit(ValidSaveButtonState());
|
||||||
|
} else {
|
||||||
|
emit(UnValidSaveButtonState());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,3 +29,5 @@ class RemoveFromBookableSpaceEvent extends NonBookableSpacesEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SendBookableSpacesToApi extends NonBookableSpacesEvent {}
|
class SendBookableSpacesToApi extends NonBookableSpacesEvent {}
|
||||||
|
|
||||||
|
class CheckConfigurValidityEvent extends NonBookableSpacesEvent {}
|
||||||
|
@ -9,7 +9,12 @@ sealed class NonBookableSpacesState extends Equatable {
|
|||||||
|
|
||||||
final class NonBookableSpacesInitial extends NonBookableSpacesState {}
|
final class NonBookableSpacesInitial extends NonBookableSpacesState {}
|
||||||
|
|
||||||
class NonBookableSpacesLoading extends NonBookableSpacesState {}
|
class NonBookableSpacesLoading extends NonBookableSpacesState {
|
||||||
|
final PaginatedDataModel<BookableSpacemodel>? lastNonBookableSpaces;
|
||||||
|
const NonBookableSpacesLoading({
|
||||||
|
this.lastNonBookableSpaces,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
class NonBookableSpacesLoaded extends NonBookableSpacesState {
|
class NonBookableSpacesLoaded extends NonBookableSpacesState {
|
||||||
final PaginatedDataModel<BookableSpacemodel> nonBookableSpaces;
|
final PaginatedDataModel<BookableSpacemodel> nonBookableSpaces;
|
||||||
@ -24,3 +29,11 @@ class NonBookableSpacesError extends NonBookableSpacesState {
|
|||||||
final String error;
|
final String error;
|
||||||
const NonBookableSpacesError(this.error);
|
const NonBookableSpacesError(this.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddNonBookableSpaceIntoBookableState extends NonBookableSpacesState {}
|
||||||
|
|
||||||
|
class RemoveBookableSpaceIntoNonBookableState extends NonBookableSpacesState {}
|
||||||
|
|
||||||
|
class ValidSaveButtonState extends NonBookableSpacesState {}
|
||||||
|
|
||||||
|
class UnValidSaveButtonState extends NonBookableSpacesState {}
|
||||||
|
@ -3,13 +3,15 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/booking_system/view/widgets/icon_text_button.dart';
|
import 'package:syncrow_web/pages/access_management/booking_system/view/widgets/icon_text_button.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/data/dummy_bookable_spaces_service.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/data/remote_bookable_spaces_service.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/bookable_spaces_params.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/bookable_spaces_params.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/bookable_spaces_bloc/bookable_spaces_bloc.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/bookable_spaces_bloc/bookable_spaces_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/screens/setup_bookable_spaces_dialog.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/screens/setup_bookable_spaces_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/custom_data_table.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/custom_data_table.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||||
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
import 'package:syncrow_web/utils/theme/responsive_text_theme.dart';
|
||||||
@ -64,8 +66,7 @@ class _ManageBookableSpacesPageState extends State<ManageBookableSpacesPage> {
|
|||||||
rightBody: const NavigateHomeGridView(),
|
rightBody: const NavigateHomeGridView(),
|
||||||
scaffoldBody: BlocProvider(
|
scaffoldBody: BlocProvider(
|
||||||
create: (context) => BookableSpacesBloc(
|
create: (context) => BookableSpacesBloc(
|
||||||
DummyBookableSpacesService(),
|
RemoteBookableSpacesService(HTTPService()),
|
||||||
// RemoteBookableSpacesService(HTTPService()),
|
|
||||||
)..add(LoadBookableSpacesEvent(
|
)..add(LoadBookableSpacesEvent(
|
||||||
BookableSpacesParams(currentPage: 1),
|
BookableSpacesParams(currentPage: 1),
|
||||||
)),
|
)),
|
||||||
@ -90,34 +91,66 @@ class ManageBookableSpacesWidget extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 10,
|
||||||
child: Row(
|
child: Padding(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
padding: const EdgeInsetsGeometry.symmetric(vertical: 5),
|
||||||
children: [
|
child: Row(
|
||||||
SvgTextButton(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
svgAsset: Assets.backButtonIcon,
|
children: [
|
||||||
label: 'Booking Home',
|
SvgTextButton(
|
||||||
|
svgSize: 15,
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
svgAsset: Assets.backButtonIcon,
|
||||||
|
label: 'Booking Home',
|
||||||
|
onPressed: () {
|
||||||
|
context.pop();
|
||||||
|
}),
|
||||||
|
SvgTextButton(
|
||||||
|
svgSize: 15,
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
svgAsset: Assets.addButtonIcon,
|
||||||
|
label: 'Set Up a Bookable Spaces',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pop();
|
final bloc = context.read<BookableSpacesBloc>();
|
||||||
}),
|
showDialog(
|
||||||
SvgTextButton(
|
context: context,
|
||||||
svgAsset: Assets.backButtonIcon,
|
builder: (context) => BlocProvider.value(
|
||||||
label: 'Set Up a Bookable Spaces',
|
value: bloc,
|
||||||
onPressed: () async => showDialog(
|
child: SetupBookableSpacesDialog(),
|
||||||
context: context,
|
),
|
||||||
builder: (context) => SetupBookableSpacesDialog(),
|
);
|
||||||
),
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
),
|
||||||
)),
|
)),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 9,
|
flex: 85,
|
||||||
child: BlocBuilder<BookableSpacesBloc, BookableSpacesState>(
|
child: BlocBuilder<BookableSpacesBloc, BookableSpacesState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is BookableSpacesLoading) {
|
if (state is BookableSpacesLoading) {
|
||||||
return const CircularProgressIndicator();
|
return const Center(child: CircularProgressIndicator());
|
||||||
} else if (state is BookableSpacesError) {
|
} else if (state is BookableSpacesError) {
|
||||||
return Text(state.error);
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(state.error),
|
||||||
|
const SizedBox(
|
||||||
|
height: 5,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => context
|
||||||
|
.read<BookableSpacesBloc>()
|
||||||
|
.add(LoadBookableSpacesEvent(
|
||||||
|
BookableSpacesParams(currentPage: 1),
|
||||||
|
)),
|
||||||
|
child: const Text('try Again'))
|
||||||
|
]);
|
||||||
} else if (state is BookableSpacesLoaded) {
|
} else if (state is BookableSpacesLoaded) {
|
||||||
return CustomDataTable<BookableSpacemodel>(
|
return CustomDataTable<BookableSpacemodel>(
|
||||||
items: state.bookableSpacesList.data,
|
items: state.bookableSpacesList.data,
|
||||||
@ -125,19 +158,26 @@ class ManageBookableSpacesWidget extends StatelessWidget {
|
|||||||
DataCell(
|
DataCell(
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsetsGeometry.only(left: 10),
|
padding: const EdgeInsetsGeometry.only(left: 10),
|
||||||
child: Text(space.spaceName)),
|
child: Text(
|
||||||
|
space.spaceName,
|
||||||
|
style: const TextStyle(fontSize: 11),
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
DataCell(Padding(
|
DataCell(Padding(
|
||||||
padding: const EdgeInsetsGeometry.only(left: 10),
|
padding: const EdgeInsetsGeometry.only(left: 10),
|
||||||
child: Text(space.spaceVirtualAddress))),
|
child: Text(
|
||||||
DataCell(SizedBox(
|
space.spaceVirtualAddress,
|
||||||
|
style: const TextStyle(fontSize: 11),
|
||||||
|
))),
|
||||||
|
DataCell(Container(
|
||||||
|
padding: const EdgeInsetsGeometry.only(left: 10),
|
||||||
width: 200,
|
width: 200,
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
spacing: 4,
|
spacing: 4,
|
||||||
children: space.spaceConfig.bookableDays
|
children: space.spaceConfig!.bookableDays
|
||||||
.map((day) => Text(
|
.map((day) => Text(
|
||||||
day,
|
day,
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 11),
|
||||||
))
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
@ -146,7 +186,9 @@ class ManageBookableSpacesWidget extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsetsGeometry.only(left: 10),
|
padding: const EdgeInsetsGeometry.only(left: 10),
|
||||||
child: Text(
|
child: Text(
|
||||||
space.spaceConfig.bookingStartTime.format(context),
|
space.spaceConfig!.bookingStartTime!
|
||||||
|
.format(context),
|
||||||
|
style: const TextStyle(fontSize: 11),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -154,18 +196,31 @@ class ManageBookableSpacesWidget extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsetsGeometry.only(left: 10),
|
padding: const EdgeInsetsGeometry.only(left: 10),
|
||||||
child: Text(
|
child: Text(
|
||||||
space.spaceConfig.bookingEndTime.format(context),
|
space.spaceConfig!.bookingEndTime!.format(context),
|
||||||
|
style: const TextStyle(fontSize: 11),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
DataCell(Padding(
|
DataCell(Padding(
|
||||||
padding: const EdgeInsetsGeometry.only(left: 10),
|
padding: const EdgeInsetsGeometry.only(left: 10),
|
||||||
child: Text('${space.spaceConfig.cost} Points'))),
|
child: Text(
|
||||||
|
'${space.spaceConfig!.cost} Points',
|
||||||
|
style: const TextStyle(fontSize: 11),
|
||||||
|
))),
|
||||||
DataCell(Center(
|
DataCell(Center(
|
||||||
child: Transform.scale(
|
child: Transform.scale(
|
||||||
scale: 0.7,
|
scale: 0.7,
|
||||||
child: Switch(
|
child: Switch(
|
||||||
value: space.spaceConfig.availability,
|
value: space.spaceConfig!.availability,
|
||||||
|
trackColor: WidgetStateProperty.resolveWith<Color>(
|
||||||
|
(Set<WidgetState> states) {
|
||||||
|
return ColorsManager.blue1;
|
||||||
|
}),
|
||||||
|
inactiveTrackColor: ColorsManager.lightGrayColor,
|
||||||
|
thumbColor: WidgetStateProperty.resolveWith<Color>(
|
||||||
|
(Set<WidgetState> states) {
|
||||||
|
return ColorsManager.whiteColors;
|
||||||
|
}),
|
||||||
onChanged: (value) {},
|
onChanged: (value) {},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -173,13 +228,22 @@ class ManageBookableSpacesWidget extends StatelessWidget {
|
|||||||
DataCell(Center(
|
DataCell(Center(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
child: SvgPicture.asset(Assets.settings),
|
style: ElevatedButton.styleFrom(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
fixedSize: const Size(50, 30),
|
||||||
|
elevation: 1,
|
||||||
|
),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.settings,
|
||||||
|
height: 15,
|
||||||
|
color: ColorsManager.blue1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
],
|
],
|
||||||
columnsTitles: const [
|
columnsTitles: const [
|
||||||
'space',
|
'Space',
|
||||||
'space Virtual Address',
|
'Space Virtual Address',
|
||||||
'Bookable Days',
|
'Bookable Days',
|
||||||
'Booking Start Time',
|
'Booking Start Time',
|
||||||
'Booking End Time',
|
'Booking End Time',
|
||||||
@ -193,9 +257,166 @@ class ManageBookableSpacesWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 5,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 5,
|
||||||
|
child: BlocBuilder<BookableSpacesBloc, BookableSpacesState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state is BookableSpacesLoaded) {
|
||||||
|
final totalPages = state.bookableSpacesList.totalPages;
|
||||||
|
final currentPage = state.bookableSpacesList.page;
|
||||||
|
|
||||||
|
List<Widget> paginationItems = [];
|
||||||
|
|
||||||
|
// « Two pages back
|
||||||
|
if (currentPage > 2) {
|
||||||
|
paginationItems.add(
|
||||||
|
_buildArrowButton(
|
||||||
|
label: '«',
|
||||||
|
onTap: () {
|
||||||
|
context.read<BookableSpacesBloc>().add(
|
||||||
|
LoadBookableSpacesEvent(
|
||||||
|
BookableSpacesParams(
|
||||||
|
currentPage: currentPage - 2),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// < One page back
|
||||||
|
if (currentPage > 1) {
|
||||||
|
paginationItems.add(
|
||||||
|
_buildArrowButton(
|
||||||
|
label: '<',
|
||||||
|
onTap: () {
|
||||||
|
context.read<BookableSpacesBloc>().add(
|
||||||
|
LoadBookableSpacesEvent(
|
||||||
|
BookableSpacesParams(
|
||||||
|
currentPage: currentPage - 1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page numbers
|
||||||
|
for (int i = 1; i <= totalPages; i++) {
|
||||||
|
paginationItems.add(
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if (i != currentPage) {
|
||||||
|
context.read<BookableSpacesBloc>().add(
|
||||||
|
LoadBookableSpacesEvent(
|
||||||
|
BookableSpacesParams(currentPage: i),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: i == currentPage
|
||||||
|
? ColorsManager.dialogBlueTitle
|
||||||
|
: Colors.grey[300],
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'$i',
|
||||||
|
style: TextStyle(
|
||||||
|
color: i == currentPage
|
||||||
|
? Colors.white
|
||||||
|
: Colors.black,
|
||||||
|
fontWeight: i == currentPage
|
||||||
|
? FontWeight.bold
|
||||||
|
: FontWeight.normal,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// > One page forward
|
||||||
|
if (currentPage < totalPages) {
|
||||||
|
paginationItems.add(
|
||||||
|
_buildArrowButton(
|
||||||
|
label: '>',
|
||||||
|
onTap: () {
|
||||||
|
context.read<BookableSpacesBloc>().add(
|
||||||
|
LoadBookableSpacesEvent(
|
||||||
|
BookableSpacesParams(
|
||||||
|
currentPage: currentPage + 1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// » Two pages forward
|
||||||
|
if (currentPage + 1 < totalPages) {
|
||||||
|
paginationItems.add(
|
||||||
|
_buildArrowButton(
|
||||||
|
label: '»',
|
||||||
|
onTap: () {
|
||||||
|
context.read<BookableSpacesBloc>().add(
|
||||||
|
LoadBookableSpacesEvent(
|
||||||
|
BookableSpacesParams(
|
||||||
|
currentPage: currentPage + 2),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: paginationItems,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildArrowButton(
|
||||||
|
{required String label, required VoidCallback onTap}) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[300],
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/data/remote_non_bookable_spaces.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/data/dummy_non_nookable_spaces.dart';
|
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/non_bookable_spaces_params.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/non_bookable_spaces_params.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/non_bookable_spaces_bloc/non_bookaable_spaces_bloc.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/non_bookable_spaces_bloc/non_bookaable_spaces_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/steps_cubit/cubit/steps_cubit.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/steps_cubit/cubit/steps_cubit.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/buttons_divider_bottom_dialog_widget.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/details_steps_widget.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/space_step_part_widget.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/next_first_step_button.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/step_two_details_widget.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/save_second_step_button.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/stepper_part_widget.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/stepper_part_widget.dart';
|
||||||
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class SetupBookableSpacesDialog extends StatelessWidget {
|
class SetupBookableSpacesDialog extends StatelessWidget {
|
||||||
@ -23,7 +23,7 @@ class SetupBookableSpacesDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
BlocProvider<NonBookableSpacesBloc>(
|
BlocProvider<NonBookableSpacesBloc>(
|
||||||
create: (context) => NonBookableSpacesBloc(
|
create: (context) => NonBookableSpacesBloc(
|
||||||
DummyNonNookableSpaces(),
|
RemoteNonBookableSpaces(HTTPService()),
|
||||||
)..add(
|
)..add(
|
||||||
LoadUnBookableSpacesEvent(
|
LoadUnBookableSpacesEvent(
|
||||||
nonBookableSpacesParams:
|
nonBookableSpacesParams:
|
||||||
@ -33,13 +33,16 @@ class SetupBookableSpacesDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: AlertDialog(
|
child: AlertDialog(
|
||||||
|
backgroundColor: ColorsManager.whiteColors,
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
title: Text(
|
title: Center(
|
||||||
'Set Up a Bookable Spaces',
|
child: Text(
|
||||||
style: TextStyle(
|
'Set Up a Bookable Spaces',
|
||||||
fontWeight: FontWeight.w700,
|
style: TextStyle(
|
||||||
color: ColorsManager.dialogBlueTitle,
|
fontWeight: FontWeight.w700,
|
||||||
fontSize: 15,
|
color: ColorsManager.dialogBlueTitle,
|
||||||
|
fontSize: 15,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
content: Column(
|
content: Column(
|
||||||
@ -69,46 +72,14 @@ class SetupBookableSpacesDialog extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
Builder(builder: (context) {
|
Builder(builder: (context) {
|
||||||
return ButtonsDividerBottomDialogWidget(
|
final stepsState = context.watch<StepsCubit>().state;
|
||||||
onNextPressed: () {
|
final nonBookableBloc = context.watch<NonBookableSpacesBloc>();
|
||||||
final stepsState = context.read<StepsCubit>().state;
|
final selectedSpaces = nonBookableBloc.selectedBookableSpaces;
|
||||||
final selectedSpaces = context
|
return stepsState is StepOneState
|
||||||
.read<NonBookableSpacesBloc>()
|
? NextFirstStepButton(selectedSpaces: selectedSpaces)
|
||||||
.selectedBookableSpaces;
|
: SaveSecondStepButton(
|
||||||
if (stepsState is StepOneState) {
|
selectedSpaces: selectedSpaces,
|
||||||
if (selectedSpaces.isNotEmpty) {
|
pointsController: pointsController);
|
||||||
context.read<StepsCubit>().goToNextStep();
|
|
||||||
} else {
|
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('Please select at least one space.'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (stepsState is StepTwoState) {
|
|
||||||
selectedSpaces.forEach(
|
|
||||||
(e) => e.spaceConfig.cost = int.parse(
|
|
||||||
pointsController.text.isEmpty
|
|
||||||
? '0'
|
|
||||||
: pointsController.text),
|
|
||||||
);
|
|
||||||
if (selectedSpaces.any(
|
|
||||||
(element) => !element.isValid,
|
|
||||||
)) {
|
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('Please fill the required fields.'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
print(selectedSpaces.first.spaceUuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onCancelPressed: () => context.pop(),
|
|
||||||
);
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -116,31 +87,3 @@ class SetupBookableSpacesDialog extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DetailsStepsWidget extends StatelessWidget {
|
|
||||||
final TextEditingController pointsController;
|
|
||||||
const DetailsStepsWidget({
|
|
||||||
super.key,
|
|
||||||
required this.pointsController,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 20),
|
|
||||||
child: BlocBuilder<StepsCubit, StepsState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
if (state is StepOneState) {
|
|
||||||
return SpacesStepDetailsWidget();
|
|
||||||
} else if (state is StepTwoState) {
|
|
||||||
return StepTwoDetailsWidget(
|
|
||||||
pointsController: pointsController,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/bookable_spaces_params.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/bookable_spaces_bloc/bookable_spaces_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/non_bookable_spaces_bloc/non_bookaable_spaces_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/steps_cubit/cubit/steps_cubit.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/steps_cubit/cubit/steps_cubit.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class ButtonsDividerBottomDialogWidget extends StatelessWidget {
|
class ButtonsDividerBottomDialogWidget extends StatelessWidget {
|
||||||
final void Function() onNextPressed;
|
final String title;
|
||||||
|
final void Function()? onNextPressed;
|
||||||
final void Function() onCancelPressed;
|
final void Function() onCancelPressed;
|
||||||
const ButtonsDividerBottomDialogWidget({
|
const ButtonsDividerBottomDialogWidget({
|
||||||
super.key,
|
super.key,
|
||||||
|
required this.title,
|
||||||
required this.onNextPressed,
|
required this.onNextPressed,
|
||||||
required this.onCancelPressed,
|
required this.onCancelPressed,
|
||||||
});
|
});
|
||||||
@ -43,38 +49,51 @@ class ButtonsDividerBottomDialogWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'Cancel',
|
'Cancel',
|
||||||
style: TextStyle(color: ColorsManager.grayBorder),
|
style: TextStyle(color: ColorsManager.blackColor),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: BlocBuilder<StepsCubit, StepsState>(
|
child:
|
||||||
builder: (context, state) {
|
BlocConsumer<NonBookableSpacesBloc, NonBookableSpacesState>(
|
||||||
return InkWell(
|
listener: (context, nonBookableState) {
|
||||||
borderRadius: const BorderRadius.only(
|
if (nonBookableState is NonBookableSpacesInitial) {
|
||||||
bottomRight: Radius.circular(26),
|
context.pop();
|
||||||
),
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
onTap: onNextPressed,
|
const SnackBar(
|
||||||
child: Container(
|
content: Text(
|
||||||
height: 40,
|
'Spaces Added Successfully',
|
||||||
alignment: Alignment.center,
|
style: TextStyle(color: ColorsManager.activeGreen),
|
||||||
decoration: const BoxDecoration(
|
),
|
||||||
border: Border(
|
duration: Duration(seconds: 2),
|
||||||
right: BorderSide(
|
behavior: SnackBarBehavior.floating,
|
||||||
color: ColorsManager.grayBorder,
|
),
|
||||||
|
);
|
||||||
|
context.read<BookableSpacesBloc>().add(
|
||||||
|
LoadBookableSpacesEvent(
|
||||||
|
BookableSpacesParams(currentPage: 1),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
} else if (nonBookableState is NonBookableSpacesError) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
nonBookableState.error,
|
||||||
|
style:
|
||||||
|
const TextStyle(color: ColorsManager.activeGreen),
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.only(
|
duration: const Duration(seconds: 2),
|
||||||
bottomRight: Radius.circular(26),
|
behavior: SnackBarBehavior.floating,
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
state is StepOneState ? 'Next' : 'Save',
|
|
||||||
style: const TextStyle(
|
|
||||||
color: ColorsManager.blueColor,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
builder: (context, nonBookableState) {
|
||||||
|
return TextButton(
|
||||||
|
onPressed: onNextPressed,
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -31,7 +31,10 @@ class ColumnTitleWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
title,
|
title,
|
||||||
style: const TextStyle(color: ColorsManager.grayColor),
|
style: const TextStyle(
|
||||||
|
color: ColorsManager.grayColor,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/steps_cubit/cubit/steps_cubit.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/space_step_part_widget.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/step_two_details_widget.dart';
|
||||||
|
|
||||||
|
class DetailsStepsWidget extends StatelessWidget {
|
||||||
|
final TextEditingController pointsController;
|
||||||
|
const DetailsStepsWidget({
|
||||||
|
super.key,
|
||||||
|
required this.pointsController,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 20),
|
||||||
|
child: BlocBuilder<StepsCubit, StepsState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
if (state is StepOneState) {
|
||||||
|
return const SpacesStepDetailsWidget();
|
||||||
|
} else if (state is StepTwoState) {
|
||||||
|
return StepTwoDetailsWidget(
|
||||||
|
pointsController: pointsController,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/steps_cubit/cubit/steps_cubit.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/buttons_divider_bottom_dialog_widget.dart';
|
||||||
|
|
||||||
|
class NextFirstStepButton extends StatelessWidget {
|
||||||
|
final List<BookableSpacemodel> selectedSpaces;
|
||||||
|
|
||||||
|
const NextFirstStepButton({
|
||||||
|
super.key,
|
||||||
|
required this.selectedSpaces,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ButtonsDividerBottomDialogWidget(
|
||||||
|
title: 'Next',
|
||||||
|
onNextPressed: selectedSpaces.isEmpty
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
context.read<StepsCubit>().goToNextStep();
|
||||||
|
},
|
||||||
|
onCancelPressed: () => context.pop(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/models/bookable_space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/non_bookable_spaces_bloc/non_bookaable_spaces_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/buttons_divider_bottom_dialog_widget.dart';
|
||||||
|
|
||||||
|
class SaveSecondStepButton extends StatelessWidget {
|
||||||
|
final List<BookableSpacemodel> selectedSpaces;
|
||||||
|
final TextEditingController pointsController;
|
||||||
|
|
||||||
|
const SaveSecondStepButton({
|
||||||
|
super.key,
|
||||||
|
required this.selectedSpaces,
|
||||||
|
required this.pointsController,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<NonBookableSpacesBloc, NonBookableSpacesState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return ButtonsDividerBottomDialogWidget(
|
||||||
|
title: 'Save',
|
||||||
|
onNextPressed: state is UnValidSaveButtonState
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
if (selectedSpaces.any(
|
||||||
|
(element) => element.isValid,
|
||||||
|
)) {
|
||||||
|
context.read<NonBookableSpacesBloc>().add(
|
||||||
|
SendBookableSpacesToApi(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCancelPressed: () => context.pop(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,7 @@ class SearchUnbookableSpacesWidget extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
width: width ?? 480,
|
width: width ?? 480,
|
||||||
height: height ?? 30,
|
height: height ?? 30,
|
||||||
|
padding: const EdgeInsets.only(top: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
@ -6,114 +6,221 @@ import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domai
|
|||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/non_bookable_spaces_params.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/domain/params/non_bookable_spaces_params.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/non_bookable_spaces_bloc/non_bookaable_spaces_bloc.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/non_bookable_spaces_bloc/non_bookaable_spaces_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/search_unbookable_spaces_widget.dart';
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/widgets/search_unbookable_spaces_widget.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/main_module/shared/models/paginated_data_model.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class SpacesStepDetailsWidget extends StatelessWidget {
|
class SpacesStepDetailsWidget extends StatefulWidget {
|
||||||
SpacesStepDetailsWidget({
|
const SpacesStepDetailsWidget({
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SpacesStepDetailsWidget> createState() =>
|
||||||
|
_SpacesStepDetailsWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SpacesStepDetailsWidgetState extends State<SpacesStepDetailsWidget> {
|
||||||
Timer? _debounce;
|
Timer? _debounce;
|
||||||
|
ScrollController scrollController = ScrollController();
|
||||||
|
int currentPage = 1;
|
||||||
|
String? currentSearchTerm;
|
||||||
|
bool isLoadingMore = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
scrollController.addListener(() {
|
||||||
|
if (scrollController.position.pixels >=
|
||||||
|
scrollController.position.maxScrollExtent - 100) {
|
||||||
|
final state = context.read<NonBookableSpacesBloc>().state;
|
||||||
|
if (state is NonBookableSpacesLoaded &&
|
||||||
|
state.nonBookableSpaces.hasNext &&
|
||||||
|
!isLoadingMore) {
|
||||||
|
isLoadingMore = true;
|
||||||
|
currentPage++;
|
||||||
|
context.read<NonBookableSpacesBloc>().add(
|
||||||
|
LoadUnBookableSpacesEvent(
|
||||||
|
nonBookableSpacesParams: NonBookableSpacesParams(
|
||||||
|
currentPage: currentPage,
|
||||||
|
searchedWords: currentSearchTerm,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<NonBookableSpacesBloc, NonBookableSpacesState>(
|
return Column(
|
||||||
builder: (context, state) {
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
if (state is NonBookableSpacesLoading) {
|
children: [
|
||||||
return const Center(child: CircularProgressIndicator());
|
const Text(
|
||||||
} else if (state is NonBookableSpacesError) {
|
'Select Space',
|
||||||
return Text(state.error);
|
style: TextStyle(
|
||||||
} else if (state is NonBookableSpacesLoaded) {
|
fontWeight: FontWeight.w700,
|
||||||
return Column(
|
color: ColorsManager.blackColor,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 450,
|
||||||
|
height: 480,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color(0x40000000),
|
||||||
|
offset: Offset.zero,
|
||||||
|
blurRadius: 5,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
|
||||||
'Select Space',
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
color: ColorsManager.blackColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 20,
|
|
||||||
),
|
|
||||||
Container(
|
Container(
|
||||||
width: 450,
|
width: 520,
|
||||||
height: 480,
|
height: 70,
|
||||||
decoration: BoxDecoration(
|
padding:
|
||||||
color: Colors.white,
|
const EdgeInsets.symmetric(vertical: 15, horizontal: 20),
|
||||||
borderRadius: BorderRadius.circular(20),
|
decoration: const BoxDecoration(
|
||||||
boxShadow: const [
|
color: Color(0xFFF8F8F8),
|
||||||
BoxShadow(
|
borderRadius: BorderRadius.vertical(
|
||||||
color: Color(0x40000000),
|
top: Radius.circular(20),
|
||||||
offset: Offset(0, 4),
|
),
|
||||||
blurRadius: 5,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
child: Column(
|
child: SearchUnbookableSpacesWidget(
|
||||||
children: [
|
title: 'Search',
|
||||||
Container(
|
onChanged: (p0) {
|
||||||
width: 520,
|
if (_debounce?.isActive ?? false) _debounce!.cancel();
|
||||||
height: 70,
|
_debounce = Timer(const Duration(milliseconds: 500), () {
|
||||||
padding: const EdgeInsets.symmetric(
|
currentSearchTerm = p0;
|
||||||
vertical: 15, horizontal: 20),
|
currentPage = 1;
|
||||||
decoration: const BoxDecoration(
|
context.read<NonBookableSpacesBloc>().add(
|
||||||
color: Color(0xFFF8F8F8),
|
LoadUnBookableSpacesEvent(
|
||||||
borderRadius: BorderRadius.vertical(
|
nonBookableSpacesParams: NonBookableSpacesParams(
|
||||||
top: Radius.circular(20),
|
currentPage: currentPage,
|
||||||
),
|
searchedWords: currentSearchTerm,
|
||||||
),
|
),
|
||||||
child: SearchUnbookableSpacesWidget(
|
),
|
||||||
title: 'Search',
|
);
|
||||||
onChanged: (p0) {
|
});
|
||||||
if (_debounce?.isActive ?? false) _debounce!.cancel();
|
},
|
||||||
_debounce =
|
),
|
||||||
Timer(const Duration(milliseconds: 500), () {
|
),
|
||||||
context.read<NonBookableSpacesBloc>().add(
|
Expanded(
|
||||||
LoadUnBookableSpacesEvent(
|
child:
|
||||||
nonBookableSpacesParams:
|
BlocConsumer<NonBookableSpacesBloc, NonBookableSpacesState>(
|
||||||
NonBookableSpacesParams(
|
listener: (context, state) {
|
||||||
currentPage: 1,
|
if (state is NonBookableSpacesLoaded) {
|
||||||
searchedWords: p0,
|
isLoadingMore = false;
|
||||||
),
|
}
|
||||||
),
|
},
|
||||||
);
|
builder: (context, state) {
|
||||||
});
|
if (state is NonBookableSpacesError) {
|
||||||
},
|
return Column(
|
||||||
),
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
),
|
children: [
|
||||||
Expanded(
|
Text(state.error),
|
||||||
child: Container(
|
const SizedBox(
|
||||||
width: 490,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.vertical(
|
|
||||||
bottom: Radius.circular(20),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.only(top: 10, left: 20, bottom: 5),
|
|
||||||
child: ListView.separated(
|
|
||||||
separatorBuilder: (context, index) => const SizedBox(
|
|
||||||
height: 5,
|
height: 5,
|
||||||
),
|
),
|
||||||
itemCount: state.nonBookableSpaces.data.length,
|
ElevatedButton(
|
||||||
itemBuilder: (context, index) => CheckBoxSpaceWidget(
|
onPressed: () {
|
||||||
nonBookableSpace:
|
context.read<NonBookableSpacesBloc>().add(
|
||||||
state.nonBookableSpaces.data[index],
|
LoadUnBookableSpacesEvent(
|
||||||
),
|
nonBookableSpacesParams:
|
||||||
),
|
NonBookableSpacesParams(
|
||||||
),
|
currentPage: currentPage,
|
||||||
)
|
searchedWords: currentSearchTerm,
|
||||||
],
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: const Text('Try Again'))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else if (state is NonBookableSpacesLoading) {
|
||||||
|
if (state.lastNonBookableSpaces == null) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return UnbookableListWidget(
|
||||||
|
scrollController: scrollController,
|
||||||
|
nonBookableSpaces: state.lastNonBookableSpaces!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (state is NonBookableSpacesLoaded) {
|
||||||
|
return UnbookableListWidget(
|
||||||
|
scrollController: scrollController,
|
||||||
|
nonBookableSpaces: state.nonBookableSpaces,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
),
|
||||||
} else {
|
)
|
||||||
return const SizedBox();
|
],
|
||||||
}
|
);
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnbookableListWidget extends StatelessWidget {
|
||||||
|
final PaginatedDataModel<BookableSpacemodel> nonBookableSpaces;
|
||||||
|
const UnbookableListWidget({
|
||||||
|
super.key,
|
||||||
|
required this.scrollController,
|
||||||
|
required this.nonBookableSpaces,
|
||||||
|
});
|
||||||
|
|
||||||
|
final ScrollController scrollController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: 490,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.vertical(
|
||||||
|
bottom: Radius.circular(20),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.only(top: 10, left: 20, bottom: 5),
|
||||||
|
child: ListView.separated(
|
||||||
|
separatorBuilder: (context, index) => const SizedBox(
|
||||||
|
height: 5,
|
||||||
|
),
|
||||||
|
controller: scrollController,
|
||||||
|
itemCount: nonBookableSpaces.data.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index < nonBookableSpaces.data.length) {
|
||||||
|
return CheckBoxSpaceWidget(
|
||||||
|
nonBookableSpace: nonBookableSpaces.data[index],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 10),
|
||||||
|
child: Center(child: CircularProgressIndicator()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,7 +266,7 @@ class _CheckBoxSpaceWidgetState extends State<CheckBoxSpaceWidget> {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 5,
|
width: 5,
|
||||||
),
|
),
|
||||||
Text(widget.nonBookableSpace.spaceName),
|
Expanded(child: Text(widget.nonBookableSpace.spaceName)),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,10 @@ class StepTwoDetailsWidget extends StatelessWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final nonBookableBloc = context.read<NonBookableSpacesBloc>();
|
final nonBookableBloc = context.read<NonBookableSpacesBloc>();
|
||||||
if (isEndTimeAfterStartTime(
|
|
||||||
timePicked, nonBookableBloc.endTime)) {
|
if (nonBookableBloc.endTime != null &&
|
||||||
|
isEndTimeAfterStartTime(
|
||||||
|
timePicked, nonBookableBloc.endTime!)) {
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
ScaffoldMessenger.of(context).clearSnackBars();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
content:
|
content:
|
||||||
@ -47,7 +49,7 @@ class StepTwoDetailsWidget extends StatelessWidget {
|
|||||||
throw Exception();
|
throw Exception();
|
||||||
} else {
|
} else {
|
||||||
nonBookableBloc.selectedBookableSpaces.forEach(
|
nonBookableBloc.selectedBookableSpaces.forEach(
|
||||||
(e) => e.spaceConfig.bookingStartTime = timePicked,
|
(e) => e.spaceConfig!.bookingStartTime = timePicked,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -62,8 +64,9 @@ class StepTwoDetailsWidget extends StatelessWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final nonBookableBloc = context.read<NonBookableSpacesBloc>();
|
final nonBookableBloc = context.read<NonBookableSpacesBloc>();
|
||||||
if (isEndTimeAfterStartTime(
|
if (nonBookableBloc.startTime != null &&
|
||||||
nonBookableBloc.startTime, timePicked)) {
|
isEndTimeAfterStartTime(
|
||||||
|
nonBookableBloc.startTime!, timePicked)) {
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
ScaffoldMessenger.of(context).clearSnackBars();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
content:
|
content:
|
||||||
@ -74,7 +77,7 @@ class StepTwoDetailsWidget extends StatelessWidget {
|
|||||||
throw Exception();
|
throw Exception();
|
||||||
} else {
|
} else {
|
||||||
nonBookableBloc.selectedBookableSpaces.forEach(
|
nonBookableBloc.selectedBookableSpaces.forEach(
|
||||||
(e) => e.spaceConfig.bookingEndTime = timePicked,
|
(e) => e.spaceConfig!.bookingEndTime = timePicked,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -102,6 +105,22 @@ class StepTwoDetailsWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
SearchUnbookableSpacesWidget(
|
SearchUnbookableSpacesWidget(
|
||||||
title: 'Ex: 0',
|
title: 'Ex: 0',
|
||||||
|
height: 40,
|
||||||
|
onChanged: (p0) {
|
||||||
|
context
|
||||||
|
.read<NonBookableSpacesBloc>()
|
||||||
|
.selectedBookableSpaces
|
||||||
|
.forEach(
|
||||||
|
(e) => e.spaceConfig!.cost = int.parse(
|
||||||
|
pointsController.text.isEmpty
|
||||||
|
? '0'
|
||||||
|
: pointsController.text,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
context
|
||||||
|
.read<NonBookableSpacesBloc>()
|
||||||
|
.add(CheckConfigurValidityEvent());
|
||||||
|
},
|
||||||
controller: pointsController,
|
controller: pointsController,
|
||||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||||
suffix: const SizedBox(),
|
suffix: const SizedBox(),
|
||||||
|
@ -24,6 +24,7 @@ class StepperPartWidget extends StatelessWidget {
|
|||||||
title: 'Space',
|
title: 'Space',
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
|
padding: const EdgeInsets.only(left: 3),
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
height: 50,
|
height: 50,
|
||||||
child: const VerticalDivider(
|
child: const VerticalDivider(
|
||||||
@ -32,7 +33,8 @@ class StepperPartWidget extends StatelessWidget {
|
|||||||
const CircleTitleStepperWidget(
|
const CircleTitleStepperWidget(
|
||||||
title: 'Settings',
|
title: 'Settings',
|
||||||
titleColor: ColorsManager.softGray,
|
titleColor: ColorsManager.softGray,
|
||||||
circleColor: ColorsManager.softGray,
|
circleColor: ColorsManager.whiteColors,
|
||||||
|
borderColor: ColorsManager.textGray,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -51,9 +53,11 @@ class StepperPartWidget extends StatelessWidget {
|
|||||||
size: 12,
|
size: 12,
|
||||||
),
|
),
|
||||||
circleColor: ColorsManager.trueIconGreen,
|
circleColor: ColorsManager.trueIconGreen,
|
||||||
radius: 3,
|
radius: 15,
|
||||||
|
borderColor: ColorsManager.trueIconGreen,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
|
padding: const EdgeInsets.only(left: 3),
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
height: 50,
|
height: 50,
|
||||||
child: const VerticalDivider(
|
child: const VerticalDivider(
|
||||||
@ -81,12 +85,14 @@ class CircleTitleStepperWidget extends StatelessWidget {
|
|||||||
final double? radius;
|
final double? radius;
|
||||||
final Widget? cicleIcon;
|
final Widget? cicleIcon;
|
||||||
final Color? circleColor;
|
final Color? circleColor;
|
||||||
|
final Color? borderColor;
|
||||||
final Color? titleColor;
|
final Color? titleColor;
|
||||||
final String title;
|
final String title;
|
||||||
const CircleTitleStepperWidget({
|
const CircleTitleStepperWidget({
|
||||||
super.key,
|
super.key,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.circleColor,
|
this.circleColor,
|
||||||
|
this.borderColor,
|
||||||
this.cicleIcon,
|
this.cicleIcon,
|
||||||
this.titleColor,
|
this.titleColor,
|
||||||
this.radius,
|
this.radius,
|
||||||
@ -96,9 +102,13 @@ class CircleTitleStepperWidget extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
CircleAvatar(
|
Container(
|
||||||
minRadius: radius ?? 5,
|
width: radius ?? 15,
|
||||||
backgroundColor: circleColor ?? ColorsManager.blue1,
|
height: radius ?? 15,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: circleColor ?? ColorsManager.blue1,
|
||||||
|
border: Border.all(color: borderColor ?? ColorsManager.blue1)),
|
||||||
child: cicleIcon,
|
child: cicleIcon,
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/access_management/manage_bookable_spaces/presentation/blocs/non_bookable_spaces_bloc/non_bookaable_spaces_bloc.dart';
|
||||||
|
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
@ -40,6 +42,7 @@ class _TimePickerWidgetState extends State<TimePickerWidget> {
|
|||||||
);
|
);
|
||||||
widget.onTimePicked(tempTime);
|
widget.onTimePicked(tempTime);
|
||||||
timePicked = tempTime;
|
timePicked = tempTime;
|
||||||
|
context.read<NonBookableSpacesBloc>().add(CheckConfigurValidityEvent());
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -70,9 +73,7 @@ class _TimePickerWidgetState extends State<TimePickerWidget> {
|
|||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
child: Text(
|
child: Text(
|
||||||
timePicked == null
|
timePicked == null ? 'HH:MM' : timePicked!.format(context),
|
||||||
? TimeOfDay.now().format(context)
|
|
||||||
: timePicked!.format(context),
|
|
||||||
style: const TextStyle(color: Color(0xB2D5D5D5)),
|
style: const TextStyle(color: Color(0xB2D5D5D5)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -42,9 +42,13 @@ class _WeekDaysCheckboxRowState extends State<WeekDaysCheckboxRow> {
|
|||||||
for (var space in context
|
for (var space in context
|
||||||
.read<NonBookableSpacesBloc>()
|
.read<NonBookableSpacesBloc>()
|
||||||
.selectedBookableSpaces) {
|
.selectedBookableSpaces) {
|
||||||
space.spaceConfig.bookableDays = selectedDays;
|
space.spaceConfig!.bookableDays = selectedDays;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
context
|
||||||
|
.read<NonBookableSpacesBloc>()
|
||||||
|
.add(CheckConfigurValidityEvent());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -141,5 +141,5 @@ abstract class ApiEndpoints {
|
|||||||
static const String saveSchedule = '/schedule/{deviceUuid}';
|
static const String saveSchedule = '/schedule/{deviceUuid}';
|
||||||
|
|
||||||
////booking System
|
////booking System
|
||||||
static const String addBookableSpaces = '/bookable-spaces';
|
static const String bookableSpaces = '/bookable-spaces';
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user