added order fetch

This commit is contained in:
komekh 2024-08-08 23:34:30 +05:00
parent bbfbbea52d
commit e8603ffeb9
27 changed files with 508 additions and 45 deletions

View File

@ -2,3 +2,4 @@ export 'bottom_navbar_cubit/bottom_navbar_cubit.dart';
export 'language_bloc/language_bloc.dart';
export 'splash_cubit/splash_cubit.dart';
export 'user_bloc/user_bloc.dart';
export 'order_bloc/order_bloc.dart';

View File

@ -0,0 +1,51 @@
import 'dart:async';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../core/core.dart';
import '../../domain/domain.dart';
part 'order_event.dart';
part 'order_state.dart';
class OrderBloc extends Bloc<OrderEvent, OrderState> {
final GetOrderUseCase _getOrdersUseCase;
OrderBloc(this._getOrdersUseCase)
: super(const OrderInitial(
orders: [],
params: FilterProductParams(),
)) {
on<GetOrders>(_onGetOrders);
}
FutureOr<void> _onGetOrders(
GetOrders event,
Emitter<OrderState> emit,
) async {
try {
emit(OrderLoading(
orders: const [],
params: event.params,
));
final result = await _getOrdersUseCase(event.params);
result.fold(
(failure) => emit(OrderError(
orders: state.orders,
failure: failure,
params: event.params,
)),
(orders) => emit(OrderLoaded(
orders: orders,
params: event.params,
)),
);
} catch (e) {
emit(OrderError(
orders: state.orders,
failure: ExceptionFailure(),
params: event.params,
));
}
}
}

View File

@ -0,0 +1,22 @@
part of 'order_bloc.dart';
sealed class OrderEvent extends Equatable {
const OrderEvent();
@override
List<Object> get props => [];
}
class GetOrders extends OrderEvent {
final FilterProductParams params;
const GetOrders(this.params);
@override
List<Object> get props => [];
}
class GetMoreOrders extends OrderEvent {
const GetMoreOrders();
@override
List<Object> get props => [];
}

View File

@ -0,0 +1,54 @@
part of 'order_bloc.dart';
abstract class OrderState extends Equatable {
final List<OrderEntity> orders;
final FilterProductParams params;
const OrderState({required this.orders, required this.params});
}
class OrderInitial extends OrderState {
const OrderInitial({
required super.orders,
required super.params,
});
@override
List<Object> get props => [];
}
class OrderEmpty extends OrderState {
const OrderEmpty({
required super.orders,
required super.params,
});
@override
List<Object> get props => [];
}
class OrderLoading extends OrderState {
const OrderLoading({
required super.orders,
required super.params,
});
@override
List<Object> get props => [];
}
class OrderLoaded extends OrderState {
const OrderLoaded({
required super.orders,
required super.params,
});
@override
List<Object> get props => [orders];
}
class OrderError extends OrderState {
final Failure failure;
const OrderError({
required super.orders,
required super.params,
required this.failure,
});
@override
List<Object> get props => [];
}

View File

