Fix profile update endpoint/payload and hide dead menu entries

This commit is contained in:
risazmat
2026-09-27 09:01:11 +05:30
parent 90a8524b83
commit c95a3f1581
2 changed files with 74 additions and 55 deletions
@@ -178,7 +178,8 @@ class _TabbedLayoutComponentState extends State<TabbedLayoutComponent> {
print("Selected: $result"); print("Selected: $result");
}, },
itemBuilder: (BuildContext context) => [ itemBuilder: (BuildContext context) => [
PopupMenuItem<String>( // COMMENTED OUT: no backend endpoint (service_request/raise_ticket)
/*PopupMenuItem<String>(
//value: 'Option 1', //value: 'Option 1',
child: Text( child: Text(
'Raise A Ticket', 'Raise A Ticket',
@@ -194,7 +195,7 @@ class _TabbedLayoutComponentState extends State<TabbedLayoutComponent> {
), ),
); );
}, },
), ),*/
PopupMenuItem<String>( PopupMenuItem<String>(
//value: 'Option 1', //value: 'Option 1',
@@ -254,7 +255,8 @@ class _TabbedLayoutComponentState extends State<TabbedLayoutComponent> {
}, },
), ),
PopupMenuItem<String>( // COMMENTED OUT
/*PopupMenuItem<String>(
//value: 'Option 1', //value: 'Option 1',
child: Text( child: Text(
'Setup Screen', 'Setup Screen',
@@ -270,9 +272,10 @@ class _TabbedLayoutComponentState extends State<TabbedLayoutComponent> {
); );
// Add your logic for menu 2 here // Add your logic for menu 2 here
}, },
), ),*/
PopupMenuItem<String>( // COMMENTED OUT: no backend endpoint (/Bookmarks -> 404)
/*PopupMenuItem<String>(
//value: 'Option 1', //value: 'Option 1',
child: Text( child: Text(
'BookMark', 'BookMark',
@@ -289,9 +292,10 @@ class _TabbedLayoutComponentState extends State<TabbedLayoutComponent> {
); );
// Add your logic for menu 2 here // Add your logic for menu 2 here
}, },
), ),*/
PopupMenuItem<String>( // COMMENTED OUT
/*PopupMenuItem<String>(
//value: 'Option 1', //value: 'Option 1',
child: Text( child: Text(
'System Parameter', 'System Parameter',
@@ -307,7 +311,7 @@ class _TabbedLayoutComponentState extends State<TabbedLayoutComponent> {
); );
// Add your logic for menu 2 here // Add your logic for menu 2 here
}, },
), ),*/
PopupMenuItem<String>( PopupMenuItem<String>(
//value: 'Option 1', //value: 'Option 1',
@@ -32,9 +32,8 @@ class ProfileSettingsScreen extends StatefulWidget {
class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> { class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
ApiServiceProfileManagement apiService = ApiServiceProfileManagement(); ApiServiceProfileManagement apiService = ApiServiceProfileManagement();
String? fetchedimageurl = Uint8List? _imageBytes; // Uint8List to store the picked image data
'http://43.205.154.152:30165/assets/images/profile-icon.png'; Uint8List? _fetchedImageBytes; // image bytes fetched from server
Uint8List? _imageBytes; // Uint8List to store the image data
String? _imageFileName; String? _imageFileName;
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
@@ -48,7 +47,7 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
//fetchProfileImageData(); fetchProfileImageData();
fetchUserProfileData(); fetchUserProfileData();
} }
@@ -66,6 +65,8 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
_imageBytes = imageBytes; _imageBytes = imageBytes;
_imageFileName = pickedImage.name; // Store the file name _imageFileName = pickedImage.name; // Store the file name
}); });
// Upload immediately after pick (same as authsec_flutter_new) and refresh
await _submitImage();
} }
} catch (e) { } catch (e) {
print(e); print(e);
@@ -127,10 +128,13 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
} }
if (response.statusCode >= 200 && response.statusCode <= 209) { if (response.statusCode >= 200 && response.statusCode <= 209) {
final Map<String, dynamic> jsonData = json.decode(response.body); final Map<String, dynamic> jsonData = json.decode(response.body);
final trustedImageUrl = Uri.dataFromString(jsonData['image'], final String base64Image = jsonData['image'] as String;
mimeType: 'image/*', encoding: Encoding.getByName('utf-8')) // Same as authsec_flutter_new: strip data-url prefix, base64 decode
.toString(); final Uint8List imageBytes =
fetchedimageurl = trustedImageUrl; base64Decode(base64Image.split(',').last);
setState(() {
_fetchedImageBytes = imageBytes;
});
} else { } else {
throw Exception('Failed to load data: ${response.statusCode}'); throw Exception('Failed to load data: ${response.statusCode}');
} }
@@ -170,6 +174,13 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
try { try {
final token = await TokenManager.getToken(); final token = await TokenManager.getToken();
await apiService.createFile(_imageBytes!, _imageFileName!, token!); await apiService.createFile(_imageBytes!, _imageFileName!, token!);
// Refresh displayed image (same as authsec_flutter_new getProfileImg)
await fetchProfileImageData();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Profile image updated')),
);
}
} catch (e) { } catch (e) {
showDialog( showDialog(
context: context, context: context,
@@ -193,21 +204,27 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
Future<void> _updateProfile() async { Future<void> _updateProfile() async {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
// Create a JSON object with the form data // Same contract as authsec_flutter_new: PUT /api/updateAppUserDto/{userId}
// with only backend-persisted keys (AppUserDto: fullName, email).
final dynamic rawUserId = widget.userData['userId'];
if (rawUserId == null) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('User id missing, please re-login')),
);
}
return;
}
final String userId = rawUserId.toString();
final profileData = { final profileData = {
'userId': userId,
'fullName': fullNameController.text, 'fullName': fullNameController.text,
'pronouns': pronounsController.text,
'role': roleController.text,
'department': departmentController.text,
'email': emailController.text, 'email': emailController.text,
'aboutMe': aboutMeController.text,
}; };
//api/user-profile
final token = await TokenManager.getToken(); final token = await TokenManager.getToken();
final String baseUrl = ApiConstants.baseUrl; final String baseUrl = ApiConstants.baseUrl;
final String apiUrl = '$baseUrl/api/user-profile'; final String apiUrl = '$baseUrl/api/updateAppUserDto/$userId';
try { try {
final response = await http.put(Uri.parse(apiUrl), final response = await http.put(Uri.parse(apiUrl),
headers: { headers: {
@@ -218,14 +235,31 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
if (response.statusCode == 401) { if (response.statusCode == 401) {
LogoutService.logout(); LogoutService.logout();
} }
if (response.statusCode <= 209) { if (response.statusCode >= 200 && response.statusCode <= 209) {
print("success"); print("success");
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Profile updated')),
);
Navigator.of(context).pop(); Navigator.of(context).pop();
}
} else { } else {
print(response.statusCode); print(response.statusCode);
print(response.body);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Failed to update profile: ${response.statusCode}')),
);
}
} }
} catch (e) { } catch (e) {
throw Exception('Failed to Update: $e'); if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to update: $e')),
);
}
} }
} }
} }
@@ -277,22 +311,21 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
children: [ children: [
CircleAvatar( CircleAvatar(
radius: 70, // Adjust as needed radius: 70, // Adjust as needed
backgroundImage: NetworkImage( backgroundImage: (_imageBytes ?? _fetchedImageBytes) != null
"$fetchedimageurl"), // Replace with your API URL ? MemoryImage(_imageBytes ?? _fetchedImageBytes!)
: null,
child: (_imageBytes ?? _fetchedImageBytes) != null
? null
: const Icon(Icons.person, size: 60),
), ),
SizedBox(height: 10), SizedBox(height: 10),
CustomButton( CustomButton(
height: getVerticalSize(50), height: getVerticalSize(50),
text: _imageBytes == null text: "Pick a Profile Photo",
? "Pick a Profile Photo"
: 'Upload Success',
margin: getMargin(top: 24, bottom: 5), margin: getMargin(top: 24, bottom: 5),
onTap: () async { onTap: () async {
if (_imageBytes != null) { // Pick + auto-upload, same as authsec_flutter_new
_submitImage(); await _uploadImageFile();
} else {
_uploadImageFile();
}
}, },
), ),
], ],
@@ -330,9 +363,6 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
} }
return null; return null;
}, },
onChanged: (value) {
fullNameController.text = value;
},
margin: getMargin(top: 6)) margin: getMargin(top: 6))
])), ])),
Padding( Padding(
@@ -349,9 +379,6 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
focusNode: FocusNode(), focusNode: FocusNode(),
hintText: "Enter Pronouns", hintText: "Enter Pronouns",
controller: pronounsController, controller: pronounsController,
onChanged: (value) {
pronounsController.text = value;
},
margin: getMargin(top: 6)) margin: getMargin(top: 6))
])), ])),
Padding( Padding(
@@ -368,9 +395,6 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
focusNode: FocusNode(), focusNode: FocusNode(),
hintText: "Enter Role", hintText: "Enter Role",
controller: roleController, controller: roleController,
onChanged: (value) {
roleController.text = value;
},
margin: getMargin(top: 6)) margin: getMargin(top: 6))
])), ])),
Padding( Padding(
@@ -387,9 +411,6 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
focusNode: FocusNode(), focusNode: FocusNode(),
hintText: "Enter Department or Team", hintText: "Enter Department or Team",
controller: departmentController, controller: departmentController,
onChanged: (value) {
departmentController.text = value;
},
margin: getMargin(top: 6)) margin: getMargin(top: 6))
])), ])),
Padding( Padding(
@@ -412,9 +433,6 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
} }
return null; return null;
}, },
onChanged: (value) {
emailController.text = value;
},
margin: getMargin(top: 6)) margin: getMargin(top: 6))
])), ])),
Padding( Padding(
@@ -432,9 +450,6 @@ class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
hintText: "About Me", hintText: "About Me",
controller: aboutMeController, controller: aboutMeController,
maxLines: 3, maxLines: 3,
onChanged: (value) {
aboutMeController.text = value;
},
margin: getMargin(top: 6)) margin: getMargin(top: 6))
])), ])),
CustomButton( CustomButton(