Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions patient/lib/presentation/activities/daily_activities_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:easy_date_timeline/easy_date_timeline.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../../core/core.dart';
import '../../core/theme/theme.dart';
import '../../provider/task_provider.dart';

Expand Down Expand Up @@ -55,18 +56,35 @@ class _DailyActivitiesScreenState extends State<DailyActivitiesScreen>

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Daily Activities'),
centerTitle: true,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new_rounded),
onPressed: () {
// context.read<TaskProvider>().updateActivityInBackground(); // TODO: Uncomment this when the backend is ready
Navigator.pop(context);
},
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) async {
if (didPop) return;
final taskProvider = context.read<TaskProvider>();
try {
await taskProvider.updateActivityInBackground();
if (taskProvider.syncStatus == ApiStatus.failure && mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Failed to save your progress'),
backgroundColor: Colors.red,
duration: Duration(seconds: 2),
),
);
}
} finally {
if (mounted) Navigator.pop(context);
}
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
child: Scaffold(
appBar: AppBar(
title: const Text('Daily Activities'),
centerTitle: true,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new_rounded),
onPressed: () => Navigator.maybePop(context),
),
),
),
body: Consumer<TaskProvider>(
builder: (context, taskProvider, child) {
final tasks = taskProvider.tasks;
Expand Down Expand Up @@ -229,6 +247,7 @@ class _DailyActivitiesScreenState extends State<DailyActivitiesScreen>
);
},
),
),
);
}
}
26 changes: 23 additions & 3 deletions patient/lib/provider/task_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class TaskProvider extends ChangeNotifier {
DateTime _selectedDate = DateTime.now();
final PatientRepository _patientRepository;
ApiStatus _apiStatus = ApiStatus.initial;
ApiStatus _syncStatus = ApiStatus.initial;
String? _activityId;
String? _activitySetId;

Expand Down Expand Up @@ -39,9 +40,13 @@ class TaskProvider extends ChangeNotifier {
}
}

