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
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 @@ -136,6 +139,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 Down Expand Up @@ -170,6 +174,10 @@ static void WriteInputOptions(CommonActions options)
{
Console.WriteLine(" - \"s\" for new search");
}
if (options.HasFlag(CommonActions.SearchBooks))
{
Console.WriteLine(" - \"b\" to check if a book is available for loan");
}
if (options.HasFlag(CommonActions.Quit))
{
Console.WriteLine(" - \"q\" to quit");
Expand All @@ -193,7 +201,7 @@ async Task<ConsoleState> PatronDetails()
loanNumber++;
}

CommonActions options = CommonActions.SearchPatrons | CommonActions.Quit | CommonActions.Select | CommonActions.RenewPatronMembership;
CommonActions options = CommonActions.SearchPatrons | CommonActions.SearchBooks | CommonActions.Quit | CommonActions.Select | CommonActions.RenewPatronMembership;
CommonActions action = ReadInputOptions(options, out int selectedLoanNumber);
if (action == CommonActions.Select)
{
Expand All @@ -217,6 +225,10 @@ async Task<ConsoleState> PatronDetails()
{
return ConsoleState.PatronSearch;
}
else if (action == CommonActions.SearchBooks)
{
return await SearchBooks();
}
else if (action == CommonActions.RenewPatronMembership)
{
var status = await _patronService.RenewMembership(selectedPatronDetails.Id);
Expand All @@ -229,6 +241,43 @@ async Task<ConsoleState> PatronDetails()
throw new InvalidOperationException("An input option is not handled.");
}

async Task<ConsoleState> SearchBooks()
{
string? bookTitle = null;
while (string.IsNullOrWhiteSpace(bookTitle))
{
Console.Write("Enter a book title to search for: ");
bookTitle = Console.ReadLine();
}

await _jsonData.EnsureDataLoaded();

Book? book = _jsonData.Books!.FirstOrDefault(b => string.Equals(b.Title, bookTitle, StringComparison.OrdinalIgnoreCase));
if (book == null)
{
Console.WriteLine($"No book found with title \"{bookTitle}\".");
return ConsoleState.PatronDetails;
}

List<BookItem> bookItems = _jsonData.BookItems!.Where(bookItem => bookItem.BookId == book.Id).ToList();
List<Loan> activeLoans = _jsonData.Loans!
.Where(loan => bookItems.Any(bookItem => bookItem.Id == loan.BookItemId) && loan.ReturnDate == null)
.OrderByDescending(loan => loan.LoanDate)
.ToList();

if (bookItems.Any(bookItem => activeLoans.All(loan => loan.BookItemId != bookItem.Id)))
{
Console.WriteLine($"{book.Title} is available for loan");
}
else
{
Loan loan = activeLoans.First();
Console.WriteLine($"{book.Title} is on loan to another patron. The return due date is {loan.DueDate}.");
}

return ConsoleState.PatronDetails;
}

async Task<ConsoleState> LoanDetails()
{
Console.WriteLine($"Book title: {selectedLoanDetails.BookItem!.Book!.Title}");
Expand Down
37 changes: 37 additions & 0 deletions untitled:plan-consultaDisponibilidadeLivros.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## Plan: Consulta de disponibilidade de livros

Completar a implementação parcial da consulta de disponibilidade no projeto `AccelerateDevGHCopilot`, mantendo o fluxo atual de console e o contrato do laboratório. A versão alvo já tem partes de `SearchBooks` em `ConsoleApp`, mas está inconsistente com `CommonActions` e com a injeção de `JsonData`; o plano corrige essa integração e valida o comportamento pelos dados JSON existentes.

**Passos**
1. Atualizar `CommonActions` com `SearchBooks = 64`, preservando os valores atuais das flags.
2. Corrigir `ConsoleApp` para receber `JsonData` no construtor e armazená-lo em `_jsonData`; manter o registro único `services.AddSingleton<JsonData>()` já presente em `Program.cs`.
3. Completar a integração em `PatronDetails`: incluir `SearchBooks` nas opções, aceitar `b` em `ReadInputOptions`, exibir a opção em `WriteInputOptions`, chamar `SearchBooks` e retornar a `PatronDetails` após a consulta.
4. Revisar `SearchBooks`: solicitar novamente enquanto o título estiver nulo ou em branco; chamar `EnsureDataLoaded`; localizar o livro sem diferenciar maiúsculas/minúsculas; informar título inexistente; localizar todos os exemplares pelo `BookId`; considerar o título disponível se algum exemplar não tiver empréstimo ativo (`ReturnDate == null`); caso todos estejam emprestados, exibir uma data de devolução de empréstimo ativo com a formatação esperada pelo roteiro.
5. Manter o escopo fora de empréstimos e reservas: não criar `Reservations.json`, repositórios, interfaces ou serviços novos.
6. Validar com `dotnet build`, `dotnet test` e execução manual do console. Como não há testes de console no projeto alvo, cobrir manualmente entrada vazia, título inexistente, livro disponível, livro emprestado, empréstimo devolvido e retorno ao menu.

**Relevant files**
- `/workspaces/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/CommonActions.cs` — enum `CommonActions`; adicionar `SearchBooks`.
- `/workspaces/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/ConsoleApp.cs` — corrigir a injeção e completar `ReadInputOptions`, `WriteInputOptions`, `PatronDetails` e `SearchBooks`.
- `/workspaces/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Console/Program.cs` — somente confirmar o registro existente de `JsonData`.
- `/workspaces/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.Infrastructure/Data/JsonData.cs` — reutilizar `EnsureDataLoaded` e as listas carregadas; nenhuma alteração prevista.
- `/workspaces/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/src/Library.ApplicationCore/Entities/Book.cs`, `BookItem.cs` e `Loan.cs` — relações `BookItem.BookId`, `Loan.BookItemId` e `Loan.ReturnDate` usadas na consulta.
- `/workspaces/mslearn-github-copilot-dev/Instructions/Labs/LAB_AK_03_develop_code_features.md` — requisitos funcionais e mensagens esperadas.
- `/workspaces/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot/tests/UnitTests` — não há testes de console; os testes existentes de serviços devem continuar passando.

**Verification**
1. Executar `dotnet build` em `/workspaces/mslearn-github-copilot-dev/LabFiles/03-develop-code-features/AccelerateDevGHCopilot` e confirmar ausência de erros, especialmente a resolução de `SearchBooks` e `_jsonData`.
2. Executar `dotnet test` no mesmo diretório e confirmar que os testes existentes continuam passando.
3. Executar `dotnet run --project src/Library.Console/Library.Console.csproj`, selecionar um patrono, usar `b` e consultar um título conhecido; verificar a mensagem de disponibilidade ou de empréstimo com data.
4. Repetir a execução com entrada vazia, título inexistente e título com diferenças de caixa; verificar a repetição da solicitação, a mensagem de inexistência e a busca case-insensitive.
5. Validar um empréstimo devolvido e, se os dados contiverem múltiplos exemplares, confirmar que um exemplar livre torna o título disponível; confirmar também o retorno a `PatronDetails` e o funcionamento de `q`.

**Decisions**
- A disponibilidade é por título e por todos os exemplares associados ao `BookId`, não somente pelo primeiro exemplar.
- Empréstimo ativo é definido por `ReturnDate == null`; a data de vencimento, inclusive vencida, não altera essa regra do requisito.
- Se houver múltiplos empréstimos ativos inconsistentes para o mesmo exemplar, selecionar deterministicamente o mais recente por `LoanDate` para a data exibida, sem alterar o modelo.
- O escopo limita-se à disponibilidade; empréstimos, reservas e persistência nova ficam para as etapas posteriores.
- Reutilizar `JsonData`; não criar novo repositório/serviço nem duplicar seu registro no DI.

**Further Considerations**
1. A implementação posterior de empréstimos pode alterar `Loans.json`; a consulta deve continuar usando o mesmo `JsonData` singleton e recarregar dados quando a camada de empréstimos fizer isso.