Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
</div>
{else}
{if $post_allowed}
<button class="btn btn-outline-primary post-product-comment" id="product-additional-info-review-button" type="button" data-bs-toggle="modal" data-bs-target="#post-product-comment-modal" data-ps-ref="product-post-review-button">
{l s='Write your review' d='Modules.Productcomments.Shop'}
</button>
<div class="product-comments-additional-info">
<button class="btn btn-outline-primary post-product-comment" id="product-additional-info-review-button" type="button" data-bs-toggle="modal" data-bs-target="#post-product-comment-modal" data-ps-ref="product-post-review-button">
{l s='Write your review' d='Modules.Productcomments.Shop'}
</button>
</div>
{/if}
{/if}
{/if}
1 change: 1 addition & 0 deletions modules/ps_emailalerts/js/mailalert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* mailalert.js */
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,35 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*}
{$componentName = 'mailalerts-account-line'}

<div class="{$componentName} d-flex flex-column position-relative">
<a href="{$mailAlert.link}" class="text-center">
<img src="{$mailAlert.cover_url}" alt="" />
</a>
<a class="mt-2" href="{$mailAlert.link}">
<div class="{$componentName}__product d-flex flex-column">
<span class="{$componentName}__product__name">{$mailAlert.name}</span>
<span class="{$componentName}__product__attributes mt-1">{$mailAlert.attributes_small}</span>
</div>
<li class="ps-emailalerts__product" data-ps-ref="emailalerts-product">
<a href="{$mailAlert.link}" class="ps-emailalerts__product-image-link" rel="nofollow">
<img class="ps-emailalerts__product-image img-fluid" src="{$mailAlert.cover_url}" alt="{$mailAlert.name}" loading="lazy">
</a>
<a href="#"
title="{l s='Remove mail alert' d='Modules.Emailalerts.Shop'}"
class="js-remove-email-alert btn btn-link {$componentName}__remove"
rel="js-id-emailalerts-{$mailAlert.id_product|intval}-{$mailAlert.id_product_attribute|intval}"
data-url="{url entity='module' name='ps_emailalerts' controller='actions' params=['process' => 'remove']}">
<i class="material-icons" aria-label="{l s='Delete' d='Modules.Emailalerts.Shop'}">&#xE872;</i>
</a>
</div>

<div class="ps-emailalerts__product-content">
<a href="{$mailAlert.link}">
<span class="ps-emailalerts__product-name">{$mailAlert.name}</span>
</a>

{if $mailAlert.attributes_small}
<span class="ps-emailalerts__product-attributes">
{l s='Attributes: %attributes%' sprintf=['%attributes%' => $mailAlert.attributes_small] d='Modules.Emailalerts.Shop'}
</span>
{/if}

{capture name='deleteData'}{strip}{ldelim}
"productId": "{$mailAlert.id_product|intval}",
"productAttributeId": "{$mailAlert.id_product_attribute|intval}",
"url": "{url entity='module' name='ps_emailalerts' controller='actions' params=['process' => 'remove']}"
{rdelim}{/strip}{/capture}

<button type="button"
aria-label="{l s='Delete %productName% mail alert' sprintf=['%productName%' => $mailAlert.name] d='Modules.Emailalerts.Shop'}"
class="link-danger ps-emailalerts__product-delete"
data-ps-action="emailalerts-delete"
data-ps-data="{$smarty.capture.deleteData}"
>
{l s='Delete' d='Modules.Emailalerts.Shop'}
</button>
</div>
</li>
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@
{/block}

{block name='page_content'}
<p>{l s='Manage your mail alerts to stay informed about product availability and updates.' d='Modules.Emailalerts.Shop'}</p>

{if $mailAlerts}
<ul class="row">
<ul class="ps-emailalerts__product-list" data-ps-ref="emailalerts-product-list">
{foreach from=$mailAlerts item=mailAlert}
<li class="col-sm-6 col-md-3">{include 'module:ps_emailalerts/views/templates/front/mailalerts-account-line.tpl' mailAlert=$mailAlert}</li>
{include 'module:ps_emailalerts/views/templates/front/mailalerts-account-line.tpl' mailAlert=$mailAlert}
{/foreach}
</ul>

<div class="alert alert-info d-none" role="alert" data-ps-ref="emailalerts-account-no-alerts">{l s='You do not have any mail alerts.' d='Modules.Emailalerts.Shop'}</div>
{else}
<div class="alert alert-info" role="alert" data-alert="info">{l s='No mail alerts yet.' d='Modules.Emailalerts.Shop'}</div>
<div class="alert alert-info" role="alert" data-ps-ref="emailalerts-account-no-alerts">{l s='You do not have any mail alerts.' d='Modules.Emailalerts.Shop'}</div>
{/if}
{/block}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*}

