1871 lines
58 KiB
Dart
1871 lines
58 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:bookmywages/model/Banner_model.dart';
|
|
import 'package:bookmywages/model/Booking_model.dart';
|
|
import 'package:bookmywages/model/Categories_model.dart';
|
|
import 'package:bookmywages/model/detail_page_model.dart';
|
|
import 'package:bookmywages/model/enquriy_list_model.dart';
|
|
import 'package:bookmywages/model/enquriy_model.dart';
|
|
import 'package:bookmywages/model/expired_plan_model.dart';
|
|
import 'package:bookmywages/model/get_review_model.dart';
|
|
import 'package:bookmywages/model/login_model.dart';
|
|
import 'package:bookmywages/model/most_popular_model.dart';
|
|
import 'package:bookmywages/model/notification_model.dart';
|
|
import 'package:bookmywages/model/otp_model.dart';
|
|
import 'package:bookmywages/model/package_model.dart';
|
|
import 'package:bookmywages/model/payment_details_model.dart';
|
|
import 'package:bookmywages/model/profile_get_model.dart';
|
|
import 'package:bookmywages/model/service_model.dart';
|
|
import 'package:bookmywages/model/subcategory_model.dart';
|
|
import 'package:bookmywages/model/user_booking_details.dart'
|
|
show UserBookingDetails;
|
|
import 'package:bookmywages/model/vendor_model/terms_and_conditions_model.dart';
|
|
import 'package:bookmywages/model/vendor_model/vendor_booking_model.dart';
|
|
import 'package:bookmywages/model/vendor_model/vendor_catgories_model.dart'
|
|
show VendorCategoriesModel;
|
|
import 'package:bookmywages/model/vendor_model/vendor_profile_model.dart';
|
|
import 'package:bookmywages/model/vendor_model/vendor_service_model.dart';
|
|
import 'package:bookmywages/model/vendor_model/vendor_serviceupload_model.dart';
|
|
import 'package:bookmywages/model/vendor_model/vendorregister_model.dart';
|
|
import 'package:bookmywages/viewmodel/consts_api.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:fluttertoast/fluttertoast.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:image_picker/image_picker.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:http_parser/http_parser.dart'; // Add this at the top
|
|
|
|
class AuthRepository {
|
|
Future<Map<String, dynamic>> loginUser(
|
|
String url,
|
|
LoginModel loginModel,
|
|
) async {
|
|
try {
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode(loginModel.toJson()),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final decoded = jsonDecode(response.body);
|
|
print('Decoded Response: $decoded'); // Debug print
|
|
|
|
dynamic data = decoded['data'];
|
|
String userId = '';
|
|
String isverify = '';
|
|
|
|
// Handle different response structures
|
|
if (data is List && data.isNotEmpty) {
|
|
// Response contains a list of data
|
|
userId = data[0]['id']?.toString() ?? '';
|
|
isverify = data[0]['is_verified']?.toString() ?? '';
|
|
} else if (data is Map) {
|
|
// Response contains a single data object
|
|
userId = data['id']?.toString() ?? '';
|
|
isverify = data['is_verified']?.toString() ?? '';
|
|
|
|
// Check if vendor_id exists in the data map
|
|
} else {
|
|
throw Exception('Unexpected response structure: $data');
|
|
}
|
|
|
|
// Store both values in SharedPreferences
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString('userId', userId);
|
|
await prefs.setString('is_verified', isverify);
|
|
|
|
// Also store the full data JSON string for other operations
|
|
await prefs.setString('data', userId);
|
|
|
|
return decoded;
|
|
} else {
|
|
throw Exception(
|
|
'Login failed with status code ${response.statusCode}: ${response.body}',
|
|
);
|
|
}
|
|
} catch (e) {
|
|
print('Login error: $e');
|
|
throw Exception('Login failed: $e');
|
|
}
|
|
}
|
|
|
|
Future<Map<String, dynamic>> registerUser(
|
|
String url,
|
|
Map<String, dynamic> data,
|
|
) async {
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode(data),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final decoded = jsonDecode(response.body);
|
|
print('Decoded Response: $decoded'); // Debug print
|
|
|
|
dynamic data = decoded['data'];
|
|
|
|
String userId;
|
|
String isverify;
|
|
|
|
if (data is List && data.isNotEmpty) {
|
|
userId = data[0]['id'].toString();
|
|
isverify = data[0]['is_verified'].toString();
|
|
} else if (data is Map && data.containsKey('id')) {
|
|
userId = data['id'].toString();
|
|
isverify = data['is_verified'].toString();
|
|
} else {
|
|
throw Exception('Unexpected response structure: $data');
|
|
}
|
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString('userId', userId);
|
|
await prefs.setString('is_verified', isverify);
|
|
|
|
return decoded;
|
|
} else {
|
|
throw Exception('Register failed: ${response.body}');
|
|
}
|
|
}
|
|
|
|
// Add to AuthRepository class
|
|
Future<Map<String, dynamic>> verifyOtp(String url, OtpModel otpModel) async {
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode(otpModel.toJson()),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final decoded = jsonDecode(response.body);
|
|
print('OTP Verify Response: $decoded');
|
|
|
|
// Directly store is_verified = '1'
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString('is_verified', '1');
|
|
|
|
return decoded;
|
|
} else {
|
|
throw Exception('OTP verification failed: ${response.body}');
|
|
}
|
|
}
|
|
}
|
|
|
|
class BannerRepository {
|
|
Future<List<BannerModel>> fetchBanners(String url) async {
|
|
try {
|
|
final response = await http
|
|
.get(Uri.parse(url))
|
|
.timeout(const Duration(seconds: 10));
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> bannerList = jsonBody['data'] ?? [];
|
|
return bannerList.map((json) => BannerModel.fromJson(json)).toList();
|
|
} else {
|
|
return []; // return empty list on server error
|
|
}
|
|
} catch (_) {
|
|
return []; // return empty list on timeout or any error
|
|
}
|
|
}
|
|
}
|
|
|
|
class CategoryRepository {
|
|
Future<List<CategoriesModel>> fetchCategories(String url) async {
|
|
final response = await http.get(Uri.parse(url));
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> categoryList = jsonBody['data'] ?? [];
|
|
|
|
return categoryList
|
|
.map((json) => CategoriesModel.fromJson(json))
|
|
.toList();
|
|
} else {
|
|
throw Exception('Failed to load categories');
|
|
}
|
|
}
|
|
}
|
|
|
|
class packageRepository {
|
|
Future<List<PackageModel>> fetchpackage(String url) async {
|
|
final response = await http.get(Uri.parse(url));
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> packagelist = jsonBody['data'] ?? [];
|
|
|
|
return packagelist.map((json) => PackageModel.fromJson(json)).toList();
|
|
} else {
|
|
throw Exception('Failed to load categories');
|
|
}
|
|
}
|
|
}
|
|
|
|
class SubcategoryRepository {
|
|
Future<List<SubcategoryModel>> fetchSubcategories(
|
|
String url,
|
|
String categoryId,
|
|
) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'userId': userId, 'category': categoryId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
return list.map((e) => SubcategoryModel.fromJson(e)).toList();
|
|
} else {
|
|
throw Exception('Failed to load subcategories');
|
|
}
|
|
}
|
|
}
|
|
|
|
class ProfilegetRepository {
|
|
Future<List<ProfileGetModel>> fetchprofileget(String url) async {
|
|
// Retrieve userId from SharedPreferences
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
// Debugging: Print the userId to make sure it's correct
|
|
print('User ID: $userId');
|
|
|
|
// Check if userId is available before making the request
|
|
if (userId.isEmpty) {
|
|
throw Exception('User ID is not available.');
|
|
}
|
|
|
|
// Send the userId in the API request
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
// Check if the response status code is successful
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
|
|
// Convert the JSON response to a list of ProfileGetModel objects
|
|
return list.map((e) => ProfileGetModel.fromJson(e)).toList();
|
|
} else {
|
|
// Handle API errors
|
|
throw Exception(
|
|
'Failed to load profile data, status code: ${response.statusCode}',
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
class ServiceRepository {
|
|
Future<List<ServiceModel>> fetchService(
|
|
String url,
|
|
String categoryId, [
|
|
String? subcategoryId,
|
|
String? selecttype, // Optional parameter in square brackets
|
|
]) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
// Create the request body
|
|
Map<String, dynamic> requestBody = {
|
|
'user_id': userId,
|
|
'category': categoryId,
|
|
};
|
|
|
|
// Add subcategory only if it's provided
|
|
if (subcategoryId != null && subcategoryId.isNotEmpty) {
|
|
requestBody['subcategory'] = subcategoryId;
|
|
}
|
|
if (selecttype != null && selecttype.isNotEmpty) {
|
|
requestBody['service_type'] = selecttype;
|
|
}
|
|
print('Request Body: $requestBody'); // Debug log
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode(requestBody),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
print('Response: ${response.body}'); // Debug log
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
return list.map((e) => ServiceModel.fromJson(e)).toList();
|
|
} else {
|
|
throw Exception('Failed to load services: ${response.statusCode}');
|
|
}
|
|
}
|
|
}
|
|
|
|
class ProfileupdateRepository {
|
|
Future<List<ProfileGetModel>> fetchprofileupdate(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
if (userId.isEmpty) throw Exception('User ID is not available.');
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
return list.map((e) => ProfileGetModel.fromJson(e)).toList();
|
|
} else {
|
|
throw Exception('Failed to load profile, code: ${response.statusCode}');
|
|
}
|
|
}
|
|
|
|
Future<void> updateProfile({
|
|
required String url,
|
|
required String name,
|
|
required String number,
|
|
required String email,
|
|
required String address,
|
|
File? imageFile,
|
|
}) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
final request = http.MultipartRequest('POST', Uri.parse(url));
|
|
request.fields['user_id'] = userId;
|
|
request.fields['name'] = name;
|
|
request.fields['number'] = number;
|
|
request.fields['email'] = email;
|
|
request.fields['address'] = address;
|
|
|
|
if (imageFile != null) {
|
|
request.files.add(
|
|
await http.MultipartFile.fromPath(
|
|
'profile_pic', // Make sure this matches your backend key
|
|
imageFile.path,
|
|
contentType: MediaType('image', 'jpeg'), // Optional but recommended
|
|
),
|
|
);
|
|
}
|
|
|
|
final response = await request.send();
|
|
|
|
if (response.statusCode != 200) {
|
|
throw Exception('Failed to update profile');
|
|
}
|
|
}
|
|
}
|
|
|
|
class GetReviewRepository {
|
|
Future<List<GetReviewModel>> fetchgetreview(
|
|
String url,
|
|
String serviceId,
|
|
) async {
|
|
Map<String, dynamic> requestBody = {'service_id': serviceId};
|
|
print('Request Body: $requestBody');
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode(requestBody),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
print('Response: ${response.body}');
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
return list.map((e) => GetReviewModel.fromJson(e)).toList();
|
|
} else {
|
|
throw Exception('Failed to load reviews: ${response.statusCode}');
|
|
}
|
|
}
|
|
}
|
|
|
|
class MostPopularRepository {
|
|
Future<List<MostPopularModel>> fetchMostPopular(
|
|
String url,
|
|
String categoryId,
|
|
) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
Map<String, dynamic> requestBody = {
|
|
'user_id': userId,
|
|
'category': categoryId,
|
|
};
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode(requestBody),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
return list.map((e) => MostPopularModel.fromJson(e)).toList();
|
|
} else {
|
|
throw Exception('Failed to load services: ${response.statusCode}');
|
|
}
|
|
}
|
|
}
|
|
|
|
class EnquriyRepository {
|
|
Future<List<EnquiryModel>> fetchenquriy(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
if (userId.isEmpty) throw Exception('User ID is not available.');
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
return list.map((e) => EnquiryModel.fromJson(e)).toList();
|
|
} else {
|
|
throw Exception('Failed to load profile, code: ${response.statusCode}');
|
|
}
|
|
}
|
|
|
|
Future<void> updateEnquriy({
|
|
required BuildContext context,
|
|
required String url,
|
|
required String name,
|
|
required String number,
|
|
required String email,
|
|
required String message,
|
|
required String serviceid,
|
|
}) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
final request = http.MultipartRequest('POST', Uri.parse(url));
|
|
request.fields['user_id'] = userId;
|
|
request.fields['name'] = name;
|
|
request.fields['mobile'] = number;
|
|
request.fields['email'] = email;
|
|
request.fields['message'] = message;
|
|
request.fields['service_id'] = serviceid;
|
|
|
|
final response = await request.send();
|
|
if (response.statusCode == 200) {
|
|
Fluttertoast.showToast(
|
|
msg: "Enquiry Successful",
|
|
toastLength: Toast.LENGTH_SHORT,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
} else {
|
|
Fluttertoast.showToast(
|
|
msg: "Failed to update profile",
|
|
toastLength: Toast.LENGTH_LONG,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
throw Exception('Failed to update profile');
|
|
}
|
|
}
|
|
}
|
|
|
|
class BookingRepository {
|
|
Future<List<BookingModel>> fetchBooking(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
if (userId.isEmpty) throw Exception('User ID is not available.');
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
return list.map((e) => BookingModel.fromJson(e)).toList();
|
|
} else {
|
|
throw Exception(
|
|
'Failed to load booking data. Code: ${response.statusCode}',
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> updateBooking({
|
|
required BuildContext context,
|
|
required String url,
|
|
required String name,
|
|
required String number,
|
|
required String email,
|
|
required String message,
|
|
required String address,
|
|
required String date,
|
|
required String time,
|
|
required String serviceId,
|
|
}) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
if (userId.isEmpty) {
|
|
Fluttertoast.showToast(
|
|
msg: "User ID not found",
|
|
toastLength: Toast.LENGTH_SHORT,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
return;
|
|
}
|
|
|
|
final request = http.MultipartRequest('POST', Uri.parse(url));
|
|
request.fields['user_id'] = userId;
|
|
request.fields['name'] = name;
|
|
request.fields['mobile_number'] = number;
|
|
request.fields['email'] = email;
|
|
request.fields['message'] = message;
|
|
request.fields['service_id'] = serviceId;
|
|
request.fields['address'] = address;
|
|
request.fields['service_date'] = date;
|
|
request.fields['service_time'] = time;
|
|
|
|
final response = await request.send();
|
|
final responseBody = await response.stream.bytesToString();
|
|
final jsonResponse = jsonDecode(responseBody);
|
|
|
|
if (response.statusCode == 200) {
|
|
Fluttertoast.showToast(
|
|
msg: "Booking Successful",
|
|
toastLength: Toast.LENGTH_SHORT,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
} else if (response.statusCode == 404 &&
|
|
jsonResponse['data'] == 'You can book maximum 1 services.') {
|
|
Fluttertoast.showToast(
|
|
msg: jsonResponse['data'],
|
|
toastLength: Toast.LENGTH_LONG,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
} else {
|
|
Fluttertoast.showToast(
|
|
msg:
|
|
jsonResponse['data'] ??
|
|
'Failed to submit enquiry. Code: ${response.statusCode}',
|
|
toastLength: Toast.LENGTH_LONG,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
throw Exception('Failed to update booking');
|
|
}
|
|
}
|
|
}
|
|
|
|
// ignore: camel_case_types
|
|
class updatereviewRepository {
|
|
Future<List<GetReviewModel>> updatereview(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
if (userId.isEmpty) throw Exception('User ID is not available.');
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
return list.map((e) => GetReviewModel.fromJson(e)).toList();
|
|
} else {
|
|
throw Exception(
|
|
'Failed to load booking data. Code: ${response.statusCode}',
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> updatereviews({
|
|
required BuildContext context,
|
|
required String url,
|
|
required String review,
|
|
required String serviceId,
|
|
}) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
if (userId.isEmpty) {
|
|
Fluttertoast.showToast(
|
|
msg: "User ID not found",
|
|
toastLength: Toast.LENGTH_SHORT,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
return;
|
|
}
|
|
|
|
final request = http.MultipartRequest('POST', Uri.parse(url));
|
|
request.fields['user_id'] = userId;
|
|
request.fields['review'] = review;
|
|
|
|
request.fields['service_id'] = serviceId;
|
|
|
|
final response = await request.send();
|
|
final responseBody = await response.stream.bytesToString();
|
|
final jsonResponse = jsonDecode(responseBody);
|
|
|
|
if (response.statusCode == 200) {
|
|
Fluttertoast.showToast(
|
|
msg: "Review submitted successfully",
|
|
toastLength: Toast.LENGTH_SHORT,
|
|
gravity: ToastGravity.BOTTOM,
|
|
backgroundColor: Colors.green,
|
|
textColor: Colors.white,
|
|
);
|
|
} else {
|
|
Fluttertoast.showToast(
|
|
msg:
|
|
jsonResponse['data'] ??
|
|
'Failed to submit review. Code: ${response.statusCode}',
|
|
toastLength: Toast.LENGTH_LONG,
|
|
gravity: ToastGravity.BOTTOM,
|
|
backgroundColor: Colors.red,
|
|
textColor: Colors.white,
|
|
);
|
|
throw Exception('Failed to update review');
|
|
}
|
|
}
|
|
}
|
|
|
|
class enquriylistRepository {
|
|
Future<List<EnquiryListModel>> fetchenquirylist(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
if (userId.isEmpty) throw Exception('User ID is not available.');
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
return list.map((e) => EnquiryListModel.fromJson(e)).toList();
|
|
} else {
|
|
throw Exception(
|
|
'Failed to load booking data. Code: ${response.statusCode}',
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
class EnquriydeleteRepository {
|
|
Future<bool> enquriydelete(String url, String id) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId, 'id': id}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
// Assuming your API returns a success flag or message
|
|
// Adjust this based on your actual API response
|
|
return jsonBody['success'] == true ||
|
|
jsonBody['status'] == 'success' ||
|
|
jsonBody['message']?.toLowerCase().contains('success') == true;
|
|
} else {
|
|
throw Exception('Failed to delete enquiry');
|
|
}
|
|
}
|
|
}
|
|
|
|
class PaymentdetailsRepository {
|
|
Future<List<PaymentDetailsModel>> fetchpayment(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
|
|
final List<dynamic> dataList = jsonBody['data'] ?? [];
|
|
return dataList
|
|
.map((json) => PaymentDetailsModel.fromJson(json))
|
|
.toList();
|
|
} else {
|
|
throw Exception('Failed to fetch payment details');
|
|
}
|
|
}
|
|
}
|
|
|
|
class PaymentdeleteRepository {
|
|
Future<bool> paymentdelete(String url, String id) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId, 'id': id}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
// Assuming your API returns a success flag or message
|
|
// Adjust this based on your actual API response
|
|
return jsonBody['success'] == true ||
|
|
jsonBody['status'] == 'success' ||
|
|
jsonBody['message']?.toLowerCase().contains('success') == true;
|
|
} else {
|
|
throw Exception('Failed to delete payment Details');
|
|
}
|
|
}
|
|
}
|
|
|
|
class ChangepasswordRepository {
|
|
Future<bool> changepassword(String url, String password) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId, 'password': password}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
// Assuming your API returns a success flag or message
|
|
// Adjust this based on your actual API response
|
|
return jsonBody['success'] == true ||
|
|
jsonBody['status'] == 'success' ||
|
|
jsonBody['message']?.toLowerCase().contains('success') == true;
|
|
} else {
|
|
throw Exception('Failed to changepassword');
|
|
}
|
|
}
|
|
}
|
|
|
|
class UserhistoryBookingdetailsRepository {
|
|
Future<List<UserBookingDetails>> fetchhistorybooking(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
print(response.body);
|
|
print(jsonBody);
|
|
|
|
final List<dynamic> dataList = jsonBody['data'] ?? [];
|
|
return dataList.map((json) => UserBookingDetails.fromJson(json)).toList();
|
|
} else {
|
|
throw Exception('Failed to fetch payment details');
|
|
}
|
|
}
|
|
}
|
|
|
|
class CancelbookingRepository {
|
|
Future<bool> cancelbooking({
|
|
required String url,
|
|
required String id,
|
|
required String serviceId,
|
|
required String type,
|
|
}) async {
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'id': id, 'service_id': serviceId, 'type': type}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
return jsonBody['success'] == true ||
|
|
jsonBody['status'] == 'success' ||
|
|
jsonBody['message']?.toLowerCase().contains('success') == true;
|
|
} else {
|
|
throw Exception('Failed to cancel booking');
|
|
}
|
|
}
|
|
}
|
|
|
|
class BookingmodifyRepository {
|
|
Future<bool> bookingmodify({
|
|
required String url,
|
|
required String id,
|
|
required String serviceId,
|
|
required String servicedate,
|
|
required String servicetime,
|
|
}) async {
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({
|
|
'id': id,
|
|
'service_id': serviceId,
|
|
'service_date': servicedate,
|
|
'service_time': servicetime,
|
|
}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
return jsonBody['success'] == true ||
|
|
jsonBody['status'] == 'success' ||
|
|
jsonBody['message']?.toLowerCase().contains('success') == true;
|
|
} else {
|
|
throw Exception('Failed to modify');
|
|
}
|
|
}
|
|
}
|
|
|
|
class ExpiredPlanRepository {
|
|
Future<ExpiredPlanModel> fetchExpiredPlan(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final Map<String, dynamic> data = jsonBody['data'] ?? {};
|
|
return ExpiredPlanModel.fromJson(data);
|
|
} else {
|
|
throw Exception('Failed to fetch expired plan');
|
|
}
|
|
}
|
|
}
|
|
|
|
class PlanSuccessRepository {
|
|
Future<bool> planSuccess({
|
|
required String url,
|
|
required String userId,
|
|
required String planId,
|
|
required int duration,
|
|
required int type,
|
|
}) async {
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({
|
|
'user_id': userId,
|
|
'plan_id': planId,
|
|
'duration': duration.toString(),
|
|
'type': type.toString(),
|
|
}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
return jsonBody['success'] == true ||
|
|
jsonBody['status'] == 'success' ||
|
|
jsonBody['message']?.toLowerCase().contains('success') == true;
|
|
} else {
|
|
throw Exception('Failed to subscribe to plan');
|
|
}
|
|
}
|
|
}
|
|
|
|
////vendor flow
|
|
class GetvendorId {
|
|
Future fetchGetid(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final data = jsonBody['data'];
|
|
|
|
// Extract and store vendor_id and vendor_status if not null
|
|
if (data != null) {
|
|
final vendorId = data['vendor_id']?.toString() ?? '';
|
|
final vendorStatus = data['vendor_status']?.toString() ?? '';
|
|
|
|
await prefs.setString('vendor_id', vendorId);
|
|
await prefs.setString('vendor_status', vendorStatus);
|
|
|
|
print('Stored vendor_id: $vendorId');
|
|
print('Stored vendor_status: $vendorStatus');
|
|
}
|
|
|
|
return data;
|
|
} else {
|
|
throw Exception('Failed to fetch vendor data');
|
|
}
|
|
}
|
|
}
|
|
|
|
class VendorRegister {
|
|
Future<Map<String, dynamic>> vendorRegister(
|
|
String url,
|
|
VendorRegisterModel vendorModel,
|
|
) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('userId') ?? '';
|
|
|
|
vendorModel.userId = userId; // inject userId into the model
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode(vendorModel.toJson()),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final decoded = jsonDecode(response.body);
|
|
print('Decoded Response: $decoded');
|
|
return decoded;
|
|
} else {
|
|
throw Exception('Register failed: ${response.body}');
|
|
}
|
|
}
|
|
}
|
|
|
|
class VendorGetProfile {
|
|
Future<Map<String, dynamic>> vendorGetProfile(String url) async {
|
|
try {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final dataId = prefs.getString('vendor_id') ?? '';
|
|
|
|
if (dataId.isEmpty) {
|
|
throw Exception('Data ID not found in SharedPreferences.');
|
|
}
|
|
|
|
final body = jsonEncode({'dataId': dataId});
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: body,
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final decoded = jsonDecode(response.body);
|
|
print('Decoded Response: $decoded');
|
|
return decoded; // Return the decoded response directly
|
|
} else {
|
|
throw Exception(
|
|
'Get profile failed with status ${response.statusCode}: ${response.body}',
|
|
);
|
|
}
|
|
} catch (e) {
|
|
print('Error in vendorGetProfile: $e');
|
|
rethrow;
|
|
}
|
|
}
|
|
}
|
|
|
|
class Vendorserviceupload {
|
|
Future<Map<String, dynamic>> vendorserviceupload(
|
|
String url,
|
|
VendorServiceUploadModel serviceupload,
|
|
List<File> images,
|
|
) async {
|
|
try {
|
|
// Create a multipart request for uploading files and data
|
|
var request = http.MultipartRequest('POST', Uri.parse(url));
|
|
|
|
// Add service data as fields
|
|
request.fields['vendor_id'] = serviceupload.id;
|
|
request.fields['vendorname'] = serviceupload.vendorName;
|
|
request.fields['servicename'] = serviceupload.serviceName;
|
|
request.fields['service_type'] = serviceupload.serviceType;
|
|
request.fields['category'] = serviceupload.category;
|
|
request.fields['subcategory'] = serviceupload.subcategory;
|
|
request.fields['workinghours'] = serviceupload.workingHours;
|
|
request.fields['workingduration'] = serviceupload.workingDuration;
|
|
request.fields['amount'] = serviceupload.amount.toString();
|
|
request.fields['location'] = serviceupload.location;
|
|
request.fields['description'] = serviceupload.description ?? '';
|
|
request.fields['details'] = serviceupload.details;
|
|
|
|
// Add video links as JSON array
|
|
if (serviceupload.videos.isNotEmpty) {
|
|
request.fields['videos'] = jsonEncode(serviceupload.videos);
|
|
}
|
|
|
|
// Add images as files with array notation
|
|
for (int i = 0; i < images.length; i++) {
|
|
final file = images[i];
|
|
final fileName =
|
|
'image_${i}_${DateTime.now().millisecondsSinceEpoch}.jpg';
|
|
|
|
// Get file extension from path
|
|
String extension = file.path.split('.').last.toLowerCase();
|
|
String mimeType = 'image/jpeg'; // Default
|
|
|
|
// Set correct mime type based on extension
|
|
if (extension == 'png') {
|
|
mimeType = 'image/png';
|
|
} else if (extension == 'jpg' || extension == 'jpeg') {
|
|
mimeType = 'image/jpeg';
|
|
} else if (extension == 'gif') {
|
|
mimeType = 'image/gif';
|
|
} else if (extension == 'webp') {
|
|
mimeType = 'image/webp';
|
|
}
|
|
|
|
// Add the file to the request with indexed array notation
|
|
request.files.add(
|
|
http.MultipartFile(
|
|
'images[$i]', // Indexed array notation for multiple images
|
|
file.readAsBytes().asStream(),
|
|
file.lengthSync(),
|
|
filename: fileName,
|
|
contentType: MediaType.parse(mimeType),
|
|
),
|
|
);
|
|
}
|
|
|
|
// Send the request
|
|
var streamedResponse = await request.send();
|
|
var response = await http.Response.fromStream(streamedResponse);
|
|
|
|
// Parse response regardless of status code
|
|
try {
|
|
final decoded = jsonDecode(response.body) as Map<String, dynamic>;
|
|
print('Decoded Response: $decoded');
|
|
|
|
// Check if request was successful
|
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
|
return decoded;
|
|
} else {
|
|
// For failed requests, extract error message
|
|
String errorMessage =
|
|
decoded['data']?.toString() ??
|
|
decoded['message']?.toString() ??
|
|
'Upload failed with status: ${response.statusCode}';
|
|
|
|
// Return the error response for handling upstream
|
|
return {
|
|
'success': false,
|
|
'error': errorMessage,
|
|
'statusCode': response.statusCode,
|
|
'data': decoded,
|
|
};
|
|
}
|
|
} catch (jsonError) {
|
|
// If JSON parsing fails, use raw response
|
|
String errorMessage =
|
|
'Request failed with status: ${response.statusCode}. Response: ${response.body}';
|
|
|
|
Fluttertoast.showToast(
|
|
msg: 'Server response error',
|
|
toastLength: Toast.LENGTH_SHORT,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
|
|
throw Exception(errorMessage);
|
|
}
|
|
} on SocketException catch (e) {
|
|
String errorMessage = 'No internet connection: ${e.message}';
|
|
Fluttertoast.showToast(
|
|
msg: 'No internet connection',
|
|
toastLength: Toast.LENGTH_SHORT,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
throw Exception(errorMessage);
|
|
} on http.ClientException catch (e) {
|
|
String errorMessage = 'Network error: ${e.message}';
|
|
Fluttertoast.showToast(
|
|
msg: 'Network error occurred',
|
|
toastLength: Toast.LENGTH_SHORT,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
throw Exception(errorMessage);
|
|
} on FormatException catch (e) {
|
|
String errorMessage = 'Invalid response format: ${e.message}';
|
|
Fluttertoast.showToast(
|
|
msg: 'Invalid server response',
|
|
toastLength: Toast.LENGTH_SHORT,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
throw Exception(errorMessage);
|
|
} catch (e) {
|
|
String errorMessage = 'Unexpected error: $e';
|
|
Fluttertoast.showToast(
|
|
msg: 'Something went wrong',
|
|
toastLength: Toast.LENGTH_SHORT,
|
|
gravity: ToastGravity.BOTTOM,
|
|
);
|
|
throw Exception(errorMessage);
|
|
}
|
|
}
|
|
}
|
|
|
|
class VendorbookingdetailsRepository {
|
|
Future<List<VendorBookingModel>> fetchvendorbooking(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('vendor_id') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'vendor_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
print(response.body);
|
|
print(jsonBody);
|
|
|
|
final List<dynamic> dataList = jsonBody['data'] ?? [];
|
|
return dataList.map((json) => VendorBookingModel.fromJson(json)).toList();
|
|
} else {
|
|
throw Exception('Failed to fetch booking details');
|
|
}
|
|
}
|
|
}
|
|
|
|
class ChangebookingstatusRepository {
|
|
Future<bool> changebooking({
|
|
required String url,
|
|
required String id,
|
|
required String status,
|
|
}) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('vendor_id') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'id': id, 'user_id': userId, 'status': status}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
return jsonBody['success'] == true ||
|
|
jsonBody['status'] == 'success' ||
|
|
jsonBody['message']?.toLowerCase().contains('success') == true;
|
|
} else {
|
|
throw Exception('Failed to update booking status');
|
|
}
|
|
}
|
|
}
|
|
|
|
class VendorcatgoriesRepository {
|
|
Future<List<VendorCategoriesModel>> fetchvendorcat(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('vendor_id') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'vendor_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
|
|
final List<dynamic> dataList = jsonBody['data'] ?? [];
|
|
return dataList
|
|
.map((json) => VendorCategoriesModel.fromJson(json))
|
|
.toList();
|
|
} else {
|
|
throw Exception('Failed to fetch booking details');
|
|
}
|
|
}
|
|
}
|
|
|
|
class VendorserviceRepository {
|
|
Future<List<VendorServiceModel>> fetchvendorservice(String url) async {
|
|
try {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('vendor_id') ?? '';
|
|
|
|
if (userId.isEmpty) {
|
|
throw Exception('Vendor ID not found in SharedPreferences');
|
|
}
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'vendor_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
|
|
// Add more detailed logging
|
|
|
|
if (jsonBody['data'] == null) {
|
|
return [];
|
|
}
|
|
|
|
final List<dynamic> dataList = jsonBody['data'] ?? [];
|
|
return dataList
|
|
.map((json) => VendorServiceModel.fromJson(json))
|
|
.toList();
|
|
} else {
|
|
throw Exception(
|
|
'Failed to fetch service details: ${response.statusCode}',
|
|
);
|
|
}
|
|
} catch (e) {
|
|
throw Exception('Failed to fetch service details: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Updated API Service Class
|
|
class Vendorserviceupadate {
|
|
Future<Map<String, dynamic>> vendorserviceupdate(
|
|
String url,
|
|
VendorServiceUploadModel serviceupload,
|
|
List<File> newImages,
|
|
) async {
|
|
try {
|
|
var request = http.MultipartRequest('POST', Uri.parse(url));
|
|
|
|
// Add all basic fields
|
|
request.fields.addAll({
|
|
'id': serviceupload.id,
|
|
'vendorname': serviceupload.vendorName,
|
|
'servicename': serviceupload.serviceName,
|
|
'service_type': serviceupload.serviceType,
|
|
'category': serviceupload.category,
|
|
'subcategory': serviceupload.subcategory,
|
|
'workinghours': serviceupload.workingHours,
|
|
'workingduration': serviceupload.workingDuration,
|
|
'amount': serviceupload.amount.toString(),
|
|
'location': serviceupload.location,
|
|
'description': serviceupload.description ?? '',
|
|
'details': serviceupload.details,
|
|
});
|
|
|
|
// Handle videos - send as JSON string
|
|
if (serviceupload.videos.isNotEmpty) {
|
|
request.fields['videos'] = jsonEncode(serviceupload.videos);
|
|
print('Videos JSON: ${request.fields['videos']}');
|
|
}
|
|
|
|
// Process ALL images (existing + new) as multipart files
|
|
List<File> allImageFiles = [];
|
|
|
|
// Step 1: Convert existing images (URLs) to files if needed
|
|
if (serviceupload.images.isNotEmpty) {
|
|
print('Processing ${serviceupload.images.length} existing images...');
|
|
|
|
for (int i = 0; i < serviceupload.images.length; i++) {
|
|
final imageUrl = serviceupload.images[i];
|
|
print('Processing existing image $i: $imageUrl');
|
|
|
|
try {
|
|
// If it's already a local file path
|
|
if (imageUrl.startsWith('/') || imageUrl.startsWith('file://')) {
|
|
final file = File(imageUrl.replaceFirst('file://', ''));
|
|
if (await file.exists()) {
|
|
allImageFiles.add(file);
|
|
} else {
|
|
print('⚠ Existing file not found: ${file.path}');
|
|
}
|
|
}
|
|
// If it's a URL, download it
|
|
else if (imageUrl.startsWith('http')) {
|
|
final downloadedFile = await _downloadImageAsFile(imageUrl, i);
|
|
if (downloadedFile != null) {
|
|
allImageFiles.add(downloadedFile);
|
|
print(
|
|
'✓ Downloaded and added existing image: ${downloadedFile.path}',
|
|
);
|
|
} else {
|
|
print('⚠ Failed to download existing image: $imageUrl');
|
|
}
|
|
}
|
|
// If it's a relative path or asset
|
|
else {
|
|
print('⚠ Unsupported existing image format: $imageUrl');
|
|
}
|
|
} catch (e) {
|
|
print('⚠ Error processing existing image $imageUrl: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Step 2: Add new images to the list
|
|
allImageFiles.addAll(newImages);
|
|
|
|
print('Total images to upload: ${allImageFiles.length}');
|
|
|
|
// Step 3: Upload all images with same field name 'images[]'
|
|
if (allImageFiles.isNotEmpty) {
|
|
print('Processing ${allImageFiles.length} total images for upload...');
|
|
|
|
for (int i = 0; i < allImageFiles.length; i++) {
|
|
final file = allImageFiles[i];
|
|
|
|
// Validate file exists
|
|
if (!await file.exists()) {
|
|
print('WARNING: File does not exist: ${file.path}');
|
|
continue;
|
|
}
|
|
|
|
// Get file info
|
|
final fileSize = await file.length();
|
|
final fileName = file.path.split('/').last;
|
|
final extension = fileName.split('.').last.toLowerCase();
|
|
|
|
print('Processing file $i: $fileName ($fileSize bytes)');
|
|
|
|
// Validate file size (5MB limit)
|
|
if (fileSize > 5 * 1024 * 1024) {
|
|
continue;
|
|
}
|
|
|
|
// Determine MIME type
|
|
String mimeType;
|
|
switch (extension) {
|
|
case 'png':
|
|
mimeType = 'image/png';
|
|
break;
|
|
case 'jpg':
|
|
case 'jpeg':
|
|
mimeType = 'image/jpeg';
|
|
break;
|
|
case 'gif':
|
|
mimeType = 'image/gif';
|
|
break;
|
|
case 'webp':
|
|
mimeType = 'image/webp';
|
|
break;
|
|
default:
|
|
mimeType = 'image/jpeg';
|
|
}
|
|
|
|
// Create unique filename for upload
|
|
final uploadFileName =
|
|
'upload_${DateTime.now().millisecondsSinceEpoch}_$i.$extension';
|
|
|
|
try {
|
|
// Method 1: Try fromPath (preferred)
|
|
var multipartFile = await http.MultipartFile.fromPath(
|
|
'images[]', // All images use same field name
|
|
file.path,
|
|
filename: uploadFileName,
|
|
contentType: MediaType.parse(mimeType),
|
|
);
|
|
|
|
request.files.add(multipartFile);
|
|
} catch (fromPathError) {
|
|
// Method 2: Fallback to fromBytes
|
|
try {
|
|
final bytes = await file.readAsBytes();
|
|
var multipartFile = http.MultipartFile.fromBytes(
|
|
'images[]',
|
|
bytes,
|
|
filename: uploadFileName,
|
|
contentType: MediaType.parse(mimeType),
|
|
);
|
|
|
|
request.files.add(multipartFile);
|
|
// ignore: empty_catches
|
|
} catch (fromBytesError) {}
|
|
}
|
|
}
|
|
} else {
|
|
print('No images to upload');
|
|
}
|
|
|
|
// Add headers
|
|
request.headers.addAll({
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'multipart/form-data',
|
|
});
|
|
|
|
// Debug request info
|
|
print('=== REQUEST SUMMARY ===');
|
|
print('Fields: ${request.fields.keys.toList()}');
|
|
print('Files: ${request.files.length}');
|
|
for (var file in request.files) {
|
|
print(
|
|
' - Field: ${file.field}, Filename: ${file.filename}, Length: ${file.length}',
|
|
);
|
|
}
|
|
|
|
// Send request with timeout
|
|
print('Sending request...');
|
|
var streamedResponse = await request.send().timeout(
|
|
Duration(seconds: 120), // 2 minute timeout for large uploads
|
|
onTimeout: () {
|
|
throw TimeoutException('Upload timeout after 2 minutes');
|
|
},
|
|
);
|
|
|
|
var response = await http.Response.fromStream(streamedResponse);
|
|
|
|
print('=== RESPONSE INFO ===');
|
|
print('Status Code: ${response.statusCode}');
|
|
print('Response Headers: ${response.headers}');
|
|
print('Response Body Length: ${response.body.length}');
|
|
print(
|
|
'Response Body Preview: ${response.body.length > 500 ? "${response.body.substring(0, 500)}..." : response.body}',
|
|
);
|
|
|
|
// Handle response
|
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
|
try {
|
|
final decoded = jsonDecode(response.body) as Map<String, dynamic>;
|
|
print('✓ Successfully parsed JSON response');
|
|
return decoded;
|
|
} catch (jsonError) {
|
|
print('⚠ JSON parsing failed: $jsonError');
|
|
// Return success with raw response if JSON parsing fails but status is OK
|
|
return {
|
|
'success': true,
|
|
'message': 'Update completed successfully',
|
|
'raw_response': response.body,
|
|
};
|
|
}
|
|
} else {
|
|
// Handle error response
|
|
String errorMessage;
|
|
try {
|
|
final errorResponse = jsonDecode(response.body);
|
|
errorMessage =
|
|
errorResponse['message'] ??
|
|
errorResponse['error'] ??
|
|
'Server returned status ${response.statusCode}';
|
|
} catch (e) {
|
|
errorMessage =
|
|
'Server error (${response.statusCode}): ${response.body}';
|
|
}
|
|
|
|
print('✗ Server error: $errorMessage');
|
|
throw Exception(errorMessage);
|
|
}
|
|
} on TimeoutException catch (e) {
|
|
print('✗ Timeout error: $e');
|
|
throw Exception(
|
|
'Upload timeout. Please check your connection and try again.',
|
|
);
|
|
} on SocketException catch (e) {
|
|
print('✗ Network error: $e');
|
|
throw Exception('Network error. Please check your internet connection.');
|
|
} on http.ClientException catch (e) {
|
|
print('✗ HTTP client error: $e');
|
|
throw Exception('Connection error: ${e.message}');
|
|
} catch (e) {
|
|
print('✗ Unexpected error: $e');
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
// Helper method to download existing images from URLs
|
|
Future<File?> _downloadImageAsFile(String imageUrl, int index) async {
|
|
try {
|
|
final response = await http.get(Uri.parse(imageUrl));
|
|
|
|
if (response.statusCode == 200) {
|
|
// Get app's temporary directory
|
|
final directory = await getTemporaryDirectory();
|
|
|
|
// Determine file extension from URL or content type
|
|
String extension = 'jpg';
|
|
if (imageUrl.contains('.png')) {
|
|
extension = 'png';
|
|
} else if (imageUrl.contains('.gif'))
|
|
extension = 'gif';
|
|
else if (imageUrl.contains('.webp'))
|
|
extension = 'webp';
|
|
else if (response.headers['content-type']?.contains('png') == true)
|
|
extension = 'png';
|
|
|
|
// Create temporary file
|
|
final fileName =
|
|
'existing_image_${index}_${DateTime.now().millisecondsSinceEpoch}.$extension';
|
|
final file = File('${directory.path}/$fileName');
|
|
|
|
// Write downloaded bytes to file
|
|
await file.writeAsBytes(response.bodyBytes);
|
|
|
|
return file;
|
|
} else {
|
|
print('Failed to download image: ${response.statusCode}');
|
|
return null;
|
|
}
|
|
} catch (e) {
|
|
print('Error downloading image $imageUrl: $e');
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Image Upload Helper Class
|
|
class ImageUploadHelper {
|
|
static Future<List<File>> pickMultipleImages() async {
|
|
try {
|
|
final picker = ImagePicker();
|
|
final List<XFile> pickedFiles = await picker.pickMultiImage(
|
|
maxWidth: 1920,
|
|
maxHeight: 1920,
|
|
imageQuality: 85,
|
|
);
|
|
|
|
List<File> validFiles = [];
|
|
|
|
for (XFile xFile in pickedFiles) {
|
|
File file = File(xFile.path);
|
|
|
|
if (await validateImageFile(file)) {
|
|
validFiles.add(file);
|
|
} else {
|
|
print('Invalid image file: ${xFile.name}');
|
|
}
|
|
}
|
|
|
|
return validFiles;
|
|
} catch (e) {
|
|
print('Error picking images: $e');
|
|
return [];
|
|
}
|
|
}
|
|
|
|
static Future<bool> validateImageFile(File file) async {
|
|
try {
|
|
if (!await file.exists()) {
|
|
print('File does not exist: ${file.path}');
|
|
return false;
|
|
}
|
|
|
|
// Check file size (max 5MB)
|
|
int fileSize = await file.length();
|
|
if (fileSize > 5 * 1024 * 1024) {
|
|
print('File too large: ${file.path} ($fileSize bytes)');
|
|
return false;
|
|
}
|
|
|
|
// Check file extension
|
|
String extension = file.path.split('.').last.toLowerCase();
|
|
List<String> validExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
|
|
|
if (!validExtensions.contains(extension)) {
|
|
print('Invalid file extension: $extension');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
} catch (e) {
|
|
print('Error validating file: $e');
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
class VendorExpiredPlanRepository {
|
|
Future<ExpiredPlanModel> fetchvendorExpiredPlan(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('vendor_id') ?? '';
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'user_id': userId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final Map<String, dynamic> data = jsonBody['data'] ?? {};
|
|
return ExpiredPlanModel.fromJson(data);
|
|
} else {
|
|
throw Exception('Failed to fetch expired plan');
|
|
}
|
|
}
|
|
}
|
|
|
|
class DetailpageRepository {
|
|
Future<List<DetailPageModel>> fetchDetailpage(
|
|
String url,
|
|
int serviceid,
|
|
) async {
|
|
final response = await http.get(
|
|
Uri.parse('$url?service_id=$serviceid'),
|
|
headers: {'Content-Type': 'application/json'},
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final data = jsonBody['data'];
|
|
|
|
// Handle single object or list
|
|
if (data is List) {
|
|
return data.map((e) => DetailPageModel.fromJson(e)).toList();
|
|
} else if (data is Map<String, dynamic>) {
|
|
return [DetailPageModel.fromJson(data)];
|
|
} else {
|
|
return [];
|
|
}
|
|
} else {
|
|
throw Exception('Failed to load detail page');
|
|
}
|
|
}
|
|
}
|
|
|
|
class CatManagementDeleteRepository {
|
|
Future<bool> deleteCategoryManagement(String url, String categoryId) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final vendorId = prefs.getString('vendor_id') ?? '';
|
|
|
|
try {
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'vendor_id': vendorId, 'category': categoryId}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
return jsonBody['success'] == true ||
|
|
jsonBody['status'] == 'success' ||
|
|
jsonBody['message']?.toLowerCase().contains('success') == true;
|
|
} else {
|
|
throw Exception('Failed to delete category: ${response.statusCode}');
|
|
}
|
|
} catch (e) {
|
|
throw Exception('Network error: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
class SerciceDeleteRepository {
|
|
Future<bool> deleteService(String url, String id) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final vendorId = prefs.getString('vendor_id') ?? '';
|
|
|
|
try {
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'vendor_id': vendorId, 'id': id}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
return jsonBody['success'] == true ||
|
|
jsonBody['status'] == 'success' ||
|
|
jsonBody['message']?.toLowerCase().contains('success') == true;
|
|
} else {
|
|
throw Exception('Failed to delete service: ${response.statusCode}');
|
|
}
|
|
} catch (e) {
|
|
throw Exception('Network error: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
class ProfilegetvendorRepository {
|
|
Future<List<ProfileGetModel>> fetchprofilegetvendor(String url) async {
|
|
// Retrieve userId from SharedPreferences
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final vendorid = prefs.getString('vendor_id') ?? '';
|
|
|
|
// Debugging: Print the userId to make sure it's correct
|
|
print('vendor_id: $vendorid');
|
|
|
|
// Check if userId is available before making the request
|
|
if (vendorid.isEmpty) {
|
|
throw Exception('User ID is not available.');
|
|
}
|
|
|
|
// Send the userId in the API request
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'vendor_id': vendorid}),
|
|
);
|
|
|
|
// Check if the response status code is successful
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
|
|
// Convert the JSON response to a list of ProfileGetModel objects
|
|
return list.map((e) => ProfileGetModel.fromJson(e)).toList();
|
|
} else {
|
|
// Handle API errors
|
|
throw Exception(
|
|
'Failed to load profile data, status code: ${response.statusCode}',
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
class ProfileupdatevendorRepository {
|
|
Future<List<VendorProfileModel>> fetchProfileupdatevendor(String url) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final vendorid = prefs.getString('vendor_id') ?? '';
|
|
|
|
if (vendorid.isEmpty) throw Exception('User ID is not available.');
|
|
|
|
final response = await http.post(
|
|
Uri.parse(url),
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'vendor_id': vendorid}),
|
|
);
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
final List<dynamic> list = jsonBody['data'] ?? [];
|
|
return list.map((e) => VendorProfileModel.fromJson(e)).toList();
|
|
} else {
|
|
throw Exception('Failed to load profile, code: ${response.statusCode}');
|
|
}
|
|
}
|
|
|
|
Future<void> updateProfilevendor({
|
|
required String url,
|
|
required String name,
|
|
required String number,
|
|
required String email,
|
|
required String address,
|
|
File? imageFile,
|
|
}) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final userId = prefs.getString('vendor_id') ?? '';
|
|
|
|
final request = http.MultipartRequest('POST', Uri.parse(url));
|
|
request.fields['vendor_id'] = userId;
|
|
request.fields['name'] = name;
|
|
request.fields['number'] = number;
|
|
request.fields['email'] = email;
|
|
request.fields['address'] = address;
|
|
|
|
if (imageFile != null) {
|
|
request.files.add(
|
|
await http.MultipartFile.fromPath(
|
|
'profile_pic', // Make sure this matches your backend key
|
|
imageFile.path,
|
|
contentType: MediaType('image', 'jpeg'), // Optional but recommended
|
|
),
|
|
);
|
|
}
|
|
|
|
final response = await request.send();
|
|
|
|
if (response.statusCode != 200) {
|
|
throw Exception('Failed to update profile');
|
|
}
|
|
}
|
|
}
|
|
|
|
class TermsAndConditionsRepository {
|
|
Future<TermsAndConditionsModel> fetchTermsAndCondition(String url) async {
|
|
try {
|
|
final response = await http.get(Uri.parse(url));
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
return TermsAndConditionsModel.fromJson(jsonBody);
|
|
} else {
|
|
throw Exception(
|
|
'Failed to load terms and conditions, status code: ${response.statusCode}',
|
|
);
|
|
}
|
|
} catch (e) {
|
|
throw Exception('Failed to fetch terms and conditions: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
class PrivacypolicyRepository {
|
|
Future<TermsAndConditionsModel> fetchPrivacypolicy(String url) async {
|
|
try {
|
|
final response = await http.get(Uri.parse(url));
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
return TermsAndConditionsModel.fromJson(jsonBody);
|
|
} else {
|
|
throw Exception(
|
|
'Failed to load terms and conditions, status code: ${response.statusCode}',
|
|
);
|
|
}
|
|
} catch (e) {
|
|
throw Exception('Failed to fetch terms and conditions: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
class NotificationRepository {
|
|
Future<List<NotificationModel>> fetchNotification({
|
|
required int type,
|
|
required String userId,
|
|
}) async {
|
|
try {
|
|
final uri = Uri.parse(ConstsApi.notification);
|
|
|
|
final response = await http.post(
|
|
uri,
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: jsonEncode({'type': type, 'user_id': userId}),
|
|
);
|
|
|
|
print('Fetching notification from: $uri');
|
|
print('Status Code: ${response.statusCode}');
|
|
print('Response Body: ${response.body}');
|
|
|
|
if (response.statusCode == 200) {
|
|
final jsonBody = jsonDecode(response.body);
|
|
|
|
// Handle if data is inside "data" key
|
|
if (jsonBody is Map && jsonBody['data'] is List) {
|
|
final List dataList = jsonBody['data'];
|
|
return dataList
|
|
.map<NotificationModel>((e) => NotificationModel.fromJson(e))
|
|
.toList();
|
|
}
|
|
|
|
// Handle if directly a List
|
|
if (jsonBody is List) {
|
|
return jsonBody
|
|
.map<NotificationModel>((e) => NotificationModel.fromJson(e))
|
|
.toList();
|
|
}
|
|
|
|
return []; // no recognizable data
|
|
} else {
|
|
throw Exception('Status Code: ${response.statusCode}');
|
|
}
|
|
} catch (e) {
|
|
print('Error fetching notification: $e');
|
|
throw Exception('Failed to fetch notification: $e');
|
|
}
|
|
}
|
|
}
|