@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import '../../application/application.dart';
import '../../di/di.dart' as di;
import '../../domain/entities/order/filter_params_model.dart';
import '../core.dart';
class MyApp extends StatelessWidget {
@ -23,6 +24,9 @@ class MyApp extends StatelessWidget {
BlocProvider(
create: (context) => di.sl<UserBloc>(), //..add(CheckUser()),
),
BlocProvider(
create: (context) => di.sl<OrderBloc>()..add(const GetOrders(FilterProductParams())),
),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,

View File

@ -0,0 +1,10 @@
import 'package:intl/intl.dart';
class DateUtil {
static String formatDateTimeToDDMMYYYY(DateTime? dateTime) {
if (dateTime == null) {
return '';
}
return DateFormat('dd.MM.yyyy').format(dateTime);
}
}

View File

@ -2,3 +2,4 @@ export 'form_validator.dart';
export 'keyboard.dart';
export 'error_util.dart';
export 'http_override.dart';
export 'date_util.dart';

View File

@ -0,0 +1,36 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../../../core/core.dart';
import '../../../domain/domain.dart';
import '../../data.dart';
abstract class OrderRemoteDataSource {
Future<List<OrderModel>> getOrders(FilterProductParams params, String token);
}
class OrderRemoteDataSourceImpl implements OrderRemoteDataSource {
final http.Client client;
OrderRemoteDataSourceImpl({required this.client});
@override
Future<List<OrderModel>> getOrders(FilterProductParams params, String token) async {
final response = await client.get(
Uri.parse('$baseUrl/Goods'),
headers: {
'Content-Type': 'application/json',
'accept': '*/*',
'Authorization': 'Bearer $token',
},
);
if (response.statusCode == 200) {
List<dynamic> jsonData = json.decode(response.body);
final list = jsonData.map((item) => OrderModel.fromJson(item)).toList();
return list;
} else {
throw ServerException();
}
}
}

View File

@ -1 +1,2 @@
export 'user_remote_data_source.dart';
export 'order_remote_data_source.dart';

View File

@ -1,3 +1,4 @@
export 'language.dart';
export 'user/authentication_response_model.dart';
export 'user/user_model.dart';
export 'order/order_model.dart';

View File

@ -0,0 +1,72 @@
import 'package:cargo/core/core.dart';
import '../../../domain/domain.dart';
class OrderModel extends OrderEntity {
const OrderModel({
required super.oid,
required super.clientId,
required super.cargoId,
required super.state,
required super.no,
required super.name,
required super.shopNo,
required super.volume,
required super.placesCount,
required super.carrier,
required super.from,
required super.to,
required super.departedAt,
required super.arrivedAt,
required super.depth,
required super.width,
required super.height,
});
// Factory method to create an instance of CargoEntity from JSON
factory OrderModel.fromJson(Map<String, dynamic> json) {
DateTime? departedAt = json['DepartedAt'] != null ? DateTime.parse(json['DepartedAt']) : null;
DateTime? arrivedAt = json['ArrivedAt'] != null ? DateTime.parse(json['ArrivedAt']) : null;
return OrderModel(
oid: json['Oid'],
clientId: json['ClientId'],
cargoId: json['CargoId'],
state: json['State'],
no: json['No'],
name: json['Name'],
shopNo: json['ShopNo'],
volume: json['Volume'].toDouble(),
placesCount: json['PlacesCount'],
carrier: json['Carrier'],
from: json['From'],
to: json['To'],
departedAt: DateUtil.formatDateTimeToDDMMYYYY(departedAt),
arrivedAt: DateUtil.formatDateTimeToDDMMYYYY(arrivedAt),
depth: json['Depth'].toDouble(),
width: json['Width'].toDouble(),
height: json['Height'].toDouble(),
);
}
// Method to convert CargoEntity to JSON
Map<String, dynamic> toJson() {
return {
'Oid': oid,
'ClientId': clientId,
'CargoId': cargoId,
'State': state,
'No': no,
'Name': name,
'ShopNo': shopNo,
'Volume': volume,
'PlacesCount': placesCount,
'Carrier': carrier,
'From': from,
'To': to,
'DepartedAt': departedAt,
'ArrivedAt': arrivedAt,
'Depth': depth,
'Width': width,
'Height': height,
};
}
}

View File

@ -0,0 +1,36 @@
import 'package:dartz/dartz.dart';
import '../../core/core.dart';
import '../../domain/domain.dart';
import '../data_sources/data_sources.dart';
class OrderRepositoryImpl extends OrderRepository {
final OrderRemoteDataSource remoteDataSource;
final UserLocalDataSource localDataSource;
final NetworkInfo networkInfo;
OrderRepositoryImpl({
required this.remoteDataSource,
required this.localDataSource,
required this.networkInfo,
});
@override
Future<Either<Failure, List<OrderEntity>>> getOrders(FilterProductParams params) async {
if (!await networkInfo.isConnected) {
return Left(NetworkFailure());
}
if (!await localDataSource.isTokenAvailable()) {
return Left(AuthenticationFailure());
}
try {
final String token = await localDataSource.getToken();
final orders = await remoteDataSource.getOrders(params, token);
return Right(orders);
} on Failure catch (failure) {
return Left(failure);
}
}
}

View File

@ -1,2 +1,3 @@
export 'user_repository_impl.dart';
export 'splash_repository_impl.dart';
export 'order_repository_impl.dart';

View File

@ -3,6 +3,7 @@ import 'package:get_it/get_it.dart';
import 'common.dart';
import 'cubits.dart';
import 'language.dart';
import 'order.dart';
import 'splash.dart';
import 'user.dart';
@ -15,7 +16,7 @@ Future<void> init() async {
registerUserFeature();
registerLanguageFeature();
registerSplashFeature();
registerOrderFeature();
// registerCategoryFeature();
// registerProductFeature();
// registerDeliveryInfoFeature();

24
lib/di/order.dart Normal file
View File

@ -0,0 +1,24 @@
import 'package:cargo/application/application.dart';
import 'package:cargo/data/data.dart';
import 'package:cargo/domain/domain.dart';
import 'di.dart';
void registerOrderFeature() {
// Order bloc and Use Cases
sl.registerFactory(() => OrderBloc(sl()));
sl.registerLazySingleton(() => GetOrderUseCase(sl()));
// Order Repository and Data Sources
sl.registerLazySingleton<OrderRepository>(
() => OrderRepositoryImpl(
localDataSource: sl(),
remoteDataSource: sl(),
networkInfo: sl(),
),
);
sl.registerLazySingleton<OrderRemoteDataSource>(
() => OrderRemoteDataSourceImpl(client: sl()),
);
}

View File

@ -1 +1,3 @@
export 'user/user.dart';
export 'order/order.dart';
export 'order/filter_params_model.dart';

View File

@ -0,0 +1,19 @@
class FilterProductParams {
final int? limit;
final int? pageSize;
const FilterProductParams({
this.limit = 0,
this.pageSize = 10,
});
FilterProductParams copyWith({
int? skip,
int? limit,
int? pageSize,
}) =>
FilterProductParams(
limit: skip ?? this.limit,
pageSize: pageSize ?? this.pageSize,
);
}

View File

@ -0,0 +1,44 @@
import 'package:equatable/equatable.dart';
class OrderEntity extends Equatable {
final String oid;
final String clientId;
final String cargoId;
final String state;
final String no;
final String name;
final String shopNo;
final double volume;
final int placesCount;
final String carrier;
final String from;
final String to;
final String departedAt;
final String arrivedAt;
final double depth;
final double width;
final double height;
const OrderEntity({
required this.oid,
required this.clientId,
required this.cargoId,
required this.state,
required this.no,
required this.name,
required this.shopNo,
required this.volume,
required this.placesCount,
required this.carrier,
required this.from,
required this.to,
required this.departedAt,
required this.arrivedAt,
required this.depth,
required this.width,
required this.height,
});
@override
List<Object?> get props => [oid];
}

View File

@ -0,0 +1,8 @@
import 'package:dartz/dartz.dart';
import '../../core/errors/failures.dart';
import '../domain.dart';
abstract class OrderRepository {
Future<Either<Failure, List<OrderEntity>>> getOrders(FilterProductParams params);
}

View File

@ -1,2 +1,3 @@
export 'user_repository.dart';
export 'splash_repository.dart';
export 'order_repository.dart';

View File

@ -0,0 +1,14 @@
import 'package:dartz/dartz.dart';
import '../../../core/core.dart';
import '../../domain.dart';
class GetOrderUseCase implements UseCase<List<OrderEntity>, FilterProductParams> {
final OrderRepository repository;
GetOrderUseCase(this.repository);
@override
Future<Either<Failure, List<OrderEntity>>> call(FilterProductParams params) async {
return await repository.getOrders(params);
}
}

View File

@ -0,0 +1 @@
export 'get_orders_usecase.dart';

View File

@ -1,2 +1,3 @@
export 'user/user.dart';
export 'splash/splash_usecase.dart';
export 'order/order.dart';

View File

@ -1,15 +1,30 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../application/order_bloc/order_bloc.dart';
import '../../configs/configs.dart';
import '../../core/core.dart';
import '../widgets/widgets.dart';
class OrdersScreen extends StatelessWidget {
class OrdersScreen extends StatefulWidget {
const OrdersScreen({super.key});
@override
State<OrdersScreen> createState() => _OrdersScreenState();
}
class _OrdersScreenState extends State<OrdersScreen> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
// Initialize the context (if needed)
App.init(context);
// Provide the OrderBloc
return Scaffold(
backgroundColor: AppColors.surface,
body: CustomScrollView(
@ -40,13 +55,46 @@ class OrdersScreen extends StatelessWidget {
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return const OrderCard();
},
childCount: 4, // items.length,
),
// Use BlocBuilder to respond to state changes
BlocBuilder<OrderBloc, OrderState>(
builder: (context, state) {
if (state is OrderLoading) {
// Display a loading indicator while fetching orders
return const SliverToBoxAdapter(
child: Center(
child: CircularProgressIndicator(),
),
);
} else if (state is OrderError) {
// Display an error message if there was a failure
return SliverToBoxAdapter(
child: Center(
child: Text(
'Failed to load orders: ${state.failure}',
style: const TextStyle(color: Colors.red),
),
),
);
} else if (state is OrderLoaded) {
// Display the list of orders
return SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
final order = state.orders[index];
return OrderCard(order: order);
},
childCount: state.orders.length,
),
);
} else {
// Default case (initial state)
return const SliverToBoxAdapter(
child: Center(
child: Text('No orders available'),
),
);
}
},
),
],
),

