Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions firebase/functions/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export const messageTypes = ['text', 'system', 'timeProposal'] as const;
export const messageTypes = ["text", "system", "timeProposal"] as const;
export type MessageType = (typeof messageTypes)[number];

// TimeOfDay string type matching Flutter's TimeFormatter.productionToString format
// Format: "TimeOfDay(HH:MM)" where HH and MM are zero-padded
type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
export type TimeOfDayString = `TimeOfDay(${Digit}${Digit}:${Digit}${Digit})`;

// Base message fields shared by all message types
Expand All @@ -15,19 +15,19 @@ type BaseMessage = {
};

export type TextMessage = BaseMessage & {
messageType: 'text';
messageType: "text";
content: string;
};

export type SystemMessage = BaseMessage & {
messageType: 'system';
messageType: "system";
content: string;
};

export type TimeProposal = BaseMessage & {
messageType: 'timeProposal';
messageType: "timeProposal";
proposedTime: TimeOfDayString;
status: 'pending' | 'accepted' | 'rejected';
status: "pending" | "accepted" | "rejected";
};

export type Message = TextMessage | SystemMessage | TimeProposal;
Expand Down Expand Up @@ -67,4 +67,4 @@ export type User = {
fcmToken?: string;
isEmailVerified: boolean;
// other fields aren't relevant
};
};
10 changes: 4 additions & 6 deletions swipeshare_app/lib/pages/buy/buy_swipes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import 'package:swipeshare_app/components/buy_and_sell_screens/time_picker.dart'
import 'package:swipeshare_app/components/buy_and_sell_screens/time_picker_validation.dart';
import 'package:swipeshare_app/components/colors.dart';
import 'package:swipeshare_app/components/text_styles.dart';
import 'package:swipeshare_app/models/user.dart';
import 'package:swipeshare_app/pages/buy/listing_selection_page.dart';
import 'package:swipeshare_app/utils/haptics.dart';

Expand Down Expand Up @@ -128,7 +127,7 @@ class _BuySwipeScreenState extends State<BuySwipeScreen> {
return SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _canProceedToNextScreen()
onPressed: _canProceedToSelection()
? _navigateToListingSelection
: null,
style: ElevatedButton.styleFrom(
Expand Down Expand Up @@ -157,10 +156,11 @@ class _BuySwipeScreenState extends State<BuySwipeScreen> {
}

/// Validates if user can proceed to next screen
bool _canProceedToNextScreen() {
bool _canProceedToSelection() {
return startTime != null &&
endTime != null &&
selectedLocations.isNotEmpty &&
selectedPaymentOptions.isNotEmpty &&
!_isEndTimeBeforeStartTime();
}

Expand All @@ -176,9 +176,7 @@ class _BuySwipeScreenState extends State<BuySwipeScreen> {
date: selectedDate,
startTime: startTime!,
endTime: endTime!,
paymentTypes: selectedPaymentOptions.isEmpty
? PaymentOption.allPaymentTypeNames
: selectedPaymentOptions,
paymentTypes: selectedPaymentOptions,
),
),
);
Expand Down
15 changes: 14 additions & 1 deletion swipeshare_app/lib/pages/onboarding/login_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ class _LoginPageState extends State<LoginPage> {

//sign in user
void signIn() async {
// Validate that email and password are not empty
if (emailController.text.trim().isEmpty ||
passwordController.text.isEmpty) {
await safeVibrate(HapticsType.error);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please enter both email and password')),
);
}
return;
}

//get the auth service
final authService = Provider.of<AuthServices>(context, listen: false);

Expand All @@ -36,9 +48,10 @@ class _LoginPageState extends State<LoginPage> {
} catch (e) {
await safeVibrate(HapticsType.error);
if (mounted) {
final errorMessage = e.toString().replaceFirst('Exception: ', '');
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(e.toString())));
).showSnackBar(SnackBar(content: Text(errorMessage)));
}
}
}
Expand Down
23 changes: 15 additions & 8 deletions swipeshare_app/lib/pages/onboarding/signup_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ class _RegisterPageState extends State<RegisterPage> {

//sign up user
void signUp() async {
// Validate that all required fields are filled out
if (nameController.text.trim().isEmpty ||
emailController.text.trim().isEmpty ||
passwordController.text.isEmpty ||
confirmPasswordController.text.isEmpty) {
await safeVibrate(HapticsType.error);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please fill out all required fields')),
);
return;
}

// make it unc email only
if (!emailController.text.trim().toLowerCase().endsWith('unc.edu') ||
(!referralController.text.trim().toLowerCase().endsWith('unc.edu') &&
Expand Down Expand Up @@ -83,18 +95,13 @@ class _RegisterPageState extends State<RegisterPage> {
nameController.text,
referralController.text,
);
if (mounted) {
await safeVibrate(HapticsType.medium);
// Navigator.pushReplacement(
// context,
// MaterialPageRoute(builder: (context) => OnboardingCarousel()),
// );
}
await safeVibrate(HapticsType.medium);
} catch (e) {
final errorMessage = e.toString().replaceFirst('Exception: ', '');
if (mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(e.toString())));
).showSnackBar(SnackBar(content: Text(errorMessage)));
}
}
}
Expand Down
35 changes: 28 additions & 7 deletions swipeshare_app/lib/services/auth/auth_services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class AuthServices extends ChangeNotifier {

return userCredential;
} on FirebaseAuthException catch (e) {
throw Exception(e.code);
throw Exception(_getAuthErrorMessage(e.code));
}
}

Expand Down Expand Up @@ -56,12 +56,7 @@ class AuthServices extends ChangeNotifier {

return userCredential;
} on FirebaseAuthException catch (e) {
//catch errors
// debugPrint('Error code: ${e.code}');
// debugPrint('Error message: ${e.message}');
// debugPrint('Error details: ${e.stackTrace}');

throw Exception(e.code);
throw Exception(_getAuthErrorMessage(e.code));
}
}

Expand All @@ -72,4 +67,30 @@ class AuthServices extends ChangeNotifier {
await FirebaseAuth.instance.signOut();
debugPrint('User signed out successfully.');
}

//convert Firebase auth error codes to user-friendly messages
String _getAuthErrorMessage(String code) {
switch (code) {
case 'invalid-credential':
return 'Invalid email or password. Please try again.';
case 'user-not-found':
return 'No account found with this email.';
case 'wrong-password':
return 'Incorrect password. Please try again.';
case 'email-already-in-use':
return 'This email is already registered.';
case 'weak-password':
return 'Password is too weak. Please use a stronger password.';
case 'invalid-email':
return 'Invalid email address format.';
case 'user-disabled':
return 'This account has been disabled.';
case 'too-many-requests':
return 'Too many failed attempts. Please try again later.';
case 'network-request-failed':
return 'Network error. Please check your connection.';
default:
return 'An error occurred. Please try again.';
}
}
}
6 changes: 3 additions & 3 deletions swipeshare_app/lib/services/order_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ class OrderService extends ChangeNotifier {
//POST ORDER
Future<MealOrder> postOrder(Listing listing) async {
try {
final result = await _functions.httpsCallable('createOrderFromListing').call({
'listingId': listing.id,
});
final result = await _functions
.httpsCallable('createOrderFromListing')
.call({'listingId': listing.id});

final orderData = result.data as Map<String, dynamic>;
final newOrder = MealOrder.fromMap(orderData);
Expand Down