Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions lib/data/datasources/category_remote_datasource.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'package:dio/dio.dart';
import '../../core/error/failures.dart';
import '../../core/network/api_client.dart';
import '../../domain/models/category.dart';
import '../../presentation/providers/auth_provider.dart';
import '../../presentation/states/auth_state.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

abstract class CategoryRemoteDatasource {
Future<CategoriesResponse> getAllCategories();
}

class CategoryRemoteDatasourceImpl implements CategoryRemoteDatasource {
final ApiClient apiClient;
final Ref ref;

CategoryRemoteDatasourceImpl(this.apiClient, this.ref);

@override
Future<CategoriesResponse> getAllCategories() async {
try {
// Check if the user is authenticated
final authState = ref.read(authNotifierProvider);
if (authState is! AuthSuccess) {
throw ServerFailure(
message: 'Authentication required to fetch categories',
);
}

// Get the access token
final token = authState.response.tokens.accessToken;

// Make the API request with the token
final response = await apiClient.get(
'/categories/all',
options: Options(
headers: {
'Authorization': 'Bearer $token',
},
),
);

// Pass the direct response data to the fromJson method
return CategoriesResponse.fromJson(response.data);
} on DioException catch (e) {
throw ServerFailure(
message: e.message ?? 'An error occurred while fetching categories',
code: e.response?.statusCode,
);
} catch (e) {
if (e is ServerFailure) {
rethrow;
}
throw ServerFailure(message: e.toString());
}
}
}
57 changes: 57 additions & 0 deletions lib/data/datasources/hashtag_remote_datasource.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'package:dio/dio.dart';
import '../../core/error/failures.dart';
import '../../core/network/api_client.dart';
import '../../domain/models/hashtag.dart';
import '../../presentation/providers/auth_provider.dart';
import '../../presentation/states/auth_state.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

abstract class HashtagRemoteDatasource {
Future<HashtagsResponse> getAllHashtags();
}

class HashtagRemoteDatasourceImpl implements HashtagRemoteDatasource {
final ApiClient apiClient;
final Ref ref;

HashtagRemoteDatasourceImpl(this.apiClient, this.ref);

@override
Future<HashtagsResponse> getAllHashtags() async {
try {
// Check if the user is authenticated
final authState = ref.read(authNotifierProvider);
if (authState is! AuthSuccess) {
throw ServerFailure(
message: 'Authentication required to fetch hashtags',
);
}

// Get the access token
final token = authState.response.tokens.accessToken;

// Make the API request with the token
final response = await apiClient.get(
'/hashtags',
options: Options(
headers: {
'Authorization': 'Bearer $token',
},
),
);

// Pass the direct response data to the fromJson method
return HashtagsResponse.fromJson(response.data);
} on DioException catch (e) {
throw ServerFailure(
message: e.message ?? 'An error occurred while fetching hashtags',
code: e.response?.statusCode,
);
} catch (e) {
if (e is ServerFailure) {
rethrow;
}
throw ServerFailure(message: e.toString());
}
}
}
14 changes: 14 additions & 0 deletions lib/data/repositories/category_repository_impl.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import '../../domain/models/category.dart';
import '../../domain/repositories/category_repository.dart';
import '../datasources/category_remote_datasource.dart';

class CategoryRepositoryImpl implements CategoryRepository {
final CategoryRemoteDatasource remoteDatasource;

CategoryRepositoryImpl(this.remoteDatasource);

@override
Future<CategoriesResponse> getAllCategories() {
return remoteDatasource.getAllCategories();
}
}
14 changes: 14 additions & 0 deletions lib/data/repositories/hashtag_repository_impl.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import '../../domain/models/hashtag.dart';
import '../../domain/repositories/hashtag_repository.dart';
import '../datasources/hashtag_remote_datasource.dart';

class HashtagRepositoryImpl implements HashtagRepository {
final HashtagRemoteDatasource remoteDatasource;

HashtagRepositoryImpl(this.remoteDatasource);

@override
Future<HashtagsResponse> getAllHashtags() {
return remoteDatasource.getAllHashtags();
}
}
44 changes: 44 additions & 0 deletions lib/domain/models/category.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
class Category {
final String id;
final String name;
final String createdAt;
final String updatedAt;

Category({
required this.id,
required this.name,
required this.createdAt,
required this.updatedAt,
});

factory Category.fromJson(Map<String, dynamic> json) => Category(
id: json['id'] ?? '',
name: json['name'] ?? '',
createdAt: json['createdAt'] ?? '',
updatedAt: json['updatedAt'] ?? '',
);
}

class CategoriesResponse {
final List<Category> categories;

CategoriesResponse({required this.categories});

factory CategoriesResponse.fromJson(dynamic json) {
// Handle both array response and object with data field
List<dynamic> categoriesData = [];

if (json is List) {
// Direct array response
categoriesData = json;
} else if (json is Map<String, dynamic>) {
// Response with data field
categoriesData = json['data'] ?? [];
}

final categories = categoriesData
.map((categoryJson) => Category.fromJson(categoryJson))
.toList();
return CategoriesResponse(categories: categories);
}
}
44 changes: 44 additions & 0 deletions lib/domain/models/hashtag.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
class Hashtag {
final String id;
final String name;
final String createdAt;
final String updatedAt;

Hashtag({
required this.id,
required this.name,
required this.createdAt,
required this.updatedAt,
});

factory Hashtag.fromJson(Map<String, dynamic> json) => Hashtag(
id: json['id'] ?? '',
name: json['name'] ?? '',
createdAt: json['createdAt'] ?? '',
updatedAt: json['updatedAt'] ?? '',
);
}

class HashtagsResponse {
final List<Hashtag> hashtags;

HashtagsResponse({required this.hashtags});

factory HashtagsResponse.fromJson(dynamic json) {
// Handle both array response and object with data field
List<dynamic> hashtagsData = [];

if (json is List) {
// Direct array response
hashtagsData = json;
} else if (json is Map<String, dynamic>) {
// Response with data field
hashtagsData = json['data'] ?? [];
}

final hashtags = hashtagsData
.map((hashtagJson) => Hashtag.fromJson(hashtagJson))
.toList();
return HashtagsResponse(hashtags: hashtags);
}
}
5 changes: 5 additions & 0 deletions lib/domain/repositories/category_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import '../models/category.dart';

abstract class CategoryRepository {
Future<CategoriesResponse> getAllCategories();
}
5 changes: 5 additions & 0 deletions lib/domain/repositories/hashtag_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import '../models/hashtag.dart';

abstract class HashtagRepository {
Future<HashtagsResponse> getAllHashtags();
}
12 changes: 12 additions & 0 deletions lib/domain/usecases/get_all_categories.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import '../models/category.dart';
import '../repositories/category_repository.dart';

class GetAllCategories {
final CategoryRepository repository;

GetAllCategories(this.repository);

Future<CategoriesResponse> call() async {
return await repository.getAllCategories();
}
}
12 changes: 12 additions & 0 deletions lib/domain/usecases/get_all_hashtags.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import '../models/hashtag.dart';
import '../repositories/hashtag_repository.dart';

class GetAllHashtags {
final HashtagRepository repository;

GetAllHashtags(this.repository);

Future<HashtagsResponse> call() async {
return await repository.getAllHashtags();
}
}
Loading