diff --git a/frontend/lib/constants/api_constants.dart b/frontend/lib/constants/api_constants.dart index 23912af..bb73cfb 100644 --- a/frontend/lib/constants/api_constants.dart +++ b/frontend/lib/constants/api_constants.dart @@ -11,4 +11,5 @@ class ApiConstants { // Invitation endpoints static const String getAllInvitationsEndpoint = '/invitations/all'; static const String acceptInvitationEndpoint = '/invitations/accept'; + static const String createInvitationEndpoint = '/invitations/create'; } diff --git a/frontend/lib/screens/pages/invitations_page.dart b/frontend/lib/screens/pages/invitations_page.dart index 0cf4702..add8de5 100644 --- a/frontend/lib/screens/pages/invitations_page.dart +++ b/frontend/lib/screens/pages/invitations_page.dart @@ -459,11 +459,14 @@ class _InvitationsPageState extends State ), ), floatingActionButton: FloatingActionButton( - onPressed: () { - Navigator.push( + onPressed: () async { + final result = await Navigator.push( context, MaterialPageRoute(builder: (context) => CreateInvitationPage()), ); + if (result == true) { + _loadInvitations(); + } }, backgroundColor: Color(0xFF6A4C93), child: Icon(Icons.add, color: Colors.white), @@ -487,16 +490,17 @@ class _CreateInvitationPageState extends State { DateTime? _selectedDate; TimeOfDay? _selectedTime; int? _selectedTagIndex; + bool _isSubmitting = false; final List> _availableTags = [ - {"name": "Sports", "color_hex": "#FF6B35", "icon_name": "sports_soccer"}, - {"name": "Food", "color_hex": "#F7931E", "icon_name": "restaurant"}, - {"name": "Gaming", "color_hex": "#FFD23F", "icon_name": "games"}, - {"name": "Study", "color_hex": "#06FFA5", "icon_name": "menu_book"}, - {"name": "Social", "color_hex": "#118AB2", "icon_name": "group"}, - {"name": "Travel", "color_hex": "#06D6A0", "icon_name": "flight"}, - {"name": "Music", "color_hex": "#8E44AD", "icon_name": "music_note"}, - {"name": "Movies", "color_hex": "#E74C3C", "icon_name": "movie"}, + {"id": 1, "name": "Sports", "color_hex": "#FF6B35", "icon_name": "sports_soccer"}, + {"id": 2, "name": "Food", "color_hex": "#F7931E", "icon_name": "restaurant"}, + {"id": 3, "name": "Gaming", "color_hex": "#FFD23F", "icon_name": "games"}, + {"id": 4, "name": "Study", "color_hex": "#06FFA5", "icon_name": "menu_book"}, + {"id": 5, "name": "Social", "color_hex": "#118AB2", "icon_name": "group"}, + {"id": 6, "name": "Travel", "color_hex": "#06D6A0", "icon_name": "flight"}, + {"id": 7, "name": "Music", "color_hex": "#8E44AD", "icon_name": "music_note"}, + {"id": 8, "name": "Movies", "color_hex": "#E74C3C", "icon_name": "movie"}, ]; @override @@ -577,7 +581,7 @@ class _CreateInvitationPageState extends State { } } - void _handleSubmit() { + Future _handleSubmit() async { if (_formKey.currentState!.validate()) { if (_selectedTagIndex == null) { ScaffoldMessenger.of(context).showSnackBar( @@ -589,28 +593,54 @@ class _CreateInvitationPageState extends State { return; } + setState(() { + _isSubmitting = true; + }); + + DateTime? combinedDateTime; + if (_selectedDate != null) { + if (_selectedTime != null) { + combinedDateTime = DateTime( + _selectedDate!.year, + _selectedDate!.month, + _selectedDate!.day, + _selectedTime!.hour, + _selectedTime!.minute, + ); + } else { + combinedDateTime = _selectedDate; + } + } + final invitationData = { "title": _titleController.text.trim(), "description": _descriptionController.text.trim(), - "date": _selectedDate?.toIso8601String(), - "time": _selectedTime != null - ? "${_selectedTime!.hour}:${_selectedTime!.minute.toString().padLeft(2, '0')}" - : null, + "dateTime": combinedDateTime?.toIso8601String(), "location": _locationController.text.trim().isEmpty ? null : _locationController.text.trim(), - "max_participants": int.parse(_maxParticipantsController.text), - "tag": _availableTags[_selectedTagIndex!], + "maxParticipants": int.parse(_maxParticipantsController.text), + "tagId": _availableTags[_selectedTagIndex!]["id"], }; - print("Invitation JSON: $invitationData"); + final result = await InvitationsService.createInvitation(invitationData); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Invitation created! Check console for JSON output.'), - backgroundColor: Color(0xFF6A4C93), - ), - ); + if (mounted) { + setState(() { + _isSubmitting = false; + }); + + if (result['success']) { + Navigator.of(context).pop(true); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(result['message'] ?? 'Failed to create invitation'), + backgroundColor: Colors.red, + ), + ); + } + } } } @@ -932,7 +962,7 @@ class _CreateInvitationPageState extends State { Container( height: 56, child: ElevatedButton( - onPressed: _handleSubmit, + onPressed: _isSubmitting ? null : _handleSubmit, style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF6A4C93), foregroundColor: Colors.white, @@ -941,13 +971,22 @@ class _CreateInvitationPageState extends State { ), elevation: 2, ), - child: Text( - 'Create Invitation', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), + child: _isSubmitting + ? SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ) + : Text( + 'Create Invitation', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), ), ), ], diff --git a/frontend/lib/services/invitations_service.dart b/frontend/lib/services/invitations_service.dart index a2ced42..248cd21 100644 --- a/frontend/lib/services/invitations_service.dart +++ b/frontend/lib/services/invitations_service.dart @@ -85,4 +85,50 @@ class InvitationsService { }; } } + + static Future> createInvitation(Map invitationData) async { + try { + final response = await HttpService.post( + ApiConstants.createInvitationEndpoint, + invitationData, + ); + + if (response.statusCode == 200) { + final responseData = jsonDecode(response.body); + if (responseData['status'] == true) { + return { + 'success': true, + 'data': responseData['data'], + 'message': responseData['message'], + }; + } else { + return { + 'success': false, + 'message': responseData['message'] ?? 'Failed to create invitation', + }; + } + } else if (response.statusCode == 401) { + return { + 'success': false, + 'message': 'Session expired. Please login again.', + }; + } else if (response.statusCode == 403) { + return { + 'success': false, + 'message': 'Access denied. Invalid credentials.', + }; + } else { + return { + 'success': false, + 'message': 'Server error (${response.statusCode})', + }; + } + } catch (e) { + print('Error creating invitation: $e'); + return { + 'success': false, + 'message': 'Network error. Please check your connection.', + }; + } + } }