diff --git a/backend/requests/blackjack.http b/backend/requests/blackjack.http deleted file mode 100644 index 21dd35e..0000000 --- a/backend/requests/blackjack.http +++ /dev/null @@ -1,20 +0,0 @@ -POST http://localhost:8080/blackjack/start -Authorization: Bearer {{token}} -Content-Type: application/json - -{ - "betAmount": 1.01 -} - -### -POST http://localhost:8080/blackjack/54/hit -Authorization: Bearer {{token}} - -### -POST http://localhost:8080/blackjack/202/stand -Authorization: Bearer {{token}} - -### -GET http://localhost:8080/blackjack/202 -Authorization: Bearer {{token}} - diff --git a/backend/requests/getBearerToken.http b/backend/requests/getBearerToken.http deleted file mode 100644 index 791c3a2..0000000 --- a/backend/requests/getBearerToken.http +++ /dev/null @@ -1,6 +0,0 @@ -POST http://localhost:9090/realms/LF12/protocol/openid-connect/token -Content-Type: application/x-www-form-urlencoded - -grant_type=password&client_id=lf12&username=lf12_test_user&password=secret&scope=openid - -> {% client.global.set("token", response.body.access_token); %} \ No newline at end of file diff --git a/backend/requests/healthCheck.http b/backend/requests/healthCheck.http deleted file mode 100644 index 4be46b5..0000000 --- a/backend/requests/healthCheck.http +++ /dev/null @@ -1 +0,0 @@ -GET localhost:8080/health \ No newline at end of file diff --git a/backend/requests/lootboxes.http b/backend/requests/lootboxes.http deleted file mode 100644 index 9059570..0000000 --- a/backend/requests/lootboxes.http +++ /dev/null @@ -1,9 +0,0 @@ -GET http://localhost:8080/lootboxes -Authorization: Bearer {{token}} -Content-Type: application/json - -### - -POST http://localhost:8080/lootboxes/2 -Authorization: Bearer {{token}} -Content-Type: application/json \ No newline at end of file diff --git a/backend/requests/user.http b/backend/requests/user.http deleted file mode 100644 index b594398..0000000 --- a/backend/requests/user.http +++ /dev/null @@ -1,27 +0,0 @@ -### Get User by ID -GET http://localhost:8080/user/52cc0208-a3bd-4367-94c5-0404b016a003 -Authorization: Bearer {{token}} - -### Get current user with token -GET http://localhost:8080/user -Authorization: Bearer {{token}} - -### Create User -POST http://localhost:8080/user -Content-Type: application/json -Authorization: Bearer {{token}} - -{ - "authentikId": "52cc0208-a3bd-4367-94c5-0404b016a003", - "username": "john.doe" -} - -### Deposit -POST http://localhost:8080/deposit/checkout -Content-Type: application/json -Origin: http://localhost:8080 -Authorization: Bearer {{token}} - -{ - "amount": 60.12 -} \ No newline at end of file diff --git a/backend/requests/webhook.http b/backend/requests/webhook.http deleted file mode 100644 index 8fa7f26..0000000 --- a/backend/requests/webhook.http +++ /dev/null @@ -1 +0,0 @@ -POST localhost:8080/webhook diff --git a/backend/src/main/java/de/szut/casino/CasinoApplication.java b/backend/src/main/java/de/szut/casino/CasinoApplication.java index 1d7e861..8c99f02 100644 --- a/backend/src/main/java/de/szut/casino/CasinoApplication.java +++ b/backend/src/main/java/de/szut/casino/CasinoApplication.java @@ -1,20 +1,10 @@ package de.szut.casino; -import de.szut.casino.lootboxes.LootBoxEntity; -import de.szut.casino.lootboxes.LootBoxRepository; -import de.szut.casino.lootboxes.RewardEntity; -import de.szut.casino.lootboxes.RewardRepository; -import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - @SpringBootApplication public class CasinoApplication { @@ -26,65 +16,4 @@ public class CasinoApplication { public static RestTemplate restTemplate() { return new RestTemplate(); } - - @Bean - public CommandLineRunner initData(LootBoxRepository lootBoxRepository, RewardRepository rewardRepository) { - return _ -> { - if (lootBoxRepository.count() == 0) { - LootBoxEntity basicLootBox = new LootBoxEntity(); - basicLootBox.setName("Basic LootBox"); - basicLootBox.setPrice(new BigDecimal("2")); - basicLootBox.setRewards(new ArrayList<>()); // Initialize the list - - LootBoxEntity premiumLootBox = new LootBoxEntity(); - premiumLootBox.setName("Premium LootBox"); - premiumLootBox.setPrice(new BigDecimal("5")); - premiumLootBox.setRewards(new ArrayList<>()); // Initialize the list - - lootBoxRepository.saveAll(Arrays.asList(basicLootBox, premiumLootBox)); - - RewardEntity commonReward = new RewardEntity(); - commonReward.setValue(new BigDecimal("0.50")); - commonReward.setProbability(new BigDecimal("0.7")); - - RewardEntity rareReward = new RewardEntity(); - rareReward.setValue(new BigDecimal("2.00")); - rareReward.setProbability(new BigDecimal("0.25")); - - RewardEntity epicReward = new RewardEntity(); - epicReward.setValue(new BigDecimal("5.00")); - epicReward.setProbability(new BigDecimal("0.5")); - - RewardEntity premiumCommon = new RewardEntity(); - premiumCommon.setValue(new BigDecimal("2.00")); - premiumCommon.setProbability(new BigDecimal("0.6")); - - RewardEntity premiumRare = new RewardEntity(); - premiumRare.setValue(new BigDecimal("5.00")); - premiumRare.setProbability(new BigDecimal("0.3")); - - RewardEntity legendaryReward = new RewardEntity(); - legendaryReward.setValue(new BigDecimal("15.00")); - legendaryReward.setProbability(new BigDecimal("0.10")); - - rewardRepository.saveAll(Arrays.asList( - commonReward, rareReward, epicReward, - premiumCommon, premiumRare, legendaryReward - )); - - basicLootBox.getRewards().add(commonReward); - basicLootBox.getRewards().add(premiumRare); - - premiumLootBox.getRewards().add(premiumCommon); - premiumLootBox.getRewards().add(premiumRare); - premiumLootBox.getRewards().add(legendaryReward); - - lootBoxRepository.saveAll(Arrays.asList(basicLootBox, premiumLootBox)); - - System.out.println("Initial LootBoxes and rewards created successfully"); - } else { - System.out.println("LootBoxes already exist, skipping initialization"); - } - }; - } } diff --git a/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameRepository.java b/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameRepository.java index d25a180..aafea4f 100644 --- a/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameRepository.java +++ b/backend/src/main/java/de/szut/casino/blackjack/BlackJackGameRepository.java @@ -1,12 +1,8 @@ package de.szut.casino.blackjack; -import de.szut.casino.user.UserEntity; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Service; -import java.util.Optional; - @Service public interface BlackJackGameRepository extends JpaRepository { } diff --git a/backend/src/main/java/de/szut/casino/blackjack/BlackJackService.java b/backend/src/main/java/de/szut/casino/blackjack/BlackJackService.java index 158e32c..cb31352 100644 --- a/backend/src/main/java/de/szut/casino/blackjack/BlackJackService.java +++ b/backend/src/main/java/de/szut/casino/blackjack/BlackJackService.java @@ -7,7 +7,6 @@ import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.List; -import java.util.Optional; import java.util.Random; @Service diff --git a/backend/src/main/java/de/szut/casino/deposit/DepositController.java b/backend/src/main/java/de/szut/casino/deposit/DepositController.java index cdf883d..dbfe449 100644 --- a/backend/src/main/java/de/szut/casino/deposit/DepositController.java +++ b/backend/src/main/java/de/szut/casino/deposit/DepositController.java @@ -8,7 +8,6 @@ import de.szut.casino.deposit.dto.AmountDto; import de.szut.casino.deposit.dto.SessionIdDto; import de.szut.casino.user.UserEntity; import de.szut.casino.user.UserRepository; -import de.szut.casino.user.UserService; import de.szut.casino.user.dto.KeycloakUserDto; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Value; @@ -16,7 +15,10 @@ import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +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.RestController; import org.springframework.web.client.RestTemplate; import java.util.Optional; diff --git a/backend/src/main/java/de/szut/casino/deposit/TransactionEntity.java b/backend/src/main/java/de/szut/casino/deposit/TransactionEntity.java index e3fc412..7c43af9 100644 --- a/backend/src/main/java/de/szut/casino/deposit/TransactionEntity.java +++ b/backend/src/main/java/de/szut/casino/deposit/TransactionEntity.java @@ -5,7 +5,7 @@ import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; -import java.math.BigDecimal; +import java.util.Date; @Setter @Getter @@ -26,4 +26,7 @@ public class TransactionEntity { @Enumerated(EnumType.STRING) private TransactionStatus status = TransactionStatus.PROCESSING; + + @Column(name = "created_at") + private Date createdAt = new Date(); } diff --git a/backend/src/main/java/de/szut/casino/deposit/TransactionRepository.java b/backend/src/main/java/de/szut/casino/deposit/TransactionRepository.java index 94b9b6b..5a16f0d 100644 --- a/backend/src/main/java/de/szut/casino/deposit/TransactionRepository.java +++ b/backend/src/main/java/de/szut/casino/deposit/TransactionRepository.java @@ -5,10 +5,20 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Service; +import java.util.List; import java.util.Optional; @Service public interface TransactionRepository extends JpaRepository { @Query("SELECT t FROM TransactionEntity t WHERE t.sessionId = ?1") Optional findOneBySessionID(String sessionId); + + @Query("SELECT t FROM TransactionEntity t WHERE t.user = ?1") + List findAllByUserId(UserEntity id); + + @Query("SELECT t FROM TransactionEntity t WHERE t.user = ?1 ORDER BY t.createdAt DESC LIMIT ?2 OFFSET ?3") + List findByUserIdWithLimit(UserEntity userEntity, Integer limit, Integer offset); + + @Query("SELECT COUNT(t) > ?2 + ?3 FROM TransactionEntity t WHERE t.user = ?1") + Boolean hasMore(UserEntity userEntity, Integer limit, Integer offset); } diff --git a/backend/src/main/java/de/szut/casino/deposit/TransactionService.java b/backend/src/main/java/de/szut/casino/deposit/TransactionService.java index b5ddfd2..2cfc19e 100644 --- a/backend/src/main/java/de/szut/casino/deposit/TransactionService.java +++ b/backend/src/main/java/de/szut/casino/deposit/TransactionService.java @@ -7,7 +7,6 @@ import de.szut.casino.user.UserEntity; import de.szut.casino.user.UserRepository; import org.springframework.stereotype.Service; -import java.util.Objects; import java.util.Optional; @Service diff --git a/backend/src/main/java/de/szut/casino/deposit/WebhookController.java b/backend/src/main/java/de/szut/casino/deposit/WebhookController.java index be90a48..dba9041 100644 --- a/backend/src/main/java/de/szut/casino/deposit/WebhookController.java +++ b/backend/src/main/java/de/szut/casino/deposit/WebhookController.java @@ -1,26 +1,21 @@ package de.szut.casino.deposit; -import com.fasterxml.jackson.core.JsonProcessingException; - import com.stripe.Stripe; -import com.stripe.exception.SignatureVerificationException; import com.stripe.exception.StripeException; -import com.stripe.model.*; +import com.stripe.model.Event; import com.stripe.model.checkout.Session; import com.stripe.net.Webhook; -import com.stripe.param.checkout.SessionRetrieveParams; -import de.szut.casino.user.UserEntity; -import de.szut.casino.user.UserRepository; import jakarta.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +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.RestController; -import java.math.BigDecimal; import java.util.Objects; -import java.util.Optional; @RestController public class WebhookController { diff --git a/backend/src/main/java/de/szut/casino/lootboxes/CreateLootBoxDto.java b/backend/src/main/java/de/szut/casino/lootboxes/CreateLootBoxDto.java new file mode 100644 index 0000000..10e1b4e --- /dev/null +++ b/backend/src/main/java/de/szut/casino/lootboxes/CreateLootBoxDto.java @@ -0,0 +1,30 @@ +package de.szut.casino.lootboxes; + +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class CreateLootBoxDto { + @NotEmpty(message = "Loot box name cannot be empty") + @Size(min = 3, max = 50, message = "Loot box name must be between 3 and 50 characters") + private String name; + + @NotNull(message = "Price cannot be null") + @DecimalMin(value = "0.01", message = "Price must be greater than 0") + private BigDecimal price; + + private List rewards = new ArrayList<>(); +} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/CreateRewardDto.java b/backend/src/main/java/de/szut/casino/lootboxes/CreateRewardDto.java new file mode 100644 index 0000000..0dbe819 --- /dev/null +++ b/backend/src/main/java/de/szut/casino/lootboxes/CreateRewardDto.java @@ -0,0 +1,26 @@ +package de.szut.casino.lootboxes; + +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.math.BigDecimal; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class CreateRewardDto { + @NotNull(message = "Reward value cannot be null") + @DecimalMin(value = "0.00", message = "Reward value must be positive") + private BigDecimal value; + + @NotNull(message = "Probability cannot be null") + @DecimalMin(value = "0.0", message = "Probability must be at least 0.0") + @DecimalMax(value = "1.0", message = "Probability must be at most 1.0") + private BigDecimal probability; +} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java index 51a17e1..2d4309d 100644 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java @@ -3,13 +3,11 @@ package de.szut.casino.lootboxes; import de.szut.casino.user.UserEntity; import de.szut.casino.user.UserRepository; import de.szut.casino.user.UserService; +import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; @RestController public class LootBoxController { @@ -55,4 +53,37 @@ public class LootBoxController { return ResponseEntity.ok(reward); } + + @PostMapping("/lootboxes") + public ResponseEntity createLootbox(@RequestBody @Valid CreateLootBoxDto createLootBoxDto) { + List rewardEntities = new ArrayList<>(); + + for (CreateRewardDto createRewardDto : createLootBoxDto.getRewards()) { + rewardEntities.add(new RewardEntity(createRewardDto.getValue(), createRewardDto.getProbability())); + } + + LootBoxEntity lootBoxEntity = new LootBoxEntity( + createLootBoxDto.getName(), + createLootBoxDto.getPrice(), + rewardEntities + ); + + this.lootBoxRepository.save(lootBoxEntity); + + return ResponseEntity.ok(lootBoxEntity); + } + + @DeleteMapping("/lootboxes/{id}") + public ResponseEntity deleteLootbox(@PathVariable Long id) { + Optional optionalLootBox = lootBoxRepository.findById(id); + if (optionalLootBox.isEmpty()) { + return ResponseEntity.notFound().build(); + } + + LootBoxEntity lootBox = optionalLootBox.get(); + lootBoxRepository.delete(lootBox); + + return ResponseEntity.ok(Collections.singletonMap("message", "successfully deleted lootbox")); + } + } diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java index 49eb532..8a3e9a9 100644 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java @@ -1,15 +1,9 @@ package de.szut.casino.lootboxes; -import com.fasterxml.jackson.annotation.JsonBackReference; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonManagedReference; -import de.szut.casino.blackjack.CardEntity; import jakarta.persistence.*; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.hibernate.annotations.SQLRestriction; import java.math.BigDecimal; import java.util.ArrayList; @@ -18,9 +12,15 @@ import java.util.List; @Entity @Getter @Setter -@AllArgsConstructor @NoArgsConstructor public class LootBoxEntity { + + public LootBoxEntity(String name, BigDecimal price, List rewards) { + this.name = name; + this.price = price; + this.rewards = rewards; + } + @Id @GeneratedValue private Long id; diff --git a/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java b/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java index ce0c155..1abd2df 100644 --- a/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java +++ b/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java @@ -1,9 +1,9 @@ package de.szut.casino.lootboxes; import com.fasterxml.jackson.annotation.JsonBackReference; -import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.*; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import java.math.BigDecimal; @@ -13,7 +13,14 @@ import java.util.List; @Getter @Setter @Entity +@NoArgsConstructor public class RewardEntity { + + public RewardEntity(BigDecimal value, BigDecimal probability) { + this.value = value; + this.probability = probability; + } + @Id @GeneratedValue private Long id; diff --git a/backend/src/main/java/de/szut/casino/user/UserController.java b/backend/src/main/java/de/szut/casino/user/UserController.java index 5daf7ef..c2ad0d0 100644 --- a/backend/src/main/java/de/szut/casino/user/UserController.java +++ b/backend/src/main/java/de/szut/casino/user/UserController.java @@ -1,19 +1,14 @@ package de.szut.casino.user; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -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.RestController; - import de.szut.casino.user.dto.CreateUserDto; import de.szut.casino.user.dto.GetUserDto; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; @Slf4j @RestController diff --git a/backend/src/main/java/de/szut/casino/user/transaction/GetTransactionService.java b/backend/src/main/java/de/szut/casino/user/transaction/GetTransactionService.java new file mode 100644 index 0000000..831c438 --- /dev/null +++ b/backend/src/main/java/de/szut/casino/user/transaction/GetTransactionService.java @@ -0,0 +1,45 @@ +package de.szut.casino.user.transaction; + +import de.szut.casino.deposit.TransactionEntity; +import de.szut.casino.deposit.TransactionRepository; +import de.szut.casino.user.UserEntity; +import de.szut.casino.user.UserService; +import de.szut.casino.user.transaction.dto.GetTransactionDto; +import de.szut.casino.user.transaction.dto.UserTransactionsDto; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class GetTransactionService { + + @Autowired + private UserService userService; + + @Autowired + private TransactionRepository transactionRepository; + + public UserTransactionsDto getUserTransactionsDto(String authToken, Integer limit, Integer offset) { + Optional user = this.userService.getCurrentUser(authToken); + if (user.isPresent()) { + List transactionEntities = this.transactionRepository.findByUserIdWithLimit(user.get(), limit, offset); + Boolean hasMore = this.transactionRepository.hasMore(user.get(), limit, offset); + + return new UserTransactionsDto(mapTransactionsToDtos(transactionEntities), hasMore); + } + + return new UserTransactionsDto(List.of(), false); + } + + public List mapTransactionsToDtos(List transactions) { + return transactions.stream() + .map(transaction -> new GetTransactionDto( + transaction.getAmount(), + transaction.getStatus(), + transaction.getCreatedAt()) + ).toList(); + } +} + diff --git a/backend/src/main/java/de/szut/casino/user/transaction/TransactionController.java b/backend/src/main/java/de/szut/casino/user/transaction/TransactionController.java new file mode 100644 index 0000000..10061fa --- /dev/null +++ b/backend/src/main/java/de/szut/casino/user/transaction/TransactionController.java @@ -0,0 +1,28 @@ +package de.szut.casino.user.transaction; + +import de.szut.casino.user.transaction.dto.UserTransactionsDto; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TransactionController { + + @Autowired + private GetTransactionService transactionService; + + @GetMapping("/user/transactions") + public ResponseEntity getUserTransactions( + @RequestHeader("Authorization") String authToken, + @RequestParam(value = "limit", required = false) Integer limit, + @RequestParam(value = "offset", required = false) Integer offset + ) { + UserTransactionsDto transactionEntities = this.transactionService.getUserTransactionsDto(authToken, limit, offset); + + return ResponseEntity.ok(transactionEntities); + } +} + diff --git a/backend/src/main/java/de/szut/casino/user/transaction/dto/GetTransactionDto.java b/backend/src/main/java/de/szut/casino/user/transaction/dto/GetTransactionDto.java new file mode 100644 index 0000000..f37fbf4 --- /dev/null +++ b/backend/src/main/java/de/szut/casino/user/transaction/dto/GetTransactionDto.java @@ -0,0 +1,16 @@ +package de.szut.casino.user.transaction.dto; + +import de.szut.casino.deposit.TransactionStatus; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@AllArgsConstructor +@NoArgsConstructor +public class GetTransactionDto { + public double amount = 0; + public TransactionStatus status = TransactionStatus.PROCESSING; + public Date createdAt = new Date(); +} + diff --git a/backend/src/main/java/de/szut/casino/user/transaction/dto/UserTransactionsDto.java b/backend/src/main/java/de/szut/casino/user/transaction/dto/UserTransactionsDto.java new file mode 100644 index 0000000..54e116b --- /dev/null +++ b/backend/src/main/java/de/szut/casino/user/transaction/dto/UserTransactionsDto.java @@ -0,0 +1,12 @@ +package de.szut.casino.user.transaction.dto; + +import lombok.AllArgsConstructor; + +import java.util.List; + +@AllArgsConstructor +public class UserTransactionsDto { + public List transactions; + public Boolean hasMore; +} + diff --git a/frontend/public/blackjack.webp b/frontend/public/blackjack.webp index a791c14..e47c246 100644 Binary files a/frontend/public/blackjack.webp and b/frontend/public/blackjack.webp differ diff --git a/frontend/public/liars-dice.webp b/frontend/public/liars-dice.webp index df1fd1c..0e1a05c 100644 Binary files a/frontend/public/liars-dice.webp and b/frontend/public/liars-dice.webp differ diff --git a/frontend/public/lootbox.webp b/frontend/public/lootbox.webp index 710deed..0750897 100644 Binary files a/frontend/public/lootbox.webp and b/frontend/public/lootbox.webp differ diff --git a/frontend/public/plinko.webp b/frontend/public/plinko.webp index c11370b..ada7958 100644 Binary files a/frontend/public/plinko.webp and b/frontend/public/plinko.webp differ diff --git a/frontend/public/poker.webp b/frontend/public/poker.webp index 9c60024..329f4da 100644 Binary files a/frontend/public/poker.webp and b/frontend/public/poker.webp differ diff --git a/frontend/public/slots.webp b/frontend/public/slots.webp index 5cf639a..12a8d8e 100644 Binary files a/frontend/public/slots.webp and b/frontend/public/slots.webp differ diff --git a/frontend/src/app/app.config.ts b/frontend/src/app/app.config.ts index 671a717..d6ac35a 100644 --- a/frontend/src/app/app.config.ts +++ b/frontend/src/app/app.config.ts @@ -6,7 +6,7 @@ import { routes } from './app.routes'; import { provideHttpClient, withInterceptors } from '@angular/common/http'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; import { OAuthStorage, provideOAuthClient } from 'angular-oauth2-oidc'; -import { httpInterceptor } from './shared/interceptor/http.interceptor'; +import { httpInterceptor } from '@shared/interceptor/http.interceptor'; export const appConfig: ApplicationConfig = { providers: [ diff --git a/frontend/src/app/feature/deposit/deposit.component.ts b/frontend/src/app/feature/deposit/deposit.component.ts index 834a2e4..8768bbe 100644 --- a/frontend/src/app/feature/deposit/deposit.component.ts +++ b/frontend/src/app/feature/deposit/deposit.component.ts @@ -1,18 +1,18 @@ import { + AfterViewInit, ChangeDetectionStrategy, + ChangeDetectorRef, Component, ElementRef, EventEmitter, inject, Input, + OnChanges, + OnDestroy, OnInit, Output, - ViewChild, - AfterViewInit, - OnDestroy, - OnChanges, SimpleChanges, - ChangeDetectorRef, + ViewChild, } from '@angular/core'; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { loadStripe, Stripe } from '@stripe/stripe-js'; diff --git a/frontend/src/app/feature/game/blackjack/blackjack.component.ts b/frontend/src/app/feature/game/blackjack/blackjack.component.ts index 370b535..3e58e25 100644 --- a/frontend/src/app/feature/game/blackjack/blackjack.component.ts +++ b/frontend/src/app/feature/game/blackjack/blackjack.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, inject, signal, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core'; import { CommonModule } from '@angular/common'; import { Router } from '@angular/router'; import { PlayingCardComponent } from './components/playing-card/playing-card.component'; @@ -6,7 +6,7 @@ import { DealerHandComponent } from './components/dealer-hand/dealer-hand.compon import { PlayerHandComponent } from './components/player-hand/player-hand.component'; import { GameControlsComponent } from './components/game-controls/game-controls.component'; import { GameInfoComponent } from './components/game-info/game-info.component'; -import { Card, BlackjackGame } from '@blackjack/models/blackjack.model'; +import { BlackjackGame, Card } from '@blackjack/models/blackjack.model'; import { BlackjackService } from '@blackjack/services/blackjack.service'; import { HttpErrorResponse } from '@angular/common/http'; import { GameResultComponent } from '@blackjack/components/game-result/game-result.component'; diff --git a/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts b/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts index 25ea0e4..7d78871 100644 --- a/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts +++ b/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts @@ -1,12 +1,12 @@ import { + AfterViewInit, ChangeDetectionStrategy, Component, + ElementRef, Input, OnChanges, SimpleChanges, - ElementRef, ViewChild, - AfterViewInit, } from '@angular/core'; import { CommonModule, CurrencyPipe } from '@angular/common'; import { CountUp } from 'countup.js'; diff --git a/frontend/src/app/feature/game/blackjack/components/game-info/game-info.component.ts b/frontend/src/app/feature/game/blackjack/components/game-info/game-info.component.ts index ecd1fad..644fb22 100644 --- a/frontend/src/app/feature/game/blackjack/components/game-info/game-info.component.ts +++ b/frontend/src/app/feature/game/blackjack/components/game-info/game-info.component.ts @@ -5,8 +5,8 @@ import { Input, OnChanges, Output, - SimpleChanges, signal, + SimpleChanges, } from '@angular/core'; import { CommonModule, CurrencyPipe } from '@angular/common'; import { FormGroup, ReactiveFormsModule } from '@angular/forms'; diff --git a/frontend/src/app/feature/game/blackjack/components/game-result/game-result.component.ts b/frontend/src/app/feature/game/blackjack/components/game-result/game-result.component.ts index b841ee8..74d02e4 100644 --- a/frontend/src/app/feature/game/blackjack/components/game-result/game-result.component.ts +++ b/frontend/src/app/feature/game/blackjack/components/game-result/game-result.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, Input, Output, EventEmitter } from '@angular/core'; +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; import { CommonModule, CurrencyPipe } from '@angular/common'; import { animate, style, transition, trigger } from '@angular/animations'; import { GameState } from '../../enum/gameState'; diff --git a/frontend/src/app/feature/game/blackjack/components/playing-card/playing-card.component.ts b/frontend/src/app/feature/game/blackjack/components/playing-card/playing-card.component.ts index 8ae8824..0fbbb5a 100644 --- a/frontend/src/app/feature/game/blackjack/components/playing-card/playing-card.component.ts +++ b/frontend/src/app/feature/game/blackjack/components/playing-card/playing-card.component.ts @@ -1,9 +1,9 @@ import { + AfterViewInit, ChangeDetectionStrategy, Component, - Input, - AfterViewInit, ElementRef, + Input, OnChanges, SimpleChanges, } from '@angular/core'; diff --git a/frontend/src/app/feature/game/blackjack/services/blackjack.service.ts b/frontend/src/app/feature/game/blackjack/services/blackjack.service.ts index ca3f218..5e43dc7 100644 --- a/frontend/src/app/feature/game/blackjack/services/blackjack.service.ts +++ b/frontend/src/app/feature/game/blackjack/services/blackjack.service.ts @@ -1,6 +1,6 @@ -import { Injectable, inject } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { Observable, catchError } from 'rxjs'; +import { catchError, Observable } from 'rxjs'; import { BlackjackGame } from '@blackjack/models/blackjack.model'; @Injectable({ diff --git a/frontend/src/app/feature/home/home.component.html b/frontend/src/app/feature/home/home.component.html index b1bfd9b..dc8ee59 100644 --- a/frontend/src/app/feature/home/home.component.html +++ b/frontend/src/app/feature/home/home.component.html @@ -81,12 +81,16 @@ [isOpen]="isDepositModalOpen" (closeModalEmitter)="closeDepositModal()" > - - + @@ -100,11 +104,13 @@
-

