Created
September 11, 2025 00:09
-
-
Save dedemenezes/9e8bdcacb7e847b5b6bdc8c84392177b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/app/controllers/programs_controller.rb b/app/controllers/programs_controller.rb | |
| index c26bb81..c6cd6e0 100644 | |
| --- a/app/controllers/programs_controller.rb | |
| +++ b/app/controllers/programs_controller.rb | |
| @@ -42,31 +42,31 @@ class ProgramsController < ApplicationController | |
| selected_filters[:query] = selected_query | |
| end | |
| - if params[:mostrasFilter].present? | |
| - selected_mostra = @mostras_filter.find { |c| c["permalink_pt"] == params[:mostrasFilter] } | |
| - selected_filters[:mostrasFilter] = selected_mostra if selected_mostra | |
| + if params[:mostra].present? | |
| + selected_mostra = @mostras_filter.find { |c| c["permalink_pt"] == params[:mostra] } | |
| + selected_filters[:mostra] = selected_mostra if selected_mostra | |
| if selected_mostra | |
| - base_scope = base_scope.where(mostras: { permalink_pt: selected_filters[:mostrasFilter]["permalink_pt"] }) | |
| + base_scope = base_scope.where(mostras: { permalink_pt: selected_filters[:mostra]["permalink_pt"] }) | |
| end | |
| end | |
| - if params[:cinemasFilter] | |
| + if params[:cinema] | |
| selected_cinema = @cinemas_filter.find do |cinema_filter| | |
| - (cinema_filter["id"].to_s === params[:cinemasFilter]) && (cinema_filter["edicao_id"] == EDICAO_ATUAL) | |
| + (cinema_filter["id"].to_s === params[:cinema]) && (cinema_filter["edicao_id"] == EDICAO_ATUAL) | |
| end | |
| if selected_cinema | |
| - selected_filters[:cinemasFilter] = selected_cinema | |
| + selected_filters[:cinema] = selected_cinema | |
| base_scope = base_scope.where(cinema_id: selected_cinema["id"]) | |
| end | |
| end | |
| - if params[:paisesFilter] | |
| + if params[:pais] | |
| selected_pais = @paises_filter.find do |pais_filter| | |
| - (pais_filter["id"].to_s === params[:paisesFilter]) | |
| + (pais_filter["id"].to_s === params[:pais]) | |
| end | |
| if selected_pais | |
| - selected_filters[:paisesFilter] = selected_pais | |
| + selected_filters[:pais] = selected_pais | |
| # base_scope = base_scope.where(paises_id: selected_pais["id"]) | |
| base_scope = base_scope.joins(pelicula: :paises).where(pelicula: { paises: { id: selected_pais["id"] } }) | |
| end | |
| @@ -81,19 +81,37 @@ class ProgramsController < ApplicationController | |
| end | |
| end | |
| - if params[:genresFilter].present? | |
| - selected_genre = @genres_filter.find { |genre| (genre["filter_value"] === params[:genresFilter]) } | |
| + if params[:genre].present? | |
| + selected_genre = @genres_filter.find { |genre| (genre["filter_value"] === params[:genre]) } | |
| if selected_genre | |
| selected_filters[:genre] = selected_genre | |
| locale_index = I18n.locale == :en ? -1 : 1 | |
| - # substring index is used to split the text in the database and select by index | |
| - base_scope = base_scope.where( | |
| - "SUBSTRING_INDEX(SUBSTRING_INDEX(peliculas.catalogo_ficha_2007, ' ', 1), '/', ?) LIKE ?", | |
| + # Use subquery instead of raw SQL on joined table | |
| + pelicula_ids = Pelicula.where(edicao_id: EDICAO_ATUAL).where( | |
| + "SUBSTRING_INDEX(SUBSTRING_INDEX(catalogo_ficha_2007, ' ', 1), '/', ?) LIKE ?", | |
| locale_index, | |
| "%#{selected_genre['filter_value']}%" | |
| - ) | |
| + ).pluck(:id) | |
| + | |
| + base_scope = base_scope.where(pelicula_id: pelicula_ids) | |
| + end | |
| + end | |
| + | |
| + if params[:director].present? | |
| + selected_director = @directors_filter.find { |d| d["filter_value"] == params[:director] } | |
| + | |
| + if selected_director | |
| + selected_filters[:director] = selected_director | |
| + | |
| + # Get pelicula IDs first - clean, simple query | |
| + pelicula_ids = Pelicula.where(edicao_id: EDICAO_ATUAL) | |
| + .where(diretor_coord_int: selected_director["filter_value"]) | |
| + .pluck(:id) | |
| + | |
| + # Then filter programacoes by IDs - no complex joins | |
| + base_scope = base_scope.where(pelicula_id: pelicula_ids) | |
| end | |
| end | |
| @@ -148,26 +166,28 @@ class ProgramsController < ApplicationController | |
| items:, | |
| elements: @programacoes, | |
| pagy: @pagy, | |
| - mostrasFilter: @mostras_filter, | |
| - cinemasFilter: @cinemas_filter, | |
| - paisesFilter: @paises_filter, | |
| - genresFilter: @genres_filter, | |
| + mostras: @mostras_filter, | |
| + cinemas: @cinemas_filter, | |
| + paises: @paises_filter, | |
| + genres: @genres_filter, | |
| sessoes: @sessoes, | |
| + directors: @directors_filter, | |
| menuTabs: @menu_tabs, | |
| current_filters: { # those are the ones used as modelValue | |
| query: selected_query, | |
| - mostrasFilter: selected_mostra, | |
| - cinemasFilter: selected_cinema, | |
| - paisesFilter: selected_pais, | |
| - genresFilter: selected_genre, | |
| - sessao: selected_sessao | |
| + mostra: selected_mostra, | |
| + cinema: selected_cinema, | |
| + pais: selected_pais, | |
| + genre: selected_genre, | |
| + sessao: selected_sessao, | |
| + director: selected_director | |
| }, | |
| - has_active_filters: params.permit(:query, :mostrasFilter).to_h.values.any?(&:present?), | |
| + has_active_filters: params.permit(:query, :mostra).to_h.values.any?(&:present?), | |
| crumbs: breadcrumbs( | |
| [ "", @root_url ], | |
| [ "Programação", "" ], | |
| [ "Programação Completa", "" ], | |
| - ) | |
| + ), | |
| } | |
| end | |
| @@ -205,10 +225,12 @@ class ProgramsController < ApplicationController | |
| def build_tab_url(date, filters) | |
| query_params = {} | |
| - query_params[:mostrasFilter]= filters[:mostrasFilter]["permalink_pt"] if filters[:mostrasFilter].present? | |
| - query_params[:cinemasFilter]= filters[:cinemasFilter]["id"] if filters[:cinemasFilter].present? | |
| - query_params[:paisesFilter]= filters[:paisesFilter]["id"] if filters[:paisesFilter].present? | |
| + query_params[:mostra]= filters[:mostra]["filter_value"] if filters[:mostra].present? | |
| + query_params[:cinema]= filters[:cinema]["filter_value"] if filters[:cinema].present? | |
| + query_params[:pais]= filters[:pais]["filter_value"] if filters[:pais].present? | |
| + query_params[:genre]= filters[:genre]["filter_value"] if filters[:genre].present? | |
| query_params[:sessao]= filters[:sessao]["filter_value"] if filters[:sessao].present? | |
| + query_params[:director]= filters[:director]["filter_value"] if filters[:director].present? | |
| query_params[:date] = date | |
| url_for(params: query_params, only_path: true) | |
| end | |
| @@ -221,7 +243,7 @@ class ProgramsController < ApplicationController | |
| .sort_by { |it| it.nome_pais } | |
| .as_json( | |
| only: %i[id nome_pais], | |
| - methods: %i[filter_display filter_value] | |
| + methods: %i[filter_display filter_value filter_label] | |
| ) | |
| @mostras_filter = Mostra.where(edicao_id: EDICAO_ATUAL) | |
| @@ -230,7 +252,7 @@ class ProgramsController < ApplicationController | |
| .sort_by { |it| it.permalink_pt } | |
| .as_json( | |
| only: %i[id permalink_pt nome_abreviado], | |
| - methods: [ :tag_class, :display_name, :filter_value, :filter_display ] | |
| + methods: [ :tag_class, :display_name, :filter_value, :filter_display, :filter_label ] | |
| ) | |
| @cinemas_filter = Cinema.where(edicao_id: EDICAO_ATUAL) | |
| .to_a | |
| @@ -238,14 +260,15 @@ class ProgramsController < ApplicationController | |
| .sort_by { |it| it.nome } | |
| .as_json( | |
| only: %i[id nome endereco edicao_id], | |
| - methods: %i[filter_display filter_value] | |
| + methods: %i[filter_display filter_value filter_label] | |
| ) | |
| @sessoes = Programacao.where(edicao_id: EDICAO_ATUAL).to_a.uniq { |p| p.sessao }.sort.as_json( | |
| only: %i[sessao], | |
| - methods: %i[display_sessao filter_value filter_display] | |
| + methods: %i[display_sessao filter_value filter_display filter_label] | |
| ) | |
| @genres_filter = Pelicula.genres_for(EDICAO_ATUAL) | |
| + @directors_filter = Pelicula.directors_for(EDICAO_ATUAL) | |
| end | |
| end | |
| diff --git a/app/frontend/components/common/tags/TagFilter.vue b/app/frontend/components/common/tags/TagFilter.vue | |
| index ebfc335..d267691 100644 | |
| --- a/app/frontend/components/common/tags/TagFilter.vue | |
| +++ b/app/frontend/components/common/tags/TagFilter.vue | |
| @@ -13,7 +13,7 @@ const props = defineProps({ | |
| const emit = defineEmits(["remove-filter"]); | |
| const removeSelf = () => { | |
| - emit("remove-filter", props.filter.value); | |
| + emit("remove-filter", props.filter); | |
| }; | |
| </script> | |
| @@ -21,13 +21,13 @@ const removeSelf = () => { | |
| <span | |
| class="max-w-fit inline-flex items-center gap-100 px-200 py-100 border rounded-full border-neutrals-300 font-body text-xs text-neutrals-700 font-regular leading-[18px] shrink-0" | |
| role="group" | |
| - :aria-label="`Filter: ${props.filter.label}`" | |
| + :aria-label="`Filter: ${props.filter.filter_display}`" | |
| > | |
| - {{ props.filter.label }} | |
| + {{ props.text }} | |
| <button | |
| type="button" | |
| - :aria-label="`Remove ${props.filter.label} filter`" | |
| + :aria-label="`Remove ${props.filter.filter_display} filter`" | |
| class="p-50 -m-50 bg-transparent border-0 rounded | |
| cursor-pointer | |
| hover:bg-neutrals-100 hover:text-neutrals-800 | |
| diff --git a/app/frontend/components/features/filters/ProgramsFilterForm.vue b/app/frontend/components/features/filters/ProgramsFilterForm.vue | |
| index bb3696a..f939c03 100644 | |
| --- a/app/frontend/components/features/filters/ProgramsFilterForm.vue | |
| +++ b/app/frontend/components/features/filters/ProgramsFilterForm.vue | |
| @@ -8,67 +8,51 @@ import SelectComponent from "@/components/ui/SelectComponent.vue"; | |
| const props = defineProps({ | |
| modelValue: { type: Object, required: true }, | |
| updateField: { type: Function, required: true }, | |
| - mostrasFilter: { type: Array, default: () => [] }, // Program-specific prop | |
| - cinemasFilter: { type: Array, default: () => [] }, // Program-specific prop | |
| - paisesFilter: { type: Array, default: () => [] }, | |
| - genresFilter: { type: Array, default: () => [] }, | |
| + mostras: { type: Array, default: () => [] }, // Program-specific prop | |
| + cinemas: { type: Array, default: () => [] }, // Program-specific prop | |
| + paises: { type: Array, default: () => [] }, | |
| + genres: { type: Array, default: () => [] }, | |
| sessoes: { type: Array, default: () => [] }, | |
| + directors: { type: Array, default: () => [] }, | |
| }); | |
| -// Transform cadernos prop for ComboboxComponent format | |
| -const mostrasFilterOptions = computed(() => { | |
| - return props.mostrasFilter.map(caderno => ({ | |
| - label: caderno.nome_abreviado, | |
| - value: caderno.permalink_pt, | |
| +const mapFilterOptions = (filterList) => { | |
| + return filterList.map(option => ({ | |
| + label: option.filter_display, | |
| + value: option.filter_value, | |
| })); | |
| -}); | |
| -// Transform cinema prop for ComboboxComponent format | |
| -const cinemasFilterOptions = computed(() => { | |
| - return props.cinemasFilter.map(cinema => ({ | |
| - label: cinema.nome, | |
| - value: cinema.id, | |
| - })); | |
| -}); | |
| -// Transform cinema prop for ComboboxComponent format | |
| -const paisesFilterOptions = computed(() => { | |
| - return props.paisesFilter.map(pais => ({ | |
| - label: pais.nome_pais, | |
| - value: pais.id, | |
| - })); | |
| -}); | |
| -// Transform cinema prop for ComboboxComponent format | |
| -const genresFilterOptions = computed(() => { | |
| - return props.genresFilter.map(genre => ({ | |
| - label: genre.filter_display, | |
| - value: genre.filter_value, | |
| - })); | |
| -}); | |
| +} | |
| + | |
| +const mostrasFilterOptions = computed(() => mapFilterOptions(props.mostras)); | |
| +const mostraLabel = computed(() => props.mostras[0].filter_label) | |
| + | |
| +const cinemasFilterOptions = computed(() => mapFilterOptions(props.cinemas)); | |
| +const cinemaLabel = computed(() => props.cinemas[0].filter_label) | |
| + | |
| +const paisesFilterOptions = computed(() => mapFilterOptions(props.paises)); | |
| +const paisLabel = computed(() => props.paises[0].filter_label) | |
| + | |
| +const genresFilterOptions = computed(() => mapFilterOptions(props.genres)); | |
| +const genreLabel = computed(() => props.genres[0].filter_label) | |
| + | |
| +const directorsOptions = computed(() => mapFilterOptions(props.directors)); | |
| +const directorLabel = computed(() => props.directors[0].filter_label) | |
| + | |
| // Transform cinema prop for ComboboxComponent format | |
| const sessoesFilterOptions = computed(() => { | |
| + // TODO: TRANSLATE | |
| return props.sessoes.map(sessao => ({ | |
| label: `Início às ${sessao.filter_display}`, | |
| value: sessao.filter_value, | |
| })); | |
| }); | |
| +const sessaoLabel = computed(() => props.sessoes[0].filter_label) | |
| -const getMostraObjectFromTagClas = (filter_value) => { | |
| - return props.mostrasFilter.find(c => c.filter_value === filter_value) || null; | |
| -}; | |
| -const getSessaoObject = (filter_value) => { | |
| - return props.sessoes.find(c => c.filter_value === filter_value) || null; | |
| -}; | |
| -const getCinemaObject = (filter_value) => { | |
| - return props.cinemasFilter.find(c => c.filter_value === filter_value) || null; | |
| -}; | |
| - | |
| -const getPaisObject = (filter_value) => { | |
| - return props.paisesFilter.find(c => c.filter_value === filter_value) || null; | |
| +const getSelectedFrom = (collectionName, value) => { | |
| + return props[collectionName].find(option => option.filter_value == value) | |
| } | |
| -const getGenreObject = (filter_value) => { | |
| - return props.genresFilter.find(c => c.filter_value === filter_value) || null; | |
| -} | |
| const getQueryObject = (filter_value) => { | |
| // TODO: REFACTOR | |
| // I'm building here beause the other get here as collection | |
| @@ -80,7 +64,6 @@ const getQueryObject = (filter_value) => { | |
| </script> | |
| <template> | |
| - <!-- Article-specific filter content --> | |
| <div class="pt-400"> | |
| <SearchBar | |
| :modelValue="props.modelValue.query?.filter_value" | |
| @@ -88,31 +71,15 @@ const getQueryObject = (filter_value) => { | |
| /> | |
| </div> | |
| - <!-- GENRES --> | |
| - <AccordionGroup | |
| - text="Gênero" | |
| - :isOpen="!!props.modelValue.genresFilter" | |
| - > | |
| - <template v-slot:content> | |
| - <div class="overflow-hidden w-full"> | |
| - <ComboboxComponent | |
| - :collection="genresFilterOptions" | |
| - :modelValue="props.modelValue.genresFilter?.filter_value || null" | |
| - @update:modelValue="(val) => props.updateField('genresFilter', getGenreObject(val))" | |
| - /> | |
| - </div> | |
| - </template> | |
| - </AccordionGroup> | |
| - | |
| <!-- HORARIO --> | |
| <AccordionGroup | |
| - text="Horário" | |
| + :text="sessaoLabel" | |
| :isOpen="!!props.modelValue.sessao" | |
| > | |
| <template v-slot:content> | |
| <SelectComponent | |
| :modelValue="props.modelValue.sessao?.filter_value || null" | |
| - @update:modelValue="(val) => props.updateField('sessao', getSessaoObject(val))" | |
| + @update:modelValue="(val) => props.updateField('sessao', getSelectedFrom('sessoes', val))" | |
| :collection="sessoesFilterOptions" | |
| /> | |
| </template> | |
| @@ -120,15 +87,15 @@ const getQueryObject = (filter_value) => { | |
| <!-- MOSTRAS --> | |
| <AccordionGroup | |
| - text="Mostra" | |
| + :text="mostraLabel" | |
| :isOpen="!!props.modelValue.mostrasFilter" | |
| > | |
| <template v-slot:content> | |
| <div class="overflow-hidden w-full"> | |
| <ComboboxComponent | |
| :collection="mostrasFilterOptions" | |
| - :modelValue="props.modelValue.mostrasFilter?.filter_value || null" | |
| - @update:modelValue="(val) => props.updateField('mostrasFilter', getMostraObjectFromTagClas(val))" | |
| + :modelValue="props.modelValue.mostra?.filter_value || null" | |
| + @update:modelValue="(val) => props.updateField('mostra', getSelectedFrom('mostras', val))" | |
| /> | |
| </div> | |
| </template> | |
| @@ -136,15 +103,31 @@ const getQueryObject = (filter_value) => { | |
| <!-- CINEMAS --> | |
| <AccordionGroup | |
| - text="Cinema" | |
| - :isOpen="!!props.modelValue.cinemasFilter" | |
| + :text="cinemaLabel" | |
| + :isOpen="!!props.modelValue.cinema" | |
| > | |
| <template v-slot:content> | |
| <div class="overflow-hidden w-full"> | |
| <ComboboxComponent | |
| :collection="cinemasFilterOptions" | |
| - :modelValue="props.modelValue.cinemasFilter?.filter_value || null" | |
| - @update:modelValue="(val) => props.updateField('cinemasFilter', getCinemaObject(val))" | |
| + :modelValue="props.modelValue.cinema?.filter_value || null" | |
| + @update:modelValue="(val) => props.updateField('cinema', getSelectedFrom('cinemas', val))" | |
| + /> | |
| + </div> | |
| + </template> | |
| + </AccordionGroup> | |
| + | |
| + <!-- GENRES --> | |
| + <AccordionGroup | |
| + :text="genreLabel" | |
| + :isOpen="!!props.modelValue.genre" | |
| + > | |
| + <template v-slot:content> | |
| + <div class="overflow-hidden w-full"> | |
| + <ComboboxComponent | |
| + :collection="genresFilterOptions" | |
| + :modelValue="props.modelValue.genre?.filter_value || null" | |
| + @update:modelValue="(val) => props.updateField('genre', getSelectedFrom('genres', val))" | |
| /> | |
| </div> | |
| </template> | |
| @@ -152,15 +135,31 @@ const getQueryObject = (filter_value) => { | |
| <!-- PAISES --> | |
| <AccordionGroup | |
| - text="Pais" | |
| - :isOpen="!!props.modelValue.paisesFilter" | |
| + :text="paisLabel" | |
| + :isOpen="!!props.modelValue.pais" | |
| > | |
| <template v-slot:content> | |
| <div class="overflow-hidden w-full"> | |
| <ComboboxComponent | |
| :collection="paisesFilterOptions" | |
| - :modelValue="props.modelValue.paisesFilter?.filter_value || null" | |
| - @update:modelValue="(val) => props.updateField('paisesFilter', getPaisObject(val))" | |
| + :modelValue="props.modelValue.pais?.filter_value || null" | |
| + @update:modelValue="(val) => props.updateField('pais', getSelectedFrom('paises', val))" | |
| + /> | |
| + </div> | |
| + </template> | |
| + </AccordionGroup> | |
| + | |
| + <!-- DIRETORES --> | |
| + <AccordionGroup | |
| + :text="directorLabel" | |
| + :isOpen="!!props.modelValue.director" | |
| + > | |
| + <template v-slot:content> | |
| + <div class="overflow-hidden w-full"> | |
| + <ComboboxComponent | |
| + :collection="directorsOptions" | |
| + :modelValue="props.modelValue.director?.filter_value || null" | |
| + @update:modelValue="(val) => props.updateField('director', getSelectedFrom('directors', val))" | |
| /> | |
| </div> | |
| </template> | |
| diff --git a/app/frontend/components/ui/SelectComponent.vue b/app/frontend/components/ui/SelectComponent.vue | |
| index 005f72f..3fac4ad 100644 | |
| --- a/app/frontend/components/ui/SelectComponent.vue | |
| +++ b/app/frontend/components/ui/SelectComponent.vue | |
| @@ -1,4 +1,5 @@ | |
| <script setup> | |
| +// TODO: DESelected element if clicking same value | |
| import { | |
| Select, | |
| SelectContent, | |
| diff --git a/app/frontend/pages/ProgramPage.vue b/app/frontend/pages/ProgramPage.vue | |
| index 3c8c3c4..0cfe43c 100644 | |
| --- a/app/frontend/pages/ProgramPage.vue | |
| +++ b/app/frontend/pages/ProgramPage.vue | |
| @@ -32,11 +32,12 @@ const props = defineProps({ | |
| items: { type: Array, required: true } | |
| ,elements: { type: Object, required: true } | |
| ,pagy: { type: Object, required: true } | |
| - ,mostrasFilter: { type: Array, default: () => [] } | |
| - ,cinemasFilter: { type: Array, default: () => [] } | |
| - ,paisesFilter: { type: Array, default: () => [] } | |
| - ,genresFilter: { type: Array, default: () => [] } | |
| + ,mostras: { type: Array, default: () => [] } | |
| + ,cinemas: { type: Array, default: () => [] } | |
| + ,paises: { type: Array, default: () => [] } | |
| + ,genres: { type: Array, default: () => [] } | |
| ,sessoes: { type: Array, default: () => [] } | |
| + ,directors: { type: Array, default: () => [] } | |
| // NEW LIFE | |
| ,menuTabs: { type: Array, required: true } | |
| ,current_filters: { type: Object, default: () => ({}) } | |
| @@ -72,9 +73,27 @@ const filterSearch = (filtersFromChild) => { | |
| }; | |
| const removeQuery = (what) => { | |
| - debugger | |
| - // remove the correct queryparams from url | |
| + const params = new URLSearchParams() | |
| + // TODO: ADD ALL TRANSLATIONS OR REFACTOR AI CAN ADD TRANSLATIONS | |
| + if (["Country", "Pais"].includes(what.filter_label)) { | |
| + localFilters.value['pais'] = null | |
| + } | |
| + | |
| + if (["Showcase", "Mostra"].includes(what.filter_label)) { | |
| + localFilters.value['mostra'] = null | |
| + } | |
| // make new request with the up to date filters | |
| + debugger | |
| + Object.entries(localFilters.value).forEach(([key, value]) => { | |
| + if (value !== null && value !== undefined && value !== "") { | |
| + params.set(key, value.filter_value); | |
| + } | |
| + }) | |
| + router.get(props.tabBaseUrl, params, { | |
| + preserveState: true, | |
| + preserveScroll: true, | |
| + only: ['elements', 'pagy', 'current_filters', 'has_active_filters', 'menuTabs'] | |
| + }) | |
| } | |
| // Called when filters cleared from MobileFilterMenu | |
| @@ -104,16 +123,8 @@ const { sentinel, isSticky } = useStickyMenuTabs() | |
| <MobileTrigger @open-menu="openMenu" /> | |
| </div> | |
| - <!-- filtered tag --> | |
| - <!-- { "query": null, | |
| - "mostrasFilter": null, | |
| - "cinemasFilter": null, | |
| - "paisesFilter": null, | |
| - "sessao": { "sessao": "2000-01-01T19:00:00.000Z", | |
| - "display_sessao": "19:00", | |
| - "filter_value": "19h00", | |
| - "filter_display": "19h00" } | |
| - } --> | |
| + <!-- TODO: REFAC into reusable components --> | |
| + <!-- MOBILE TAG FILTER --> | |
| <div | |
| class="flex lg:hidden gap-300 pt-200 pb-300 overflow-x-auto no-scroll-bar" | |
| v-if="Object.values(props.current_filters).some((item) => item !== null)" | |
| @@ -121,10 +132,10 @@ const { sentinel, isSticky } = useStickyMenuTabs() | |
| <TagFilter | |
| v-for="[key, value] in Object.entries(props.current_filters).filter(([k, v]) => v !== null)" | |
| :key="key" | |
| - :filter="{ label: value.filter_display, value: value.filter_value }" | |
| + :filter="value" | |
| :text="value.filter_display" | |
| @remove-filter="removeQuery" | |
| - /> | |
| + /> | |
| </div> | |
| <!-- filtered tag --> | |
| @@ -137,18 +148,22 @@ const { sentinel, isSticky } = useStickyMenuTabs() | |
| :tabs="menuTabs" | |
| class="h-15" | |
| /> | |
| + | |
| + <!-- DESKTOP TAG FILTER --> | |
| <div | |
| class="hidden lg:flex gap-300 pt-200 pb-300 overflow-x-auto no-scroll-bar sticky top-15 z-10 bg-white" | |
| v-if="Object.values(props.current_filters).some((item) => item !== null)" | |
| > | |
| <TagFilter | |
| v-for="[key, value] in Object.entries(props.current_filters).filter(([k, v]) => v !== null)" | |
| - :key="key" | |
| - :filter="{ label: value.filter_display, value: value.filter_value }" | |
| + :key="value.filter_value" | |
| + :filter="value" | |
| :text="value.filter_display" | |
| @remove-filter="removeQuery" | |
| - /> | |
| + /> | |
| </div> | |
| + | |
| + <!-- CONTENT --> | |
| <InfiniteScrollLayout #content="{ allElements }" | |
| :elements="props.elements" | |
| :pagy="props.pagy" | |
| @@ -171,11 +186,12 @@ const { sentinel, isSticky } = useStickyMenuTabs() | |
| <ProgramsFilterForm | |
| :model-value="modelValue" | |
| :update-field="updateField" | |
| - :mostrasFilter="props.mostrasFilter" | |
| - :cinemasFilter="props.cinemasFilter" | |
| - :paisesFilter="props.paisesFilter" | |
| - :genresFilter="props.genresFilter" | |
| + :mostras="props.mostras" | |
| + :cinemas="props.cinemas" | |
| + :paises="props.paises" | |
| + :genres="props.genres" | |
| :sessoes="props.sessoes" | |
| + :directors="props.directors" | |
| /> | |
| </template> | |
| </ResponsiveFilterMenu> | |
| diff --git a/app/models/cinema.rb b/app/models/cinema.rb | |
| index 9ca1bd6..c57b37f 100644 | |
| --- a/app/models/cinema.rb | |
| +++ b/app/models/cinema.rb | |
| @@ -10,4 +10,8 @@ class Cinema < ApplicationRecord | |
| def filter_display | |
| nome | |
| end | |
| + | |
| + def filter_label | |
| + I18n.t("filter.cinema") | |
| + end | |
| end | |
| diff --git a/app/models/mostra.rb b/app/models/mostra.rb | |
| index 034b02a..b4b4754 100644 | |
| --- a/app/models/mostra.rb | |
| +++ b/app/models/mostra.rb | |
| @@ -31,6 +31,14 @@ class Mostra < ApplicationRecord | |
| end | |
| def filter_display | |
| - display_name | |
| + if I18n.locale == :pt | |
| + nome_pt | |
| + else | |
| + nome_en | |
| + end | |
| + end | |
| + | |
| + def filter_label | |
| + I18n.t("filter.submostra") | |
| end | |
| end | |
| diff --git a/app/models/pais.rb b/app/models/pais.rb | |
| index c382cd2..da02a5b 100644 | |
| --- a/app/models/pais.rb | |
| +++ b/app/models/pais.rb | |
| @@ -1,4 +1,6 @@ | |
| class Pais < ApplicationRecord | |
| + include ActiveSupport::Inflector | |
| + | |
| has_many :paises_peliculas | |
| def filter_value | |
| @@ -6,6 +8,15 @@ class Pais < ApplicationRecord | |
| end | |
| def filter_display | |
| - nome_pais | |
| + nome_without_special_char = transliterate(self.nome_pais, :pt).downcase.gsub(" ", "_") | |
| + if I18n.locale == :pt | |
| + I18n.t("countries.#{nome_without_special_char}") | |
| + else | |
| + I18n.t("countries.#{nome_without_special_char}") | |
| + end | |
| + end | |
| + | |
| + def filter_label | |
| + I18n.t("filter.pais") | |
| end | |
| end | |
| diff --git a/app/models/pelicula.rb b/app/models/pelicula.rb | |
| index 578cb31..33ccf13 100644 | |
| --- a/app/models/pelicula.rb | |
| +++ b/app/models/pelicula.rb | |
| @@ -23,7 +23,20 @@ class Pelicula < ApplicationRecord | |
| .uniq | |
| .sort | |
| - genres.map { |g| { "filter_display" => g, "filter_value" => g } } | |
| + genres.map { |g| { "filter_display" => g, "filter_value" => g, "filter_label" => I18n.t("filter.genero") } } | |
| + # end | |
| + end | |
| + | |
| + def self.directors_for(edicao_id) | |
| + # Rails.cache.fetch("directors-for-edicao-#{edicao_id}", expires_in: 12.hours) do | |
| + where(edicao_id: edicao_id) | |
| + .where.not(diretor_coord_int: [nil, ""]) | |
| + .pluck(:diretor_coord_int) | |
| + .map(&:strip) | |
| + .uniq | |
| + .compact | |
| + .sort | |
| + .map { |director| { "filter_display" => director, "filter_value" => director, "filter_label" => I18n.t("filter.direcao") } } | |
| # end | |
| end | |
| diff --git a/app/models/programacao.rb b/app/models/programacao.rb | |
| index 639fa4b..086897a 100644 | |
| --- a/app/models/programacao.rb | |
| +++ b/app/models/programacao.rb | |
| @@ -18,4 +18,8 @@ class Programacao < ApplicationRecord | |
| def filter_display | |
| sessao.strftime("%Hh%M") | |
| end | |
| + | |
| + def filter_label | |
| + I18n.t("filter.time") | |
| + end | |
| end | |
| diff --git a/config/locales/en.yml b/config/locales/en.yml | |
| index 15ced19..b23ad61 100644 | |
| --- a/config/locales/en.yml | |
| +++ b/config/locales/en.yml | |
| @@ -34,7 +34,7 @@ en: | |
| date: "Date" | |
| time: "Time" | |
| submostra: "Showcase" | |
| - cinema: "Cinema" | |
| + cinema: "Theater" | |
| genero: "Genre" | |
| pais: "Country" | |
| direcao: "Director" | |
| @@ -58,3 +58,121 @@ en: | |
| placeholder: | |
| select: "Pick one" | |
| + | |
| + countries: | |
| + afeganistao: "Afghanistan" | |
| + albania: "Albania" | |
| + argelia: "Algeria" | |
| + angola: "Angola" | |
| + argentina: "Argentina" | |
| + armenia: "Armenia" | |
| + australia: "Australia" | |
| + austria: "Austria" | |
| + belgica: "Belgium" | |
| + butao: "Bhutan" | |
| + bolivia: "Bolivia" | |
| + bosnia_herzegovina: "Bosnia and Herzegovina" | |
| + brasil: "Brazil" | |
| + bulgaria: "Bulgaria" | |
| + camboja: "Cambodia" | |
| + canada: "Canada" | |
| + chile: "Chile" | |
| + china: "China" | |
| + colombia: "Colombia" | |
| + congo: "Congo" | |
| + congo_republica_democratica: "Democratic Republic of the Congo" | |
| + costa_rica: "Costa Rica" | |
| + croacia: "Croatia" | |
| + cuba: "Cuba" | |
| + chipre: "Cyprus" | |
| + republica_tcheca: "Czech Republic" | |
| + tchecoslovaquia: "Czechoslovakia" | |
| + dinamarca: "Denmark" | |
| + republica_dominicana: "Dominican Republic" | |
| + equador: "Ecuador" | |
| + egito: "Egypt" | |
| + estonia: "Estonia" | |
| + finlandia: "Finland" | |
| + franca: "France" | |
| + georgia: "Georgia" | |
| + alemanha: "Germany" | |
| + alemanha_ocidental: "West Germany" | |
| + grecia: "Greece" | |
| + guatemala: "Guatemala" | |
| + guiana: "Guyana" | |
| + hong_kong: "Hong Kong" | |
| + hungria: "Hungary" | |
| + islandia: "Iceland" | |
| + india: "India" | |
| + indonesia: "Indonesia" | |
| + ira: "Iran" | |
| + irlanda: "Ireland" | |
| + israel: "Israel" | |
| + italia: "Italy" | |
| + japao: "Japan" | |
| + jordania: "Jordan" | |
| + casaquistao: "Kazakhstan" | |
| + quenia: "Kenya" | |
| + kyrgyztan: "Kyrgyzstan" | |
| + libano: "Lebanon" | |
| + lituania: "Lithuania" | |
| + luxemburgo: "Luxembourg" | |
| + macedonia: "North Macedonia" | |
| + macedonia_antiga_iugoslavia: "North Macedonia" | |
| + mali: "Mali" | |
| + mauritania: "Mauritania" | |
| + mexico: "Mexico" | |
| + moldavia: "Moldova" | |
| + mongolia: "Mongolia" | |
| + marrocos: "Morocco" | |
| + mocambique: "Mozambique" | |
| + myanmar: "Myanmar" | |
| + nepal: "Nepal" | |
| + holanda: "Netherlands" | |
| + paises_baixos: "Netherlands" | |
| + nova_zelandia: "New Zealand" | |
| + niger: "Niger" | |
| + nigeria: "Nigeria" | |
| + noruega: "Norway" | |
| + paquistao: "Pakistan" | |
| + palestina: "Palestine" | |
| + panama: "Panama" | |
| + paraguai: "Paraguay" | |
| + peru: "Peru" | |
| + filipinas: "Philippines" | |
| + polonia: "Poland" | |
| + portugal: "Portugal" | |
| + catar: "Qatar" | |
| + qatar: "Qatar" | |
| + romenia: "Romania" | |
| + russia: "Russia" | |
| + ruanda: "Rwanda" | |
| + arabia_saudita: "Saudi Arabia" | |
| + senegal: "Senegal" | |
| + servia: "Serbia" | |
| + singapura: "Singapore" | |
| + eslovaquia: "Slovakia" | |
| + eslovenia: "Slovenia" | |
| + africa_do_sul: "South Africa" | |
| + coreia_do_sul: "South Korea" | |
| + espanha: "Spain" | |
| + sri_lanka: "Sri Lanka" | |
| + sri_lanca: "Sri Lanka" | |
| + sudao: "Sudan" | |
| + suecia: "Sweden" | |
| + suica: "Switzerland" | |
| + siria: "Syria" | |
| + taiwan: "Taiwan" | |
| + tailandia: "Thailand" | |
| + tunisia: "Tunisia" | |
| + turquia: "Turkey" | |
| + emirados_arabes_unidos: "United Arab Emirates" | |
| + ucrania: "Ukraine" | |
| + reino_unido: "United Kingdom" | |
| + estados_unidos: "United States" | |
| + estados_unidos_da_america: "United States of America" | |
| + uruguai: "Uruguay" | |
| + vietname: "Vietnam" | |
| + iemen: "Yemen" | |
| + zambia: "Zambia" | |
| + acrotiri_e_decelia: "Acrotíri e Decelia" | |
| diff --git a/config/locales/pt.yml b/config/locales/pt.yml | |
| index bc71dcf..476fdc7 100644 | |
| --- a/config/locales/pt.yml | |
| +++ b/config/locales/pt.yml | |
| @@ -84,3 +84,121 @@ pt: | |
| - Out | |
| - Nov | |
| - Dez | |
| + | |
| + countries: | |
| + acrotiri_e_decelia: "Acrotíri e Decelia" | |
| + afeganistao: "Afeganistão" | |
| + albania: "Albânia" | |
| + argelia: "Argélia" | |
| + angola: "Angola" | |
| + argentina: "Argentina" | |
| + armenia: "Armênia" | |
| + australia: "Austrália" | |
| + austria: "Áustria" | |
| + belgica: "Bélgica" | |
| + butao: "Butão" | |
| + bolivia: "Bolívia" | |
| + bosnia_herzegovina: "Bósnia e Herzegovina" | |
| + brasil: "Brasil" | |
| + bulgaria: "Bulgária" | |
| + camboja: "Camboja" | |
| + canada: "Canadá" | |
| + chile: "Chile" | |
| + china: "China" | |
| + colombia: "Colômbia" | |
| + congo: "Congo" | |
| + congo_republica_democratica: "Congo República Democrática" | |
| + costa_rica: "Costa Rica" | |
| + croacia: "Croácia" | |
| + cuba: "Cuba" | |
| + chipre: "Chipre" | |
| + republica_tcheca: "República Tcheca" | |
| + tchecoslovaquia: "Tchecoslováquia" | |
| + dinamarca: "Dinamarca" | |
| + republica_dominicana: "República Dominicana" | |
| + equador: "Equador" | |
| + egito: "Egito" | |
| + estonia: "Estônia" | |
| + finlandia: "Finlândia" | |
| + franca: "França" | |
| + georgia: "Geórgia" | |
| + alemanha: "Alemanha" | |
| + alemanha_ocidental: "Alemanha Ocidental" | |
| + grecia: "Grécia" | |
| + guatemala: "Guatemala" | |
| + guiana: "Guiana" | |
| + hong_kong: "Hong Kong" | |
| + hungria: "Hungria" | |
| + islandia: "Islândia" | |
| + india: "Índia" | |
| + indonesia: "Indonésia" | |
| + ira: "Irã" | |
| + irlanda: "Irlanda" | |
| + israel: "Israel" | |
| + italia: "Itália" | |
| + japao: "Japão" | |
| + jordania: "Jordânia" | |
| + casaquistao: "Casaquistão" | |
| + quenia: "Quênia" | |
| + kyrgyztan: "Kyrgyztan" | |
| + libano: "Líbano" | |
| + lituania: "Lituânia" | |
| + luxemburgo: "Luxemburgo" | |
| + macedonia: "Macedônia" | |
| + macedonia_antiga_iugoslavia: "Macedônia, antiga Iugoslávia" | |
| + mali: "Mali" | |
| + mauritania: "Mauritânia" | |
| + mexico: "México" | |
| + moldavia: "Moldávia" | |
| + mongolia: "Mongólia" | |
| + marrocos: "Marrocos" | |
| + mocambique: "Moçambique" | |
| + myanmar: "Myanmar" | |
| + nepal: "Nepal" | |
| + holanda: "Holanda" | |
| + paises_baixos: "Países Baixos" | |
| + nova_zelandia: "Nova Zelândia" | |
| + niger: "Niger" | |
| + nigeria: "Nigéria" | |
| + noruega: "Noruega" | |
| + paquistao: "Paquistão" | |
| + palestina: "Palestina" | |
| + panama: "Panamá" | |
| + paraguai: "Paraguai" | |
| + peru: "Peru" | |
| + filipinas: "Filipinas" | |
| + polonia: "Polônia" | |
| + portugal: "Portugal" | |
| + catar: "Catar" | |
| + qatar: "Qatar" | |
| + romenia: "Romênia" | |
| + russia: "Rússia" | |
| + ruanda: "Ruanda" | |
| + arabia_saudita: "Arábia Saudita" | |
| + senegal: "Senegal" | |
| + servia: "Sérvia" | |
| + singapura: "Singapura" | |
| + eslovaquia: "Eslováquia" | |
| + eslovenia: "Eslovênia" | |
| + africa_do_sul: "África do Sul" | |
| + coreia_do_sul: "Coreia do Sul" | |
| + espanha: "Espanha" | |
| + sri_lanka: "Sri Lanka" | |
| + sri_lanca: "Sri Lanca" | |
| + sudao: "Sudão" | |
| + suecia: "Suécia" | |
| + suica: "Suíça" | |
| + siria: "Síria" | |
| + taiwan: "Taiwan" | |
| + tailandia: "Tailândia" | |
| + tunisia: "Tunísia" | |
| + turquia: "Turquia" | |
| + emirados_arabes_unidos: "Emirados Árabes Unidos" | |
| + ucrania: "Ucrânia" | |
| + reino_unido: "Reino Unido" | |
| + estados_unidos: "Estados Unidos" | |
| + estados_unidos_da_america: "Estados Unidos da América" | |
| + uruguai: "Uruguai" | |
| + vietname: "Vietname" | |
| + iemen: "Iémen" | |
| + zambia: "Zâmbia" | |
| diff --git a/package-lock.json b/package-lock.json | |
| index c7287e5..812a055 100644 | |
| --- a/package-lock.json | |
| +++ b/package-lock.json | |
| @@ -4,7 +4,6 @@ | |
| "requires": true, | |
| "packages": { | |
| "": { | |
| - "name": "riff-inertia", | |
| "dependencies": { | |
| "@inertiajs/vue3": "^2.1.3", | |
| "@tailwindcss/forms": "^0.5.10", | |
| diff --git a/test/controllers/programs_controller/director_filter_test.rb b/test/controllers/programs_controller/director_filter_test.rb | |
| new file mode 100644 | |
| index 0000000..92c6382 | |
| --- /dev/null | |
| +++ b/test/controllers/programs_controller/director_filter_test.rb | |
| @@ -0,0 +1,356 @@ | |
| +require "test_helper" | |
| + | |
| +class ProgramsController::DirectorFilterTest < ActionDispatch::IntegrationTest | |
| + test "filters by director - Christopher Nolan" do | |
| + get program_url, params: { director: "Christopher Nolan" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + | |
| + elements.each do |element| | |
| + assert_includes ["Batman"], element["titulo"] | |
| + # Verify the director matches the filter | |
| + end | |
| + end | |
| + | |
| + test "filters by director - Wachowskis" do | |
| + get program_url, params: { director: "Wachowskis" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + # Should include just Matrix os 17 sao outro dia | |
| + assert_equal 1, elements.length | |
| + | |
| + # Check total count via pagination | |
| + total_elements = props["pagy"]["count"] | |
| + assert_equal 1, total_elements | |
| + end | |
| + | |
| + test "filters by director - João Silva" do | |
| + get program_url, params: { director: "João Silva" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + | |
| + elements.each do |element| | |
| + assert_includes ["Cidade Perdida"], element["titulo"] | |
| + end | |
| + end | |
| + | |
| + test "filters by director - Ana Pereira" do | |
| + get program_url, params: { director: "Ana Pereira" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + | |
| + elements.each do |element| | |
| + assert_includes ["Amor em Brasília"], element["titulo"] | |
| + end | |
| + end | |
| + | |
| + test "filters by director - Hans Mueller" do | |
| + get program_url, params: { director: "Hans Mueller" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + | |
| + elements.each do |element| | |
| + assert_includes ["Berlin Nights"], element["titulo"] | |
| + end | |
| + end | |
| + | |
| + test "filters by director - Pierre Dubois" do | |
| + get program_url, params: { director: "Pierre Dubois" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + | |
| + elements.each do |element| | |
| + assert_includes ["Paris Stories"], element["titulo"] | |
| + end | |
| + end | |
| + | |
| + test "filters by director - Roberto Oliveira" do | |
| + get program_url, params: { director: "Roberto Oliveira" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + | |
| + elements.each do |element| | |
| + assert_includes ["Amazônia Selvagem"], element["titulo"] | |
| + end | |
| + end | |
| + | |
| + test "filters by director - Marina Costa" do | |
| + get program_url, params: { director: "Marina Costa" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + | |
| + elements.each do |element| | |
| + assert_includes ["Cidade em Transformação"], element["titulo"] | |
| + end | |
| + end | |
| + | |
| + test "filters by director - Marcos Jorge" do | |
| + get program_url, params: { director: "Marcos Jorge" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + | |
| + elements.each do |element| | |
| + assert_includes ["São Paulo"], element["titulo"] | |
| + end | |
| + end | |
| + | |
| + # COMBINED FILTERS TESTS WITH DIRECTOR | |
| + test "combines search query and director filter" do | |
| + get program_url, params: { | |
| + query: "Batman", | |
| + director: "Christopher Nolan" | |
| + } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + assert_equal "Batman", elements.first["titulo"] | |
| + | |
| + # Verify both filters are preserved | |
| + assert_equal "Batman", props["current_filters"]["query"]["filter_value"] | |
| + assert_equal "Christopher Nolan", props["current_filters"]["director"]["filter_value"] | |
| + end | |
| + | |
| + test "combines search query and director filter with no results" do | |
| + get program_url, params: { | |
| + query: "Batman", | |
| + director: "Wachowskis" | |
| + } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + # Batman is directed by Christopher Nolan, not Wachowskis | |
| + elements = props["elements"] | |
| + assert_equal 0, elements.length | |
| + | |
| + # Filters should still be preserved | |
| + assert_equal "Batman", props["current_filters"]["query"]["filter_value"] | |
| + assert_equal "Wachowskis", props["current_filters"]["director"]["filter_value"] | |
| + end | |
| + | |
| + test "search finds movies across different directors" do | |
| + get program_url, params: { query: "Cidade" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 2, elements.length | |
| + | |
| + titles = elements.map { |e| e["titulo"] } | |
| + | |
| + assert_includes titles, "Cidade Perdida" # directed by João Silva | |
| + assert_includes titles, "Cidade em Transformação" # directed by Marina Costa | |
| + end | |
| + | |
| + test "combines director filter with mostra filter" do | |
| + get program_url, params: { | |
| + director: "João Silva", | |
| + mostra: "competicao-nacional" | |
| + } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + assert_equal "Cidade Perdida", elements.first["titulo"] | |
| + | |
| + # Verify both filters are preserved | |
| + assert_equal "João Silva", props["current_filters"]["director"]["filter_value"] | |
| + assert_equal "competicao-nacional", props["current_filters"]["mostra"]["permalink_pt"] | |
| + end | |
| + | |
| + test "combines director filter with mostra filter with no results" do | |
| + get program_url, params: { | |
| + director: "Christopher Nolan", | |
| + mostra: "competicao-nacional" | |
| + } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + # Christopher Nolan's Batman is in sci_fi mostra, not competicao-nacional | |
| + elements = props["elements"] | |
| + assert_equal 0, elements.length | |
| + | |
| + # Filters should still be preserved | |
| + assert_equal "Christopher Nolan", props["current_filters"]["director"]["filter_value"] | |
| + assert_equal "competicao-nacional", props["current_filters"]["mostra"]["permalink_pt"] | |
| + end | |
| + | |
| + test "combines director filter with cinema filter" do | |
| + cinepolis = cinemas(:cinepolis) | |
| + get program_url, params: { | |
| + director: "João Silva", | |
| + cinema: cinepolis.id | |
| + } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + # This depends on which cinemas show João Silva's movies | |
| + # Adjust expected count based on fixtures | |
| + assert elements.length >= 0 | |
| + | |
| + elements.each do |element| | |
| + end | |
| + | |
| + # Verify both filters are preserved | |
| + assert_equal "João Silva", props["current_filters"]["director"]["filter_value"] | |
| + assert_equal cinepolis.id, props["current_filters"]["cinema"]["id"] | |
| + end | |
| + | |
| + test "director filter affects available dates" do | |
| + get program_url, params: { director: "Christopher Nolan" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + available_dates = props["menuTabs"].map { _1["date"] } | |
| + # Should only show dates where Christopher Nolan movies are programmed | |
| + # Adjust expected dates based on your programacoes fixtures | |
| + assert available_dates.length >= 0 | |
| + end | |
| + | |
| + test "preserves director filter when navigating dates" do | |
| + get program_url, params: { | |
| + director: "Wachowskis", | |
| + date: "2024-10-07" # Adjust date based on when Wachowskis movies are shown | |
| + } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + elements.each do |element| | |
| + end | |
| + | |
| + # Filter should be preserved | |
| + assert_equal "Wachowskis", props["current_filters"]["director"]["filter_value"] | |
| + end | |
| + | |
| + test "combines all filters - search, director, mostra, cinema, and date" do | |
| + cinepolis = cinemas(:cinepolis) | |
| + get program_url, params: { | |
| + query: "Matrix", | |
| + director: "Wachowskis", | |
| + mostra: "sci-fi", # Adjust based on actual mostra permalink | |
| + cinema: cinepolis.id, | |
| + date: "2024-10-06" # Adjust based on when Matrix is shown at Cinépolis | |
| + } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + # Expect 1 result if all filters align, 0 if they don't | |
| + elements.each do |element| | |
| + assert_includes element["titulo"], "Matrix" | |
| + end | |
| + | |
| + # All filters should be preserved | |
| + assert_equal "Matrix", props["current_filters"]["query"]["filter_value"] | |
| + assert_equal "Wachowskis", props["current_filters"]["director"]["filter_value"] | |
| + # Adjust mostra assertion based on actual data structure | |
| + assert_equal cinepolis.id, props["current_filters"]["cinema"]["id"] | |
| + end | |
| + | |
| + test "returns correct director options in props" do | |
| + get program_url | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + directors_filter = props["directors"] | |
| + assert directors_filter.is_a?(Array) | |
| + assert directors_filter.length >= 8 # At least the directors from fixtures | |
| + | |
| + # Check that key directors are included | |
| + director_names = directors_filter.map { |d| d["filter_value"] || d["nome"] || d } | |
| + assert_includes director_names, "Christopher Nolan" | |
| + assert_includes director_names, "Wachowskis" | |
| + assert_includes director_names, "João Silva" | |
| + assert_includes director_names, "Ana Pereira" | |
| + assert_includes director_names, "Hans Mueller" | |
| + assert_includes director_names, "Pierre Dubois" | |
| + assert_includes director_names, "Roberto Oliveira" | |
| + assert_includes director_names, "Marina Costa" | |
| + assert_includes director_names, "Marcos Jorge" | |
| + | |
| + # Check structure of director objects (adjust based on actual implementation) | |
| + unless directors_filter.empty? | |
| + director = directors_filter.first | |
| + # This depends on how the controller structures the director filter options | |
| + # Common patterns: simple array of strings, or array of hashes with keys | |
| + assert (director.is_a?(String) || director.is_a?(Hash)) | |
| + end | |
| + end | |
| + | |
| + test "handles empty director filter gracefully" do | |
| + get program_url, params: { director: "" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + # Empty filter should behave like no filter - return all elements | |
| + elements = props["elements"] | |
| + assert elements.length > 0 | |
| + | |
| + selected_filters = props["current_filters"] | |
| + # Empty filter should not be preserved | |
| + assert_nil selected_filters["director"] | |
| + end | |
| + | |
| + test "director filter with special characters" do | |
| + # Test with director that has special characters if any exist in your fixtures | |
| + # This is more relevant if you have international directors with accents, etc. | |
| + get program_url, params: { director: "Marcos Jorge" } | |
| + | |
| + assert_response :success | |
| + props = inertia_props | |
| + | |
| + elements = props["elements"] | |
| + assert_equal 1, elements.length | |
| + assert_equal "São Paulo", elements.first["titulo"] | |
| + end | |
| +end | |
| diff --git a/test/controllers/programs_controller_test.rb b/test/controllers/programs_controller_test.rb | |
| index fc152b3..7f6b187 100644 | |
| --- a/test/controllers/programs_controller_test.rb | |
| +++ b/test/controllers/programs_controller_test.rb | |
| @@ -277,7 +277,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| end | |
| test "filters by mostra - competicao nacional" do | |
| - get program_url, params: { mostrasFilter: "competicao-nacional" } | |
| + get program_url, params: { mostra: "competicao-nacional" } | |
| assert_response :success | |
| props = inertia_props | |
| @@ -291,7 +291,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| end | |
| test "filters by mostra - mostra internacional" do | |
| - get program_url, params: { mostrasFilter: "mostra-internacional" } | |
| + get program_url, params: { mostra: "mostra-internacional" } | |
| assert_response :success | |
| props = inertia_props | |
| @@ -305,7 +305,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| end | |
| test "filters by mostra - documentarios" do | |
| - get program_url, params: { mostrasFilter: "documentarios" } | |
| + get program_url, params: { mostra: "documentarios" } | |
| assert_response :success | |
| props = inertia_props | |
| @@ -319,7 +319,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| end | |
| test "handles invalid mostra filter gracefully" do | |
| - get program_url, params: { mostrasFilter: "non-existent-mostra" } | |
| + get program_url, params: { mostra: "non-existent-mostra" } | |
| assert_response :success | |
| props = inertia_props | |
| @@ -330,14 +330,14 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| # selectedFilters should be empty | |
| selected_filters = props["current_filters"] | |
| - assert_nil selected_filters["mostrasFilter"] | |
| + assert_nil selected_filters["mostra"] | |
| end | |
| # COMBINED FILTERS TESTS | |
| test "combines search query and mostra filter" do | |
| get program_url, params: { | |
| query: "Cidade", | |
| - mostrasFilter: "competicao-nacional" | |
| + mostra: "competicao-nacional" | |
| } | |
| assert_response :success | |
| @@ -349,13 +349,13 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| # Verify both filters are preserved | |
| assert_equal "Cidade", props["current_filters"]["query"]["filter_value"] | |
| - assert_equal "competicao-nacional", props["current_filters"]["mostrasFilter"]["permalink_pt"] | |
| + assert_equal "competicao-nacional", props["current_filters"]["mostra"]["permalink_pt"] | |
| end | |
| test "combines search query and mostra filter with no results" do | |
| get program_url, params: { | |
| query: "Paris", | |
| - mostrasFilter: "competicao-nacional" | |
| + mostra: "competicao-nacional" | |
| } | |
| assert_response :success | |
| @@ -367,7 +367,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| # Filters should still be preserved | |
| assert_equal "Paris", props["current_filters"]["query"]["filter_value"] | |
| - assert_equal "competicao-nacional", props["current_filters"]["mostrasFilter"]["permalink_pt"] | |
| + assert_equal "competicao-nacional", props["current_filters"]["mostra"]["permalink_pt"] | |
| end | |
| test "search finds movies across different mostras" do | |
| @@ -386,7 +386,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| test "mostra filter affects available dates" do | |
| # Documentarios only has content on 2024-10-05, 2024-10-06 and 2024-10-07 | |
| - get program_url, params: { mostrasFilter: "documentarios" } | |
| + get program_url, params: { mostra: "documentarios" } | |
| assert_response :success | |
| props = inertia_props | |
| @@ -398,7 +398,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| test "preserves mostra filter when navigating dates" do | |
| get program_url, params: { | |
| - mostrasFilter: "competicao-nacional", | |
| + mostra: "competicao-nacional", | |
| date: "2024-10-06" | |
| } | |
| @@ -411,13 +411,13 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| assert_equal "Cidade Perdida", elements.first["titulo"] | |
| # Filter should be preserved | |
| - assert_equal "competicao-nacional", props["current_filters"]["mostrasFilter"]["permalink_pt"] | |
| + assert_equal "competicao-nacional", props["current_filters"]["mostra"]["permalink_pt"] | |
| end | |
| test "combines all filters - search, mostra, and date" do | |
| get program_url, params: { | |
| query: "Cidade", | |
| - mostrasFilter: "documentarios", | |
| + mostra: "documentarios", | |
| date: "2024-10-07" | |
| } | |
| @@ -430,13 +430,13 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| # All filters should be preserved | |
| assert_equal "Cidade", props["current_filters"]["query"]["filter_value"] | |
| - assert_equal "documentarios", props["current_filters"]["mostrasFilter"]["permalink_pt"] | |
| + assert_equal "documentarios", props["current_filters"]["mostra"]["permalink_pt"] | |
| assert_includes props["menuTabs"].map { _1["date"] }, "2024-10-07" | |
| end | |
| test "mostra filter with pagination" do | |
| get program_url, params: { | |
| - mostrasFilter: "competicao-nacional" | |
| + mostra: "competicao-nacional" | |
| } | |
| assert_response :success | |
| @@ -455,13 +455,13 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| assert_equal 1, pagy["page"] | |
| end | |
| - test "returns correct mostrasFilter options in props" do | |
| + test "returns correct mostras options in props" do | |
| get program_url | |
| assert_response :success | |
| props = inertia_props | |
| - mostras_filter = props["mostrasFilter"] | |
| + mostras_filter = props["mostras"] | |
| assert_equal 4, mostras_filter.length | |
| # Check that all mostras are included | |
| @@ -481,13 +481,13 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| get program_url | |
| assert_response :success | |
| props = inertia_props | |
| - cinema_options = props["cinemasFilter"] | |
| + cinema_options = props["cinemas"] | |
| assert_equal 2, cinema_options.length | |
| end | |
| test "filters by cinema - cine brasilia" do | |
| cine_brasilia = cinemas(:cine_brasilia) | |
| - get program_url, params: { cinemasFilter: cine_brasilia.id } | |
| + get program_url, params: { cinema: cine_brasilia.id } | |
| assert_response :success | |
| props = inertia_props | |
| @@ -501,7 +501,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| end | |
| test "filters by cinema - cinepolis" do | |
| cinepolis = cinemas(:cinepolis) | |
| - get program_url, params: { cinemasFilter: cinepolis.id } | |
| + get program_url, params: { cinema: cinepolis.id } | |
| assert_response :success | |
| props = inertia_props | |
| @@ -515,7 +515,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| end | |
| test "handles invalid cinema filter gracefully" do | |
| - get program_url, params: { cinemasFilter: 999_999 } | |
| + get program_url, params: { cinema: 999_999 } | |
| assert_response :success | |
| props = inertia_props | |
| @@ -524,14 +524,14 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| assert props["elements"].length > 0 | |
| selected_filters = props["current_filters"] | |
| - assert_nil selected_filters["cinemasFilter"] | |
| + assert_nil selected_filters["cinema"] | |
| end | |
| test "combines search query and cinema filter" do | |
| cinepolis = cinemas(:cinepolis) | |
| get program_url, params: { | |
| query: "Batman", | |
| - cinemasFilter: cinepolis.id | |
| + cinema: cinepolis.id | |
| } | |
| assert_response :success | |
| @@ -543,14 +543,14 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| # Filters preserved | |
| assert_equal "Batman", props["current_filters"]["query"]["filter_value"] | |
| - assert_equal cinepolis.id, props["current_filters"]["cinemasFilter"]["id"] | |
| + assert_equal cinepolis.id, props["current_filters"]["cinema"]["id"] | |
| end | |
| test "combines search query and cinema filter with no results" do | |
| cine_brasilia = cinemas(:cine_brasilia) | |
| get program_url, params: { | |
| query: "Batman", | |
| - cinemasFilter: cine_brasilia.id | |
| + cinema: cine_brasilia.id | |
| } | |
| assert_response :success | |
| @@ -560,7 +560,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| # Filters preserved | |
| assert_equal "Batman", props["current_filters"]["query"]["filter_value"] | |
| - assert_equal cine_brasilia.id, props["current_filters"]["cinemasFilter"]["id"] | |
| + assert_equal cine_brasilia.id, props["current_filters"]["cinema"]["id"] | |
| end | |
| test "search finds movies across different cinemas" do | |
| @@ -578,7 +578,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| test "cinema filter affects available dates" do | |
| cine_brasilia = cinemas(:cine_brasilia) | |
| - get program_url, params: { cinemasFilter: cine_brasilia.id } | |
| + get program_url, params: { cinema: cine_brasilia.id } | |
| assert_response :success | |
| props = inertia_props | |
| @@ -590,7 +590,7 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| test "preserves cinema filter when navigating dates" do | |
| cinepolis = cinemas(:cinepolis) | |
| get program_url, params: { | |
| - cinemasFilter: cinepolis.id, | |
| + cinema: cinepolis.id, | |
| date: "2024-10-06" | |
| } | |
| @@ -602,14 +602,14 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| assert_includes titles, "Amazônia Selvagem" | |
| assert_includes titles, "Matrix" | |
| - assert_equal cinepolis.id, props["current_filters"]["cinemasFilter"]["id"] | |
| + assert_equal cinepolis.id, props["current_filters"]["cinema"]["id"] | |
| end | |
| test "combines all filters - search, cinema, and date" do | |
| cinepolis = cinemas(:cinepolis) | |
| get program_url, params: { | |
| query: "Cidade", | |
| - cinemasFilter: cinepolis.id, | |
| + cinema: cinepolis.id, | |
| date: "2024-10-07" | |
| } | |
| @@ -621,13 +621,13 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| assert_equal "Cidade em Transformação", elements.first["titulo"] | |
| assert_equal "Cidade", props["current_filters"]["query"]["filter_value"] | |
| - assert_equal cinepolis.id, props["current_filters"]["cinemasFilter"]["id"] | |
| + assert_equal cinepolis.id, props["current_filters"]["cinema"]["id"] | |
| assert_includes props["menuTabs"].map { _1["date"] }, "2024-10-07" | |
| end | |
| test "cinema filter with pagination" do | |
| cine_brasilia = cinemas(:cine_brasilia) | |
| - get program_url, params: { cinemasFilter: cine_brasilia.id } | |
| + get program_url, params: { cinema: cine_brasilia.id } | |
| assert_response :success | |
| props = inertia_props | |
| @@ -637,13 +637,13 @@ class ProgramsControllerTest < ActionDispatch::IntegrationTest | |
| assert_equal 17, props["pagy"]["count"] | |
| end | |
| - test "returns correct cinemasFilter options in props" do | |
| + test "returns correct cinemas options in props" do | |
| get program_url | |
| assert_response :success | |
| props = inertia_props | |
| - cinemas_filter = props["cinemasFilter"] | |
| + cinemas_filter = props["cinemas"] | |
| assert_equal 2, cinemas_filter.length | |
| names = cinemas_filter.map { _1["nome"] } | |
| diff --git a/test/test_helper.rb b/test/test_helper.rb | |
| index 9f2d5a5..7966786 100644 | |
| --- a/test/test_helper.rb | |
| +++ b/test/test_helper.rb | |
| @@ -5,7 +5,7 @@ require "rails/test_help" | |
| module ActiveSupport | |
| class TestCase | |
| # Run tests in parallel with specified workers | |
| - parallelize(workers: :number_of_processors) | |
| + parallelize(workers: 1) | |
| # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. | |
| fixtures :all |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment