Четвертая лабораторная работа. React.
This commit is contained in:
parent
93166df773
commit
19d01dab54
Binary file not shown.
@ -0,0 +1,44 @@
|
||||
package com.example.lab.DataBase.Controllers;
|
||||
|
||||
|
||||
import com.example.lab.DataBase.DTOs.CartDTO;
|
||||
import com.example.lab.DataBase.DTOs.CustomerDTO;
|
||||
import com.example.lab.DataBase.Services.CartService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/cart")
|
||||
|
||||
public class CartController {
|
||||
private final CartService cartService;
|
||||
|
||||
public CartController(CartService cartService){
|
||||
this.cartService = cartService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public CartDTO getCart(@PathVariable Long id){
|
||||
return new CartDTO(cartService.getCart(id));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<CartDTO> getCarts(){
|
||||
return cartService.getAllCarts().stream()
|
||||
.map(CartDTO::new)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@PutMapping("/{add}")
|
||||
public void addProduct( @RequestParam("productId") Long productId,
|
||||
@RequestParam("cartId") Long cartId){
|
||||
cartService.addProduct(cartId, productId);
|
||||
}
|
||||
|
||||
@PutMapping("/{delete}")
|
||||
public void deleteProduct( @RequestParam("productId") Long productId,
|
||||
@RequestParam("cartId") Long cartId){
|
||||
cartService.deleteProduct(cartId, productId);
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.example.lab.DataBase.Controllers;
|
||||
|
||||
import com.example.lab.DataBase.DTOs.CountProductDTO;
|
||||
import com.example.lab.DataBase.Models.Cart;
|
||||
import com.example.lab.DataBase.Models.Product;
|
||||
import com.example.lab.DataBase.Services.CartService;
|
||||
import com.example.lab.DataBase.Services.CountProductService;
|
||||
import com.example.lab.DataBase.Services.ProductService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/countProduct")
|
||||
public class CountProdController {
|
||||
private final CountProductService countProductService;
|
||||
private final CartService cartService;
|
||||
private final ProductService productService;
|
||||
|
||||
public CountProdController(CountProductService countProductService, CartService cartService, ProductService productService){
|
||||
this.countProductService = countProductService;
|
||||
this.cartService = cartService;
|
||||
this.productService = productService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public List<CountProductDTO> getProductsForCart(@PathVariable Long id){
|
||||
return countProductService.getProductsForCart(id).stream().map(CountProductDTO::new).toList();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public CountProductDTO deliverProduct(@RequestParam("cartId") Long cartId,
|
||||
@RequestParam("productId") Long productId){
|
||||
if (countProductService.getCountProduct(productId, cartId) != null){
|
||||
return new CountProductDTO(countProductService.incrementProduct(productId, cartId));
|
||||
}
|
||||
else {
|
||||
Product product = productService.getProduct(productId);
|
||||
Cart cart = cartService.getCart(cartId);
|
||||
return new CountProductDTO(countProductService.addCountProduct(product, cart));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public CountProductDTO incrementProduct(@PathVariable Long id){
|
||||
var countProd = countProductService.getCountProductById(id);
|
||||
if (countProd != null){
|
||||
return new CountProductDTO(countProductService.incrementProductById(id));
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public CountProductDTO reduceProduct(@RequestParam("id") Long id){
|
||||
var countProd = countProductService.getCountProductById(id);
|
||||
if (countProd != null){
|
||||
if (countProd.getAmount() == 1){
|
||||
countProductService.deleteCountProductById(id);
|
||||
return null;
|
||||
}
|
||||
else return new CountProductDTO(countProductService.decrementProductById(id));
|
||||
}
|
||||
else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.example.lab.DataBase.Controllers;
|
||||
|
||||
import com.example.lab.DataBase.Models.Customer;
|
||||
import com.example.lab.DataBase.DTOs.CustomerDTO;
|
||||
import com.example.lab.DataBase.Services.CustomerService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/customer")
|
||||
public class CustomerController {
|
||||
private final CustomerService customerService;
|
||||
|
||||
public CustomerController(CustomerService customerService){
|
||||
this.customerService = customerService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public CustomerDTO getCustomer(@PathVariable Long id){
|
||||
return new CustomerDTO(customerService.getCustomer(id));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<CustomerDTO> getCustomers(){
|
||||
return customerService.getAllCustomers().stream()
|
||||
.map(CustomerDTO::new)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public CustomerDTO createCustomer(@RequestParam("customerLastName") String customerLastName,
|
||||
@RequestParam("customerFirstName") String customerFirstName,
|
||||
@RequestParam("customerAddress") String customerAddress){
|
||||
final Customer customer = customerService.addCustomer(customerLastName, customerFirstName, customerAddress);
|
||||
return new CustomerDTO(customer);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public CustomerDTO updateCustomer(@RequestParam("customerLastName") String customerLastName,
|
||||
@RequestParam("customerFirstName") String customerFirstName,
|
||||
@RequestParam("customerAddress") String customerAddress,
|
||||
@PathVariable Long id){
|
||||
return new CustomerDTO(customerService.updateCustomer(id, customerLastName, customerFirstName, customerAddress));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public CustomerDTO deleteCustomer(@PathVariable Long id){
|
||||
return new CustomerDTO(customerService.deleteCustomer(id));
|
||||
}
|
||||
|
||||
@DeleteMapping()
|
||||
public void deleteAllCustomers(){
|
||||
customerService.deleteAllCustomers();
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.example.lab.DataBase.Controllers;
|
||||
|
||||
import com.example.lab.DataBase.DTOs.ProductCategoryDTO;
|
||||
import com.example.lab.DataBase.Models.ProductCategory;
|
||||
import com.example.lab.DataBase.Services.ProductCategoryService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/productCategory")
|
||||
public class ProductCategoryController {
|
||||
|
||||
private final ProductCategoryService productCategoryService;
|
||||
|
||||
public ProductCategoryController(ProductCategoryService productCategoryService){
|
||||
this.productCategoryService = productCategoryService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ProductCategoryDTO getProductCategory(@PathVariable Long id){
|
||||
return new ProductCategoryDTO(productCategoryService.getProductCategory(id));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<ProductCategoryDTO> getProductCategories(){
|
||||
return productCategoryService.getAllProductCategorys().stream()
|
||||
.map(ProductCategoryDTO::new)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ProductCategoryDTO createProductCategory(@RequestParam("name") String name){
|
||||
final ProductCategory productCategory = productCategoryService.
|
||||
addProductCategory(name);
|
||||
return new ProductCategoryDTO(productCategory);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ProductCategoryDTO updateProduct(@RequestParam("name") String name,
|
||||
@PathVariable Long id){
|
||||
return new ProductCategoryDTO(productCategoryService.updateProductCategory
|
||||
(id, name));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ProductCategoryDTO deleteProductCategory(@PathVariable Long id){
|
||||
return new ProductCategoryDTO(productCategoryService.deleteProductCategory(id));
|
||||
}
|
||||
|
||||
@DeleteMapping()
|
||||
public void deleteAllProductCategories(){
|
||||
productCategoryService.deleteAllProductCategories();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.example.lab.DataBase.Controllers;
|
||||
|
||||
import com.example.lab.DataBase.Models.Product;
|
||||
import com.example.lab.DataBase.DTOs.ProductDTO;
|
||||
import com.example.lab.DataBase.Models.ProductCategory;
|
||||
import com.example.lab.DataBase.Services.ProductCategoryService;
|
||||
import com.example.lab.DataBase.Services.ProductService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/product")
|
||||
public class ProductController {
|
||||
private final ProductService productService;
|
||||
private final ProductCategoryService productCategoryService;
|
||||
|
||||
public ProductController(ProductService productService, ProductCategoryService productCategoryService){
|
||||
this.productService = productService;
|
||||
this.productCategoryService = productCategoryService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ProductDTO getProduct(@PathVariable Long id){
|
||||
return new ProductDTO(productService.getProduct(id));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<ProductDTO> getProducts(){
|
||||
return productService.getAllProducts().stream()
|
||||
.map(ProductDTO::new)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ProductDTO createProduct(@RequestParam("productName") String name,
|
||||
@RequestParam("price") String price,
|
||||
@RequestParam("productCategoryId") long productCategoryId){
|
||||
final Product product = productService.addProduct(name, Float.parseFloat(price) ,
|
||||
productCategoryService.getProductCategory(productCategoryId));
|
||||
return new ProductDTO(product);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ProductDTO updateProduct(@RequestParam("productName") String name,
|
||||
@RequestParam("price") float price,
|
||||
@PathVariable Long id){
|
||||
return new ProductDTO(productService.updateProduct(id, name, price));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ProductDTO deleteProduct(@PathVariable Long id){
|
||||
return new ProductDTO(productService.deleteProduct(id));
|
||||
}
|
||||
|
||||
@DeleteMapping()
|
||||
public void deleteAllProducts(){
|
||||
productService.deleteAllProducts();
|
||||
}
|
||||
|
||||
}
|
@ -3,10 +3,12 @@ import java.util.List;
|
||||
import com.example.lab.DataBase.Models.Cart;
|
||||
|
||||
public class CartDTO {
|
||||
public Long id;;
|
||||
public Long id;
|
||||
public String customer;
|
||||
|
||||
public CartDTO(Cart cart){
|
||||
this.id = cart.getId();
|
||||
this.customer = cart.getCustomer().getLastName() + " " + cart.getCustomer().getFirstName();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
@ -16,4 +18,12 @@ public class CartDTO {
|
||||
public void setId(Long id){
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(String customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,15 @@ import jakarta.persistence.Column;
|
||||
|
||||
public class CountProductDTO {
|
||||
private Long id;
|
||||
public String name;
|
||||
public Integer amount;
|
||||
public float price;
|
||||
|
||||
public CountProductDTO(CountProduct countProduct){
|
||||
this.id = countProduct.getId();
|
||||
this.name = countProduct.getProduct().getName();
|
||||
this.amount = countProduct.getAmount();
|
||||
this.price = this.amount * countProduct.getProduct().getPrice();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
|
@ -5,11 +5,15 @@ public class ProductDTO {
|
||||
public Long id;
|
||||
public String name;
|
||||
public float price;
|
||||
public Long productCategoryId;
|
||||
public String categoryName;
|
||||
|
||||
public ProductDTO(Product product){
|
||||
this.id = product.getId();
|
||||
this.name = product.getName();
|
||||
this.price = product.getPrice();
|
||||
this.productCategoryId = product.getProductCategory().getId();
|
||||
this.categoryName = product.getProductCategory().getName();
|
||||
}
|
||||
public Long getId() {
|
||||
return id;
|
||||
|
@ -11,7 +11,6 @@ public class CountProduct {
|
||||
private Long id;
|
||||
|
||||
@Column
|
||||
@NotBlank(message = "Amount can't be empty, only 0")
|
||||
private Integer amount;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@ -27,7 +26,7 @@ public class CountProduct {
|
||||
public CountProduct(Cart cart, Product product) {
|
||||
this.cart = cart;
|
||||
this.product = product;
|
||||
this.amount = 0;
|
||||
this.amount = 1;
|
||||
this.cart.addCountProduct(this);
|
||||
this.product.addCountProduct(this);
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ public class Product {
|
||||
@NotBlank(message = "Product's name can't be empty")
|
||||
private String name;
|
||||
@Column
|
||||
@NotBlank(message = "Price can't be empty")
|
||||
private float price;
|
||||
|
||||
@OneToMany
|
||||
|
@ -4,4 +4,5 @@ import com.example.lab.DataBase.Models.Cart;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface CartRepository extends JpaRepository<Cart, Long> {
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,11 @@ package com.example.lab.DataBase.Repositories;
|
||||
|
||||
import com.example.lab.DataBase.Models.CountProduct;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface CountProductRepository extends JpaRepository<CountProduct, Long> {
|
||||
@Query("SELECT p FROM CountProduct p WHERE p.cart.id = ?1")
|
||||
Collection<CountProduct> findAllProductsByCartId(Long cartId);
|
||||
}
|
@ -32,14 +32,13 @@ public class CountProductService {
|
||||
@Transactional
|
||||
public CountProduct getCountProduct(long productId, long cartId){
|
||||
var count = getAllCountProducts();
|
||||
var countProduct = count.stream().filter(x -> x.getProduct().getId() == productId
|
||||
&& x.getCart().getId() == cartId ).findFirst();
|
||||
var countProduct = count.stream().filter(x -> x.getProduct().getId() == productId && x.getCart().getId() == cartId ).findFirst();
|
||||
if(countProduct.isEmpty()) return null;
|
||||
else return countProduct.get();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CountProduct getCountProductGeneral(long id){
|
||||
public CountProduct getCountProductById(long id){
|
||||
return countProductRepository.findById(id).orElseThrow(() -> new CustomerNotFoundException(id));
|
||||
}
|
||||
|
||||
@ -50,6 +49,13 @@ public class CountProductService {
|
||||
return countProductRepository.save(countProduct);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CountProduct incrementProductById(long id){
|
||||
CountProduct countProduct = getCountProductById(id);
|
||||
countProduct.incrementAmount();
|
||||
return countProductRepository.save(countProduct);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CountProduct decrementProduct (long productId, long cartId){
|
||||
CountProduct countProduct = getCountProduct(productId, cartId);
|
||||
@ -57,6 +63,13 @@ public class CountProductService {
|
||||
return countProductRepository.save(countProduct);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CountProduct decrementProductById (Long id){
|
||||
CountProduct countProduct = getCountProductById(id);
|
||||
countProduct.decrementAmount();
|
||||
return countProductRepository.save(countProduct);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CountProduct deleteCountProduct(long productId, long cartId){
|
||||
CountProduct countProduct = getCountProduct(productId,cartId);
|
||||
@ -64,6 +77,13 @@ public class CountProductService {
|
||||
return countProduct;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CountProduct deleteCountProductById(long id){
|
||||
CountProduct countProduct = getCountProductById(id);
|
||||
countProductRepository.delete(countProduct);
|
||||
return countProduct;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteAll(){
|
||||
countProductRepository.deleteAll();
|
||||
@ -73,4 +93,7 @@ public class CountProductService {
|
||||
public List<CountProduct> getAllCountProducts(){
|
||||
return countProductRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<CountProduct> getProductsForCart(Long cartId) { return countProductRepository.findAllProductsByCartId(cartId).stream().toList();}
|
||||
}
|
@ -13,11 +13,13 @@ import java.util.List;
|
||||
@Service
|
||||
public class CustomerService {
|
||||
private final CustomerRepository customerRepository;
|
||||
private final CartService cartService;
|
||||
private final ValidatorUtil validatorUtil;
|
||||
|
||||
public CustomerService(CustomerRepository customerRepository,
|
||||
public CustomerService(CustomerRepository customerRepository, CartService cartService,
|
||||
ValidatorUtil validatorUtil){
|
||||
this.customerRepository = customerRepository;
|
||||
this.cartService = cartService;
|
||||
this.validatorUtil = validatorUtil;
|
||||
}
|
||||
|
||||
@ -25,7 +27,9 @@ public class CustomerService {
|
||||
public Customer addCustomer(String customerFirstName, String customerLastName, String customerAddress){
|
||||
Customer customer = new Customer(customerLastName, customerFirstName, customerAddress);
|
||||
validatorUtil.validate(customer);
|
||||
return customerRepository.save(customer);
|
||||
var cus = customerRepository.save(customer);
|
||||
cartService.addCart(cus);
|
||||
return cus;
|
||||
}
|
||||
|
||||
@Transactional()
|
||||
|
BIN
front/images/arrow.png
Normal file
BIN
front/images/arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
front/images/favicon.ico
Normal file
BIN
front/images/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
front/images/free-icon-search-2997940.png
Normal file
BIN
front/images/free-icon-search-2997940.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
front/images/free-icon-shopping-cart-6518420.png
Normal file
BIN
front/images/free-icon-shopping-cart-6518420.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
BIN
front/images/logo.png
Normal file
BIN
front/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
BIN
front/images/logo_color.png
Normal file
BIN
front/images/logo_color.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
@ -1,32 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Интернет программирование</title>
|
||||
<script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<link href="node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"/>
|
||||
<link href="node_modules/@fortawesome/fontawesome-free/css/all.min.css" rel="stylesheet"/>
|
||||
<script src="scripts.js"></script>
|
||||
</head>
|
||||
<body class="ms-3">
|
||||
<h3 class="mt-2">Вычисления</h3>
|
||||
<div class="d-flex form-group">
|
||||
<label class="m-2" for="obj1Input">Поле 1:</label>
|
||||
<input class="w-25" id="obj1Input" placeholder="Введите...">
|
||||
<label class="m-2" for="obj2Input">Поле 2:</label>
|
||||
<input class="w-25" id="obj2Input" placeholder="Введите...">
|
||||
<select class="custom-select w-auto ms-3" id="typeSelect">
|
||||
<option value="int">Числа</option>
|
||||
<option value="str">Строки</option>
|
||||
<option value="arr">Массив</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<button id = "1" class="btn btn-primary w-auto mt-2 ms-3" onclick="Okclick(this.id)">+</button>
|
||||
<button id = "2" class="btn btn-primary w-auto mt-2 ms-3" onclick="Okclick(this.id)">-</button>
|
||||
<button id = "3" class="btn btn-primary w-auto mt-2 ms-3" onclick="Okclick(this.id)">*</button>
|
||||
<button id = "4" class="btn btn-primary w-auto mt-2 ms-3" onclick="Okclick(this.id)">%</button>
|
||||
</div>
|
||||
<a id="res"></a>
|
||||
</body>
|
||||
<html lang="ru" class="h-100">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="/node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/node_modules/@fortawesome/fontawesome-free/css/all.min.css">
|
||||
<title>4th lab</title>
|
||||
</head>
|
||||
<body class="h-100 bg-light m-0">
|
||||
<article class="h-100">
|
||||
<div id="app" class="h-100"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
4691
front/package-lock.json
generated
4691
front/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,26 @@
|
||||
{
|
||||
"name": "thistore",
|
||||
"name": "test",
|
||||
"version": "1.0.0",
|
||||
"description": "Internet Programming labs",
|
||||
"main": "MainPage.html",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "http-server -p 3000 ./",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"dev": "vite",
|
||||
"start": "npm-run-all --parallel dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"author": "Nevaeva Ksenia",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bootstrap": "5.2.1",
|
||||
"@fortawesome/fontawesome-free": "6.2.0"
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.4.4",
|
||||
"axios": "^1.1.3",
|
||||
"bootstrap": "^5.2.2",
|
||||
"@fortawesome/fontawesome-free": "^6.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"http-server": "14.1.1"
|
||||
"@types/react": "^18.0.24",
|
||||
"@types/react-dom": "^18.0.8",
|
||||
"vite": "^3.2.3",
|
||||
"@vitejs/plugin-react": "^2.2.0",
|
||||
"npm-run-all": "^4.1.5"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
function Okclick(clicked) {
|
||||
var obj1 = document.getElementById("obj1Input").value
|
||||
var obj2 = document.getElementById("obj2Input").value
|
||||
var typeInp = document.getElementById("typeSelect").value
|
||||
var id = clicked;
|
||||
var argument = "";
|
||||
console.log(typeInp);
|
||||
if (document.getElementById("typeSelect").value == "arr"){
|
||||
console.log("aaa");
|
||||
obj1= encodeURIComponent(obj1);
|
||||
obj2 = encodeURIComponent(obj2);
|
||||
console.log(obj1);
|
||||
console.log(obj2);
|
||||
}
|
||||
if(id == "1"){
|
||||
argument = ("GetSum?obj1=" + obj1 +"&obj2=" + obj2 + "&typeInp=" + typeInp);
|
||||
}
|
||||
else if (id == "2"){
|
||||
argument = ("GetMinus?obj1=" + obj1 + "&obj2=" + obj2 + "&typeInp=" + typeInp);
|
||||
}
|
||||
else if( id == "3"){
|
||||
argument = ("GetMult?obj1=" + obj1 + "&obj2=" + obj2 + "&typeInp=" + typeInp);
|
||||
}
|
||||
else if (id == "4"){
|
||||
argument = ("GetDiv?obj1=" + obj1 + "&obj2=" + obj2 + "&typeInp=" + typeInp);
|
||||
}
|
||||
fetch ("http://127.0.0.1:8080/" + argument)
|
||||
.then(response => response.text())
|
||||
.then((response) => {
|
||||
console.log(response)
|
||||
document.getElementById("res").innerHTML = "Результат = " + response
|
||||
})
|
||||
|
||||
}
|
45
front/src/App.jsx
Normal file
45
front/src/App.jsx
Normal file
@ -0,0 +1,45 @@
|
||||
import { useRoutes, Outlet, BrowserRouter } from 'react-router-dom';
|
||||
import Header from './components/common/Header';
|
||||
import CustomerPage from './components/pages/customerPage';
|
||||
import ProductPage from './components/pages/productPage';
|
||||
import ProductCategoryPage from './components/pages/productCategoryPage';
|
||||
import CartsPage from './components/pages/cartsPage';
|
||||
import CartPage from './components/pages/cartPage';
|
||||
import './style.css';
|
||||
|
||||
function Router(props) {
|
||||
return useRoutes(props.rootRoute);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const routes = [
|
||||
{ index: true, element: <CustomerPage/> },
|
||||
{ path: 'customer', element: <CustomerPage/>, label:'Покупатели'},
|
||||
{ path: 'carts', element: <CartsPage/>, label: 'Корзины' },
|
||||
{ path: 'product', element: <ProductPage/>, label: 'Товары' },
|
||||
{ path: 'productCategory', element: <ProductCategoryPage/>, label: 'Категории товаров'},
|
||||
{ path: 'cart', element: <CartPage/>},
|
||||
];
|
||||
const links = routes.filter(route => route.hasOwnProperty('label'));
|
||||
const rootRoute = [
|
||||
{ path: '/', element: render(links), children: routes }
|
||||
];
|
||||
|
||||
function render(links) {
|
||||
console.info('render links');
|
||||
return (
|
||||
<>
|
||||
<Header links={links} />
|
||||
<div className="container-fluid">
|
||||
<Outlet />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Router rootRoute={ rootRoute } />
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
9
front/src/Main.jsx
Normal file
9
front/src/Main.jsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('app')).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
)
|
103
front/src/components/common/CartTable.jsx
Normal file
103
front/src/components/common/CartTable.jsx
Normal file
@ -0,0 +1,103 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import Modal from './Modal';
|
||||
import DataService from '../../services/DataService';
|
||||
import Toolbar from './Toolbar';
|
||||
import Table from './CartsTable';
|
||||
|
||||
export default function CartTable(props){
|
||||
const [items, setItems] = useState([]);
|
||||
const [modalHeader, setModalHeader] = useState('');
|
||||
const [modalConfirm, setModalConfirm] = useState('');
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [isEdit, setEdit] = useState(false);
|
||||
|
||||
let selectedItems = [];
|
||||
|
||||
useEffect(() => {
|
||||
loadItems();
|
||||
}, []);
|
||||
|
||||
function loadItems() {
|
||||
DataService.readAll(props.getAllUrl, props.transformer)
|
||||
.then(data => setItems(data));
|
||||
}
|
||||
|
||||
function saveItem() {
|
||||
if (!isEdit) {
|
||||
DataService.create(props.url, "?customerLastName=" + props.data.lastName
|
||||
+ "&customerFirstName=" + props.data.firstName
|
||||
+ "&customerAddress=" + props.data.customerAddress).then(() => loadItems());
|
||||
} else {
|
||||
DataService.update(props.getUrl + props.data.id, "?customerLastName=" + props.data.lastName
|
||||
+ "&customerFirstName=" + props.data.firstName
|
||||
+ "&customerAddress=" + props.data.customerAddress).then(() => loadItems());
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
setEdit(false);
|
||||
setModalHeader('Создание');
|
||||
setModalConfirm('Создать');
|
||||
setModalVisible(true);
|
||||
props.onAdd();
|
||||
}
|
||||
|
||||
function handleEdit() {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
edit(selectedItems[0]);
|
||||
}
|
||||
|
||||
function edit(editedId) {
|
||||
DataService.read(props.getUrl + editedId, props.transformer)
|
||||
.then(data => {
|
||||
setEdit(true);
|
||||
setModalHeader('Редактирование пользователя');
|
||||
setModalConfirm('Сохранить');
|
||||
setModalVisible(true);
|
||||
props.onEdit(data);
|
||||
});
|
||||
}
|
||||
|
||||
function handleRemove() {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (confirm('Удалить выбранные элементы?')) {
|
||||
const promises = [];
|
||||
selectedItems.forEach(item => {
|
||||
promises.push(DataService.delete(props.getUrl + item));
|
||||
});
|
||||
Promise.all(promises).then((results) => {
|
||||
selectedItems.length = 0;
|
||||
loadItems();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleTableClick(tableSelectedItems) {
|
||||
selectedItems = tableSelectedItems;
|
||||
}
|
||||
|
||||
function handleTableDblClick(tableSelectedItem) {
|
||||
edit(tableSelectedItem);
|
||||
}
|
||||
|
||||
function handleModalHide() {
|
||||
setModalVisible(false);
|
||||
}
|
||||
|
||||
function handleModalDone() {
|
||||
saveItem();
|
||||
}
|
||||
|
||||
return(
|
||||
<>
|
||||
<Table
|
||||
headers={props.headers}
|
||||
items={items}
|
||||
selectable={false}/>
|
||||
</>
|
||||
)
|
||||
}
|
73
front/src/components/common/CartsTable.jsx
Normal file
73
front/src/components/common/CartsTable.jsx
Normal file
@ -0,0 +1,73 @@
|
||||
import { useState } from 'react';
|
||||
import styles from './Table.module.css';
|
||||
|
||||
export default function Table(props) {
|
||||
const [tableUpdate, setTableUpdate] = useState(false);
|
||||
const [selectedItems, setSelectedItems] = useState([]);
|
||||
|
||||
function isSelected(id) {
|
||||
if (!props.selectable) {
|
||||
return false;
|
||||
}
|
||||
return selectedItems.includes(id);
|
||||
}
|
||||
|
||||
function click(id) {
|
||||
if (!props.selectable) {
|
||||
return;
|
||||
}
|
||||
if (isSelected(id)) {
|
||||
var index = selectedItems.indexOf(id);
|
||||
if (index !== -1) {
|
||||
selectedItems.splice(index, 1);
|
||||
setSelectedItems(selectedItems);
|
||||
setTableUpdate(!tableUpdate);
|
||||
}
|
||||
} else {
|
||||
selectedItems.push(id);
|
||||
setSelectedItems(selectedItems);
|
||||
setTableUpdate(!tableUpdate);
|
||||
}
|
||||
props.onClick(selectedItems);
|
||||
}
|
||||
|
||||
function dblClick(id) {
|
||||
if (!props.selectable) {
|
||||
return;
|
||||
}
|
||||
props.onDblClick(id);
|
||||
}
|
||||
|
||||
return (
|
||||
<table className={`table table-success table-hover ${styles.table} ${props.selectable ? styles.selectable : '' } `}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
{
|
||||
props.headers.map(header =>
|
||||
<th key={header.name} scope="col">
|
||||
{header.label}
|
||||
</th>
|
||||
)
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
props.items.map((item, index) =>
|
||||
<tr key={item.id}
|
||||
className={isSelected(item.id) ? styles.selected : ''}
|
||||
onClick={(e) => click(item.id, e)} onDoubleClick={(e) => dblClick(item.id, e)}>
|
||||
<th scope="row"><a href={"/cart?id=" + item.id}>{index + 1}</a></th>
|
||||
{
|
||||
props.headers.map(header =>
|
||||
<td key={item.id + header.name}>{item[header.name]}</td>
|
||||
)
|
||||
}
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
</tbody >
|
||||
</table >
|
||||
);
|
||||
}
|
102
front/src/components/common/CountProductTable.jsx
Normal file
102
front/src/components/common/CountProductTable.jsx
Normal file
@ -0,0 +1,102 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import Modal from './Modal';
|
||||
import DataService from '../../services/DataService';
|
||||
import Toolbar from './ToolbarOnlyAdd'
|
||||
import Table from './TableProduct';
|
||||
|
||||
export default function CustomerTable(props){
|
||||
const [items, setItems] = useState([]);
|
||||
const [cartId, setCartId] = useState(0);
|
||||
const [modalHeader, setModalHeader] = useState('');
|
||||
const [modalConfirm, setModalConfirm] = useState('');
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [isEdit, setEdit] = useState(false);
|
||||
|
||||
let selectedItems = [];
|
||||
|
||||
useEffect(() => {
|
||||
loadItems();
|
||||
}, []);
|
||||
|
||||
function loadItems() {
|
||||
const queryString = window.location.search;
|
||||
const urlParams = new URLSearchParams(queryString);
|
||||
var cartId = urlParams.get('id');
|
||||
console.log(cartId);
|
||||
setCartId(cartId);
|
||||
DataService.readAll(props.getAllUrl + cartId, props.transformer)
|
||||
.then(data => setItems(data));
|
||||
}
|
||||
|
||||
function saveItem() {
|
||||
DataService.create(props.getUrl, "?cartId=" + cartId
|
||||
+ "&productId=" + props.data.productId).then(() => loadItems());
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
setEdit(false);
|
||||
setModalHeader('Регистрация');
|
||||
setModalConfirm('Добавить');
|
||||
setModalVisible(true);
|
||||
props.onAdd();
|
||||
}
|
||||
|
||||
function edit(editedId) {
|
||||
DataService.read(props.getUrl + editedId, props.transformer)
|
||||
.then(data => {
|
||||
setEdit(true);
|
||||
setModalHeader('Редактирование пользователя');
|
||||
setModalConfirm('Сохранить');
|
||||
setModalVisible(true);
|
||||
props.onEdit(data);
|
||||
});
|
||||
}
|
||||
|
||||
function add(prodId){
|
||||
console.log(prodId);
|
||||
DataService.update(props.url, prodId).then((results) => loadItems());
|
||||
}
|
||||
|
||||
function remove(prodId) {
|
||||
DataService.delete(props.getUrl + "?id=" + prodId).then((results) => loadItems());
|
||||
}
|
||||
|
||||
function handleTableClick(tableSelectedItems) {
|
||||
selectedItems = tableSelectedItems;
|
||||
}
|
||||
|
||||
function handleTableDblClick(tableSelectedItem) {
|
||||
edit(tableSelectedItem);
|
||||
}
|
||||
|
||||
function handleModalHide() {
|
||||
setModalVisible(false);
|
||||
}
|
||||
|
||||
function handleModalDone() {
|
||||
saveItem();
|
||||
}
|
||||
|
||||
return(
|
||||
<>
|
||||
<h2>Корзина №{cartId}</h2>
|
||||
<Toolbar onAdd={handleAdd}/>
|
||||
<Table
|
||||
headers={props.headers}
|
||||
items={items}
|
||||
selectable={false}
|
||||
add={add}
|
||||
remove={remove}
|
||||
onClick={handleTableClick}
|
||||
onDblClick={handleTableDblClick}/>
|
||||
<Modal
|
||||
header={modalHeader}
|
||||
confirm={modalConfirm}
|
||||
visible={modalVisible}
|
||||
onHide={handleModalHide}
|
||||
onDone={handleModalDone}>
|
||||
{props.children}
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
117
front/src/components/common/CustomerTable.jsx
Normal file
117
front/src/components/common/CustomerTable.jsx
Normal file
@ -0,0 +1,117 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import Modal from './Modal';
|
||||
import DataService from '../../services/DataService';
|
||||
import Toolbar from './Toolbar';
|
||||
import Table from './Table';
|
||||
|
||||
export default function CustomerTable(props){
|
||||
const [items, setItems] = useState([]);
|
||||
const [modalHeader, setModalHeader] = useState('');
|
||||
const [modalConfirm, setModalConfirm] = useState('');
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [isEdit, setEdit] = useState(false);
|
||||
|
||||
let selectedItems = [];
|
||||
|
||||
useEffect(() => {
|
||||
loadItems();
|
||||
}, []);
|
||||
|
||||
function loadItems() {
|
||||
DataService.readAll(props.getAllUrl, props.transformer)
|
||||
.then(data => setItems(data));
|
||||
}
|
||||
|
||||
function saveItem() {
|
||||
if (!isEdit) {
|
||||
DataService.create(props.url, "?customerLastName=" + props.data.lastName
|
||||
+ "&customerFirstName=" + props.data.firstName
|
||||
+ "&customerAddress=" + props.data.customerAddress).then(() => loadItems());
|
||||
} else {
|
||||
DataService.update(props.getUrl + props.data.id, "?customerLastName=" + props.data.lastName
|
||||
+ "&customerFirstName=" + props.data.firstName
|
||||
+ "&customerAddress=" + props.data.customerAddress).then(() => loadItems());
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
setEdit(false);
|
||||
setModalHeader('Регистрация');
|
||||
setModalConfirm('Добавить');
|
||||
setModalVisible(true);
|
||||
props.onAdd();
|
||||
}
|
||||
|
||||
function handleEdit() {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
edit(selectedItems[0]);
|
||||
}
|
||||
|
||||
function edit(editedId) {
|
||||
DataService.read(props.getUrl + editedId, props.transformer)
|
||||
.then(data => {
|
||||
setEdit(true);
|
||||
setModalHeader('Редактирование пользователя');
|
||||
setModalConfirm('Сохранить');
|
||||
setModalVisible(true);
|
||||
props.onEdit(data);
|
||||
});
|
||||
}
|
||||
|
||||
function handleRemove() {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (confirm('Удалить выбранные элементы?')) {
|
||||
const promises = [];
|
||||
selectedItems.forEach(item => {
|
||||
promises.push(DataService.delete(props.getUrl + item));
|
||||
});
|
||||
Promise.all(promises).then((results) => {
|
||||
selectedItems.length = 0;
|
||||
loadItems();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleTableClick(tableSelectedItems) {
|
||||
selectedItems = tableSelectedItems;
|
||||
}
|
||||
|
||||
function handleTableDblClick(tableSelectedItem) {
|
||||
edit(tableSelectedItem);
|
||||
}
|
||||
|
||||
function handleModalHide() {
|
||||
setModalVisible(false);
|
||||
}
|
||||
|
||||
function handleModalDone() {
|
||||
saveItem();
|
||||
}
|
||||
|
||||
return(
|
||||
<>
|
||||
<Toolbar
|
||||
onAdd={handleAdd}
|
||||
onEdit={handleEdit}
|
||||
onRemove={handleRemove}/>
|
||||
<Table
|
||||
headers={props.headers}
|
||||
items={items}
|
||||
selectable={true}
|
||||
onClick={handleTableClick}
|
||||
onDblClick={handleTableDblClick}/>
|
||||
<Modal
|
||||
header={modalHeader}
|
||||
confirm={modalConfirm}
|
||||
visible={modalVisible}
|
||||
onHide={handleModalHide}
|
||||
onDone={handleModalDone}>
|
||||
{props.children}
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
38
front/src/components/common/Header.jsx
Normal file
38
front/src/components/common/Header.jsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import './style.css';
|
||||
|
||||
export default function Header(props) {
|
||||
return (
|
||||
<header className="d-flex flex-row">
|
||||
<div id="leftPart" className="d-flex flex-row">
|
||||
<div className="logo mt-2 mb-2 ms-3 me-1">
|
||||
<a href="/">
|
||||
<img src="images/logo.png" width="60" height="60px" />
|
||||
</a>
|
||||
</div>
|
||||
<div id="siteName" className="mt-0">
|
||||
ThiStore
|
||||
</div>
|
||||
<div id="mainPage" className="mt-2 ms-3 text-nowrap">
|
||||
</div>
|
||||
</div>
|
||||
<nav className="navbar navbar-expand-md">
|
||||
<div className="container-fluid" id="navigationMenu">
|
||||
<button className="navbar-toggler mt-0" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span className="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div className="navbar-collapse collapse justify-content-end" id="navbarNav">
|
||||
<ul className="navbar-nav d-flex flex-row">
|
||||
{
|
||||
props.links.map(route=>
|
||||
<div id="listItemsMy" key ={route.path} className="nav-item d-flex text-nowrap"><NavLink className="nav-link d-inline" to ={route.path}>{route.label}</NavLink></div>
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
}
|
46
front/src/components/common/Modal.jsx
Normal file
46
front/src/components/common/Modal.jsx
Normal file
@ -0,0 +1,46 @@
|
||||
import React from "react";
|
||||
|
||||
export default function Modal(props) {
|
||||
const formRef = React.createRef();
|
||||
|
||||
function hide() {
|
||||
props.onHide();
|
||||
}
|
||||
|
||||
function done(e) {
|
||||
e.preventDefault();
|
||||
if (formRef.current.checkValidity()) {
|
||||
props.onDone();
|
||||
hide();
|
||||
} else {
|
||||
formRef.current.reportValidity();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="modal fade show" tabIndex="-1" aria-hidden="true"
|
||||
style={{ display: props.visible ? 'block' : 'none' }}>
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h1 className="modal-title fs-5" id="exampleModalLabel">{props.header}</h1>
|
||||
<button className="btn-close" type="button" aria-label="Close"
|
||||
onClick={hide}></button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<form ref={formRef} onSubmit={done}>
|
||||
{props.children}
|
||||
</form>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button className="btn btn-secondary" type="button" onClick={hide}>Закрыть</button>
|
||||
<button className="btn btn-primary" type="button" onClick={done}>
|
||||
{props.confirm}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
113
front/src/components/common/ProductCategoryTable.jsx
Normal file
113
front/src/components/common/ProductCategoryTable.jsx
Normal file
@ -0,0 +1,113 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import Modal from './Modal';
|
||||
import DataService from '../../services/DataService';
|
||||
import Toolbar from './Toolbar';
|
||||
import Table from './Table';
|
||||
|
||||
export default function ProductCategoryTable(props){
|
||||
const [items, setItems] = useState([]);
|
||||
const [modalHeader, setModalHeader] = useState('');
|
||||
const [modalConfirm, setModalConfirm] = useState('');
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [isEdit, setEdit] = useState(false);
|
||||
|
||||
let selectedItems = [];
|
||||
|
||||
useEffect(() => {
|
||||
loadItems();
|
||||
}, []);
|
||||
|
||||
function loadItems() {
|
||||
DataService.readAll(props.getAllUrl, props.transformer)
|
||||
.then(data => setItems(data));
|
||||
}
|
||||
|
||||
function saveItem() {
|
||||
if (!isEdit) {
|
||||
DataService.create(props.url, "?name=" + props.data.name).then(() => loadItems());
|
||||
} else {
|
||||
DataService.update(props.getUrl + props.data.id, "?name=" + props.data.name).then(() => loadItems());
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
setEdit(false);
|
||||
setModalHeader('Добавления категории');
|
||||
setModalConfirm('Добавить');
|
||||
setModalVisible(true);
|
||||
props.onAdd();
|
||||
}
|
||||
|
||||
function handleEdit() {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
edit(selectedItems[0]);
|
||||
}
|
||||
|
||||
function edit(editedId) {
|
||||
DataService.read(props.getUrl + editedId, props.transformer)
|
||||
.then(data => {
|
||||
setEdit(true);
|
||||
setModalHeader('Редактирование пользователя');
|
||||
setModalConfirm('Сохранить');
|
||||
setModalVisible(true);
|
||||
props.onEdit(data);
|
||||
});
|
||||
}
|
||||
|
||||
function handleRemove() {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (confirm('Удалить выбранные элементы?')) {
|
||||
const promises = [];
|
||||
selectedItems.forEach(item => {
|
||||
promises.push(DataService.delete(props.getUrl + item));
|
||||
});
|
||||
Promise.all(promises).then((results) => {
|
||||
selectedItems.length = 0;
|
||||
loadItems();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleTableClick(tableSelectedItems) {
|
||||
selectedItems = tableSelectedItems;
|
||||
}
|
||||
|
||||
function handleTableDblClick(tableSelectedItem) {
|
||||
edit(tableSelectedItem);
|
||||
}
|
||||
|
||||
function handleModalHide() {
|
||||
setModalVisible(false);
|
||||
}
|
||||
|
||||
function handleModalDone() {
|
||||
saveItem();
|
||||
}
|
||||
|
||||
return(
|
||||
<>
|
||||
<Toolbar
|
||||
onAdd={handleAdd}
|
||||
onEdit={handleEdit}
|
||||
onRemove={handleRemove}/>
|
||||
<Table
|
||||
headers={props.headers}
|
||||
items={items}
|
||||
selectable={true}
|
||||
onClick={handleTableClick}
|
||||
onDblClick={handleTableDblClick}/>
|
||||
<Modal
|
||||
header={modalHeader}
|
||||
confirm={modalConfirm}
|
||||
visible={modalVisible}
|
||||
onHide={handleModalHide}
|
||||
onDone={handleModalDone}>
|
||||
{props.children}
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
114
front/src/components/common/ProductTable.jsx
Normal file
114
front/src/components/common/ProductTable.jsx
Normal file
@ -0,0 +1,114 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import Modal from './Modal';
|
||||
import DataService from '../../services/DataService';
|
||||
import Toolbar from './Toolbar';
|
||||
import Table from './Table';
|
||||
|
||||
export default function ProductTable(props){
|
||||
const [items, setItems] = useState([]);
|
||||
const [modalHeader, setModalHeader] = useState('');
|
||||
const [modalConfirm, setModalConfirm] = useState('');
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [isEdit, setEdit] = useState(false);
|
||||
|
||||
let selectedItems = [];
|
||||
|
||||
useEffect(() => {
|
||||
loadItems();
|
||||
}, []);
|
||||
|
||||
function loadItems() {
|
||||
DataService.readAll(props.getAllUrl, props.transformer)
|
||||
.then(data => setItems(data));
|
||||
}
|
||||
|
||||
function saveItem() {
|
||||
console.log("Createing product");
|
||||
if (!isEdit) {
|
||||
DataService.create(props.url, "?productName=" + props.data.name + "&price=" + props.data.price + "&productCategoryId=" + props.data.productCategoryId).then(() => loadItems());
|
||||
} else {
|
||||
DataService.update(props.getUrl + props.data.id, "?productName=" + props.data.name + "&price=" + props.data.price + "&productCategoryId=" + props.data.productCategoryId).then(() => loadItems());
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
setEdit(false);
|
||||
setModalHeader('Добавления товара');
|
||||
setModalConfirm('Добавить');
|
||||
setModalVisible(true);
|
||||
props.onAdd();
|
||||
}
|
||||
|
||||
function handleEdit() {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
edit(selectedItems[0]);
|
||||
}
|
||||
|
||||
function edit(editedId) {
|
||||
DataService.read(props.getUrl + editedId, props.transformer)
|
||||
.then(data => {
|
||||
setEdit(true);
|
||||
setModalHeader('Редактирование пользователя');
|
||||
setModalConfirm('Сохранить');
|
||||
setModalVisible(true);
|
||||
props.onEdit(data);
|
||||
});
|
||||
}
|
||||
|
||||
function handleRemove() {
|
||||
if (selectedItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (confirm('Удалить выбранные элементы?')) {
|
||||
const promises = [];
|
||||
selectedItems.forEach(item => {
|
||||
promises.push(DataService.delete(props.getUrl + item));
|
||||
});
|
||||
Promise.all(promises).then((results) => {
|
||||
selectedItems.length = 0;
|
||||
loadItems();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleTableClick(tableSelectedItems) {
|
||||
selectedItems = tableSelectedItems;
|
||||
}
|
||||
|
||||
function handleTableDblClick(tableSelectedItem) {
|
||||
edit(tableSelectedItem);
|
||||
}
|
||||
|
||||
function handleModalHide() {
|
||||
setModalVisible(false);
|
||||
}
|
||||
|
||||
function handleModalDone() {
|
||||
saveItem();
|
||||
}
|
||||
|
||||
return(
|
||||
<>
|
||||
<Toolbar
|
||||
onAdd={handleAdd}
|
||||
onEdit={handleEdit}
|
||||
onRemove={handleRemove}/>
|
||||
<Table
|
||||
headers={props.headers}
|
||||
items={items}
|
||||
selectable={true}
|
||||
onClick={handleTableClick}
|
||||
onDblClick={handleTableDblClick}/>
|
||||
<Modal
|
||||
header={modalHeader}
|
||||
confirm={modalConfirm}
|
||||
visible={modalVisible}
|
||||
onHide={handleModalHide}
|
||||
onDone={handleModalDone}>
|
||||
{props.children}
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
73
front/src/components/common/Table.jsx
Normal file
73
front/src/components/common/Table.jsx
Normal file
@ -0,0 +1,73 @@
|
||||
import { useState } from 'react';
|
||||
import styles from './Table.module.css';
|
||||
|
||||
export default function Table(props) {
|
||||
const [tableUpdate, setTableUpdate] = useState(false);
|
||||
const [selectedItems, setSelectedItems] = useState([]);
|
||||
|
||||
function isSelected(id) {
|
||||
if (!props.selectable) {
|
||||
return false;
|
||||
}
|
||||
return selectedItems.includes(id);
|
||||
}
|
||||
|
||||
function click(id) {
|
||||
if (!props.selectable) {
|
||||
return;
|
||||
}
|
||||
if (isSelected(id)) {
|
||||
var index = selectedItems.indexOf(id);
|
||||
if (index !== -1) {
|
||||
selectedItems.splice(index, 1);
|
||||
setSelectedItems(selectedItems);
|
||||
setTableUpdate(!tableUpdate);
|
||||
}
|
||||
} else {
|
||||
selectedItems.push(id);
|
||||
setSelectedItems(selectedItems);
|
||||
setTableUpdate(!tableUpdate);
|
||||
}
|
||||
props.onClick(selectedItems);
|
||||
}
|
||||
|
||||
function dblClick(id) {
|
||||
if (!props.selectable) {
|
||||
return;
|
||||
}
|
||||
props.onDblClick(id);
|
||||
}
|
||||
|
||||
return (
|
||||
<table className={`table table-success table-hover ${styles.table} ${props.selectable ? styles.selectable : '' } `}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
{
|
||||
props.headers.map(header =>
|
||||
<th key={header.name} scope="col">
|
||||
{header.label}
|
||||
</th>
|
||||
)
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
props.items.map((item, index) =>
|
||||
<tr key={item.id}
|
||||
className={isSelected(item.id) ? styles.selected : ''}
|
||||
onClick={(e) => click(item.id, e)} onDoubleClick={(e) => dblClick(item.id, e)}>
|
||||
<th scope="row">{index + 1}</th>
|
||||
{
|
||||
props.headers.map(header =>
|
||||
<td key={item.id + header.name}>{item[header.name]}</td>
|
||||
)
|
||||
}
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
</tbody >
|
||||
</table >
|
||||
);
|
||||
}
|
12
front/src/components/common/Table.module.css
Normal file
12
front/src/components/common/Table.module.css
Normal file
@ -0,0 +1,12 @@
|
||||
.table tbody tr {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.selectable tbody tr:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: #0d6efd;
|
||||
opacity: 80%;
|
||||
}
|
90
front/src/components/common/TableProduct.jsx
Normal file
90
front/src/components/common/TableProduct.jsx
Normal file
@ -0,0 +1,90 @@
|
||||
import { useState } from 'react';
|
||||
import styles from './Table.module.css';
|
||||
|
||||
export default function Table(props) {
|
||||
const [tableUpdate, setTableUpdate] = useState(false);
|
||||
const [selectedItems, setSelectedItems] = useState([]);
|
||||
|
||||
function isSelected(id) {
|
||||
if (!props.selectable) {
|
||||
return false;
|
||||
}
|
||||
return selectedItems.includes(id);
|
||||
}
|
||||
|
||||
function click(id) {
|
||||
if (!props.selectable) {
|
||||
return;
|
||||
}
|
||||
if (isSelected(id)) {
|
||||
var index = selectedItems.indexOf(id);
|
||||
if (index !== -1) {
|
||||
selectedItems.splice(index, 1);
|
||||
setSelectedItems(selectedItems);
|
||||
setTableUpdate(!tableUpdate);
|
||||
}
|
||||
} else {
|
||||
selectedItems.push(id);
|
||||
setSelectedItems(selectedItems);
|
||||
setTableUpdate(!tableUpdate);
|
||||
}
|
||||
props.onClick(selectedItems);
|
||||
}
|
||||
|
||||
function dblClick(id) {
|
||||
if (!props.selectable) {
|
||||
return;
|
||||
}
|
||||
props.onDblClick(id);
|
||||
}
|
||||
|
||||
function add(prodId){
|
||||
props.add(prodId);
|
||||
}
|
||||
|
||||
function remove(prodId){
|
||||
props.remove(prodId);
|
||||
}
|
||||
|
||||
return (
|
||||
<table className={`table table-success table-hover ${styles.table} ${props.selectable ? styles.selectable : '' } `}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
{
|
||||
props.headers.map(header =>
|
||||
<th key={header.name} scope="col">
|
||||
{header.label}
|
||||
</th>
|
||||
)
|
||||
}
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
props.items.map((item, index) =>
|
||||
<tr key={item.id}
|
||||
className={isSelected(item.id) ? styles.selected : ''}
|
||||
onClick={(e) => click(item.id, e)} onDoubleClick={(e) => dblClick(item.id, e)}>
|
||||
<th scope="row">{index + 1}</th>
|
||||
{
|
||||
props.headers.map(header =>
|
||||
<td key={item.id + header.name}>{item[header.name]}</td>
|
||||
)
|
||||
}
|
||||
<td>
|
||||
<button type="button" className='btn btn-success mx-2' onClick={(e) => add(item.id, e)}>
|
||||
+
|
||||
</button>
|
||||
<button type="button" className='btn btn-danger mx-2' onClick={(e) => remove(item.id, e)}>
|
||||
-
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
</tbody >
|
||||
</table >
|
||||
);
|
||||
}
|
29
front/src/components/common/Toolbar.jsx
Normal file
29
front/src/components/common/Toolbar.jsx
Normal file
@ -0,0 +1,29 @@
|
||||
import styles from './Toolbar.module.css';
|
||||
|
||||
export default function Toolbar(props) {
|
||||
function add() {
|
||||
props.onAdd();
|
||||
}
|
||||
|
||||
function edit() {
|
||||
props.onEdit();
|
||||
}
|
||||
|
||||
function remove() {
|
||||
props.onRemove();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="btn-group mt-2" role="group">
|
||||
<button type="button" className={`btn btn-success ${styles.btn}`} onClick={add}>
|
||||
Добавить
|
||||
</button>
|
||||
<button type="button" className={`btn btn-warning ${styles.btn}`} onClick={edit} >
|
||||
Изменить
|
||||
</button >
|
||||
<button type="button" className={`btn btn-danger ${styles.btn}`} onClick={remove}>
|
||||
Удалить
|
||||
</button >
|
||||
</div >
|
||||
);
|
||||
}
|
3
front/src/components/common/Toolbar.module.css
Normal file
3
front/src/components/common/Toolbar.module.css
Normal file
@ -0,0 +1,3 @@
|
||||
.btn {
|
||||
min-width: 140px;
|
||||
}
|
15
front/src/components/common/ToolbarOnlyAdd.jsx
Normal file
15
front/src/components/common/ToolbarOnlyAdd.jsx
Normal file
@ -0,0 +1,15 @@
|
||||
import styles from './Toolbar.module.css';
|
||||
|
||||
export default function Toolbar(props) {
|
||||
function add() {
|
||||
props.onAdd();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="btn-group mt-2" role="group">
|
||||
<button type="button" className={`btn btn-success ${styles.btn}`} onClick={add}>
|
||||
Добавить
|
||||
</button>
|
||||
</div >
|
||||
);
|
||||
}
|
473
front/src/components/common/style.css
Normal file
473
front/src/components/common/style.css
Normal file
@ -0,0 +1,473 @@
|
||||
.mainHtml{
|
||||
background-color: #ffb84b !important;
|
||||
}
|
||||
.hide{
|
||||
display: none;
|
||||
}
|
||||
.active{
|
||||
display: block;
|
||||
}
|
||||
.active img {
|
||||
height: auto;
|
||||
}
|
||||
header {
|
||||
height: fit-content;
|
||||
background-image: linear-gradient(to right, #ff8400 , #ffc156);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
img.center {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
div.colorBG{
|
||||
background-color: #ffb84b;
|
||||
}
|
||||
|
||||
.firstPart div {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.firstPart figcaption {
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#salePrice{
|
||||
font-family: 'Agency FB Bold', arial;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
.adIphone {
|
||||
color: white;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
#saleText{
|
||||
color: red;
|
||||
font-size: 35px;
|
||||
}
|
||||
|
||||
#specialText{
|
||||
font-size: 40px;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.adIphone figure img{
|
||||
text-align: justify-all;
|
||||
}
|
||||
|
||||
.menu {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.menu a,
|
||||
.menu .active {
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
display: block;
|
||||
padding: 8px 10px;
|
||||
color: white;
|
||||
font-size: 22px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.menu .active {
|
||||
color: #fff;
|
||||
background-color: #ff3d00;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
#siteName{
|
||||
color: white;
|
||||
font-family: 'Agency FB Bold', arial;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
#mainPage{
|
||||
font-size: 27px;
|
||||
}
|
||||
|
||||
#mainPage a{
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
div.colorBG{
|
||||
background-color: #ffb84b;
|
||||
}
|
||||
|
||||
.firstPart{
|
||||
background-image: url(images/banner.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 107%;
|
||||
}
|
||||
|
||||
.firstPart figure {
|
||||
margin-inline-start: 10px;
|
||||
margin-block-start: 10px;
|
||||
}
|
||||
|
||||
footer {
|
||||
background-image: linear-gradient(to right, #ff8400 , #ffc156);
|
||||
}
|
||||
|
||||
.socialMedia{
|
||||
margin-right: 5px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.socialMedia figcaption{
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
}
|
||||
.copyright {
|
||||
margin-right: 10px;
|
||||
flex-basis: 98%;
|
||||
text-align: right;
|
||||
color: white;
|
||||
font-family: 'Agency FB', arial;
|
||||
}
|
||||
#weInSocial {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.aboutUsFooter{
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
}
|
||||
|
||||
.aboutUsFooter a{
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.aboutUsFooter li{
|
||||
list-style-type: none;
|
||||
margin: 7px 0;
|
||||
}
|
||||
|
||||
.aboutUsText figcaption {
|
||||
color: #ff8400;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
font-size: 46px;
|
||||
}
|
||||
|
||||
#loremIpsumText{
|
||||
color: black;
|
||||
font-size: 20px;
|
||||
margin-right: 15%;
|
||||
margin-left: 15%;
|
||||
}
|
||||
|
||||
#leftColumn{
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#middleColumn{
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#rightColumn{
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item{
|
||||
text-align: center;
|
||||
font-family: Segoe UI;
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.item figcaption{
|
||||
color: black;
|
||||
}
|
||||
|
||||
#Items {
|
||||
columns: 3;
|
||||
column-gap: 1em;
|
||||
}
|
||||
|
||||
* {box-sizing: border-box;}
|
||||
form {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
margin-top: 20px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background-image: linear-gradient(to right, #ff8400 , #ffc156);
|
||||
}
|
||||
input, button {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
}
|
||||
input {
|
||||
height: 42px;
|
||||
}
|
||||
.searchbutton{
|
||||
height: 42px;
|
||||
width: 42px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
button .searchbutton:before {
|
||||
font-family: FontAwesome;
|
||||
font-size: 16px;
|
||||
color: #F9F0DA;
|
||||
}
|
||||
|
||||
.orders{
|
||||
width: 1000px;
|
||||
display: block;
|
||||
float: none;
|
||||
height: 350px;
|
||||
background: #ffc156;
|
||||
border: 1px solid #C1C1C1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#activeOrders {
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
margin-top: 10px;
|
||||
color: #c06300;
|
||||
}
|
||||
|
||||
#listOfInf{
|
||||
background-color: #ffc156;
|
||||
height: 150px;
|
||||
width: 900px;
|
||||
vertical-align: center;
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#listOfInf li{
|
||||
color: #c06300;
|
||||
list-style-type: none;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
margin: 9px 0;
|
||||
}
|
||||
|
||||
.orderItem{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nameItem{
|
||||
margin-top: 20px;
|
||||
color: white;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.priceItem {
|
||||
color: white;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
margin-bottom: 30px;
|
||||
margin-top: auto;
|
||||
margin-right: 100px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.deleteItem button{
|
||||
color: white;
|
||||
width: auto;
|
||||
height: 25px;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
left: 10%;
|
||||
top: 73%;
|
||||
transform: translate(-70%, 0);
|
||||
background: #ff8400;
|
||||
|
||||
}
|
||||
|
||||
.ordersCart{
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 30px;
|
||||
margin-top: 30px;
|
||||
width: 1000px;
|
||||
display: block;
|
||||
float: none;
|
||||
height: auto;
|
||||
background: #ffc156;
|
||||
border: 1px solid #C1C1C1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.orderItems button{
|
||||
color: white;
|
||||
width: auto;
|
||||
height: 40px;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
font-size: 36px;
|
||||
position: relative;
|
||||
left: 85%;
|
||||
top: 73%;
|
||||
transform: translate(-70%, 0);
|
||||
background: #ff8400;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
/* change the link color */
|
||||
.navbar-custom .navbar-nav .nav-link {
|
||||
color: white;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
}
|
||||
|
||||
@media (max-width: 550px){
|
||||
.nameItem{
|
||||
font-size: 12px;
|
||||
}
|
||||
.deleteItem{
|
||||
font-size: 12px;
|
||||
}
|
||||
.priceItem{
|
||||
font-size: 12px;
|
||||
}
|
||||
.orderItem img{
|
||||
height: 120px;
|
||||
width: auto;
|
||||
}
|
||||
.orderItems button {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
@media(max-width: 500px){
|
||||
header{
|
||||
flex-direction: column;
|
||||
}
|
||||
#mainPage{
|
||||
margin-top: 0px;
|
||||
}
|
||||
#leftPart a{
|
||||
font-size: 12px;
|
||||
text-align: left;
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
.logo img{
|
||||
margin-top: 10px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#siteName{
|
||||
font-size: 14px;
|
||||
margin-top: 24px !important;
|
||||
}
|
||||
#profile li{
|
||||
font-size: 6px !important;
|
||||
}
|
||||
#profile ul{
|
||||
padding-left: 6px;
|
||||
}
|
||||
#activeOrders{
|
||||
font-size: 8px !important;
|
||||
}
|
||||
footer{
|
||||
font-size: 8px !important;
|
||||
}
|
||||
.socialMedia img{
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
#Items {
|
||||
columns: 1;
|
||||
}
|
||||
#textIphone{
|
||||
font-size: 10px;
|
||||
}
|
||||
#specialText{
|
||||
font-size: 12px;
|
||||
}
|
||||
#saleText{
|
||||
font-size: 12px;
|
||||
}
|
||||
#salePrice{
|
||||
font-size: 12px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: 700px){
|
||||
.firstPart img{
|
||||
width:80px !important;
|
||||
height: auto;
|
||||
}
|
||||
.firstPart figcaption{
|
||||
font-size: 8px;
|
||||
}
|
||||
#textIphone{
|
||||
font-size: 12px;
|
||||
}
|
||||
#specialText{
|
||||
font-size: 14px;
|
||||
}
|
||||
#saleText{
|
||||
font-size: 16px;
|
||||
}
|
||||
#salePrice{
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
@media(max-width: 600px){
|
||||
.firstPart img{
|
||||
width:60px !important;
|
||||
height: auto;
|
||||
}
|
||||
.firstPart figcaption{
|
||||
font-size: 6px;
|
||||
}
|
||||
}
|
||||
@media(max-width: 800px){
|
||||
#profile li{
|
||||
font-size: 12px;
|
||||
}
|
||||
#activeOrders{
|
||||
font-size: 12px;
|
||||
}
|
||||
#avatar{
|
||||
width: 110px;
|
||||
}
|
||||
#profile ul{
|
||||
padding-left: 6px;
|
||||
}
|
||||
.socialMedia img{
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
.firstPart img{
|
||||
width:90px;
|
||||
height: auto;
|
||||
}
|
||||
.firstPart figcaption{
|
||||
font-size: 10px;
|
||||
}
|
||||
footer{
|
||||
font-size: 12px;
|
||||
}
|
||||
.navbar-toggler{
|
||||
margin-top: 10px !important;
|
||||
}
|
||||
#Items {
|
||||
columns: 1;
|
||||
}
|
||||
}
|
||||
@media(max-width: 900px){
|
||||
.firstPart img{
|
||||
width:100px;
|
||||
height: auto;
|
||||
}
|
||||
.firstPart figcaption{
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
84
front/src/components/pages/cartPage.jsx
Normal file
84
front/src/components/pages/cartPage.jsx
Normal file
@ -0,0 +1,84 @@
|
||||
import CountProduct from '../../models/countProduct';
|
||||
import Product from '../../models/product';
|
||||
import CountProductTable from '../common/CountProductTable'
|
||||
import DataService from '../../services/DataService';
|
||||
import { useState, useEffect} from "react";
|
||||
|
||||
import '../common/style.css';
|
||||
|
||||
export default function CartPage(){
|
||||
const url = 'countProduct/';
|
||||
const getUrl = 'countProduct';
|
||||
const getProductUrl = 'product'
|
||||
const transformer = (data) => new CountProduct(data);
|
||||
const transformerProd = (data) => new Product(data);
|
||||
const catalogCountProductHeaders = [
|
||||
{name: 'name', label: 'Название' },
|
||||
{name: 'amount', label: 'Количество' },
|
||||
{name: 'price', label: 'Цена' },
|
||||
];
|
||||
|
||||
const [data, setData] = useState(new CountProduct());
|
||||
const [productOptions, setProductOptions] = useState([]);
|
||||
|
||||
function handleOnAdd() {
|
||||
setData(new CountProduct());
|
||||
}
|
||||
|
||||
function handleOnEdit(data) {
|
||||
setData(new CountProduct(data));
|
||||
}
|
||||
|
||||
function handleFormChange(event) {
|
||||
setData({ ...data, [event.target.id]: event.target.value })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadOptions();
|
||||
}, []);
|
||||
|
||||
async function loadOptions(){
|
||||
loadProdOptions(await DataService.readAll(getProductUrl, transformerProd));
|
||||
}
|
||||
|
||||
function loadProdOptions(dataProduct){
|
||||
const products = [];
|
||||
|
||||
dataProduct.forEach((value) => {
|
||||
products.push({
|
||||
key: value.name,
|
||||
value: value.id,
|
||||
})
|
||||
})
|
||||
console.log(products);
|
||||
setProductOptions(products);
|
||||
}
|
||||
|
||||
|
||||
return(
|
||||
<article className="h-100 mt-0 mb-0 d-flex flex-column justify-content-between">
|
||||
<CountProductTable headers={catalogCountProductHeaders}
|
||||
getAllUrl={url}
|
||||
url={url}
|
||||
getUrl={getUrl}
|
||||
transformer={transformer}
|
||||
data={data}
|
||||
onAdd={handleOnAdd}
|
||||
onEdit={handleOnEdit}>
|
||||
<label className="form-label" forhtml="productId"></label>
|
||||
<select className="form-select" id="productId" value={data.productCategoryId} onChange={handleFormChange} required>
|
||||
{
|
||||
productOptions.map((option) => {
|
||||
return(
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.key}
|
||||
</option>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
</select>
|
||||
</CountProductTable>
|
||||
</article>
|
||||
)
|
||||
}
|
41
front/src/components/pages/cartsPage.jsx
Normal file
41
front/src/components/pages/cartsPage.jsx
Normal file
@ -0,0 +1,41 @@
|
||||
import Cart from "../../models/cart"
|
||||
import CartTable from '../common/CartTable'
|
||||
import { useState, useEffect} from "react";
|
||||
|
||||
import '../common/style.css';
|
||||
|
||||
export default function CartsPage(){
|
||||
const url = 'cart';
|
||||
const getUrl = 'cart/';
|
||||
const transformer = (data) => new Cart(data);
|
||||
const catalogCartHeaders = [
|
||||
{name: 'customer', label: 'Покупатель' },
|
||||
];
|
||||
|
||||
const [data, setData] = useState(new Cart());
|
||||
|
||||
function handleOnAdd() {
|
||||
setData(new Cart());
|
||||
}
|
||||
|
||||
function handleOnEdit(data) {
|
||||
setData(new Cart(data));
|
||||
}
|
||||
|
||||
function handleFormChange(event) {
|
||||
setData({ ...data, [event.target.id]: event.target.value })
|
||||
}
|
||||
return(
|
||||
<article className="h-100 mt-0 mb-0 d-flex flex-column justify-content-between">
|
||||
<CartTable headers={catalogCartHeaders}
|
||||
getAllUrl={url}
|
||||
url={url}
|
||||
getUrl={getUrl}
|
||||
transformer={transformer}
|
||||
data={data}
|
||||
onAdd={handleOnAdd}
|
||||
onEdit={handleOnEdit}>
|
||||
</CartTable>
|
||||
</article>
|
||||
)
|
||||
}
|
53
front/src/components/pages/customerPage.jsx
Normal file
53
front/src/components/pages/customerPage.jsx
Normal file
@ -0,0 +1,53 @@
|
||||
import Customer from "../../models/customer"
|
||||
import CustomerTable from '../common/CustomerTable'
|
||||
import { useState, useEffect} from "react";
|
||||
|
||||
export default function CustomerPage(){
|
||||
const url = 'customer';
|
||||
const getUrl = 'customer/';
|
||||
const transformer = (data) => new Customer(data);
|
||||
const catalogCustomerHeaders = [
|
||||
{ name: 'lastName', label: 'Фамилия' },
|
||||
{name: 'firstName', label: 'Имя'},
|
||||
{name: 'customerAddress', label: 'Адрес'}
|
||||
];
|
||||
|
||||
const [data, setData] = useState(new Customer());
|
||||
|
||||
function handleOnAdd() {
|
||||
setData(new Customer());
|
||||
}
|
||||
|
||||
function handleOnEdit(data) {
|
||||
setData(new Customer(data));
|
||||
}
|
||||
|
||||
function handleFormChange(event) {
|
||||
setData({ ...data, [event.target.id]: event.target.value })
|
||||
}
|
||||
return(
|
||||
<article className="h-100 mt-0 mb-0 d-flex flex-column justify-content-between">
|
||||
<CustomerTable headers={catalogCustomerHeaders}
|
||||
getAllUrl={url}
|
||||
url={url}
|
||||
getUrl={getUrl}
|
||||
transformer={transformer}
|
||||
data={data}
|
||||
onAdd={handleOnAdd}
|
||||
onEdit={handleOnEdit}>
|
||||
<div className="col-md-4">
|
||||
<label className="form-label" forhtml="lastName">Фамилия</label>
|
||||
<input className="form-control" type="text" id="lastName" value={data.lastName} onChange={handleFormChange} required="required"/>
|
||||
</div>
|
||||
<div className="col-md-4">
|
||||
<label className="form-label" forhtml="firstName">Имя</label>
|
||||
<input className="form-control" type="text" value={data.firstName} onChange={handleFormChange} id="firstName" required="required"/>
|
||||
</div>
|
||||
<div className="col-md-4">
|
||||
<label className="form-label" forhtml="customerAddress">Адрес</label>
|
||||
<input className="form-control" type="text" id="customerAddress" value={data.customerAddress} onChange={handleFormChange} required="required"/>
|
||||
</div>
|
||||
</CustomerTable>
|
||||
</article>
|
||||
)
|
||||
}
|
43
front/src/components/pages/productCategoryPage.jsx
Normal file
43
front/src/components/pages/productCategoryPage.jsx
Normal file
@ -0,0 +1,43 @@
|
||||
import ProductCategory from "../../models/productCategory"
|
||||
import ProductCategoryTable from '../common/productCategoryTable'
|
||||
import { useState, useEffect} from "react";
|
||||
|
||||
export default function ProductCategoryPage(){
|
||||
const url = 'productCategory';
|
||||
const getUrl = 'productCategory/';
|
||||
const transformer = (data) => new ProductCategory(data);
|
||||
const catalogCustomerHeaders = [
|
||||
{ name: 'name', label: 'Название категории' },
|
||||
];
|
||||
|
||||
const [data, setData] = useState(new ProductCategory());
|
||||
|
||||
function handleOnAdd() {
|
||||
setData(new ProductCategory());
|
||||
}
|
||||
|
||||
function handleOnEdit(data) {
|
||||
setData(new ProductCategory(data));
|
||||
}
|
||||
|
||||
function handleFormChange(event) {
|
||||
setData({ ...data, [event.target.id]: event.target.value })
|
||||
}
|
||||
return(
|
||||
<article className="h-100 mt-0 mb-0 d-flex flex-column justify-content-between">
|
||||
<ProductCategoryTable headers={catalogCustomerHeaders}
|
||||
getAllUrl={url}
|
||||
url={url}
|
||||
getUrl={getUrl}
|
||||
transformer={transformer}
|
||||
data={data}
|
||||
onAdd={handleOnAdd}
|
||||
onEdit={handleOnEdit}>
|
||||
<div className="col-md-4">
|
||||
<label className="form-label" forhtml="name">Название категории</label>
|
||||
<input className="form-control" type="text" id="name" value={data.name} onChange={handleFormChange} required="required"/>
|
||||
</div>
|
||||
</ProductCategoryTable>
|
||||
</article>
|
||||
)
|
||||
}
|
91
front/src/components/pages/productPage.jsx
Normal file
91
front/src/components/pages/productPage.jsx
Normal file
@ -0,0 +1,91 @@
|
||||
import Product from "../../models/product"
|
||||
import ProductCategory from "../../models/productCategory"
|
||||
import DataService from '../../services/DataService';
|
||||
import ProductTable from '../common/productTable'
|
||||
import { useState, useEffect} from "react";
|
||||
|
||||
export default function ProductPage(){
|
||||
const url = 'product';
|
||||
const getUrl = 'product/';
|
||||
const getCatUrl = 'productCategory';
|
||||
const transformer = (data) => new Product(data);
|
||||
const transformerCat = (data) => new ProductCategory(data);
|
||||
const catalogProductHeaders = [
|
||||
{ name: 'name', label: 'Название товара' },
|
||||
{ name: 'price', label: 'Цена' },
|
||||
{ name: 'categoryName', label: 'Категория товара' }
|
||||
];
|
||||
|
||||
const [data, setData] = useState(new Product());
|
||||
const [productCategoryOptions, setProductCategoryOptions] = useState([]);
|
||||
|
||||
function handleOnAdd() {
|
||||
setData(new Product());
|
||||
}
|
||||
|
||||
function handleOnEdit(data) {
|
||||
setData(new Product(data));
|
||||
}
|
||||
|
||||
function handleFormChange(event) {
|
||||
setData({ ...data, [event.target.id]: event.target.value })
|
||||
}
|
||||
|
||||
//подтягиваем список категорий в селект
|
||||
|
||||
useEffect(() => {
|
||||
loadOptions();
|
||||
}, []);
|
||||
|
||||
async function loadOptions(){
|
||||
loadCatOptions(await DataService.readAll(getCatUrl, transformerCat));
|
||||
}
|
||||
|
||||
function loadCatOptions(dataProductCategory){
|
||||
const productCategories = [];
|
||||
|
||||
dataProductCategory.forEach((value) => {
|
||||
productCategories.push({
|
||||
key: value.name,
|
||||
value: value.id,
|
||||
})
|
||||
})
|
||||
console.log(productCategories);
|
||||
setProductCategoryOptions(productCategories);
|
||||
}
|
||||
|
||||
return(
|
||||
<article className="h-100 mt-0 mb-0 d-flex flex-column justify-content-between">
|
||||
<ProductTable headers={catalogProductHeaders}
|
||||
getAllUrl={url}
|
||||
url={url}
|
||||
getUrl={getUrl}
|
||||
transformer={transformer}
|
||||
data={data}
|
||||
onAdd={handleOnAdd}
|
||||
onEdit={handleOnEdit}>
|
||||
<div className="col-md-4">
|
||||
<label className="form-label" forhtml="name">Название</label>
|
||||
<input className="form-control" type="text" id="name" value={data.name} onChange={handleFormChange} required="required"/>
|
||||
</div>
|
||||
<div className="col-md-4">
|
||||
<label className="form-label" forhtml="price">Цена</label>
|
||||
<input className="form-control" type="text" id="price" value={data.price} onChange={handleFormChange} required="required"/>
|
||||
</div>
|
||||
<label className="form-label" forhtml="productCategoryId"></label>
|
||||
<select className="form-select" id="productCategoryId" value={data.productCategoryId} onChange={handleFormChange} required>
|
||||
{
|
||||
productCategoryOptions.map((option) => {
|
||||
return(
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.key}
|
||||
</option>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
</select>
|
||||
</ProductTable>
|
||||
</article>
|
||||
)
|
||||
}
|
6
front/src/models/cart.js
Normal file
6
front/src/models/cart.js
Normal file
@ -0,0 +1,6 @@
|
||||
export default class Cart {
|
||||
constructor(data) {
|
||||
this.id = data?.id;
|
||||
this.customer = data?.customer || '';
|
||||
}
|
||||
}
|
8
front/src/models/countProduct.js
Normal file
8
front/src/models/countProduct.js
Normal file
@ -0,0 +1,8 @@
|
||||
export default class CountProduct {
|
||||
constructor(data) {
|
||||
this.id = data?.id;
|
||||
this.name = data?.name || '';
|
||||
this.amount = data?.amount || '';
|
||||
this.price = data?.price || '';
|
||||
}
|
||||
}
|
8
front/src/models/customer.js
Normal file
8
front/src/models/customer.js
Normal file
@ -0,0 +1,8 @@
|
||||
export default class Customer {
|
||||
constructor(data) {
|
||||
this.id = data?.id;
|
||||
this.lastName = data?.lastName || '';
|
||||
this.firstName = data?.firstName || '';
|
||||
this.customerAddress = data?.customerAddress || '';
|
||||
}
|
||||
}
|
9
front/src/models/product.js
Normal file
9
front/src/models/product.js
Normal file
@ -0,0 +1,9 @@
|
||||
export default class Product {
|
||||
constructor(data) {
|
||||
this.id = data?.id;
|
||||
this.name = data?.name || '';
|
||||
this.price = data?.price || '';
|
||||
this.productCategoryId = data?.productCategoryId || '';
|
||||
this.categoryName = data?.categoryName || '';
|
||||
}
|
||||
}
|
6
front/src/models/productCategory.js
Normal file
6
front/src/models/productCategory.js
Normal file
@ -0,0 +1,6 @@
|
||||
export default class Product {
|
||||
constructor(data) {
|
||||
this.id = data?.id;
|
||||
this.name = data?.name || '';
|
||||
}
|
||||
}
|
45
front/src/services/DataService.js
Normal file
45
front/src/services/DataService.js
Normal file
@ -0,0 +1,45 @@
|
||||
import axios from 'axios';
|
||||
|
||||
function toJSON(data) {
|
||||
const jsonObj = {};
|
||||
const fields = Object.getOwnPropertyNames(data);
|
||||
for (const field of fields) {
|
||||
if (data[field] === undefined) {
|
||||
continue;
|
||||
}
|
||||
jsonObj[field] = data[field];
|
||||
}
|
||||
return jsonObj;
|
||||
}
|
||||
|
||||
export default class DataService {
|
||||
static dataUrlPrefix = 'http://localhost:8080/';
|
||||
|
||||
static async readAll(url, transformer) {
|
||||
const response = await axios.get(this.dataUrlPrefix + url);
|
||||
return response.data.map(item => transformer(item));
|
||||
}
|
||||
|
||||
static async read(url, transformer) {
|
||||
const response = await axios.get(this.dataUrlPrefix + url);
|
||||
return transformer(response.data);
|
||||
}
|
||||
|
||||
static async create(url, data) {
|
||||
console.log("Create " + this.dataUrlPrefix + url + data);
|
||||
const response = await axios.post(this.dataUrlPrefix + url + data);
|
||||
return true;
|
||||
}
|
||||
|
||||
static async update(url, data) {
|
||||
console.log("UPD")
|
||||
const response = await axios.put(this.dataUrlPrefix + url + data);
|
||||
console.log("Done upd")
|
||||
return true;
|
||||
}
|
||||
|
||||
static async delete(url) {
|
||||
const response = await axios.delete(this.dataUrlPrefix + url);
|
||||
return response.data.id;
|
||||
}
|
||||
}
|
473
front/src/style.css
Normal file
473
front/src/style.css
Normal file
@ -0,0 +1,473 @@
|
||||
.mainHtml{
|
||||
background-color: #ffb84b !important;
|
||||
}
|
||||
.hide{
|
||||
display: none;
|
||||
}
|
||||
.active{
|
||||
display: block;
|
||||
}
|
||||
.active img {
|
||||
height: auto;
|
||||
}
|
||||
header {
|
||||
height: fit-content;
|
||||
background-image: linear-gradient(to right, #ff8400 , #ffc156);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
img.center {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
div.colorBG{
|
||||
background-color: #ffb84b;
|
||||
}
|
||||
|
||||
.firstPart div {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.firstPart figcaption {
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#salePrice{
|
||||
font-family: 'Agency FB Bold', arial;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
.adIphone {
|
||||
color: white;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
#saleText{
|
||||
color: red;
|
||||
font-size: 35px;
|
||||
}
|
||||
|
||||
#specialText{
|
||||
font-size: 40px;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.adIphone figure img{
|
||||
text-align: justify-all;
|
||||
}
|
||||
|
||||
.menu {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.menu a,
|
||||
.menu .active {
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
display: block;
|
||||
padding: 8px 10px;
|
||||
color: white;
|
||||
font-size: 22px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.menu .active {
|
||||
color: #fff;
|
||||
background-color: #ff3d00;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
#siteName{
|
||||
color: white;
|
||||
font-family: 'Agency FB Bold', arial;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
#mainPage{
|
||||
font-size: 27px;
|
||||
}
|
||||
|
||||
#mainPage a{
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
div.colorBG{
|
||||
background-color: #ffb84b;
|
||||
}
|
||||
|
||||
.firstPart{
|
||||
background-image: url(images/banner.png);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 107%;
|
||||
}
|
||||
|
||||
.firstPart figure {
|
||||
margin-inline-start: 10px;
|
||||
margin-block-start: 10px;
|
||||
}
|
||||
|
||||
footer {
|
||||
background-image: linear-gradient(to right, #ff8400 , #ffc156);
|
||||
}
|
||||
|
||||
.socialMedia{
|
||||
margin-right: 5px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.socialMedia figcaption{
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
}
|
||||
.copyright {
|
||||
margin-right: 10px;
|
||||
flex-basis: 98%;
|
||||
text-align: right;
|
||||
color: white;
|
||||
font-family: 'Agency FB', arial;
|
||||
}
|
||||
#weInSocial {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.aboutUsFooter{
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
}
|
||||
|
||||
.aboutUsFooter a{
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.aboutUsFooter li{
|
||||
list-style-type: none;
|
||||
margin: 7px 0;
|
||||
}
|
||||
|
||||
.aboutUsText figcaption {
|
||||
color: #ff8400;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
font-size: 46px;
|
||||
}
|
||||
|
||||
#loremIpsumText{
|
||||
color: black;
|
||||
font-size: 20px;
|
||||
margin-right: 15%;
|
||||
margin-left: 15%;
|
||||
}
|
||||
|
||||
#leftColumn{
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#middleColumn{
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#rightColumn{
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item{
|
||||
text-align: center;
|
||||
font-family: Segoe UI;
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.item figcaption{
|
||||
color: black;
|
||||
}
|
||||
|
||||
#Items {
|
||||
columns: 3;
|
||||
column-gap: 1em;
|
||||
}
|
||||
|
||||
* {box-sizing: border-box;}
|
||||
form {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
margin-top: 20px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background-image: linear-gradient(to right, #ff8400 , #ffc156);
|
||||
}
|
||||
input, button {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
}
|
||||
input {
|
||||
height: 42px;
|
||||
}
|
||||
.searchbutton{
|
||||
height: 42px;
|
||||
width: 42px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
button .searchbutton:before {
|
||||
font-family: FontAwesome;
|
||||
font-size: 16px;
|
||||
color: #F9F0DA;
|
||||
}
|
||||
|
||||
.orders{
|
||||
width: 1000px;
|
||||
display: block;
|
||||
float: none;
|
||||
height: 350px;
|
||||
background: #ffc156;
|
||||
border: 1px solid #C1C1C1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#activeOrders {
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
margin-top: 10px;
|
||||
color: #c06300;
|
||||
}
|
||||
|
||||
#listOfInf{
|
||||
background-color: #ffc156;
|
||||
height: 150px;
|
||||
width: 900px;
|
||||
vertical-align: center;
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#listOfInf li{
|
||||
color: #c06300;
|
||||
list-style-type: none;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
margin: 9px 0;
|
||||
}
|
||||
|
||||
.orderItem{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nameItem{
|
||||
margin-top: 20px;
|
||||
color: white;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.priceItem {
|
||||
color: white;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
margin-bottom: 30px;
|
||||
margin-top: auto;
|
||||
margin-right: 100px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.deleteItem button{
|
||||
color: white;
|
||||
width: auto;
|
||||
height: 25px;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
left: 10%;
|
||||
top: 73%;
|
||||
transform: translate(-70%, 0);
|
||||
background: #ff8400;
|
||||
|
||||
}
|
||||
|
||||
.ordersCart{
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 30px;
|
||||
margin-top: 30px;
|
||||
width: 1000px;
|
||||
display: block;
|
||||
float: none;
|
||||
height: auto;
|
||||
background: #ffc156;
|
||||
border: 1px solid #C1C1C1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.orderItems button{
|
||||
color: white;
|
||||
width: auto;
|
||||
height: 40px;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
font-size: 36px;
|
||||
position: relative;
|
||||
left: 85%;
|
||||
top: 73%;
|
||||
transform: translate(-70%, 0);
|
||||
background: #ff8400;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
/* change the link color */
|
||||
.navbar-custom .navbar-nav .nav-link {
|
||||
color: white;
|
||||
font-family: 'Antipasto Pro', sans-serif;
|
||||
}
|
||||
|
||||
@media (max-width: 550px){
|
||||
.nameItem{
|
||||
font-size: 12px;
|
||||
}
|
||||
.deleteItem{
|
||||
font-size: 12px;
|
||||
}
|
||||
.priceItem{
|
||||
font-size: 12px;
|
||||
}
|
||||
.orderItem img{
|
||||
height: 120px;
|
||||
width: auto;
|
||||
}
|
||||
.orderItems button {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
@media(max-width: 500px){
|
||||
header{
|
||||
flex-direction: column;
|
||||
}
|
||||
#mainPage{
|
||||
margin-top: 0px;
|
||||
}
|
||||
#leftPart a{
|
||||
font-size: 12px;
|
||||
text-align: left;
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
.logo img{
|
||||
margin-top: 10px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#siteName{
|
||||
font-size: 14px;
|
||||
margin-top: 24px !important;
|
||||
}
|
||||
#profile li{
|
||||
font-size: 6px !important;
|
||||
}
|
||||
#profile ul{
|
||||
padding-left: 6px;
|
||||
}
|
||||
#activeOrders{
|
||||
font-size: 8px !important;
|
||||
}
|
||||
footer{
|
||||
font-size: 8px !important;
|
||||
}
|
||||
.socialMedia img{
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
#Items {
|
||||
columns: 1;
|
||||
}
|
||||
#textIphone{
|
||||
font-size: 10px;
|
||||
}
|
||||
#specialText{
|
||||
font-size: 12px;
|
||||
}
|
||||
#saleText{
|
||||
font-size: 12px;
|
||||
}
|
||||
#salePrice{
|
||||
font-size: 12px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: 700px){
|
||||
.firstPart img{
|
||||
width:80px !important;
|
||||
height: auto;
|
||||
}
|
||||
.firstPart figcaption{
|
||||
font-size: 8px;
|
||||
}
|
||||
#textIphone{
|
||||
font-size: 12px;
|
||||
}
|
||||
#specialText{
|
||||
font-size: 14px;
|
||||
}
|
||||
#saleText{
|
||||
font-size: 16px;
|
||||
}
|
||||
#salePrice{
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
@media(max-width: 600px){
|
||||
.firstPart img{
|
||||
width:60px !important;
|
||||
height: auto;
|
||||
}
|
||||
.firstPart figcaption{
|
||||
font-size: 6px;
|
||||
}
|
||||
}
|
||||
@media(max-width: 800px){
|
||||
#profile li{
|
||||
font-size: 12px;
|
||||
}
|
||||
#activeOrders{
|
||||
font-size: 12px;
|
||||
}
|
||||
#avatar{
|
||||
width: 110px;
|
||||
}
|
||||
#profile ul{
|
||||
padding-left: 6px;
|
||||
}
|
||||
.socialMedia img{
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
.firstPart img{
|
||||
width:90px;
|
||||
height: auto;
|
||||
}
|
||||
.firstPart figcaption{
|
||||
font-size: 10px;
|
||||
}
|
||||
footer{
|
||||
font-size: 12px;
|
||||
}
|
||||
.navbar-toggler{
|
||||
margin-top: 10px !important;
|
||||
}
|
||||
#Items {
|
||||
columns: 1;
|
||||
}
|
||||
}
|
||||
@media(max-width: 900px){
|
||||
.firstPart img{
|
||||
width:100px;
|
||||
height: auto;
|
||||
}
|
||||
.firstPart figcaption{
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
7
front/vite.config.js
Normal file
7
front/vite.config.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()]
|
||||
})
|
Loading…
x
Reference in New Issue
Block a user