From b939d94dc42fb4e1f94a1ea4750b6968736bdad4 Mon Sep 17 00:00:00 2001 From: Victor Turgeon <76506447+Medenos@users.noreply.github.com> Date: Mon, 31 Oct 2022 12:11:18 -0700 Subject: [PATCH] Image preview and images for items (wip) --- .../Controllers/ProductController.cs | 23 ++++++-- .../GrossesMitainesAPI/Models/Product.cs | 4 ++ .../src/components/Ajouter.js | 53 +++++++++++++++---- .../src/stylesheets/site.css | 10 ++++ 4 files changed, 78 insertions(+), 12 deletions(-) diff --git a/GrossesMitaines/GrossesMitainesAPI/Controllers/ProductController.cs b/GrossesMitaines/GrossesMitainesAPI/Controllers/ProductController.cs index 0a922bc..a09f78c 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Controllers/ProductController.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Controllers/ProductController.cs @@ -20,21 +20,23 @@ using GrossesMitainesAPI.Services; /// qui sera effectuée dans les 10 secondes après /// l'éxécution d'une modification de la BD. /// -[EnableCors("_myAllowSpecificOrigins"), ApiController, Route("api/[controller]"), +[EnableCors("_myAllowSpecificOrigins"), ApiController, Route("api/[controller]"), Authorize(AuthenticationSchemes = "Identity.Application")] public class ProductController : ControllerBase { #region DI Fields private readonly ILogger _logger; private readonly InventoryContext _context; private readonly DatabaseCacheService _cache; + private readonly IWebHostEnvironment _hostEnvironment; #endregion #region Ctor - public ProductController(ILogger logger, InventoryContext context, DatabaseCacheService cache) { + public ProductController(ILogger logger, InventoryContext context, DatabaseCacheService cache, IWebHostEnvironment hostEnvironment) { _logger = logger; _context = context; _cache = cache; + _hostEnvironment = hostEnvironment; } #endregion @@ -55,10 +57,13 @@ public class ProductController : ControllerBase { } [EnableCors("_myAllowSpecificOrigins"), HttpPost(Name = "Product")] - public ActionResult Post(Product prod) { + public async Task> Post(Product prod) { if (prod.Price <= prod.PromoPrice) prod.PromoPrice = prod.Price - 0.01M; try { + if (prod.ImageFile != null) + prod.ImageName = await SaveImage(prod.ImageFile); + _context.Products.Add(prod); _context.SaveChanges(); } @@ -99,4 +104,16 @@ public class ProductController : ControllerBase { } #endregion + + #region UtilityMethods + private async Task SaveImage(IFormFile imageFile) { + string imageName = new String(Path.GetFileNameWithoutExtension(imageFile.FileName).Take(10).ToArray()).Replace(' ', '-'); + imageName = imageName + DateTime.Now.ToString("yymmssfff") + Path.GetExtension(imageFile.FileName); + var imagePath = Path.Combine(_hostEnvironment.ContentRootPath, "Images", imageName); + using (var fileStream = new FileStream(imagePath, FileMode.Create)) { + await imageFile.CopyToAsync(fileStream); + } + return imageName; + } + #endregion } \ No newline at end of file diff --git a/GrossesMitaines/GrossesMitainesAPI/Models/Product.cs b/GrossesMitaines/GrossesMitainesAPI/Models/Product.cs index 4f72503..d9709f0 100644 --- a/GrossesMitaines/GrossesMitainesAPI/Models/Product.cs +++ b/GrossesMitaines/GrossesMitainesAPI/Models/Product.cs @@ -1,5 +1,6 @@ using Microsoft.Data.SqlClient.Server; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace GrossesMitainesAPI.Models; @@ -31,4 +32,7 @@ public class Product { public DateTime? LastSale { get; set; } public DateTime? LastHit { get; set; } public string? ImageName { get; set; } // Base pour sortir les images ({ImageName}.jpg , {ImageName}_thumbnail.jpg, etc...) + + [NotMapped] + public IFormFile? ImageFile { get; set; }  } \ No newline at end of file diff --git a/GrossesMitaines/grosses-mitaines-ui/src/components/Ajouter.js b/GrossesMitaines/grosses-mitaines-ui/src/components/Ajouter.js index c905e52..ee2f5db 100644 --- a/GrossesMitaines/grosses-mitaines-ui/src/components/Ajouter.js +++ b/GrossesMitaines/grosses-mitaines-ui/src/components/Ajouter.js @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { Dropdown } from "react-bootstrap"; import { Button } from "react-bootstrap"; @@ -12,14 +12,36 @@ const Ajouter = ({ onCreation }) => { const [price, setPrice] = useState(""); const [promoPrice, setPromoPrice] = useState(""); const [quantity, setQuantity] = useState(""); - const [imageName, setImageName] = useState("sqdc.jpg"); const [status, setStatusValue] = useState(0); + const [imageFile, setImage] = useState(null); + const [imageUrl, setImageUrl] = useState(null); + + + useEffect(() => { + + if (imageFile) + setImageUrl(URL.createObjectURL(imageFile)); + else + setImageUrl(null); + + }, [imageFile]); + const handleSubmit = (e) => { e.preventDefault(); // Empêcher de reloader la page au submit. // Appeler le comportement onCreation - onCreation({ title, description, category, price, promoPrice, quantity, imageName, status }); + onCreation({ + title: title, + description: description, + category: category, + price: price, + promoPrice: promoPrice, + quantity: quantity, + imageFile: imageFile, + imageName: "noName.jpg", + status: status + }); // Reset les états du formulaire. setTitle(""); @@ -28,7 +50,15 @@ const Ajouter = ({ onCreation }) => { setPrice(""); setPromoPrice(""); setQuantity(""); - setImageName("sqdc.jpg"); + setImage(null); + setImageUrl(null); + } + + const handleImageChange = (e) => { + if (e.target.files && e.target.files[0]) + setImage(e.target.files[0]); + else + setImage(null); } return ( @@ -78,11 +108,16 @@ const Ajouter = ({ onCreation }) => { onChange={(e) => setQuantity(e.target.value)} />
- - setImageName(e.target.value)} /> + + handleImageChange(e)} /> + {imageUrl &&
+ +
} +
diff --git a/GrossesMitaines/grosses-mitaines-ui/src/stylesheets/site.css b/GrossesMitaines/grosses-mitaines-ui/src/stylesheets/site.css index 8cdb491..30c2e38 100644 --- a/GrossesMitaines/grosses-mitaines-ui/src/stylesheets/site.css +++ b/GrossesMitaines/grosses-mitaines-ui/src/stylesheets/site.css @@ -543,6 +543,16 @@ html { border-radius: 5px; } +.img-preview-container{ + margin-top: 15px; + display:flex; +} + +.img-preview{ + margin:auto; + max-width: 90%; + max-height: 200px; +} .sorting-container { width: 20%;