diff --git a/src/Config/Config.php b/src/Config/Config.php index c3264a8..26e886d 100644 --- a/src/Config/Config.php +++ b/src/Config/Config.php @@ -14,6 +14,14 @@ class Config 'html' => 'HTML', 'faq' => 'FAQ Accordion', 'banner' => 'Banner', + 'alert' => 'Alert', + ]; + + const ALERT_STYLES = [ + 'success' => 'Success', + 'info' => 'Info', + 'warning' => 'Warning', + 'danger' => 'Danger', ]; const BANNER_IMAGE_ALLOWED_EXTENSIONS = [ diff --git a/src/Form/DataHandler/CustomHtmlBlockDataHandler.php b/src/Form/DataHandler/CustomHtmlBlockDataHandler.php index 5737af0..2642335 100644 --- a/src/Form/DataHandler/CustomHtmlBlockDataHandler.php +++ b/src/Form/DataHandler/CustomHtmlBlockDataHandler.php @@ -27,6 +27,8 @@ final class CustomHtmlBlockDataHandler implements FormDataHandlerInterface $block->description = (string) ($formData['description'] ?? ''); $block->extra_description = (string) ($formData['extra_description'] ?? ''); $block->link = (string) ($formData['link'] ?? ''); + $block->alert_type = (string) ($formData['alert_type'] ?? 'info'); + $block->timeout = (int) ($formData['timeout'] ?? 0); $block->image = $this->saveUploadedImage($formData['image'] ?? null, ''); $block->active = (int) $formData['active']; $block->ordering = $this->getNextOrdering($idGroup); @@ -57,6 +59,8 @@ final class CustomHtmlBlockDataHandler implements FormDataHandlerInterface $block->description = (string) ($formData['description'] ?? ''); $block->extra_description = (string) ($formData['extra_description'] ?? ''); $block->link = (string) ($formData['link'] ?? ''); + $block->alert_type = (string) ($formData['alert_type'] ?? 'info'); + $block->timeout = (int) ($formData['timeout'] ?? 0); $block->image = $this->saveUploadedImage($formData['image'] ?? null, $block->image); $block->active = (int) $formData['active']; diff --git a/src/Form/DataProvider/CustomHtmlBlockDataProvider.php b/src/Form/DataProvider/CustomHtmlBlockDataProvider.php index 14b99ee..2337365 100644 --- a/src/Form/DataProvider/CustomHtmlBlockDataProvider.php +++ b/src/Form/DataProvider/CustomHtmlBlockDataProvider.php @@ -28,6 +28,8 @@ final class CustomHtmlBlockDataProvider implements FormDataProviderInterface 'description' => $block->description, 'extra_description' => $block->extra_description, 'link' => $block->link, + 'alert_type' => $block->alert_type, + 'timeout' => (int) $block->timeout, 'faqs' => $this->loadFaqs((int) $id), 'active' => (bool) $block->active, ]; @@ -46,6 +48,8 @@ final class CustomHtmlBlockDataProvider implements FormDataProviderInterface 'description' => '', 'extra_description' => '', 'link' => '', + 'alert_type' => 'info', + 'timeout' => 0, 'faqs' => [], 'active' => true, ]; diff --git a/src/Form/Type/CustomHtmlBlockType.php b/src/Form/Type/CustomHtmlBlockType.php index b8b4298..e7d3453 100644 --- a/src/Form/Type/CustomHtmlBlockType.php +++ b/src/Form/Type/CustomHtmlBlockType.php @@ -7,6 +7,7 @@ use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\FileType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use PrestaShop\PrestaShop\Core\Form\ConfigurableFormChoiceProviderInterface; @@ -70,10 +71,23 @@ class CustomHtmlBlockType extends AbstractType 'prototype' => true, 'required' => false, ]) + ->add('alert_type', ChoiceType::class, [ + 'label' => $this->translator->trans('Alert style', [], 'Modules.Wscustomhtml.Admin'), + 'choices' => array_flip(Config::ALERT_STYLES), + 'required' => false, + 'row_attr' => ['class' => 'customhtmlblock-type-field customhtmlblock-type-alert'], + ]) + ->add('timeout', IntegerType::class, [ + 'label' => $this->translator->trans('Auto-dismiss after (seconds)', [], 'Modules.Wscustomhtml.Admin'), + 'required' => false, + 'attr' => ['min' => 0, 'placeholder' => '0'], + 'help' => $this->translator->trans('0 means the alert never auto-dismisses; visitors can still close it manually.', [], 'Modules.Wscustomhtml.Admin'), + 'row_attr' => ['class' => 'customhtmlblock-type-field customhtmlblock-type-alert'], + ]) ->add('description', TextareaType::class, [ 'label' => $this->translator->trans('Description', [], 'Modules.Wscustomhtml.Admin'), 'required' => false, - 'row_attr' => ['class' => 'customhtmlblock-type-field customhtmlblock-type-banner'], + 'row_attr' => ['class' => 'customhtmlblock-type-field customhtmlblock-type-banner customhtmlblock-type-alert'], ]) ->add('extra_description', TextareaType::class, [ 'label' => $this->translator->trans('Extra description', [], 'Modules.Wscustomhtml.Admin'), diff --git a/src/Model/CustomHtmlBlock.php b/src/Model/CustomHtmlBlock.php index e549999..efa6d10 100644 --- a/src/Model/CustomHtmlBlock.php +++ b/src/Model/CustomHtmlBlock.php @@ -37,6 +37,12 @@ class CustomHtmlBlock extends ObjectModel /** @var string */ public $image = ''; + /** @var string */ + public $alert_type = 'info'; + + /** @var int */ + public $timeout = 0; + /** @var int */ public $active = 1; @@ -65,6 +71,8 @@ class CustomHtmlBlock extends ObjectModel 'extra_description' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => false, 'size' => 1024], 'link' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => false, 'size' => 512], 'image' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => false, 'size' => 255], + 'alert_type' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => false, 'size' => 16], + 'timeout' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'required' => false], 'active' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'show_title' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'ordering' => ['type' => self::TYPE_INT, 'validate' => 'isInt'], @@ -97,7 +105,7 @@ class CustomHtmlBlock extends ObjectModel $result = Db::getInstance()->executeS( 'SELECT `id_ws_customhtml`, `id_ws_customhtml_group`, `title`, `type`, `content`, `custom_class`, - `description`, `extra_description`, `link`, `image`, `active`, `show_title`, `ordering` + `description`, `extra_description`, `link`, `image`, `alert_type`, `timeout`, `active`, `show_title`, `ordering` FROM `' . _DB_PREFIX_ . 'ws_customhtml` WHERE `id_ws_customhtml_group` IN (' . implode(',', $groupIds) . ') AND `active` = 1 diff --git a/src/Module/DisplayHooks.php b/src/Module/DisplayHooks.php index f1eb00e..35b0eb2 100644 --- a/src/Module/DisplayHooks.php +++ b/src/Module/DisplayHooks.php @@ -15,6 +15,11 @@ trait DisplayHooks 'ws_customhtml_front', '/modules/' . $this->name . '/views/css/front/customhtml.css' ); + + $this->context->controller->registerJavascript( + 'ws_customhtml_front', + '/modules/' . $this->name . '/views/js/front/customhtml.js' + ); } public function renderWidget($hookName = null, array $configuration = []) diff --git a/upgrade/upgrade-1.10.0.php b/upgrade/upgrade-1.10.0.php new file mode 100644 index 0000000..f2b3626 --- /dev/null +++ b/upgrade/upgrade-1.10.0.php @@ -0,0 +1,31 @@ + 'VARCHAR(16) NOT NULL DEFAULT \'info\'', + 'timeout' => 'INT(11) NOT NULL DEFAULT 0', + ]; + + foreach ($columnsToAdd as $column => $definition) { + $existing = Db::getInstance()->executeS( + 'SHOW COLUMNS FROM `' . _DB_PREFIX_ . 'ws_customhtml` LIKE \'' . $column . '\'' + ); + + if (!empty($existing)) { + continue; + } + + if (!Db::getInstance()->execute( + 'ALTER TABLE `' . _DB_PREFIX_ . 'ws_customhtml` ADD COLUMN `' . $column . '` ' . $definition + )) { + return false; + } + } + + return true; +} diff --git a/upgrade/upgrade-1.8.0.php b/upgrade/upgrade-1.8.0.php new file mode 100644 index 0000000..27ce763 --- /dev/null +++ b/upgrade/upgrade-1.8.0.php @@ -0,0 +1,20 @@ +executeS( + 'SHOW COLUMNS FROM `' . _DB_PREFIX_ . 'ws_customhtml` LIKE \'template_key\'' + ); + + if (!empty($existing)) { + return true; + } + + return Db::getInstance()->execute( + 'ALTER TABLE `' . _DB_PREFIX_ . 'ws_customhtml` ADD COLUMN `template_key` VARCHAR(64) NOT NULL DEFAULT \'\'' + ); +} diff --git a/upgrade/upgrade-1.9.0.php b/upgrade/upgrade-1.9.0.php new file mode 100644 index 0000000..f4410aa --- /dev/null +++ b/upgrade/upgrade-1.9.0.php @@ -0,0 +1,20 @@ +executeS( + 'SHOW COLUMNS FROM `' . _DB_PREFIX_ . 'ws_customhtml` LIKE \'template_key\'' + ); + + if (empty($existing)) { + return true; + } + + return Db::getInstance()->execute( + 'ALTER TABLE `' . _DB_PREFIX_ . 'ws_customhtml` DROP COLUMN `template_key`' + ); +} diff --git a/views/css/admin/grid.css b/views/css/admin/grid.css index e802213..68498fe 100644 --- a/views/css/admin/grid.css +++ b/views/css/admin/grid.css @@ -18,21 +18,27 @@ td.action-type .btn-group-action { max-width: unset !important; text-align: left !important; } - form[name="custom_html_block"] .card-body { + form[name="custom_html_block"] .card-body, + form[name="custom_html_group"] .card-body { padding: 25px 50px !important; } form[name="custom_html_block"] .card-header, - form[name="custom_html_block"] .card-footer { + form[name="custom_html_block"] .card-footer, + form[name="custom_html_group"] .card-header, + form[name="custom_html_group"] .card-footer { padding: 20px 50px !important; } } @media (min-width: 1500px) { - form[name="custom_html_block"] .card-body { + form[name="custom_html_block"] .card-body, + form[name="custom_html_group"] .card-body { padding: 25px 300px !important; } form[name="custom_html_block"] .card-header, - form[name="custom_html_block"] .card-footer { + form[name="custom_html_block"] .card-footer, + form[name="custom_html_group"] .card-header, + form[name="custom_html_group"] .card-footer { padding: 20px 300px !important; } } diff --git a/views/css/front/customhtml.css b/views/css/front/customhtml.css index 94bd04c..98cfeef 100644 --- a/views/css/front/customhtml.css +++ b/views/css/front/customhtml.css @@ -15,3 +15,25 @@ .customhtml-banner-extra-description { margin-bottom: 1rem; } + +.customhtml-alert { + max-height: 500px; + overflow: hidden; + transition: + max-height 0.4s ease, + padding 0.4s ease, + margin 0.4s ease, + opacity 0.4s ease; +} + +.customhtml-alert.customhtml-alert-collapsing { + max-height: 0; + padding-top: 0; + padding-bottom: 0; + margin-bottom: 0; + opacity: 0; +} + +.customhtml-alert-title { + margin-right: 0.5rem; +} diff --git a/views/js/front/customhtml.js b/views/js/front/customhtml.js new file mode 100644 index 0000000..978e581 --- /dev/null +++ b/views/js/front/customhtml.js @@ -0,0 +1,26 @@ +document.addEventListener('DOMContentLoaded', function () { + document.querySelectorAll('.customhtml-alert').forEach(function (alertEl) { + var timeout = parseInt(alertEl.getAttribute('data-timeout'), 10) || 0; + var timer = null; + + var dismiss = function () { + alertEl.classList.add('customhtml-alert-collapsing'); + }; + + if (timeout > 0) { + timer = setTimeout(dismiss, timeout * 1000); + } + + var closeButton = alertEl.querySelector('.customhtml-alert-close'); + + if (closeButton) { + closeButton.addEventListener('click', function () { + if (timer) { + clearTimeout(timer); + } + + dismiss(); + }); + } + }); +}); diff --git a/views/templates/admin/form/blocks/block_form.html.twig b/views/templates/admin/form/blocks/block_form.html.twig index fb8e4ef..66a6c7f 100644 --- a/views/templates/admin/form/blocks/block_form.html.twig +++ b/views/templates/admin/form/blocks/block_form.html.twig @@ -59,6 +59,8 @@ + {{ form_row(customHtmlBlockForm.alert_type) }} + {{ form_row(customHtmlBlockForm.timeout) }} {{ form_row(customHtmlBlockForm.description) }} {{ form_row(customHtmlBlockForm.extra_description) }} {{ form_row(customHtmlBlockForm.link) }} diff --git a/views/templates/admin/form/customhtmlblock_create.html.twig b/views/templates/admin/form/customhtmlblock_create.html.twig index d053cbc..608fe3e 100644 --- a/views/templates/admin/form/customhtmlblock_create.html.twig +++ b/views/templates/admin/form/customhtmlblock_create.html.twig @@ -20,6 +20,7 @@ $('.customhtmlblock-type-html').hide(); $('.customhtmlblock-type-faq').hide(); $('.customhtmlblock-type-banner').hide(); + $('.customhtmlblock-type-alert').hide(); $('.customhtmlblock-type-' + type).show(); } diff --git a/views/templates/admin/form/customhtmlblock_edit.html.twig b/views/templates/admin/form/customhtmlblock_edit.html.twig index 1b263a9..9a184f2 100644 --- a/views/templates/admin/form/customhtmlblock_edit.html.twig +++ b/views/templates/admin/form/customhtmlblock_edit.html.twig @@ -20,6 +20,7 @@ $('.customhtmlblock-type-html').hide(); $('.customhtmlblock-type-faq').hide(); $('.customhtmlblock-type-banner').hide(); + $('.customhtmlblock-type-alert').hide(); $('.customhtmlblock-type-' + type).show(); } diff --git a/views/templates/hook/_alert.tpl b/views/templates/hook/_alert.tpl new file mode 100644 index 0000000..6527057 --- /dev/null +++ b/views/templates/hook/_alert.tpl @@ -0,0 +1,16 @@ +{if !empty($block.description)} +