Commit 68feb6a9 authored by Ilham Maulana's avatar Ilham Maulana 💻

feat: near outstanding loans and overdued loans (admin or librarian access)

parent ff094e41
...@@ -23,6 +23,10 @@ class AuthProvider with ChangeNotifier { ...@@ -23,6 +23,10 @@ class AuthProvider with ChangeNotifier {
bool resetPasswordTokenSended = false; bool resetPasswordTokenSended = false;
bool resetPasswordSucced = false; bool resetPasswordSucced = false;
List<dynamic>? loans;
List<dynamic>? nearOutstandingLoans;
List<dynamic>? overduedLoans;
Future<void> storeAccessToken(String accessToken) async { Future<void> storeAccessToken(String accessToken) async {
await storage.write(key: 'access_token', value: accessToken); await storage.write(key: 'access_token', value: accessToken);
} }
...@@ -366,4 +370,47 @@ class AuthProvider with ChangeNotifier { ...@@ -366,4 +370,47 @@ class AuthProvider with ChangeNotifier {
debugPrint("Failed to create member loan. $error"); debugPrint("Failed to create member loan. $error");
} }
} }
// for admin or librarian
Future<void> getLoans(String? type) async {
final token = await storage.read(key: 'access_token');
String url = baseUrl;
if (type == "upcoming") {
url += "/upcoming-loans/";
} else if (type == "overdue") {
url += "/overdued-loans/";
} else {
url += "/book-loans/";
}
if (token != null) {
try {
final response = await http.get(
Uri.parse(url),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer $token',
},
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
if (type == "upcoming") {
nearOutstandingLoans = data["results"];
} else if (type == "overdue") {
overduedLoans = data["results"];
} else {
loans = data["results"];
}
} else {
final code = response.statusCode;
debugPrint("Error: Fetch upcoming loans failed, $code");
}
notifyListeners();
} catch (error) {
debugPrint("Error: Fetch upcoming loans failed, $error");
}
}
}
} }
...@@ -6,8 +6,9 @@ import 'package:library_app/src/providers/book_provider.dart'; ...@@ -6,8 +6,9 @@ import 'package:library_app/src/providers/book_provider.dart';
import 'package:library_app/src/providers/navigations_provider.dart'; import 'package:library_app/src/providers/navigations_provider.dart';
import 'package:library_app/src/widgets/home.dart'; import 'package:library_app/src/widgets/home.dart';
import 'package:library_app/src/widgets/loans/loan_list.dart';
import 'package:library_app/src/widgets/profile.dart'; import 'package:library_app/src/widgets/profile.dart';
import 'package:library_app/src/widgets/loans/overdued_loan_list.dart';
import 'package:library_app/src/widgets/loans/upcoming_loan_list.dart';
class AdminListScreen extends StatefulWidget { class AdminListScreen extends StatefulWidget {
const AdminListScreen({super.key}); const AdminListScreen({super.key});
...@@ -59,14 +60,10 @@ class _AdminListScreen extends State<AdminListScreen> { ...@@ -59,14 +60,10 @@ class _AdminListScreen extends State<AdminListScreen> {
body: <Widget>[ body: <Widget>[
// Home // Home
const HomePage(), const HomePage(),
// Books // Near Outstanding Loans
LoanList( const UpcomingLoanList(),
memberId: authProvider.user?.accountId ?? 0, // Overdued Loans
), const OverduedLoanList(),
// Loans
LoanList(
memberId: authProvider.user?.accountId ?? 0,
),
// Profile // Profile
const Profile(), const Profile(),
][navProvider.currentPageIndex], ][navProvider.currentPageIndex],
......
...@@ -29,8 +29,11 @@ class _HomePage extends State<HomePage> { ...@@ -29,8 +29,11 @@ class _HomePage extends State<HomePage> {
return Consumer2<NavigationsProvider, AuthProvider>( return Consumer2<NavigationsProvider, AuthProvider>(
builder: (context, navProvider, authProvider, child) { builder: (context, navProvider, authProvider, child) {
final user = authProvider.user;
if (user != null) {
return NestedScrollView( return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return [ return [
const TopBar(title: title), const TopBar(title: title),
]; ];
...@@ -42,13 +45,10 @@ class _HomePage extends State<HomePage> { ...@@ -42,13 +45,10 @@ class _HomePage extends State<HomePage> {
child: Text("Shortcut"), child: Text("Shortcut"),
), ),
Shortcut( Shortcut(
icon: authProvider.user!.isStaff icon:
? Icons.timer_outlined user.isStaff ? Icons.timer_outlined : Icons.book_rounded,
: Icons.book_rounded, title: user.isStaff ? "Near Outstanding Loans" : "Books",
title: authProvider.user!.isStaff subtitle: user.isStaff
? "Near Outstanding Loans"
: "Books",
subtitle: authProvider.user!.isStaff
? "Discover near outstanding users loans." ? "Discover near outstanding users loans."
: "Discover many amazing books.", : "Discover many amazing books.",
onTap: () { onTap: () {
...@@ -56,13 +56,11 @@ class _HomePage extends State<HomePage> { ...@@ -56,13 +56,11 @@ class _HomePage extends State<HomePage> {
}, },
), ),
Shortcut( Shortcut(
icon: authProvider.user!.isStaff icon: user.isStaff
? Icons.timer_off_rounded ? Icons.timer_off_rounded
: Icons.date_range_rounded, : Icons.date_range_rounded,
title: authProvider.user!.isStaff title: user.isStaff ? "Overdued Loans" : "Book Loans",
? "Overdued Loans" subtitle: user.isStaff
: "Book Loans",
subtitle: authProvider.user!.isStaff
? "Discover Overdued users loans." ? "Discover Overdued users loans."
: "Manage your book loan very easy.", : "Manage your book loan very easy.",
onTap: () { onTap: () {
...@@ -72,6 +70,9 @@ class _HomePage extends State<HomePage> { ...@@ -72,6 +70,9 @@ class _HomePage extends State<HomePage> {
], ],
), ),
); );
}
return Container();
}, },
); );
} }
......
import 'package:flutter/material.dart';
import 'package:library_app/src/models/book.dart';
import 'package:library_app/src/providers/auth_provider.dart';
import 'package:provider/provider.dart';
import 'package:library_app/src/models/loan.dart';
import 'package:library_app/src/widgets/loans/loan_item.dart';
class OverduedLoanList extends StatefulWidget {
const OverduedLoanList({super.key});
@override
State<OverduedLoanList> createState() => _OverduedLoanList();
}
class _OverduedLoanList extends State<OverduedLoanList> {
@override
void initState() {
super.initState();
Provider.of<AuthProvider>(context, listen: false).getLoans("overdue");
}
@override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(builder: (context, loanProvider, child) {
if (loanProvider.overduedLoans != null) {
var loans = loanProvider.overduedLoans!.map(
(loan) {
var book = Book.fromJson(loan["book_detail"]);
return Loan(
book,
loan["loan_date"],
loan["due_date"],
loan["remaining_loan_time"],
loan["is_overdue"],
);
},
);
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [const TopAppBar(title: "Overdued Loans")];
},
body: ListView(
children: List.generate(loans.length, (index) {
return LoanItem(loans.elementAt(index));
}),
),
);
} else {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [const TopAppBar(title: "Book Loans")];
},
body: const Center(
child: Text("the loan is currently empty"),
),
);
}
});
}
}
class TopAppBar extends StatefulWidget {
final String title;
const TopAppBar({super.key, required this.title});
@override
_TopAppBar createState() => _TopAppBar();
}
class _TopAppBar extends State<TopAppBar> {
String get title => widget.title;
bool showWidget = false;
@override
Widget build(BuildContext context) {
return SliverAppBar(
title: Text(title),
elevation: 10.0,
automaticallyImplyLeading: false,
expandedHeight: 50,
floating: true,
snap: true,
);
}
}
import 'package:flutter/material.dart';
import 'package:library_app/src/models/book.dart';
import 'package:library_app/src/providers/auth_provider.dart';
import 'package:provider/provider.dart';
import 'package:library_app/src/models/loan.dart';
import 'package:library_app/src/widgets/loans/loan_item.dart';
class UpcomingLoanList extends StatefulWidget {
const UpcomingLoanList({super.key});
@override
State<UpcomingLoanList> createState() => _UpcomingLoanList();
}
class _UpcomingLoanList extends State<UpcomingLoanList> {
@override
void initState() {
super.initState();
Provider.of<AuthProvider>(context, listen: false).getLoans("upcoming");
}
@override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(builder: (context, loanProvider, child) {
if (loanProvider.nearOutstandingLoans != null) {
var loans = loanProvider.nearOutstandingLoans!.map(
(loan) {
var book = Book.fromJson(loan["book_detail"]);
return Loan(
book,
loan["loan_date"],
loan["due_date"],
loan["remaining_loan_time"],
loan["is_overdue"],
);
},
);
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [const TopAppBar(title: "Near Outstanding Loans")];
},
body: ListView(
children: List.generate(loans.length, (index) {
return LoanItem(loans.elementAt(index));
}),
),
);
} else {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [const TopAppBar(title: "Book Loans")];
},
body: const Center(
child: Text("the loan is currently empty"),
),
);
}
});
}
}
class TopAppBar extends StatefulWidget {
final String title;
const TopAppBar({super.key, required this.title});
@override
_TopAppBar createState() => _TopAppBar();
}
class _TopAppBar extends State<TopAppBar> {
String get title => widget.title;
bool showWidget = false;
@override
Widget build(BuildContext context) {
return SliverAppBar(
title: Text(title),
elevation: 10.0,
automaticallyImplyLeading: false,
expandedHeight: 50,
floating: true,
snap: true,
);
}
}
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