Future<void> updateActivityCompletion(List<PatientTaskModel> tasks) async {
Future<void> updateActivityCompletion() async {
try {
final result = await _patientRepository.updateActivityCompletion(tasks: _allTasks, activityId: _activityId, activitySetId: _activitySetId);
final result = await _patientRepository.updateActivityCompletion(
tasks: _allTasks,
activityId: _activityId,
activitySetId: _activitySetId,
);
if(result is ActionResultSuccess) {
_apiStatus = ApiStatus.success;
} else {
Expand All @@ -60,7 +65,7 @@ class TaskProvider extends ChangeNotifier {
_selectedDate = date;
notifyListeners();
if(_allTasks.isNotEmpty) {
updateActivityCompletion(_allTasks);
updateActivityCompletion();
}
getTodayActivities(date: date);
}
Expand All @@ -76,6 +81,21 @@ class TaskProvider extends ChangeNotifier {
notifyListeners();
}

/// Updates activity completion status in the background (typically before navigation)
/// This method syncs the current task completion status to the backend
Future<void> updateActivityInBackground() async {
if (_allTasks.isEmpty || _syncStatus == ApiStatus.loading) {
return;
}
_syncStatus = ApiStatus.loading;
notifyListeners();
await updateActivityCompletion();
// updateActivityCompletion sets _apiStatus, copy it to _syncStatus
_syncStatus = _apiStatus;
notifyListeners();
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

int get completedTasksCount => tasks.where((task) => task.isCompleted ?? false).length;
int get totalTasksCount => tasks.length;
ApiStatus get syncStatus => _syncStatus;
}
113 changes: 49 additions & 64 deletions therapist/lib/presentation/home/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ class _HomeScreenState extends State<HomeScreen> {
WidgetsBinding.instance.addPostFrameCallback((_) {
Provider.of<ConsultationProvider>(context, listen: false)
.fetchConsultationRequests();
Provider.of<TherapistDataProvider>(context, listen: false)
.fetchPatientsMappedToTherapist();
final therapistProvider = Provider.of<TherapistDataProvider>(context, listen: false);
therapistProvider.fetchPatientsMappedToTherapist();
therapistProvider.fetchTotals();
Provider.of<SessionProvider>(context, listen: false)
.fetchTherapistSessions();
});

_refreshTimer = Timer.periodic(const Duration(minutes: 3), (_) {
Expand Down Expand Up @@ -211,72 +214,54 @@ class HomeContent extends StatelessWidget {
child: ListView(
padding: const EdgeInsets.all(20),
children: [
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
StatsCard(
imagePath: 'assets/icon1.png',
backgroundColor: Color(0xFFFEE8E8),
label: 'Patients',
value: '02',
),
StatsCard(
imagePath: 'assets/icon2.png',
backgroundColor: Color(0xFFF1E8FE),
label: 'Sessions',
value: '20',
Consumer<TherapistDataProvider>(
builder: (context, therapistProvider, _) {
if (therapistProvider.isTotalsLoading) {
return const Center(child: CircularProgressIndicator());
}

return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
StatsCard(
imagePath: 'assets/icon3.png',
backgroundColor: Color(0xFFE8FEF0),
label: 'Therapies',
value: '13',
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
StatsCard(
imagePath: 'assets/icon1.png',
backgroundColor: const Color(0xFFFEE8E8),
label: 'Patients',
value: therapistProvider.totalPatients.toString(),
),
StatsCard(
imagePath: 'assets/icon2.png',
backgroundColor: const Color(0xFFF1E8FE),
label: 'Sessions',
value: therapistProvider.totalSessions.toString(),
),
StatsCard(
imagePath: 'assets/icon3.png',
backgroundColor: const Color(0xFFE8FEF0),
label: 'Therapies',
value: therapistProvider.totalTherapies.toString(),
),
],
),
],
),
);
},
),
const SizedBox(height: 24),
//_buildConsultationRequestSection(context),
// _buildConsultationRequestSection(context),
Consumer<TherapistDataProvider>(
builder: (context, provider, _) {
if(provider.patientsStatus == ApiStatus.loading) {
return const Center(child: CircularProgressIndicator());
} else if(provider.patientsStatus == ApiStatus.failure) {
return const Center(child: Text('No patients found'));
} else if(provider.patientsStatus == ApiStatus.success) {
if(provider.patients.isEmpty) {
return const Center(child: Text('No patients found'));
} else {
return Column(
children: provider.patients.map((patient) => PatientCard(
name: patient.patientName,
id: patient.patientId,
phone: patient.phoneNo,
email: patient.email,
package: '-',
duration: '-',
imagePath: 'assets/abdul.png',
)).toList(),
);
}
}
return const SizedBox.shrink();
},
),
// _buildConsultationRequestSection(context),

],
),
),
Expand Down
68 changes: 58 additions & 10 deletions therapist/lib/provider/therapist_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ class TherapistDataProvider extends ChangeNotifier {

bool _isLoading = false;
bool get isLoading => _isLoading;
bool _isTotalsLoading = false;
bool get isTotalsLoading => _isTotalsLoading;
bool _isPatientsLoading = false;
bool get isPatientsLoading => _isPatientsLoading;

String _errorMessage = '';
String get errorMessage => _errorMessage;
Expand Down Expand Up @@ -152,6 +156,15 @@ class TherapistDataProvider extends ChangeNotifier {
notifyListeners();
}

int _totalPatients = 0;
int get totalPatients => _totalPatients;

int _totalSessions = 0;
int get totalSessions => _totalSessions;

int _totalTherapies = 0;
int get totalTherapies => _totalTherapies;

// Fetch therapies based on selected profession
Future<void> fetchTherapies(int professionId) async {
_isLoading = true;
Expand All @@ -170,6 +183,36 @@ class TherapistDataProvider extends ChangeNotifier {
notifyListeners();
}

Future<void> fetchTotals() async {
_isTotalsLoading = true;
notifyListeners();
try {
final results = await Future.wait([
_therapistRepository.getTotalPatients(),
_therapistRepository.getTotalSessions(),
_therapistRepository.getTotalTherapies(),
]);

final patientsResult = results[0];
if (patientsResult is ActionResultSuccess) {
_totalPatients = (patientsResult.data as num?)?.toInt() ?? 0;
}

final sessionsResult = results[1];
if (sessionsResult is ActionResultSuccess) {
_totalSessions = (sessionsResult.data as num?)?.toInt() ?? 0;
}

final therapiesResult = results[2];
if (therapiesResult is ActionResultSuccess) {
_totalTherapies = (therapiesResult.data as num?)?.toInt() ?? 0;
}
} finally {
_isTotalsLoading = false;
notifyListeners();
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Set selected profession and fetch related data
Future<void> setSelectedProfession(int professionId, String professionName) async {
_selectedProfessionId = professionId;
Expand Down Expand Up @@ -209,19 +252,24 @@ class TherapistDataProvider extends ChangeNotifier {
}

Future<void> fetchPatientsMappedToTherapist() async {
_isPatientsLoading = true;
_patientsStatus = ApiStatus.loading;
notifyListeners();

final result = await _therapistRepository.fetchPatientsMappedToTherapist();

if(result is ActionResultSuccess) {
_patients = result.data;
_patientsStatus = ApiStatus.success;
} else if(result is ActionResultFailure) {
_patients = <TherapistPatientDetailsModel>[];
_patientsStatus = ApiStatus.failure;
_errorMessage = result.errorMessage!;
try {
final result = await _therapistRepository.fetchPatientsMappedToTherapist();

if(result is ActionResultSuccess) {
_patients = result.data;
_patientsStatus = ApiStatus.success;
} else if(result is ActionResultFailure) {
_patients = <TherapistPatientDetailsModel>[];
_patientsStatus = ApiStatus.failure;
_errorMessage = result.errorMessage!;
}
} finally {
_isPatientsLoading = false;
notifyListeners();
}
notifyListeners();
}
}
Loading