244 lines
7.5 KiB
Dart
244 lines
7.5 KiB
Dart
// lib/presentation/discount/bloc/discount_bloc.dart
|
|
|
|
import 'dart:developer';
|
|
import 'package:business_panel/core/config/api_config.dart';
|
|
import 'package:business_panel/core/services/token_storage_service.dart';
|
|
import 'package:business_panel/core/utils/logging_interceptor.dart';
|
|
import 'package:dio/dio.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'discount_event.dart';
|
|
import 'discount_state.dart';
|
|
import 'dart:convert'; // Import for jsonEncode
|
|
|
|
class DiscountBloc extends Bloc<DiscountEvent, DiscountState> {
|
|
final Dio _dio = Dio();
|
|
final TokenStorageService _tokenStorage = TokenStorageService();
|
|
|
|
DiscountBloc() : super(const DiscountState()) {
|
|
_dio.interceptors.add(LoggingInterceptor());
|
|
|
|
on<FetchDiscountDetails>((event, emit) async {
|
|
emit(state.copyWith(isLoadingDetails: true, errorMessage: null));
|
|
try {
|
|
final token = await _tokenStorage.getAccessToken();
|
|
if (token == null) {
|
|
emit(
|
|
state.copyWith(
|
|
isLoadingDetails: false,
|
|
errorMessage: "خطای احراز هویت.",
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
|
|
final response = await _dio.get(
|
|
ApiConfig.getDiscountById(event.discountId),
|
|
options: Options(headers: {'Authorization': 'Bearer $token'}),
|
|
);
|
|
|
|
if (response.statusCode == 200 && response.data['data'] != null) {
|
|
final data = response.data['data'];
|
|
|
|
List<Map<String, String?>> images = [];
|
|
if (data['Images'] is List) {
|
|
images = (data['Images'] as List)
|
|
.map<Map<String, String?>>(
|
|
(img) => {
|
|
'id': img['_id'] as String?,
|
|
'url': img['Url'] as String?,
|
|
},
|
|
)
|
|
.where((img) => img['url'] != null)
|
|
.toList();
|
|
}
|
|
|
|
final name = data['Name'] ?? '';
|
|
final typeId = data['Type']?['ID'];
|
|
final description = data['Description'] ?? '';
|
|
final price = data['Price']?.toString() ?? '0';
|
|
final nPrice = data['NPrice']?.toString() ?? '0';
|
|
final startDate =
|
|
data['StartDate'] != null ? DateTime.tryParse(data['StartDate']) : null;
|
|
final endDate =
|
|
data['EndDate'] != null ? DateTime.tryParse(data['EndDate']) : null;
|
|
final startTime = data['StartTime'];
|
|
final endTime = data['EndTime'];
|
|
final radius = (data['Radius'] as num?)?.toDouble() ?? 0.0;
|
|
|
|
emit(
|
|
state.copyWith(
|
|
isLoadingDetails: false,
|
|
discountId: data['_id'],
|
|
productName: name,
|
|
productImages: images,
|
|
discountTypeId: typeId,
|
|
description: description,
|
|
price: price,
|
|
discountedPrice: nPrice,
|
|
startDate: startDate,
|
|
endDate: endDate,
|
|
startTime: startTime,
|
|
endTime: endTime,
|
|
notificationRadius: radius,
|
|
),
|
|
);
|
|
} else {
|
|
emit(
|
|
state.copyWith(
|
|
isLoadingDetails: false,
|
|
errorMessage: "تخفیف یافت نشد.",
|
|
),
|
|
);
|
|
}
|
|
} catch (e) {
|
|
emit(
|
|
state.copyWith(
|
|
isLoadingDetails: false,
|
|
errorMessage: 'خطا در دریافت اطلاعات.',
|
|
),
|
|
);
|
|
}
|
|
});
|
|
|
|
on<ProductImageAdded>((event, emit) {
|
|
List<Map<String, String?>> updatedImages = List.from(state.productImages);
|
|
final newImageMap = {'id': null, 'url': event.imagePath};
|
|
|
|
if (updatedImages.length > event.index) {
|
|
updatedImages[event.index] = newImageMap;
|
|
} else {
|
|
updatedImages.add(newImageMap);
|
|
}
|
|
emit(state.copyWith(productImages: updatedImages));
|
|
});
|
|
|
|
on<ProductNameChanged>((event, emit) {
|
|
emit(state.copyWith(productName: event.name));
|
|
});
|
|
|
|
on<DiscountTypeChanged>((event, emit) {
|
|
emit(state.copyWith(discountTypeId: event.typeId));
|
|
});
|
|
|
|
on<DescriptionChanged>((event, emit) {
|
|
emit(state.copyWith(description: event.description));
|
|
});
|
|
|
|
on<ValidityDateChanged>((event, emit) {
|
|
emit(state.copyWith(startDate: event.startDate, endDate: event.endDate));
|
|
});
|
|
|
|
on<TimeRangeChanged>((event, emit) {
|
|
emit(state.copyWith(startTime: event.startTime, endTime: event.endTime));
|
|
});
|
|
|
|
on<PriceChanged>((event, emit) {
|
|
emit(state.copyWith(price: event.price));
|
|
});
|
|
|
|
on<DiscountedPriceChanged>((event, emit) {
|
|
emit(state.copyWith(discountedPrice: event.price));
|
|
});
|
|
|
|
on<NotificationRadiusChanged>((event, emit) {
|
|
emit(state.copyWith(notificationRadius: event.radius));
|
|
});
|
|
|
|
on<SubmitDiscount>((event, emit) async {
|
|
await _submitDiscountForm(emit, isEdit: false);
|
|
});
|
|
|
|
on<UpdateDiscount>((event, emit) async {
|
|
await _submitDiscountForm(
|
|
emit,
|
|
isEdit: true,
|
|
discountId: event.discountId,
|
|
);
|
|
});
|
|
}
|
|
|
|
Future<void> _submitDiscountForm(
|
|
Emitter<DiscountState> emit, {
|
|
required bool isEdit,
|
|
String? discountId,
|
|
}) async {
|
|
emit(state.copyWith(isSubmitting: true, errorMessage: null));
|
|
|
|
try {
|
|
final token = await _tokenStorage.getAccessToken();
|
|
if (token == null) {
|
|
emit(
|
|
state.copyWith(isSubmitting: false, errorMessage: "خطای احراز هویت."),
|
|
);
|
|
return;
|
|
}
|
|
|
|
final Map<String, dynamic> data = {
|
|
'Name': state.productName,
|
|
'Type': state.discountTypeId,
|
|
'Description': state.description,
|
|
'Price': double.tryParse(state.price),
|
|
'NPrice': double.tryParse(state.discountedPrice),
|
|
'Start': state.startDate?.toUtc().toIso8601String(),
|
|
'End': state.endDate?.toUtc().toIso8601String(),
|
|
'StartTime': state.startTime,
|
|
'EndTime': state.endTime,
|
|
'Radius': state.notificationRadius,
|
|
};
|
|
|
|
List<MultipartFile> newImageFiles = [];
|
|
List<String> existingImageIds = [];
|
|
|
|
for (var imageMap in state.productImages) {
|
|
final id = imageMap['id'];
|
|
final url = imageMap['url'];
|
|
|
|
if (id != null && url != null && url.startsWith('http')) {
|
|
existingImageIds.add(id);
|
|
} else if (url != null && !url.startsWith('http')) {
|
|
newImageFiles.add(
|
|
await MultipartFile.fromFile(url, filename: url.split('/').last),
|
|
);
|
|
}
|
|
}
|
|
|
|
if (newImageFiles.isNotEmpty) {
|
|
data['Images'] = newImageFiles;
|
|
}
|
|
|
|
if (isEdit) {
|
|
data['ExistingImages'] = jsonEncode(existingImageIds);
|
|
}
|
|
|
|
// *** CHANGE IS HERE: Logging the data before sending ***
|
|
log('Submitting Discount Data: $data', name: 'DiscountBloc');
|
|
|
|
final formData = FormData.fromMap(data);
|
|
final url =
|
|
isEdit ? ApiConfig.editDiscount(discountId!) : ApiConfig.addDiscount;
|
|
|
|
await _dio.post(
|
|
url,
|
|
data: formData,
|
|
options: Options(headers: {'Authorization': 'Bearer $token'}),
|
|
);
|
|
|
|
emit(state.copyWith(isSubmitting: false, isSuccess: true));
|
|
} on DioException catch (e) {
|
|
emit(
|
|
state.copyWith(
|
|
isSubmitting: false,
|
|
errorMessage: e.response?.data['message'] ?? 'خطای سرور.',
|
|
),
|
|
);
|
|
} catch (e) {
|
|
emit(
|
|
state.copyWith(
|
|
isSubmitting: false,
|
|
errorMessage: 'خطای ناشناخته: ${e.toString()}',
|
|
),
|
|
);
|
|
}
|
|
}
|
|
} |