added pages to project
This commit is contained in:
@@ -19,7 +19,67 @@ class LessonsApi {
|
||||
String? month,
|
||||
}) async {
|
||||
final query = (month != null && month.isNotEmpty) ? '?month=$month' : '';
|
||||
final uri = Uri.parse('${ApiConfig.phpApiBase}/my_lessons.php$query');
|
||||
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));
|
||||
|
||||
@@ -31,9 +91,118 @@ class LessonsApi {
|
||||
}
|
||||
|
||||
if (res.statusCode != 200 || data['success'] != true) {
|
||||
throw Exception(data['error'] ?? data['message'] ?? 'Errore lezioni');
|
||||
throw Exception(data['error'] ?? data['message'] ?? 'Errore slot');
|
||||
}
|
||||
|
||||
return LessonsResponse.fromJson(data);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
import 'package:mime/mime.dart';
|
||||
import '../config/api_config.dart';
|
||||
|
||||
class VanguardApi {
|
||||
@@ -123,4 +126,107 @@ class VanguardApi {
|
||||
|
||||
throw Exception('Logout failed (${res.statusCode}): ${res.body}');
|
||||
}
|
||||
|
||||
// ---------- Profilo (Vanguard native) ----------
|
||||
|
||||
/// GET /me — dati profilo. Ritorna il contenuto di "data".
|
||||
static Future<Map<String, dynamic>> getMe({required String token}) async {
|
||||
final url = Uri.parse('${ApiConfig.laravelApiBase}/me');
|
||||
|
||||
final res = await http.get(url, headers: authHeaders(token));
|
||||
|
||||
if (res.statusCode != 200) {
|
||||
throw Exception('Get profile failed (${res.statusCode}): ${res.body}');
|
||||
}
|
||||
|
||||
final body = jsonDecode(res.body) as Map<String, dynamic>;
|
||||
final data = body['data'];
|
||||
if (data is! Map<String, dynamic>) {
|
||||
throw Exception('Formato risposta /me non valido.');
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/// PATCH /me/details — aggiorna nome e cognome.
|
||||
static Future<Map<String, dynamic>> updateDetails({
|
||||
required String token,
|
||||
String? firstName,
|
||||
String? lastName,
|
||||
}) async {
|
||||
final url = Uri.parse('${ApiConfig.laravelApiBase}/me/details');
|
||||
|
||||
final payload = <String, dynamic>{};
|
||||
if (firstName != null) payload['first_name'] = firstName;
|
||||
if (lastName != null) payload['last_name'] = lastName;
|
||||
|
||||
final res = await http.patch(
|
||||
url,
|
||||
headers: authHeaders(token),
|
||||
body: jsonEncode(payload),
|
||||
);
|
||||
|
||||
if (res.statusCode != 200) {
|
||||
throw Exception('Update details failed (${res.statusCode}): ${res.body}');
|
||||
}
|
||||
|
||||
final body = jsonDecode(res.body) as Map<String, dynamic>;
|
||||
return (body['data'] as Map<String, dynamic>?) ?? {};
|
||||
}
|
||||
|
||||
/// PATCH /me/details/auth — aggiorna la password (nuova + conferma).
|
||||
static Future<void> updatePassword({
|
||||
required String token,
|
||||
required String password,
|
||||
required String passwordConfirmation,
|
||||
}) async {
|
||||
final url = Uri.parse('${ApiConfig.laravelApiBase}/me/details/auth');
|
||||
|
||||
final res = await http.patch(
|
||||
url,
|
||||
headers: authHeaders(token),
|
||||
body: jsonEncode({
|
||||
'password': password,
|
||||
'password_confirmation': passwordConfirmation,
|
||||
}),
|
||||
);
|
||||
|
||||
if (res.statusCode != 200) {
|
||||
throw Exception(
|
||||
'Update password failed (${res.statusCode}): ${res.body}',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// POST /me/avatar — upload avatar (multipart). Ritorna l'URL avatar aggiornato.
|
||||
static Future<String?> uploadAvatar({
|
||||
required String token,
|
||||
required String filePath,
|
||||
}) async {
|
||||
final url = Uri.parse('${ApiConfig.laravelApiBase}/me/avatar');
|
||||
|
||||
final mimeType = lookupMimeType(filePath) ?? 'image/jpeg';
|
||||
final parts = mimeType.split('/');
|
||||
|
||||
final request = http.MultipartRequest('POST', url)
|
||||
..headers['Accept'] = 'application/json'
|
||||
..headers['Authorization'] = 'Bearer $token'
|
||||
..files.add(
|
||||
await http.MultipartFile.fromPath(
|
||||
'file',
|
||||
filePath,
|
||||
contentType: MediaType(parts[0], parts[1]),
|
||||
),
|
||||
);
|
||||
|
||||
final streamed = await request.send();
|
||||
final res = await http.Response.fromStream(streamed);
|
||||
|
||||
if (res.statusCode != 200) {
|
||||
throw Exception('Upload avatar failed (${res.statusCode}): ${res.body}');
|
||||
}
|
||||
|
||||
final body = jsonDecode(res.body) as Map<String, dynamic>;
|
||||
final data = body['data'] as Map<String, dynamic>?;
|
||||
return data?['avatar']?.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user