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,14 @@
<template>
<div class="wrapper" v-if="plexId">
<div v-if="plexId" class="wrapper">
<h1>Your watch activity</h1>
<div style="display: flex; flex-direction: row">
<label class="filter">
<label class="filter" for="dayinput">
<span>Days:</span>
<input
class="dayinput"
id="dayinput"
v-model="days"
class="dayinput"
placeholder="days"
type="number"
pattern="[0-9]*"
@@ -15,15 +16,15 @@
/>
</label>
<label class="filter">
<div class="filter">
<span>Data sorted by:</span>
<toggle-button
v-model:selected="graphViewMode"
class="filter-item"
:options="[GraphTypes.Plays, GraphTypes.Duration]"
v-model:selected="graphViewMode"
@change="fetchChartData"
/>
</label>
</div>
</div>
<div class="chart-section">
@@ -34,9 +35,9 @@
:data="playsByDayData"
type="line"
:stacked="false"
:datasetDescriptionSuffix="`watch last ${days} days`"
:tooltipDescriptionSuffix="selectedGraphViewMode.tooltipLabel"
:graphValueType="selectedGraphViewMode.valueType"
:dataset-description-suffix="`watch last ${days} days`"
:tooltip-description-suffix="selectedGraphViewMode.tooltipLabel"
:graph-value-type="selectedGraphViewMode.valueType"
/>
</div>
@@ -44,13 +45,12 @@
<div class="graph">
<Graph
v-if="playsByDayofweekData"
class="graph"
:data="playsByDayofweekData"
type="bar"
:stacked="true"
:datasetDescriptionSuffix="`watch last ${days} days`"
:tooltipDescriptionSuffix="selectedGraphViewMode.tooltipLabel"
:graphValueType="selectedGraphViewMode.valueType"
:dataset-description-suffix="`watch last ${days} days`"
:tooltip-description-suffix="selectedGraphViewMode.tooltipLabel"
:graph-value-type="selectedGraphViewMode.valueType"
/>
</div>
</div>
@@ -61,23 +61,18 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import { ref, computed } from "vue";
import { useStore } from "vuex";
import Graph from "@/components/Graph.vue";
import ToggleButton from "@/components/ui/ToggleButton.vue";
import IconStop from "@/icons/IconStop.vue";
import { fetchGraphData } from "../api";
import type { Ref } from "vue";
enum GraphTypes {
Plays = "plays",
Duration = "duration"
}
enum GraphValueTypes {
Number = "number",
Time = "time"
}
import { fetchGraphData } from "../api";
import {
GraphTypes,
GraphValueTypes,
IGraphData
} from "../interfaces/IGraph";
const store = useStore();
@@ -85,9 +80,6 @@
const graphViewMode: Ref<GraphTypes> = ref(GraphTypes.Plays);
const plexId = computed(() => store.getters["user/plexId"]);
const selectedGraphViewMode = computed(() =>
graphValueViewMode.find(viewMode => viewMode.type === graphViewMode.value)
);
const graphValueViewMode = [
{
type: GraphTypes.Plays,
@@ -101,13 +93,27 @@
}
];
const playsByDayData: Ref<any> = ref(null);
const playsByDayofweekData: Ref<any> = ref(null);
fetchChartData();
const playsByDayData: Ref<IGraphData> = ref(null);
const playsByDayofweekData: Ref<IGraphData> = ref(null);
function fetchChartData() {
fetchPlaysByDay();
fetchPlaysByDayOfWeek();
const selectedGraphViewMode = computed(() =>
graphValueViewMode.find(viewMode => viewMode.type === graphViewMode.value)
);
function convertDateStringToDayMonth(date: string): string {
if (!date.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}/)) {
return date;
}
const [, month, day] = date.split("-");
return `${day}.${month}`;
}
function convertDateLabels(data) {
return {
labels: data.categories.map(convertDateStringToDayMonth),
series: data.series
};
}
async function fetchPlaysByDay() {
@@ -126,21 +132,12 @@
).then(data => convertDateLabels(data?.data));
}
function convertDateLabels(data) {
return {
labels: data.categories.map(convertDateStringToDayMonth),
series: data.series
};
function fetchChartData() {
fetchPlaysByDay();
fetchPlaysByDayOfWeek();
}
function convertDateStringToDayMonth(date: string): string {
if (!date.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}/)) {
return date;
}
const [year, month, day] = date.split("-");
return `${day}.${month}`;
}
fetchChartData();
</script>
<style lang="scss" scoped>

