Files
YungR1otz/lib/features/admin/presentation/pages/admin_page.dart
Lucas Saburido cabf2025cd first commit
2026-05-13 16:26:45 +01:00

190 lines
5.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../../shared/widgets/riotz_shell.dart';
import '../../domain/models/admin_post_model.dart';
import '../../domain/models/admin_user_model.dart';
import '../providers/admin_providers.dart';
class AdminPage extends ConsumerWidget {
const AdminPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final isAdmin = ref.watch(isAdminProvider);
final dataAsync = ref.watch(adminPanelDataProvider);
ref.listen(adminControllerProvider, (_, next) {
next.whenOrNull(
data: (_) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Admin action applied')),
);
},
error: (error, _) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(error.toString())),
);
},
);
});
if (!isAdmin) {
return const RiotzShell(
title: 'RIOTZ // Admin',
child: Center(
child: Text('You are not authorized for admin panel access.'),
),
);
}
return RiotzShell(
title: 'RIOTZ // Admin',
child: RefreshIndicator(
onRefresh: () async => ref.invalidate(adminPanelDataProvider),
child: dataAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, _) => Center(child: Text('Error: $error')),
data: (data) => ListView(
padding: const EdgeInsets.all(16),
children: [
Text(
'Whitelist-based Admin Panel',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 12),
Text(
'Users',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
...data.users.map(
(user) => _UserModerationCard(
user: user,
onToggleBan: (banned) => ref
.read(adminControllerProvider.notifier)
.setUserBanned(userId: user.userId, banned: banned),
),
),
const SizedBox(height: 18),
Text(
'Posts',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
...data.posts.map(
(post) => _PostModerationCard(
post: post,
onDelete: () =>
ref.read(adminControllerProvider.notifier).deletePost(post.id),
onToggleFeatured: (featured) => ref
.read(adminControllerProvider.notifier)
.setPostFeatured(postId: post.id, featured: featured),
),
),
],
),
),
),
);
}
}
class _UserModerationCard extends StatelessWidget {
const _UserModerationCard({
required this.user,
required this.onToggleBan,
});
final AdminUserModel user;
final ValueChanged<bool> onToggleBan;
@override
Widget build(BuildContext context) {
return Card(
child: SwitchListTile(
value: user.banned,
onChanged: onToggleBan,
title: Text(user.username),
subtitle: Text(user.userId),
secondary: CircleAvatar(
backgroundImage:
user.avatarUrl.isNotEmpty ? NetworkImage(user.avatarUrl) : null,
child: user.avatarUrl.isEmpty ? const Icon(Icons.person) : null,
),
activeThumbColor: Colors.redAccent,
),
);
}
}
class _PostModerationCard extends StatelessWidget {
const _PostModerationCard({
required this.post,
required this.onDelete,
required this.onToggleFeatured,
});
final AdminPostModel post;
final VoidCallback onDelete;
final ValueChanged<bool> onToggleFeatured;
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
post.username,
style: Theme.of(context).textTheme.titleSmall,
),
),
IconButton(
onPressed: onDelete,
icon: const Icon(Icons.delete_outline),
),
],
),
if (post.caption.isNotEmpty) ...[
Text(post.caption),
const SizedBox(height: 8),
],
if (post.imageUrl.isNotEmpty)
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
post.imageUrl,
width: double.infinity,
height: 160,
fit: BoxFit.cover,
),
),
const SizedBox(height: 8),
Row(
children: [
Text('${post.likesCount} likes'),
const Spacer(),
Row(
children: [
const Text('Feature'),
Switch(
value: post.featured,
onChanged: onToggleFeatured,
),
],
),
],
),
],
),
),
);
}
}