View File

@ -2,10 +2,13 @@ import 'package:flutter/material.dart';
import '../../configs/configs.dart';
import '../../core/core.dart';
import '../../domain/domain.dart';
import 'vertical_line.dart';
class OrderCard extends StatelessWidget {
const OrderCard({super.key});
final OrderEntity order;
const OrderCard({required this.order, super.key});
@override
Widget build(BuildContext context) {
@ -22,7 +25,7 @@ class OrderCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'ABC456789',
'${order.no}',
style: AppText.b1b,
),
GestureDetector(
@ -48,14 +51,14 @@ class OrderCard extends StatelessWidget {
const Icon(Icons.circle, color: AppColors.green, size: 12),
const SizedBox(width: 4),
Text(
'Ýolda',
order.state,
style: AppText.b2b!.copyWith(
color: AppColors.grey,
),
),
const Spacer(),
Text(
'Ugradylan senesi: 16.07.2024',
'Ugradylan senesi: ${order.departedAt}',
style: AppText.b2b!.copyWith(
color: AppColors.grey,
),
@ -72,7 +75,7 @@ class OrderCard extends StatelessWidget {
Row(
children: [
Expanded(
flex: 2,
flex: 3,
child: Row(
children: [
/// vertical status line
@ -88,35 +91,41 @@ class OrderCard extends StatelessWidget {
),
/// info
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Nireden:',
style: AppText.b2b!.copyWith(
color: AppColors.grey,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Nireden:',
style: AppText.b2b!.copyWith(
color: AppColors.grey,
),
),
),
Text(
'Urumçy',
style: AppText.b2b!.copyWith(
color: const Color(0xFF57575C),
Text(
order.from,
style: AppText.b2b!.copyWith(
color: const Color(0xFF57575C),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(height: 8),
Text(
'Nirede:',
style: AppText.b2b!.copyWith(
color: AppColors.grey,
const SizedBox(height: 8),
Text(
'Nirede:',
style: AppText.b2b!.copyWith(
color: AppColors.grey,
),
),
),
Text(
'Aşgabat',
style: AppText.b2b!.copyWith(
color: const Color(0xFF57575C),
Text(
order.to,
style: AppText.b2b!.copyWith(
color: const Color(0xFF57575C),
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
],
],
),
),
],
),
@ -125,7 +134,7 @@ class OrderCard extends StatelessWidget {
),
// const Spacer(flex: 1),
Expanded(
flex: 2,
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -136,7 +145,7 @@ class OrderCard extends StatelessWidget {
),
),
Text(
'10',
order.placesCount.toString(),
style: AppText.b2b!.copyWith(
color: const Color(0xFF57575C),
),
@ -149,7 +158,7 @@ class OrderCard extends StatelessWidget {
),
),
Text(
'1472,31',
order.volume.toString(),
style: AppText.b2b!.copyWith(
color: const Color(0xFF57575C),
),
@ -169,7 +178,7 @@ class OrderCard extends StatelessWidget {
),
),
Text(
'AA1234AA',
order.carrier,
style: AppText.b2b!.copyWith(
color: const Color(0xFF57575C),
),
@ -182,7 +191,7 @@ class OrderCard extends StatelessWidget {
),
),
Text(
'A1043',
order.shopNo,
style: AppText.b2b!.copyWith(
color: const Color(0xFF57575C),
),

View File

@ -238,7 +238,7 @@ packages:
source: hosted
version: "1.0.0+1"
intl:
dependency: transitive
dependency: "direct main"
description:
name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf

View File

@ -26,6 +26,7 @@ dependencies:
latlong2: ^0.9.0
flutter_map_marker_cluster: ^1.3.6
easy_localization: ^3.0.7
intl: ^0.19.0
dev_dependencies:
flutter_test: