Skip to content

Commit

Permalink
product page events refacto part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
Oksydan committed Oct 1, 2023
1 parent 60247db commit bf8d402
Show file tree
Hide file tree
Showing 21 changed files with 404 additions and 205 deletions.
5 changes: 3 additions & 2 deletions _dev/js/theme/components/http/useDefaultHttpRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import useHttpRequest from './useHttpRequest';
* Default http request accepting payload as object and returning promise with response
* @param {string} url - url to send request
* @param {object} payload - payload to send
* @param {object} options - request options for example different headers
* @returns {Promise<unknown>}
*/
const useDefaultHttpRequest = (url, payload) => {
const { request } = useHttpRequest(url);
const useDefaultHttpRequest = (url, payload, options = {}) => {
const { request } = useHttpRequest(url, options);

return new Promise((resolve, reject) => {
request
Expand Down
2 changes: 1 addition & 1 deletion _dev/js/theme/components/http/useHttpPayloadDefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const useHttpPayloadDefinition = (payload, definition) => {
regex,
} = fieldDefinition;

if (required && !value) {
if (required && typeof value === 'undefined') {
validateErrors.push(`'${fieldName}' ${ERROR_MESSAGES.REQUIRED}`);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import prestashop from 'prestashop';
import productFormDataPersister from '../../persister/productFormDataPersister';
import productStateStore from '../../store/productStateStore';

const { setOnPopState, isFormChanged } = productStateStore();

const { get } = productFormDataPersister();

const productPopStateHandler = (event) => {
setOnPopState(true);

const formData = event?.state?.form || get();

if ((!formData || formData?.length === 0) && !isFormChanged()) {
return;
}

const form = document.querySelector(`${prestashop.selectors.product.actions} form`);

const handleFormElementState = (data) => {
const element = form.querySelector(`[name="${data.name}"]`);

if (element) {
element.value = data.value;
}
};

formData.forEach(handleFormElementState);

prestashop.emit('updateProduct', {
eventType: 'updatedProductCombination',
event,
});
};

export default productPopStateHandler;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import useAlertToast from '../../../../components/useAlertToast';

const { danger } = useAlertToast();

const productUpdateErrorHandler = (event) => {
if (event?.errorMessage) {
danger(event.errorMessage);
}
};

export default productUpdateErrorHandler;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import isQuickViewOpen from '../../utils/isQuickViewOpen';
import productStateStore from '../../store/productStateStore';

const { isOnPopState, setOnPopState } = productStateStore();

const updatedProductHandler = ({
product_url: responseProductUrl = null,
id_product_attribute: responseIdProductAttribute = null,
product_title: responseProductTitle = '',
}, formData) => {
if (!responseProductUrl || !responseIdProductAttribute) {
return;
}

/*
* If quickview modal is present we are not on product page, so
* we don't change the url nor title
*/
if (isQuickViewOpen()) {
return;
}

const pageTitle = document.title;

if (responseProductTitle) {
document.title = responseProductTitle;
}

if (!isOnPopState()) {
window.history.pushState(
{
id_product_attribute: responseIdProductAttribute,
form: formData,
},
pageTitle,
responseProductUrl,
);
}

setOnPopState(false);
};

export default updatedProductHandler;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import prestashop from 'prestashop';
import quickViewRequest from '../request/quickViewRequest';
import quickViewRequest from '../../request/quickView/quickViewRequest';

/**
* Quick view handler
Expand Down
5 changes: 0 additions & 5 deletions _dev/js/theme/core/product/handler/updatedProductHandler.js

This file was deleted.

38 changes: 38 additions & 0 deletions _dev/js/theme/core/product/persister/productFormDataPersister.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { formSerializeArray } from '../../../utils/formSerialize';

let formData = [];

/**
* Persists product form data
* @module
*/
const productFormDataPersister = () => {
/**
* Persists form data from the form element
* @method
* @param {HTMLFormElement} formElement - form element to persist
* @throws {Error} - if formElement is not a form element
* @return {void}
*/
const persist = (formElement) => {
if (formElement?.tagName !== 'FORM') {
throw new Error('formElement is not a form element');
}

formData = formSerializeArray(formElement);
};

/**
* Returns persisted data
* @method
* @return {*[]}
*/
const get = () => formData;

return {
persist,
get,
};
};

export default productFormDataPersister;
21 changes: 19 additions & 2 deletions _dev/js/theme/core/product/productController.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
import prestashop from 'prestashop';
import useEvent from '../../components/event/useEvent';
import quickViewClickHandler from './handler/quickViewClickHandler';
import quickViewHandler from './handler/quickViewHandler';
import quickViewClickHandler from './handler/quickView/quickViewClickHandler';
import quickViewHandler from './handler/quickView/quickViewHandler';
import productUpdateErrorHandler from './handler/product/productUpdateErrorHandler';
import productFormDataPersister from './persister/productFormDataPersister';
import productPopStateHandler from './handler/product/productPopStateHandler';
import updatedProductHandler from './handler/product/updatedProductHandler';

const { on } = useEvent();
const { persist } = productFormDataPersister();

const persistFormDataOnInit = () => {
const form = document.querySelector(`${prestashop.selectors.product.actions} form`);

if (form) {
persist(form);
}
};

const productController = () => {
const init = () => {
persistFormDataOnInit();
on(document, 'click', prestashop.selectors.listing.quickview, quickViewClickHandler);

window.addEventListener('popstate', productPopStateHandler);
prestashop.on('updatedProduct', updatedProductHandler);
prestashop.on('showErrorNextToAddtoCartButton', productUpdateErrorHandler);
prestashop.on('clickQuickView', ({ idProduct, idProductAttribute }) => quickViewHandler(idProduct, idProductAttribute));
};

Expand Down
121 changes: 121 additions & 0 deletions _dev/js/theme/core/product/request/product/updateProductRequest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import prestashop from 'prestashop';
import useHttpRequest from '../../../../components/http/useHttpRequest';
import useHttpController from '../../../../components/http/useHttpController';
import useHttpPayloadDefinition from '../../../../components/http/useHttpPayloadDefinition';

const { dispatch, abortAll } = useHttpController();

/**
* @typedef ServerResponse
* @type {object}
* @property {string} address_form - new address form html content
*/

/**
* Update listing facets request
* @param payload {object} - payload for request
* @param payload.preview {number} - is preview 1 or 0
* @param payload.quickview {number} - is quick view 1 or 0
* @param payload.quantity_wanted {number} - quantity wanted
* @param payload.id_product {number} - product id
* @param payload.id_product_attribute {number} - product attribute id
* @param payload.id_customization {number} - customization id - optional, default 0
* @param payload.ajax {number} - optional, default 1
* @param payload.action {string} - optional, default refresh
* @param payload.group[] {array} - array of attributes groups - optional
* @example
* const url = 'address-form.com/url'; // url to update address form
* const payload = {
* id_product: 1,
* id_product_attribute: 1,
* quantity_wanted: 1,
* preview: 0,
* quickview: 0,
* }
* const { getRequest } = updateProductRequest(payload);
*
* try {
* const resp = await getRequest();
* } catch (error) {
* console.error(error);
* }
* @returns {{getRequest: (function(): Promise<ServerResponse>)}}
*/
const updateProductRequest = (payload) => {
const { request, controller } = useHttpRequest(prestashop.urls.pages.product);
const payloadToSend = {
ajax: 1,
action: 'refresh',
...payload,
};

const payloadDefinition = {
action: {
type: 'string',
required: true,
},
ajax: {
type: 'int',
required: true,
},
preview: {
type: 'int',
required: true,
},
quickview: {
type: 'int',
required: true,
},
quantity_wanted: {
type: 'int',
required: true,
},
id_product: {
type: 'int',
required: true,
},
id_product_attribute: {
type: 'int',
required: true,
},
id_customization: {
type: 'int',
required: false,
},
};

const { validatePayload } = useHttpPayloadDefinition(payloadToSend, payloadDefinition);

const validationErrors = validatePayload();

if (validationErrors.length) {
throw Error(validationErrors.join(',\n'));
}

const getRequest = () => {
abortAll();

return new Promise((resolve, reject) => {
dispatch(request, controller)(() => request
.query(payloadToSend)
.post()
.json((resp) => {
resolve(resp);
})
.catch((e) => {
// IF ABORTED
if (e instanceof DOMException) {
return;
}

reject();
}));
});
};

return {
getRequest,
};
};

export default updateProductRequest;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import prestashop from 'prestashop';
import useDefaultHttpRequest from '../../../components/http/useDefaultHttpRequest';
import useHttpPayloadDefinition from '../../../components/http/useHttpPayloadDefinition';
import useDefaultHttpRequest from '../../../../components/http/useDefaultHttpRequest';
import useHttpPayloadDefinition from '../../../../components/http/useHttpPayloadDefinition';

/**
* @typedef ServerResponse
Expand Down Expand Up @@ -44,6 +44,10 @@ const quickViewRequest = (payload) => {
type: 'string',
required: true,
},
ajax: {
type: 'int',
required: true,
},
id_product: {
type: 'int',
required: true,
Expand Down
5 changes: 0 additions & 5 deletions _dev/js/theme/core/product/request/updateProductRequest.js

This file was deleted.

Loading

0 comments on commit bf8d402

Please sign in to comment.