Skip to content

Instantly share code, notes, and snippets.

@dedemenezes
Created September 12, 2025 19:14
Show Gist options
  • Select an option

  • Save dedemenezes/9f6df4c0b172fd4176537fd1b3792208 to your computer and use it in GitHub Desktop.

Select an option

Save dedemenezes/9f6df4c0b172fd4176537fd1b3792208 to your computer and use it in GitHub Desktop.
diff --git a/app/frontend/components/features/filters/ResponsiveFilterMenu.vue b/app/frontend/components/features/filters/ResponsiveFilterMenu.vue
index a80bacc..93ef2cc 100644
--- a/app/frontend/components/features/filters/ResponsiveFilterMenu.vue
+++ b/app/frontend/components/features/filters/ResponsiveFilterMenu.vue
@@ -1,3 +1,27 @@
+<!--
+// WE REMOVED EVERYHTING BELOW
+// AND NOW THE WHOLE DATA FLOW
+// INSIDE THIS COMPONENT RELIES
+// ON THE MODELVALUE PROPS PASSED FROM THE PARENT
+// IT WILL FORWARD THE MODELVALUE
+// TO THE SEARCHFILTER COMPONENT
+// AS PROP :modelValue AND RECEIVE
+// IT BACK IN THE TEMPLATE THROUGH
+// MODELVALUE :modelValue
+
+// WHEN SEARCHFILTER UPDATES MODELVALUE
+// IT WILL FORWARD THE EVENT UPDATE:MODELVALUE
+// WE RECEIVE HERE, UPDATE THE KEY FILTER
+// INSIDE MODELVALUE WITH THE USER SELECTED OPTION
+// AND FORWARD AN UPDATE:MODELVALUE EVENT
+
+// THIS LAST EMIT IS NOT RECEIVED HERE BUT IN THE PARENT
+// AND THEN WE SUBMIT THE FILTER IN THE PARENT
+
+// A HUGE CHAIN THAT FOR SURE CAN BE SIMPLIFIED
+// BECAUSE THE SEARCHFILTER ALSO HAS AN UPDATEFIELD FUNCTION
+// THIS SHOULD BE ONLY IN ONE PLACE.
+ -->
<script setup>
import { ref, watch, useTemplateRef } from "vue";
import { IconClose } from "@/components/common/icons";
@@ -6,23 +30,10 @@ import TwContainer from "@/components/layout/TwContainer.vue";
const props = defineProps({
isOpen: { type: Boolean, required: true },
- initialFilters: { type: Object, required: true },
+ // initialFilters: { type: Object, required: true },
modelValue: { type: Object, required: true },
});
-// Use a single internal state for both desktop and mobile
-const internalFilters = ref({ ...props.modelValue });
-
-// Watch for changes in modelValue from parent
-watch(() => props.modelValue, (newValue) => {
- internalFilters.value = { ...newValue };
-}, { deep: true, immediate: true });
-
-// Watch for changes in initialFilters (after successful submission)
-watch(() => props.initialFilters, (newFilters) => {
- internalFilters.value = { ...newFilters };
-}, { deep: true });
-
const emit = defineEmits([
"update:modelValue",
"filtersApplied",
@@ -35,31 +46,27 @@ const closeBtn = useTemplateRef('close-btn');
// Unified update function that emits changes back to parent
const updateField = (field, value) => {
console.log(`ResponsiveFilterMenu updating ${field}:`, value);
-
- // Update internal state
- internalFilters.value[field] = value;
-
// Emit the change back to parent
- const updatedFilters = { ...internalFilters.value };
+ const updatedFilters = { ...props.modelValue, [field]: value };
emit('update:modelValue', updatedFilters);
};
// Handle filter application
const handleFiltersApplied = () => {
- console.log('Filters applied:', internalFilters.value);
- emit('filtersApplied', internalFilters.value);
+ console.log('Filters applied:', props.modelValue);
+ emit('filtersApplied', props.modelValue);
};
// Handle filter clearing
const handleFiltersCleared = () => {
- console.log('Filters cleared');
- // Reset internal filters
- const clearedFilters = Object.keys(internalFilters.value).reduce((acc, key) => {
+ console.log('Clearing Filters...');
+ // Reset internal filters = RESET MODELVALUE
+ const clearedFilters = Object.keys(props.modelValue).reduce((acc, key) => {
acc[key] = null;
return acc;
}, {});
+ console.log('Filters cleared', clearedFilters);
- internalFilters.value = clearedFilters;
emit('update:modelValue', clearedFilters);
emit('filtersCleared');
};
@@ -68,11 +75,11 @@ const handleFiltersCleared = () => {
<template>
<!-- Debug info -->
<!-- <div class="bg-blue-50 p-2 mb-4 text-xs">
- <p><strong>ResponsiveFilterMenu internalFilters:</strong> {{ internalFilters }}</p>
<p><strong>ResponsiveFilterMenu modelValue:</strong> {{ modelValue }}</p>
</div> -->
<!-- Desktop Layout: Sticky sidebar (always visible) -->
+ <!-- add js to isDesktop -->
<div
style="margin-top: 0"
class="desktop-style bg-white hidden md:flex md:flex-col sticky top-0"
@@ -90,8 +97,8 @@ const handleFiltersCleared = () => {
<!-- Desktop Filter Content -->
<SearchFilter
- v-model="internalFilters"
- @update:modelValue="(val) => emit('update:modelValue', val)"
+ :modelValue="props.modelValue"
+ @update:modelValue="emit('update:modelValue', $event)"
@filtersApplied="handleFiltersApplied"
@filtersCleared="handleFiltersCleared"
@close-filter-menu="emit('close-filter-menu')"
@@ -99,7 +106,7 @@ const handleFiltersCleared = () => {
<template #filters="slotProps">
<slot
name="filters"
- :modelValue="internalFilters"
+ :modelValue="modelValue"
:updateField="updateField"
/>
</template>
@@ -144,7 +151,7 @@ const handleFiltersCleared = () => {
<!-- Mobile Filter Content -->
<SearchFilter
- v-model="internalFilters"
+ :modelValue="modelValue"
@update:modelValue="(val) => emit('update:modelValue', val)"
@filtersApplied="handleFiltersApplied"
@filtersCleared="handleFiltersCleared"
@@ -153,7 +160,7 @@ const handleFiltersCleared = () => {
<template #filters="slotProps">
<slot
name="filters"
- :modelValue="internalFilters"
+ :modelValue="modelValue"
:updateField="updateField"
/>
</template>
diff --git a/app/frontend/pages/ProgramPage.vue b/app/frontend/pages/ProgramPage.vue
index eba40b5..eb05572 100644
--- a/app/frontend/pages/ProgramPage.vue
+++ b/app/frontend/pages/ProgramPage.vue
@@ -7,6 +7,15 @@
// TODO: Add icon for menu tabs scroll
// TODO: Fix image urls
+// FOLLOWING THE COMMENTS INSIDE RESPONSIVE MENU
+// IN HERE WE RECEIVE ALL THE FILTER OPTIONS AS PROPS
+// WE RECEIVE THE CURRENT_FILTERS FROM THE CONTROLLER
+// A HASH CONTAINING THE SELECTED OPTION
+// WITH STRUCTURE PREDEFINED
+// {filter_display: '', filter_value: '', filter_label: ''}
+// but maybe this is not mandatory
+
+
import { ref, watch } from "vue";
import { router } from "@inertiajs/vue3"
@@ -58,46 +67,48 @@ const initializeFilters = () => ({
pais: null,
direcao: null,
elenco: null,
- ...props.current_filters // Override with actual values
})
+// Override with reactive filter with
+// current filtered values in case
+// there are any coming from controller
+const overrideFiltersValues = () => {
+ const emptyFilters = initializeFilters()
+ return {emptyFilters, ...props.current_filters}
+}
-const localFilters = ref(initializeFilters())
-const filters = ref(initializeFilters())
+const filters = ref(overrideFiltersValues())
// Watch for prop changes and update our local state
+// DONT THINK WE NEED AS THE PROP COMES FROM THE CONTROLLER
+// WHEN WE CHANGE A FILTER WE WILL AND SHOULD
+// ALWAYS UPDATE FILTERS REACTIVE AND NOT PROPS
+// PROPS DONT CHANGE VALUE
watch(() => props.current_filters, (newFilters) => {
- localFilters.value = initializeFilters()
- filters.value = initializeFilters()
+ filters.value = overrideFiltersValues()
}, { immediate: true, deep: true })
-// This can be removed right?
-// We are not using the props anymore
-// here are the removed props from MenuContext below
-// :items="props.items"
-// :icon-mapping="iconMapping"
-//const iconMapping = {
-// "program": IconProgram,
-// "user": IconNewUser,
-// "change": IconChange,
-// "clock": IconClock
-//};
-
// Update field function to pass to the form
+// if we are defining and passin we dont need it there
+// but in my mind it should be inside searchfilter
+// i said smth related to this
+// inside responsivefiltermenu comments
const updateField = (fieldName, value) => {
console.log(`Updating ${fieldName}:`, value)
filters.value[fieldName] = value
- localFilters.value[fieldName] = value
}
// Called when user clears search bar
-// const handleClear = () => {
-// filters.value.query = null;
-// submit(props.tabBaseUrl);
-// };
+const handleClear = () => {
+ debugger
+ filters.value.query = null;
+ submit(props.tabBaseUrl);
+};
-// Called when filters applied in MobileFilterMenu
+// Called when filters applied through button inside filter
const filterSearch = (filtersFromChild) => {
+ // this function extract actually
+ // build the query params ignoring null filters
const cleanedFilters = extractFilterValues(filtersFromChild || filters.value)
router.get(props.tabBaseUrl, cleanedFilters, {
preserveScroll: true,
@@ -109,44 +120,39 @@ const removeQuery = (what) => {
const newParams = new URLSearchParams()
// Clear the specific filter
+ // TODO: REFAC TIP ADD FILTER_KEY FROM CONTROLLER
+ // IT SHOULD MAKE AGNOSTIC
if (["Time", "Sessão"].includes(what.filter_label)) {
- localFilters.value['sessao'] = null
filters.value['sessao'] = null
}
if (["Showcase", "Mostra"].includes(what.filter_label)) {
- localFilters.value['mostra'] = null
filters.value['mostra'] = null
}
// Add other filter types as needed
if (["Cinema"].includes(what.filter_label)) {
- localFilters.value['cinema'] = null
filters.value['cinema'] = null
}
if (["Genre", "Genero"].includes(what.filter_label)) {
- localFilters.value['genero'] = null
filters.value['genero'] = null
}
if (["Country", "Pais"].includes(what.filter_label)) {
- localFilters.value['pais'] = null
filters.value['pais'] = null
}
if (["Director", "Direção"].includes(what.filter_label)) {
- localFilters.value['direcao'] = null
filters.value['direcao'] = null
}
if (["Cast", "Elenco"].includes(what.filter_label)) {
- localFilters.value['elenco'] = null
filters.value['elenco'] = null
}
- Object.entries(localFilters.value).forEach(([key, value]) => {
+ Object.entries(filters.value).forEach(([key, value]) => {
if (value !== null && value !== undefined && value !== "" && value?.filter_value) {
newParams.set(key, value.filter_value);
}
@@ -158,11 +164,12 @@ const removeQuery = (what) => {
})
}
-// Called when filters cleared from MobileFilterMenu
+// Called when filters cleared from Limpar Todos btn
const clearSearchQuery = () => {
const clearedFilters = initializeFilters()
- localFilters.value = clearedFilters
filters.value = clearedFilters
+ debugger
+ // MUST ACTIVATE IT
// router.get(props.tabBaseUrl, {}, {
// preserveScroll: true,
// only: ['elements', 'pagy', 'current_filters', 'has_active_filters', 'menuTabs']
@@ -174,9 +181,9 @@ const { sentinel, isSticky } = useStickyMenuTabs()
</script>
<template>
- <!-- <p>current_filters: {{ props.current_filters }}</p>
- <p>localFilters: {{ localFilters }}</p>
- <p>filters: {{ filters }}</p> -->
+ <p class="text-neutrals-900">current_filters: {{ props.current_filters }}</p>
+ <!-- <p class="text-neutrals-700">localFilters: {{ localFilters }}</p> -->
+ <p class="text-neutrals-500">filters: {{ filters }}</p>
<TwContainer>
<Breadcrumb :crumbs="props.crumbs" />
@@ -226,7 +233,8 @@ const { sentinel, isSticky } = useStickyMenuTabs()
:text="value.filter_display"
@remove-filter="removeQuery"
/>
- </div> <!-- CONTENT -->
+ </div>
+ <!-- CONTENT -->
<InfiniteScrollLayout #content="{ allElements }"
:elements="props.elements"
:pagy="props.pagy"
@@ -242,7 +250,6 @@ const { sentinel, isSticky } = useStickyMenuTabs()
<ResponsiveFilterMenu
v-model="filters"
:is-open="isFilterMenuOpen"
- :initialFilters="localFilters"
@filtersApplied="filterSearch"
@filtersCleared="clearSearchQuery"
@close-filter-menu="closeMenu"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment