$(function() {
const adsList = $("#ads-list");
const loadMoreWrap = $(".load-more-wrap");
const loadMoreButton = $("#load-more-ads");
const loading = $("#ads-loading");
const clearFiltersButton = $("#clear-ad-filters");
let isLoadingAds = false;
let lastFilterSignature = JSON.stringify(collectAdFilters());
loading.addClass("hidden");
updateClearFiltersButton();
$("#apply-ad-filters").on("click", function() {
loadAds(0, false);
});
clearFiltersButton.on("click", function() {
clearAdFilters();
loadAds(0, false);
});
$("#adsSort").on("change", function() {
updateClearFiltersButton();
loadAds(0, false);
});
$("#adsSearch").on("keydown", function(event) {
if (event.key === "Enter") {
event.preventDefault();
loadAds(0, false);
}
});
$("#adsSearch, #adsPrice").on("input change", function() {
updateClearFiltersButton();
});
$("#adsState").on("change", function() {
updateClearFiltersButton();
loadAdCities($(this).val(), "");
});
$("#adsCity").on("change", function() {
updateClearFiltersButton();
});
$('input[name="manufacturer"], input[name="scale"], input[name="condition"]').on("change", function() {
updateClearFiltersButton();
});
$(".chip").on("click", function() {
const chip = $(this);
const chipValue = chip.data("chip");
if (chipValue === "all") {
$(".chip").removeClass("active");
chip.addClass("active");
} else {
$('.chip[data-chip="all"]').removeClass("active");
chip.toggleClass("active");
if ($(".chip.active").length === 0) {
$('.chip[data-chip="all"]').addClass("active");
}
}
loadAds(0, false);
});
loadMoreButton.on("click", function() {
const offset = parseInt(loadMoreButton.attr("data-offset"), 10) || 0;
loadAds(offset, true);
});
$(document).on("click", ".public-admin-ad-menu-toggle", function(event) {
event.preventDefault();
event.stopPropagation();
const menu = $(this).closest(".public-admin-ad-menu");
const isOpen = menu.hasClass("is-open");
closePublicAdminAdMenus();
if (!isOpen) {
menu.addClass("is-open");
positionPublicAdminAdMenu(menu);
$(this).attr("aria-expanded", "true");
}
});
$(document).on("click", function() {
closePublicAdminAdMenus();
});
$(document).on("click", ".public-admin-ad-action", async function(event) {
event.preventDefault();
event.stopPropagation();
const button = $(this);
const publicId = button.data("ad-id");
const action = button.data("ad-action");
closePublicAdminAdMenus();
if (button.prop("disabled") || button.data("loading")) {
return;
}
if (!publicId || action !== "block") {
popZ("Ação administrativa inválida para este anúncio.", "warning");
return;
}
const confirmed = await confirmPublicAdminAdAction({
title: "Bloquear anúncio?",
text: "Use esta ação para anúncios irregulares. O anúncio será removido do catálogo público.",
confirmButtonText: "Sim, bloquear"
});
if (!confirmed) {
return;
}
button.data("loading", true).prop("disabled", true).attr("aria-busy", "true");
$.ajax({
type: "POST",
url: "/api/admin/ads",
data: {
action: "update_status",
public_id: publicId,
ad_action: action
},
dataType: "json",
success: function(response) {
handlePublicAdminAdResponse(response);
if (response.result === "admin_ad_status_updated") {
loadAds(0, false, true);
}
},
error: function(jqXhr) {
handlePublicAdminAdResponse(jqXhr.responseJSON || {});
},
complete: function() {
button.data("loading", false).prop("disabled", false).removeAttr("aria-busy");
}
});
});
function loadAds(offset, append, force) {
const filters = collectAdFilters();
const filterSignature = JSON.stringify(filters);
force = Boolean(force);
if (isLoadingAds) {
return;
}
if (!append && !force && filterSignature === lastFilterSignature) {
return;
}
isLoadingAds = true;
loading.removeClass("hidden");
loadMoreButton.prop("disabled", true).text("Carregando...");
$.ajax({
type: "POST",
url: "/api/anuncios",
data: {
offset: offset,
limit: 12,
search: filters.search,
manufacturers: filters.manufacturers,
scales: filters.scales,
conditions: filters.conditions,
price: filters.price,
state: filters.state,
city: filters.city,
chips: filters.chips,
sort: filters.sort,
seller_username: filters.sellerUsername
},
dataType: "json",
success: function(response) {
if (response.result !== "ads_loaded") {
popZ("Não foi possível carregar os anúncios.", "error");
return;
}
if (append) {
adsList.append(response.html);
} else {
adsList.html(response.html);
}
loadMoreButton.attr("data-offset", response.nextOffset);
if (response.hasMore) {
loadMoreWrap.removeClass("hidden");
} else {
loadMoreWrap.addClass("hidden");
}
lastFilterSignature = filterSignature;
updateClearFiltersButton();
},
error: function(jqXhr) {
if (jqXhr.status === 503) {
popZ("Estamos aplicando uma atualização, tente novamente mais tarde.", "warning");
return;
}
popZ("Não foi possível carregar os anúncios.", "error");
},
complete: function() {
isLoadingAds = false;
loading.addClass("hidden");
loadMoreButton.prop("disabled", false).text("Carregar mais");
}
});
}
if (applyStoredHomeFilters()) {
updateClearFiltersButton();
loadAds(0, false);
}
});
function clearAdFilters() {
$("#adsSearch").val("");
$("#adsPrice").val("");
$("#adsState").val("");
$("#adsCity")
.html('')
.prop("disabled", true)
.val("");
$("#adsSort").val("recent");
$('input[name="manufacturer"], input[name="scale"], input[name="condition"]').prop("checked", false);
$(".chip").removeClass("active");
$('.chip[data-chip="all"]').addClass("active");
updateClearFiltersButton();
}
function hasActiveAdFilters() {
return (
($("#adsSearch").val() || "") !== ""
|| ($("#adsPrice").val() || "") !== ""
|| ($("#adsState").val() || "") !== ""
|| ($("#adsCity").val() || "") !== ""
|| ($("#adsSort").val() || "recent") !== "recent"
|| $('input[name="manufacturer"]:checked').length > 0
|| $('input[name="scale"]:checked').length > 0
|| $('input[name="condition"]:checked').length > 0
|| $('.chip.active[data-chip!="all"]').length > 0
);
}
function updateClearFiltersButton() {
$("#clear-ad-filters").toggleClass("hidden", !hasActiveAdFilters());
}
function applyStoredHomeFilters() {
const storedFilters = sessionStorage.getItem("garagem164AdFilters");
if (!storedFilters) {
return false;
}
sessionStorage.removeItem("garagem164AdFilters");
let filters = {};
try {
filters = JSON.parse(storedFilters);
} catch (error) {
return false;
}
$("#adsSearch").val(filters.search || "");
$("#adsPrice").val(filters.price || "");
$("#adsState").val(filters.state || "");
$("#adsSort").val(filters.sort || "recent");
$('input[name="manufacturer"]').prop("checked", false);
String(filters.manufacturers || "").split("|").forEach(function(manufacturer) {
if (manufacturer) {
$('input[name="manufacturer"][value="' + manufacturer + '"]').prop("checked", true);
}
});
$('input[name="scale"]').prop("checked", false);
String(filters.scales || "").split("|").forEach(function(scale) {
if (scale) {
$('input[name="scale"][value="' + scale + '"]').prop("checked", true);
}
});
$('input[name="condition"]').prop("checked", false);
String(filters.conditions || "").split("|").forEach(function(condition) {
if (condition) {
$('input[name="condition"][value="' + condition + '"]').prop("checked", true);
}
});
$(".chip").removeClass("active");
const chips = String(filters.chips || "").split("|").filter(Boolean);
if (chips.length) {
chips.forEach(function(chip) {
$('.chip[data-chip="' + chip + '"]').addClass("active");
});
} else {
$('.chip[data-chip="all"]').addClass("active");
}
if (filters.state) {
loadAdCities(filters.state, filters.city || "");
}
return true;
}
function loadAdCities(state, selectedCity) {
const citySelect = $("#adsCity");
citySelect
.prop("disabled", true)
.html('');
if (!state) {
citySelect
.html('')
.prop("disabled", true);
return;
}
$.ajax({
type: "GET",
url: "/api/cidades/" + encodeURIComponent(state),
dataType: "json",
success: function(response) {
citySelect.html('');
if (!response.cities || !response.cities.length) {
citySelect.html('');
return;
}
response.cities.forEach(function(city) {
citySelect.append(
$("');
popZ("Não foi possível carregar as cidades deste estado.", "error");
},
complete: function() {
citySelect.prop("disabled", false);
updateClearFiltersButton();
}
});
}
function collectAdFilters() {
const manufacturers = [];
const scales = [];
const conditions = [];
const chips = [];
$('input[name="manufacturer"]:checked').each(function() {
manufacturers.push($(this).val());
});
$('input[name="scale"]:checked').each(function() {
scales.push($(this).val());
});
$('input[name="condition"]:checked').each(function() {
conditions.push($(this).val());
});
$(".chip.active").each(function() {
const chip = $(this).data("chip");
if (chip && chip !== "all") {
chips.push(chip);
}
});
return {
search: $("#adsSearch").val() || "",
manufacturers: manufacturers.join("|"),
scales: scales.join("|"),
conditions: conditions.join("|"),
price: $("#adsPrice").val() || "",
state: $("#adsState").val() || "",
city: $("#adsCity").val() || "",
chips: chips.join("|"),
sort: $("#adsSort").val() || "recent",
sellerUsername: $("#adsSellerUsername").val() || ""
};
}
function closePublicAdminAdMenus() {
$(".public-admin-ad-menu")
.removeClass("is-open opens-up")
.find(".public-admin-ad-menu-toggle")
.attr("aria-expanded", "false");
$(".card.public-admin-menu-open").removeClass("public-admin-menu-open");
}
function positionPublicAdminAdMenu(menu) {
const list = menu.find(".dashboard-ad-menu-list");
if (!list.length) {
return;
}
menu.removeClass("opens-up");
const menuRect = menu[0].getBoundingClientRect();
const listHeight = list.outerHeight() || 0;
const bottomSpace = window.innerHeight - menuRect.bottom;
if (bottomSpace < listHeight + 16) {
menu.addClass("opens-up");
}
menu.closest(".card").addClass("public-admin-menu-open");
}
async function confirmPublicAdminAdAction(options) {
if (typeof Swal === "undefined") {
return window.confirm(options.title || "Deseja continuar?");
}
const result = await Swal.fire({
icon: "warning",
title: options.title,
text: options.text,
showCancelButton: true,
confirmButtonText: options.confirmButtonText || "Confirmar",
cancelButtonText: "Cancelar",
reverseButtons: true,
confirmButtonColor: "#e63946",
cancelButtonColor: "#6b7785"
});
return result.isConfirmed;
}
function handlePublicAdminAdResponse(response) {
switch (response.result) {
case "admin_ad_status_updated":
popZ("Anúncio bloqueado com sucesso.", "success");
break;
case "admin_ad_not_found":
popZ("Anúncio não encontrado.", "warning");
break;
case "invalid_admin_ad_status_transition":
popZ("Este anúncio não permite essa alteração.", "warning");
break;
case "invalid_admin_ad_action":
popZ("Ação inválida para este anúncio.", "warning");
break;
case "admin_ad_status_update_failed":
popZ("Não foi possível bloquear o anúncio. Tente novamente.", "error");
break;
default:
popZ("Não foi possível executar a ação no anúncio.", "error");
break;
}
}