mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-29 10:24:20 +01:00
stock (wip)
This commit is contained in:
parent
a5a45ee1ce
commit
f21a68593a
@ -16,6 +16,7 @@ import { CouponInput } from '../coupon/coupon-input';
|
||||
import { Coupon } from '../../models/coupon';
|
||||
import { computePriceWithCoupon } from '../../lib/coupon';
|
||||
import noImage from '../../../../images/no_image.png';
|
||||
import Switch from 'react-switch';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -112,6 +113,13 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
|
||||
return cart && cart.order_items_attributes.length === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle product offer
|
||||
*/
|
||||
const onSwitch = (product, checked: boolean) => {
|
||||
console.log('Offer ', product.orderable_name, ': ', checked);
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply coupon to current cart
|
||||
*/
|
||||
@ -162,6 +170,21 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
|
||||
<i className="fa fa-trash" />
|
||||
</FabButton>
|
||||
</div>
|
||||
{isPrivileged() &&
|
||||
<div className='offer'>
|
||||
<label>
|
||||
<span>Offer the product</span>
|
||||
<Switch
|
||||
checked={item.is_offered}
|
||||
onChange={(checked) => onSwitch(item, checked)}
|
||||
width={40}
|
||||
height={19}
|
||||
uncheckedIcon={false}
|
||||
checkedIcon={false}
|
||||
handleDiameter={15} />
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
|
@ -41,8 +41,11 @@ export const FormSwitch = <TFieldValues, TContext extends object>({ id, label, t
|
||||
onChangeCb(val);
|
||||
}}
|
||||
checked={value as boolean || false}
|
||||
height={19}
|
||||
width={40}
|
||||
height={19}
|
||||
uncheckedIcon={false}
|
||||
checkedIcon={false}
|
||||
handleDiameter={15}
|
||||
ref={ref}
|
||||
disabled={typeof disabled === 'function' ? disabled(id) : disabled} />
|
||||
} />
|
||||
|
@ -9,6 +9,7 @@ import { StoreListHeader } from './store-list-header';
|
||||
import { AccordionItem } from './accordion-item';
|
||||
import { OrderItem } from './order-item';
|
||||
import { MemberSelect } from '../user/member-select';
|
||||
import { FabInput } from '../base/fab-input';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
|
@ -18,6 +18,7 @@ import ProductCategoryAPI from '../../api/product-category';
|
||||
import MachineAPI from '../../api/machine';
|
||||
import ProductAPI from '../../api/product';
|
||||
import { Plus } from 'phosphor-react';
|
||||
import { ProductStockForm } from './product-stock-form';
|
||||
|
||||
interface ProductFormProps {
|
||||
product: Product,
|
||||
@ -48,6 +49,7 @@ export const ProductForm: React.FC<ProductFormProps> = ({ product, title, onSucc
|
||||
const [isActivePrice, setIsActivePrice] = useState<boolean>(product.id && _.isFinite(product.amount) && product.amount > 0);
|
||||
const [productCategories, setProductCategories] = useState<selectOption[]>([]);
|
||||
const [machines, setMachines] = useState<checklistOption[]>([]);
|
||||
const [stockTab, setStockTab] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
ProductCategoryAPI.index().then(data => {
|
||||
@ -235,174 +237,183 @@ export const ProductForm: React.FC<ProductFormProps> = ({ product, title, onSucc
|
||||
</div>
|
||||
</header>
|
||||
<form className="product-form" onSubmit={onSubmit}>
|
||||
<div className="subgrid">
|
||||
<FormInput id="name"
|
||||
register={register}
|
||||
rules={{ required: true }}
|
||||
formState={formState}
|
||||
onChange={handleNameChange}
|
||||
label={t('app.admin.store.product_form.name')}
|
||||
className="span-7" />
|
||||
<FormInput id="sku"
|
||||
register={register}
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.sku')}
|
||||
className="span-3" />
|
||||
<div className='tabs'>
|
||||
<p className={!stockTab ? 'is-active' : ''} onClick={() => setStockTab(false)}>{t('app.admin.store.product_form.product_parameters')}</p>
|
||||
<p className={stockTab ? 'is-active' : ''} onClick={() => setStockTab(true)}>{t('app.admin.store.product_form.stock_management')}</p>
|
||||
</div>
|
||||
<div className="subgrid">
|
||||
<FormInput id="slug"
|
||||
register={register}
|
||||
rules={{ required: true }}
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.slug')}
|
||||
className='span-7' />
|
||||
<FormSwitch control={control}
|
||||
id="is_active"
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.is_show_in_store')}
|
||||
tooltip={t('app.admin.store.product_form.active_price_info')}
|
||||
className='span-3' />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div className="price-data">
|
||||
<div className="price-data-header">
|
||||
<h4 className='span-7'>{t('app.admin.store.product_form.price_and_rule_of_selling_product')}</h4>
|
||||
<FormSwitch control={control}
|
||||
id="is_active_price"
|
||||
label={t('app.admin.store.product_form.is_active_price')}
|
||||
defaultValue={isActivePrice}
|
||||
onChange={toggleIsActivePrice}
|
||||
className='span-3' />
|
||||
</div>
|
||||
{isActivePrice && <div className="price-data-content">
|
||||
<FormInput id="amount"
|
||||
type="number"
|
||||
{stockTab
|
||||
? <ProductStockForm product={product} control={control} onError={onError} onSuccess={onSuccess} />
|
||||
: <section>
|
||||
<div className="subgrid">
|
||||
<FormInput id="name"
|
||||
register={register}
|
||||
rules={{ required: true, min: 0.01 }}
|
||||
step={0.01}
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.price')} />
|
||||
<FormInput id="quantity_min"
|
||||
type="number"
|
||||
rules={{ required: true }}
|
||||
formState={formState}
|
||||
onChange={handleNameChange}
|
||||
label={t('app.admin.store.product_form.name')}
|
||||
className="span-7" />
|
||||
<FormInput id="sku"
|
||||
register={register}
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.quantity_min')} />
|
||||
</div>}
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h4>{t('app.admin.store.product_form.product_images')}</h4>
|
||||
<FabAlert level="warning">
|
||||
<HtmlTranslate trKey="app.admin.store.product_form.product_images_info" />
|
||||
</FabAlert>
|
||||
<div className="product-images">
|
||||
<div className="list">
|
||||
{output.product_images_attributes.map((image, i) => (
|
||||
<FormImageUpload key={i}
|
||||
defaultImage={image}
|
||||
id={`product_images_attributes[${i}]`}
|
||||
accept="image/*"
|
||||
size="small"
|
||||
register={register}
|
||||
setValue={setValue}
|
||||
formState={formState}
|
||||
className={image._destroy ? 'hidden' : ''}
|
||||
mainOption={true}
|
||||
onFileRemove={handleRemoveProductImage(i)}
|
||||
onFileIsMain={handleSetMainImage(i)}
|
||||
/>
|
||||
))}
|
||||
label={t('app.admin.store.product_form.sku')}
|
||||
className="span-3" />
|
||||
</div>
|
||||
<div className="subgrid">
|
||||
<FormInput id="slug"
|
||||
register={register}
|
||||
rules={{ required: true }}
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.slug')}
|
||||
className='span-7' />
|
||||
<FormSwitch control={control}
|
||||
id="is_active"
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.is_show_in_store')}
|
||||
tooltip={t('app.admin.store.product_form.active_price_info')}
|
||||
className='span-3' />
|
||||
</div>
|
||||
<FabButton
|
||||
onClick={addProductImage}
|
||||
className='is-info'
|
||||
icon={<Plus size={24} />}>
|
||||
{t('app.admin.store.product_form.add_product_image')}
|
||||
</FabButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h4>{t('app.admin.store.product_form.assigning_category')}</h4>
|
||||
<FabAlert level="warning">
|
||||
<HtmlTranslate trKey="app.admin.store.product_form.assigning_category_info" />
|
||||
</FabAlert>
|
||||
<FormSelect options={productCategories}
|
||||
control={control}
|
||||
id="product_category_id"
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.linking_product_to_category')} />
|
||||
</div>
|
||||
<div className="price-data">
|
||||
<div className="header-switch">
|
||||
<h4 className='span-7'>{t('app.admin.store.product_form.price_and_rule_of_selling_product')}</h4>
|
||||
<FormSwitch control={control}
|
||||
id="is_active_price"
|
||||
label={t('app.admin.store.product_form.is_active_price')}
|
||||
defaultValue={isActivePrice}
|
||||
onChange={toggleIsActivePrice}
|
||||
className='span-3' />
|
||||
</div>
|
||||
{isActivePrice && <div className="price-data-content">
|
||||
<FormInput id="amount"
|
||||
type="number"
|
||||
register={register}
|
||||
rules={{ required: true, min: 0.01 }}
|
||||
step={0.01}
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.price')} />
|
||||
<FormInput id="quantity_min"
|
||||
type="number"
|
||||
rules={{ required: true }}
|
||||
register={register}
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.quantity_min')} />
|
||||
</div>}
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h4>{t('app.admin.store.product_form.assigning_machines')}</h4>
|
||||
<FabAlert level="warning">
|
||||
<HtmlTranslate trKey="app.admin.store.product_form.assigning_machines_info" />
|
||||
</FabAlert>
|
||||
<FormChecklist options={machines}
|
||||
<div>
|
||||
<h4>{t('app.admin.store.product_form.product_images')}</h4>
|
||||
<FabAlert level="warning">
|
||||
<HtmlTranslate trKey="app.admin.store.product_form.product_images_info" />
|
||||
</FabAlert>
|
||||
<div className="product-images">
|
||||
<div className="list">
|
||||
{output.product_images_attributes.map((image, i) => (
|
||||
<FormImageUpload key={i}
|
||||
defaultImage={image}
|
||||
id={`product_images_attributes[${i}]`}
|
||||
accept="image/*"
|
||||
size="small"
|
||||
register={register}
|
||||
setValue={setValue}
|
||||
formState={formState}
|
||||
className={image._destroy ? 'hidden' : ''}
|
||||
mainOption={true}
|
||||
onFileRemove={handleRemoveProductImage(i)}
|
||||
onFileIsMain={handleSetMainImage(i)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<FabButton
|
||||
onClick={addProductImage}
|
||||
className='is-info'
|
||||
icon={<Plus size={24} />}>
|
||||
{t('app.admin.store.product_form.add_product_image')}
|
||||
</FabButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h4>{t('app.admin.store.product_form.assigning_category')}</h4>
|
||||
<FabAlert level="warning">
|
||||
<HtmlTranslate trKey="app.admin.store.product_form.assigning_category_info" />
|
||||
</FabAlert>
|
||||
<FormSelect options={productCategories}
|
||||
control={control}
|
||||
id="machine_ids"
|
||||
formState={formState} />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h4>{t('app.admin.store.product_form.product_description')}</h4>
|
||||
<FabAlert level="warning">
|
||||
<HtmlTranslate trKey="app.admin.store.product_form.product_description_info" />
|
||||
</FabAlert>
|
||||
<FormRichText control={control}
|
||||
heading
|
||||
bulletList
|
||||
blockquote
|
||||
link
|
||||
limit={6000}
|
||||
id="description" />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h4>{t('app.admin.store.product_form.product_files')}</h4>
|
||||
<FabAlert level="warning">
|
||||
<HtmlTranslate trKey="app.admin.store.product_form.product_files_info" />
|
||||
</FabAlert>
|
||||
<div className="product-documents">
|
||||
<div className="list">
|
||||
{output.product_files_attributes.map((file, i) => (
|
||||
<FormFileUpload key={i}
|
||||
defaultFile={file}
|
||||
id={`product_files_attributes[${i}]`}
|
||||
accept="application/pdf"
|
||||
register={register}
|
||||
setValue={setValue}
|
||||
formState={formState}
|
||||
className={file._destroy ? 'hidden' : ''}
|
||||
onFileRemove={handleRemoveProductFile(i)}/>
|
||||
))}
|
||||
id="product_category_id"
|
||||
formState={formState}
|
||||
label={t('app.admin.store.product_form.linking_product_to_category')} />
|
||||
</div>
|
||||
<FabButton
|
||||
onClick={addProductFile}
|
||||
className='is-info'
|
||||
icon={<Plus size={24} />}>
|
||||
{t('app.admin.store.product_form.add_product_file')}
|
||||
</FabButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="main-actions">
|
||||
<FabButton type="submit" className="main-action-btn">{t('app.admin.store.product_form.save')}</FabButton>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h4>{t('app.admin.store.product_form.assigning_machines')}</h4>
|
||||
<FabAlert level="warning">
|
||||
<HtmlTranslate trKey="app.admin.store.product_form.assigning_machines_info" />
|
||||
</FabAlert>
|
||||
<FormChecklist options={machines}
|
||||
control={control}
|
||||
id="machine_ids"
|
||||
formState={formState} />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h4>{t('app.admin.store.product_form.product_description')}</h4>
|
||||
<FabAlert level="warning">
|
||||
<HtmlTranslate trKey="app.admin.store.product_form.product_description_info" />
|
||||
</FabAlert>
|
||||
<FormRichText control={control}
|
||||
heading
|
||||
bulletList
|
||||
blockquote
|
||||
link
|
||||
limit={6000}
|
||||
id="description" />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<h4>{t('app.admin.store.product_form.product_files')}</h4>
|
||||
<FabAlert level="warning">
|
||||
<HtmlTranslate trKey="app.admin.store.product_form.product_files_info" />
|
||||
</FabAlert>
|
||||
<div className="product-documents">
|
||||
<div className="list">
|
||||
{output.product_files_attributes.map((file, i) => (
|
||||
<FormFileUpload key={i}
|
||||
defaultFile={file}
|
||||
id={`product_files_attributes[${i}]`}
|
||||
accept="application/pdf"
|
||||
register={register}
|
||||
setValue={setValue}
|
||||
formState={formState}
|
||||
className={file._destroy ? 'hidden' : ''}
|
||||
onFileRemove={handleRemoveProductFile(i)}/>
|
||||
))}
|
||||
</div>
|
||||
<FabButton
|
||||
onClick={addProductFile}
|
||||
className='is-info'
|
||||
icon={<Plus size={24} />}>
|
||||
{t('app.admin.store.product_form.add_product_file')}
|
||||
</FabButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="main-actions">
|
||||
<FabButton type="submit" className="main-action-btn">{t('app.admin.store.product_form.save')}</FabButton>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
|
@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import { Product } from '../../models/product';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Control } from 'react-hook-form';
|
||||
import { FormSwitch } from '../form/form-switch';
|
||||
|
||||
interface ProductStockFormProps {
|
||||
product: Product,
|
||||
control: Control,
|
||||
onSuccess: (product: Product) => void,
|
||||
onError: (message: string) => void,
|
||||
}
|
||||
|
||||
/**
|
||||
* Form tab to manage product's stock
|
||||
*/
|
||||
export const ProductStockForm: React.FC<ProductStockFormProps> = ({ product, control, onError, onSuccess }) => {
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
/**
|
||||
* Toggle stock threshold
|
||||
*/
|
||||
const toggleStockThreshold = (checked: boolean) => {
|
||||
console.log('Stock threshold:', checked);
|
||||
};
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h4>Stock à jour <span>00/00/0000 - 00H30</span></h4>
|
||||
<div></div>
|
||||
<hr />
|
||||
|
||||
<div className="header-switch">
|
||||
<h4 className='span-7'>{t('app.admin.store.product_stock_form.low_stock_threshold')}</h4>
|
||||
<FormSwitch control={control}
|
||||
id="is_active_threshold"
|
||||
label={t('app.admin.store.product_stock_form.toggle_stock_threshold')}
|
||||
defaultValue={false}
|
||||
onChange={toggleStockThreshold}
|
||||
className='span-3' />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
@ -251,7 +251,7 @@ const Products: React.FC<ProductsProps> = ({ onSuccess, onError }) => {
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
<FabButton onClick={applyFilters} className="is-info">{t('app.admin.store.products.filter_apply')}</FabButton>
|
||||
<FabButton onClick={() => setUpdate(true)} className="is-info">{t('app.admin.store.products.filter_apply')}</FabButton>
|
||||
</div>
|
||||
</AccordionItem>
|
||||
|
||||
@ -269,7 +269,7 @@ const Products: React.FC<ProductsProps> = ({ onSuccess, onError }) => {
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
<FabButton onClick={applyFilters} className="is-info">{t('app.admin.store.products.filter_apply')}</FabButton>
|
||||
<FabButton onClick={() => setUpdate(true)} className="is-info">{t('app.admin.store.products.filter_apply')}</FabButton>
|
||||
</div>
|
||||
</AccordionItem>
|
||||
</div>
|
||||
|
@ -13,6 +13,7 @@ import { StoreProductItem } from './store-product-item';
|
||||
import useCart from '../../hooks/use-cart';
|
||||
import { emitCustomEvent } from 'react-custom-events';
|
||||
import { User } from '../../models/user';
|
||||
import { Order } from '../../models/order';
|
||||
import { AccordionItem } from './accordion-item';
|
||||
import { StoreListHeader } from './store-list-header';
|
||||
|
||||
@ -20,6 +21,7 @@ declare const Application: IApplication;
|
||||
|
||||
interface StoreProps {
|
||||
onError: (message: string) => void,
|
||||
onSuccess: (message: string) => void,
|
||||
currentUser: User,
|
||||
}
|
||||
/**
|
||||
@ -31,7 +33,7 @@ interface StoreProps {
|
||||
/**
|
||||
* This component shows public store
|
||||
*/
|
||||
const Store: React.FC<StoreProps> = ({ onError, currentUser }) => {
|
||||
const Store: React.FC<StoreProps> = ({ onError, onSuccess, currentUser }) => {
|
||||
const { t } = useTranslation('public');
|
||||
|
||||
const { cart, setCart } = useCart(currentUser);
|
||||
@ -138,6 +140,14 @@ const Store: React.FC<StoreProps> = ({ onError, currentUser }) => {
|
||||
console.log('Display in stock only:', checked);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add product to the cart
|
||||
*/
|
||||
const addToCart = (cart: Order) => {
|
||||
setCart(cart);
|
||||
onSuccess(t('app.public.store.add_to_cart_success'));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="store">
|
||||
<ul className="breadcrumbs">
|
||||
@ -224,7 +234,7 @@ const Store: React.FC<StoreProps> = ({ onError, currentUser }) => {
|
||||
/>
|
||||
<div className="products-grid">
|
||||
{products.map((product) => (
|
||||
<StoreProductItem key={product.id} product={product} cart={cart} onSuccessAddProductToCart={setCart} />
|
||||
<StoreProductItem key={product.id} product={product} cart={cart} onSuccessAddProductToCart={addToCart} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@ -253,7 +263,7 @@ const StoreWrapper: React.FC<StoreProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
Application.Components.component('store', react2angular(StoreWrapper, ['onError', 'currentUser']));
|
||||
Application.Components.component('store', react2angular(StoreWrapper, ['onError', 'onSuccess', 'currentUser']));
|
||||
|
||||
interface ActiveCategory {
|
||||
id: number,
|
||||
|
@ -55,6 +55,24 @@
|
||||
background-color: var(--gray-soft-light);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
.offer {
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.8rem 1.6rem;
|
||||
border: 1px solid var(--gray-soft-dark);
|
||||
border-radius: var(--border-radius);
|
||||
label {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
@include text-base;
|
||||
cursor: pointer;
|
||||
span { margin-right: 0.8rem; }
|
||||
}
|
||||
}
|
||||
.price,
|
||||
.total {
|
||||
min-width: 10rem;
|
||||
@ -158,7 +176,9 @@
|
||||
justify-content: center;
|
||||
text-transform: uppercase;
|
||||
&:hover {
|
||||
color: var(--gray-soft-lightest);
|
||||
opacity: 0.75;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@
|
||||
background-color: var(--information-lightest);
|
||||
color: var(--information);
|
||||
border: 1px solid var(--information);
|
||||
border-radius: 8px;
|
||||
border-radius: var(--border-radius);
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
line-height: 1.2em;
|
||||
|
@ -1,5 +1,26 @@
|
||||
.product-form {
|
||||
grid-column: 2 / -2;
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
p {
|
||||
flex: 1;
|
||||
margin-bottom: 4rem;
|
||||
padding: 0.8rem;
|
||||
text-align: center;
|
||||
color: var(--main);
|
||||
border-bottom: 1px solid var(--gray-soft-dark);
|
||||
&.is-active {
|
||||
color: var(--gray-hard-dark);
|
||||
border: 1px solid var(--gray-soft-dark);
|
||||
border-bottom: none;
|
||||
border-radius: var(--border-radius-sm) var(--border-radius-sm) 0 0;
|
||||
}
|
||||
&:hover { cursor: pointer; }
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0 0 2.4rem;
|
||||
@include title-base;
|
||||
@ -30,7 +51,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.price-data-header {
|
||||
.header-switch {
|
||||
@include grid-col(10);
|
||||
gap: 3.2rem;
|
||||
align-items: center;
|
||||
|
@ -123,6 +123,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
width: 100%;
|
||||
min-height: 4rem;
|
||||
padding: 0 0.8rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
border: 1px solid var(--gray-soft-dark);
|
||||
border-radius: var(--border-radius-sm);
|
||||
@include text-base;
|
||||
}
|
||||
|
||||
button {
|
||||
opacity: 100;
|
||||
margin-top: 0.8rem;
|
||||
|
@ -1964,6 +1964,8 @@ en:
|
||||
edit_product:
|
||||
successfully_updated: "The product has been updated."
|
||||
product_form:
|
||||
product_parameters: "Product parameters"
|
||||
stock_management: "Stock management"
|
||||
name: "Name of product"
|
||||
sku: "Reference product (SKU)"
|
||||
slug: "Name of URL"
|
||||
@ -1987,6 +1989,9 @@ en:
|
||||
product_images_info: "<strong>Advice</strong></br>We advise you to use a square format, jpg or png, for jpgs, please use white for the background colour. The main visual will be the visual presented first in the product sheet."
|
||||
add_product_image: "Add an image"
|
||||
save: "Save"
|
||||
product_stock_form:
|
||||
low_stock_threshold: "Define a low stock threshold"
|
||||
toggle_stock_threshold: "Activate stock threshold"
|
||||
orders:
|
||||
heading: "Orders"
|
||||
create_order: "Create an order"
|
||||
|
@ -383,6 +383,7 @@ en:
|
||||
store:
|
||||
fablab_store: "FabLab Store"
|
||||
unexpected_error_occurred: "An unexpected error occurred. Please try again later."
|
||||
add_to_cart_success: "Product added to the cart."
|
||||
products:
|
||||
all_products: "All the products"
|
||||
filter: "Filter"
|
||||
|
Loading…
Reference in New Issue
Block a user