View File

@@ -1,5 +1,5 @@
<template>
<ResultsSection :title="listName" :apiFunction="_getTmdbMovieListByName" />
<ResultsSection :title="listName" :api-function="_getTmdbMovieListByName" />
</template>
<script setup lang="ts">

View File

@@ -1,14 +1,14 @@
<template>
<section class="profile">
<div class="profile__content" v-if="loggedIn">
<div v-if="loggedIn" class="profile__content">
<header class="profile__header">
<h2 class="profile__title">{{ emoji }} Welcome {{ username }}</h2>
<div class="button--group">
<seasoned-button @click="toggleSettings" :active="showSettings">{{
<seasoned-button :active="showSettings" @click="toggleSettings">{{
showSettings ? "hide settings" : "show settings"
}}</seasoned-button>
<seasoned-button @click="toggleActivity" :active="showActivity">{{
<seasoned-button :active="showActivity" @click="toggleActivity">{{
showActivity ? "hide activity" : "show activity"
}}</seasoned-button>
@@ -16,15 +16,15 @@
</div>
</header>
<settings v-if="showSettings" />
<settings-page v-if="showSettings" />
<activity v-if="showActivity" />
<activity-page v-if="showActivity" />
<page-header title="Your requests" :info="resultCount" />
<results-list v-if="results" :results="results" />
</div>
<section class="not-found" v-if="!loggedIn">
<section v-if="!loggedIn" class="not-found">
<div class="not-found__content">
<h2 class="not-found__title">Authentication Request Failed</h2>
<router-link :to="{ name: 'signin' }" exact title="Sign in here">
@@ -40,11 +40,11 @@
import { useStore } from "vuex";
import PageHeader from "@/components/PageHeader.vue";
import ResultsList from "@/components/ResultsList.vue";
import Settings from "@/pages/SettingsPage.vue";
import Activity from "@/pages/ActivityPage.vue";
import SettingsPage from "@/pages/SettingsPage.vue";
import ActivityPage from "@/pages/ActivityPage.vue";
import SeasonedButton from "@/components/ui/SeasonedButton.vue";
import { getEmoji, getUserRequests, getSettings, logout } from "../api";
import type { Ref, ComputedRef } from "vue";
import { getEmoji, getUserRequests } from "../api";
import type { ListResults } from "../interfaces/IList";
const emoji: Ref<string> = ref("");
@@ -57,7 +57,6 @@
const loggedIn: Ref<boolean> = computed(() => store.getters["user/loggedIn"]);
const username: Ref<string> = computed(() => store.getters["user/username"]);
const settings: Ref<object> = computed(() => store.getters["user/settings"]);
const resultCount: ComputedRef<number | string> = computed(() => {
const currentCount = results?.value?.length || 0;
@@ -65,6 +64,10 @@
return `${currentCount} of ${totalCount} results`;
});
function setEmoji(_emoji: string) {
emoji.value = _emoji;
}
// Component loaded actions
getUserRequests().then(requestResults => {
if (!requestResults?.results) return;
@@ -72,26 +75,12 @@
totalResults.value = requestResults.total_results;
});
getEmoji().then(resp => (emoji.value = resp?.emoji));
getEmoji().then(resp => setEmoji(resp?.emoji));
showSettings.value = window.location.toString().includes("settings=true");
showActivity.value = window.location.toString().includes("activity=true");
// Component loaded actions end
function toggleSettings() {
showSettings.value = !showSettings.value;
updateQueryParams("settings", showSettings.value);
}
function toggleActivity() {
showActivity.value = !showActivity.value;
updateQueryParams("activity", showActivity.value);
}
function _logout() {
store.dispatch("user/logout");
}
function updateQueryParams(key, value = false) {
const params = new URLSearchParams(window.location.search);
if (params.has(key)) {
@@ -112,6 +101,20 @@
}`
);
}
function toggleSettings() {
showSettings.value = !showSettings.value;
updateQueryParams("settings", showSettings.value);
}
function toggleActivity() {
showActivity.value = !showActivity.value;
updateQueryParams("activity", showActivity.value);
}
function _logout() {
store.dispatch("user/logout");
}
</script>
<style lang="scss" scoped>

View File

@@ -2,27 +2,27 @@
<section>
<h1>Register new user</h1>
<form class="form" ref="formElement">
<form ref="formElement" class="form">
<seasoned-input
v-model="username"
placeholder="username"
icon="Email"
type="email"
v-model="username"
@keydown.enter="focusOnNextElement"
/>
<seasoned-input
v-model="password"
placeholder="password"
icon="Keyhole"
type="password"
v-model="password"
@keydown.enter="focusOnNextElement"
/>
<seasoned-input
v-model="passwordRepeat"
placeholder="repeat password"
icon="Keyhole"
type="password"
v-model="passwordRepeat"
@keydown.enter="submit"
/>
@@ -44,10 +44,10 @@
import SeasonedButton from "@/components/ui/SeasonedButton.vue";
import SeasonedInput from "@/components/ui/SeasonedInput.vue";
import SeasonedMessages from "@/components/ui/SeasonedMessages.vue";
import type { Ref } from "vue";
import { register } from "../api";
import { focusFirstFormInput, focusOnNextElement } from "../utils";
import { ErrorMessageTypes } from "../interfaces/IErrorMessage";
import type { Ref } from "vue";
import type { IErrorMessage } from "../interfaces/IErrorMessage";
const username: Ref<string> = ref("");
@@ -85,32 +85,27 @@
return new Promise((resolve, reject) => {
if (!username.value || username?.value?.length === 0) {
addWarningMessage("Missing username", "Validation error");
return reject();
reject();
}
if (!password.value || password?.value?.length === 0) {
addWarningMessage("Missing password", "Validation error");
return reject();
reject();
}
if (passwordRepeat.value == null || passwordRepeat.value.length == 0) {
if (passwordRepeat.value == null || passwordRepeat.value.length === 0) {
addWarningMessage("Missing repeat password", "Validation error");
return reject();
reject();
}
if (passwordRepeat != password) {
if (passwordRepeat.value !== password.value) {
addWarningMessage("Passwords do not match", "Validation error");
return reject();
reject();
}
resolve(true);
});
}
function submit() {
clearMessages();
validate().then(registerUser);
}
function registerUser() {
register(username.value, password.value)
.then(data => {
@@ -120,15 +115,19 @@
})
.catch(error => {
if (error?.status === 401) {
return addErrorMessage(
"Incorrect username or password",
"Access denied"
);
addErrorMessage("Incorrect username or password", "Access denied");
return null;
}
addErrorMessage(error?.message, "Unexpected error");
return null;
});
}
function submit() {
clearMessages();
validate().then(registerUser);
}
</script>
<style lang="scss" scoped>

View File

@@ -1,5 +1,5 @@
<template>
<ResultsSection title="Requests" :apiFunction="getRequests" />
<ResultsSection title="Requests" :api-function="getRequests" />
</template>
<script setup lang="ts">

View File

@@ -1,18 +1,18 @@
<template>
<div>
<div style="display: flex; flex-direction: row">
<label class="filter">
<div class="filter">
<span>Search filter:</span>
<toggle-button
:options="toggleOptions"
v-model:selected="mediaType"
:options="toggleOptions"
@change="toggleChanged"
/>
</label>
</div>
</div>
<ResultsSection v-if="query" :title="title" :apiFunction="search" />
<ResultsSection v-if="query" :title="title" :api-function="search" />
<h1 v-else class="no-results">No query found, please search above</h1>
</div>
</template>
@@ -20,12 +20,11 @@
<script setup lang="ts">
import { ref, computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import { searchTmdb } from "../api";
import ResultsSection from "@/components/ResultsSection.vue";
import PageHeader from "@/components/PageHeader.vue";
import ToggleButton from "@/components/ui/ToggleButton.vue";
import type { Ref } from "vue";
import { searchTmdb } from "../api";
import { MediaTypes } from "../interfaces/IList";
// interface ISearchParams {
@@ -54,20 +53,14 @@
mediaType.value = (urlQuery?.media_type as MediaTypes) || mediaType.value;
}
let search = (
const search = (
_page = page.value || 1,
_mediaType = mediaType.value || "all"
) => {
return searchTmdb(query.value, _page, adult.value, _mediaType);
};
function toggleChanged() {
updateQueryParams();
}
function updateQueryParams() {
const { query, page, adult, media_type } = route.query;
router.push({
path: "search",
query: {
@@ -76,6 +69,10 @@
}
});
}
function toggleChanged() {
updateQueryParams();
}
</script>
<style lang="scss" scoped>

View File

@@ -11,12 +11,28 @@
</template>
<script setup lang="ts">
import { inject } from "vue";
import { useStore } from "vuex";
import { useRoute } from "vue-router";
import ChangePassword from "@/components/profile/ChangePassword.vue";
import LinkPlexAccount from "@/components/profile/LinkPlexAccount.vue";
import { getSettings } from "../api";
const store = useStore();
const route = useRoute();
const notifications: {
error;
} = inject("notifications");
function displayWarningIfMissingPlexAccount() {
if (route.query?.missingPlexAccount === "true") {
notifications.error({
title: "Missing plex account 🧲",
description: "Link your plex account to view activity",
timeout: 10000
});
}
}
function reloadSettings() {
return getSettings().then(response => {
@@ -26,6 +42,9 @@
store.dispatch("user/setSettings", settings);
});
}
// Functions called on component load
displayWarningIfMissingPlexAccount();
</script>
<style lang="scss">

View File

@@ -2,19 +2,19 @@
<section>
<h1>Sign in</h1>
<form class="form" ref="formElement">
<form ref="formElement" class="form">
<seasoned-input
v-model="username"
placeholder="username"
icon="Email"
type="email"
v-model="username"
@keydown.enter="focusOnNextElement"
/>
<seasoned-input
v-model="password"
placeholder="password"
icon="Keyhole"
type="password"
v-model="password"
@keydown.enter="submit"
/>
@@ -35,10 +35,10 @@
import SeasonedInput from "@/components/ui/SeasonedInput.vue";
import SeasonedButton from "@/components/ui/SeasonedButton.vue";
import SeasonedMessages from "@/components/ui/SeasonedMessages.vue";
import type { Ref } from "vue";
import { login } from "../api";
import { focusFirstFormInput, focusOnNextElement } from "../utils";
import { ErrorMessageTypes } from "../interfaces/IErrorMessage";
import type { Ref } from "vue";
import type { IErrorMessage } from "../interfaces/IErrorMessage";
const username: Ref<string> = ref("");
@@ -75,23 +75,18 @@
return new Promise((resolve, reject) => {
if (!username.value || username?.value?.length === 0) {
addWarningMessage("Missing username", "Validation error");
return reject();
reject();
}
if (!password.value || password?.value?.length === 0) {
addWarningMessage("Missing password", "Validation error");
return reject();
reject();
}
resolve(true);
});
}
function submit() {
clearMessages();
validate().then(signin);
}
function signin() {
login(username.value, password.value, true)
.then(data => {
@@ -101,15 +96,19 @@
})
.catch(error => {
if (error?.status === 401) {
return addErrorMessage(
"Incorrect username or password",
"Access denied"
);
addErrorMessage("Incorrect username or password", "Access denied");
return null;
}
addErrorMessage(error?.message, "Unexpected error");
return null;
});
}
function submit() {
clearMessages();
validate().then(signin);
}
</script>
<style lang="scss" scoped>

View File

@@ -7,8 +7,8 @@
<seasoned-input
v-model="query"
type="torrents"
@keydown.enter="setTorrentQuery"
placeholder="Search torrents"
@keydown.enter="setTorrentQuery"
/>
<seasoned-button @click="setTorrentQuery">Search</seasoned-button>
</div>
@@ -27,8 +27,8 @@
import SeasonedButton from "@/components/ui/SeasonedButton.vue";
import TorrentList from "@/components/torrent/TorrentSearchResults.vue";
import ActiveTorrents from "@/components/torrent/ActiveTorrents.vue";
import { getValueFromUrlQuery, setUrlQueryParameter } from "../utils";
import type { Ref } from "vue";
import { getValueFromUrlQuery, setUrlQueryParameter } from "../utils";
const urlQuery = getValueFromUrlQuery("query");