Skip to content

Commit

Permalink
Merge pull request #84 from TeamSevenWeb/add-cards-page
Browse files Browse the repository at this point in the history
Add cards page
  • Loading branch information
amechkarov authored Mar 18, 2024
2 parents 5adf73c + 4f20c0e commit bf0baf1
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,51 +1,62 @@
package com.telerikacademy.web.virtualwallet.controllers.mvc;

import com.telerikacademy.web.virtualwallet.exceptions.AuthenticationException;
import com.telerikacademy.web.virtualwallet.exceptions.AuthorizationException;
import com.telerikacademy.web.virtualwallet.exceptions.EntityDuplicateException;
import com.telerikacademy.web.virtualwallet.models.Card;
import com.telerikacademy.web.virtualwallet.models.User;
import com.telerikacademy.web.virtualwallet.models.dtos.CardDto;
import com.telerikacademy.web.virtualwallet.services.contracts.CardService;
import com.telerikacademy.web.virtualwallet.services.contracts.UserService;
import com.telerikacademy.web.virtualwallet.utils.AuthenticationHelper;
import com.telerikacademy.web.virtualwallet.utils.CardMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;
import java.util.Set;

@Controller
@RequestMapping("users/cards")
@RequestMapping("/users/cards")
public class CardMvcController {

private final UserService userService;
private final CardService cardService;

private final CardMapper cardMapper;
private final AuthenticationHelper authenticationHelper;

private final CardService cardService;
@Autowired
public CardMvcController(UserService userService, CardMapper cardMapper, CardService cardService) {
this.userService = userService;
this.cardMapper = cardMapper;
public CardMvcController(CardService cardService, AuthenticationHelper authenticationHelper) {
this.authenticationHelper = authenticationHelper;
this.cardService = cardService;
}

@ModelAttribute("isAuthenticated")
public boolean populateIsAuthenticated(HttpSession session) {
return session.getAttribute("currentUser") != null;
}

// @PostMapping()
// public void create(@RequestHeader HttpHeaders headers, @Valid @RequestBody CardDto cardDto) {
// try {
// User holder = userService.getById(1);
// Card card = cardMapper.fromDto(holder,cardDto);
// cardService.create(holder,card);
// } catch (EntityDuplicateException e) {
// throw new ResponseStatusException(HttpStatus.CONFLICT, e.getMessage());
// } catch (AuthorizationException e) {
// throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage());
// }
// }
@ModelAttribute("requestURI")
public String requestURI(final HttpServletRequest request) {
return request.getRequestURI();
}
@GetMapping
public String showCardsPage(HttpSession session, Model model) {
try {
User holder = authenticationHelper.tryGetCurrentUser(session);
List<Card> cards = cardService.getUsersCards(holder);
model.addAttribute("currentUser",holder);
model.addAttribute("userCards",cards);
return "CardsView";
}catch (AuthenticationException | AuthorizationException e) {
return "redirect:/auth/login";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public String createTransaction(@Valid @ModelAttribute("transaction") Transactio
return "ErrorView";
} catch (TransactionConfirmationException | TransactionExpiredException e) {
redirectAttributes.addFlashAttribute("success", e.getMessage());
return "redirect:/";
return "redirect:/users/transactions";
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.telerikacademy.web.virtualwallet.controllers.rest;

import com.telerikacademy.web.virtualwallet.exceptions.AuthenticationException;
import com.telerikacademy.web.virtualwallet.exceptions.AuthorizationException;
import com.telerikacademy.web.virtualwallet.exceptions.EntityDuplicateException;
import com.telerikacademy.web.virtualwallet.exceptions.EntityNotFoundException;
Expand Down Expand Up @@ -44,6 +45,8 @@ public Card getById(@RequestHeader(name = "Authentication")
return cardService.get(holder,id);
} catch (EntityNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
}catch (AuthenticationException | AuthorizationException e) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage());
}
}

Expand All @@ -56,7 +59,7 @@ public void create(@RequestHeader(name = "Authentication")
cardService.create(holder,card);
} catch (EntityDuplicateException e) {
throw new ResponseStatusException(HttpStatus.CONFLICT, e.getMessage());
} catch (AuthorizationException e) {
} catch (AuthenticationException | AuthorizationException e) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage());
}
}
Expand All @@ -69,6 +72,8 @@ public void delete(@RequestHeader(name = "Authentication")
cardService.delete(holder,id);
} catch (EntityNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
}catch (AuthenticationException | AuthorizationException e){
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, e.getMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.telerikacademy.web.virtualwallet.models.dtos;

import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;

public class TransferDto {
Expand All @@ -10,6 +11,7 @@ public class TransferDto {

@NotNull(message = "Amount can't be empty")
@Digits(integer = 10, fraction = 2)
@Min(value = 1)
private long amount;

public TransferDto(){
Expand Down
6 changes: 5 additions & 1 deletion src/main/resources/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,8 @@ wallets=Wallets
currencies=Currencies

holdings=Holdings
holder=Holder
holder=Holder

#Cards
cards.page.title=All Cards
cards.page.empty.title=Oops, there are no cards in your account.
18 changes: 16 additions & 2 deletions src/main/resources/static/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -938,11 +938,11 @@ header{
.copyright {
background-color: rgb(0,0,0);
}

.multi-container {
display: flex;
flex-wrap: wrap; /* Allow items to wrap to new lines */
justify-content: center; /* Center the items horizontally */
padding-bottom: 10rem;
gap: 20px; /* Add some spacing between items */
}

/* ########################################### */
Expand Down Expand Up @@ -2348,6 +2348,15 @@ header{
margin-left: 2.5em ;
}

.marg-r-2em{
margin-right: 2.5em ;
}

.mar-l-r-40{
margin-left: 20%;
margin-right: 20%;
}

.marg-l-1em{
margin-left: 1.5em ;
}
Expand Down Expand Up @@ -2482,4 +2491,9 @@ header{

.display-none{
display: none;
}

.enlarged-fab {
font-size: 80px; /* Adjust the font size as needed */
transition: font-size 0.3s ease; /* Add a smooth transition effect */
}
72 changes: 72 additions & 0 deletions src/main/resources/templates/CardsView.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-XXXXX" crossorigin="anonymous" />
<div th:insert="~{fragments/PageFrame :: head('Cards')}"></div>
<script th:inline="javascript">
var userCardsEmpty = [[${currentUser.userCards.isEmpty()}]];
var username = [[${currentUser.username}]];
var password = [[${currentUser.password}]];
</script>
<body>
<div th:replace="~{fragments/PageFrame :: navbar}"></div>
<section class="page-section">
<header class="navigate">
<!-- Masthead Heading-->
<h1 th:unless="${userCards.isEmpty()}" class="text-uppercase mb-0 font-aquire" th:text="#{cards.page.title}">All
Cards</h1>
<h1 th:if="${userCards.isEmpty()}" class="text-uppercase mb-0 font-aquire" th:text="#{cards.page.empty.title}">No
Cards </h1>
</header>
</section>
<section class="page-section text-center font-aquire">
<div th:unless="${userCards.isEmpty()}">

<div class="multi-container navigate mar-l-r-40">
<div th:each="card : ${userCards}">
<div class="wallet-block">
<br/>
<span class="font-aquire" th:text="${'**** **** **** '+card.number.subSequence(12,16)}"></span>
<br/>
<label style="font-weight: bold" th:text="${card.holder.firstName}">Holdings</label>
<br/><br/>
<span class="font-aquire" th:text="${card.expirationDate}"></span>
<br/><br/>
<i th:if="${card.number.startsWith('6')}" class="enlarged-fab fab fa-cc-discover"></i> <!-- Discover -->
<i th:if="${card.number.startsWith('5')}" class="enlarged-fab fab fa-cc-mastercard"></i> <!-- Mastercard -->
<i th:if="${card.number.startsWith('4')}" class="enlarged-fab fab fa-cc-visa"></i> <!-- VISA -->
<i th:if="${card.number.startsWith('3')}" class="enlarged-fab fab fa-cc-amex"></i> <!-- AMEX -->
<i th:unless="${card.number.startsWith('6') or card.number.startsWith('5') or card.number.startsWith('4') or card.number.startsWith('3')}" class="enlarged-fab fab fa-credit-card"></i> <!-- Default icon (Credit Card) -->
</div>
</div>
</div>
</div>
<br/><br/>
<div class="modal-overlay" id="modalOverlay"></div>
<div class="modal" id="cardFlyout" style="display: none;">
<div class="modal-header">
<span type="button" class="close" data-dismiss="modal">&times;</span>
<span style="font-size: 18px;" class="modal-title font-aquire">Enter Card Details</span>
</div>
<div class="modal-content">
<br/>
<br/>
<form id="cardForm">
<input class="simple-input-style w-10" oninput="removeSpaces()" type="text" id="number" placeholder="Card Number" required><br>
<input class="simple-input-style w-10" type="text" id="holder" placeholder="Cardholder Name" required><br>
<input class="simple-input-style w-10" oninput="formatCVV()" type="text" id="cvv" placeholder="Cvv Number" required><br>
<input class="simple-input-style w-10" oninput="formatExpiryDate()" onblur="validateExpiryDate()"
type="text" id="expiryDate" placeholder="Expiry Date (MM/YY)" required><br>
<span id="expiryDateError" class="error f-size-08 display-none">Invalid date</span><br>
<br>
<button class="py-3-create w-8 rounded font-aquire" type="submit">Save card</button>
</form>
</div>
</br>
</div>

<button class="py-3-create w-8 rounded font-aquire" id="openFlyout">Add Card</button>
</section>
<div th:replace="~{fragments/PageFrame :: scripts}"></div>
</body>
<script src="../../static/js/card.js" th:src="@{/js/card.js}"></script>
</html>
4 changes: 3 additions & 1 deletion src/main/resources/templates/ErrorView.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<div th:insert="~{fragments/PageFrame :: head('Currencies')}"></div>
<body>
<div class="body-content">
<div th:replace="~{fragments/PageFrame :: navbar}"></div>
<div class="body-content font-aquire">
<h2 class="label-error" th:text="${statusCode}">HTTP Status Code</h2>
<h3 class="error" th:text="${error}">Error placeholder</h3>
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/main/resources/templates/NewTransactionView.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ <h2 class="font-aquire pd-b-1" th:text="#{transaction.page.title}">Transaction</
<form action="#" th:action="@{__${requestURI}__}" th:object="${transaction}" method="post">
<label th:text="#{transaction.receiver.label}">Content</label>
<br/>
<input class="textarea-style w-20" type="text" th:field="*{receiver}" placeholder="Username, phone number or email">
<input class="textarea-style w-10" type="text" th:field="*{receiver}" placeholder="Username, phone number or email">
<br/>
<label class="error" th:errors="*{receiver}">Receiver error placeholder</label>
<br/><br/>
<label th:text="#{transaction.amount.label}">Content</label>
<br/>
<input class="simple-input-style" type="number" th:field="*{amount}" th:text="BGN">
<br/>
<input class="simple-input-style w-5 marg-l-2em" type="number" th:field="*{amount}" th:text="BGN">
<br/><br/>
<label class="error" th:errors="*{amount}">Amount error placeholder</label>
<br/><br/>
<input class="py-3-create w-8 rounded font-aquire" type="submit" value="Send"/>
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/templates/UserView.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
<a th:if="${session.isAdmin && isBlocked}" href="#" th:href="@{/users/__${viewedUser.getUsername()}__/unblock}">
<div class="user-button" >Unblock User</div></a>
<br/>
<a href="#" th:href="@{/users/cards}">
<div class="user-button" >Cards</div></a>
<br/>
<div class="user-info">
<h2 class="center" th:text="${viewedUser.username}"></h2>
<hr>
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/templates/fragments/PageFrame.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!DOCTYPE html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:fragment="head(title)">
<meta charset="UTF-8">
Expand Down

0 comments on commit bf0baf1

Please sign in to comment.