1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-26 20:54:21 +01:00

(wip) unsaved form alert

This commit is contained in:
Sylvain 2022-09-13 17:18:35 +02:00
parent feabded2a0
commit c381c985d2
8 changed files with 65 additions and 18 deletions

View File

@ -0,0 +1,28 @@
import React, { PropsWithChildren, useEffect } from 'react';
import { UIRouter } from '@uirouter/angularjs';
import { FormState } from 'react-hook-form/dist/types/form';
import { FieldValues } from 'react-hook-form/dist/types/fields';
interface UnsavedFormAlertProps<TFieldValues> {
uiRouter: UIRouter,
formState: FormState<TFieldValues>,
}
/**
* Alert the user about unsaved changes in the given form, before leaving the current page
*/
export const UnsavedFormAlert = <TFieldValues extends FieldValues>({ uiRouter, formState, children }: PropsWithChildren<UnsavedFormAlertProps<TFieldValues>>) => {
useEffect(() => {
const { transitionService, globals: { current } } = uiRouter;
transitionService.onBefore({ from: current.name }, () => {
const { isDirty } = formState;
console.log('transition start', isDirty);
});
}, []);
return (
<div className="unsaved-form-alert">
{children}
</div>
);
};

View File

@ -6,6 +6,7 @@ import { IApplication } from '../../models/application';
import { ProductForm } from './product-form';
import { Product } from '../../models/product';
import ProductAPI from '../../api/product';
import { UIRouter } from '@uirouter/angularjs';
declare const Application: IApplication;
@ -13,12 +14,13 @@ interface EditProductProps {
productId: number,
onSuccess: (message: string) => void,
onError: (message: string) => void,
uiRouter: UIRouter
}
/**
* This component show edit product form
*/
const EditProduct: React.FC<EditProductProps> = ({ productId, onSuccess, onError }) => {
const EditProduct: React.FC<EditProductProps> = ({ productId, onSuccess, onError, uiRouter }) => {
const { t } = useTranslation('admin');
const [product, setProduct] = useState<Product>();
@ -40,19 +42,23 @@ const EditProduct: React.FC<EditProductProps> = ({ productId, onSuccess, onError
if (product) {
return (
<div className="edit-product">
<ProductForm product={product} title={product.name} onSuccess={saveProductSuccess} onError={onError} />
<ProductForm product={product}
title={product.name}
onSuccess={saveProductSuccess}
onError={onError}
uiRouter={uiRouter} />
</div>
);
}
return null;
};
const EditProductWrapper: React.FC<EditProductProps> = ({ productId, onSuccess, onError }) => {
const EditProductWrapper: React.FC<EditProductProps> = (props) => {
return (
<Loader>
<EditProduct productId={productId} onSuccess={onSuccess} onError={onError} />
<EditProduct {...props} />
</Loader>
);
};
Application.Components.component('editProduct', react2angular(EditProductWrapper, ['productId', 'onSuccess', 'onError']));
Application.Components.component('editProduct', react2angular(EditProductWrapper, ['productId', 'onSuccess', 'onError', 'uiRouter']));

View File

@ -4,18 +4,20 @@ import { react2angular } from 'react2angular';
import { Loader } from '../base/loader';
import { IApplication } from '../../models/application';
import { ProductForm } from './product-form';
import { UIRouter } from '@uirouter/angularjs';
declare const Application: IApplication;
interface NewProductProps {
onSuccess: (message: string) => void,
onError: (message: string) => void,
uiRouter: UIRouter,
}
/**
* This component show new product form
*/
const NewProduct: React.FC<NewProductProps> = ({ onSuccess, onError }) => {
const NewProduct: React.FC<NewProductProps> = ({ onSuccess, onError, uiRouter }) => {
const { t } = useTranslation('admin');
const product = {
@ -46,17 +48,21 @@ const NewProduct: React.FC<NewProductProps> = ({ onSuccess, onError }) => {
return (
<div className="new-product">
<ProductForm product={product} title={t('app.admin.store.new_product.add_a_new_product')} onSuccess={saveProductSuccess} onError={onError} />
<ProductForm product={product}
title={t('app.admin.store.new_product.add_a_new_product')}
onSuccess={saveProductSuccess}
onError={onError}
uiRouter={uiRouter} />
</div>
);
};
const NewProductWrapper: React.FC<NewProductProps> = ({ onSuccess, onError }) => {
const NewProductWrapper: React.FC<NewProductProps> = (props) => {
return (
<Loader>
<NewProduct onSuccess={onSuccess} onError={onError} />
<NewProduct {...props} />
</Loader>
);
};
Application.Components.component('newProduct', react2angular(NewProductWrapper, ['onSuccess', 'onError']));
Application.Components.component('newProduct', react2angular(NewProductWrapper, ['onSuccess', 'onError', 'uiRouter']));

View File

@ -20,12 +20,15 @@ import ProductAPI from '../../api/product';
import { Plus } from 'phosphor-react';
import { ProductStockForm } from './product-stock-form';
import ProductLib from '../../lib/product';
import { UnsavedFormAlert } from '../form/unsaved-form-alert';
import { UIRouter } from '@uirouter/angularjs';
interface ProductFormProps {
product: Product,
title: string,
onSuccess: (product: Product) => void,
onError: (message: string) => void,
uiRouter: UIRouter
}
/**
@ -42,7 +45,7 @@ type checklistOption = { value: number, label: string };
/**
* Form component to create or update a product
*/
export const ProductForm: React.FC<ProductFormProps> = ({ product, title, onSuccess, onError }) => {
export const ProductForm: React.FC<ProductFormProps> = ({ product, title, onSuccess, onError, uiRouter }) => {
const { t } = useTranslation('admin');
const { handleSubmit, register, control, formState, setValue, reset } = useForm<Product>({ defaultValues: { ...product } });
@ -224,6 +227,7 @@ 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>
<UnsavedFormAlert uiRouter={uiRouter} formState={formState} />
<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>

View File

@ -4,11 +4,14 @@
*/
'use strict';
Application.Controllers.controller('AdminStoreProductController', ['$scope', 'CSRF', 'growl', '$state', '$transition$',
function ($scope, CSRF, growl, $state, $transition$) {
Application.Controllers.controller('AdminStoreProductController', ['$scope', 'CSRF', 'growl', '$state', '$transition$', '$uiRouter',
function ($scope, CSRF, growl, $state, $transition$, $uiRouter) {
/* PUBLIC SCOPE */
$scope.productId = $transition$.params().id;
// the following item is used by the UnsavedFormAlert component to detect a page change
$scope.uiRouter = $uiRouter;
/**
* Callback triggered in case of error
*/

View File

@ -60,5 +60,5 @@ export interface Product {
_destroy?: boolean,
is_main?: boolean
}>,
product_stock_movements_attributes: Array<ProductStockMovement>,
product_stock_movements_attributes?: Array<ProductStockMovement>,
}

View File

@ -15,5 +15,5 @@
<span translate>{{ 'app.admin.store.back_products_list' }}</span>
</a>
</div>
<edit-product product-id="productId" on-success="onSuccess" on-error="onError"/>
</section>
<edit-product product-id="productId" on-success="onSuccess" on-error="onError" ui-router="uiRouter" />
</section>

View File

@ -15,5 +15,5 @@
<span translate>{{ 'app.admin.store.back_products_list' }}</span>
</a>
</div>
<new-product on-success="onSuccess" on-error="onError"/>
</section>
<new-product on-success="onSuccess" on-error="onError" ui-router="uiRouter"/>
</section>