diff --git a/lib/models/lesson.dart b/lib/models/lesson.dart index 96f458a..ca78416 100644 --- a/lib/models/lesson.dart +++ b/lib/models/lesson.dart @@ -1,52 +1,112 @@ +/// Modello delle lezioni per la scuola YogaSoul. +/// +/// Rispecchia il JSON prodotto da `public/api/my_lessons.php`. +/// Nota: questa app รจ single-school, quindi niente concetti multiscuola +/// (wallet/entries/recoveries/level) che non esistono nel DB YogaSoul. + +class LessonsResponse { + final String month; // "YYYY-MM" + final LessonsSummary summary; + final List lessons; + + LessonsResponse({ + required this.month, + required this.summary, + required this.lessons, + }); + + factory LessonsResponse.fromJson(Map j) { + final rawLessons = (j['lessons'] as List?) ?? const []; + return LessonsResponse( + month: (j['month'] ?? '').toString(), + summary: LessonsSummary.fromJson( + (j['summary'] as Map?)?.cast() ?? const {}, + ), + lessons: rawLessons + .map((e) => Lesson.fromJson((e as Map).cast())) + .toList(), + ); + } +} + +/// I conteggi della fascia riepilogo (le "card pastello" della webapp). +class LessonsSummary { + final int purchased; // acquistate + final int practiced; // praticate + final int booked; // prenotate + final int pending; // da confermare + final int toSchedule; // da programmare + final int lost; // perse + + LessonsSummary({ + required this.purchased, + required this.practiced, + required this.booked, + required this.pending, + required this.toSchedule, + required this.lost, + }); + + factory LessonsSummary.fromJson(Map j) { + int n(dynamic v) => (v as num?)?.toInt() ?? 0; + return LessonsSummary( + purchased: n(j['purchased']), + practiced: n(j['practiced']), + booked: n(j['booked']), + pending: n(j['pending']), + toSchedule: n(j['to_schedule']), + lost: n(j['lost']), + ); + } +} + class Lesson { final int bookingId; final String status; - final String date; // YYYY-MM-DD - final String startTime; - final String endTime; - final String? roomName; + final String datetime; // "YYYY-MM-DD HH:MM:SS" + final String date; // "YYYY-MM-DD" + final String time; // "HH:MM" final String className; - final String? level; + final String color; // es. "#1ebf73" + final String location; - final int availableEntries; - final int availableRecoveries; + final String? expireOn; // "YYYY-MM-DD" o null + final bool lostLesson; - final bool canModify; + final bool canReschedule; + final bool canDelete; Lesson({ required this.bookingId, required this.status, + required this.datetime, required this.date, - required this.startTime, - required this.endTime, - required this.roomName, + required this.time, required this.className, - required this.level, - required this.availableEntries, - required this.availableRecoveries, - required this.canModify, + required this.color, + required this.location, + required this.expireOn, + required this.lostLesson, + required this.canReschedule, + required this.canDelete, }); factory Lesson.fromJson(Map j) { - final session = (j['session'] as Map? ?? {}); - final cls = (j['class'] as Map? ?? {}); - final wallet = (j['wallet'] as Map? ?? {}); - return Lesson( - bookingId: (j['booking_id'] as num).toInt(), + bookingId: (j['booking_id'] as num?)?.toInt() ?? 0, status: (j['status'] ?? '').toString(), - date: (session['date'] ?? '').toString(), - startTime: (session['start_time'] ?? '').toString(), - endTime: (session['end_time'] ?? '').toString(), - roomName: session['room_name']?.toString(), - className: (cls['name'] ?? '').toString(), - level: cls['level']?.toString(), - availableEntries: (wallet['available_entries'] as num?)?.toInt() ?? 0, - availableRecoveries: - (wallet['available_recoveries'] as num?)?.toInt() ?? 0, - canModify: (j['can_modify'] == true), + datetime: (j['datetime'] ?? '').toString(), + date: (j['date'] ?? '').toString(), + time: (j['time'] ?? '').toString(), + className: (j['class_name'] ?? '').toString(), + color: (j['color'] ?? '#1ebf73').toString(), + location: (j['location'] ?? '').toString(), + expireOn: j['expire_on']?.toString(), + lostLesson: j['lost_lesson'] == true, + canReschedule: j['can_reschedule'] == true, + canDelete: j['can_delete'] == true, ); } } diff --git a/lib/services/lessons_api.dart b/lib/services/lessons_api.dart new file mode 100644 index 0000000..8eb8f87 --- /dev/null +++ b/lib/services/lessons_api.dart @@ -0,0 +1,39 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; + +import '../config/api_config.dart'; +import '../models/lesson.dart'; + +/// Service per le lezioni della scuola YogaSoul. +/// Chiama `public/api/my_lessons.php` (phpApiBase), stesso pattern di SettingsApi. +class LessonsApi { + static Map _headers(String token) => { + 'Accept': 'application/json', + 'Authorization': 'Bearer $token', + }; + + /// Carica le lezioni del mese indicato. + /// [month] deve essere nel formato "YYYY-MM". Se null, il server usa il mese corrente. + static Future fetchMyLessons({ + required String token, + String? month, + }) async { + final query = (month != null && month.isNotEmpty) ? '?month=$month' : ''; + final uri = Uri.parse('${ApiConfig.phpApiBase}/my_lessons.php$query'); + + final res = await http.get(uri, headers: _headers(token)); + + Map data; + try { + data = jsonDecode(res.body) as Map; + } catch (_) { + throw Exception('Risposta non valida dal server (${res.statusCode})'); + } + + if (res.statusCode != 200 || data['success'] != true) { + throw Exception(data['error'] ?? data['message'] ?? 'Errore lezioni'); + } + + return LessonsResponse.fromJson(data); + } +}