Fix profile update endpoint/payload and hide dead menu entries
This commit is contained in:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user