feedback bug fix

This commit is contained in:
venbaittech 2024-11-15 14:32:20 +05:30
parent acaa9f046c
commit e54998ac5f
4 changed files with 426 additions and 284 deletions

View File

@ -35,7 +35,6 @@ class MainApp extends StatelessWidget {
} }
} }
// class MainApp extends ConsumerWidget { // class MainApp extends ConsumerWidget {
// const MainApp({super.key}); // const MainApp({super.key});
// //

View File

@ -172,50 +172,27 @@ class _ProfileScreenState extends State<ProfileScreen> {
DateTime dob = DateFormat('dd/MM/yyyy').parse(dateOfBirth); DateTime dob = DateFormat('dd/MM/yyyy').parse(dateOfBirth);
String formattedDob = DateFormat('yyyy-MM-dd').format(dob); String formattedDob = DateFormat('yyyy-MM-dd').format(dob);
// Prepare form data // Prepare the data to be updated
final request = http.MultipartRequest( final Map<String, dynamic> userData = {
'PATCH', 'full_name': fullName,
Uri.parse( 'dob': formattedDob,
'https://pb.venbait.in/api/collections/users/records/$userID'), // replace with actual user ID 'country_region': countryRegion,
); 'is_profile_completed': 'True'
};
// Set the fields for the user profile // If there's a profile image, upload it separately or include in userData if PocketBase supports files in the update
request.fields['full_name'] = fullName;
// request.fields['username'] = username;
// request.fields['email'] = email;
request.fields['dob'] = formattedDob; // ensure correct format
request.fields['country_region'] = countryRegion;
request.fields['terms_accepted'] = termsAccepted.toString();
// Add image file if selected
if (_profileImage != null) { if (_profileImage != null) {
request.files.add(await http.MultipartFile.fromPath( userData['avatar'] = await http.MultipartFile.fromPath(
'avatar', _profileImage!.path)); 'avatar', _profileImage!.path);
} }
final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
final adminToken = adminAuth.token;
// Add PocketBase auth headers if needed (for authenticated requests)
request.headers['Authorization'] = 'Bearer ${adminToken}';
print(request); // Update the user profile in PocketBase
final updatedUser =
// Send the request await _pb.collection('users').update(userID, body: userData);
final response = await request.send(); print(updatedUser);
if (response.statusCode == 200) {
print(response.statusCode);
_resetFormFields(); _resetFormFields();
// Navigator.pushNamed(context, 'home');
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Profile updated successfully!"))); SnackBar(content: Text("Profile updated successfully!")));
} else {
// Log the response body for better debugging
final responseBody = await response.stream.bytesToString();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
"Failed to update profile: ${response.reasonPhrase}, Body: $responseBody")));
}
} catch (error) { } catch (error) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Failed to update profile: $error"))); SnackBar(content: Text("Failed to update profile: $error")));
@ -533,9 +510,9 @@ class _ProfileScreenState extends State<ProfileScreen> {
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) => Changepassword()), MaterialPageRoute(
builder: (context) => Changepassword()),
); );
}, },
child: Text( child: Text(
"Change Password", "Change Password",

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/presentation/Screens/profilepage.dart'; import 'package:uae_stat/presentation/Screens/profilepage.dart';
import '../../infrastructure/services/pocketbase_service.dart'; import '../../infrastructure/services/pocketbase_service.dart';
@ -20,7 +22,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
bool isChecked = false; bool isChecked = false;
bool showError = false; bool showError = false;
String? _password; String? _password;
bool registrationSuccess = false;
bool registrationFailed = false;
final pb = PocketBase('https://pb.venbait.in'); final pb = PocketBase('https://pb.venbait.in');
@override @override
@ -88,25 +91,26 @@ class _RegisterScreenState extends State<RegisterScreen> {
if (response.id != null) { if (response.id != null) {
// Request email verification // Request email verification
PocketBaseService.users.requestVerification(_emailController.text); PocketBaseService.users.requestVerification(_emailController.text);
// Show success message instead of navigating away
ScaffoldMessenger.of(context).showSnackBar( setState(() {
SnackBar(content: Text('Registration Successed')), registrationSuccess = true;
); registrationFailed = false; // Show success message on success
});
// Navigate to ProfileScreen after successful registration // Navigate to ProfileScreen after successful registration
Navigator.pushReplacement( // Navigator.pushReplacement(
context, // context,
MaterialPageRoute( // MaterialPageRoute(
builder: (context) => ProfileScreen(userId: response.id)), // builder: (context) => ProfileScreen(userId: response.id)),
); // );
} else { } else {
throw Exception('User registration failed: missing user ID'); throw Exception('User registration failed: missing user ID');
} }
} catch (e) { } catch (e) {
// Handle registration error setState(() {
ScaffoldMessenger.of(context).showSnackBar( registrationFailed = true;
SnackBar(content: Text('Registration failed: $e')), registrationSuccess = false;
); });
} }
} else { } else {
setState(() { setState(() {
@ -124,9 +128,135 @@ class _RegisterScreenState extends State<RegisterScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
double screenheight = MediaQuery.of(context).size.height; double screenheight = MediaQuery.of(context).size.height;
double screenwidth = MediaQuery.of(context).size.width; double screenwidth = MediaQuery.of(context).size.width;
Widget buildIconContainer(IconData icon, Color iconColor) {
return Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Color(0xFFF9F9F9),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 6,
offset: Offset(0, 2),
),
],
),
child: Icon(
icon,
color: iconColor,
size: 30,
),
);
}
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
body: Padding( body: registrationSuccess
? Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: screenheight / 8),
buildIconContainer(Icons.report, Color(0xFF7DAFBC)),
SizedBox(height: 20),
Text(
"Your registration is pending for Admin Approval.",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Color(0xFF414042)),
),
SizedBox(height: 10),
Text(
"Access will be granted once your account is approved.",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: Color(0xFF898C81),
),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () => context.go(
'/${context.language}/login',
),
child: Text(
'Go to Login',
),
),
SizedBox(height: screenheight / 5),
Center(
child: Container(
height: screenheight / 8,
width: screenwidth / 2,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
"assets/splash_screen/logo.png"), // Background image asset
fit: BoxFit.fill,
),
),
))
],
),
)
: registrationFailed
? Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: screenheight / 8),
buildIconContainer(Icons.report, Colors.red),
SizedBox(height: 20),
Text(
"Sorry ${_usernameController.text}!",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Color(0xFF414042)),
),
SizedBox(height: 10),
Text(
"Your registration process failed. For further assistance, please contact support.",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: Color(0xFF898C81),
),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () => context.go(
'/${context.language}/login',
),
child: Text(
'Retry',
),
),
SizedBox(height: screenheight / 5),
Center(
child: Container(
height: screenheight / 8,
width: screenwidth / 2,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
"assets/splash_screen/logo.png"), // Background image asset
fit: BoxFit.fill,
),
),
))
],
),
)
: Padding(
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),
child: Form( child: Form(
key: _formKey, key: _formKey,
@ -137,11 +267,13 @@ class _RegisterScreenState extends State<RegisterScreen> {
SizedBox(height: screenheight / 6), SizedBox(height: screenheight / 6),
Text( Text(
'Register', 'Register',
style: TextStyle(fontSize: 32, fontWeight: FontWeight.w400), style: TextStyle(
fontSize: 32, fontWeight: FontWeight.w400),
), ),
SizedBox(height: 10), SizedBox(height: 10),
Text('Please enter your details'), Text('Please enter your details'),
SizedBox(height: 20), SizedBox(height: 20),
// Display this if registration is pending approval
TextFormField( TextFormField(
controller: _usernameController, controller: _usernameController,
decoration: InputDecoration( decoration: InputDecoration(
@ -154,7 +286,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
counterText: '', counterText: '',
), ),
validator: _validateUsername, validator: _validateUsername,
maxLength: 40, // Set the maximum length to 20 characters maxLength:
40, // Set the maximum length to 20 characters
maxLengthEnforcement: MaxLengthEnforcement.enforced, maxLengthEnforcement: MaxLengthEnforcement.enforced,
), ),
SizedBox(height: 15), SizedBox(height: 15),
@ -215,7 +348,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
), ),
onPressed: () { onPressed: () {
setState(() { setState(() {
_obscureConfirmPassword = !_obscureConfirmPassword; _obscureConfirmPassword =
!_obscureConfirmPassword;
}); });
}, },
), ),
@ -281,8 +415,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
child: ElevatedButton( child: ElevatedButton(
onPressed: _registerUser, onPressed: _registerUser,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor: Color(
Color(0xFFA7887A), // Brownish color for Register 0xFFA7887A), // Brownish color for Register
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
@ -292,10 +426,12 @@ class _RegisterScreenState extends State<RegisterScreen> {
children: [ children: [
Text( Text(
"Register", "Register",
style: TextStyle(fontSize: 16, color: Colors.white), style: TextStyle(
fontSize: 16, color: Colors.white),
), ),
SizedBox(width: 8), SizedBox(width: 8),
Icon(Icons.arrow_forward, color: Colors.white), Icon(Icons.arrow_forward,
color: Colors.white),
], ],
), ),
), ),
@ -303,7 +439,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
SizedBox(height: 10), SizedBox(height: 10),
Text( Text(
"Already have an account?", "Already have an account?",
style: TextStyle(fontSize: 16, color: Colors.grey[600]), style: TextStyle(
fontSize: 16, color: Colors.grey[600]),
), ),
SizedBox(height: 10), SizedBox(height: 10),
SizedBox( SizedBox(
@ -313,8 +450,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
// Add your login logic here // Add your login logic here
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor: Color(
Color(0xFF82AFCB), // Blueish color for Login 0xFF82AFCB), // Blueish color for Login
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
@ -324,10 +461,12 @@ class _RegisterScreenState extends State<RegisterScreen> {
children: [ children: [
Text( Text(
"Login", "Login",
style: TextStyle(fontSize: 16, color: Colors.white), style: TextStyle(
fontSize: 16, color: Colors.white),
), ),
SizedBox(width: 8), SizedBox(width: 8),
Icon(Icons.arrow_forward, color: Colors.white), Icon(Icons.arrow_forward,
color: Colors.white),
], ],
), ),
), ),