<li>
<a href="{url entity='module' name='ps_emailalerts' controller='account'}" title="{l s='My alerts' d='Shop.Theme.Catalog'}">
<a href="{url entity='module' name='ps_emailalerts' controller='account'}" rel="nofollow">
{l s='My alerts' d='Shop.Theme.Catalog'}
</a>
</li>
62 changes: 47 additions & 15 deletions modules/ps_emailalerts/views/templates/hook/product.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,59 @@
* International Registered Trademark & Property of PrestaShop SA
*}

<div class="card card-body text-center js-mailalert mb-3 mt-3 bg-light" data-url="{url entity='module' name='ps_emailalerts' controller='actions' params=['process' => 'add']}">
<div class="ps-emailalerts ps-emailalerts--product"
data-ps-ref="emailalerts"
data-ps-component="gdpr"
data-url="{url entity='module' name='ps_emailalerts' controller='actions' params=['process' => 'add']}">
<div class="ps-emailalerts__content" data-ps-ref="emailalerts-content">
<p class="h4 mb-0">
{l s='Notify me when available' d='Modules.Emailalerts.Shop'}
</p>

{if isset($email) AND $email}
<p>{l s='Interested in this product? Drop us an email and we will let you know when it\'s available for order.' d='Modules.Emailalerts.Shop'}</p>
<input class="form-control" type="email" placeholder="{l s='your@email.com' d='Modules.Emailalerts.Shop'}"/>
<p class="mb-0">
{l s='Interested in this product? Drop us an email and we will let you know when it\'s available for order.' d='Modules.Emailalerts.Shop'}
</p>

<input class="form-control"
type="email"
name="email"
data-ps-ref="emailalerts-email"
placeholder="{l s='Your email address' d='Modules.Emailalerts.Shop'}"
aria-label="{l s='Your email address' d='Modules.Emailalerts.Shop'}"
autocomplete="email"
>
{else}
<p>{l s='Interested in this product? Click below and we will let you know when it\'s available for order.' d='Modules.Emailalerts.Shop'}</p>
<p class="mb-0">
{l s='Interested in this product? Click below and we will let you know when it\'s available for order.' d='Modules.Emailalerts.Shop'}
</p>
{/if}

{if !empty($id_module)}
{capture name='gdprContent'}{hook h='displayGDPRConsent' id_module=$id_module}{/capture}
{if $smarty.capture.gdprContent != ''}
<div class="gdpr_consent_wrapper mt-1">{$smarty.capture.gdprContent nofilter}</div>
{/if}
{capture name='gdprContent'}{hook h='displayGDPRConsent' id_module=$id_module}{/capture}
{/if}

<button
data-product="{$product.id_product}"
data-product-attribute="{$product.id_product_attribute}"
class="btn btn-primary js-mailalert-add mt-1"
rel="nofollow">
{l s='Notify me when available' d='Modules.Emailalerts.Shop'}
{capture name='subscribeData'}{strip}{ldelim}
"productId": "{$product.id_product}",
"productAttributeId": "{$product.id_product_attribute}"
{rdelim}{/strip}{/capture}

<button data-ps-action="emailalerts-subscribe"
data-ps-ref="gdpr-submit"
data-ps-data="{$smarty.capture.subscribeData}"
class="btn btn-primary"
rel="nofollow"
role="button"
>
{l s='Notify me when available' d='Modules.Emailalerts.Shop'}
</button>
<div class="js-mailalert-alerts d-none"></div>

{if $smarty.capture.gdprContent != ''}
<div class="fs-6 text-body-secondary">
{$smarty.capture.gdprContent nofilter}
</div>
{/if}
</div>

<div class="d-none" data-ps-target="emailalerts-alerts" aria-live="assertive"></div>
</div>
26 changes: 22 additions & 4 deletions modules/psgdpr/views/templates/hook/displayGDPRConsent.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,30 @@
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*}
{extends file='modules/psgdpr/views/templates/hook/displayGDPRConsent.tpl'}

