Add service and provider for Teams
This commit is contained in:
@@ -17,7 +17,6 @@ export class TournamentService {
|
|||||||
name TEXT,
|
name TEXT,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
maxTeamAmount INTEGER,
|
maxTeamAmount INTEGER,
|
||||||
currentTeamAmount INTEGER,
|
|
||||||
registrationStartDate TEXT,
|
registrationStartDate TEXT,
|
||||||
registrationEndDate TEXT
|
registrationEndDate TEXT
|
||||||
)`);
|
)`);
|
||||||
@@ -43,7 +42,7 @@ export class TournamentService {
|
|||||||
name: row.name,
|
name: row.name,
|
||||||
description: row.description,
|
description: row.description,
|
||||||
maxTeamAmount: row.maxTeamAmount,
|
maxTeamAmount: row.maxTeamAmount,
|
||||||
currentTeamAmount: row.currentTeamAmount,
|
currentTeamAmount: 0,
|
||||||
registrationStartDate: row.registrationStartDate,
|
registrationStartDate: row.registrationStartDate,
|
||||||
registrationEndDate: row.registrationEndDate,
|
registrationEndDate: row.registrationEndDate,
|
||||||
teams: [],
|
teams: [],
|
||||||
@@ -57,6 +56,7 @@ export class TournamentService {
|
|||||||
description: row.teamDescription,
|
description: row.teamDescription,
|
||||||
createdAt: row.teamCreatedAt,
|
createdAt: row.teamCreatedAt,
|
||||||
} as Team);
|
} as Team);
|
||||||
|
tournamentsMap.get(row.id)!.currentTeamAmount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolve(Array.from(tournamentsMap.values()));
|
resolve(Array.from(tournamentsMap.values()));
|
||||||
@@ -98,6 +98,7 @@ export class TournamentService {
|
|||||||
description: row.teamDescription,
|
description: row.teamDescription,
|
||||||
createdAt: row.teamCreatedAt,
|
createdAt: row.teamCreatedAt,
|
||||||
} as Team);
|
} as Team);
|
||||||
|
tournament.currentTeamAmount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolve(tournament);
|
resolve(tournament);
|
||||||
@@ -108,8 +109,8 @@ export class TournamentService {
|
|||||||
|
|
||||||
addTournament(tournament: Tournament): Promise<void> {
|
addTournament(tournament: Tournament): Promise<void> {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const statement = this.db.prepare('Insert Into Tournaments (name, description, maxTeamAmount, currentTeamAmount, registrationStartDate, registrationEndDate) VALUES (?, ?, ?, ?, ?, ?)')
|
const statement = this.db.prepare('Insert Into Tournaments (name, description, maxTeamAmount, registrationStartDate, registrationEndDate) VALUES (?, ?, ?, ?, ?)')
|
||||||
statement.run(tournament.name, tournament.description, tournament.maxTeamAmount, tournament.currentTeamAmount, tournament.registrationStartDate, tournament.registrationEndDate);
|
statement.run(tournament.name, tournament.description, tournament.maxTeamAmount, tournament.registrationStartDate, tournament.registrationEndDate);
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -120,7 +121,6 @@ export class TournamentService {
|
|||||||
Set name = $name,
|
Set name = $name,
|
||||||
description = $description,
|
description = $description,
|
||||||
maxTeamAmount = $maxTeamAmount,
|
maxTeamAmount = $maxTeamAmount,
|
||||||
currentTeamAmount = $currentTeamAmount,
|
|
||||||
registrationStartDate = $registrationStartDate,
|
registrationStartDate = $registrationStartDate,
|
||||||
registrationEndDate = $registrationEndDate
|
registrationEndDate = $registrationEndDate
|
||||||
where id = $id`, {
|
where id = $id`, {
|
||||||
@@ -128,7 +128,6 @@ export class TournamentService {
|
|||||||
$name: updatedTournament.name,
|
$name: updatedTournament.name,
|
||||||
$description: updatedTournament.description,
|
$description: updatedTournament.description,
|
||||||
$maxTeamAmount: updatedTournament.maxTeamAmount,
|
$maxTeamAmount: updatedTournament.maxTeamAmount,
|
||||||
$currentTeamAmount: updatedTournament.currentTeamAmount,
|
|
||||||
$registrationStartDate: updatedTournament.registrationStartDate,
|
$registrationStartDate: updatedTournament.registrationStartDate,
|
||||||
$registrationEndDate: updatedTournament.registrationEndDate,
|
$registrationEndDate: updatedTournament.registrationEndDate,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:frontend_splatournament_manager/pages/home_page.dart';
|
|||||||
import 'package:frontend_splatournament_manager/pages/login_page.dart';
|
import 'package:frontend_splatournament_manager/pages/login_page.dart';
|
||||||
import 'package:frontend_splatournament_manager/pages/settings_page.dart';
|
import 'package:frontend_splatournament_manager/pages/settings_page.dart';
|
||||||
import 'package:frontend_splatournament_manager/providers/auth_provider.dart';
|
import 'package:frontend_splatournament_manager/providers/auth_provider.dart';
|
||||||
|
import 'package:frontend_splatournament_manager/providers/team_provider.dart';
|
||||||
import 'package:frontend_splatournament_manager/providers/theme_provider.dart';
|
import 'package:frontend_splatournament_manager/providers/theme_provider.dart';
|
||||||
import 'package:frontend_splatournament_manager/providers/tournament_provider.dart';
|
import 'package:frontend_splatournament_manager/providers/tournament_provider.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
@@ -15,6 +16,7 @@ void main() {
|
|||||||
ChangeNotifierProvider(create: (_) => ThemeProvider()),
|
ChangeNotifierProvider(create: (_) => ThemeProvider()),
|
||||||
ChangeNotifierProvider(create: (_) => TournamentProvider()),
|
ChangeNotifierProvider(create: (_) => TournamentProvider()),
|
||||||
ChangeNotifierProvider(create: (_) => AuthProvider()),
|
ChangeNotifierProvider(create: (_) => AuthProvider()),
|
||||||
|
ChangeNotifierProvider(create: (_) => TeamProvider()),
|
||||||
],
|
],
|
||||||
child: const SplatournamentApp(),
|
child: const SplatournamentApp(),
|
||||||
),
|
),
|
||||||
@@ -22,6 +24,7 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SplatournamentApp extends StatelessWidget {
|
class SplatournamentApp extends StatelessWidget {
|
||||||
|
static const String baseUrl = "http://10.0.2.2:3000";
|
||||||
const SplatournamentApp({super.key});
|
const SplatournamentApp({super.key});
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -41,12 +44,17 @@ class SplatournamentApp extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var routes = GoRouter(
|
var routes = GoRouter(
|
||||||
initialLocation: '/login',
|
initialLocation: '/login',
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(path: "/login", builder: (context, state) => const LoginPage()),
|
GoRoute(path: "/login", builder: (context, state) => const LoginPage()),
|
||||||
GoRoute(path: "/", builder: (context, state) => HomePage(),routes: [
|
GoRoute(
|
||||||
GoRoute(path: "settings", builder: (context, state) => SettingsPage(),)
|
path: "/",
|
||||||
])
|
builder: (context, state) => HomePage(),
|
||||||
]
|
routes: [
|
||||||
|
GoRoute(path: "settings", builder: (context, state) => SettingsPage()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:frontend_splatournament_manager/models/team.dart';
|
||||||
import 'package:frontend_splatournament_manager/models/tournament.dart';
|
import 'package:frontend_splatournament_manager/models/tournament.dart';
|
||||||
|
import 'package:frontend_splatournament_manager/providers/team_provider.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class TournamentDetailPage extends StatefulWidget {
|
class TournamentDetailPage extends StatefulWidget {
|
||||||
final Tournament tournament;
|
final Tournament tournament;
|
||||||
@@ -72,15 +75,89 @@ class _TournamentDetailPageState extends State<TournamentDetailPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TournamentTeamsWidget extends StatelessWidget{
|
class TournamentTeamsWidget extends StatefulWidget {
|
||||||
const TournamentTeamsWidget({super.key, required Tournament tournament});
|
final Tournament tournament;
|
||||||
|
|
||||||
|
const TournamentTeamsWidget({super.key, required this.tournament});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TournamentTeamsWidget> createState() => _TournamentTeamsWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TournamentTeamsWidgetState extends State<TournamentTeamsWidget> {
|
||||||
|
late Future<List<Team>> _teamsFuture;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_teamsFuture = Provider.of<TeamProvider>(context, listen: false)
|
||||||
|
.getTeamsByTournament(widget.tournament.id);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Expanded(
|
return Expanded(
|
||||||
child: Column( children: [
|
child: Column(
|
||||||
//TODO: Show participating Teams
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Text("Teams"),
|
children: [
|
||||||
],),
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
|
||||||
|
child: Text(
|
||||||
|
'Registered Teams',
|
||||||
|
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 17),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: FutureBuilder<List<Team>>(
|
||||||
|
future: _teamsFuture,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
if (snapshot.hasError) {
|
||||||
|
return Center(child: Text('Error: ${snapshot.error}'));
|
||||||
|
}
|
||||||
|
final teams = snapshot.data ?? [];
|
||||||
|
if (teams.isEmpty) {
|
||||||
|
return Center(child: Text('No teams registered yet.'));
|
||||||
|
}
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: teams.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final team = teams[index];
|
||||||
|
return ListTile(
|
||||||
|
leading: CircleAvatar(child: Text(team.tag)),
|
||||||
|
title: Text(team.name),
|
||||||
|
subtitle: team.description.isNotEmpty
|
||||||
|
? Text(team.description)
|
||||||
|
: null,
|
||||||
|
trailing: IconButton(
|
||||||
|
icon: Icon(Icons.remove_circle_outline, color: Colors.red),
|
||||||
|
onPressed: () async {
|
||||||
|
try {
|
||||||
|
await Provider.of<TeamProvider>(context, listen: false)
|
||||||
|
.removeTeamFromTournament(widget.tournament.id, team.id);
|
||||||
|
setState(() {
|
||||||
|
_teamsFuture =
|
||||||
|
Provider.of<TeamProvider>(context, listen: false)
|
||||||
|
.getTeamsByTournament(widget.tournament.id);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (!context.mounted) return;
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text('Failed to remove team: $e')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:frontend_splatournament_manager/models/team.dart';
|
||||||
|
import 'package:frontend_splatournament_manager/services/team_service.dart';
|
||||||
|
|
||||||
|
class TeamProvider extends ChangeNotifier {
|
||||||
|
final TeamService _teamService = TeamService();
|
||||||
|
|
||||||
|
List<Team> _teams = [];
|
||||||
|
List<Team> get teams => _teams;
|
||||||
|
|
||||||
|
Future<List<Team>> fetchAllTeams() async {
|
||||||
|
_teams = await _teamService.getAllTeams();
|
||||||
|
notifyListeners();
|
||||||
|
return _teams;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Team> createTeam({
|
||||||
|
required String name,
|
||||||
|
required String tag,
|
||||||
|
String description = '',
|
||||||
|
}) async {
|
||||||
|
final team = await _teamService.createTeam(
|
||||||
|
name: name,
|
||||||
|
tag: tag,
|
||||||
|
description: description,
|
||||||
|
);
|
||||||
|
_teams = [..._teams, team];
|
||||||
|
notifyListeners();
|
||||||
|
return team;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateTeam(
|
||||||
|
int id, {
|
||||||
|
String? name,
|
||||||
|
String? tag,
|
||||||
|
String? description,
|
||||||
|
}) async {
|
||||||
|
await _teamService.updateTeam(id, name: name, tag: tag, description: description);
|
||||||
|
await fetchAllTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteTeam(int id) async {
|
||||||
|
await _teamService.deleteTeam(id);
|
||||||
|
_teams = _teams.where((t) => t.id != id).toList();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Team>> getTeamsByTournament(int tournamentId) async {
|
||||||
|
return _teamService.getTeamsByTournament(tournamentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> registerTeamForTournament(int tournamentId, int teamId) async {
|
||||||
|
await _teamService.registerTeamForTournament(tournamentId, teamId);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeTeamFromTournament(int tournamentId, int teamId) async {
|
||||||
|
await _teamService.removeTeamFromTournament(tournamentId, teamId);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -5,8 +5,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:frontend_splatournament_manager/models/tournament.dart';
|
import 'package:frontend_splatournament_manager/models/tournament.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import '../main.dart';
|
||||||
|
|
||||||
class TournamentProvider extends ChangeNotifier {
|
class TournamentProvider extends ChangeNotifier {
|
||||||
static const String baseUrl = "http://10.0.2.2:3000";
|
final String baseUrl = SplatournamentApp.baseUrl;
|
||||||
|
|
||||||
List<Tournament> _availableTournaments = [];
|
List<Tournament> _availableTournaments = [];
|
||||||
Future<List<Tournament>>? _initialLoadFuture;
|
Future<List<Tournament>>? _initialLoadFuture;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'package:frontend_splatournament_manager/main.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
class AuthService {
|
class AuthService {
|
||||||
static const String baseUrl = "http://10.0.2.2:3000";
|
final String baseUrl = SplatournamentApp.baseUrl;
|
||||||
|
|
||||||
Future<Map<String, dynamic>> register(String username, String password) async {
|
Future<Map<String, dynamic>> register(String username, String password) async {
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('$baseUrl/register'),
|
Uri.parse('$baseUrl/register'),
|
||||||
|
|||||||
127
frontend_splatournament_manager/lib/services/team_service.dart
Normal file
127
frontend_splatournament_manager/lib/services/team_service.dart
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:frontend_splatournament_manager/main.dart';
|
||||||
|
import 'package:frontend_splatournament_manager/models/team.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
class TeamService {
|
||||||
|
final String baseUrl = SplatournamentApp.baseUrl;
|
||||||
|
|
||||||
|
Future<List<Team>> getAllTeams() async {
|
||||||
|
final response = await http.get(Uri.parse('$baseUrl/teams'));
|
||||||
|
if (response.statusCode != HttpStatus.ok) {
|
||||||
|
throw Exception('Failed to load teams (${response.statusCode})');
|
||||||
|
}
|
||||||
|
final List<dynamic> list = json.decode(response.body);
|
||||||
|
return list.map((j) => Team.fromJson(j as Map<String, dynamic>)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Team> getTeamById(int id) async {
|
||||||
|
final response = await http.get(Uri.parse('$baseUrl/teams/$id'));
|
||||||
|
if (response.statusCode == HttpStatus.notFound) {
|
||||||
|
throw Exception('Team not found');
|
||||||
|
}
|
||||||
|
if (response.statusCode != HttpStatus.ok) {
|
||||||
|
throw Exception('Failed to load team (${response.statusCode})');
|
||||||
|
}
|
||||||
|
return Team.fromJson(json.decode(response.body) as Map<String, dynamic>);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Team> createTeam({
|
||||||
|
required String name,
|
||||||
|
required String tag,
|
||||||
|
String description = '',
|
||||||
|
}) async {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse('$baseUrl/teams'),
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: json.encode({'name': name, 'tag': tag, 'description': description}),
|
||||||
|
);
|
||||||
|
if (response.statusCode != HttpStatus.created) {
|
||||||
|
final body = json.decode(response.body);
|
||||||
|
throw Exception(body['error'] ?? 'Failed to create team');
|
||||||
|
}
|
||||||
|
return Team.fromJson(json.decode(response.body) as Map<String, dynamic>);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateTeam(
|
||||||
|
int id, {
|
||||||
|
String? name,
|
||||||
|
String? tag,
|
||||||
|
String? description,
|
||||||
|
}) async {
|
||||||
|
final response = await http.put(
|
||||||
|
Uri.parse('$baseUrl/teams/$id'),
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: json.encode({
|
||||||
|
'name': ?name,
|
||||||
|
'tag': ?tag,
|
||||||
|
'description': ?description,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
if (response.statusCode != HttpStatus.ok) {
|
||||||
|
final body = json.decode(response.body);
|
||||||
|
throw Exception(body['error'] ?? 'Failed to update team');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteTeam(int id) async {
|
||||||
|
final response = await http.delete(Uri.parse('$baseUrl/teams/$id'));
|
||||||
|
if (response.statusCode != HttpStatus.ok) {
|
||||||
|
final body = json.decode(response.body);
|
||||||
|
throw Exception(body['error'] ?? 'Failed to delete team');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Team>> getTeamsByTournament(int tournamentId) async {
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse('$baseUrl/tournaments/$tournamentId/teams'),
|
||||||
|
);
|
||||||
|
if (response.statusCode != HttpStatus.ok) {
|
||||||
|
throw Exception(
|
||||||
|
'Failed to load teams for tournament (${response.statusCode})',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final List<dynamic> list = json.decode(response.body);
|
||||||
|
return list.map((j) => Team.fromJson(j as Map<String, dynamic>)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> registerTeamForTournament(int tournamentId, int teamId) async {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse('$baseUrl/tournaments/$tournamentId/teams'),
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: json.encode({'teamId': teamId}),
|
||||||
|
);
|
||||||
|
if (response.statusCode == 409) {
|
||||||
|
throw Exception('Team is already registered for this tournament');
|
||||||
|
}
|
||||||
|
if (response.statusCode != HttpStatus.created) {
|
||||||
|
final body = json.decode(response.body);
|
||||||
|
throw Exception(body['error'] ?? 'Failed to register team');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeTeamFromTournament(int tournamentId, int teamId) async {
|
||||||
|
final response = await http.delete(
|
||||||
|
Uri.parse('$baseUrl/tournaments/$tournamentId/teams/$teamId'),
|
||||||
|
);
|
||||||
|
if (response.statusCode != HttpStatus.ok) {
|
||||||
|
final body = json.decode(response.body);
|
||||||
|
throw Exception(body['error'] ?? 'Failed to remove team from tournament');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Map<String, dynamic>>> getTournamentsByTeam(int teamId) async {
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse('$baseUrl/teams/$teamId/tournaments'),
|
||||||
|
);
|
||||||
|
if (response.statusCode != HttpStatus.ok) {
|
||||||
|
throw Exception(
|
||||||
|
'Failed to load tournaments for team (${response.statusCode})',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final List<dynamic> list = json.decode(response.body);
|
||||||
|
return list.cast<Map<String, dynamic>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user