View File

@ -25,7 +25,8 @@ class FeedbackForm extends StatefulWidget {
_FeedbackFormState createState() => _FeedbackFormState(); _FeedbackFormState createState() => _FeedbackFormState();
} }
class _FeedbackFormState extends State<FeedbackForm> { class _FeedbackFormState extends State<FeedbackForm>
with WidgetsBindingObserver {
final _pb = final _pb =
PocketBase('https://pb.venbait.in'); // Initialize PocketBase client PocketBase('https://pb.venbait.in'); // Initialize PocketBase client
// final _pb = PocketBase('http://127.0.0.1:8090'); // Initialize PocketBase client // final _pb = PocketBase('http://127.0.0.1:8090'); // Initialize PocketBase client
@ -78,17 +79,34 @@ class _FeedbackFormState extends State<FeedbackForm> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addObserver(this);
_loadFeedbackText(); _loadFeedbackText();
_feedbackController.addListener(_handleTextChange); _feedbackController.addListener(_handleTextChange);
fetchEmailConfiguration(); fetchEmailConfiguration();
} }
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.detached ||
state == AppLifecycleState.paused) {
_removeFeedbackText();
}
}
// Detect when navigating to another page
@override
void didPushNext() {
// Called when a new page is pushed on top of FeedbackPage
_removeFeedbackText();
}
Future<void> _saveFeedbackText( Future<void> _saveFeedbackText(
int emojiIndex, String ratingKey, double ratingValue) async { int emojiIndex, String ratingKey, double ratingValue) async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
await prefs.setString('feedbackText', _feedbackController.text); await prefs.setString('feedbackText', _feedbackController.text);
await prefs.setInt('selected_emoji_index', emojiIndex); await prefs.setInt('selected_emoji_index', emojiIndex);
await prefs.setDouble(ratingKey, ratingValue); await prefs.setDouble(ratingKey, ratingValue);
print('one save');
} }
Future<void> _saveAllRatings() async { Future<void> _saveAllRatings() async {
@ -101,24 +119,36 @@ class _FeedbackFormState extends State<FeedbackForm> {
Future<void> _loadFeedbackText() async { Future<void> _loadFeedbackText() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
// Step 1: Load values from SharedPreferences into variables
final feedbackText = prefs.getString('feedbackText') ?? ''; final feedbackText = prefs.getString('feedbackText') ?? '';
final savedIndex = prefs.getInt('selected_emoji_index');
final easeOfUseRating = prefs.getDouble('ease_of_use_rating') ?? 0;
final qualityRating = prefs.getDouble('quality_rating') ?? 0;
final designRating = prefs.getDouble('design_rating') ?? 0;
final redundancyRating = prefs.getDouble('redundancy_rating') ?? 0;
// Step 2: Populate fields with values without immediately clearing storage
setState(() { setState(() {
_feedbackController.text = feedbackText; _feedbackController.text = feedbackText;
});
final savedIndex = prefs.getInt('selected_emoji_index');
if (savedIndex != null) { if (savedIndex != null) {
setState(() {
_selectedEmojiIndex = savedIndex; _selectedEmojiIndex = savedIndex;
_isSmileySelected = true; // Indicating the user selected an emoji _isSmileySelected = true; // Indicating the user selected an emoji
});
} }
_easeOfUseRating = easeOfUseRating;
_qualityRating = qualityRating;
_designRating = designRating;
_redundancyRating = redundancyRating;
});
setState(() { // Step 3: Clear storage after a slight delay
_easeOfUseRating = prefs.getDouble('ease_of_use_rating') ?? 0; Future.delayed(Duration(milliseconds: 50), () async {
_qualityRating = prefs.getDouble('quality_rating') ?? 0; await prefs.remove('feedbackText');
_designRating = prefs.getDouble('design_rating') ?? 0; await prefs.remove('selected_emoji_index');
_redundancyRating = prefs.getDouble('redundancy_rating') ?? 0; await prefs.remove('ease_of_use_rating');
await prefs.remove('quality_rating');
await prefs.remove('design_rating');
await prefs.remove('redundancy_rating');
}); });
} }
@ -622,10 +652,6 @@ class _FeedbackFormState extends State<FeedbackForm> {
final DateFormat formatter = DateFormat("dd.MM.yyyy HH:mm 'UTC'"); final DateFormat formatter = DateFormat("dd.MM.yyyy HH:mm 'UTC'");
String formattedDateTime = formatter.format(feedbackDateTime); String formattedDateTime = formatter.format(feedbackDateTime);
// Assuming the server timezone as UTC, you can append as needed
String submissionTime = "$formattedDateTime <Server_Timezone>";
print("Formatted Date (UTC): $formattedDate");
String email = configEmail; // Direct assignment String email = configEmail; // Direct assignment
// Create the email message // Create the email message
final message = Message() final message = Message()
@ -641,7 +667,7 @@ class _FeedbackFormState extends State<FeedbackForm> {
1. Name: Guest 1. Name: Guest
2. Date of Submission: $formattedDate 2. Date of Submission: $formattedDate
3. Time of Submission: $submissionTime 3. Time of Submission: $formattedDateTime
Feedback: Feedback:
@ -676,6 +702,7 @@ class _FeedbackFormState extends State<FeedbackForm> {
@override @override
void dispose() { void dispose() {
_feedbackController.dispose(); _feedbackController.dispose();
WidgetsBinding.instance.removeObserver(this);
super.dispose(); super.dispose();
} }
} }