{block name='gdpr_checkbox'}
<div id="gdpr_consent" class="mt-2 gdpr_module_{$psgdpr_id_module|escape:'htmlall':'UTF-8'}">
{capture name='gdprData'}{strip}{ldelim}
"moduleId": "{$psgdpr_id_module|escape:'htmlall':'UTF-8'}",
"frontController": "{$psgdpr_front_controller|escape:'htmlall':'UTF-8'}",
"idCustomer": "{$psgdpr_id_customer|escape:'htmlall':'UTF-8'}",
"customerToken": "{$psgdpr_customer_token|escape:'htmlall':'UTF-8'}",
"idGuest": "{$psgdpr_id_guest|escape:'htmlall':'UTF-8'}",
"guestToken": "{$psgdpr_guest_token|escape:'htmlall':'UTF-8'}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"moduleId": "{$psgdpr_id_module|escape:'htmlall':'UTF-8'}",
"frontController": "{$psgdpr_front_controller|escape:'htmlall':'UTF-8'}",
"idCustomer": "{$psgdpr_id_customer|escape:'htmlall':'UTF-8'}",
"customerToken": "{$psgdpr_customer_token|escape:'htmlall':'UTF-8'}",
"idGuest": "{$psgdpr_id_guest|escape:'htmlall':'UTF-8'}",
"guestToken": "{$psgdpr_guest_token|escape:'htmlall':'UTF-8'}"
"id_module": "{$psgdpr_id_module|escape:'htmlall':'UTF-8'}",
"front_controller": "{$psgdpr_front_controller|escape:'htmlall':'UTF-8'}",
"id_customer": "{$psgdpr_id_customer|escape:'htmlall':'UTF-8'}",
"customer_token": "{$psgdpr_customer_token|escape:'htmlall':'UTF-8'}",
"id_guest": "{$psgdpr_id_guest|escape:'htmlall':'UTF-8'}",
"guest_token": "{$psgdpr_guest_token|escape:'htmlall':'UTF-8'}"

{rdelim}{/strip}{/capture}

<div id="gdpr_consent_{$psgdpr_id_module|escape:'htmlall':'UTF-8'}"
class="gdpr-consent"
data-ps-ref="gdpr-consent"
data-ps-data="{$smarty.capture.gdprData}"
>
<span class="form-check">
<input id="psgdpr_consent_checkbox_{$psgdpr_id_module|escape:'htmlall':'UTF-8'}" name="psgdpr_consent_checkbox" type="checkbox" value="1" class="form-check-input psgdpr_consent_checkboxes_{$psgdpr_id_module|escape:'htmlall':'UTF-8'}">
<label class="form-check-label psgdpr_consent_message">
<input id="psgdpr_consent_checkbox_{$psgdpr_id_module|escape:'htmlall':'UTF-8'}"
name="psgdpr_consent_checkbox"
type="checkbox"
value="1"
class="form-check-input"
data-ps-ref="gdpr-checkbox">
<label class="form-check-label" for="psgdpr_consent_checkbox_{$psgdpr_id_module|escape:'htmlall':'UTF-8'}">
{$psgdpr_consent_message nofilter}{* html data *}
</label>
</span>
Expand Down
21 changes: 21 additions & 0 deletions src/js/constants/selectors-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,25 @@ export const visiblePassword = {
visiblePassword: '[data-ps-action="toggle-password"]',
};

export const gdpr = {
consent: '[data-ps-ref="gdpr-consent"]',
consentWrapper: '[data-ps-component="gdpr"]',
checkbox: '[data-ps-ref="gdpr-checkbox"]',
submitButton: '[data-ps-ref="gdpr-submit"]',
};

export const emailAlerts = {
wrapper: '[data-ps-ref="emailalerts"]',
content: '[data-ps-ref="emailalerts-content"]',
submitButton: '[data-ps-action="emailalerts-subscribe"]',
emailInput: '[data-ps-ref="emailalerts-email"]',
alertsContainer: '[data-ps-target="emailalerts-alerts"]',
deleteButton: '[data-ps-action="emailalerts-delete"]',
product: '[data-ps-ref="emailalerts-product"]',
productList: '[data-ps-ref="emailalerts-product-list"]',
noAlerts: '[data-ps-ref="emailalerts-account-no-alerts"]',
};

export const desktopMenu = {
container: '[data-ps-ref="desktop-menu-container"]',
menuTree: '[data-ps-ref="desktop-menu-tree"]',
Expand Down Expand Up @@ -240,6 +259,8 @@ const selectorsMap = {
desktopMenu,
formValidation,
passwordPolicy,
emailAlerts,
gdpr,
};

export default selectorsMap;
30 changes: 30 additions & 0 deletions src/js/helpers/parseData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

/**
* Parse JSON data from data-ps-data attribute
*
* @example
* // HTML: <button data-ps-data='{"id": "123", "name": "Product"}'>
* const data = parseData<{id: string, name: string}>(button);
* // Returns: { id: "123", name: "Product" }
*
* @param element - The HTML element containing data-ps-data attribute
* @returns Parsed data object or null if parsing fails
*/
const parseData = <T>(element: HTMLElement): T | null => {
const {psData} = element.dataset;

if (!psData) return null;

try {
return JSON.parse(psData) as T;
} catch {
console.error('[parseData] Failed to parse data-ps-data:', psData);
return null;
}
};

export default parseData;
Loading