*** CORE - Clean up overall the project ***

This commit is contained in:
Aivars Zukovskis 2026-09-30 21:32:50 +03:00
parent 0649a9e1b0
commit 6cca56dc74
10 changed files with 289 additions and 44 deletions

View File

@ -4,9 +4,11 @@ namespace BRSystems\Core\App\index\inc;
use BRSystems\Core\Cms\cmsTextManager\inc\cmsTextManagerConst; use BRSystems\Core\Cms\cmsTextManager\inc\cmsTextManagerConst;
use BRSystems\Core\Library\cCore\cCore; use BRSystems\Core\Library\cCore\cCore;
use BRSystems\Core\Library\cApc\cApc;
use BRSystems\Core\Library\cDefuseCrypto\cDefuseCrypto; use BRSystems\Core\Library\cDefuseCrypto\cDefuseCrypto;
use BRSystems\Core\Library\cJSON\cJSON; use BRSystems\Core\Library\cJSON\cJSON;
use BRSystems\Core\Library\cSession\cSession; use BRSystems\Core\Library\cSession\cSession;
use BRSystems\Core\Library\cUrl\cUrl;
use BRSystems\Core\Library\cValidator\cValidator; use BRSystems\Core\Library\cValidator\cValidator;
use BRSystems\Core\Library\cApc\cCacheHelper; use BRSystems\Core\Library\cApc\cCacheHelper;
use Exception; use Exception;
@ -29,6 +31,7 @@ class indexController extends cCore
const IMG_DEFAULT_BREADCRUMBS_BG = '/img/assets/other/breadcrumb-bgimg3.jpg'; const IMG_DEFAULT_BREADCRUMBS_BG = '/img/assets/other/breadcrumb-bgimg3.jpg';
const IMG_DEFAULT_COLLECTION_BANNER = '/img/assets/collection/collection-banner.jpg'; const IMG_DEFAULT_COLLECTION_BANNER = '/img/assets/collection/collection-banner.jpg';
const IMG_DEFAULT_POPUP_BG = '/img/assets/newsletter/newsletter-popup.jpg'; const IMG_DEFAULT_POPUP_BG = '/img/assets/newsletter/newsletter-popup.jpg';
const IMG_DEFAULT_FOOTER_INSTAGRAM = '/img/assets/instagram/insta-1.jpg';
public function __construct($uriData, $dir, $name) public function __construct($uriData, $dir, $name)
{ {
@ -472,6 +475,52 @@ class indexController extends cCore
return ($backgroundImg ?: self::IMG_DEFAULT_COLLECTION_BANNER); return ($backgroundImg ?: self::IMG_DEFAULT_COLLECTION_BANNER);
} }
public static function getFooterInstagramSlides(int $langId): array
{
$cache = new cCacheHelper(new cApc());
$cached = $cache->get(cmsTextManagerConst::APC_FOOTER_INSTAGRAM_KEY, $langId);
if ($cached !== false && is_array($cached)) {
return $cached;
}
$slidesData = (new indexModule())->getArticleData(cmsTextManagerConst::FOOTER_INSTAGRAM, $langId, true);
$slides = [];
if (!empty($slidesData) && is_array($slidesData)) {
foreach ($slidesData as $slideRow) {
if (!is_array($slideRow)) {
continue;
}
$imgPath = self::IMG_DEFAULT_FOOTER_INSTAGRAM;
if (!empty($slideRow['i'])) {
$normalizedImg = self::normalizeImagePath($slideRow['i'], 'footer_instagram');
if ($normalizedImg) {
$imgPath = $normalizedImg;
}
}
$slides[] = [
'img' => $imgPath,
'url' => self::normalizeSlideUrl($slideRow['l'] ?? ''),
'title' => !empty($slideRow['t']) ? $slideRow['t'] : '',
];
}
}
$cache->store(cmsTextManagerConst::APC_FOOTER_INSTAGRAM_KEY, $langId, $slides);
return $slides;
}
private static function normalizeSlideUrl(?string $url): string
{
if (empty($url)) {
return '/';
}
return (new cUrl())->rmSlashesIndex($url);
}
public function getIndexAboutTextSectionsData(): array public function getIndexAboutTextSectionsData(): array
{ {
$data = $this->module->getArticleData(cmsTextManagerConst::INDEX_PAGE_ABOUT_TEXT, $this->langId, true); $data = $this->module->getArticleData(cmsTextManagerConst::INDEX_PAGE_ABOUT_TEXT, $this->langId, true);
@ -811,12 +860,18 @@ class indexController extends cCore
]; ];
} }
public static function acceptCookiePolicy(): bool public static function acceptCookiePolicy(bool $acceptAll = false): bool
{ {
if (!isset($_COOKIE['_cookie_policy_accepted'])) { if (!isset($_COOKIE['_cookie_policy_accepted'])) {
/* expire in 1 month */ /* expire in 1 month */
setSameSiteCookie('_cookie_policy_accepted', 1, 60 * 60 * 24 * 30); setSameSiteCookie('_cookie_policy_accepted', 1, 60 * 60 * 24 * 30);
} }
$statistics = ($acceptAll ? 1 : (int)getP('statistics'));
$preferences = ($acceptAll ? 1 : (int)getP('preferences'));
setSameSiteCookie('_cookie_policy_statistics', $statistics, 60 * 60 * 24 * 30);
setSameSiteCookie('_cookie_policy_preferences', $preferences, 60 * 60 * 24 * 30);
return true; return true;
} }

