feat: creating invites frontend

This commit is contained in:
sBubshait 2025-07-22 10:47:45 +03:00
parent d2f74d0296
commit 2f7bc9e6c5
3 changed files with 118 additions and 32 deletions

View File

@ -11,4 +11,5 @@ class ApiConstants {
// Invitation endpoints // Invitation endpoints
static const String getAllInvitationsEndpoint = '/invitations/all'; static const String getAllInvitationsEndpoint = '/invitations/all';
static const String acceptInvitationEndpoint = '/invitations/accept'; static const String acceptInvitationEndpoint = '/invitations/accept';
static const String createInvitationEndpoint = '/invitations/create';
} }

View File

@ -459,11 +459,14 @@ class _InvitationsPageState extends State<InvitationsPage>
), ),
), ),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
onPressed: () { onPressed: () async {
Navigator.push( final result = await Navigator.push(
context, context,
MaterialPageRoute(builder: (context) => CreateInvitationPage()), MaterialPageRoute(builder: (context) => CreateInvitationPage()),
); );
if (result == true) {
_loadInvitations();
}
}, },
backgroundColor: Color(0xFF6A4C93), backgroundColor: Color(0xFF6A4C93),
child: Icon(Icons.add, color: Colors.white), child: Icon(Icons.add, color: Colors.white),
@ -487,16 +490,17 @@ class _CreateInvitationPageState extends State<CreateInvitationPage> {
DateTime? _selectedDate; DateTime? _selectedDate;
TimeOfDay? _selectedTime; TimeOfDay? _selectedTime;
int? _selectedTagIndex; int? _selectedTagIndex;
bool _isSubmitting = false;
final List<Map<String, dynamic>> _availableTags = [ final List<Map<String, dynamic>> _availableTags = [
{"name": "Sports", "color_hex": "#FF6B35", "icon_name": "sports_soccer"}, {"id": 1, "name": "Sports", "color_hex": "#FF6B35", "icon_name": "sports_soccer"},
{"name": "Food", "color_hex": "#F7931E", "icon_name": "restaurant"}, {"id": 2, "name": "Food", "color_hex": "#F7931E", "icon_name": "restaurant"},
{"name": "Gaming", "color_hex": "#FFD23F", "icon_name": "games"}, {"id": 3, "name": "Gaming", "color_hex": "#FFD23F", "icon_name": "games"},
{"name": "Study", "color_hex": "#06FFA5", "icon_name": "menu_book"}, {"id": 4, "name": "Study", "color_hex": "#06FFA5", "icon_name": "menu_book"},
{"name": "Social", "color_hex": "#118AB2", "icon_name": "group"}, {"id": 5, "name": "Social", "color_hex": "#118AB2", "icon_name": "group"},
{"name": "Travel", "color_hex": "#06D6A0", "icon_name": "flight"}, {"id": 6, "name": "Travel", "color_hex": "#06D6A0", "icon_name": "flight"},
{"name": "Music", "color_hex": "#8E44AD", "icon_name": "music_note"}, {"id": 7, "name": "Music", "color_hex": "#8E44AD", "icon_name": "music_note"},
{"name": "Movies", "color_hex": "#E74C3C", "icon_name": "movie"}, {"id": 8, "name": "Movies", "color_hex": "#E74C3C", "icon_name": "movie"},
]; ];
@override @override
@ -577,7 +581,7 @@ class _CreateInvitationPageState extends State<CreateInvitationPage> {
} }
} }
void _handleSubmit() { Future<void> _handleSubmit() async {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
if (_selectedTagIndex == null) { if (_selectedTagIndex == null) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
@ -589,28 +593,54 @@ class _CreateInvitationPageState extends State<CreateInvitationPage> {
return; 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 = { final invitationData = {
"title": _titleController.text.trim(), "title": _titleController.text.trim(),
"description": _descriptionController.text.trim(), "description": _descriptionController.text.trim(),
"date": _selectedDate?.toIso8601String(), "dateTime": combinedDateTime?.toIso8601String(),
"time": _selectedTime != null
? "${_selectedTime!.hour}:${_selectedTime!.minute.toString().padLeft(2, '0')}"
: null,
"location": _locationController.text.trim().isEmpty "location": _locationController.text.trim().isEmpty
? null ? null
: _locationController.text.trim(), : _locationController.text.trim(),
"max_participants": int.parse(_maxParticipantsController.text), "maxParticipants": int.parse(_maxParticipantsController.text),
"tag": _availableTags[_selectedTagIndex!], "tagId": _availableTags[_selectedTagIndex!]["id"],
}; };
print("Invitation JSON: $invitationData"); final result = await InvitationsService.createInvitation(invitationData);
ScaffoldMessenger.of(context).showSnackBar( if (mounted) {
SnackBar( setState(() {
content: Text('Invitation created! Check console for JSON output.'), _isSubmitting = false;
backgroundColor: Color(0xFF6A4C93), });
),
); 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<CreateInvitationPage> {
Container( Container(
height: 56, height: 56,
child: ElevatedButton( child: ElevatedButton(
onPressed: _handleSubmit, onPressed: _isSubmitting ? null : _handleSubmit,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF6A4C93), backgroundColor: Color(0xFF6A4C93),
foregroundColor: Colors.white, foregroundColor: Colors.white,
@ -941,13 +971,22 @@ class _CreateInvitationPageState extends State<CreateInvitationPage> {
), ),
elevation: 2, elevation: 2,
), ),
child: Text( child: _isSubmitting
'Create Invitation', ? SizedBox(
style: TextStyle( height: 20,
fontSize: 18, width: 20,
fontWeight: FontWeight.w600, child: CircularProgressIndicator(
), strokeWidth: 2,
), valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Text(
'Create Invitation',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
), ),
), ),
], ],

View File

@ -85,4 +85,50 @@ class InvitationsService {
}; };
} }
} }
static Future<Map<String, dynamic>> createInvitation(Map<String, dynamic> 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.',
};
}
}
} }