add detail, fetch products, categories
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import '../models/category_model.dart';
|
||||
import '../../../../core/network/dio_client.dart';
|
||||
import '../../../../core/constants/api_constants.dart';
|
||||
import '../../../../core/errors/exceptions.dart';
|
||||
|
||||
/// Category remote data source using API
|
||||
abstract class CategoryRemoteDataSource {
|
||||
Future<List<CategoryModel>> getAllCategories();
|
||||
Future<CategoryModel> getCategoryById(String id);
|
||||
}
|
||||
|
||||
class CategoryRemoteDataSourceImpl implements CategoryRemoteDataSource {
|
||||
final DioClient client;
|
||||
|
||||
CategoryRemoteDataSourceImpl(this.client);
|
||||
|
||||
@override
|
||||
Future<List<CategoryModel>> getAllCategories() async {
|
||||
try {
|
||||
final response = await client.get(ApiConstants.categories);
|
||||
|
||||
// API returns: { success: true, data: [...categories...] }
|
||||
if (response.data['success'] == true) {
|
||||
final List<dynamic> data = response.data['data'] ?? [];
|
||||
return data.map((json) => CategoryModel.fromJson(json)).toList();
|
||||
} else {
|
||||
throw ServerException(response.data['message'] ?? 'Failed to fetch categories');
|
||||
}
|
||||
} catch (e) {
|
||||
if (e is ServerException) rethrow;
|
||||
throw ServerException('Failed to fetch categories: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<CategoryModel> getCategoryById(String id) async {
|
||||
try {
|
||||
final response = await client.get(ApiConstants.categoryById(id));
|
||||
|
||||
// API returns: { success: true, data: {...category...} }
|
||||
if (response.data['success'] == true) {
|
||||
return CategoryModel.fromJson(response.data['data']);
|
||||
} else {
|
||||
throw ServerException(response.data['message'] ?? 'Category not found');
|
||||
}
|
||||
} catch (e) {
|
||||
if (e is ServerException) rethrow;
|
||||
throw ServerException('Failed to fetch category: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import '../datasources/category_local_datasource.dart';
|
||||
import '../datasources/category_remote_datasource.dart';
|
||||
import '../repositories/category_repository_impl.dart';
|
||||
import '../models/category_model.dart';
|
||||
import '../../domain/repositories/category_repository.dart';
|
||||
import '../../../../core/providers/providers.dart';
|
||||
import '../../../../core/constants/storage_constants.dart';
|
||||
|
||||
part 'category_providers.g.dart';
|
||||
|
||||
/// Provider for category Hive box
|
||||
@riverpod
|
||||
Box<CategoryModel> categoryBox(Ref ref) {
|
||||
return Hive.box<CategoryModel>(StorageConstants.categoriesBox);
|
||||
}
|
||||
|
||||
/// Provider for category local data source
|
||||
@riverpod
|
||||
CategoryLocalDataSource categoryLocalDataSource(Ref ref) {
|
||||
final box = ref.watch(categoryBoxProvider);
|
||||
return CategoryLocalDataSourceImpl(box);
|
||||
}
|
||||
|
||||
/// Provider for category remote data source
|
||||
@riverpod
|
||||
CategoryRemoteDataSource categoryRemoteDataSource(Ref ref) {
|
||||
final dioClient = ref.watch(dioClientProvider);
|
||||
return CategoryRemoteDataSourceImpl(dioClient);
|
||||
}
|
||||
|
||||
/// Provider for category repository
|
||||
@riverpod
|
||||
CategoryRepository categoryRepository(Ref ref) {
|
||||
final localDataSource = ref.watch(categoryLocalDataSourceProvider);
|
||||
final remoteDataSource = ref.watch(categoryRemoteDataSourceProvider);
|
||||
|
||||
return CategoryRepositoryImpl(
|
||||
localDataSource: localDataSource,
|
||||
remoteDataSource: remoteDataSource,
|
||||
);
|
||||
}
|
||||
220
lib/features/categories/data/providers/category_providers.g.dart
Normal file
220
lib/features/categories/data/providers/category_providers.g.dart
Normal file
@@ -0,0 +1,220 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'category_providers.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Provider for category Hive box
|
||||
|
||||
@ProviderFor(categoryBox)
|
||||
const categoryBoxProvider = CategoryBoxProvider._();
|
||||
|
||||
/// Provider for category Hive box
|
||||
|
||||
final class CategoryBoxProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
Box<CategoryModel>,
|
||||
Box<CategoryModel>,
|
||||
Box<CategoryModel>
|
||||
>
|
||||
with $Provider<Box<CategoryModel>> {
|
||||
/// Provider for category Hive box
|
||||
const CategoryBoxProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'categoryBoxProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$categoryBoxHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<Box<CategoryModel>> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
Box<CategoryModel> create(Ref ref) {
|
||||
return categoryBox(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(Box<CategoryModel> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<Box<CategoryModel>>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$categoryBoxHash() => r'cbcd3cf6f0673b13a5e0af6dba10ca10f32be70c';
|
||||
|
||||
/// Provider for category local data source
|
||||
|
||||
@ProviderFor(categoryLocalDataSource)
|
||||
const categoryLocalDataSourceProvider = CategoryLocalDataSourceProvider._();
|
||||
|
||||
/// Provider for category local data source
|
||||
|
||||
final class CategoryLocalDataSourceProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
CategoryLocalDataSource,
|
||||
CategoryLocalDataSource,
|
||||
CategoryLocalDataSource
|
||||
>
|
||||
with $Provider<CategoryLocalDataSource> {
|
||||
/// Provider for category local data source
|
||||
const CategoryLocalDataSourceProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'categoryLocalDataSourceProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$categoryLocalDataSourceHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<CategoryLocalDataSource> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
CategoryLocalDataSource create(Ref ref) {
|
||||
return categoryLocalDataSource(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(CategoryLocalDataSource value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<CategoryLocalDataSource>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$categoryLocalDataSourceHash() =>
|
||||
r'8d42c0dcfb986dfa0413e4267c4b08f24963ef50';
|
||||
|
||||
/// Provider for category remote data source
|
||||
|
||||
@ProviderFor(categoryRemoteDataSource)
|
||||
const categoryRemoteDataSourceProvider = CategoryRemoteDataSourceProvider._();
|
||||
|
||||
/// Provider for category remote data source
|
||||
|
||||
final class CategoryRemoteDataSourceProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
CategoryRemoteDataSource,
|
||||
CategoryRemoteDataSource,
|
||||
CategoryRemoteDataSource
|
||||
>
|
||||
with $Provider<CategoryRemoteDataSource> {
|
||||
/// Provider for category remote data source
|
||||
const CategoryRemoteDataSourceProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'categoryRemoteDataSourceProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$categoryRemoteDataSourceHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<CategoryRemoteDataSource> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
CategoryRemoteDataSource create(Ref ref) {
|
||||
return categoryRemoteDataSource(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(CategoryRemoteDataSource value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<CategoryRemoteDataSource>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$categoryRemoteDataSourceHash() =>
|
||||
r'60294160d6655f1455064fb01016d341570e9a5d';
|
||||
|
||||
/// Provider for category repository
|
||||
|
||||
@ProviderFor(categoryRepository)
|
||||
const categoryRepositoryProvider = CategoryRepositoryProvider._();
|
||||
|
||||
/// Provider for category repository
|
||||
|
||||
final class CategoryRepositoryProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
CategoryRepository,
|
||||
CategoryRepository,
|
||||
CategoryRepository
|
||||
>
|
||||
with $Provider<CategoryRepository> {
|
||||
/// Provider for category repository
|
||||
const CategoryRepositoryProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'categoryRepositoryProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$categoryRepositoryHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<CategoryRepository> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
CategoryRepository create(Ref ref) {
|
||||
return categoryRepository(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(CategoryRepository value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<CategoryRepository>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$categoryRepositoryHash() =>
|
||||
r'256a9f2aa52a1858bbb50a87f2f838c33552ef22';
|
||||
@@ -2,14 +2,17 @@ import 'package:dartz/dartz.dart';
|
||||
import '../../domain/entities/category.dart';
|
||||
import '../../domain/repositories/category_repository.dart';
|
||||
import '../datasources/category_local_datasource.dart';
|
||||
import '../datasources/category_remote_datasource.dart';
|
||||
import '../../../../core/errors/failures.dart';
|
||||
import '../../../../core/errors/exceptions.dart';
|
||||
|
||||
class CategoryRepositoryImpl implements CategoryRepository {
|
||||
final CategoryLocalDataSource localDataSource;
|
||||
final CategoryRemoteDataSource remoteDataSource;
|
||||
|
||||
CategoryRepositoryImpl({
|
||||
required this.localDataSource,
|
||||
required this.remoteDataSource,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -38,12 +41,13 @@ class CategoryRepositoryImpl implements CategoryRepository {
|
||||
@override
|
||||
Future<Either<Failure, List<Category>>> syncCategories() async {
|
||||
try {
|
||||
// For now, return cached categories
|
||||
// In the future, implement remote sync
|
||||
final categories = await localDataSource.getAllCategories();
|
||||
final categories = await remoteDataSource.getAllCategories();
|
||||
await localDataSource.cacheCategories(categories);
|
||||
return Right(categories.map((model) => model.toEntity()).toList());
|
||||
} on CacheException catch (e) {
|
||||
return Left(CacheFailure(e.message));
|
||||
} on ServerException catch (e) {
|
||||
return Left(ServerFailure(e.message));
|
||||
} on NetworkException catch (e) {
|
||||
return Left(NetworkFailure(e.message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user