L'importation d'image fonctionne. Il manque à faire fonctionner la modifiction et le delete avec.
5
.gitignore
vendored
@ -349,3 +349,8 @@ MigrationBackup/
|
|||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
.ionide/
|
.ionide/
|
||||||
|
|
||||||
|
# ignore les images pour ne pas avoir pleins d'image non-lié
|
||||||
|
GrossesMitaines/GrossesMitainesAPI/Images/*
|
||||||
|
!GrossesMitaines/GrossesMitainesAPI/Images/default.jpg
|
||||||
|
!GrossesMitaines/GrossesMitainesAPI/Images/default_thumbnail.jpg
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
using GrossesMitainesAPI.Data;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Cors;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace GrossesMitainesAPI.Controllers {
|
||||||
|
[EnableCors("_myAllowSpecificOrigins"), ApiController, Route("api/[controller]"), Authorize(AuthenticationSchemes = "Identity.Application")]
|
||||||
|
|
||||||
|
public class ImageController : ControllerBase {
|
||||||
|
|
||||||
|
|
||||||
|
private readonly InventoryContext _context;
|
||||||
|
private readonly IWebHostEnvironment _hostEnvironment;
|
||||||
|
private readonly ILogger<ProductController> _logger;
|
||||||
|
|
||||||
|
public ImageController(ILogger<ProductController> logger, InventoryContext context, IWebHostEnvironment hostEnvironment) {
|
||||||
|
_context = context;
|
||||||
|
_hostEnvironment = hostEnvironment;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[EnableCors("_myAllowSpecificOrigins"), HttpGet(Name = "Image"), AllowAnonymous]
|
||||||
|
public IActionResult Get(int id, bool? thumbnail = false) {
|
||||||
|
|
||||||
|
string path;
|
||||||
|
string filename;
|
||||||
|
string filetype;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var prod = _context.Products.Where(x => x.Id == id).First();
|
||||||
|
filename = prod.ImageName ?? throw new Exception("Unable to find product image name. Sending default.jpg instead...");
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
_logger.LogError(8, e.Message);
|
||||||
|
filename = "default.jpg";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
path = thumbnail == true ? Path.Combine(_hostEnvironment.ContentRootPath, "Images", Path.GetFileNameWithoutExtension(filename) + "_thumbnail" + Path.GetExtension(filename))
|
||||||
|
: Path.Combine(_hostEnvironment.ContentRootPath, "Images", filename);
|
||||||
|
|
||||||
|
if (!System.IO.File.Exists(path)) {
|
||||||
|
_logger.LogError(8, "Unable to find image. Sending default image instead...");
|
||||||
|
path = Path.Combine(_hostEnvironment.ContentRootPath, "Images", "default.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (Path.GetExtension(path)) {
|
||||||
|
case ".jpg":
|
||||||
|
case ".jpeg":
|
||||||
|
filetype = "image/jpeg";
|
||||||
|
break;
|
||||||
|
case ".png":
|
||||||
|
filetype = "image/png";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
filetype = "image/jpeg";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
byte[] imageData = System.IO.File.ReadAllBytes(path);
|
||||||
|
return File(imageData, filetype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
using GrossesMitainesAPI.Services;
|
using GrossesMitainesAPI.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
[EnableCors("_myAllowSpecificOrigins"), ApiController, Route("api/[controller]"),
|
[EnableCors("_myAllowSpecificOrigins"), ApiController, Route("api/[controller]"),
|
||||||
@ -24,14 +24,16 @@ public class InventoryController : Controller {
|
|||||||
private readonly ILogger<InventoryController> _logger;
|
private readonly ILogger<InventoryController> _logger;
|
||||||
private readonly InventoryContext _context;
|
private readonly InventoryContext _context;
|
||||||
private readonly DatabaseCacheService _cache;
|
private readonly DatabaseCacheService _cache;
|
||||||
|
private readonly IWebHostEnvironment _hostEnvironment;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Ctor
|
#region Ctor
|
||||||
public InventoryController(ILogger<InventoryController> logger, InventoryContext context, DatabaseCacheService cache) {
|
public InventoryController(ILogger<InventoryController> logger, InventoryContext context, DatabaseCacheService cache, IWebHostEnvironment hostEnvironment) {
|
||||||
_context = context;
|
_context = context;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
|
_hostEnvironment = hostEnvironment;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -117,6 +119,7 @@ public class InventoryController : Controller {
|
|||||||
|
|
||||||
foreach (ProductViewModel prod in ret.ToList()) {
|
foreach (ProductViewModel prod in ret.ToList()) {
|
||||||
if (yup && add < AMOUNT_SCROLL || (all.HasValue && all == true)) {
|
if (yup && add < AMOUNT_SCROLL || (all.HasValue && all == true)) {
|
||||||
|
|
||||||
lst.Add(prod);
|
lst.Add(prod);
|
||||||
add++;
|
add++;
|
||||||
}
|
}
|
||||||
@ -124,13 +127,15 @@ public class InventoryController : Controller {
|
|||||||
yup = true;
|
yup = true;
|
||||||
}
|
}
|
||||||
return lst;
|
return lst;
|
||||||
} catch (Exception e) {
|
}
|
||||||
|
catch (Exception e) {
|
||||||
if (iscache)
|
if (iscache)
|
||||||
_logger.LogError(e, "Erreur d'appel de cache.");
|
_logger.LogError(e, "Erreur d'appel de cache.");
|
||||||
else _logger.LogError(e, "Erreur d'appel d'API.");
|
else _logger.LogError(e, "Erreur d'appel d'API.");
|
||||||
return new List<ProductViewModel>();
|
return new List<ProductViewModel>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inventory/Delete => Décrémenter un produit. Va aller chercher directement dans la BD.
|
// Inventory/Delete => Décrémenter un produit. Va aller chercher directement dans la BD.
|
||||||
//[EnableCors("_myAllowSpecificOrigins"), HttpDelete(Name = "Inventory"), AllowAnonymous]
|
//[EnableCors("_myAllowSpecificOrigins"), HttpDelete(Name = "Inventory"), AllowAnonymous]
|
||||||
//public ActionResult<int> Delete(int? id) {
|
//public ActionResult<int> Delete(int? id) {
|
||||||
|
@ -10,7 +10,9 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using GrossesMitainesAPI.Services;
|
using GrossesMitainesAPI.Services;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -57,7 +59,7 @@ public class ProductController : ControllerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[EnableCors("_myAllowSpecificOrigins"), HttpPost(Name = "Product")]
|
[EnableCors("_myAllowSpecificOrigins"), HttpPost(Name = "Product")]
|
||||||
public async Task<ActionResult<ProductModel>> Post(ProductModel prod) {
|
public async Task<ActionResult<ProductModel>> Post([FromForm] ProductModel prod) {
|
||||||
if (prod.Price <= prod.PromoPrice)
|
if (prod.Price <= prod.PromoPrice)
|
||||||
prod.PromoPrice = prod.Price - 0.01M;
|
prod.PromoPrice = prod.Price - 0.01M;
|
||||||
try {
|
try {
|
||||||
@ -110,10 +112,33 @@ public class ProductController : ControllerBase {
|
|||||||
string imageName = new String(Path.GetFileNameWithoutExtension(imageFile.FileName).Take(10).ToArray()).Replace(' ', '-');
|
string imageName = new String(Path.GetFileNameWithoutExtension(imageFile.FileName).Take(10).ToArray()).Replace(' ', '-');
|
||||||
imageName = imageName + DateTime.Now.ToString("yymmssfff") + Path.GetExtension(imageFile.FileName);
|
imageName = imageName + DateTime.Now.ToString("yymmssfff") + Path.GetExtension(imageFile.FileName);
|
||||||
var imagePath = Path.Combine(_hostEnvironment.ContentRootPath, "Images", imageName);
|
var imagePath = Path.Combine(_hostEnvironment.ContentRootPath, "Images", imageName);
|
||||||
|
|
||||||
using (var fileStream = new FileStream(imagePath, FileMode.Create)) {
|
using (var fileStream = new FileStream(imagePath, FileMode.Create)) {
|
||||||
await imageFile.CopyToAsync(fileStream);
|
await imageFile.CopyToAsync(fileStream);
|
||||||
|
SaveImageThumbnail(fileStream, imageName);
|
||||||
}
|
}
|
||||||
return imageName;
|
return imageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SaveImageThumbnail(FileStream stream, string imageName) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const float maxSize = 200f;
|
||||||
|
Image image = Image.FromStream(stream);
|
||||||
|
|
||||||
|
//Choisi le bon ratio de division pour ne pas dépasser le 200px ni dans height ni dans width
|
||||||
|
float ratio = image.Width / (image.Height / maxSize) <= maxSize ? image.Height / maxSize : image.Width / maxSize;
|
||||||
|
|
||||||
|
Bitmap resize = new Bitmap(image, new Size((int)(image.Width / ratio), (int)(image.Height / ratio)));
|
||||||
|
string path = Path.Combine(_hostEnvironment.ContentRootPath, "Images", Path.GetFileNameWithoutExtension(imageName) + "_thumbnail" + Path.GetExtension(imageName));
|
||||||
|
resize.Save(path);
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
_logger.LogError(8, ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
@ -22,6 +22,7 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
BIN
GrossesMitaines/GrossesMitainesAPI/Images/default.jpg
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
GrossesMitaines/GrossesMitainesAPI/Images/default_thumbnail.jpg
Normal file
After Width: | Height: | Size: 3.0 KiB |
@ -13,6 +13,8 @@ public class ProductViewModel {
|
|||||||
public States Status { get; set; } = States.Available;
|
public States Status { get; set; } = States.Available;
|
||||||
public string? ImageName { get; set; }
|
public string? ImageName { get; set; }
|
||||||
|
|
||||||
|
public string? ImageData { get; set; }
|
||||||
|
|
||||||
public ProductViewModel(ProductModel prod) {
|
public ProductViewModel(ProductModel prod) {
|
||||||
this.Id = prod.Id;
|
this.Id = prod.Id;
|
||||||
this.Title = prod.Title;
|
this.Title = prod.Title;
|
||||||
|
Before Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 296 KiB |
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 330 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 410 KiB |
Before Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 270 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 917 KiB |
Before Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 875 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 67 KiB |
@ -0,0 +1,26 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
const FeaturedImage = ({ productId }) => {
|
||||||
|
|
||||||
|
const [imageSrc, setImageSrc] = useState("/images/default_thumbnail.jpg");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(`https://localhost:7292/api/Image?id=${productId}`)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => {
|
||||||
|
const imageUrl = URL.createObjectURL(blob);
|
||||||
|
setImageSrc(imageUrl);
|
||||||
|
})
|
||||||
|
},[]);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
className="featured-img"
|
||||||
|
src={imageSrc}
|
||||||
|
alt={productId + "_image"}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FeaturedImage;
|
@ -1,5 +1,7 @@
|
|||||||
import { Carousel } from "react-bootstrap";
|
import { Carousel } from "react-bootstrap";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import FeaturedImage from "./FeaturedImage";
|
||||||
|
|
||||||
const FeaturedList = ({ products }) => {
|
const FeaturedList = ({ products }) => {
|
||||||
if (products === null)
|
if (products === null)
|
||||||
return (<></>);
|
return (<></>);
|
||||||
@ -9,10 +11,7 @@ const FeaturedList = ({ products }) => {
|
|||||||
|
|
||||||
<Carousel.Item key={product.id} className="featured-itm">
|
<Carousel.Item key={product.id} className="featured-itm">
|
||||||
<Link key={product.id} to={`/morceaux/${product.id}`}>
|
<Link key={product.id} to={`/morceaux/${product.id}`}>
|
||||||
<img
|
<FeaturedImage productId={product.id}/>
|
||||||
className="featured-img"
|
|
||||||
src={`/images/${product.imageName}.jpg`}
|
|
||||||
/>
|
|
||||||
<Carousel.Caption className="featured-info">
|
<Carousel.Caption className="featured-info">
|
||||||
<h3>{product.title}</h3>
|
<h3>{product.title}</h3>
|
||||||
<p>{product.description}</p>
|
<p>{product.description}</p>
|
||||||
|
@ -1,13 +1,7 @@
|
|||||||
import { Card } from "react-bootstrap";
|
import { Card } from "react-bootstrap";
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
|
||||||
// public enum States {
|
|
||||||
// Available,
|
|
||||||
// BackOrder,
|
|
||||||
// Unavailable,
|
|
||||||
// Clearance,
|
|
||||||
// Promotion,
|
|
||||||
// Discontinued
|
|
||||||
// }
|
|
||||||
function renderStatus(statusCode) {
|
function renderStatus(statusCode) {
|
||||||
if (statusCode !== undefined) {
|
if (statusCode !== undefined) {
|
||||||
|
|
||||||
@ -62,7 +56,7 @@ function renderPrice(price, newPrice, status) {
|
|||||||
if (price !== undefined) {
|
if (price !== undefined) {
|
||||||
|
|
||||||
|
|
||||||
if (status != 3 && status != 4) {
|
if (status !== 3 && status !== 4) {
|
||||||
return (
|
return (
|
||||||
<Card.Text className="item-price-container">
|
<Card.Text className="item-price-container">
|
||||||
<span className="item-price">
|
<span className="item-price">
|
||||||
@ -87,12 +81,25 @@ function renderPrice(price, newPrice, status) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Item = ({ imageUrl, name, price, newPrice, status }) => {
|
const Item = ({ productId, name, price, newPrice, status }) => {
|
||||||
|
|
||||||
|
const [imageSrc, setImageSrc] = useState("/images/default_thumbnail.jpg");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(`https://localhost:7292/api/Image?id=${productId}&thumbnail=true`)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => {
|
||||||
|
const imageUrl = URL.createObjectURL(blob);
|
||||||
|
setImageSrc(imageUrl);
|
||||||
|
})
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
if (name !== undefined) {
|
if (name !== undefined) {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<Card className="item">
|
<Card className="item">
|
||||||
<Card.Img className="item-img" variant="top" src={`/images/${imageUrl}_thumbnail.jpg`} />
|
<Card.Img className="item-img" variant="top" src={imageSrc} />
|
||||||
<Card.Body className="item-info">
|
<Card.Body className="item-info">
|
||||||
<div className="item-name-container">
|
<div className="item-name-container">
|
||||||
<Card.Title className="item-name">
|
<Card.Title className="item-name">
|
||||||
|
@ -9,7 +9,8 @@ const ItemList = ({ items }) => {
|
|||||||
{items.length <= 0 && <p>Aucun morceaux à montrer...</p>}
|
{items.length <= 0 && <p>Aucun morceaux à montrer...</p>}
|
||||||
{items.map((item) =>
|
{items.map((item) =>
|
||||||
<Link key={item.id} className='item-link' to={`/morceaux/${item.id}`}>
|
<Link key={item.id} className='item-link' to={`/morceaux/${item.id}`}>
|
||||||
<Item imageUrl={item.imageName}
|
<Item
|
||||||
|
productId={item.id}
|
||||||
name={item.title}
|
name={item.title}
|
||||||
price={item.price}
|
price={item.price}
|
||||||
status={item.status}
|
status={item.status}
|
||||||
|
@ -20,14 +20,24 @@ const Inventaire = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleAddItem = async (morceau) => {
|
const handleAddItem = async (morceau) => {
|
||||||
|
|
||||||
|
console.log(morceau);
|
||||||
|
|
||||||
|
let formData = new FormData();
|
||||||
|
Object.keys(morceau).map((k) => {
|
||||||
|
formData.set(k,morceau[k]);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(formData);
|
||||||
|
|
||||||
const response = await fetch(`https://localhost:7292/api/Product`, {
|
const response = await fetch(`https://localhost:7292/api/Product`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
|
mode: 'cors',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'accept': 'application/json',
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify(morceau)
|
body: formData
|
||||||
})
|
})
|
||||||
|
|
||||||
const newMorceau = await response.json();
|
const newMorceau = await response.json();
|
||||||
@ -38,7 +48,7 @@ const Inventaire = () => {
|
|||||||
console.log("Ajout de l'item avec succès: \r\n" + newMorceau);
|
console.log("Ajout de l'item avec succès: \r\n" + newMorceau);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
console.log("Erreur de creation " + morceau);
|
console.log("Erreur de creation " + morceau.title);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteItem = async (id) => {
|
const handleDeleteItem = async (id) => {
|
||||||
|
@ -7,6 +7,7 @@ const MorceauDetail = () => {
|
|||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const [item, setItem] = useState({});
|
const [item, setItem] = useState({});
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [imageSrc, setImageSrc] = useState("/images/default_thumbnail.jpg");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Morceaux';
|
document.title = 'Morceaux';
|
||||||
@ -16,10 +17,25 @@ const MorceauDetail = () => {
|
|||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
setItem(json);
|
setItem(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fetchData();
|
fetchData();
|
||||||
|
|
||||||
|
fetch(`https://localhost:7292/api/Image?id=${id}`)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => {
|
||||||
|
const imageUrl = URL.createObjectURL(blob);
|
||||||
|
setImageSrc(imageUrl);
|
||||||
|
})
|
||||||
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
}, []);
|
||||||
|
|
||||||
function renderPrice(price, newPrice, status) {
|
function renderPrice(price, newPrice, status) {
|
||||||
if (price !== undefined) {
|
if (price !== undefined) {
|
||||||
if (status !== 3 && status !== 4) {
|
if (status !== 3 && status !== 4) {
|
||||||
@ -99,7 +115,7 @@ const MorceauDetail = () => {
|
|||||||
|
|
||||||
<div className="detail-container">
|
<div className="detail-container">
|
||||||
<div className="detail-container-left">
|
<div className="detail-container-left">
|
||||||
<img className="detail-image" alt="" src={`/images/${item.imageName}.jpg`} />
|
<img className="detail-image" alt="" src={imageSrc} />
|
||||||
<p className="detail-description">{item.description}</p>
|
<p className="detail-description">{item.description}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="detail-container-right">
|
<div className="detail-container-right">
|
||||||
|