{{ transaction.type }}

-

{{ transaction.date }}

+

{{ transaction.status }}

+

+ {{ transaction.createdAt | date: 'd.m.Y H:m' }} +

{{ transaction.amount | currency: 'EUR' }} diff --git a/frontend/src/app/feature/home/home.component.ts b/frontend/src/app/feature/home/home.component.ts index eb12454..be84450 100644 --- a/frontend/src/app/feature/home/home.component.ts +++ b/frontend/src/app/feature/home/home.component.ts @@ -1,22 +1,36 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { CurrencyPipe, NgFor } from '@angular/common'; +import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core'; +import { AsyncPipe, CurrencyPipe, DatePipe, NgFor } from '@angular/common'; import { DepositComponent } from '../deposit/deposit.component'; import { ActivatedRoute, Router } from '@angular/router'; import { ConfirmationComponent } from '@shared/components/confirmation/confirmation.component'; -import { Transaction } from 'app/model/Transaction'; import { NavbarComponent } from '@shared/components/navbar/navbar.component'; import { Game } from 'app/model/Game'; +import { Observable } from 'rxjs'; +import { TransactionService } from '@service/transaction.service'; +import format from 'ajv/dist/vocabularies/format'; +import { TransactionHistoryComponent } from '../transaction-history/transaction-history.component'; +import { TransactionData } from '../../model/TransactionData'; @Component({ selector: 'app-homepage', standalone: true, - imports: [NavbarComponent, CurrencyPipe, NgFor, DepositComponent, ConfirmationComponent], + imports: [ + NavbarComponent, + CurrencyPipe, + NgFor, + DepositComponent, + ConfirmationComponent, + AsyncPipe, + DatePipe, + TransactionHistoryComponent, + ], templateUrl: './home.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) export default class HomeComponent implements OnInit { isDepositModalOpen = false; isDepositSuccessful = false; + isTransactionModalOpen = false; constructor( public route: ActivatedRoute, @@ -74,11 +88,13 @@ export default class HomeComponent implements OnInit { allGames: Game[] = [...this.featuredGames]; - recentTransactions: Transaction[] = []; + recentTransactionData: Observable = + inject(TransactionService).getUsersTransactions(5); openDepositModal() { this.isDepositModalOpen = true; } + closeDepositModal() { this.isDepositModalOpen = false; } @@ -86,11 +102,22 @@ export default class HomeComponent implements OnInit { openDepositConfirmationModal() { this.isDepositSuccessful = true; } + + openTransactionModal() { + this.isTransactionModalOpen = true; + } + closeDepositConfirmationModal() { this.isDepositSuccessful = false; } + closeTransactionModal() { + this.isTransactionModalOpen = false; + } + navigateToGame(route: string) { this.router.navigate([route]); } + + protected readonly format = format; } diff --git a/frontend/src/app/feature/landing/landing.component.ts b/frontend/src/app/feature/landing/landing.component.ts index 62fa25e..915547f 100644 --- a/frontend/src/app/feature/landing/landing.component.ts +++ b/frontend/src/app/feature/landing/landing.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, OnInit, OnDestroy } from '@angular/core'; +import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core'; import { NgFor } from '@angular/common'; import { NavbarComponent } from '@shared/components/navbar/navbar.component'; diff --git a/frontend/src/app/feature/transaction-history/transaction-history.component.css b/frontend/src/app/feature/transaction-history/transaction-history.component.css new file mode 100644 index 0000000..c68e294 --- /dev/null +++ b/frontend/src/app/feature/transaction-history/transaction-history.component.css @@ -0,0 +1,8 @@ +button[disabled] { + cursor: not-allowed; + background-color: #077b58; + box-shadow: none; +} +button[disabled]:hover { + background-color: #077b58; +} diff --git a/frontend/src/app/feature/transaction-history/transaction-history.component.html b/frontend/src/app/feature/transaction-history/transaction-history.component.html new file mode 100644 index 0000000..974964c --- /dev/null +++ b/frontend/src/app/feature/transaction-history/transaction-history.component.html @@ -0,0 +1,60 @@ + diff --git a/frontend/src/app/feature/transaction-history/transaction-history.component.ts b/frontend/src/app/feature/transaction-history/transaction-history.component.ts new file mode 100644 index 0000000..0bef06d --- /dev/null +++ b/frontend/src/app/feature/transaction-history/transaction-history.component.ts @@ -0,0 +1,54 @@ +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + inject, + Input, + Output, +} from '@angular/core'; +import { TransactionService } from '@service/transaction.service'; +import { Observable } from 'rxjs'; +import { AsyncPipe, CurrencyPipe, DatePipe, NgForOf, NgIf } from '@angular/common'; +import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component'; +import { TransactionData } from '../../model/TransactionData'; + +const PER_PAGE = 5; + +@Component({ + standalone: true, + selector: 'app-transaction-history', + imports: [NgForOf, AsyncPipe, CurrencyPipe, DatePipe, AnimatedNumberComponent, NgIf], + templateUrl: './transaction-history.component.html', + styleUrl: './transaction-history.component.css', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TransactionHistoryComponent { + @Input() + isOpen = false; + @Output() + closeEventEmitter = new EventEmitter(); + + protected offset = 0; + + private transactionService: TransactionService = inject(TransactionService); + transactionData$: Observable = this.loadTransactions(); + + closeDialog() { + this.isOpen = false; + this.closeEventEmitter.emit(); + } + + forward() { + this.offset++; + this.transactionData$ = this.loadTransactions(); + } + + back() { + this.offset--; + this.transactionData$ = this.loadTransactions(); + } + + loadTransactions() { + return this.transactionService.getUsersTransactions(PER_PAGE, this.offset * PER_PAGE); + } +} diff --git a/frontend/src/app/model/Transaction.ts b/frontend/src/app/model/Transaction.ts index 21277b4..d3bccf1 100644 --- a/frontend/src/app/model/Transaction.ts +++ b/frontend/src/app/model/Transaction.ts @@ -1,6 +1,5 @@ export interface Transaction { - id: string; - type: string; + status: string; amount: number; - date: string; + createdAt: string; } diff --git a/frontend/src/app/model/TransactionData.ts b/frontend/src/app/model/TransactionData.ts new file mode 100644 index 0000000..2da39bb --- /dev/null +++ b/frontend/src/app/model/TransactionData.ts @@ -0,0 +1,6 @@ +import { Transaction } from './Transaction'; + +export interface TransactionData { + transactions: Transaction[]; + hasMore: boolean; +} diff --git a/frontend/src/app/service/transaction.service.ts b/frontend/src/app/service/transaction.service.ts new file mode 100644 index 0000000..55aba0f --- /dev/null +++ b/frontend/src/app/service/transaction.service.ts @@ -0,0 +1,24 @@ +import { inject, Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { TransactionData } from '../model/TransactionData'; + +@Injectable({ + providedIn: 'root', +}) +export class TransactionService { + private http: HttpClient = inject(HttpClient); + + public getUsersTransactions(limit: number | null = null, offset: number | null = null) { + const baseUrl = new URL(`${window.location.origin}/backend/user/transactions`); + + if (limit !== null) { + baseUrl.searchParams.append('limit', limit.toString()); + } + + if (offset !== null) { + baseUrl.searchParams.append('offset', offset.toString()); + } + + return this.http.get(`${baseUrl}`); + } +} diff --git a/frontend/src/app/shared/components/confirmation/confirmation.component.ts b/frontend/src/app/shared/components/confirmation/confirmation.component.ts index 8bc884a..9ce91ba 100644 --- a/frontend/src/app/shared/components/confirmation/confirmation.component.ts +++ b/frontend/src/app/shared/components/confirmation/confirmation.component.ts @@ -1,12 +1,12 @@ import { + AfterViewInit, Component, ElementRef, EventEmitter, Input, + OnDestroy, Output, ViewChild, - AfterViewInit, - OnDestroy, } from '@angular/core'; import { ModalAnimationService } from '@shared/services/modal-animation.service'; import gsap from 'gsap'; diff --git a/frontend/src/app/shared/components/footer/footer.component.ts b/frontend/src/app/shared/components/footer/footer.component.ts index 1c3b309..2cb56e1 100644 --- a/frontend/src/app/shared/components/footer/footer.component.ts +++ b/frontend/src/app/shared/components/footer/footer.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; -import { faMoneyBillTransfer, faCreditCard, faWallet } from '@fortawesome/free-solid-svg-icons'; -import { faPaypal, faGooglePay, faApplePay } from '@fortawesome/free-brands-svg-icons'; +import { faCreditCard, faMoneyBillTransfer, faWallet } from '@fortawesome/free-solid-svg-icons'; +import { faApplePay, faGooglePay, faPaypal } from '@fortawesome/free-brands-svg-icons'; @Component({ selector: 'app-footer', diff --git a/frontend/src/app/shared/components/navbar/navbar.component.ts b/frontend/src/app/shared/components/navbar/navbar.component.ts index 6bbeeb9..6cc6f56 100644 --- a/frontend/src/app/shared/components/navbar/navbar.component.ts +++ b/frontend/src/app/shared/components/navbar/navbar.component.ts @@ -2,8 +2,8 @@ import { ChangeDetectionStrategy, Component, inject, - OnInit, OnDestroy, + OnInit, signal, } from '@angular/core'; import { RouterModule } from '@angular/router';