209 lines
6.6 KiB
Dart
209 lines
6.6 KiB
Dart
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.laravelApiBase}/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('RAW(${res.statusCode}): ${res.body}');
|
|
}
|
|
|
|
if (res.statusCode != 200 || data['success'] != true) {
|
|
throw Exception(data['error'] ?? data['message'] ?? 'Errore lezioni');
|
|
}
|
|
|
|
return LessonsResponse.fromJson(data);
|
|
}
|
|
|
|
/// Cancella una prenotazione dell'utente.
|
|
static Future<bool> cancelLesson({
|
|
required String token,
|
|
required int bookingId,
|
|
}) async {
|
|
final uri = Uri.parse('${ApiConfig.laravelApiBase}/cancel_lesson.php');
|
|
|
|
final res = await http.post(
|
|
uri,
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $token',
|
|
},
|
|
body: jsonEncode({'booking_id': bookingId}),
|
|
);
|
|
|
|
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) {
|
|
return true;
|
|
}
|
|
|
|
throw Exception(data['error'] ?? data['message'] ?? 'Errore cancellazione');
|
|
}
|
|
|
|
/// Elenca gli slot disponibili per riprogrammare/prenotare.
|
|
static Future<List<AvailableSlot>> fetchAvailableSlots({
|
|
required String token,
|
|
required int serviceId,
|
|
String? month,
|
|
}) async {
|
|
final monthQuery = (month != null && month.isNotEmpty)
|
|
? '&month=$month'
|
|
: '';
|
|
final uri = Uri.parse(
|
|
'${ApiConfig.laravelApiBase}/available_slots.php?service_id=$serviceId$monthQuery',
|
|
);
|
|
|
|
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 slot');
|
|
}
|
|
|
|
final raw = (data['slots'] as List?) ?? const [];
|
|
return raw
|
|
.map((e) => AvailableSlot.fromJson((e as Map).cast<String, dynamic>()))
|
|
.toList();
|
|
}
|
|
|
|
/// Esegue la riprogrammazione di una lezione su un nuovo slot.
|
|
static Future<String> reschedule({
|
|
required String token,
|
|
required int bookingId,
|
|
required int newScheduleId,
|
|
}) async {
|
|
final uri = Uri.parse('${ApiConfig.laravelApiBase}/reschedule.php');
|
|
final res = await http.post(
|
|
uri,
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $token',
|
|
},
|
|
body: jsonEncode({
|
|
'booking_id': bookingId,
|
|
'new_schedule_id': newScheduleId,
|
|
}),
|
|
);
|
|
|
|
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) {
|
|
return (data['message'] ?? 'Riprogrammazione richiesta').toString();
|
|
}
|
|
throw Exception(
|
|
data['error'] ?? data['message'] ?? 'Errore riprogrammazione',
|
|
);
|
|
}
|
|
|
|
/// Elenca gli ordini/pacchetti dell'utente con residui.
|
|
static Future<List<OrderPackage>> fetchOrders({required String token}) async {
|
|
final uri = Uri.parse('${ApiConfig.laravelApiBase}/orders.php');
|
|
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 ordini');
|
|
}
|
|
final raw = (data['orders'] as List?) ?? const [];
|
|
return raw
|
|
.map((e) => OrderPackage.fromJson((e as Map).cast<String, dynamic>()))
|
|
.toList();
|
|
}
|
|
|
|
/// Prenota una nuova lezione da un ticket residuo.
|
|
static Future<String> bookFromTicket({
|
|
required String token,
|
|
required int orderId,
|
|
required int newScheduleId,
|
|
}) async {
|
|
final uri = Uri.parse('${ApiConfig.laravelApiBase}/book_from_ticket.php');
|
|
final res = await http.post(
|
|
uri,
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Bearer $token',
|
|
},
|
|
body: jsonEncode({'order_id': orderId, 'new_schedule_id': newScheduleId}),
|
|
);
|
|
|
|
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) {
|
|
return (data['message'] ?? 'Prenotazione richiesta').toString();
|
|
}
|
|
throw Exception(data['error'] ?? data['message'] ?? 'Errore prenotazione');
|
|
}
|
|
|
|
/// Elenca gli ordini dettagliati (con conteggi e lezioni).
|
|
static Future<List<OrderDetail>> fetchOrdersDetail({
|
|
required String token,
|
|
}) async {
|
|
final uri = Uri.parse('${ApiConfig.laravelApiBase}/orders_detail.php');
|
|
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 ordini');
|
|
}
|
|
final raw = (data['orders'] as List?) ?? const [];
|
|
return raw
|
|
.map((e) => OrderDetail.fromJson((e as Map).cast<String, dynamic>()))
|
|
.toList();
|
|
}
|
|
}
|