View File

@ -57,6 +57,9 @@ class index
case 'accept-cookies': case 'accept-cookies':
cJSON::sendOk($this->controller->acceptCookiePolicy()); cJSON::sendOk($this->controller->acceptCookiePolicy());
break; break;
case 'accept-all-cookies':
cJSON::sendOk($this->controller->acceptCookiePolicy(true));
break;
default: default:
$this->controller->runCookies(); $this->controller->runCookies();
break; break;

View File

@ -73,6 +73,9 @@ class cmsClassificators
cJSON::sendOk($this->controller->changeEnumFields(getP('baseField'), getP('fields'))); cJSON::sendOk($this->controller->changeEnumFields(getP('baseField'), getP('fields')));
} }
break; break;
case 'generateInsertSql':
cJSON::sendOk($this->controller->generateInsertSql(getV('ids'), getP('filter')));
break;
default: default:
$this->controller->run(); $this->controller->run();
break; break;

View File

@ -296,6 +296,65 @@ class cmsClassificatorsController extends cCore
} }
public function generateInsertSql($ids, $filterJson = '')
{
if (!!$ids) {
$ids = json_decode($ids, true);
}
$filter = [];
if ($filterJson) {
$filter = cJSON::decode($filterJson, true);
}
$where = 'AND 1';
$sort = "id DESC";
$tFields = $this->getTableFields();
if (count($filter)) {
$where = $this->module->db->genSearchFieldQuery($filter, $tFields);
}
$vData = $this->module->getClassificatorDataForSqlExport($ids ?: [], $where, $sort);
if (!empty($vData) && is_array($vData)) {
$sSqlInsertClassificators = "INSERT INTO mod_classificators (id, cl_name, cl_data, cl_type, cl_order, cl_blocked, cl_shop_filter, cl_has_translations, cl_modified, cl_created) VALUES";
$sSqlInsertTranslations = "";
$sSqlPt1 = "";
$classificatorIds = [];
foreach ($vData as $v) {
$classificatorIds[$v['id']] = $v['id'];
$clName = $this->module->db->prepData($v['cl_name']);
$clData = $this->module->db->prepData($v['cl_data']);
$sSqlPt1 .= ",\n ({$v['id']}, '{$clName}', '{$clData}', {$v['cl_type']}, {$v['cl_order']}, '{$v['cl_blocked']}', '{$v['cl_shop_filter']}', '{$v['cl_has_translations']}', {$v['cl_modified']}, {$v['cl_created']})";
}
$sSqlInsertClassificators .= substr($sSqlPt1, 1) . ";";
$translations = $this->module->getClassificatorTranslationsForSqlExport(array_values($classificatorIds));
if (!empty($translations)) {
$sSqlPt2 = "";
$sSqlInsertTranslations = "INSERT INTO mod_classificators_translations (id, cl_id, cl_lang_id, cl_value, cl_data) VALUES";
foreach ($translations as $translation) {
$clValue = $this->module->db->prepData($translation['cl_value']);
$clData = $this->module->db->prepData($translation['cl_data']);
$sSqlPt2 .= ",\n ({$translation['id']}, {$translation['cl_id']}, {$translation['cl_lang_id']}, '{$clValue}', '{$clData}')";
}
$sSqlInsertTranslations .= substr($sSqlPt2, 1) . ";";
}
return array(
'sql' => array(
'sDeleteTranslations' => "DELETE FROM mod_classificators_translations WHERE cl_id IN (" . implode(", ", $classificatorIds) . ");",
'sDeleteClassificators' => "DELETE FROM mod_classificators WHERE id IN (" . implode(", ", $classificatorIds) . ");",
'sInsertClassificators' => $sSqlInsertClassificators,
'sInsertTranslations' => $sSqlInsertTranslations,
)
);
}
return false;
}
/** /**
* Function to create table headers + search * Function to create table headers + search
* *
@ -403,6 +462,8 @@ class cmsClassificatorsController extends cCore
return array( return array(
'yes' => $this->gM('Yes'), 'yes' => $this->gM('Yes'),
'no' => $this->gM('No'), 'no' => $this->gM('No'),
'done' => $this->gM('Done!'),
'sSqlExpTitle' => $this->gM('Sql Export for classificators'),
'delTitle' => $this->gM('Delete classificators?'), 'delTitle' => $this->gM('Delete classificators?'),
'delMessage' => $this->gM('Selected classificators will be permanently deleted and cannot be recovered. Confirm delete?'), 'delMessage' => $this->gM('Selected classificators will be permanently deleted and cannot be recovered. Confirm delete?'),
'buttonYes' => $this->gM('Delete selected classificators'), 'buttonYes' => $this->gM('Delete selected classificators'),
@ -429,6 +490,9 @@ class cmsClassificatorsController extends cCore
'lbl' => $this->gM("Add new"), 'lbl' => $this->gM("Add new"),
'icon' => 'nico-add' 'icon' => 'nico-add'
), ),
'igensql' => array(
'lbl' => $this->gM("Gen. sql"),
),
'istatus' => array( 'istatus' => array(
'lbl' => $this->gM("Change item status"), 'lbl' => $this->gM("Change item status"),
), ),

View File

@ -130,6 +130,65 @@ class cmsClassificatorsModule
} }
public function getClassificatorDataForSqlExport($ids = [], $where = 'AND 1', $sort = 'id DESC')
{
$ids = $this->db->prepData($ids);
$idWhere = '';
if (!empty($ids) && is_array($ids)) {
$idWhere = " AND mc.id IN (" . implode(',', $ids) . ")";
}
$sSql = "
SELECT
mc.id,
mc.cl_name,
mc.cl_data,
mc.cl_type,
mc.cl_order,
mc.cl_blocked,
mc.cl_shop_filter,
mc.cl_has_translations,
mc.cl_modified,
mc.cl_created
FROM
mod_classificators mc
WHERE
1 {$where}
{$idWhere}
ORDER BY
{$sort}
";
$this->db->query($sSql);
return $this->db->getFieldBasedArrayFieldsAdv('id');
}
public function getClassificatorTranslationsForSqlExport($ids)
{
$ids = $this->db->prepData($ids);
if (empty($ids) || !is_array($ids)) {
return [];
}
$sSql = "
SELECT
mct.id,
mct.cl_id,
mct.cl_lang_id,
mct.cl_value,
mct.cl_data
FROM
mod_classificators_translations mct
WHERE
mct.cl_id IN (" . implode(',', $ids) . ")
ORDER BY
mct.cl_id, mct.cl_lang_id, mct.id
";
$this->db->query($sSql);
return $this->db->getArray();
}
/** /**
* Function to get record translation data * Function to get record translation data
* *

View File

@ -7,7 +7,62 @@ var CmsClassificators = (function() {
_this.oTable.loadTableData(); _this.oTable.loadTableData();
} }
CTable.prototype.tableObjectCallback = function(jqObj){ CTable.prototype.tableObjectCallback = function(jqObj){
jqObj.find("#igensql").click(function(){
var oIds = [],
id = 0,
filter = {};
jqObj.find("ul.dxr.single:not(.thead) li.first .chked").each(function(){
id = $(this).closest("ul").attr("id");
if(id) oIds.push(id);
});
jqObj.find(".thead .search :input").each(function(){
var jqInput = $(this),
inputId = jqInput.attr("id");
if(inputId && jqInput.val() !== ""){
filter[inputId] = jqInput.val();
}
});
var jqData = $("<div class='sqlDrop'><div></div></div>");
CBase.ajax({action : "generateInsertSql", ids : $.toJSON(oIds), filter : $.toJSON(filter)}, false, function(d){
if(d && d.jsonok && d.sql){
$.each(d.sql, function(k, str){
if(str){
jqData.find("> div").append($("<p>"+ str +"</p>"));
}
});
jqData.find("> div").click(function(){
var selection = window.getSelection();
var txt = jqData.find("> div");
var range = document.createRange();
range.selectNodeContents(txt[0]);
selection.removeAllRanges();
selection.addRange(range);
});
}
});
if(!CBase.jsModule.oMyDialog)
CBase.jsModule.oMyDialog = new ConfirmDialog("sqlExport");
CBase.jsModule.oMyDialog.setCustomContentAndShow({
closeBtn: true,
title : defaultVal(CBase.gM.sSqlExpTitle, "Sql Export for classificators"),
message : jqData,
buttons : {
1 : {
lbl : defaultVal(CBase.gM.done, "Done!"),
id : "buttonYes",
click : function(){
CBase.jsModule.oMyDialog.hide();
}
}
}
});
});
}; };
// Rewrite CBase form callback // Rewrite CBase form callback
CBlank.prototype.viewCallback = function(jqObj){ CBlank.prototype.viewCallback = function(jqObj){

View File

@ -17,6 +17,7 @@ class cmsTextManagerConst
const APC_CATEGORY_MENU_KEY = "APP_CATEGORY_MENU_"; const APC_CATEGORY_MENU_KEY = "APP_CATEGORY_MENU_";
const APC_HEADER_CATEGORY_MENU_KEY = "APP_HEADER_CATEGORY_MENU_"; const APC_HEADER_CATEGORY_MENU_KEY = "APP_HEADER_CATEGORY_MENU_";
const APC_SHOP_SIDE_BANNER_KEY = "APP_SHOP_SIDE_BANNER_"; const APC_SHOP_SIDE_BANNER_KEY = "APP_SHOP_SIDE_BANNER_";
const APC_FOOTER_INSTAGRAM_KEY = 'FOOTER_INSTAGRAM';
const APC_INDEX_GLOBAL_KEY = 'INDEX_GLOBAL'; const APC_INDEX_GLOBAL_KEY = 'INDEX_GLOBAL';
const APC_INDEX_COOKIES_KEY = 'INDEX_COOKIES'; const APC_INDEX_COOKIES_KEY = 'INDEX_COOKIES';
const APC_INDEX_AGREE_TO_TERMS_KEY = 'INDEX_AGREE_TO_TERMS'; const APC_INDEX_AGREE_TO_TERMS_KEY = 'INDEX_AGREE_TO_TERMS';
@ -54,6 +55,7 @@ class cmsTextManagerConst
const PAGE_TYPE_RETURN_POLICY = 1478; // Return Policy page const PAGE_TYPE_RETURN_POLICY = 1478; // Return Policy page
const PAGE_TYPE_SHIPPING_POLICY = 1479; // Shipping Policy page const PAGE_TYPE_SHIPPING_POLICY = 1479; // Shipping Policy page
const PAGE_TYPE_COPYRIGHT = 1480; // Copyright page const PAGE_TYPE_COPYRIGHT = 1480; // Copyright page
const FOOTER_INSTAGRAM = 1481; // Footer instagram slider
// Text manager types for Products categories and sub-categories // Text manager types for Products categories and sub-categories
const BASE_SUB_CATEGORIES = 1443; // Base sub categories const BASE_SUB_CATEGORIES = 1443; // Base sub categories

View File

@ -38,6 +38,7 @@ class cmsTextManagerController extends cCore
'carousel' => '1920x950', 'carousel' => '1920x950',
'shop_side_banner' => '360x420', 'shop_side_banner' => '360x420',
'collection_banner' => '1420x330', 'collection_banner' => '1420x330',
'footer_instagram' => '450x450',
], ],
], ],
'file' => [ 'file' => [
@ -962,6 +963,7 @@ class cmsTextManagerController extends cCore
cmsTextManagerConst::GLOBAL_BREADCRUMBS => ['category_bg'], cmsTextManagerConst::GLOBAL_BREADCRUMBS => ['category_bg'],
cmsTextManagerConst::SHOP_SIDE_BANNER => ['shop_side_banner'], cmsTextManagerConst::SHOP_SIDE_BANNER => ['shop_side_banner'],
cmsTextManagerConst::COLLECTION_BANNER => ['collection_banner'], cmsTextManagerConst::COLLECTION_BANNER => ['collection_banner'],
cmsTextManagerConst::FOOTER_INSTAGRAM => ['footer_instagram'],
cmsTextManagerConst::INDEX_PAGE_TESTIMONIAL => ['service_card'], cmsTextManagerConst::INDEX_PAGE_TESTIMONIAL => ['service_card'],
]; ];
@ -1028,6 +1030,7 @@ class cmsTextManagerController extends cCore
cmsTextManagerConst::POPUP_SUBSCRIBE_BG => $defaultImageOnly, cmsTextManagerConst::POPUP_SUBSCRIBE_BG => $defaultImageOnly,
cmsTextManagerConst::SHOP_SIDE_BANNER => [$image, $link], cmsTextManagerConst::SHOP_SIDE_BANNER => [$image, $link],
cmsTextManagerConst::COLLECTION_BANNER => $defaultImageOnly, cmsTextManagerConst::COLLECTION_BANNER => $defaultImageOnly,
cmsTextManagerConst::FOOTER_INSTAGRAM => [$shortRecord, $image, $link],
cmsTextManagerConst::PAGE_TYPE_ABOUT_US => $defaultTextWithFiles, cmsTextManagerConst::PAGE_TYPE_ABOUT_US => $defaultTextWithFiles,
cmsTextManagerConst::PAGE_TYPE_FAQ => $defaultTextWithFiles, cmsTextManagerConst::PAGE_TYPE_FAQ => $defaultTextWithFiles,
cmsTextManagerConst::PAGE_TYPE_DISCLAIMER => $defaultTextWithFiles, cmsTextManagerConst::PAGE_TYPE_DISCLAIMER => $defaultTextWithFiles,
@ -1113,6 +1116,9 @@ class cmsTextManagerController extends cCore
case cmsTextManagerConst::SHOP_SIDE_BANNER: case cmsTextManagerConst::SHOP_SIDE_BANNER:
$apcKey = cmsTextManagerConst::APC_SHOP_SIDE_BANNER_KEY; $apcKey = cmsTextManagerConst::APC_SHOP_SIDE_BANNER_KEY;
break; break;
case cmsTextManagerConst::FOOTER_INSTAGRAM:
$apcKey = cmsTextManagerConst::APC_FOOTER_INSTAGRAM_KEY;
break;
case cmsTextManagerConst::COLLECTION_BANNER: case cmsTextManagerConst::COLLECTION_BANNER:
$apcKey = cmsTextManagerConst::APC_COLLECTION_BANNER_KEY; $apcKey = cmsTextManagerConst::APC_COLLECTION_BANNER_KEY;
break; break;

View File

@ -189,8 +189,12 @@ class cCore
/** Set global default settings across all pages */ /** Set global default settings across all pages */
$defaultLang = cmsTextManagerConst::DEFAULT_LANGUAGE; $defaultLang = cmsTextManagerConst::DEFAULT_LANGUAGE;
$this->oView->BREADCRUMBS_BG_IMG = indexController::getBreadcrumbBackgroundImg($defaultLang); $viewLangId = (!empty($this->langId) ? (int)$this->langId : $defaultLang);
$this->oView->SUBSCRIBE_BG_IMG = indexController::getPopupBackgroundImg($defaultLang);
$this->oView->BREADCRUMBS_BG_IMG = indexController::getBreadcrumbBackgroundImg($viewLangId);
$this->oView->SUBSCRIBE_BG_IMG = indexController::getPopupBackgroundImg($viewLangId);
$this->oView->FOOTER_INSTAGRAM_SLIDES = indexController::getFooterInstagramSlides($viewLangId);
$this->oView->setAsJSON('subCfg', indexController::valCfgForSubscribe()); $this->oView->setAsJSON('subCfg', indexController::valCfgForSubscribe());
$this->oView->setAsJSON('subLink', $this->gL(742)); $this->oView->setAsJSON('subLink', $this->gL(742));
$this->oView->setAsJSON('profileLink', $this->gL(905)); $this->oView->setAsJSON('profileLink', $this->gL(905));

