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>
3
.env
@ -2,4 +2,5 @@ CUSTOM_SCHEME=com.cosqnet.telemednet
|
||||
PROFILE_COLLECTION_NAME=telemednetusers
|
||||
PATIENT_PROFILE_COLLECTION_NAME=patientprofiles
|
||||
DOCTOR_PROFILE_COLLECTION_NAME=doctorprofiles
|
||||
CONSULTATION_CENTER_COLLECTION_NAME=businesscenters
|
||||
CONSULTATION_CENTER_COLLECTION_NAME=businesscenters
|
||||
FIREBASE_STORAGE_BUCKET=gs://cosq-telemednet-dev.firebasestorage.app
|
||||
|
||||
6
.vscode/launch.json
vendored
@ -5,18 +5,18 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "telemednet",
|
||||
"name": "Medora",
|
||||
"request": "launch",
|
||||
"type": "dart"
|
||||
},
|
||||
{
|
||||
"name": "telemednet (profile mode)",
|
||||
"name": "Medora (profile mode)",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"flutterMode": "profile"
|
||||
},
|
||||
{
|
||||
"name": "telemednet (release mode)",
|
||||
"name": "Medora (release mode)",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"flutterMode": "release"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application
|
||||
android:label="telemednet"
|
||||
android:label="Medora"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
</adaptive-icon>
|
||||
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 6.5 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 31 KiB |
BIN
images/logo.jpg
Normal file
|
After Width: | Height: | Size: 274 KiB |
BIN
images/splash_screen.jpg
Normal file
|
After Width: | Height: | Size: 227 KiB |
@ -427,7 +427,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@ -484,7 +484,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
|
||||
@ -1,122 +1 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "Icon-App-1024x1024@1x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 501 KiB |
|
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 901 B |
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 704 B After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 762 B After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 25 KiB |
@ -1,4 +1,4 @@
|
||||
import 'package:telemednet/data/models/doctor.dart';
|
||||
import 'package:medora/data/models/doctor.dart';
|
||||
|
||||
class ValidationHelper {
|
||||
// Basic regex patterns
|
||||
@ -92,16 +92,16 @@ class DoctorController {
|
||||
model.middleName = middleName;
|
||||
}
|
||||
|
||||
void updateLastName(String lastName) {
|
||||
model.lastName = lastName;
|
||||
void updateLastName(String firstName) {
|
||||
model.firstName = firstName;
|
||||
}
|
||||
|
||||
void addQualification(String qualification) {
|
||||
model.qualifications!.add(qualification);
|
||||
model.qualifications!.add(qualification.trim());
|
||||
}
|
||||
|
||||
void removeQualification(String qualification) {
|
||||
model.qualifications!.remove(qualification);
|
||||
model.qualifications!.remove(qualification.trim());
|
||||
}
|
||||
|
||||
void updateFloorBuilding(String floorBuilding) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import 'package:telemednet/data/models/patient.dart';
|
||||
import 'package:medora/data/models/patient.dart';
|
||||
import '../data/services/patient_registration_service.dart';
|
||||
|
||||
class PatientController {
|
||||
@ -95,7 +95,7 @@ class PatientController {
|
||||
}
|
||||
|
||||
Future<bool> updatePatientData() async {
|
||||
return await PatientProfileService.updatePatientProfile(this);
|
||||
return await PatientProfileService.updatePatientProfile(model);
|
||||
}
|
||||
|
||||
Future<bool> deletePatientData() async {
|
||||
|
||||
@ -10,7 +10,7 @@ class Doctor {
|
||||
String? title;
|
||||
String? surName;
|
||||
String? middleName;
|
||||
String? lastName;
|
||||
String? firstName;
|
||||
List<String>? qualifications = [];
|
||||
String? floorBuilding;
|
||||
String? street;
|
||||
@ -32,7 +32,7 @@ class Doctor {
|
||||
this.title,
|
||||
this.surName,
|
||||
this.middleName,
|
||||
this.lastName,
|
||||
this.firstName,
|
||||
this.qualifications,
|
||||
this.floorBuilding,
|
||||
this.street,
|
||||
@ -53,7 +53,7 @@ class Doctor {
|
||||
'digitalSignature': digitalSignature,
|
||||
'title': title,
|
||||
'surname': surName,
|
||||
'lastName': lastName,
|
||||
'firstName': firstName,
|
||||
'middleName': middleName,
|
||||
'qualifications': qualifications,
|
||||
'floorBuilding': floorBuilding,
|
||||
@ -76,7 +76,7 @@ class Doctor {
|
||||
title: json['title'],
|
||||
surName: json['surname'],
|
||||
middleName: json['middleName'],
|
||||
lastName: json['lastName'],
|
||||
firstName: json['firstName'],
|
||||
qualifications: List<String>.from(json['qualifications'] ?? []),
|
||||
floorBuilding: json['floorBuilding'],
|
||||
street: json['street'],
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
// import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
|
||||
// class Doctors {
|
||||
// final String name;
|
||||
// final String location;
|
||||
// final String specialization;
|
||||
// final int experience;
|
||||
// final String description;
|
||||
// final List<String> qualification;
|
||||
// final List<Map<String, dynamic>> consultation;
|
||||
// final String profileImage;
|
||||
|
||||
// Doctors({
|
||||
// required this.name,
|
||||
// required this.location,
|
||||
// required this.specialization,
|
||||
// required this.experience,
|
||||
// required this.description,
|
||||
// required this.qualification,
|
||||
// required this.consultation,
|
||||
// required this.profileImage,
|
||||
// });
|
||||
|
||||
// factory Doctors.fromFirestore(DocumentSnapshot doc) {
|
||||
// final data = doc.data() as Map<String, dynamic>;
|
||||
// return Doctors(
|
||||
// name: data['name'] ?? '',
|
||||
// location: data['location'] ?? '',
|
||||
// specialization: data['specialization'] ?? '',
|
||||
// experience: data['experience'] ?? 0,
|
||||
// description: data['description'] ?? '',
|
||||
// qualification: List<String>.from(data['qualification'] ?? []),
|
||||
// consultation: List<Map<String, dynamic>>.from(data['consultation'] ?? []),
|
||||
// profileImage: data['profile_image'] ?? '',
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
@ -4,6 +4,7 @@ class PatientModel {
|
||||
String? gender;
|
||||
DateTime? dateOfBirth;
|
||||
String? profileImagePath;
|
||||
String? profileImageUrl;
|
||||
PatientAddress address;
|
||||
|
||||
List<FamilyMember> familyMembers = [];
|
||||
@ -17,6 +18,7 @@ class PatientModel {
|
||||
'gender': gender,
|
||||
'dateOfBirth': dateOfBirth?.toIso8601String(),
|
||||
'profileImagePath': profileImagePath,
|
||||
'profileImageUrl': profileImageUrl,
|
||||
'address': address.toJson(),
|
||||
'familyMembers': familyMembers.map((member) => member.toJson()).toList(),
|
||||
};
|
||||
@ -31,15 +33,11 @@ class PatientModel {
|
||||
? DateTime.parse(json['dateOfBirth'])
|
||||
: null;
|
||||
profileImagePath = json['profileImagePath'];
|
||||
address.houseNo = json['houseNo'];
|
||||
address.line = json['line'];
|
||||
address.town = json['town'];
|
||||
address.pincode = json['pincode'];
|
||||
address.country = json['country'];
|
||||
address.state = json['state'];
|
||||
address.city = json['city'];
|
||||
address.addressType = json['addressType'];
|
||||
address.otherLabel = json['otherLabel'];
|
||||
profileImageUrl = json['profileImageUrl'];
|
||||
if (json['address'] != null) {
|
||||
address =
|
||||
PatientAddress.fromJson(json['address'] as Map<String, dynamic>);
|
||||
}
|
||||
if (json['familyMembers'] != null) {
|
||||
familyMembers = (json['familyMembers'] as List)
|
||||
.map((memberJson) => FamilyMember.fromJson(memberJson))
|
||||
@ -53,15 +51,8 @@ class PatientModel {
|
||||
gender = other.gender;
|
||||
dateOfBirth = other.dateOfBirth;
|
||||
profileImagePath = other.profileImagePath;
|
||||
address.houseNo = other.address.houseNo;
|
||||
address.line = other.address.line;
|
||||
address.town = other.address.town;
|
||||
address.pincode = other.address.pincode;
|
||||
address.country = other.address.country;
|
||||
address.state = other.address.state;
|
||||
address.city = other.address.city;
|
||||
address.addressType = other.address.addressType;
|
||||
address.otherLabel = other.address.otherLabel;
|
||||
profileImageUrl = other.profileImageUrl;
|
||||
address = other.address;
|
||||
familyMembers = other.familyMembers;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:telemednet/data/models/consultation_booking.dart';
|
||||
import 'package:medora/data/models/consultation_booking.dart';
|
||||
|
||||
class BookingService {
|
||||
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:telemednet/controllers/consultation_center_controller.dart';
|
||||
import 'package:medora/controllers/consultation_center_controller.dart';
|
||||
import '../models/consultation_center.dart';
|
||||
|
||||
class ConsultationCenterService {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:telemednet/data/models/telemed_user.dart';
|
||||
import 'package:medora/data/models/telemed_user.dart';
|
||||
|
||||
class DataService {
|
||||
static final String profileCollectionName =
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:telemednet/controllers/doctor_controller.dart';
|
||||
import 'package:telemednet/data/models/doctor.dart';
|
||||
import 'package:medora/controllers/doctor_controller.dart';
|
||||
import 'package:medora/data/models/doctor.dart';
|
||||
|
||||
class DoctorProfileService {
|
||||
static final String doctorProfileCollectionName =
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/data/models/telemed_user.dart';
|
||||
import 'package:telemednet/data/services/data_service.dart';
|
||||
import 'package:telemednet/data/services/doctor_profile_service.dart';
|
||||
import 'package:telemednet/data/services/patient_registration_service.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/data/models/telemed_user.dart';
|
||||
import 'package:medora/data/services/data_service.dart';
|
||||
import 'package:medora/data/services/doctor_profile_service.dart';
|
||||
import 'package:medora/data/services/patient_registration_service.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
class NavigationService {
|
||||
static Future<void> handleUserNavigation(BuildContext context) async {
|
||||
|
||||
@ -1,13 +1,63 @@
|
||||
import 'dart:io';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:firebase_storage/firebase_storage.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:telemednet/controllers/patient_controller.dart';
|
||||
import 'package:telemednet/data/models/patient.dart';
|
||||
import 'package:medora/controllers/patient_controller.dart';
|
||||
import 'package:medora/data/models/patient.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
class PatientProfileService {
|
||||
static final String patientProfileCollectionName =
|
||||
dotenv.env['PATIENT_PROFILE_COLLECTION_NAME']!;
|
||||
static final FirebaseFirestore db = FirebaseFirestore.instance;
|
||||
static final FirebaseStorage storage = FirebaseStorage.instanceFor(
|
||||
bucket: dotenv.env['FIREBASE_STORAGE_BUCKET']!);
|
||||
|
||||
static Future<String?> uploadProfileImage(File imageFile) async {
|
||||
try {
|
||||
final User? user = FirebaseAuth.instance.currentUser;
|
||||
if (user == null) {
|
||||
print('No user logged in');
|
||||
return null;
|
||||
}
|
||||
final String uid = user.uid;
|
||||
final String fileName =
|
||||
'profile_${uid}_${DateTime.now().millisecondsSinceEpoch}${path.extension(imageFile.path)}';
|
||||
final Reference storageRef =
|
||||
storage.ref().child('profile_images/$fileName');
|
||||
final UploadTask uploadTask = storageRef.putFile(
|
||||
imageFile,
|
||||
SettableMetadata(
|
||||
contentType: 'image/${path.extension(imageFile.path).substring(1)}',
|
||||
customMetadata: {
|
||||
'userId': uid,
|
||||
'uploadedAt': DateTime.now().toIso8601String(),
|
||||
},
|
||||
),
|
||||
);
|
||||
final TaskSnapshot snapshot = await uploadTask;
|
||||
final String downloadUrl = await snapshot.ref.getDownloadURL();
|
||||
|
||||
print('Profile image uploaded successfully');
|
||||
return downloadUrl;
|
||||
} catch (e) {
|
||||
print('Error uploading profile image: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> deleteProfileImage(String imageUrl) async {
|
||||
try {
|
||||
final Reference storageRef = storage.refFromURL(imageUrl);
|
||||
await storageRef.delete();
|
||||
print('Profile image deleted successfully');
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error deleting profile image: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> savePatientProfile(PatientController controller) async {
|
||||
try {
|
||||
@ -19,11 +69,21 @@ class PatientProfileService {
|
||||
|
||||
final String uid = user.uid;
|
||||
final PatientModel patientData = controller.model;
|
||||
String? imageUrl;
|
||||
if (patientData.profileImagePath != null) {
|
||||
final File imageFile = File(patientData.profileImagePath!);
|
||||
imageUrl = await uploadProfileImage(imageFile);
|
||||
if (imageUrl == null) {
|
||||
print('Failed to upload profile image');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final Map<String, dynamic> patientJson = patientData.toJson();
|
||||
patientJson['createdAt'] = FieldValue.serverTimestamp();
|
||||
patientJson['updatedAt'] = FieldValue.serverTimestamp();
|
||||
patientJson['uid'] = uid;
|
||||
patientJson['profileImageUrl'] = imageUrl;
|
||||
|
||||
await db
|
||||
.collection(patientProfileCollectionName)
|
||||
@ -38,32 +98,7 @@ class PatientProfileService {
|
||||
}
|
||||
}
|
||||
|
||||
static Future<PatientModel?> getPatientProfile() async {
|
||||
try {
|
||||
final User? user = FirebaseAuth.instance.currentUser;
|
||||
if (user == null) {
|
||||
print('No user logged in');
|
||||
return null;
|
||||
}
|
||||
|
||||
final String uid = user.uid;
|
||||
final DocumentSnapshot doc =
|
||||
await db.collection(patientProfileCollectionName).doc(uid).get();
|
||||
|
||||
if (!doc.exists) {
|
||||
print('No patient profile found for this user');
|
||||
return null;
|
||||
}
|
||||
|
||||
final data = doc.data() as Map<String, dynamic>;
|
||||
return PatientModel.fromJson(data);
|
||||
} catch (e) {
|
||||
print('Error fetching patient profile: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> updatePatientProfile(PatientController controller) async {
|
||||
static Future<bool> updatePatientProfile(PatientModel patient) async {
|
||||
try {
|
||||
final User? user = FirebaseAuth.instance.currentUser;
|
||||
if (user == null) {
|
||||
@ -72,10 +107,30 @@ class PatientProfileService {
|
||||
}
|
||||
|
||||
final String uid = user.uid;
|
||||
final PatientModel patientData = controller.model;
|
||||
String? imageUrl;
|
||||
if (patient.profileImagePath != null) {
|
||||
final DocumentSnapshot oldDoc =
|
||||
await db.collection(patientProfileCollectionName).doc(uid).get();
|
||||
if (oldDoc.exists) {
|
||||
final oldData = oldDoc.data() as Map<String, dynamic>;
|
||||
final String? oldImageUrl = oldData['profileImageUrl'];
|
||||
if (oldImageUrl != null) {
|
||||
await deleteProfileImage(oldImageUrl);
|
||||
}
|
||||
}
|
||||
final File imageFile = File(patient.profileImagePath!);
|
||||
imageUrl = await uploadProfileImage(imageFile);
|
||||
if (imageUrl == null) {
|
||||
print('Failed to upload new profile image');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final Map<String, dynamic> patientJson = patientData.toJson();
|
||||
final Map<String, dynamic> patientJson = patient.toJson();
|
||||
patientJson['updatedAt'] = FieldValue.serverTimestamp();
|
||||
if (imageUrl != null) {
|
||||
patientJson['profileImageUrl'] = imageUrl;
|
||||
}
|
||||
|
||||
await db
|
||||
.collection(patientProfileCollectionName)
|
||||
@ -99,6 +154,15 @@ class PatientProfileService {
|
||||
}
|
||||
|
||||
final String uid = user.uid;
|
||||
final DocumentSnapshot doc =
|
||||
await db.collection(patientProfileCollectionName).doc(uid).get();
|
||||
if (doc.exists) {
|
||||
final data = doc.data() as Map<String, dynamic>;
|
||||
final String? imageUrl = data['profileImageUrl'];
|
||||
if (imageUrl != null) {
|
||||
await deleteProfileImage(imageUrl);
|
||||
}
|
||||
}
|
||||
|
||||
await db.collection(patientProfileCollectionName).doc(uid).delete();
|
||||
|
||||
@ -109,4 +173,26 @@ class PatientProfileService {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<PatientModel?> getPatientProfile() async {
|
||||
try {
|
||||
final User? user = FirebaseAuth.instance.currentUser;
|
||||
if (user == null) {
|
||||
print('No user logged in');
|
||||
return null;
|
||||
}
|
||||
final String uid = user.uid;
|
||||
final DocumentSnapshot doc =
|
||||
await db.collection(patientProfileCollectionName).doc(uid).get();
|
||||
if (!doc.exists) {
|
||||
print('No patient profile found for this user');
|
||||
return null;
|
||||
}
|
||||
final data = doc.data() as Map<String, dynamic>;
|
||||
return PatientModel.fromJson(data);
|
||||
} catch (e) {
|
||||
print('Error fetching patient profile: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import 'package:medora/telemednet_app.dart';
|
||||
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:telemednet/telemednet_app.dart';
|
||||
import 'firebase_options.dart';
|
||||
|
||||
void main() async {
|
||||
@ -10,10 +10,7 @@ void main() async {
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
);
|
||||
FirebaseUIAuth.configureProviders([
|
||||
EmailAuthProvider(),
|
||||
PhoneAuthProvider()
|
||||
]);
|
||||
FirebaseUIAuth.configureProviders([EmailAuthProvider(), PhoneAuthProvider()]);
|
||||
await dotenv.load();
|
||||
runApp(const TelemednetApp());
|
||||
}
|
||||
|
||||
@ -40,4 +40,6 @@ class RouteNames {
|
||||
static const String doctorServicesMenuScreen = '/doctor-services-menu';
|
||||
static const String consultationTimeSlotScreen = '/doctor-timeslot';
|
||||
static const String consultationDayScreen = '/doctor-consultation-days';
|
||||
static const String loadingScreen = '/loading-screen';
|
||||
static const String splashScreen = '/splash-screen';
|
||||
}
|
||||
@ -1,51 +1,53 @@
|
||||
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/controllers/consultation_center_controller.dart';
|
||||
import 'package:telemednet/data/models/consultation_center.dart';
|
||||
import 'package:telemednet/data/models/doctor.dart';
|
||||
import 'package:telemednet/screens/authentication/launch_screen.dart';
|
||||
// import 'package:telemednet/data/telemed_user.dart';
|
||||
import 'package:telemednet/controllers/patient_controller.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/business_center_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/center_fee_and_duration_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/consultation_day_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/consultation_schedule.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/consultation_time_slot_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_dashboard_home_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_dashboard_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_landing_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_personal_profile_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_services_menu_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/doctor_profile_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/qualifications_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/appoinmentBooking/consultation_booking_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/appoinmentBooking/consultation_time_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/appoinmentBooking/consultations_center_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/appoinmentBooking/doctor_details_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/appoinmentBooking/doctors_list_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/appoinmentBooking/speciality_screen.dart';
|
||||
import 'package:medora/controllers/consultation_center_controller.dart';
|
||||
import 'package:medora/data/models/consultation_center.dart';
|
||||
import 'package:medora/data/models/doctor.dart';
|
||||
import 'package:medora/screens/authentication/launch_screen.dart';
|
||||
// import 'package:medora/data/telemed_user.dart';
|
||||
import 'package:medora/controllers/patient_controller.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
import 'package:medora/screens/common/loading_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorConsultationSchedule/business_center_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorConsultationSchedule/center_fee_and_duration_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorConsultationSchedule/consultation_day_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorConsultationSchedule/consultation_schedule.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorConsultationSchedule/consultation_time_slot_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorDashboard/doctor_dashboard_home_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorDashboard/doctor_dashboard_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorDashboard/doctor_landing_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorDashboard/doctor_personal_profile_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorDashboard/doctor_services_menu_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorProfileScreens/doctor_profile_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorProfileScreens/qualifications_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/appoinmentBooking/consultation_booking_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/appoinmentBooking/consultation_time_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/appoinmentBooking/consultations_center_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/appoinmentBooking/doctor_details_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/appoinmentBooking/doctors_list_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/appoinmentBooking/speciality_screen.dart';
|
||||
|
||||
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/achivements_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/address_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorProfileScreens/achivements_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorProfileScreens/address_screen.dart';
|
||||
|
||||
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/digital_signature_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorProfileScreens/digital_signature_screen.dart';
|
||||
|
||||
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/experience_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/profile_description_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorProfileScreens/experience_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorProfileScreens/profile_description_screen.dart';
|
||||
|
||||
import 'package:telemednet/screens/doctorScreens/doctorProfileScreens/specialities_selection_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/patientDashboard/patient_dashboard_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/patientDashboard/patient_home_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorProfileScreens/specialities_selection_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/patientDashboard/patient_dashboard_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/patientDashboard/patient_home_screen.dart';
|
||||
|
||||
import 'package:telemednet/screens/patientScreens/patientDashboard/patient_profile_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/registrationScreens/patient_adress_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/registrationScreens/patient_family_members_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/registrationScreens/patient_registration_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/patientDashboard/patient_profile_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/registrationScreens/patient_adress_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/registrationScreens/patient_family_members_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/registrationScreens/patient_registration_screen.dart';
|
||||
import 'package:medora/screens/splash_screen.dart';
|
||||
|
||||
import 'controllers/doctor_controller.dart';
|
||||
import 'screens/patientScreens/patient_landing_screen.dart';
|
||||
import 'screens/patientScreens/registrationScreens/family_members_edit_screen.dart';
|
||||
import '../controllers/doctor_controller.dart';
|
||||
import '../screens/patientScreens/patient_landing_screen.dart';
|
||||
import '../screens/patientScreens/registrationScreens/family_members_edit_screen.dart';
|
||||
|
||||
final Map<String, Widget Function(BuildContext)> routes = {
|
||||
RouteNames.launch: (context) => const LaunchScreen(),
|
||||
@ -208,4 +210,6 @@ final Map<String, Widget Function(BuildContext)> routes = {
|
||||
controller: controller ?? ConsultationCenterController(),
|
||||
);
|
||||
},
|
||||
RouteNames.loadingScreen: (context) => const LoadingScreen(),
|
||||
RouteNames.splashScreen: (context) => const SplashScreen(),
|
||||
};
|
||||
@ -1,10 +1,9 @@
|
||||
import 'dart:async';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/data/services/navigation_service.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:telemednet/screens/authentication/sign_up_screen.dart';
|
||||
import 'package:telemednet/widgets/primary_button.dart';
|
||||
import 'package:medora/data/services/navigation_service.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
import 'package:medora/screens/authentication/sign_up_screen.dart';
|
||||
import 'package:medora/widgets/primary_button.dart';
|
||||
|
||||
class LaunchScreen extends StatefulWidget {
|
||||
const LaunchScreen({super.key});
|
||||
@ -19,6 +18,17 @@ class _LaunchScreenState extends State<LaunchScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_checkAuthenticationState();
|
||||
}
|
||||
|
||||
void _checkAuthenticationState() {
|
||||
FirebaseAuth.instance.authStateChanges().listen((user) {
|
||||
if (user != null) {
|
||||
if (mounted) {
|
||||
_fetchProfileAndNavigate(context);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@ -41,40 +51,7 @@ class _LaunchScreenState extends State<LaunchScreen> {
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: StreamBuilder(
|
||||
stream: FirebaseAuth.instance.authStateChanges(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return _buildLoadingWidget();
|
||||
} else if (snapshot.hasData) {
|
||||
_fetchProfileAndNavigate(context);
|
||||
return _buildLoadingWidget();
|
||||
} else {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
'Register',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Who are you?',
|
||||
style: TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
_buildUserTypeSelection(context),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
child: _buildUserTypeSelection(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -83,26 +60,26 @@ class _LaunchScreenState extends State<LaunchScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLoadingWidget() {
|
||||
return const SizedBox(
|
||||
height: 120,
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CircularProgressIndicator(),
|
||||
SizedBox(height: 12),
|
||||
Text('Please wait...'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUserTypeSelection(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
'Register',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Who are you?',
|
||||
style: TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
_buildSelectionCard(
|
||||
title: 'Doctor',
|
||||
description: 'Can organise and approve appointments',
|
||||
@ -122,15 +99,7 @@ class _LaunchScreenState extends State<LaunchScreen> {
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: PrimaryButton(
|
||||
onPressed: selectedUserType != null
|
||||
? () => Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => SignUpScreen(
|
||||
selectedUserType: selectedUserType!,
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
onPressed: selectedUserType != null ? _navigateToSignUp : null,
|
||||
text: 'Next',
|
||||
),
|
||||
),
|
||||
@ -213,9 +182,17 @@ class _LaunchScreenState extends State<LaunchScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
void _navigateToSignUp() {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => SignUpScreen(
|
||||
selectedUserType: selectedUserType!,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _fetchProfileAndNavigate(BuildContext context) async {
|
||||
if (mounted) {
|
||||
await NavigationService.handleUserNavigation(context);
|
||||
}
|
||||
await NavigationService.handleUserNavigation(context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl_phone_field/intl_phone_field.dart';
|
||||
import 'package:telemednet/data/services/data_service.dart';
|
||||
import 'package:telemednet/data/services/navigation_service.dart';
|
||||
import 'package:telemednet/widgets/primary_button.dart';
|
||||
import 'package:medora/data/services/data_service.dart';
|
||||
import 'package:medora/data/services/navigation_service.dart';
|
||||
import 'package:medora/widgets/primary_button.dart';
|
||||
|
||||
class SignUpScreen extends StatefulWidget {
|
||||
final String selectedUserType;
|
||||
|
||||
50
lib/screens/common/loading_screen.dart
Normal file
@ -0,0 +1,50 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LoadingScreen extends StatelessWidget {
|
||||
const LoadingScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 32),
|
||||
CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue.shade700),
|
||||
strokeWidth: 4,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
'Loading...',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue.shade700,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Please wait while we fetch you...',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey.shade600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
child: LinearProgressIndicator(
|
||||
value: null,
|
||||
backgroundColor: Colors.grey.shade200,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue.shade700),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/controllers/consultation_center_controller.dart';
|
||||
import 'package:medora/controllers/consultation_center_controller.dart';
|
||||
|
||||
import '../../../route_names.dart';
|
||||
import '../../../route/route_names.dart';
|
||||
|
||||
class BusinessCenterScreen extends StatefulWidget {
|
||||
final ConsultationCenterController controller;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:telemednet/controllers/consultation_center_controller.dart';
|
||||
import 'package:telemednet/data/services/consultation_center_service.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/consultation_day_screen.dart';
|
||||
import '../../../route_names.dart';
|
||||
import 'package:medora/controllers/consultation_center_controller.dart';
|
||||
import 'package:medora/data/services/consultation_center_service.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorConsultationSchedule/consultation_day_screen.dart';
|
||||
import '../../../route/route_names.dart';
|
||||
|
||||
class CenterFeeAndDurationScreen extends StatefulWidget {
|
||||
final ConsultationCenterController controller;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/controllers/consultation_center_controller.dart';
|
||||
import 'package:telemednet/data/models/consultation_center.dart';
|
||||
import 'package:telemednet/data/services/consultation_center_service.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorConsultationSchedule/consultation_time_slot_screen.dart';
|
||||
import 'package:medora/controllers/consultation_center_controller.dart';
|
||||
import 'package:medora/data/models/consultation_center.dart';
|
||||
import 'package:medora/data/services/consultation_center_service.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorConsultationSchedule/consultation_time_slot_screen.dart';
|
||||
|
||||
class ConsultationDayScreen extends StatefulWidget {
|
||||
final ConsultationCenterController controller;
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:telemednet/data/models/consultation_center.dart';
|
||||
import 'package:telemednet/data/services/consultation_center_service.dart';
|
||||
import 'package:medora/data/models/consultation_center.dart';
|
||||
import 'package:medora/data/services/consultation_center_service.dart';
|
||||
|
||||
import '../../../common/custom_style.dart';
|
||||
import '../../../route_names.dart';
|
||||
import '../../../route/route_names.dart';
|
||||
|
||||
class ScheduleConsultationScreen extends StatefulWidget {
|
||||
const ScheduleConsultationScreen({super.key});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/controllers/consultation_center_controller.dart';
|
||||
import 'package:telemednet/data/models/consultation_center.dart';
|
||||
import 'package:medora/controllers/consultation_center_controller.dart';
|
||||
import 'package:medora/data/models/consultation_center.dart';
|
||||
|
||||
class ConsultationTimeSlotScreen extends StatefulWidget {
|
||||
final ConsultationCenterController controller;
|
||||
|
||||
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
import 'package:telemednet/screens/patientScreens/appoinmentBooking/speciality_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/appoinmentBooking/speciality_screen.dart';
|
||||
|
||||
class DoctorDashboardHomeScreen extends StatefulWidget {
|
||||
const DoctorDashboardHomeScreen({super.key});
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:curved_navigation_bar/curved_navigation_bar.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_dashboard_home_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_personal_profile_screen.dart';
|
||||
import 'package:telemednet/screens/doctorScreens/doctorDashboard/doctor_services_menu_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorDashboard/doctor_dashboard_home_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorDashboard/doctor_personal_profile_screen.dart';
|
||||
import 'package:medora/screens/doctorScreens/doctorDashboard/doctor_services_menu_screen.dart';
|
||||
|
||||
class DoctorDashboardScreen extends StatefulWidget {
|
||||
const DoctorDashboardScreen({super.key});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
class DoctorLandingScreen extends StatelessWidget {
|
||||
const DoctorLandingScreen({super.key});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
class DoctorPersonalProfileScreen extends StatefulWidget {
|
||||
const DoctorPersonalProfileScreen({super.key});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
class DoctorServicesMenuScreen extends StatefulWidget {
|
||||
const DoctorServicesMenuScreen({super.key});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/controllers/doctor_controller.dart';
|
||||
import 'package:medora/controllers/doctor_controller.dart';
|
||||
|
||||
import '../../../route_names.dart';
|
||||
import '../../../route/route_names.dart';
|
||||
|
||||
class AchievementsScreen extends StatefulWidget {
|
||||
final DoctorController controller;
|
||||
@ -57,6 +57,10 @@ class _AchievementsScreenState extends State<AchievementsScreen> {
|
||||
_showError('Achievement must be at least 3 characters long');
|
||||
return false;
|
||||
}
|
||||
if (!RegExp(r'^[a-zA-Z0-9\s.,]+$').hasMatch(value)) {
|
||||
_showError('Please enter valid achievement text');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/controllers/doctor_controller.dart';
|
||||
import 'package:medora/controllers/doctor_controller.dart';
|
||||
|
||||
import '../../../route_names.dart';
|
||||
import '../../../route/route_names.dart';
|
||||
|
||||
class DoctorAddressScreen extends StatefulWidget {
|
||||
final DoctorController? controller;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:io';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:telemednet/controllers/doctor_controller.dart';
|
||||
import 'package:medora/controllers/doctor_controller.dart';
|
||||
import '../../../data/services/doctor_profile_service.dart';
|
||||
import '../../../route_names.dart';
|
||||
import '../../../route/route_names.dart';
|
||||
|
||||
class DigitalSignatureScreen extends StatefulWidget {
|
||||
final DoctorController controller;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:telemednet/controllers/doctor_controller.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/controllers/doctor_controller.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
class ProfileUploadPage extends StatefulWidget {
|
||||
const ProfileUploadPage({super.key});
|
||||
@ -15,7 +15,7 @@ class _ProfileUploadPageState extends State<ProfileUploadPage> {
|
||||
final DoctorController _controller = DoctorController();
|
||||
final TextEditingController _titleController = TextEditingController();
|
||||
final TextEditingController _surnameController = TextEditingController();
|
||||
final TextEditingController _lastnameController = TextEditingController();
|
||||
final TextEditingController _firstController = TextEditingController();
|
||||
final TextEditingController _middlenameController = TextEditingController();
|
||||
File? _image;
|
||||
final ImagePicker _picker = ImagePicker();
|
||||
@ -31,7 +31,7 @@ class _ProfileUploadPageState extends State<ProfileUploadPage> {
|
||||
|
||||
_titleController.text = _controller.model.title ?? '';
|
||||
_surnameController.text = _controller.model.surName ?? '';
|
||||
_lastnameController.text = _controller.model.lastName ?? '';
|
||||
_firstController.text = _controller.model.firstName ?? '';
|
||||
_middlenameController.text = _controller.model.middleName ?? '';
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ class _ProfileUploadPageState extends State<ProfileUploadPage> {
|
||||
void dispose() {
|
||||
_titleController.dispose();
|
||||
_surnameController.dispose();
|
||||
_lastnameController.dispose();
|
||||
_firstController.dispose();
|
||||
_middlenameController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
@ -65,7 +65,7 @@ class _ProfileUploadPageState extends State<ProfileUploadPage> {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
_controller.updateTitle(_titleController.text);
|
||||
_controller.updateSurName(_surnameController.text);
|
||||
_controller.updateLastName(_lastnameController.text);
|
||||
_controller.updateLastName(_firstController.text);
|
||||
_controller.updateMiddleName(_middlenameController.text);
|
||||
return true;
|
||||
}
|
||||
@ -242,6 +242,7 @@ class _ProfileUploadPageState extends State<ProfileUploadPage> {
|
||||
children: [
|
||||
_buildUniformField(
|
||||
label: 'Name',
|
||||
|
||||
icon: Icons.person,
|
||||
child:
|
||||
Container(), // The child parameter is not used in this implementation
|
||||
@ -355,7 +356,7 @@ class _ProfileUploadPageState extends State<ProfileUploadPage> {
|
||||
),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: _lastnameController,
|
||||
controller: _firstController,
|
||||
onChanged: (value) {
|
||||
_controller.updateLastName(value);
|
||||
},
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:telemednet/controllers/doctor_controller.dart';
|
||||
import 'package:medora/controllers/doctor_controller.dart';
|
||||
|
||||
import '../../../route_names.dart';
|
||||
import '../../../route/route_names.dart';
|
||||
|
||||
class ExperienceScreen extends StatefulWidget {
|
||||
final DoctorController controller;
|
||||
@ -180,7 +180,7 @@ class _ExperienceScreenState extends State<ExperienceScreen> {
|
||||
if (value.length < 5) {
|
||||
return 'License number must be at least 5 digits';
|
||||
}
|
||||
if (!RegExp(r'^[0-9]+$').hasMatch(value)) {
|
||||
if (!RegExp(r'^[a-zA-Z0-9]+$').hasMatch(value)) {
|
||||
return 'Please enter numbers only';
|
||||
}
|
||||
return null;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/controllers/doctor_controller.dart';
|
||||
import '../../../route_names.dart';
|
||||
import 'package:medora/controllers/doctor_controller.dart';
|
||||
import '../../../route/route_names.dart';
|
||||
|
||||
class ProfileDescriptionScreen extends StatefulWidget {
|
||||
final DoctorController? controller;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/controllers/doctor_controller.dart';
|
||||
import '../../../route_names.dart';
|
||||
import 'package:medora/controllers/doctor_controller.dart';
|
||||
import '../../../route/route_names.dart';
|
||||
|
||||
class QualificationsScreen extends StatefulWidget {
|
||||
final DoctorController? controller;
|
||||
@ -82,12 +82,26 @@ class _QualificationsScreenState extends State<QualificationsScreen> {
|
||||
|
||||
if (_formKey.currentState!.validate() &&
|
||||
_validateQualification(qualification)) {
|
||||
setState(() {
|
||||
qualifications.add(qualification);
|
||||
_isEditing = true;
|
||||
_qualificationsController.clear();
|
||||
});
|
||||
_controller.addQualification(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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,8 +116,22 @@ class _QualificationsScreenState extends State<QualificationsScreen> {
|
||||
qualifications.remove(qualification);
|
||||
_controller.removeQualification(qualification);
|
||||
} else {
|
||||
qualifications.add(qualification);
|
||||
_controller.addQualification(qualification);
|
||||
// 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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/controllers/doctor_controller.dart';
|
||||
import '../../../route_names.dart';
|
||||
import 'package:medora/controllers/doctor_controller.dart';
|
||||
import '../../../route/route_names.dart';
|
||||
|
||||
class SpecialitiesScreen extends StatefulWidget {
|
||||
final DoctorController controller;
|
||||
|
||||
@ -2,13 +2,15 @@ import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:telemednet/data/models/consultation_center.dart';
|
||||
import 'package:telemednet/data/models/doctor.dart';
|
||||
import 'package:telemednet/data/services/consultation_booking_service.dart';
|
||||
import 'package:telemednet/data/services/patient_registration_service.dart';
|
||||
import 'package:telemednet/widgets/alert_screen.dart';
|
||||
import 'package:medora/data/models/consultation_center.dart';
|
||||
import 'package:medora/data/models/doctor.dart';
|
||||
import 'package:medora/data/models/patient.dart';
|
||||
import 'package:medora/data/services/consultation_booking_service.dart';
|
||||
import 'package:medora/data/services/patient_registration_service.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
import 'package:medora/widgets/alert_screen.dart';
|
||||
|
||||
class ConsultationBookingScreen extends StatelessWidget {
|
||||
class ConsultationBookingScreen extends StatefulWidget {
|
||||
final Doctor doctor;
|
||||
final ConsultationCenter selectedConsultation;
|
||||
final DateTime selectedDate;
|
||||
@ -21,13 +23,58 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
required this.selectedDate,
|
||||
required this.selectedTime,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ConsultationBookingScreen> createState() =>
|
||||
_ConsultationBookingScreenState();
|
||||
}
|
||||
|
||||
class _ConsultationBookingScreenState extends State<ConsultationBookingScreen> {
|
||||
PatientModel? selectedPatient;
|
||||
List<PatientModel> familyMembers = [];
|
||||
FamilyMember? selectedFamilyMember;
|
||||
bool isLoading = true;
|
||||
final TextEditingController _nameController = TextEditingController();
|
||||
final TextEditingController _relationController = TextEditingController();
|
||||
DateTime? _selectedDateOfBirth;
|
||||
String _selectedGender = 'Male';
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nameController.dispose();
|
||||
_relationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadPatientProfile();
|
||||
}
|
||||
|
||||
Future<void> _loadPatientProfile() async {
|
||||
setState(() => isLoading = true);
|
||||
try {
|
||||
final currentPatient = await PatientProfileService.getPatientProfile();
|
||||
if (currentPatient != null) {
|
||||
setState(() {
|
||||
selectedPatient = currentPatient;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error loading patient data: $e');
|
||||
} finally {
|
||||
setState(() => isLoading = false);
|
||||
}
|
||||
}
|
||||
|
||||
String get formattedAddress {
|
||||
final parts = [
|
||||
selectedConsultation.floorBuilding,
|
||||
selectedConsultation.street,
|
||||
selectedConsultation.city,
|
||||
selectedConsultation.state,
|
||||
selectedConsultation.postalCode
|
||||
widget.selectedConsultation.floorBuilding,
|
||||
widget.selectedConsultation.street,
|
||||
widget.selectedConsultation.city,
|
||||
widget.selectedConsultation.state,
|
||||
widget.selectedConsultation.postalCode
|
||||
].where((part) => part != null && part.isNotEmpty).toList();
|
||||
return parts.join(', ');
|
||||
}
|
||||
@ -51,6 +98,8 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
const SizedBox(height: 24),
|
||||
_buildPaymentDetails(),
|
||||
const SizedBox(height: 24),
|
||||
_buildInClinicAppointmentText(),
|
||||
const SizedBox(height: 24),
|
||||
_buildConfirmButton(context),
|
||||
],
|
||||
),
|
||||
@ -59,6 +108,63 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInClinicAppointmentText() {
|
||||
String patientName =
|
||||
selectedFamilyMember?.name ?? selectedPatient?.name ?? 'Select Patient';
|
||||
String relation = selectedFamilyMember?.relation != null
|
||||
? ' (${selectedFamilyMember!.relation})'
|
||||
: '';
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 16,
|
||||
color: Colors.black87,
|
||||
),
|
||||
children: [
|
||||
const TextSpan(text: 'In-clinic appointment for '),
|
||||
TextSpan(
|
||||
text: '$patientName$relation',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _showPatientSelectionDialog,
|
||||
child: Text(
|
||||
'Change',
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.blue,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
PreferredSizeWidget _buildAppBar(BuildContext context) {
|
||||
return AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
@ -100,7 +206,7 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
const Icon(Icons.calendar_today, color: Colors.white),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
DateFormat('EEEE, MMMM d').format(selectedDate),
|
||||
DateFormat('EEEE, MMMM d').format(widget.selectedDate),
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
@ -115,7 +221,7 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
const Icon(Icons.access_time, color: Colors.white),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
selectedTime,
|
||||
widget.selectedTime,
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
@ -147,8 +253,8 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Image.asset(
|
||||
doctor.profileImage!,
|
||||
child: Image.network(
|
||||
widget.doctor.profileImage!,
|
||||
width: 80,
|
||||
height: 80,
|
||||
fit: BoxFit.cover,
|
||||
@ -168,21 +274,21 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
doctor.lastName!,
|
||||
widget.doctor.firstName ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
doctor.speciality!,
|
||||
widget.doctor.speciality!,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'${doctor.yearsOfExperience} years experience',
|
||||
'${widget.doctor.yearsOfExperience} years experience',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[600],
|
||||
@ -230,7 +336,7 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Average consultation time: ${selectedConsultation.averageDurationMinutes} minutes',
|
||||
'Average consultation time: ${widget.selectedConsultation.averageDurationMinutes} minutes',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[600],
|
||||
@ -277,7 +383,7 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'₹${selectedConsultation.consultationFee ?? "500"}',
|
||||
'₹${widget.selectedConsultation.consultationFee ?? "500"}',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
@ -318,14 +424,24 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
}
|
||||
|
||||
void _showConfirmationDialog(BuildContext context) async {
|
||||
final bookingService = BookingService();
|
||||
final currentUser = FirebaseAuth.instance.currentUser;
|
||||
final patientProfile = await PatientProfileService.getPatientProfile();
|
||||
|
||||
if (patientProfile == null) {
|
||||
if (selectedPatient == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Please select a patient for the appointment'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final bookingService = BookingService();
|
||||
final currentUser = FirebaseAuth.instance.currentUser;
|
||||
|
||||
// Get the correct patient name based on selection
|
||||
final patientName = selectedFamilyMember != null
|
||||
? selectedFamilyMember!.name
|
||||
: selectedPatient!.name;
|
||||
|
||||
try {
|
||||
if (context.mounted) {
|
||||
showDialog(
|
||||
@ -338,15 +454,15 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
}
|
||||
|
||||
final bookingId = await bookingService.createBooking(
|
||||
doctorName: doctor.lastName!,
|
||||
doctorName: widget.doctor.firstName ?? 'Doctor',
|
||||
patientId: currentUser!.uid,
|
||||
patientName: patientProfile.name ?? 'Patient',
|
||||
patientName: patientName ?? 'Patient',
|
||||
location: formattedAddress,
|
||||
appointmentDate: selectedDate,
|
||||
appointmentTime: selectedTime,
|
||||
appointmentDate: widget.selectedDate,
|
||||
appointmentTime: widget.selectedTime,
|
||||
consultationFee:
|
||||
int.parse(selectedConsultation.consultationFee ?? "500"),
|
||||
specialization: doctor.speciality!,
|
||||
int.parse(widget.selectedConsultation.consultationFee ?? "500"),
|
||||
specialization: widget.doctor.speciality!,
|
||||
);
|
||||
|
||||
if (context.mounted) {
|
||||
@ -358,11 +474,12 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
arguments: AlertArguments(
|
||||
title: 'Booking Confirmed',
|
||||
message:
|
||||
'Your appointment has been successfully booked. Booking ID: ${bookingId.substring(0, 8)}\n\nPlease complete the payment to confirm your appointment.',
|
||||
'Your in-clinic appointment has been successfully booked for $patientName. Booking ID: ${bookingId.substring(0, 8)}\n\nPlease complete the payment to confirm your appointment.',
|
||||
actionTitle: 'View Appointments',
|
||||
type: AlertType.success,
|
||||
onActionPressed: () {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
Navigator.pushReplacementNamed(
|
||||
context, RouteNames.patientDashboardScreen);
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -391,4 +508,333 @@ class ConsultationBookingScreen extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _showAddFamilyMemberDialog() async {
|
||||
_nameController.clear();
|
||||
_relationController.clear();
|
||||
setState(() {
|
||||
_selectedDateOfBirth = null;
|
||||
_selectedGender = 'Male';
|
||||
});
|
||||
|
||||
return showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext dialogContext) => StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setDialogState) {
|
||||
return AlertDialog(
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||
title: Text(
|
||||
'Add Family Member',
|
||||
style: GoogleFonts.poppins(fontWeight: FontWeight.w600),
|
||||
),
|
||||
content: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _nameController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Full Name',
|
||||
labelStyle: GoogleFonts.poppins(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
prefixIcon: const Icon(
|
||||
Icons.person_outline,
|
||||
color: Colors.blue,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _relationController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Relation',
|
||||
labelStyle: GoogleFonts.poppins(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
prefixIcon: const Icon(
|
||||
Icons.family_restroom,
|
||||
color: Colors.blue,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
final DateTime? picked = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: DateTime.now(),
|
||||
firstDate: DateTime(1900),
|
||||
lastDate: DateTime.now(),
|
||||
builder: (context, child) {
|
||||
return Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
colorScheme: ColorScheme.light(
|
||||
primary: Colors.blue,
|
||||
onPrimary: Colors.white,
|
||||
surface: Colors.grey[100]!,
|
||||
),
|
||||
),
|
||||
child: child!,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (picked != null) {
|
||||
setDialogState(() {
|
||||
_selectedDateOfBirth = picked;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey[300]!),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.calendar_today,
|
||||
color: Colors.blue),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
_selectedDateOfBirth != null
|
||||
? DateFormat('dd/MM/yyyy')
|
||||
.format(_selectedDateOfBirth!)
|
||||
: 'Select Date of Birth',
|
||||
style: GoogleFonts.poppins(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey[300]!),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: _selectedGender,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.person_outline,
|
||||
color: Colors.blue),
|
||||
border: InputBorder.none,
|
||||
labelStyle: GoogleFonts.poppins(),
|
||||
),
|
||||
items: ['Male', 'Female', 'Other']
|
||||
.map((gender) => DropdownMenuItem(
|
||||
value: gender,
|
||||
child: Text(gender,
|
||||
style: GoogleFonts.poppins()),
|
||||
))
|
||||
.toList(),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
setDialogState(() => _selectedGender = value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: GoogleFonts.poppins(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => _addFamilyMember(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue,
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
'Add Member',
|
||||
style: GoogleFonts.poppins(color: Colors.white),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _addFamilyMember(BuildContext context) async {
|
||||
if (_nameController.text.isEmpty ||
|
||||
_relationController.text.isEmpty ||
|
||||
_selectedDateOfBirth == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'Please fill in all fields',
|
||||
style: GoogleFonts.poppins(),
|
||||
),
|
||||
backgroundColor: Colors.red,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final newFamilyMember = FamilyMember(
|
||||
name: _nameController.text,
|
||||
relation: _relationController.text,
|
||||
gender: _selectedGender,
|
||||
dateOfBirth: _selectedDateOfBirth,
|
||||
);
|
||||
|
||||
if (selectedPatient != null) {
|
||||
selectedPatient!.familyMembers.add(newFamilyMember);
|
||||
await PatientProfileService.updatePatientProfile(selectedPatient!);
|
||||
|
||||
setState(() {
|
||||
selectedFamilyMember = newFamilyMember;
|
||||
});
|
||||
}
|
||||
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context);
|
||||
|
||||
_showPatientSelectionDialog();
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context); // Pop add family member dialog
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _showPatientSelectionDialog() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||
title: Text(
|
||||
'Select Patient',
|
||||
style: GoogleFonts.poppins(fontWeight: FontWeight.w600),
|
||||
),
|
||||
content: SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
// Main patient
|
||||
_buildPatientTile(
|
||||
name: selectedPatient?.name ?? '',
|
||||
subtitle: 'Primary Patient',
|
||||
isSelected: selectedFamilyMember == null,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectedFamilyMember = null;
|
||||
});
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
// Family members
|
||||
...selectedPatient?.familyMembers.map(
|
||||
(member) => _buildPatientTile(
|
||||
name: member.name ?? '',
|
||||
subtitle: member.relation ?? '',
|
||||
isSelected: selectedFamilyMember == member,
|
||||
onTap: () {
|
||||
setState(() {
|
||||
selectedFamilyMember = member;
|
||||
});
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
) ??
|
||||
[],
|
||||
const Divider(),
|
||||
ListTile(
|
||||
leading: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(Icons.person_add, color: Colors.blue),
|
||||
),
|
||||
title: Text(
|
||||
'Add Family Member',
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.blue,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
_showAddFamilyMemberDialog();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPatientTile({
|
||||
required String name,
|
||||
required String subtitle,
|
||||
required bool isSelected,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return ListTile(
|
||||
leading: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? Colors.blue.withOpacity(0.1)
|
||||
: Colors.grey.withOpacity(0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.person,
|
||||
color: isSelected ? Colors.blue : Colors.grey,
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
name,
|
||||
style: GoogleFonts.poppins(
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
|
||||
color: isSelected ? Colors.blue : Colors.black87,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
subtitle,
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
trailing: isSelected
|
||||
? const Icon(Icons.check_circle, color: Colors.blue)
|
||||
: null,
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:telemednet/data/models/consultation_center.dart';
|
||||
import 'package:telemednet/data/models/doctor.dart';
|
||||
import 'package:medora/data/models/consultation_center.dart';
|
||||
import 'package:medora/data/models/doctor.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
class ConsultationTimeScreen extends StatefulWidget {
|
||||
final Doctor doctor;
|
||||
@ -134,7 +134,7 @@ class _ConsultationTimeScreenState extends State<ConsultationTimeScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.doctor.lastName!,
|
||||
widget.doctor.firstName ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
@ -152,7 +152,7 @@ class _ConsultationTimeScreenState extends State<ConsultationTimeScreen> {
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Image.asset(
|
||||
child: Image.network(
|
||||
widget.doctor.profileImage!,
|
||||
width: 60,
|
||||
height: 60,
|
||||
@ -474,7 +474,7 @@ class _ConsultationTimeScreenState extends State<ConsultationTimeScreen> {
|
||||
children: [
|
||||
_buildConfirmationDetail(
|
||||
'Doctor',
|
||||
widget.doctor.lastName!,
|
||||
widget.doctor.firstName!,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_buildConfirmationDetail(
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:telemednet/data/models/doctor.dart';
|
||||
import 'package:telemednet/data/models/consultation_center.dart';
|
||||
import 'package:telemednet/data/services/consultation_center_service.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/data/models/doctor.dart';
|
||||
import 'package:medora/data/models/consultation_center.dart';
|
||||
import 'package:medora/data/services/consultation_center_service.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
class ConsultationsCenterScreen extends StatefulWidget {
|
||||
final Doctor doctor;
|
||||
@ -143,7 +143,7 @@ class _ConsultationsCenterScreenState extends State<ConsultationsCenterScreen> {
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Image.asset(
|
||||
child: Image.network(
|
||||
widget.doctor.profileImage!,
|
||||
width: 80,
|
||||
height: 80,
|
||||
@ -164,7 +164,7 @@ class _ConsultationsCenterScreenState extends State<ConsultationsCenterScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.doctor.lastName!,
|
||||
widget.doctor.firstName ?? "",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:telemednet/data/models/doctor.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/data/models/doctor.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
class DoctorDetailsScreen extends StatelessWidget {
|
||||
final Doctor doctor;
|
||||
@ -115,7 +115,7 @@ class DoctorDetailsScreen extends StatelessWidget {
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Image.asset(
|
||||
child: Image.network(
|
||||
doctor.profileImage!,
|
||||
width: 100,
|
||||
height: 100,
|
||||
@ -137,7 +137,7 @@ class DoctorDetailsScreen extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
doctor.lastName!,
|
||||
doctor.firstName ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
||||
@ -2,9 +2,9 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:telemednet/data/models/doctor.dart';
|
||||
import 'package:medora/data/models/doctor.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
class DoctorsListScreen extends StatefulWidget {
|
||||
final String specialty;
|
||||
@ -174,7 +174,7 @@ class _DoctorsListScreenState extends State<DoctorsListScreen> {
|
||||
.where((doctor) {
|
||||
if (_searchController.text.isEmpty) return true;
|
||||
final searchQuery = _searchController.text.toLowerCase();
|
||||
return doctor.surName!.toLowerCase().contains(searchQuery) ||
|
||||
return doctor.firstName!.toLowerCase().contains(searchQuery) ||
|
||||
doctor.city!.toLowerCase().contains(searchQuery);
|
||||
}).toList();
|
||||
|
||||
@ -244,7 +244,7 @@ class _DoctorsListScreenState extends State<DoctorsListScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
doctor.surName!,
|
||||
doctor.firstName ?? '',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
||||
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:animate_do/animate_do.dart';
|
||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
class Specialty {
|
||||
final String name;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:curved_navigation_bar/curved_navigation_bar.dart';
|
||||
import 'package:telemednet/screens/patientScreens/patientDashboard/patient_home_screen.dart';
|
||||
import 'package:telemednet/screens/patientScreens/patientDashboard/patient_profile_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/patientDashboard/patient_home_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/patientDashboard/patient_profile_screen.dart';
|
||||
|
||||
class PatientDashboardScreen extends StatefulWidget {
|
||||
const PatientDashboardScreen({super.key});
|
||||
@ -46,8 +46,8 @@ class _PatientDashboardScreenState extends State<PatientDashboardScreen> {
|
||||
index: _selectedIndex,
|
||||
items: const [
|
||||
Icon(Icons.home, size: 30, color: Colors.white),
|
||||
// Icon(Icons.chat_bubble, size: 30, color: Colors.white),
|
||||
Icon(Icons.list, size: 30, color: Colors.white),
|
||||
Icon(Icons.chat_bubble, size: 30, color: Colors.white),
|
||||
Icon(Icons.assignment, size: 30, color: Colors.white),
|
||||
Icon(Icons.person, size: 30, color: Colors.white),
|
||||
],
|
||||
onTap: (index) {
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:medora/data/models/consultation_booking.dart';
|
||||
import 'package:medora/data/services/consultation_booking_service.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
|
||||
import 'package:telemednet/screens/patientScreens/appoinmentBooking/speciality_screen.dart';
|
||||
import 'package:medora/screens/patientScreens/appoinmentBooking/speciality_screen.dart';
|
||||
|
||||
class PatientHomeScreen extends StatefulWidget {
|
||||
const PatientHomeScreen({super.key});
|
||||
@ -14,6 +19,8 @@ class PatientHomeScreen extends StatefulWidget {
|
||||
class _PatientHomeScreenState extends State<PatientHomeScreen>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
final BookingService _bookingService = BookingService();
|
||||
late Stream<List<Booking>> _bookingsStream;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -23,6 +30,14 @@ class _PatientHomeScreenState extends State<PatientHomeScreen>
|
||||
duration: const Duration(milliseconds: 300),
|
||||
);
|
||||
_animationController.forward();
|
||||
|
||||
final User? user = FirebaseAuth.instance.currentUser;
|
||||
if (user != null) {
|
||||
final String userId = user.uid;
|
||||
_bookingsStream = _bookingService.getPatientBookings(userId);
|
||||
} else {
|
||||
_bookingsStream = const Stream.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@ -50,7 +65,6 @@ class _PatientHomeScreenState extends State<PatientHomeScreen>
|
||||
],
|
||||
),
|
||||
),
|
||||
// _buildBottomNavBar(),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -61,14 +75,7 @@ class _PatientHomeScreenState extends State<PatientHomeScreen>
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Colors.blue[400]!,
|
||||
Colors.blue[300]!,
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
color: Colors.blue,
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(30.0),
|
||||
bottomRight: Radius.circular(30.0),
|
||||
@ -179,47 +186,161 @@ class _PatientHomeScreenState extends State<PatientHomeScreen>
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Upcoming Consultations',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Upcoming Consultations',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey[800],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: 20),
|
||||
SizedBox(
|
||||
height: 160,
|
||||
child: ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: [
|
||||
_consultationCard(
|
||||
'Dr. Smith', '23/09/2024\n5:00 PM - 6:00 PM', 'Cardiologist'),
|
||||
const SizedBox(width: 16),
|
||||
_consultationCard('Dr. Johnson', '24/09/2024\n3:30 PM - 4:30 PM',
|
||||
'Pediatrician'),
|
||||
],
|
||||
height: 201,
|
||||
child: StreamBuilder<List<Booking>>(
|
||||
stream: _bookingsStream,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'Loading consultations...',
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.error_outline,
|
||||
color: Colors.red[400], size: 48),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'Error loading consultations',
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.red[400],
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// Implement refresh logic
|
||||
},
|
||||
child: Text(
|
||||
'Try Again',
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.blue[700],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final bookings = snapshot.data ?? [];
|
||||
|
||||
if (bookings.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.calendar_today,
|
||||
color: Colors.grey[400], size: 48),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'No upcoming consultations',
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.grey[600],
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// Navigate to book consultation
|
||||
},
|
||||
child: Text(
|
||||
'Book a Consultation',
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.blue[700],
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: bookings.length,
|
||||
itemBuilder: (context, index) {
|
||||
final booking = bookings[index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 16),
|
||||
child: Hero(
|
||||
tag: 'consultation_${booking.id}',
|
||||
child: Material(
|
||||
child: _consultationCard(
|
||||
booking.doctorName,
|
||||
'${DateFormat('EEE, MMM d, yyyy').format(booking.appointmentDate)}\n${booking.appointmentTime}',
|
||||
booking.specialization,
|
||||
booking.paymentStatus,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _consultationCard(String name, String schedule, String speciality) {
|
||||
Widget _consultationCard(
|
||||
String name,
|
||||
String schedule,
|
||||
String speciality,
|
||||
PaymentStatus paymentStatus,
|
||||
) {
|
||||
return Container(
|
||||
width: 280,
|
||||
padding: const EdgeInsets.all(16),
|
||||
width: 300,
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.white, Colors.grey[50]!],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.2),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 5),
|
||||
color: Colors.grey.withOpacity(0.1),
|
||||
blurRadius: 20,
|
||||
offset: const Offset(0, 8),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -229,19 +350,30 @@ class _PatientHomeScreenState extends State<PatientHomeScreen>
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue[100],
|
||||
gradient: LinearGradient(
|
||||
colors: [Colors.blue[400]!, Colors.blue[600]!],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.blue[300]!.withOpacity(0.3),
|
||||
blurRadius: 12,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.person,
|
||||
size: 40,
|
||||
size: 36,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -249,14 +381,50 @@ class _PatientHomeScreenState extends State<PatientHomeScreen>
|
||||
Text(
|
||||
name,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 16,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey[800],
|
||||
),
|
||||
),
|
||||
Text(
|
||||
speciality,
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.grey[600],
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _getStatusColor(paymentStatus).withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(
|
||||
color:
|
||||
_getStatusColor(paymentStatus).withOpacity(0.2),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
_getStatusIcon(paymentStatus),
|
||||
size: 14,
|
||||
color: _getStatusColor(paymentStatus),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
_getStatusText(paymentStatus),
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: _getStatusColor(paymentStatus),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -264,26 +432,79 @@ class _PatientHomeScreenState extends State<PatientHomeScreen>
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue[50],
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(
|
||||
schedule,
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.blue[700],
|
||||
fontSize: 12,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: Colors.blue[100]!,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.calendar_today,
|
||||
size: 18,
|
||||
color: Colors.blue[700],
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
schedule,
|
||||
style: GoogleFonts.poppins(
|
||||
color: Colors.blue[700],
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
IconData _getStatusIcon(PaymentStatus status) {
|
||||
switch (status) {
|
||||
case PaymentStatus.completed:
|
||||
return Icons.check_circle;
|
||||
case PaymentStatus.pending:
|
||||
return Icons.access_time;
|
||||
case PaymentStatus.failed:
|
||||
return Icons.error;
|
||||
default:
|
||||
return Icons.info;
|
||||
}
|
||||
}
|
||||
|
||||
Color _getStatusColor(PaymentStatus status) {
|
||||
switch (status) {
|
||||
case PaymentStatus.pending:
|
||||
return Colors.orange;
|
||||
case PaymentStatus.completed:
|
||||
return Colors.green;
|
||||
case PaymentStatus.failed:
|
||||
return Colors.red;
|
||||
default:
|
||||
return Colors.grey;
|
||||
}
|
||||
}
|
||||
|
||||
String _getStatusText(PaymentStatus status) {
|
||||
switch (status) {
|
||||
case PaymentStatus.pending:
|
||||
return 'Payment Pending';
|
||||
case PaymentStatus.completed:
|
||||
return 'Confirmed';
|
||||
case PaymentStatus.failed:
|
||||
return 'Payment Failed';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildFindDoctorSection() {
|
||||
final specialistData = [
|
||||
{
|
||||
@ -396,7 +617,13 @@ class _PatientHomeScreenState extends State<PatientHomeScreen>
|
||||
}) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
// Replace with your desired navigation action
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
RouteNames.doctorListScreen,
|
||||
arguments: {
|
||||
'specialty': label,
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: 140,
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:medora/data/services/patient_registration_service.dart';
|
||||
import 'package:medora/route/route_names.dart';
|
||||
import 'package:medora/data/models/patient.dart';
|
||||
|
||||
class PatientProfileScreen extends StatefulWidget {
|
||||
const PatientProfileScreen({super.key});
|
||||
@ -11,7 +13,23 @@ class PatientProfileScreen extends StatefulWidget {
|
||||
|
||||
class _PatientProfileScreenState extends State<PatientProfileScreen> {
|
||||
final FirebaseAuth _auth = FirebaseAuth.instance;
|
||||
// final GlobalKey<CurvedNavigationBarState> _bottomNavigationKey = GlobalKey();
|
||||
PatientModel? _patientProfile;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_fetchPatientProfile();
|
||||
}
|
||||
|
||||
Future<void> _fetchPatientProfile() async {
|
||||
final patientProfile = await PatientProfileService.getPatientProfile();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_patientProfile = patientProfile;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -20,8 +38,6 @@ class _PatientProfileScreenState extends State<PatientProfileScreen> {
|
||||
children: [
|
||||
_buildProfileHeader(),
|
||||
_buildProfileOptions(),
|
||||
const Spacer(),
|
||||
// _buildBottomNavBar(),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -50,41 +66,46 @@ class _PatientProfileScreenState extends State<PatientProfileScreen> {
|
||||
Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
decoration: const BoxDecoration(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
shape: BoxShape.circle,
|
||||
image: _patientProfile?.profileImageUrl != null
|
||||
? DecorationImage(
|
||||
image: NetworkImage(_patientProfile!.profileImageUrl!),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'D',
|
||||
style: TextStyle(
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: _patientProfile?.profileImageUrl == null
|
||||
? Center(
|
||||
child: Text(
|
||||
_patientProfile != null && _patientProfile!.name != null
|
||||
? _patientProfile!.name![0].toUpperCase()
|
||||
: '',
|
||||
style: const TextStyle(
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue,
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
const Expanded(
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Dhansh A S',
|
||||
style: TextStyle(
|
||||
_patientProfile != null && _patientProfile!.name != null
|
||||
? _patientProfile!.name!
|
||||
: 'Create your profile',
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'User profile is incomplete',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.white70,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -117,7 +138,9 @@ class _PatientProfileScreenState extends State<PatientProfileScreen> {
|
||||
_buildOptionTile(
|
||||
'Medical Profile',
|
||||
Icons.medical_information_outlined,
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
// Add navigation or action
|
||||
},
|
||||
),
|
||||
const Divider(height: 1),
|
||||
_buildOptionTile(
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import 'package:medora/route/route_names.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
|
||||
class PatientLandingScreen extends StatelessWidget {
|
||||
const PatientLandingScreen({super.key});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/controllers/patient_controller.dart';
|
||||
import 'package:telemednet/data/models/patient.dart';
|
||||
import 'package:medora/controllers/patient_controller.dart';
|
||||
import 'package:medora/data/models/patient.dart';
|
||||
|
||||
class FamilyMembersEditScreen extends StatefulWidget {
|
||||
final FamilyMember? familyMember;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:medora/controllers/patient_controller.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:country_state_city_picker/country_state_city_picker.dart';
|
||||
import 'package:telemednet/controllers/patient_controller.dart';
|
||||
|
||||
class PatientAddressScreen extends StatefulWidget {
|
||||
final PatientController? controller;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:medora/data/models/patient.dart';
|
||||
import 'package:medora/screens/patientScreens/registrationScreens/family_members_edit_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/screens/patientScreens/registrationScreens/family_members_edit_screen.dart';
|
||||
import 'package:telemednet/data/models/patient.dart';
|
||||
import '../../../controllers/patient_controller.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:medora/route/route_names.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
38
lib/screens/splash_screen.dart
Normal file
@ -0,0 +1,38 @@
|
||||
import 'package:medora/data/services/navigation_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SplashScreen extends StatefulWidget {
|
||||
const SplashScreen({super.key});
|
||||
|
||||
@override
|
||||
State<SplashScreen> createState() => _SplashScreenState();
|
||||
}
|
||||
|
||||
class _SplashScreenState extends State<SplashScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Future.delayed(const Duration(seconds: 3), () {
|
||||
if (!mounted) return;
|
||||
_navigateToAppropriateScreen();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _navigateToAppropriateScreen() async {
|
||||
await NavigationService.handleUserNavigation(context);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
decoration: const BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage('images/splash_screen.jpg'),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
import 'package:medora/route/route_names.dart';
|
||||
import 'package:medora/route/routes.dart';
|
||||
import 'package:medora/screens/splash_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:telemednet/route_names.dart';
|
||||
import 'package:telemednet/routes.dart';
|
||||
|
||||
class TelemednetApp extends StatefulWidget {
|
||||
const TelemednetApp({super.key});
|
||||
@ -15,14 +16,15 @@ class _TelemednetAppState extends State<TelemednetApp> {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
Future<void> login() async {}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
initialRoute: RouteNames.launch,
|
||||
routes: routes,
|
||||
initialRoute: RouteNames.splashScreen,
|
||||
routes: {
|
||||
RouteNames.splashScreen: (context) => const SplashScreen(),
|
||||
...routes,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
182
pubspec.lock
@ -9,6 +9,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.44"
|
||||
animate_do:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: animate_do
|
||||
sha256: "7a3162729f0ea042f9dd84da217c5bde5472ad9cef644079929d4304a5dc4ca0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.4"
|
||||
animations:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: animations
|
||||
sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.11"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.6.1"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -33,6 +57,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
carousel_slider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: carousel_slider
|
||||
sha256: "7b006ec356205054af5beaef62e2221160ea36b90fb70a35e4deacd49d0349ae"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -41,6 +73,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
cli_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.2"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -121,6 +169,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
curved_navigation_bar:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: curved_navigation_bar
|
||||
sha256: bb4ab128fcb6f4a9f0f1f72d227db531818b20218984789777f049fcbf919279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
desktop_webview_auth:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -145,6 +201,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
fhir:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -326,6 +390,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.2.1"
|
||||
flutter_launcher_icons:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_launcher_icons
|
||||
sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.14.1"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -355,6 +427,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
flutter_staggered_animations:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_staggered_animations
|
||||
sha256: "81d3c816c9bb0dca9e8a5d5454610e21ffb068aedb2bde49d2f8d04f75538351"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter_staggered_grid_view:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_staggered_grid_view
|
||||
sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
flutter_svg:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -389,6 +477,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
google_fonts:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: google_fonts
|
||||
sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.1"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -405,6 +501,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.3.0"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -558,7 +662,7 @@ packages:
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path
|
||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||
@ -569,10 +673,58 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_parsing
|
||||
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
|
||||
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.0.1"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.12"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -581,6 +733,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.2"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.6"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -589,6 +749,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
shimmer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shimmer
|
||||
sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -714,6 +882,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
12
pubspec.yaml
@ -1,4 +1,4 @@
|
||||
name: telemednet
|
||||
name: medora
|
||||
description: "A new Flutter project."
|
||||
# The following line prevents the package from being accidentally published to
|
||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||
@ -57,6 +57,8 @@ dependencies:
|
||||
flutter_staggered_animations: ^1.1.1
|
||||
flutter_staggered_grid_view: ^0.7.0
|
||||
carousel_slider: ^5.0.0
|
||||
path: ^1.9.0
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -68,13 +70,18 @@ dev_dependencies:
|
||||
# package. See that file for information about deactivating specific lint
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^4.0.0
|
||||
flutter_launcher_icons: ^0.14.1
|
||||
flutter_icons:
|
||||
android: true
|
||||
ios: true
|
||||
image_path: "images/logo.jpg"
|
||||
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
# The following section is specific to Flutter packages.
|
||||
flutter:
|
||||
|
||||
# The following line ensures that the Material Icons font is
|
||||
# included with your application, so that you can use the icons in
|
||||
# the material Icons class.
|
||||
@ -90,6 +97,7 @@ flutter:
|
||||
- images/patient-avathar.png
|
||||
- images/MaleDr.jpg.png
|
||||
- images/FemaleDr.jpg.png
|
||||
- images/splash_screen.jpg
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/to/resolution-aware-images
|
||||
|
||||