medora-provider/lib/screens/doctorScreens/doctorProfileScreens/qualifications_screen.dart
DhanshCOSQ b57523599c feature/medora-55 (#6)
Booking physical consultation ,  bugs fixed and Profile picture adding using firebase storage is complete.

Co-authored-by: Jipson George <152465898+Jipson-cosq@users.noreply.github.com>
Reviewed-on: cosqnet/telemednet#6
Co-authored-by: DhanshCOSQ <dhanshas@cosq.net>
Co-committed-by: DhanshCOSQ <dhanshas@cosq.net>
2024-11-05 08:22:13 +00:00

342 lines
12 KiB
Dart

import 'package:flutter/material.dart';
import 'package:medora/controllers/doctor_controller.dart';
import '../../../route/route_names.dart';
class QualificationsScreen extends StatefulWidget {
final DoctorController? controller;
const QualificationsScreen({
super.key,
required this.controller,
});
@override
State<QualificationsScreen> createState() => _QualificationsScreenState();
}
class _QualificationsScreenState extends State<QualificationsScreen> {
late DoctorController _controller;
late TextEditingController _qualificationsController;
late List<String> qualifications;
bool _isEditing = false;
bool _showOthersField = false;
final _formKey = GlobalKey<FormState>();
// Predefined popular qualifications
final List<String> popularQualifications = [
'MBBS',
'MD',
'MS',
'BDS',
'DNB',
'DM',
'MCh',
'PhD',
'MPH',
'Others'
];
@override
void initState() {
super.initState();
_controller = widget.controller ?? DoctorController();
_controller.model.qualifications ??= [];
_qualificationsController = TextEditingController();
qualifications = List<String>.from(_controller.model.qualifications ?? []);
}
bool _validateBeforeNextPage() {
if (qualifications.isEmpty) {
_showError('Please add at least one qualification');
return false;
}
return true;
}
bool _validateQualification(String value) {
if (value.isEmpty) {
_showError('Please enter a qualification');
return false;
}
if (qualifications.any((q) => q.toLowerCase() == value.toLowerCase())) {
_showError('This qualification has already been added');
return false;
}
if (!RegExp(r'^[a-zA-Z0-9\s.,]+$').hasMatch(value)) {
_showError('Please enter valid qualification text');
return false;
}
if (value.length < 2) {
_showError('Qualification must be at least 2 characters long');
return false;
}
return true;
}
void _newQualification() {
final qualification = _qualificationsController.text.trim();
if (_formKey.currentState!.validate() &&
_validateQualification(qualification)) {
// Check if qualification already exists (case-insensitive)
bool isDuplicate = qualifications
.any((q) => q.toLowerCase() == qualification.toLowerCase());
if (!isDuplicate) {
setState(() {
qualifications.add(qualification);
_isEditing = true;
_qualificationsController.clear();
});
_controller.addQualification(qualification);
} else {
// Show error message for duplicate qualification
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('This qualification has already been added'),
backgroundColor: Colors.red,
),
);
}
}
}
void _toggleQualification(String qualification) {
setState(() {
if (qualification == 'Others') {
_showOthersField = !_showOthersField;
return;
}
if (qualifications.contains(qualification)) {
qualifications.remove(qualification);
_controller.removeQualification(qualification);
} else {
// Check if qualification already exists (case-insensitive)
bool isDuplicate = qualifications
.any((q) => q.toLowerCase() == qualification.toLowerCase());
if (!isDuplicate) {
qualifications.add(qualification);
_controller.addQualification(qualification);
} else {
// Show error message for duplicate qualification
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('This qualification has already been added'),
backgroundColor: Colors.red,
),
);
}
}
});
}
void _removeQualification(int index) {
setState(() {
qualifications.removeAt(index);
_isEditing = true;
});
_controller.removeQualification(_qualificationsController.text);
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
if (_validateBeforeNextPage()) {
Navigator.pushNamed(
context,
RouteNames.doctorAddressScreen,
arguments: _controller,
);
}
},
icon: const Icon(Icons.arrow_forward),
),
],
title: const Text('Qualifications'),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 5,
blurRadius: 10,
offset: const Offset(0, 3),
),
],
),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(20),
child: GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 2.5,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemCount: popularQualifications.length,
itemBuilder: (context, index) {
final qualification = popularQualifications[index];
final isSelected = qualification != 'Others' &&
qualifications.contains(qualification);
final isOthers = qualification == 'Others';
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () => _toggleQualification(qualification),
borderRadius: BorderRadius.circular(25),
child: Container(
decoration: BoxDecoration(
color:
isSelected || (isOthers && _showOthersField)
? Colors.blue.withOpacity(0.2)
: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(25),
border: Border.all(
color: isSelected ||
(isOthers && _showOthersField)
? Colors.blue
: Colors.transparent,
),
),
alignment: Alignment.center,
child: Text(
qualification,
style: TextStyle(
color: isSelected ||
(isOthers && _showOthersField)
? Colors.blue
: Colors.black87,
fontWeight: FontWeight.w500,
),
),
),
),
);
},
),
),
if (_showOthersField) ...[
Container(
margin: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.blue.shade100),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: TextFormField(
controller: _qualificationsController,
decoration: InputDecoration(
hintText: 'Enter your qualification',
border: InputBorder.none,
suffixIcon: IconButton(
icon: const Icon(Icons.add_circle_outline,
color: Colors.blue),
onPressed: _newQualification,
),
),
onFieldSubmitted: (_) => _newQualification(),
),
),
),
const SizedBox(height: 20),
],
if (qualifications.isNotEmpty) ...[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(
'Selected Qualifications',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.grey[700],
),
),
),
const SizedBox(height: 10),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: qualifications.length,
padding: const EdgeInsets.symmetric(horizontal: 20),
itemBuilder: (context, index) {
return Card(
elevation: 0,
color: Colors.blue.withOpacity(0.1),
margin: const EdgeInsets.only(bottom: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: ListTile(
title: Text(
qualifications[index],
style: const TextStyle(
fontWeight: FontWeight.w500,
),
),
trailing: IconButton(
icon: const Icon(
Icons.delete,
color: Colors.red,
size: 20,
),
onPressed: () => _removeQualification(index),
),
),
);
},
),
],
const SizedBox(height: 20),
],
),
),
),
),
),
);
}
@override
void dispose() {
_qualificationsController.dispose();
super.dispose();
}
}