mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-20 14:54:15 +01:00
(quality) refactored categories sorting + fix ts issues
This commit is contained in:
parent
3f08d831b9
commit
45bac88b26
@ -42,7 +42,7 @@ export const FabModal: React.FC<FabModalProps> = ({ title, isOpen, toggleModal,
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen}
|
||||
className={`fab-modal fab-modal-${width} ${className}`}
|
||||
className={`fab-modal fab-modal-${width} ${className || ''}`}
|
||||
overlayClassName="fab-modal-overlay"
|
||||
onRequestClose={toggleModal}>
|
||||
{closeButton && <FabButton className="modal-btn--close" onClick={toggleModal}>{t('app.shared.fab_modal.close')}</FabButton>}
|
||||
|
@ -95,7 +95,7 @@ export const StripeCardUpdate: React.FC<StripeCardUpdateProps> = ({ onSubmit, on
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} id="stripe-card" className={`stripe-card-update ${className}`}>
|
||||
<form onSubmit={handleSubmit} id="stripe-card" className={`stripe-card-update ${className || ''}`}>
|
||||
<CardElement options={cardOptions} />
|
||||
{children}
|
||||
</form>
|
||||
|
@ -69,7 +69,6 @@ export const ManageProductCategory: React.FC<ManageProductCategoryProps> = ({ pr
|
||||
<div className='manage-product-category'>
|
||||
{ toggleBtn() }
|
||||
<FabModal title={t(`app.admin.store.manage_product_category.${action}`)}
|
||||
className="fab-modal-lg"
|
||||
width={ModalSize.large}
|
||||
isOpen={isOpen}
|
||||
toggleModal={toggleModal}
|
||||
|
@ -10,6 +10,7 @@ import { HtmlTranslate } from '../../base/html-translate';
|
||||
import { IApplication } from '../../../models/application';
|
||||
import { Loader } from '../../base/loader';
|
||||
import { react2angular } from 'react2angular';
|
||||
import ProductLib from '../../../lib/product';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -54,18 +55,7 @@ const ProductCategories: React.FC<ProductCategoriesProps> = ({ onSuccess, onErro
|
||||
*/
|
||||
const refreshCategories = () => {
|
||||
ProductCategoryAPI.index().then(data => {
|
||||
// Map product categories by position
|
||||
const sortedCategories = data
|
||||
.filter(c => !c.parent_id)
|
||||
.sort((a, b) => a.position - b.position);
|
||||
const childrenCategories = data
|
||||
.filter(c => typeof c.parent_id === 'number')
|
||||
.sort((a, b) => b.position - a.position);
|
||||
childrenCategories.forEach(c => {
|
||||
const parentIndex = sortedCategories.findIndex(i => i.id === c.parent_id);
|
||||
sortedCategories.splice(parentIndex + 1, 0, c);
|
||||
});
|
||||
setProductCategories(sortedCategories);
|
||||
setProductCategories(new ProductLib().sortCategories(data));
|
||||
}).catch((error) => onError(error));
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import { SubmitHandler, useForm, useWatch } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import slugify from 'slugify';
|
||||
import _ from 'lodash';
|
||||
@ -19,6 +19,7 @@ import MachineAPI from '../../api/machine';
|
||||
import ProductAPI from '../../api/product';
|
||||
import { Plus } from 'phosphor-react';
|
||||
import { ProductStockForm } from './product-stock-form';
|
||||
import ProductLib from '../../lib/product';
|
||||
|
||||
interface ProductFormProps {
|
||||
product: Product,
|
||||
@ -53,18 +54,7 @@ export const ProductForm: React.FC<ProductFormProps> = ({ product, title, onSucc
|
||||
|
||||
useEffect(() => {
|
||||
ProductCategoryAPI.index().then(data => {
|
||||
// Map product categories by position
|
||||
const sortedCategories = data
|
||||
.filter(c => !c.parent_id)
|
||||
.sort((a, b) => a.position - b.position);
|
||||
const childrenCategories = data
|
||||
.filter(c => typeof c.parent_id === 'number')
|
||||
.sort((a, b) => b.position - a.position);
|
||||
childrenCategories.forEach(c => {
|
||||
const parentIndex = sortedCategories.findIndex(i => i.id === c.parent_id);
|
||||
sortedCategories.splice(parentIndex + 1, 0, c);
|
||||
});
|
||||
setProductCategories(buildSelectOptions(sortedCategories));
|
||||
setProductCategories(buildSelectOptions(new ProductLib().sortCategories(data)));
|
||||
}).catch(onError);
|
||||
MachineAPI.index({ disabled: false }).then(data => {
|
||||
setMachines(buildChecklistOptions(data));
|
||||
@ -111,10 +101,8 @@ export const ProductForm: React.FC<ProductFormProps> = ({ product, title, onSucc
|
||||
/**
|
||||
* Callback triggered when the form is submitted: process with the product creation or update.
|
||||
*/
|
||||
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
return handleSubmit((data: Product) => {
|
||||
saveProduct(data);
|
||||
})(event);
|
||||
const onSubmit: SubmitHandler<Product> = (data: Product) => {
|
||||
saveProduct(data);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -236,13 +224,13 @@ export const ProductForm: React.FC<ProductFormProps> = ({ product, title, onSucc
|
||||
<FabButton className="main-action-btn" onClick={handleSubmit(saveProduct)}>{t('app.admin.store.product_form.save')}</FabButton>
|
||||
</div>
|
||||
</header>
|
||||
<form className="product-form" onSubmit={onSubmit}>
|
||||
<form className="product-form" onSubmit={handleSubmit(onSubmit)}>
|
||||
<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>
|
||||
{stockTab
|
||||
? <ProductStockForm product={product} register={register} control={control} id="stock" onError={onError} onSuccess={onSuccess} />
|
||||
? <ProductStockForm product={product} register={register} control={control} formState={formState} onError={onError} onSuccess={onSuccess} />
|
||||
: <section>
|
||||
<div className="subgrid">
|
||||
<FormInput id="name"
|
||||
|
@ -12,6 +12,7 @@ import { FabButton } from '../base/fab-button';
|
||||
import { PencilSimple } from 'phosphor-react';
|
||||
import { FabModal, ModalSize } from '../base/fab-modal';
|
||||
import { ProductStockModal } from './product-stock-modal';
|
||||
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
||||
import { FabStateLabel } from '../base/fab-state-label';
|
||||
|
||||
interface ProductStockFormProps<TFieldValues, TContext extends object> {
|
||||
@ -26,7 +27,7 @@ interface ProductStockFormProps<TFieldValues, TContext extends object> {
|
||||
/**
|
||||
* Form tab to manage a product's stock
|
||||
*/
|
||||
export const ProductStockForm = <TFieldValues, TContext extends object> ({ product, register, control, formState, onError, onSuccess }: ProductStockFormProps<TFieldValues, TContext>) => {
|
||||
export const ProductStockForm = <TFieldValues extends FieldValues, TContext extends object> ({ product, register, control, formState, onError, onSuccess }: ProductStockFormProps<TFieldValues, TContext>) => {
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
const [activeThreshold, setActiveThreshold] = useState<boolean>(false);
|
||||
@ -197,12 +198,11 @@ export const ProductStockForm = <TFieldValues, TContext extends object> ({ produ
|
||||
</div>
|
||||
|
||||
<FabModal title={t('app.admin.store.product_stock_form.modal_title')}
|
||||
className="fab-modal-lg"
|
||||
width={ModalSize.large}
|
||||
isOpen={isOpen}
|
||||
toggleModal={toggleModal}
|
||||
closeButton>
|
||||
<ProductStockModal product={product} register={register} control={control} id="stock-modal" onError={onError} onSuccess={onSuccess} />
|
||||
<ProductStockModal product={product} register={register} control={control} formState={formState} onError={onError} onSuccess={onSuccess} />
|
||||
</FabModal>
|
||||
</section>
|
||||
);
|
||||
|
@ -6,6 +6,7 @@ import { Control, FormState } from 'react-hook-form/dist/types/form';
|
||||
import { FormSelect } from '../form/form-select';
|
||||
import { FormInput } from '../form/form-input';
|
||||
import { FabButton } from '../base/fab-button';
|
||||
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
||||
|
||||
type selectOption = { value: number, label: string };
|
||||
|
||||
@ -23,7 +24,7 @@ interface ProductStockModalProps<TFieldValues, TContext extends object> {
|
||||
*/
|
||||
// TODO: delete next eslint disable
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export const ProductStockModal = <TFieldValues, TContext extends object> ({ product, register, control, formState, onError, onSuccess }: ProductStockModalProps<TFieldValues, TContext>) => {
|
||||
export const ProductStockModal = <TFieldValues extends FieldValues, TContext extends object> ({ product, register, control, formState, onError, onSuccess }: ProductStockModalProps<TFieldValues, TContext>) => {
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
const [movement, setMovement] = useState<'in' | 'out'>('in');
|
||||
|
@ -14,6 +14,7 @@ import MachineAPI from '../../api/machine';
|
||||
import { AccordionItem } from './accordion-item';
|
||||
import { X } from 'phosphor-react';
|
||||
import { StoreListHeader } from './store-list-header';
|
||||
import ProductLib from '../../lib/product';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -52,18 +53,7 @@ const Products: React.FC<ProductsProps> = ({ onSuccess, onError }) => {
|
||||
});
|
||||
|
||||
ProductCategoryAPI.index().then(data => {
|
||||
// Map product categories by position
|
||||
const sortedCategories = data
|
||||
.filter(c => !c.parent_id)
|
||||
.sort((a, b) => a.position - b.position);
|
||||
const childrenCategories = data
|
||||
.filter(c => typeof c.parent_id === 'number')
|
||||
.sort((a, b) => b.position - a.position);
|
||||
childrenCategories.forEach(c => {
|
||||
const parentIndex = sortedCategories.findIndex(i => i.id === c.parent_id);
|
||||
sortedCategories.splice(parentIndex + 1, 0, c);
|
||||
});
|
||||
setProductCategories(sortedCategories);
|
||||
setProductCategories(new ProductLib().sortCategories(data));
|
||||
}).catch(onError);
|
||||
|
||||
MachineAPI.index({ disabled: false }).then(data => {
|
||||
|
@ -179,7 +179,7 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
|
||||
const userNetworks = new UserLib(user).getUserSocialNetworks();
|
||||
|
||||
return (
|
||||
<form className={`user-profile-form user-profile-form--${size} ${className}`} onSubmit={onSubmit}>
|
||||
<form className={`user-profile-form user-profile-form--${size} ${className || ''}`} onSubmit={onSubmit}>
|
||||
<div className="avatar-group">
|
||||
<AvatarInput currentAvatar={output.profile_attributes?.user_avatar_attributes?.attachment_url}
|
||||
userName={`${output.profile_attributes?.first_name} ${output.profile_attributes?.last_name}`}
|
||||
|
21
app/frontend/src/javascript/lib/product.ts
Normal file
21
app/frontend/src/javascript/lib/product.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { ProductCategory } from '../models/product-category';
|
||||
|
||||
export default class ProductLib {
|
||||
/**
|
||||
* Map product categories by position
|
||||
* @param categories unsorted categories, as returned by the API
|
||||
*/
|
||||
sortCategories = (categories: Array<ProductCategory>): Array<ProductCategory> => {
|
||||
const sortedCategories = categories
|
||||
.filter(c => !c.parent_id)
|
||||
.sort((a, b) => a.position - b.position);
|
||||
const childrenCategories = categories
|
||||
.filter(c => typeof c.parent_id === 'number')
|
||||
.sort((a, b) => b.position - a.position);
|
||||
childrenCategories.forEach(c => {
|
||||
const parentIndex = sortedCategories.findIndex(i => i.id === c.parent_id);
|
||||
sortedCategories.splice(parentIndex + 1, 0, c);
|
||||
});
|
||||
return sortedCategories;
|
||||
};
|
||||
}
|
@ -16,11 +16,11 @@ export interface Stock {
|
||||
}
|
||||
|
||||
export interface Product {
|
||||
id: number,
|
||||
id?: number,
|
||||
name: string,
|
||||
slug: string,
|
||||
sku: string,
|
||||
description: string,
|
||||
sku?: string,
|
||||
description?: string,
|
||||
is_active: boolean,
|
||||
product_category_id?: number,
|
||||
amount?: number,
|
||||
|
Loading…
x
Reference in New Issue
Block a user