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