Initial commit: Flutter app + PHP/MySQL backend on Hostinger
Replaces Firebase with a self-hosted PHP/MySQL API served from winded.prymsolutions.com. Includes full backend (schema, auth, events, teams, brackets, suggestions, stats, media, file upload) and updated Flutter repositories and domain models. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import '../../brackets/domain/bracket.dart';
|
||||
import '../../brackets/infrastructure/brackets_repository.dart';
|
||||
|
||||
part 'admin_brackets_notifier.g.dart';
|
||||
|
||||
/// Live Firestore-backed stream of every bracket, used by the admin panel.
|
||||
@riverpod
|
||||
Stream<List<Bracket>> adminBracketsStream(AdminBracketsStreamRef ref) {
|
||||
final repo = ref.watch(bracketsRepositoryProvider);
|
||||
return repo.watchBrackets();
|
||||
}
|
||||
|
||||
/// Imperative wrapper around the brackets repository write methods.
|
||||
@riverpod
|
||||
class AdminBracketsNotifier extends _$AdminBracketsNotifier {
|
||||
@override
|
||||
Future<void> build() async {}
|
||||
|
||||
Future<String> create(Bracket bracket) async {
|
||||
final repo = ref.read(bracketsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
try {
|
||||
final id = await repo.createBracket(bracket);
|
||||
state = const AsyncData(null);
|
||||
return id;
|
||||
} catch (e, st) {
|
||||
state = AsyncError(e, st);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> save(Bracket bracket) async {
|
||||
final repo = ref.read(bracketsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() => repo.updateBracket(bracket));
|
||||
}
|
||||
|
||||
Future<void> delete(String id) async {
|
||||
final repo = ref.read(bracketsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() => repo.deleteBracket(id));
|
||||
}
|
||||
|
||||
Future<void> updateMatch(
|
||||
String bracketId,
|
||||
String roundLabel,
|
||||
BracketMatch match,
|
||||
) async {
|
||||
final repo = ref.read(bracketsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(
|
||||
() => repo.updateMatch(bracketId, roundLabel, match),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'admin_brackets_notifier.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$adminBracketsStreamHash() =>
|
||||
r'2a76ca85dc76fc7514b7b9ae17a5610f1c1760d9';
|
||||
|
||||
/// Live Firestore-backed stream of every bracket, used by the admin panel.
|
||||
///
|
||||
/// Copied from [adminBracketsStream].
|
||||
@ProviderFor(adminBracketsStream)
|
||||
final adminBracketsStreamProvider =
|
||||
AutoDisposeStreamProvider<List<Bracket>>.internal(
|
||||
adminBracketsStream,
|
||||
name: r'adminBracketsStreamProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$adminBracketsStreamHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef AdminBracketsStreamRef = AutoDisposeStreamProviderRef<List<Bracket>>;
|
||||
String _$adminBracketsNotifierHash() =>
|
||||
r'ac2ba11f3c44e7feccf440538249e078c9a55031';
|
||||
|
||||
/// Imperative wrapper around the brackets repository write methods.
|
||||
///
|
||||
/// Copied from [AdminBracketsNotifier].
|
||||
@ProviderFor(AdminBracketsNotifier)
|
||||
final adminBracketsNotifierProvider =
|
||||
AutoDisposeAsyncNotifierProvider<AdminBracketsNotifier, void>.internal(
|
||||
AdminBracketsNotifier.new,
|
||||
name: r'adminBracketsNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$adminBracketsNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AdminBracketsNotifier = AutoDisposeAsyncNotifier<void>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -0,0 +1,49 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import '../../events/domain/event.dart';
|
||||
import '../../events/infrastructure/events_repository.dart';
|
||||
|
||||
part 'admin_events_notifier.g.dart';
|
||||
|
||||
/// Live Firestore-backed stream of every event in the system, used by the
|
||||
/// admin panel. The public-facing [eventsStreamProvider] still emits mocked
|
||||
/// data; admins read straight through to the real collection.
|
||||
@riverpod
|
||||
Stream<List<Event>> adminEventsStream(AdminEventsStreamRef ref) {
|
||||
final repo = ref.watch(eventsRepositoryProvider);
|
||||
return repo.watchEvents();
|
||||
}
|
||||
|
||||
/// Imperative wrapper around the events repository write methods. The notifier
|
||||
/// is `AsyncValue<void>`-shaped so screens can wire it up the same way as the
|
||||
/// existing auth/suggestions notifiers.
|
||||
@riverpod
|
||||
class AdminEventsNotifier extends _$AdminEventsNotifier {
|
||||
@override
|
||||
Future<void> build() async {}
|
||||
|
||||
Future<String> create(Event event) async {
|
||||
final repo = ref.read(eventsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
try {
|
||||
final id = await repo.createEvent(event);
|
||||
state = const AsyncData(null);
|
||||
return id;
|
||||
} catch (e, st) {
|
||||
state = AsyncError(e, st);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> save(Event event) async {
|
||||
final repo = ref.read(eventsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() => repo.updateEvent(event));
|
||||
}
|
||||
|
||||
Future<void> delete(String id) async {
|
||||
final repo = ref.read(eventsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() => repo.deleteEvent(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'admin_events_notifier.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$adminEventsStreamHash() => r'33d6cd9ec02f788540270db08f0933e9c46c72e8';
|
||||
|
||||
/// Live Firestore-backed stream of every event in the system, used by the
|
||||
/// admin panel. The public-facing [eventsStreamProvider] still emits mocked
|
||||
/// data; admins read straight through to the real collection.
|
||||
///
|
||||
/// Copied from [adminEventsStream].
|
||||
@ProviderFor(adminEventsStream)
|
||||
final adminEventsStreamProvider =
|
||||
AutoDisposeStreamProvider<List<Event>>.internal(
|
||||
adminEventsStream,
|
||||
name: r'adminEventsStreamProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$adminEventsStreamHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef AdminEventsStreamRef = AutoDisposeStreamProviderRef<List<Event>>;
|
||||
String _$adminEventsNotifierHash() =>
|
||||
r'd39031c4b14120bba5d4ea0baeed2661eb336ec0';
|
||||
|
||||
/// Imperative wrapper around the events repository write methods. The notifier
|
||||
/// is `AsyncValue<void>`-shaped so screens can wire it up the same way as the
|
||||
/// existing auth/suggestions notifiers.
|
||||
///
|
||||
/// Copied from [AdminEventsNotifier].
|
||||
@ProviderFor(AdminEventsNotifier)
|
||||
final adminEventsNotifierProvider =
|
||||
AutoDisposeAsyncNotifierProvider<AdminEventsNotifier, void>.internal(
|
||||
AdminEventsNotifier.new,
|
||||
name: r'adminEventsNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$adminEventsNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AdminEventsNotifier = AutoDisposeAsyncNotifier<void>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import '../../suggestions/domain/suggestion.dart';
|
||||
import '../../suggestions/infrastructure/suggestions_repository.dart';
|
||||
|
||||
part 'admin_suggestions_notifier.g.dart';
|
||||
|
||||
/// Live Firestore-backed stream of every suggestion, newest first, for the
|
||||
/// admin review dashboard.
|
||||
@riverpod
|
||||
Stream<List<Suggestion>> adminSuggestionsStream(
|
||||
AdminSuggestionsStreamRef ref,
|
||||
) {
|
||||
final repo = ref.watch(suggestionsRepositoryProvider);
|
||||
return repo.watchAllSuggestions();
|
||||
}
|
||||
|
||||
/// Imperative wrapper around the suggestion write methods.
|
||||
@riverpod
|
||||
class AdminSuggestionsNotifier extends _$AdminSuggestionsNotifier {
|
||||
@override
|
||||
Future<void> build() async {}
|
||||
|
||||
Future<void> updateStatus(String id, SuggestionStatus status) async {
|
||||
final repo = ref.read(suggestionsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() => repo.updateStatus(id, status));
|
||||
}
|
||||
|
||||
Future<void> delete(String id) async {
|
||||
final repo = ref.read(suggestionsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() => repo.deleteSuggestion(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'admin_suggestions_notifier.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$adminSuggestionsStreamHash() =>
|
||||
r'e87ca116c64b03bf5e62df4c390ff5c3dcfb4e0a';
|
||||
|
||||
/// Live Firestore-backed stream of every suggestion, newest first, for the
|
||||
/// admin review dashboard.
|
||||
///
|
||||
/// Copied from [adminSuggestionsStream].
|
||||
@ProviderFor(adminSuggestionsStream)
|
||||
final adminSuggestionsStreamProvider =
|
||||
AutoDisposeStreamProvider<List<Suggestion>>.internal(
|
||||
adminSuggestionsStream,
|
||||
name: r'adminSuggestionsStreamProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$adminSuggestionsStreamHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef AdminSuggestionsStreamRef =
|
||||
AutoDisposeStreamProviderRef<List<Suggestion>>;
|
||||
String _$adminSuggestionsNotifierHash() =>
|
||||
r'fd85d538be1e2d9abad02812d9c964c2df2b547a';
|
||||
|
||||
/// Imperative wrapper around the suggestion write methods.
|
||||
///
|
||||
/// Copied from [AdminSuggestionsNotifier].
|
||||
@ProviderFor(AdminSuggestionsNotifier)
|
||||
final adminSuggestionsNotifierProvider =
|
||||
AutoDisposeAsyncNotifierProvider<AdminSuggestionsNotifier, void>.internal(
|
||||
AdminSuggestionsNotifier.new,
|
||||
name: r'adminSuggestionsNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$adminSuggestionsNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AdminSuggestionsNotifier = AutoDisposeAsyncNotifier<void>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -0,0 +1,46 @@
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import '../../teams/domain/team.dart';
|
||||
import '../../teams/infrastructure/teams_repository.dart';
|
||||
|
||||
part 'admin_teams_notifier.g.dart';
|
||||
|
||||
/// Live Firestore-backed stream of every team (including pending and
|
||||
/// rejected), used by the admin panel.
|
||||
@riverpod
|
||||
Stream<List<Team>> adminTeamsStream(AdminTeamsStreamRef ref) {
|
||||
final repo = ref.watch(teamsRepositoryProvider);
|
||||
return repo.adminWatchAllTeams();
|
||||
}
|
||||
|
||||
/// Imperative wrapper around the teams repository write methods.
|
||||
@riverpod
|
||||
class AdminTeamsNotifier extends _$AdminTeamsNotifier {
|
||||
@override
|
||||
Future<void> build() async {}
|
||||
|
||||
Future<String> create(Team team) async {
|
||||
final repo = ref.read(teamsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
try {
|
||||
final id = await repo.createTeam(team);
|
||||
state = const AsyncData(null);
|
||||
return id;
|
||||
} catch (e, st) {
|
||||
state = AsyncError(e, st);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> save(Team team) async {
|
||||
final repo = ref.read(teamsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() => repo.updateTeam(team));
|
||||
}
|
||||
|
||||
Future<void> delete(String id) async {
|
||||
final repo = ref.read(teamsRepositoryProvider);
|
||||
state = const AsyncLoading();
|
||||
state = await AsyncValue.guard(() => repo.deleteTeam(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'admin_teams_notifier.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$adminTeamsStreamHash() => r'f392e2c9de281c80912d4fccfaf56c0cbe8ef880';
|
||||
|
||||
/// Live Firestore-backed stream of every team (including pending and
|
||||
/// rejected), used by the admin panel.
|
||||
///
|
||||
/// Copied from [adminTeamsStream].
|
||||
@ProviderFor(adminTeamsStream)
|
||||
final adminTeamsStreamProvider = AutoDisposeStreamProvider<List<Team>>.internal(
|
||||
adminTeamsStream,
|
||||
name: r'adminTeamsStreamProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$adminTeamsStreamHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef AdminTeamsStreamRef = AutoDisposeStreamProviderRef<List<Team>>;
|
||||
String _$adminTeamsNotifierHash() =>
|
||||
r'1f5febaa0f2eb35596538db76896c96dd240a1d8';
|
||||
|
||||
/// Imperative wrapper around the teams repository write methods.
|
||||
///
|
||||
/// Copied from [AdminTeamsNotifier].
|
||||
@ProviderFor(AdminTeamsNotifier)
|
||||
final adminTeamsNotifierProvider =
|
||||
AutoDisposeAsyncNotifierProvider<AdminTeamsNotifier, void>.internal(
|
||||
AdminTeamsNotifier.new,
|
||||
name: r'adminTeamsNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$adminTeamsNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AdminTeamsNotifier = AutoDisposeAsyncNotifier<void>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
Reference in New Issue
Block a user