Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Ajout Bloc Produit #60

Merged
merged 1 commit into from
Oct 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
338 changes: 303 additions & 35 deletions templates/backOffice/default/app/src/blocks/Product/Product.tsx
Original file line number Diff line number Diff line change
@@ -1,56 +1,324 @@
import { BlockModuleComponentProps, BlockPluginDefinition } from "../../types";
import {BlockModuleComponentProps, BlockPluginDefinition} from "../../types";

import React, { useState } from "react";
import { useProductByTitle,useProductsByIds } from "../../hooks/data";
import React, {useState} from "react";

export type BlockProductData = {
productId: string | null;
productList : string[],
};

export type BlockProductComponentProps =
BlockModuleComponentProps<BlockProductData>;
export type BlockProductComponentProps = BlockModuleComponentProps<BlockProductData>;

function BlockProductComponent({ data }: BlockProductComponentProps) {
const [query, setQuery] = useState<string>("");
function Product ({product, data, onUpdate}){

function removeFromList(productId: any){ //Fonction du bouton Supprimer
let newProductList = data.productList.filter(function(product){
return product != productId;
});
onUpdate({ ...data, productList: newProductList});
}
return (
<div className="BlockProduct">
{data.productId ? (
"TODO: SHOW PRODUCT THUMBNAIL"
) : (
<div>
<div className="mb-2 font-bold text-red-500">No assigned product</div>
<div className="relative">
<input
<div className="flex flex-row col-span-1 m-4 font-sans bg-gray-100 shadow-lg rounded-2xl">
<div className="w-full">
<div className="flex flex-col px-8 pb-2 bg-lime-100 rounded-2xl">
{(product.images.length > 0) ? (
<img className="w-full" src="" alt="image"/>
) : null}
<div className="pt-6 m-2 text-2xl font-bold">{product.i18n.title}</div>

<div className="self-end">
<span className="m-2 font-sans text-xl text-gray-600 place-self-end">{product.productSaleElements[0].price.untaxed} $</span>
<span className="m-2 text-xl font-bold text-gray-700 place-self-end">{product.productSaleElements[0].price.taxed} $</span>
</div>

<div className="py-4">
{product.categories.map(function(category){
return (
<span className="relative inline-flex px-3 py-1 font-sans text-xl font-semibold text-gray-700 bg-gray-200 rounded-full">
<p className="inline-block m-2">{category.i18n.title}</p>
</span>
);
})}
</div>
</div>
</div>
<a className="relative inline-block w-12 h-12 m-4 bg-red-400 rounded-full hover:text-black hover:bg-red-600" onClick={() => removeFromList(product.id)}>
<svg xmlns="http://www.w3.org/2000/svg" className="relative w-8 h-8 m-2" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</a>
</div>
)
}

function Filters({products, setCategoriesId, filters, setFilters}){

const [categories, setCategories] = useState<
Array<{
i18n: {
chapo: string,
description:string,
metaDescription: string,
metaKeywords: string,
metaTitle: string,
postsciptum: string,
title: string
},
id: number
visible: number
}>
>([])
const [activeCategories, setActiveCategories] = useState<
Array<{
i18n: {
chapo: string,
description:string,
metaDescription: string,
metaKeywords: string,
metaTitle: string,
postsciptum: string,
title: string
},
id: number
visible: number
}>
>([])

//Pour le chargement individuel des Catégories de Produit
//const productList = useProductsByIds(products.join(","));

function switchToActiveCategories(category){ //Ajoute une Catégorie aux Catégories qui trient les Produits
let valid = true;
if(activeCategories.length > 0){
activeCategories.map(function(activeCategory){ //Evite les Doublons dans la liste
if(activeCategory.id === category.id) {
valid = false;
}
})
}
if(valid){
let tempActiveCategories = activeCategories;
tempActiveCategories.push(category);
setCategories(categories.filter(function(categoryFromList){ //Retire la Catégorie de la liste Inactive
return categoryFromList.id != category.id;
}));
setActiveCategories(tempActiveCategories); //Replace la Catégorie dans la liste Active
let tempIdList = [];
tempActiveCategories.map(function(tempActiveCategory){ //Creation de la Liste d'ID de Categories
tempIdList.push(tempActiveCategory.id);
});
setCategoriesId(tempIdList);
}
}

function switchToCategories(activeCategory){ //Retire une Catégorie aux Catégories qui trient les Produits
let valid = true;
if(categories.length > 0){
categories.map(function(category){
if(activeCategory.id === category.id) { //Evite les Doublons dans la liste
valid = false;
}
})
}
if(valid){
let tempCategories = categories;
tempCategories.push(activeCategory);
setActiveCategories(activeCategories.filter(function(category){ //Retire la Catégorie de la liste Active
return activeCategory.id != category.id;
}));
setCategories(tempCategories); //Replace la Catégorie dans la liste Inactive
let tempIdList = [];
activeCategories.filter(function(category){ //Creation de la Liste d'ID de Categories
return activeCategory.id != category.id;
}).map(function(activeCategory){
tempIdList.push(activeCategory.id);
});
setCategoriesId(tempIdList);
}
}

products.data.map(function(product){ // LOAD CATEGORIES
product.categories.map(function(category){
let valid = true;
categories.map(function(existingCategory){
if(existingCategory.id === category.id) {
valid = false;
}
})
activeCategories.map(function(existingCategory){
if(existingCategory.id === category.id) {
valid = false;
}
})
if(valid){
categories.push(category);
}
})
})

return (
<div>
<div className="flex px-4 py-1 mx-12 my-6 bg-gray-100 rounded-3xl">

{filters ? (
<a className="relative self-center inline-block w-12 h-12 m-2 bg-green-300 rounded-full hover:text-black hover:bg-green-400" onClick={() => setFilters(!filters)}>
<svg xmlns="http://www.w3.org/2000/svg" className="w-10 h-10 m-2" viewBox="0 0 24 24" fill="currentColor">
<path fill-rule="evenodd" d="M3 3a1 1 0 011-1h12a1 1 0 011 1v3a1 1 0 01-.293.707L12 11.414V15a1 1 0 01-.293.707l-2 2A1 1 0 018 17v-5.586L3.293 6.707A1 1 0 013 6V3z" clip-rule="evenodd" />
</svg>
</a>
) : (
<a className="relative self-center inline-block w-12 h-12 m-2 bg-gray-300 rounded-full hover:text-black hover:bg-gray-400" onClick={() => setFilters(!filters) }>
<svg xmlns="http://www.w3.org/2000/svg" className="w-8 h-8 m-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
</svg>
</a>
)}

<div className="inline-flex flex-wrap rounded-full">
{categories.map(function(category){
return(
<span className="relative inline-flex px-3 py-1 m-2 font-sans text-xl font-semibold text-gray-700 bg-gray-200 rounded-full cursor-pointer hover:bg-gray-300" onClick={() => switchToActiveCategories(category)}>
<p className="inline-block m-2">{category.i18n.title}</p>
</span>
)
})}
{filters ? (
activeCategories.map(function(category){
return(
<span className="relative inline-flex px-3 py-1 m-2 font-sans text-xl font-semibold text-gray-700 bg-green-200 rounded-full cursor-pointer hover:bg-green-300" onClick={() => switchToCategories(category)}>
<p className="inline-block m-2">{category.i18n.title}</p>
</span>
)
})
) : (
activeCategories.map(function(category){
return(
<span className="relative inline-flex px-3 py-1 m-2 font-sans text-xl font-semibold text-gray-500 bg-gray-300 rounded-full cursor-not-allowed" onClick={() => setFilters(!filters)}>
<p className="inline-block m-2">{category.i18n.title}</p>
</span>
)
})
)}
</div>
</div>
</div>
)
}

function BlockProductComponent({ data, onUpdate }: BlockProductComponentProps) {

const [filters, setFilters] = useState<boolean>(false); //Activation du Filtre Catégorie (Bouton Entonnoir)
const [query, setQuery] = useState<string>(""); //Recherche par titres
const [categoriesId, setCategoriesId] = useState<Array<number>>([]); //Liste des Catégories choisies pour trier les Produits

function pushToList(data: BlockProductData, product: any){ //Ajoute un ID de Produit dans la liste des Produits selectionnés
onUpdate({ ...data, productList: [...data.productList, product.id]});
}

function sortProducts(product){ //Trie le produit en fonction des Catégories choisies
let valid = false
categoriesId.map(function(id){ //Pour chaque Catégories sélectionnées
return (
product.categories.map(function(category){ //Pour chaque Catégories affiliées produit
return (
(category.id == id) ? ( //Si les deux catégories sont les mêmes, valide l'affichage du Produit
valid = true
) : null
)
})
)
})
return valid;
}

let products = useProductByTitle(query); //Liste des Produits concernés par la recherche par titres

const productsElements = useProductsByIds(data.productList.join(",")); //Liste des Produits

let filteredProducts = null;

if(products.status === "success") { //Une fois la recherche des produits par titre abouttie
filteredProducts = products.data.filter(function(product){ //Retire les produits déjà sélectionnés
return !data.productList.some(productFromList => productFromList === product.id);
}
)}

return (

<div className="p-4 BlockProduct">
<div className="grid grid-cols-4 gap-2">

<div className="col-span-1">
<input
type="text"
value={query}
className="w-full"
className="w-full px-8 py-4 font-sans text-2xl"
placeholder="Find a product inside the catalog"
onChange={(e) => {
setQuery(e.target.value);
}}
/>
{query ? (
<ul className="border border-gray-400 divide-y divide-gray-300 top-full">
<li
onClick={() => {
setQuery("");
}}
className="px-4 py-1 cursor-pointer"
>
Product #1
</li>
<li className="px-4 py-1">Product #2</li>
<li className="px-4 py-1">Product #3</li>
/>
{filteredProducts ? ( //Affiche les choix par rapport à la recherche par titres
<ul className="font-sans text-2xl border border-gray-400 divide-y divide-gray-400 top-full">
{filteredProducts.map((product: any) =>
<li key={product.id}
onClick={() => pushToList(data, product)}
className="px-8 py-4 cursor-pointer hover:bg-gray-100">
{product.i18n.title}
</li>
)}
</ul>
) : null}
</div>
) : (
<ul className="font-sans text-2xl border border-gray-400 divide-y divide-gray-400 top-full">
<li className="px-8 py-4 hover:bg-gray-100">No Result</li>
</ul>
)}
</div>

<div className="col-span-3">
{(data.productList.length > 0) ? (
<div>
{(productsElements.status === "success") ? (
<div>
<Filters products={productsElements} setCategoriesId={setCategoriesId} filters={filters} setFilters={setFilters}/>
<div className="grid grid-cols-2 gap-2">
{(filters) ? ( //Bouton Entonnoir activé
productsElements.data.map((product: any) =>
sortProducts(product) ? ( //Filtre les produits
<Product product={product} data={data} onUpdate={onUpdate}/>
) : null
)
) : (
productsElements.data.map((product: any) =>
<Product product={product} data={data} onUpdate={onUpdate}/>
)
)}
</div>
</div>
) : ( //Tant que les produits ne sont pas chargés affiche :
<div className="p-10 m-2 font-sans text-2xl bg-cyan-100 rounded-2xl">
<div className="font-sans text-2xl">Chargement des Produits</div>
</div>
)}
</div>
) : ( //Si Aucun Produit sélectionné dans le Block
<div className="grid grid-cols-1 gap-2">
<div className="col-span-1">
<div className="p-10 m-4 font-sans shadow-lg bg-rose-100 rounded-2xl">
<p className="font-sans text-2xl">Veuillez Chercher et Choisir un Produit</p>
</div>
</div>
</div>
)}
</div>
)}
</div>
</div>
);
}

const initialData = {
productId: null,
const initialData: BlockProductData = {
productList: [],
};

const moduleType = {
Expand All @@ -67,7 +335,7 @@ const blockProduct: BlockPluginDefinition<BlockProductData> = {
},
description: {
default: "Display a product",
fr_FR: "Affiche un produit du catalogue",
fr_FR: "Affiche des produits du catalogue",
},
image: {
default: "https://source.unsplash.com/featured/300x250?nature&blockProduct",
Expand Down
Loading