Skip to content

Commit cdcf04e

Browse files
committed
update: pfp and user data issue in oAuth methods
1 parent 4a39faa commit cdcf04e

File tree

4 files changed

+65
-129
lines changed

4 files changed

+65
-129
lines changed

lib/core/providers/supabase_provider.dart

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import 'dart:async';
22
import 'dart:io'; // For File operations in non-web platforms
3-
// Import the new model
43
import 'package:cookethflow/core/utils/state_handler.dart';
54
import 'package:cookethflow/features/models/user_model.dart';
65
import 'package:flutter/foundation.dart'; // For kIsWeb
@@ -20,6 +19,10 @@ class SupabaseService extends StateHandler {
2019
final User? user = data.session?.user;
2120

2221
if (user != null) {
22+
// Handle OAuth sign-in flow
23+
if (event == AuthChangeEvent.signedIn) {
24+
await _handleOAuthSignIn(user);
25+
}
2326
await _fetchCurrentUserDetails(
2427
user,
2528
); // Fetch details on sign-in/refresh
@@ -57,6 +60,43 @@ class SupabaseService extends StateHandler {
5760

5861
// --- User Data Management (Internal & Public) ---
5962

63+
Future<void> _handleOAuthSignIn(User user) async {
64+
// Check if it's a first-time sign-up via OAuth
65+
final providerData = user.appMetadata;
66+
final isOAuth = providerData['provider'] != null;
67+
final String? currentAvatarUrl = user.userMetadata!['profile_picture_url'];
68+
final String? currentName = user.userMetadata!['name'];
69+
70+
// If it's an OAuth user and they don't have our custom metadata fields,
71+
// it's their first time.
72+
if (isOAuth && (currentAvatarUrl == null || currentName == null)) {
73+
final String? name = user.userMetadata!['full_name'] as String? ?? user.userMetadata!['name'] as String?;
74+
final String? avatarUrl = user.userMetadata!['avatar_url'] as String?;
75+
76+
final Map<String, dynamic> updatedData = {};
77+
if (name != null) {
78+
updatedData['name'] = name;
79+
updatedData['username'] = name.toLowerCase().replaceAll(' ', '');
80+
}
81+
82+
// If an avatar URL is available from the provider, download and upload it
83+
if (avatarUrl != null) {
84+
try {
85+
final xFile = await fetchUserProfilePictureFile(avatarUrl);
86+
if (xFile != null) {
87+
final publicUrl = await uploadUserProfilePicture(xFile);
88+
updatedData['profile_picture_url'] = publicUrl;
89+
}
90+
} catch (e) {
91+
print("Error handling initial PFP upload: $e");
92+
}
93+
}
94+
if (updatedData.isNotEmpty) {
95+
await supabase.auth.updateUser(UserAttributes(data: updatedData));
96+
}
97+
}
98+
}
99+
60100
// Called initially and on auth state changes to populate _currentUser
61101
Future<void> _fetchCurrentUserDetails(User? user) async {
62102
if (user == null) {
@@ -136,9 +176,8 @@ class SupabaseService extends StateHandler {
136176
// and added to your Supabase Auth Providers -> Google -> Redirect URIs
137177
// For desktop, usually 'http://localhost:port' or similar is used.
138178
final String? redirectUrl =
139-
kIsWeb? kReleaseMode ?
140-
'http://cookethflow.cookethcompany.xyz/dashboard':
141-
'http://localhost:3000/dashboard'
179+
kIsWeb ?
180+
kReleaseMode ? 'http://cookethflow.cookethcompany.xyz/dashboard' : 'http://localhost:3000/dashboard'
142181
: (Platform.isAndroid || Platform.isIOS
143182
? 'myapp://login-callback/'
144183
: null); // For mobile/desktop
@@ -162,9 +201,8 @@ class SupabaseService extends StateHandler {
162201
Future<String> signInWithGithub() async {
163202
try {
164203
final String? redirectUrl =
165-
kIsWeb? kReleaseMode ?
166-
'http://cookethflow.cookethcompany.xyz/dashboard':
167-
'http://localhost:3000/dashboard'
204+
kIsWeb ?
205+
kReleaseMode ? 'http://cookethflow.cookethcompany.xyz/dashboard' : 'http://localhost:3000/dashboard'
168206
: (Platform.isAndroid || Platform.isIOS
169207
? 'my.scheme://my-host'
170208
: null); // Replace with your actual scheme
@@ -250,7 +288,7 @@ class SupabaseService extends StateHandler {
250288
// Update user_metadata directly
251289
final updatedData = {
252290
'name': newName,
253-
'userName': newUsername, // Storing custom username in metadata
291+
'username': newUsername, // Storing custom username in metadata
254292
};
255293

256294
await supabase.auth.updateUser(UserAttributes(data: updatedData));
@@ -479,4 +517,4 @@ class SupabaseService extends StateHandler {
479517
}
480518
return null;
481519
}
482-
}
520+
}

lib/features/dashboard/services/file_service.dart

Whitespace-only changes.

lib/features/dashboard/services/platform_file_service.dart

Lines changed: 0 additions & 84 deletions
This file was deleted.

lib/features/dashboard/widgets/edit_profile.dart

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,6 @@ class _ProfileSettingsWidgetState extends State<ProfileSettingsWidget> {
2626
final TextEditingController _usernameController = TextEditingController();
2727
XFile? _selectedImage; // To hold the newly selected image for upload
2828

29-
@override
30-
void didChangeDependencies() {
31-
super.didChangeDependencies();
32-
// Initialize controllers with current user data when dependencies change
33-
final supabaseService = Provider.of<SupabaseService>(
34-
context,
35-
listen: false,
36-
);
37-
if (supabaseService.currentUser != null) {
38-
_nameController.text = supabaseService.currentUser!.name ?? '';
39-
_emailController.text = supabaseService.currentUser!.email;
40-
_usernameController.text = supabaseService.currentUser!.username ?? '';
41-
// No need to fetch image here, CachedNetworkImage handles it
42-
}
43-
}
44-
4529
@override
4630
void dispose() {
4731
_nameController.dispose();
@@ -65,8 +49,6 @@ class _ProfileSettingsWidgetState extends State<ProfileSettingsWidget> {
6549
context,
6650
listen: false,
6751
);
68-
final String currentUserId =
69-
supabaseService.currentUser!.id; // Ensure user is logged in
7052

7153
// Update Name and Username
7254
if (_nameController.text != supabaseService.currentUser!.name ||
@@ -105,12 +87,12 @@ class _ProfileSettingsWidgetState extends State<ProfileSettingsWidget> {
10587
// Upload Profile Picture if a new one was selected
10688
if (_selectedImage != null) {
10789
try {
108-
final res = await supabaseService.uploadUserProfilePicture(
90+
await supabaseService.uploadUserProfilePicture(
10991
_selectedImage!,
11092
);
11193
ScaffoldMessenger.of(
11294
context,
113-
).showSnackBar(SnackBar(content: Text('Profile picture updated!')));
95+
).showSnackBar(const SnackBar(content: Text('Profile picture updated!')));
11496
setState(() {
11597
_selectedImage = null; // Clear selected image after upload
11698
});
@@ -120,12 +102,9 @@ class _ProfileSettingsWidgetState extends State<ProfileSettingsWidget> {
120102
).showSnackBar(SnackBar(content: Text(e.toString())));
121103
}
122104
}
123-
124-
// Optionally, refresh user data to ensure everything is in sync
105+
106+
// Refresh user data from Supabase to ensure UI is in sync
125107
await supabaseService.supabase.auth.refreshSession();
126-
127-
// Close the dialog after saving
128-
// Navigator.of(context).pop();
129108
}
130109

131110
@override
@@ -136,11 +115,16 @@ class _ProfileSettingsWidgetState extends State<ProfileSettingsWidget> {
136115
return Consumer2<DashboardProvider, SupabaseService>(
137116
builder: (context, dashboardProvider, supabaseService, child) {
138117
final currentUser = supabaseService.currentUser;
118+
119+
// Update controllers with the current state of the provider
120+
_nameController.text = currentUser?.name ?? '';
121+
_emailController.text = currentUser?.email ?? '';
122+
_usernameController.text = currentUser?.username ?? '';
123+
139124
final String displayAvatarUrl =
140125
_selectedImage != null
141-
? _selectedImage!
142-
.path // Show locally selected image immediately
143-
: currentUser?.avatarUrl ?? ''; // Fallback to network or empty
126+
? _selectedImage!.path
127+
: currentUser?.avatarUrl ?? '';
144128

145129
return Dialog(
146130
backgroundColor: Theme.of(context).cardColor,
@@ -189,8 +173,7 @@ class _ProfileSettingsWidgetState extends State<ProfileSettingsWidget> {
189173
child: ClipOval(
190174
child:
191175
displayAvatarUrl.isNotEmpty
192-
? (_selectedImage !=
193-
null // If a new image is selected, display it from path/memory
176+
? (_selectedImage != null
194177
? (kIsWeb
195178
? Image.network(
196179
displayAvatarUrl,
@@ -201,7 +184,6 @@ class _ProfileSettingsWidgetState extends State<ProfileSettingsWidget> {
201184
fit: BoxFit.cover,
202185
))
203186
: CachedNetworkImage(
204-
// Otherwise, display from network cache
205187
imageUrl: displayAvatarUrl,
206188
fit: BoxFit.cover,
207189
placeholder:
@@ -225,10 +207,10 @@ class _ProfileSettingsWidgetState extends State<ProfileSettingsWidget> {
225207
bottom: 0,
226208
right: 0,
227209
child: InkWell(
228-
onTap: _pickImage, // Call image picker
210+
onTap: _pickImage,
229211
child: Container(
230212
width:
231-
28, // Slightly larger for better tap target
213+
28,
232214
height: 28,
233215
decoration: BoxDecoration(
234216
color: Theme.of(context).primaryColor,
@@ -249,8 +231,8 @@ class _ProfileSettingsWidgetState extends State<ProfileSettingsWidget> {
249231
],
250232
),
251233
deviceType == rh.DeviceType.desktop
252-
? const SizedBox(height: 16)
253-
: const SizedBox(height: 8),
234+
? const SizedBox(width: 16)
235+
: const SizedBox(width: 8),
254236
Column(
255237
crossAxisAlignment: CrossAxisAlignment.start,
256238
children: [
@@ -596,4 +578,4 @@ class _ProfileSettingsWidgetState extends State<ProfileSettingsWidget> {
596578
),
597579
);
598580
}
599-
}
581+
}

0 commit comments

Comments
 (0)