View File

@ -14,57 +14,51 @@
{ 'title': 'Terms & condition', 'url': dt.gL(832) } { 'title': 'Terms & condition', 'url': dt.gL(832) }
] %} ] %}
{% set instaSlides = [ {% set instaSlides = FOOTER_INSTAGRAM_SLIDES|default([]) %}
{ 'img': '/img/assets/instagram/insta-1.jpg', 'url': dt.gL(525) },
{ 'img': '/img/assets/instagram/insta-2.jpg', 'url': dt.gL(525) },
{ 'img': '/img/assets/instagram/insta-3.jpg', 'url': dt.gL(525) },
{ 'img': '/img/assets/instagram/insta-4.jpg', 'url': dt.gL(525) },
{ 'img': '/img/assets/instagram/insta-5.jpg', 'url': dt.gL(525) },
{ 'img': '/img/assets/instagram/insta-6.jpg', 'url': dt.gL(525) },
{ 'img': '/img/assets/instagram/insta-7.jpg', 'url': dt.gL(525) }
] %}
<footer id="footer"> <footer id="footer">
<!-- footer-insta start --> {% if instaSlides is not empty %}
<section class="footer-insta section-pb bg-brand-sand extra-bg"> <!-- footer-insta start -->
<div class="container"> <section class="footer-insta section-pb bg-brand-sand extra-bg">
<div class="insta-category"> <div class="container">
<div class="section-capture text-center" style="display: none;"> <div class="insta-category">
<span class="sub-title text-brand-dark">{{ dt.gM("Follow us") }}</span> <div class="section-capture text-center" style="display: none;">
<div class="section-title"> <span class="sub-title text-brand-dark">{{ dt.gM("Follow us") }}</span>
<h2 class="section-heading text-brand-dark">{{ dt.gM("Instagram shop") }}</h2> <div class="section-title">
<h2 class="section-heading text-brand-dark">{{ dt.gM("Instagram shop") }}</h2>
</div>
</div> </div>
</div> <br>
<br> <div class="insta-wrap">
<div class="insta-wrap"> <div class="insta-slider swiper" id="insta-slider">
<div class="insta-slider swiper" id="insta-slider"> <div class="swiper-wrapper">
<div class="swiper-wrapper"> {% for slide in instaSlides %}
{% for slide in instaSlides %} <div class="swiper-slide">
<div class="swiper-slide"> <div class="banner-hover bg-card-custom">
<div class="banner-hover bg-card-custom"> <a href="{{ slide.url }}" class="d-block banner-img position-relative br-hidden">
<a href="{{ slide.url }}" class="d-block banner-img position-relative br-hidden"> <span class="banner-icon extra-color icon-24 position-absolute top-50 start-50 translate-middle z-1 rounded-circle"><i class="ri-instagram-line d-block lh-1"></i></span>
<span class="banner-icon extra-color icon-24 position-absolute top-50 start-50 translate-middle z-1 rounded-circle"><i class="ri-instagram-line d-block lh-1"></i></span> <img src="{{ slide.img }}" class="w-100 img-fluid" alt="{{ slide.title|default('insta-' ~ loop.index) }}">
<img src="{{ slide.img }}" class="w-100 img-fluid" alt="insta-{{ loop.index }}"> </a>
</a> </div>
</div> </div>
</div> {% endfor %}
{% endfor %} </div>
</div> </div>
</div> <div class="swiper-buttons">
<div class="swiper-buttons"> <div class="swiper-buttons-wrap">
<div class="swiper-buttons-wrap"> <button type="button" class="swiper-prev swiper-prev-insta" aria-label="Arrow previous"><i class="ri-arrow-left-line d-block lh-1"></i></button>
<button type="button" class="swiper-prev swiper-prev-insta" aria-label="Arrow previous"><i class="ri-arrow-left-line d-block lh-1"></i></button> <button type="button" class="swiper-next swiper-next-insta" aria-label="Arrow next"><i class="ri-arrow-right-line d-block lh-1"></i></button>
<button type="button" class="swiper-next swiper-next-insta" aria-label="Arrow next"><i class="ri-arrow-right-line d-block lh-1"></i></button> </div>
</div>
<div class="swiper-dots">
<div class="swiper-pagination swiper-pagination-insta"></div>
</div> </div>
</div>
<div class="swiper-dots">
<div class="swiper-pagination swiper-pagination-insta"></div>
</div> </div>
</div> </div>
</div> </div>
</div> </section>
</section>
<!-- footer-insta end --> <!-- footer-insta end -->
{% endif %}
<!-- footer-top start --> <!-- footer-top start -->
<div class="footer-area section-ptb bg-brand-sand extra-bg"> <div class="footer-area section-ptb bg-brand-sand extra-bg">