product review
This commit is contained in:
@@ -283,6 +283,12 @@
|
|||||||
"packageUri": "lib/",
|
"packageUri": "lib/",
|
||||||
"languageVersion": "3.4"
|
"languageVersion": "3.4"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "flutter_rating_bar",
|
||||||
|
"rootUri": "file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_rating_bar-4.0.1",
|
||||||
|
"packageUri": "lib/",
|
||||||
|
"languageVersion": "2.14"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "flutter_rating_stars",
|
"name": "flutter_rating_stars",
|
||||||
"rootUri": "file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_rating_stars-1.1.0",
|
"rootUri": "file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_rating_stars-1.1.0",
|
||||||
@@ -1004,7 +1010,7 @@
|
|||||||
"languageVersion": "3.4"
|
"languageVersion": "3.4"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"generated": "2025-03-21T12:45:09.442791Z",
|
"generated": "2025-03-22T13:23:26.634731Z",
|
||||||
"generator": "pub",
|
"generator": "pub",
|
||||||
"generatorVersion": "3.4.4",
|
"generatorVersion": "3.4.4",
|
||||||
"flutterRoot": "file:///Users/rajeevsingh/Documents/allSoftwares/flutter",
|
"flutterRoot": "file:///Users/rajeevsingh/Documents/allSoftwares/flutter",
|
||||||
|
|||||||
@@ -182,6 +182,10 @@ flutter_plugin_android_lifecycle
|
|||||||
3.4
|
3.4
|
||||||
file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.22/
|
file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.22/
|
||||||
file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.22/lib/
|
file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.22/lib/
|
||||||
|
flutter_rating_bar
|
||||||
|
2.14
|
||||||
|
file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_rating_bar-4.0.1/
|
||||||
|
file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_rating_bar-4.0.1/lib/
|
||||||
flutter_rating_stars
|
flutter_rating_stars
|
||||||
3.2
|
3.2
|
||||||
file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_rating_stars-1.1.0/
|
file:///Users/rajeevsingh/.pub-cache/hosted/pub.dev/flutter_rating_stars-1.1.0/
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -49,4 +49,9 @@ class APIURL {
|
|||||||
|
|
||||||
static const String updateStatus = "${BASE_URL}orders/items/";
|
static const String updateStatus = "${BASE_URL}orders/items/";
|
||||||
static const String checkAddress = "${BASE_URL}distance/by-address/";
|
static const String checkAddress = "${BASE_URL}distance/by-address/";
|
||||||
|
|
||||||
|
static const String productReview = "${BASE_URL}products/";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ class OrderProvider extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (e)
|
} catch (e) {
|
||||||
{
|
|
||||||
print("sfddsfdfff $e");
|
print("sfddsfdfff $e");
|
||||||
|
|
||||||
isloading = false;
|
isloading = false;
|
||||||
@@ -73,6 +72,44 @@ class OrderProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> productReview(
|
||||||
|
BuildContext context,
|
||||||
|
dynamic data,
|
||||||
|
String productId,
|
||||||
|
) async {
|
||||||
|
context.showLoader(show: true);
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
var result = await _orderRepo.productReview(data, productId);
|
||||||
|
|
||||||
|
return result.fold(
|
||||||
|
(error)
|
||||||
|
{
|
||||||
|
context.showLoader(show: false);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
(response)
|
||||||
|
{
|
||||||
|
context.showLoader(show: false);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} catch (e)
|
||||||
|
{
|
||||||
|
context.showLoader(show: false);
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: "Something went wrong",
|
||||||
|
toastLength: Toast.LENGTH_SHORT,
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
textColor: Colors.white,
|
||||||
|
fontSize: 14.0,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _showOtpPopup(BuildContext context, String otp) {
|
void _showOtpPopup(BuildContext context, String otp) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
|||||||
@@ -48,12 +48,19 @@ class ProfileProvider extends ChangeNotifier {
|
|||||||
Future<bool> updateProfile(
|
Future<bool> updateProfile(
|
||||||
BuildContext context, String firstName, String lastName) async {
|
BuildContext context, String firstName, String lastName) async {
|
||||||
context.showLoader(show: true);
|
context.showLoader(show: true);
|
||||||
|
var data;
|
||||||
var data = {
|
if (_uploadedUrl.isEmpty) {
|
||||||
"firstName": firstName,
|
data = {
|
||||||
"lastName": lastName,
|
"firstName": firstName,
|
||||||
"img": _uploadedUrl
|
"lastName": lastName,
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
data = {
|
||||||
|
"firstName": firstName,
|
||||||
|
"lastName": lastName,
|
||||||
|
"img": _uploadedUrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var result = await _productRepo.updateProfile(data);
|
var result = await _productRepo.updateProfile(data);
|
||||||
|
|||||||
@@ -25,12 +25,22 @@ class OrderRepo {
|
|||||||
return left(error);
|
return left(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FutureResult<String> productReview(data,id) async
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
var response = await _orderService.productReview(data,id);
|
||||||
|
|
||||||
|
String model = response.toString();
|
||||||
|
return right(model);
|
||||||
|
} on DioException catch (e)
|
||||||
|
{
|
||||||
|
var error = CustomDioExceptions.handleError(e);
|
||||||
|
return left(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FutureResult<DeliveryOtpmodel> getAssignedOtp(data) async {
|
FutureResult<DeliveryOtpmodel> getAssignedOtp(data) async {
|
||||||
try {
|
try {
|
||||||
var response = await _orderService.getAssignedOtp(data);
|
var response = await _orderService.getAssignedOtp(data);
|
||||||
|
|
||||||
@@ -56,7 +66,4 @@ class OrderRepo {
|
|||||||
return left(error);
|
return left(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ class OrderService extends ApiService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Future productReview(data,id) async {
|
||||||
|
var response = await api.post(APIURL.productReview+id+"/reviews", data: jsonEncode(data));
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -760,7 +760,8 @@ class _MycartState extends State<Mycart> {
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (provider.allitem == null) {
|
} else if (provider.allitem == null)
|
||||||
|
{
|
||||||
return Center(child: Text('🛒 Your Front Shop Cart is empty'));
|
return Center(child: Text('🛒 Your Front Shop Cart is empty'));
|
||||||
} else if (provider.allitem.items == null ||
|
} else if (provider.allitem.items == null ||
|
||||||
provider.allitem.items!.isEmpty) {
|
provider.allitem.items!.isEmpty) {
|
||||||
@@ -790,7 +791,8 @@ class _MycartState extends State<Mycart> {
|
|||||||
size: 15,
|
size: 15,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (provider.couponDataModel.data!.isNotEmpty) {
|
if (provider.couponDataModel.data!.isNotEmpty)
|
||||||
|
{
|
||||||
context.push(MyRoutes.COUPONSSCREEN,
|
context.push(MyRoutes.COUPONSSCREEN,
|
||||||
extra: provider.allitem.id);
|
extra: provider.allitem.id);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -115,8 +115,7 @@ class _EditProfileScreenState extends State<EditProfileScreen> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: imageProvider.isImageLoading
|
onTap: () async {
|
||||||
? () async {
|
|
||||||
var status = await imageProvider.updateProfile(
|
var status = await imageProvider.updateProfile(
|
||||||
context,
|
context,
|
||||||
firstController.text,
|
firstController.text,
|
||||||
@@ -126,7 +125,7 @@ class _EditProfileScreenState extends State<EditProfileScreen> {
|
|||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: null,
|
,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 50,
|
height: 50,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|||||||
@@ -103,7 +103,8 @@ class _SingnuScreenState extends State<SingnuScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: Container(
|
bottomNavigationBar:
|
||||||
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.greenAccent.withOpacity(0.1),
|
color: Colors.greenAccent.withOpacity(0.1),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:gap/gap.dart';
|
|||||||
import 'package:grocery_app/src/common_widget/network_image.dart';
|
import 'package:grocery_app/src/common_widget/network_image.dart';
|
||||||
import 'package:grocery_app/src/data/myOrder.dart';
|
import 'package:grocery_app/src/data/myOrder.dart';
|
||||||
import 'package:grocery_app/src/logic/provider/order_provider.dart';
|
import 'package:grocery_app/src/logic/provider/order_provider.dart';
|
||||||
|
import 'package:grocery_app/src/ui/product_review.dart';
|
||||||
import 'package:grocery_app/utils/extensions/extensions.dart';
|
import 'package:grocery_app/utils/extensions/extensions.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
@@ -284,26 +285,34 @@ class _OrderDetailsScreenState extends State<OrderDetailsScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
if (orderitem.orderItemStatus == "DELIVERED")
|
if (orderitem.orderItemStatus == "DELIVERED")
|
||||||
RichText(
|
RichText(
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
text: " ",
|
text: " ",
|
||||||
style: context.buttonTestStyle.copyWith(
|
style: context.buttonTestStyle.copyWith(
|
||||||
color: context.appColor.blackColor,
|
color: context.appColor.blackColor,
|
||||||
),
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: "Give Feedback",
|
|
||||||
style: context.buttonTestStyle.copyWith(
|
|
||||||
color: Colors.blue,
|
|
||||||
decoration: TextDecoration.underline,
|
|
||||||
),
|
|
||||||
recognizer: TapGestureRecognizer()
|
|
||||||
..onTap = () {},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: "Give Feedback",
|
||||||
|
style: context.buttonTestStyle.copyWith(
|
||||||
|
color: Colors.blue,
|
||||||
|
decoration: TextDecoration.underline,
|
||||||
|
),
|
||||||
|
recognizer: TapGestureRecognizer()..onTap = () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) =>
|
||||||
|
RatingScreen(orderId: orderitem.productId),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
164
lib/src/ui/product_review.dart
Normal file
164
lib/src/ui/product_review.dart
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_rating_bar/flutter_rating_bar.dart';
|
||||||
|
import 'package:grocery_app/src/logic/provider/order_provider.dart';
|
||||||
|
import 'package:grocery_app/utils/constants/color_constant.dart';
|
||||||
|
import 'package:grocery_app/utils/extensions/uicontext.dart';
|
||||||
|
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class RatingScreen extends StatefulWidget {
|
||||||
|
final String orderId;
|
||||||
|
const RatingScreen({Key? key, required this.orderId}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_RatingScreenState createState() => _RatingScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RatingScreenState extends State<RatingScreen> {
|
||||||
|
double _rating = 0.0;
|
||||||
|
final TextEditingController _titleController = TextEditingController();
|
||||||
|
final TextEditingController _descriptionController = TextEditingController();
|
||||||
|
List<File> _selectedImages = [];
|
||||||
|
|
||||||
|
Future<void> _pickImage() async {
|
||||||
|
final pickedFile =
|
||||||
|
await ImagePicker().pickImage(source: ImageSource.gallery);
|
||||||
|
if (pickedFile != null) {
|
||||||
|
setState(() {
|
||||||
|
_selectedImages.add(File(pickedFile.path));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar:
|
||||||
|
AppBar(backgroundColor: Colors.white, title: Text("Give a Rating")),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text("Rate this product:",
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
RatingBar.builder(
|
||||||
|
initialRating: 0,
|
||||||
|
minRating: 1,
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
allowHalfRating: true,
|
||||||
|
itemCount: 5,
|
||||||
|
itemPadding: EdgeInsets.symmetric(horizontal: 4.0),
|
||||||
|
itemBuilder: (context, _) =>
|
||||||
|
Icon(Icons.star, color: Colors.amber),
|
||||||
|
onRatingUpdate: (rating) {
|
||||||
|
setState(() {
|
||||||
|
_rating = rating;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
TextField(
|
||||||
|
controller: _titleController,
|
||||||
|
decoration: InputDecoration(labelText: "Title"),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
TextField(
|
||||||
|
controller: _descriptionController,
|
||||||
|
decoration: InputDecoration(labelText: "Description"),
|
||||||
|
maxLines: 3,
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
children: _selectedImages
|
||||||
|
.map((file) => Image.file(file, width: 60, height: 60))
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: _pickImage,
|
||||||
|
child: Text("Upload Image"),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Consumer<OrderProvider>(builder: (context, provider, child) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.greenAccent.withOpacity(0.1),
|
||||||
|
),
|
||||||
|
height: 100,
|
||||||
|
child: Padding(
|
||||||
|
padding: context.bodyAllPadding.copyWith(bottom: 20),
|
||||||
|
child: Center(
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () async {
|
||||||
|
final ratingData = {
|
||||||
|
"rating": _rating,
|
||||||
|
"title": _titleController.text,
|
||||||
|
"description": _descriptionController.text,
|
||||||
|
"imageUrls":
|
||||||
|
_selectedImages.map((file) => file.path).toList(),
|
||||||
|
};
|
||||||
|
var response = await provider.productReview(
|
||||||
|
context, ratingData, widget.orderId);
|
||||||
|
if (response) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
} else {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text("failed to Give feedback"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (_formKey.currentState?.validate() ?? false) {
|
||||||
|
// final success = await pageNotifier.sendOtp(
|
||||||
|
// phoneController.text, context);
|
||||||
|
|
||||||
|
// if (success) {
|
||||||
|
// context.push(MyRoutes.OTPSCREEN);
|
||||||
|
// } else {
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
// SnackBar(
|
||||||
|
// content:
|
||||||
|
// Text("Failed to send OTP. Please try again."),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
// SnackBar(
|
||||||
|
// content:
|
||||||
|
// Text("Enter a valid 10-digit phone number."),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
height: 50,
|
||||||
|
width: MediaQuery.sizeOf(context).width,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: APPCOLOR.appGreen,
|
||||||
|
borderRadius: BorderRadius.circular(4)),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
"Submit",
|
||||||
|
style: context.customMedium(Colors.white, 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -374,6 +374,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.22"
|
version: "2.0.22"
|
||||||
|
flutter_rating_bar:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_rating_bar
|
||||||
|
sha256: d2af03469eac832c591a1eba47c91ecc871fe5708e69967073c043b2d775ed93
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.1"
|
||||||
flutter_rating_stars:
|
flutter_rating_stars:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ dependencies:
|
|||||||
skeletonizer: ^1.4.3
|
skeletonizer: ^1.4.3
|
||||||
art_sweetalert: ^0.0.5
|
art_sweetalert: ^0.0.5
|
||||||
blur:
|
blur:
|
||||||
|
flutter_rating_bar:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user