Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Library.ApplicationCore.Entities;

namespace Library.ApplicationCore;

public interface IBookRepository
{
Task<Book?> SearchBookByTitle(string title);
Task<List<Loan>> GetLoansByBookId(int bookId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ public enum CommonActions
SearchPatrons = 4,
RenewPatronMembership = 8,
ReturnLoanedBook = 16,
ExtendLoanedBook = 32
ExtendLoanedBook = 32,
SearchBooks = 64
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Library.ApplicationCore.Entities;
using Library.ApplicationCore.Enums;
using Library.Console;
using Library.Infrastructure.Data;

public class ConsoleApp
{
Expand All @@ -16,13 +17,15 @@ public class ConsoleApp
ILoanRepository _loanRepository;
ILoanService _loanService;
IPatronService _patronService;
JsonData _jsonData;

public ConsoleApp(ILoanService loanService, IPatronService patronService, IPatronRepository patronRepository, ILoanRepository loanRepository)
public ConsoleApp(ILoanService loanService, IPatronService patronService, IPatronRepository patronRepository, ILoanRepository loanRepository, JsonData jsonData)
{
_patronRepository = patronRepository;
_loanRepository = loanRepository;
_loanService = loanService;
_patronService = patronService;
_jsonData = jsonData;
}

public async Task Run()
Expand Down Expand Up @@ -94,7 +97,7 @@ static void PrintPatronsList(List<Patron> matchingPatrons)

async Task<ConsoleState> PatronSearchResults()
{
CommonActions options = CommonActions.Select | CommonActions.SearchPatrons | CommonActions.Quit;
CommonActions options = CommonActions.Select | CommonActions.SearchPatrons | CommonActions.SearchBooks | CommonActions.Quit;
CommonActions action = ReadInputOptions(options, out int selectedPatronNumber);
if (action == CommonActions.Select)
{
Expand All @@ -110,6 +113,10 @@ async Task<ConsoleState> PatronSearchResults()
return ConsoleState.PatronSearchResults;
}
}
else if (action == CommonActions.SearchBooks)
{
return ConsoleState.PatronSearchResults;
}
else if (action == CommonActions.Quit)
{
return ConsoleState.Quit;
Expand All @@ -124,6 +131,7 @@ async Task<ConsoleState> PatronSearchResults()

static CommonActions ReadInputOptions(CommonActions options, out int optionNumber)
{

CommonActions action;
optionNumber = 0;
do
Expand All @@ -136,6 +144,7 @@ static CommonActions ReadInputOptions(CommonActions options, out int optionNumbe
{
"q" when options.HasFlag(CommonActions.Quit) => CommonActions.Quit,
"s" when options.HasFlag(CommonActions.SearchPatrons) => CommonActions.SearchPatrons,
"b" when options.HasFlag(CommonActions.SearchBooks) => CommonActions.SearchBooks,
"m" when options.HasFlag(CommonActions.RenewPatronMembership) => CommonActions.RenewPatronMembership,
"e" when options.HasFlag(CommonActions.ExtendLoanedBook) => CommonActions.ExtendLoanedBook,
"r" when options.HasFlag(CommonActions.ReturnLoanedBook) => CommonActions.ReturnLoanedBook,
Expand All @@ -153,6 +162,7 @@ _ when int.TryParse(userInput, out optionNumber) => CommonActions.Select,

static void WriteInputOptions(CommonActions options)
{

Console.WriteLine("Input Options:");
if (options.HasFlag(CommonActions.ReturnLoanedBook))
{
Expand All @@ -170,6 +180,10 @@ static void WriteInputOptions(CommonActions options)
{
Console.WriteLine(" - \"s\" for new search");
}
if (options.HasFlag(CommonActions.SearchBooks))
{
Console.WriteLine(" - \"b\" to check for book availability");
}
if (options.HasFlag(CommonActions.Quit))
{
Console.WriteLine(" - \"q\" to quit");
Expand All @@ -193,7 +207,7 @@ async Task<ConsoleState> PatronDetails()
loanNumber++;
}

CommonActions options = CommonActions.SearchPatrons | CommonActions.Quit | CommonActions.Select | CommonActions.RenewPatronMembership;
CommonActions options = CommonActions.SearchPatrons | CommonActions.Quit | CommonActions.Select | CommonActions.RenewPatronMembership | CommonActions.SearchBooks;
CommonActions action = ReadInputOptions(options, out int selectedLoanNumber);
if (action == CommonActions.Select)
{
Expand Down Expand Up @@ -225,10 +239,67 @@ async Task<ConsoleState> PatronDetails()
selectedPatronDetails = (await _patronRepository.GetPatron(selectedPatronDetails.Id))!;
return ConsoleState.PatronDetails;
}
else if (action == CommonActions.SearchBooks)
{
return await SearchBooks();
}

throw new InvalidOperationException("An input option is not handled.");
}

async Task<ConsoleState> SearchBooks()
{
// Ensure data is loaded
await _jsonData.EnsureDataLoaded();

string? bookTitle = null;
while (String.IsNullOrWhiteSpace(bookTitle))
{
Console.Write("Enter a book title to search for: ");
bookTitle = Console.ReadLine();
}

// Use FirstOrDefault to find a book in Books.json (case-insensitive)
Book? foundBook = _jsonData.Books?.FirstOrDefault(b =>
b.Title.Contains(bookTitle, StringComparison.OrdinalIgnoreCase));

if (foundBook == null)
{
Console.WriteLine($"No book found with title: {bookTitle}");
return ConsoleState.PatronDetails;
}

// Retrieve the corresponding BookItem using the BookId from BookItems.json
var bookItems = _jsonData.BookItems?.Where(bi => bi.BookId == foundBook.Id).ToList();

// Check Loans.json for an active loan (loan.ReturnDate == null) for the BookItem
Loan? activeLoan = null;
if (bookItems != null && bookItems.Count > 0)
{
foreach (var bookItem in bookItems)
{
activeLoan = _jsonData.Loans?.FirstOrDefault(l =>
l.BookItemId == bookItem.Id && l.ReturnDate == null);
if (activeLoan != null)
{
break;
}
}
}

// Display whether the book is available for loan or currently on loan with the due date
if (activeLoan == null)
{
Console.WriteLine($"\"{foundBook.Title}\" is available for loan");
}
else
{
Console.WriteLine($"\"{foundBook.Title}\" is on loan to another patron. The return due date is {activeLoan.DueDate}");
}

return ConsoleState.PatronDetails;
}

async Task<ConsoleState> LoanDetails()
{
Console.WriteLine($"Book title: {selectedLoanDetails.BookItem!.Book!.Title}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
.AddJsonFile("appSettings.json")
.Build();


services.AddSingleton<IConfiguration>(configuration);

services.AddScoped<IPatronRepository, JsonPatronRepository>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Library.ApplicationCore;
using Library.ApplicationCore.Entities;

namespace Library.Infrastructure.Data;

public class JsonBookRepository : IBookRepository
{
private readonly JsonData _jsonData;

public JsonBookRepository(JsonData jsonData)
{
_jsonData = jsonData;
}

public async Task<Book?> SearchBookByTitle(string title)
{
await _jsonData.EnsureDataLoaded();

// Case-insensitive search
return _jsonData.Books?.FirstOrDefault(b =>
b.Title.Contains(title, StringComparison.OrdinalIgnoreCase));
}

public async Task<List<Loan>> GetLoansByBookId(int bookId)
{
await _jsonData.EnsureDataLoaded();

var loans = new List<Loan>();
foreach (var loan in _jsonData.Loans!)
{
var bookItem = _jsonData.BookItems?.FirstOrDefault(bi => bi.Id == loan.BookItemId);
if (bookItem?.BookId == bookId)
{
loans.Add(loan);
}
}
return loans;
}
}