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
static const String getAllInvitationsEndpoint = '/invitations/all';
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(
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<CreateInvitationPage> {
DateTime? _selectedDate;
TimeOfDay? _selectedTime;
int? _selectedTagIndex;
bool _isSubmitting = false;
final List<Map<String, dynamic>> _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<CreateInvitationPage> {
}
}
void _handleSubmit() {
Future<void> _handleSubmit() async {
if (_formKey.currentState!.validate()) {
if (_selectedTagIndex == null) {
ScaffoldMessenger.of(context).showSnackBar(
@ -589,28 +593,54 @@ class _CreateInvitationPageState extends State<CreateInvitationPage> {
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<CreateInvitationPage> {
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<CreateInvitationPage> {
),
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<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.',
};
}
}
}