Resolved ALL eslint issues for project

This commit is contained in:
2022-08-12 23:46:55 +02:00
parent 29dfe55974
commit 3594b18872
63 changed files with 1064 additions and 800 deletions

View File

@@ -1,13 +1,12 @@
<template>
<transition name="shut">
<ul class="dropdown">
<!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events -->
<li
v-for="result in searchResults"
:key="`${result.index}-${result.title}-${result.type}`"
v-for="(result, _index) in searchResults"
:key="`${_index}-${result.title}-${result.type}`"
:class="`result di-${_index} ${_index === index ? 'active' : ''}`"
@click="openPopup(result)"
:class="`result di-${result.index} ${
result.index === index ? 'active' : ''
}`"
>
<IconMovie v-if="result.type == 'movie'" class="type-icon" />
<IconShow v-if="result.type == 'show'" class="type-icon" />
@@ -29,36 +28,38 @@
import { useStore } from "vuex";
import IconMovie from "@/icons/IconMovie.vue";
import IconShow from "@/icons/IconShow.vue";
import IconPerson from "@/icons/IconPerson.vue";
import { elasticSearchMoviesAndShows } from "../../api";
import type { Ref } from "vue";
import { elasticSearchMoviesAndShows } from "../../api";
import { MediaTypes } from "../../interfaces/IList";
import { Index } from "../../interfaces/IAutocompleteSearch";
import type {
IAutocompleteResult,
IAutocompleteSearchResults
} from "../../interfaces/IAutocompleteSearch";
interface Props {
query?: string;
index?: Number;
results?: Array<any>;
index?: number;
results?: Array<IAutocompleteResult>;
}
interface Emit {
(e: "update:results", value: Array<any>);
(e: "update:results", value: Array<IAutocompleteResult>);
}
const numberOfResults: number = 10;
const numberOfResults = 10;
const props = defineProps<Props>();
const emit = defineEmits<Emit>();
const store = useStore();
const searchResults: Ref<Array<any>> = ref([]);
const searchResults: Ref<Array<IAutocompleteResult>> = ref([]);
const keyboardNavigationIndex: Ref<number> = ref(0);
// on load functions
fetchAutocompleteResults();
// end on load functions
watch(
() => props.query,
newQuery => {
if (newQuery?.length > 0) fetchAutocompleteResults();
if (newQuery?.length > 0)
fetchAutocompleteResults(); /* eslint-disable-line no-use-before-define */
}
);
@@ -68,6 +69,53 @@
store.dispatch("popup/open", { ...result });
}
function removeDuplicates(_searchResults) {
const filteredResults = [];
_searchResults.forEach(result => {
if (result === undefined) return;
const numberOfDuplicates = filteredResults.filter(
filterItem => filterItem.id === result.id
);
if (numberOfDuplicates.length >= 1) {
return;
}
filteredResults.push(result);
});
return filteredResults;
}
function elasticIndexToMediaType(index: Index): MediaTypes {
if (index === Index.Movies) return MediaTypes.Movie;
if (index === Index.Shows) return MediaTypes.Show;
return null;
}
function parseElasticResponse(elasticResponse: IAutocompleteSearchResults) {
const data = elasticResponse.hits.hits;
const results: Array<IAutocompleteResult> = [];
data.forEach(item => {
if (!Object.values(Index).includes(item._index)) {
return;
}
results.push({
title: item._source?.original_name || item._source.original_title,
id: item._source.id,
adult: item._source.adult,
type: elasticIndexToMediaType(item._index)
});
});
return removeDuplicates(results).map((el, index) => {
return { ...el, index };
});
}
function fetchAutocompleteResults() {
keyboardNavigationIndex.value = 0;
searchResults.value = [];
@@ -80,44 +128,9 @@
});
}
function parseElasticResponse(elasticResponse: any) {
const data = elasticResponse.hits.hits;
let results = data.map(item => {
let index = null;
if (item._source.log.file.path.includes("movie")) index = "movie";
if (item._source.log.file.path.includes("series")) index = "show";
if (index === "movie" || index === "show") {
return {
title: item._source.original_name || item._source.original_title,
id: item._source.id,
adult: item._source.adult,
type: index
};
}
});
return removeDuplicates(results).map((el, index) => {
return { ...el, index };
});
}
function removeDuplicates(searchResults) {
let filteredResults = [];
searchResults.map(result => {
if (result === undefined) return;
const numberOfDuplicates = filteredResults.filter(
filterItem => filterItem.id == result.id
);
if (numberOfDuplicates.length >= 1) {
return null;
}
filteredResults.push(result);
});
return filteredResults;
}
// on load functions
fetchAutocompleteResults();
// end on load functions
</script>
<style lang="scss" scoped>

View File

@@ -1,8 +1,10 @@
<template>
<nav>
<!-- eslint-disable-next-line vuejs-accessibility/anchor-has-content -->
<a v-if="isHome" class="nav__logo" href="/">
<TmdbLogo class="logo" />
</a>
<router-link v-else class="nav__logo" to="/" exact>
<TmdbLogo class="logo" />
</router-link>
@@ -13,7 +15,7 @@
<NavigationIcon class="desktop-only" :route="profileRoute" />
<!-- <div class="navigation-icons-grid mobile-only" :class="{ open: isOpen }"> -->
<div class="navigation-icons-grid mobile-only" v-if="isOpen">
<div v-if="isOpen" class="navigation-icons-grid mobile-only">
<NavigationIcons>
<NavigationIcon :route="profileRoute" />
</NavigationIcons>
@@ -22,8 +24,7 @@
</template>
<script setup lang="ts">
import { computed, defineProps, PropType } from "vue";
import type { App } from "vue";
import { computed } from "vue";
import { useStore } from "vuex";
import { useRoute } from "vue-router";
import SearchInput from "@/components/header/SearchInput.vue";

View File

@@ -1,11 +1,11 @@
<template>
<router-link
:to="{ path: route?.route }"
:key="route?.title"
v-if="route?.requiresAuth == undefined || (route?.requiresAuth && loggedIn)"
:key="route?.title"
:to="{ path: route?.route }"
>
<li class="navigation-link" :class="{ active: route.route == active }">
<component class="navigation-icon" :is="route.icon"></component>
<component :is="route.icon" class="navigation-icon"></component>
<span>{{ route.title }}</span>
</li>
</router-link>

View File

@@ -1,9 +1,9 @@
<template>
<ul class="navigation-icons">
<NavigationIcon
v-for="route in routes"
:key="route.route"
:route="route"
v-for="_route in routes"
:key="_route.route"
:route="_route"
:active="activeRoute"
/>
<slot></slot>
@@ -66,7 +66,11 @@
}
];
watch(route, () => (activeRoute.value = window?.location?.pathname));
function setActiveRoute(_route: string) {
activeRoute.value = _route;
}
watch(route, () => setActiveRoute(window?.location?.pathname || ""));
</script>
<style lang="scss" scoped>

View File

@@ -3,15 +3,16 @@
<div class="search" :class="{ active: inputIsActive }">
<IconSearch class="search-icon" tabindex="-1" />
<!-- eslint-disable-next-line vuejs-accessibility/form-control-has-label -->
<input
ref="inputElement"
v-model="query"
type="text"
placeholder="Search for movie or show"
aria-label="Search input for finding a movie or show"
autocorrect="off"
autocapitalize="off"
tabindex="0"
v-model="query"
@input="handleInput"
@click="focus"
@keydown.escape="handleEscape"
@@ -23,20 +24,20 @@
/>
<IconClose
v-if="query && query.length"
tabindex="0"
aria-label="button"
v-if="query && query.length"
class="close-icon"
@click="clearInput"
@keydown.enter.stop="clearInput"
class="close-icon"
/>
</div>
<AutocompleteDropdown
v-if="showAutocompleteResults"
v-model:results="dropdownResults"
:query="query"
:index="dropdownIndex"
v-model:results="dropdownResults"
/>
</div>
</template>
@@ -44,14 +45,12 @@
<script setup lang="ts">
import { ref, computed } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { useRoute } from "vue-router";
import SeasonedButton from "@/components/ui/SeasonedButton.vue";
import { useRouter, useRoute } from "vue-router";
import AutocompleteDropdown from "@/components/header/AutocompleteDropdown.vue";
import IconSearch from "@/icons/IconSearch.vue";
import IconClose from "@/icons/IconClose.vue";
import config from "../../config";
import type { Ref } from "vue";
import config from "../../config";
import type { MediaTypes } from "../../interfaces/IList";
interface ISearchResult {
@@ -70,8 +69,7 @@
const dropdownIndex: Ref<number> = ref(-1);
const dropdownResults: Ref<ISearchResult[]> = ref([]);
const inputIsActive: Ref<boolean> = ref(false);
const showAutocomplete: Ref<boolean> = ref(false);
const inputElement: Ref<any> = ref(null);
const inputElement: Ref<HTMLInputElement> = ref(null);
const isOpen = computed(() => store.getters["popup/isOpen"]);
const showAutocompleteResults = computed(() => {
@@ -95,12 +93,12 @@
function navigateDown() {
if (dropdownIndex.value < dropdownResults.value.length - 1) {
dropdownIndex.value++;
dropdownIndex.value += 1;
}
}
function navigateUp() {
if (dropdownIndex.value > -1) dropdownIndex.value--;
if (dropdownIndex.value > -1) dropdownIndex.value -= 1;
const textLength = inputElement.value.value.length;
@@ -122,12 +120,31 @@
});
}
function handleInput(e) {
function handleInput() {
dropdownIndex.value = -1;
}
function focus() {
inputIsActive.value = true;
}
function reset() {
inputElement.value.blur();
dropdownIndex.value = -1;
inputIsActive.value = false;
}
function blur() {
return setTimeout(reset, 150);
}
function clearInput() {
query.value = "";
inputElement.value.focus();
}
function handleSubmit() {
if (!query.value || query.value.length == 0) return;
if (!query.value || query.value.length === 0) return;
if (dropdownIndex.value >= 0) {
const resultItem = dropdownResults.value[dropdownIndex.value];
@@ -143,25 +160,6 @@
reset();
}
function focus() {
inputIsActive.value = true;
}
function blur(event: MouseEvent = null) {
return setTimeout(reset, 150);
}
function reset() {
inputElement.value.blur();
dropdownIndex.value = -1;
inputIsActive.value = false;
}
function clearInput(event: MouseEvent) {
query.value = "";
inputElement.value.focus();
}
function handleEscape() {
if (!isOpen.value) reset();
}