api start
This commit is contained in:
+90
-30
@@ -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<Lesson> lessons;
|
||||
|
||||
LessonsResponse({
|
||||
required this.month,
|
||||
required this.summary,
|
||||
required this.lessons,
|
||||
});
|
||||
|
||||
factory LessonsResponse.fromJson(Map<String, dynamic> j) {
|
||||
final rawLessons = (j['lessons'] as List?) ?? const [];
|
||||
return LessonsResponse(
|
||||
month: (j['month'] ?? '').toString(),
|
||||
summary: LessonsSummary.fromJson(
|
||||
(j['summary'] as Map?)?.cast<String, dynamic>() ?? const {},
|
||||
),
|
||||
lessons: rawLessons
|
||||
.map((e) => Lesson.fromJson((e as Map).cast<String, dynamic>()))
|
||||
.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<String, dynamic> 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<String, dynamic> j) {
|
||||
final session = (j['session'] as Map<String, dynamic>? ?? {});
|
||||
final cls = (j['class'] as Map<String, dynamic>? ?? {});
|
||||
final wallet = (j['wallet'] as Map<String, dynamic>? ?? {});
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String, String> _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<LessonsResponse> 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<String, dynamic> data;
|
||||
try {
|
||||
data = jsonDecode(res.body) as Map<String, dynamic>;
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user