Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add groseries #6

Merged
merged 8 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
Empty file added .idea/sonarlint.xml
Empty file.
15 changes: 15 additions & 0 deletions backend/src/main/java/org/example/backend/IdService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.example.backend;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.UUID;

@Service
@RequiredArgsConstructor

public class IdService {

public String randomId() {
return UUID.randomUUID().toString();
}
}
9 changes: 9 additions & 0 deletions backend/src/main/java/org/example/backend/NewProduct.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.example.backend;

import lombok.With;

@With
public record NewProduct(
String name,
int amount
){}
11 changes: 6 additions & 5 deletions backend/src/main/java/org/example/backend/ProductController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/products")
Expand All @@ -19,6 +15,11 @@ public List<Product> getAllGroceries() {
return productService.findAllGroceries();
}

@PostMapping
public Product saveProduct(@RequestBody NewProduct newProduct) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe rename saveProduct - method name to addProduct

return productService.saveProduct(newProduct);
}

@DeleteMapping("{id}")
void delete(@PathVariable String id) {
productService.deletebyid(id);
Expand Down
5 changes: 5 additions & 0 deletions backend/src/main/java/org/example/backend/ProductService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
@Service
public class ProductService {
private final ProductRepository productRepository;
private final IdService idService;

public void deletebyid(String id) {
productRepository.deleteById(id);
Expand All @@ -21,6 +22,10 @@ public List<Product> findAllGroceries(){
return productRepository.findAll();
}

public Product saveProduct(NewProduct newProduct){
Product product = new Product(idService.randomId(), newProduct.name(), newProduct.amount());
return productRepository.save(product);
}

public Product findGroceriesById(String id) {
return productRepository.findById(id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;


@SpringBootTest
Expand All @@ -21,8 +22,9 @@ class ProductControllerTest {

@Autowired
ProductRepository productRepository;
@DirtiesContext

@Test
@DirtiesContext
void getAllGroceries() throws Exception {
//GIVEN
//WHEN
Expand All @@ -42,13 +44,29 @@ void deletebyid() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.delete("/api/products/2"))
//Then
.andExpect(status().isOk());
}
@Test
@DirtiesContext
void addNewProduct() throws Exception {
//GIVEN





//WHEN
mockMvc.perform(post("/api/products")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"name": "Milch",
"amount": 1
}
"""))
//THEN
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").exists())
.andExpect(jsonPath("$.name").value("Milch"))
.andExpect(jsonPath("$.amount").value(1));
}


@Test
@DirtiesContext
void getGroceryProductById() throws Exception {
Expand Down
22 changes: 20 additions & 2 deletions backend/src/test/java/org/example/backend/ProductServiceTest.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package org.example.backend;

import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class ProductServiceTest {

IdService idService = mock(IdService.class);
ProductRepository productRepository = mock(ProductRepository.class);
ProductService productService = new ProductService(productRepository);
ProductService productService = new ProductService(productRepository, idService);


@Test
void findAllGroceries() {
Expand All @@ -28,6 +30,22 @@ void findAllGroceries() {
assertEquals(products, actual);
}
@Test
void addProdukt() {
// GIVEN
NewProduct newProduct = new NewProduct("Orangen", 5);
Product saveProduct = new Product(idService.randomId(), newProduct.name(), newProduct.amount());
when(productRepository.save(saveProduct)).thenReturn(saveProduct);
when(idService.randomId()).thenReturn(saveProduct.id());

// WHEN
Product actual = productService.saveProduct(newProduct);

// THEN
Product expected = new Product(idService.randomId(), newProduct.name(), newProduct.amount());
verify(productRepository).save(saveProduct);
assertEquals(expected, actual);
}
@Test
void deleteProduct_Test() {
doNothing().when(productRepository).deleteById("2");
productService.deletebyid("2");
Expand Down
45 changes: 45 additions & 0 deletions frontend/dist/assets/index-DO30CrK6.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions frontend/dist/assets/index-DiwrgTda.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions frontend/dist/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<script type="module" crossorigin src="/assets/index-DO30CrK6.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DiwrgTda.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
1 change: 1 addition & 0 deletions frontend/dist/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 43 additions & 1 deletion frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"dependencies": {
"axios": "^1.7.4",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"react-router-dom": "^6.26.1"
},
"devDependencies": {
"@eslint/js": "^9.8.0",
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ body{
text-align: center;
}
.search-card{
background-color: darkgray;
background-color: darkgray;
padding: 1.2rem;
}

Expand Down Expand Up @@ -99,5 +99,4 @@ background-color: darkgray;
padding: 1rem;
background-color: #f8f8f8;
border-radius: 10px;
}

}
3 changes: 1 addition & 2 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,4 @@ export default function App() {

</div>
)
}

}
51 changes: 51 additions & 0 deletions frontend/src/components/AddProduct.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.add-product {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
background-color: #f8f8f8;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.add-product h3 {
font-size: 1.8rem;
color: #333;
text-align: center;
}

.name-input {
width: 100%;
padding: 0.5rem;
border: 2px solid #cccccc;
border-radius: 5px;
font-size: 1rem;
}

.amount-input {
width: 50%;
padding: 0.5rem;
border: 2px solid #cccccc;
border-radius: 5px;
font-size: 1rem;
}

button {
background-color: #4CAF50;
color: white;
padding: 0.7rem 1.5rem;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
transition: background-color 0.3s ease, transform 0.1s ease;
}

button:hover {
background-color: #45a049;
}

button:active {
transform: scale(0.95); /* Эффект нажатия */
background-color: #3e8e41; /* Темнее цвет для эффекта нажатия */
}
46 changes: 46 additions & 0 deletions frontend/src/components/AddProduсt.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useState, ChangeEvent, FormEvent } from 'react'
import axios from 'axios'
import { Product } from "../models/product.tsx"


type AddProductProps = {
productAdd: () => void;
};

export default function AddProduct({ productAdd }: AddProductProps) {
const [name, setName] = useState("");
const [amount, setAmount] = useState("")

const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();

const newProduct = {
name: name.trim(),
amount: parseInt(amount)
}

axios.post<Product>("/api/products", newProduct)
.then(() => {
setName("")
setAmount("")
productAdd()
})
.catch(error => {
console.error("Es ist ein Fehler aufgetreten!", error)
})
}

return (
<div className="add-product">
<h3>Neues Produkt hinzufügen</h3>
<form onSubmit={handleSubmit}>
<input type="text" value={name} onChange={(event: ChangeEvent<HTMLInputElement>) => setName(event.target.value)}
placeholder="Product name" />
<input type="number" value={amount}
onChange={(event: ChangeEvent<HTMLInputElement>) => setAmount(event.target.value)}
placeholder="Menge"/>
<button type="submit">Produkt hinzufügen </button>
</form>
</div>
)
}
Loading
Loading