Commit 4c625184 authored by Ilham Maulana's avatar Ilham Maulana 💻

fix: filter member loan widgets

parent 8424e274
......@@ -14,4 +14,15 @@ class Loan {
this.remainingDays,
this.isOverdue,
);
factory Loan.fromJson(Map<String, dynamic> data) {
final book = Book.fromJson(data["book_detail"]);
return Loan(
book,
data["loan_date"],
data["due_date"],
data["remaining_loan_time"],
data["is_overdue"],
);
}
}
......@@ -5,6 +5,7 @@ import 'package:http/http.dart' as http;
import 'package:library_app/src/models/token.dart';
import 'package:library_app/src/models/user.dart';
// Flutter: make memberLoans adjustable to be filtered to near outstanding loan and overdued loan
class AuthProvider with ChangeNotifier {
String baseUrl = 'http://localhost:8000/api/v1';
......@@ -14,6 +15,9 @@ class AuthProvider with ChangeNotifier {
bool invalidUsernameOrPassword = false;
List<dynamic>? memberLoans;
bool filterByUpcoming = false;
bool filterByOverdued = false;
Future<void> signIn(String username, String password) async {
try {
final response = await http.post(
......@@ -157,10 +161,19 @@ class AuthProvider with ChangeNotifier {
}
}
Future<void> getMemberLoan(int id) async {
Future<void> getMemberLoan() async {
String url = '$baseUrl/members/${user?.accountId}/loans/';
if (filterByUpcoming) {
url += '?near_outstanding=True';
} else if (filterByOverdued) {
url += '?overdue=True';
} else {
null;
}
try {
final response = await http.get(
Uri.parse('$baseUrl/members/$id/loans/'),
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ${token?.key}'
......@@ -181,6 +194,16 @@ class AuthProvider with ChangeNotifier {
}
}
void setFilterUpcoming() {
filterByUpcoming = !filterByUpcoming;
notifyListeners();
}
void setFilterOverdued() {
filterByOverdued = !filterByOverdued;
notifyListeners();
}
Future<void> createMemberLoan(int memberId, int bookId, int loanDay) async {
final now = DateTime.now();
final dueDate = now.add(Duration(days: loanDay));
......
......@@ -18,18 +18,16 @@ class _LoanList extends State<LoanList> {
@override
void initState() {
super.initState();
Provider.of<AuthProvider>(context, listen: false)
.getMemberLoan(widget.memberId);
Provider.of<AuthProvider>(context, listen: false).getMemberLoan();
}
@override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(builder: (context, authProvider, child) {
if (authProvider.memberLoans != null) {
final Iterable<Loan> loans = authProvider.memberLoans!.map(
var loans = authProvider.memberLoans!.map(
(loan) {
Map<String, dynamic> bookMap = loan["book_detail"];
final book = Book.fromJson(bookMap);
var book = Book.fromJson(loan["book_detail"]);
return Loan(
book,
loan["loan_date"],
......@@ -39,6 +37,7 @@ class _LoanList extends State<LoanList> {
);
},
);
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [const TopAppBar(title: "Book Loans")];
......@@ -78,97 +77,107 @@ class _TopAppBar extends State<TopAppBar> {
@override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size;
return SliverAppBar(
title: Text(showWidget ? "" : title),
actions: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
onPressed: () {
setState(() {
showWidget = !showWidget;
});
},
icon: Icon(showWidget ? Icons.close : Icons.filter_alt_outlined),
),
Offstage(
offstage: !showWidget,
child: Row(
children: [
FilledButton(
style: TextButton.styleFrom(
padding: EdgeInsets.symmetric(
horizontal: screenSize.width * 0.04,
vertical: screenSize.width * 0.02),
return Consumer<AuthProvider>(builder: (context, authBuilder, child) {
return SliverAppBar(
title: Text(showWidget ? "" : title),
actions: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
onPressed: () {
setState(() {
showWidget = !showWidget;
});
},
icon: Icon(
showWidget ? Icons.close : Icons.filter_alt_outlined,
),
),
Offstage(
offstage: !showWidget,
child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [Text("Upcoming"), SwitchToUpcoming()],
),
onPressed: () {},
child: const Text('Near Outstanding'),
),
const SizedBox(
width: 8.0,
),
FilledButton(
style: TextButton.styleFrom(
padding: EdgeInsets.symmetric(
horizontal: screenSize.width * 0.04,
vertical: screenSize.width * 0.02),
SizedBox(
width: 20.0,
),
onPressed: () {},
child: const Text(
'Overdued',
Row(
children: [Text("Overdue"), SwitchToOverdued()],
),
),
],
),
),
],
),
],
elevation: 10.0,
automaticallyImplyLeading: false,
expandedHeight: 50,
floating: true,
snap: true,
);
],
),
)
],
),
],
elevation: 10.0,
automaticallyImplyLeading: false,
expandedHeight: 50,
floating: true,
snap: true,
);
});
}
}
class LoanTypeFilter extends StatelessWidget implements PreferredSizeWidget {
final double sizeAppBar = 50.0;
class SwitchToUpcoming extends StatefulWidget {
const SwitchToUpcoming({super.key});
@override
State<SwitchToUpcoming> createState() => _SwitchToUpcoming();
}
class _SwitchToUpcoming extends State<SwitchToUpcoming> {
@override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(builder: (context, authProvider, child) {
return Switch(
value: authProvider.filterByUpcoming,
onChanged: (bool value) {
setState(() {
authProvider.setFilterUpcoming();
if (authProvider.filterByUpcoming &&
authProvider.filterByOverdued) {
authProvider.setFilterOverdued();
}
authProvider.getMemberLoan();
});
},
);
});
}
}
const LoanTypeFilter({super.key});
class SwitchToOverdued extends StatefulWidget {
const SwitchToOverdued({super.key});
@override
Size get preferredSize => Size.fromHeight(sizeAppBar);
State<SwitchToOverdued> createState() => _SwitchToOverdued();
}
class _SwitchToOverdued extends State<SwitchToOverdued> {
@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(width: 10.0),
SizedBox(
height: 30.0,
child: OutlinedButton(
onPressed: () {}, child: const Text("Near Overdue")),
),
const SizedBox(width: 10.0),
SizedBox(
height: 30.0,
child: OutlinedButton(
onPressed: () {}, child: const Text("Overdue")),
),
],
),
),
],
return Consumer<AuthProvider>(
builder: (context, authProvider, child) {
return Switch(
value: authProvider.filterByOverdued,
onChanged: (bool value) {
setState(() {
authProvider.setFilterOverdued();
if (authProvider.filterByUpcoming &&
authProvider.filterByOverdued) {
authProvider.setFilterUpcoming();
}
authProvider.getMemberLoan();
});
},
);
},
);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment