mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
made communities paginatable.
This commit is contained in:
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.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/pages/space_management_v2/main_module/widgets/space_management_body.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/space_management_body.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/communities_pagination_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/services/communities_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/services/communities_service.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
|
||||||
@ -46,37 +46,20 @@ class SpaceManagementPage extends StatelessWidget {
|
|||||||
|
|
||||||
class _FakeCommunitiesService extends CommunitiesService {
|
class _FakeCommunitiesService extends CommunitiesService {
|
||||||
@override
|
@override
|
||||||
Future<List<CommunityModel>> getCommunity(LoadCommunitiesParam param) async {
|
Future<CommunitiesPaginationModel> getCommunity(LoadCommunitiesParam param) {
|
||||||
return Future.delayed(
|
return Future.value(const CommunitiesPaginationModel(
|
||||||
const Duration(seconds: 1),
|
communities: [
|
||||||
() => [
|
CommunityModel(
|
||||||
const CommunityModel(
|
|
||||||
uuid: '1',
|
uuid: '1',
|
||||||
name: 'Community 1',
|
name: 'Community 1',
|
||||||
spaces: [
|
|
||||||
SpaceModel(
|
|
||||||
uuid: '3',
|
|
||||||
spaceName: 'Space 1',
|
|
||||||
icon: 'assets/icons/space.png',
|
|
||||||
children: [
|
|
||||||
SpaceModel(
|
|
||||||
uuid: '4',
|
|
||||||
spaceName: 'Space 2',
|
|
||||||
icon: 'assets/icons/space.png',
|
|
||||||
children: [],
|
|
||||||
status: SpaceStatus.active,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
status: SpaceStatus.active,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const CommunityModel(
|
|
||||||
uuid: '2',
|
|
||||||
name: 'Community 1',
|
|
||||||
spaces: [],
|
spaces: [],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
page: 1,
|
||||||
|
size: 10,
|
||||||
|
hasNext: false,
|
||||||
|
totalItems: 2,
|
||||||
|
totalPages: 1,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/communities_pagination_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/services/communities_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/services/communities_service.dart';
|
||||||
import 'package:syncrow_web/services/api/api_exception.dart';
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
@ -15,28 +15,25 @@ class RemoteCommunitiesService implements CommunitiesService {
|
|||||||
static const _defaultErrorMessage = 'Failed to load communities';
|
static const _defaultErrorMessage = 'Failed to load communities';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<CommunityModel>> getCommunity(LoadCommunitiesParam param) async {
|
Future<CommunitiesPaginationModel> getCommunity(LoadCommunitiesParam param) async {
|
||||||
final projectUuid = await ProjectManager.getProjectUUID();
|
final projectUuid = await ProjectManager.getProjectUUID();
|
||||||
if (projectUuid == null) throw APIException('Project UUID is not set');
|
if (projectUuid == null) throw APIException('Project UUID is not set');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final allCommunities = <CommunityModel>[];
|
final response = await _httpService.get(
|
||||||
await _httpService.get(
|
|
||||||
path: await _makeUrl(),
|
path: await _makeUrl(),
|
||||||
|
queryParameters: {
|
||||||
|
'page': param.page,
|
||||||
|
'size': param.size,
|
||||||
|
'includeSpaces': param.includeSpaces,
|
||||||
|
if (param.search.isNotEmpty) 'search': param.search,
|
||||||
|
},
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
final response = json as Map<String, dynamic>;
|
return CommunitiesPaginationModel.fromJson(json as Map<String, dynamic>);
|
||||||
final jsonData = response['data'] as List<dynamic>? ?? [];
|
|
||||||
return jsonData
|
|
||||||
.map(
|
|
||||||
(jsonItem) => CommunityModel.fromJson(
|
|
||||||
jsonItem as Map<String, dynamic>,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList();
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return allCommunities;
|
return response;
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
final message = e.response?.data as Map<String, dynamic>?;
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
final error = message?['error'] as Map<String, dynamic>?;
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
||||||
|
|
||||||
|
class CommunitiesPaginationModel extends Equatable {
|
||||||
|
const CommunitiesPaginationModel({
|
||||||
|
required this.communities,
|
||||||
|
required this.page,
|
||||||
|
required this.size,
|
||||||
|
required this.hasNext,
|
||||||
|
required this.totalItems,
|
||||||
|
required this.totalPages,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<CommunityModel> communities;
|
||||||
|
final int page;
|
||||||
|
final int size;
|
||||||
|
final bool hasNext;
|
||||||
|
final int totalItems;
|
||||||
|
final int totalPages;
|
||||||
|
|
||||||
|
const CommunitiesPaginationModel.empty()
|
||||||
|
: communities = const [],
|
||||||
|
page = 1,
|
||||||
|
size = 25,
|
||||||
|
hasNext = false,
|
||||||
|
totalItems = 0,
|
||||||
|
totalPages = 0;
|
||||||
|
|
||||||
|
factory CommunitiesPaginationModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return CommunitiesPaginationModel(
|
||||||
|
communities: (json['data'] as List<dynamic>? ?? [])
|
||||||
|
.map((e) => CommunityModel.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
page: json['page'] as int? ?? 1,
|
||||||
|
size: json['size'] as int? ?? 25,
|
||||||
|
hasNext: json['hasNext'] as bool? ?? false,
|
||||||
|
totalItems: json['totalItems'] as int? ?? 0,
|
||||||
|
totalPages: json['totalPages'] as int? ?? 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CommunitiesPaginationModel copyWith({
|
||||||
|
List<CommunityModel>? communities,
|
||||||
|
int? page,
|
||||||
|
int? size,
|
||||||
|
bool? hasNext,
|
||||||
|
int? totalItems,
|
||||||
|
int? totalPages,
|
||||||
|
}) {
|
||||||
|
return CommunitiesPaginationModel(
|
||||||
|
communities: communities ?? this.communities,
|
||||||
|
page: page ?? this.page,
|
||||||
|
size: size ?? this.size,
|
||||||
|
hasNext: hasNext ?? this.hasNext,
|
||||||
|
totalItems: totalItems ?? this.totalItems,
|
||||||
|
totalPages: totalPages ?? this.totalPages,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
communities,
|
||||||
|
page,
|
||||||
|
size,
|
||||||
|
hasNext,
|
||||||
|
totalItems,
|
||||||
|
totalPages,
|
||||||
|
];
|
||||||
|
}
|
@ -1,3 +1,32 @@
|
|||||||
class LoadCommunitiesParam {
|
import 'package:equatable/equatable.dart';
|
||||||
const LoadCommunitiesParam();
|
|
||||||
|
class LoadCommunitiesParam extends Equatable {
|
||||||
|
const LoadCommunitiesParam({
|
||||||
|
this.page = 1,
|
||||||
|
this.size = 25,
|
||||||
|
this.search = '',
|
||||||
|
this.includeSpaces = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
final int page;
|
||||||
|
final int size;
|
||||||
|
final String search;
|
||||||
|
final bool includeSpaces;
|
||||||
|
|
||||||
|
LoadCommunitiesParam copyWith({
|
||||||
|
int? page,
|
||||||
|
int? size,
|
||||||
|
String? search,
|
||||||
|
bool? includeSpaces,
|
||||||
|
}) {
|
||||||
|
return LoadCommunitiesParam(
|
||||||
|
page: page ?? this.page,
|
||||||
|
size: size ?? this.size,
|
||||||
|
search: search ?? this.search,
|
||||||
|
includeSpaces: includeSpaces ?? this.includeSpaces,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [page, size, search, includeSpaces];
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/communities_pagination_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/params/load_communities_param.dart';
|
||||||
|
|
||||||
abstract class CommunitiesService {
|
abstract class CommunitiesService {
|
||||||
Future<List<CommunityModel>> getCommunity(LoadCommunitiesParam param);
|
Future<CommunitiesPaginationModel> getCommunity(LoadCommunitiesParam param);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ class CommunitiesBloc extends Bloc<CommunitiesEvent, CommunitiesState> {
|
|||||||
}) : _communitiesService = communitiesService,
|
}) : _communitiesService = communitiesService,
|
||||||
super(const CommunitiesState()) {
|
super(const CommunitiesState()) {
|
||||||
on<LoadCommunities>(_onLoadCommunities);
|
on<LoadCommunities>(_onLoadCommunities);
|
||||||
|
on<LoadMoreCommunities>(_onLoadMoreCommunities);
|
||||||
|
on<SearchCommunities>(_onSearchCommunities);
|
||||||
}
|
}
|
||||||
|
|
||||||
final CommunitiesService _communitiesService;
|
final CommunitiesService _communitiesService;
|
||||||
@ -23,24 +25,113 @@ class CommunitiesBloc extends Bloc<CommunitiesEvent, CommunitiesState> {
|
|||||||
Emitter<CommunitiesState> emit,
|
Emitter<CommunitiesState> emit,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
emit(const CommunitiesState(status: CommunitiesStatus.loading));
|
emit(state.copyWith(status: CommunitiesStatus.loading));
|
||||||
final communities = await _communitiesService.getCommunity(event.param);
|
|
||||||
|
final paginationResponse = await _communitiesService.getCommunity(event.param);
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
CommunitiesState(
|
CommunitiesState(
|
||||||
status: CommunitiesStatus.success,
|
status: CommunitiesStatus.success,
|
||||||
communities: communities,
|
communities: paginationResponse.communities,
|
||||||
|
hasNext: paginationResponse.hasNext,
|
||||||
|
currentPage: paginationResponse.page,
|
||||||
|
searchQuery: event.param.search,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} on APIException catch (e) {
|
} on APIException catch (e) {
|
||||||
emit(
|
emit(
|
||||||
CommunitiesState(
|
state.copyWith(
|
||||||
status: CommunitiesStatus.failure,
|
status: CommunitiesStatus.failure,
|
||||||
errorMessage: e.message,
|
errorMessage: e.message,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
status: CommunitiesStatus.failure,
|
||||||
|
errorMessage: e.toString(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onLoadMoreCommunities(
|
||||||
|
LoadMoreCommunities event,
|
||||||
|
Emitter<CommunitiesState> emit,
|
||||||
|
) async {
|
||||||
|
if (!state.hasNext || state.isLoadingMore) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
emit(state.copyWith(isLoadingMore: true));
|
||||||
|
|
||||||
|
final param = LoadCommunitiesParam(
|
||||||
|
page: state.currentPage + 1,
|
||||||
|
search: state.searchQuery,
|
||||||
|
);
|
||||||
|
|
||||||
|
final paginationResponse = await _communitiesService.getCommunity(param);
|
||||||
|
|
||||||
|
final updatedCommunities = List<CommunityModel>.from(state.communities)
|
||||||
|
..addAll(paginationResponse.communities);
|
||||||
|
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
communities: updatedCommunities,
|
||||||
|
hasNext: paginationResponse.hasNext,
|
||||||
|
currentPage: paginationResponse.page,
|
||||||
|
isLoadingMore: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} on APIException catch (e) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
isLoadingMore: false,
|
||||||
|
errorMessage: e.message,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
isLoadingMore: false,
|
||||||
|
errorMessage: e.toString(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onSearchCommunities(
|
||||||
|
SearchCommunities event,
|
||||||
|
Emitter<CommunitiesState> emit,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
emit(state.copyWith(status: CommunitiesStatus.loading));
|
||||||
|
|
||||||
|
final param = LoadCommunitiesParam(
|
||||||
|
page: 1,
|
||||||
|
search: event.searchQuery,
|
||||||
|
);
|
||||||
|
|
||||||
|
final paginationResponse = await _communitiesService.getCommunity(param);
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
CommunitiesState(
|
CommunitiesState(
|
||||||
|
status: CommunitiesStatus.success,
|
||||||
|
communities: paginationResponse.communities,
|
||||||
|
hasNext: paginationResponse.hasNext,
|
||||||
|
currentPage: paginationResponse.page,
|
||||||
|
searchQuery: event.searchQuery,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} on APIException catch (e) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
status: CommunitiesStatus.failure,
|
||||||
|
errorMessage: e.message,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
status: CommunitiesStatus.failure,
|
status: CommunitiesStatus.failure,
|
||||||
errorMessage: e.toString(),
|
errorMessage: e.toString(),
|
||||||
),
|
),
|
||||||
|
@ -15,3 +15,19 @@ class LoadCommunities extends CommunitiesEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object?> get props => [param];
|
List<Object?> get props => [param];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LoadMoreCommunities extends CommunitiesEvent {
|
||||||
|
const LoadMoreCommunities();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchCommunities extends CommunitiesEvent {
|
||||||
|
const SearchCommunities(this.searchQuery);
|
||||||
|
|
||||||
|
final String searchQuery;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [searchQuery];
|
||||||
|
}
|
||||||
|
@ -7,12 +7,48 @@ final class CommunitiesState extends Equatable {
|
|||||||
this.status = CommunitiesStatus.initial,
|
this.status = CommunitiesStatus.initial,
|
||||||
this.communities = const [],
|
this.communities = const [],
|
||||||
this.errorMessage,
|
this.errorMessage,
|
||||||
|
this.isLoadingMore = false,
|
||||||
|
this.hasNext = false,
|
||||||
|
this.currentPage = 1,
|
||||||
|
this.searchQuery = '',
|
||||||
});
|
});
|
||||||
|
|
||||||
final CommunitiesStatus status;
|
final CommunitiesStatus status;
|
||||||
final List<CommunityModel> communities;
|
final List<CommunityModel> communities;
|
||||||
final String? errorMessage;
|
final String? errorMessage;
|
||||||
|
final bool isLoadingMore;
|
||||||
|
final bool hasNext;
|
||||||
|
final int currentPage;
|
||||||
|
final String searchQuery;
|
||||||
|
|
||||||
|
CommunitiesState copyWith({
|
||||||
|
CommunitiesStatus? status,
|
||||||
|
List<CommunityModel>? communities,
|
||||||
|
String? errorMessage,
|
||||||
|
bool? isLoadingMore,
|
||||||
|
bool? hasNext,
|
||||||
|
int? currentPage,
|
||||||
|
String? searchQuery,
|
||||||
|
}) {
|
||||||
|
return CommunitiesState(
|
||||||
|
status: status ?? this.status,
|
||||||
|
communities: communities ?? this.communities,
|
||||||
|
errorMessage: errorMessage ?? this.errorMessage,
|
||||||
|
isLoadingMore: isLoadingMore ?? this.isLoadingMore,
|
||||||
|
hasNext: hasNext ?? this.hasNext,
|
||||||
|
currentPage: currentPage ?? this.currentPage,
|
||||||
|
searchQuery: searchQuery ?? this.searchQuery,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [status, communities, errorMessage];
|
List<Object?> get props => [
|
||||||
|
status,
|
||||||
|
communities,
|
||||||
|
errorMessage,
|
||||||
|
isLoadingMore,
|
||||||
|
hasNext,
|
||||||
|
currentPage,
|
||||||
|
searchQuery,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user