diff --git a/package.json b/package.json index af2ddd0..1b93da9 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@babel/plugin-transform-runtime": "7.17.0", "@babel/preset-env": "7.16.11", "@babel/runtime": "7.17.2", + "@types/node": "^18.6.1", "babel-loader": "8.2.3", "css-loader": "6.7.0", "documentation": "^11.0.0", @@ -35,6 +36,8 @@ "sass": "1.49.9", "sass-loader": "12.6.0", "terser-webpack-plugin": "5.3.1", + "ts-loader": "^9.3.1", + "typescript": "^4.7.4", "vue-loader": "15.9.8", "vue-template-compiler": "2.6.14", "webpack": "5.70.0", diff --git a/src/api.js b/src/api.ts similarity index 92% rename from src/api.js rename to src/api.ts index 430834e..131809d 100644 --- a/src/api.js +++ b/src/api.ts @@ -1,15 +1,17 @@ -import config from "@/config.json"; +import config from "./config"; +import { IList } from "./interfaces/IList"; -const SEASONED_URL = config.SEASONED_URL || window.location.origin; -const ELASTIC_URL = config.ELASTIC_URL; -const ELASTIC_INDEX = config.ELASTIC_INDEX; +let { SEASONED_URL, ELASTIC_URL, ELASTIC_INDEX } = config; +if (!SEASONED_URL) { + SEASONED_URL = window.location.origin; +} // TODO // - Move autorization token and errors here? const checkStatusAndReturnJson = response => { if (!response.ok) { - throw resp; + throw response; } return response.json(); }; @@ -31,13 +33,13 @@ const getMovie = ( const url = new URL("/api/v2/movie", SEASONED_URL); url.pathname = `${url.pathname}/${id.toString()}`; if (checkExistance) { - url.searchParams.append("check_existance", true); + url.searchParams.append("check_existance", "true"); } if (credits) { - url.searchParams.append("credits", true); + url.searchParams.append("credits", "true"); } if (release_dates) { - url.searchParams.append("release_dates", true); + url.searchParams.append("release_dates", "true"); } return fetch(url.href) @@ -58,10 +60,10 @@ const getShow = (id, checkExistance = false, credits = false) => { const url = new URL("/api/v2/show", SEASONED_URL); url.pathname = `${url.pathname}/${id.toString()}`; if (checkExistance) { - url.searchParams.append("check_existance", true); + url.searchParams.append("check_existance", "true"); } if (credits) { - url.searchParams.append("credits", true); + url.searchParams.append("credits", "true"); } return fetch(url.href) @@ -72,6 +74,10 @@ const getShow = (id, checkExistance = false, credits = false) => { }); }; +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + /** * Fetches tmdb person by id. Can optionally include cast credits in result object. * @param {number} id @@ -82,7 +88,7 @@ const getPerson = (id, credits = false) => { const url = new URL("/api/v2/person", SEASONED_URL); url.pathname = `${url.pathname}/${id.toString()}`; if (credits) { - url.searchParams.append("credits", true); + url.searchParams.append("credits", "true"); } return fetch(url.href) @@ -162,9 +168,12 @@ const getPersonCredits = id => { * @param {number} [page=1] * @returns {object} Tmdb list response */ -const getTmdbMovieListByName = (name, page = 1) => { +const getTmdbMovieListByName = ( + name: string, + page: number = 1 +): Promise => { const url = new URL("/api/v2/movie/" + name, SEASONED_URL); - url.searchParams.append("page", page); + url.searchParams.append("page", page.toString()); return fetch(url.href).then(resp => resp.json()); // .catch(error => { console.error(`api error getting list: ${name}, page: ${page}`); throw error }) @@ -175,9 +184,9 @@ const getTmdbMovieListByName = (name, page = 1) => { * @param {number} [page=1] * @returns {object} Request response */ -const getRequests = (page = 1) => { +const getRequests = (page: number = 1) => { const url = new URL("/api/v2/request", SEASONED_URL); - url.searchParams.append("page", page); + url.searchParams.append("page", page.toString()); return fetch(url.href).then(resp => resp.json()); // .catch(error => { console.error(`api error getting list: ${name}, page: ${page}`); throw error }) @@ -185,7 +194,7 @@ const getRequests = (page = 1) => { const getUserRequests = (page = 1) => { const url = new URL("/api/v1/user/requests", SEASONED_URL); - url.searchParams.append("page", page); + url.searchParams.append("page", page.toString()); return fetch(url.href).then(resp => resp.json()); }; @@ -203,8 +212,8 @@ const searchTmdb = (query, page = 1, adult = false, mediaType = null) => { } url.searchParams.append("query", query); - url.searchParams.append("page", page); - url.searchParams.append("adult", adult); + url.searchParams.append("page", page.toString()); + url.searchParams.append("adult", adult.toString()); return fetch(url.href) .then(resp => resp.json()) @@ -369,7 +378,7 @@ const login = (username, password, throwError = false) => { }); }; -const logout = () => { +const logout = (throwError = false) => { const url = new URL("/api/v1/user/logout", SEASONED_URL); const options = { method: "POST" }; diff --git a/src/components/header/SearchInput.vue b/src/components/header/SearchInput.vue index 7b146bf..3c0e8b2 100644 --- a/src/components/header/SearchInput.vue +++ b/src/components/header/SearchInput.vue @@ -48,7 +48,7 @@ import AutocompleteDropdown from "@/components/header/AutocompleteDropdown"; import IconSearch from "src/icons/IconSearch"; import IconClose from "src/icons/IconClose"; -import config from "@/config.json"; +import config from "@/config"; export default { name: "SearchInput", diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..b9125ad --- /dev/null +++ b/src/config.ts @@ -0,0 +1,9 @@ +import type IConfig from "./interfaces/IConfig"; + +const config: IConfig = { + SEASONED_URL: "", + ELASTIC_URL: "https://elastic.kevinmidboe.com/", + ELASTIC_INDEX: "shows,movies" +}; + +export default config; diff --git a/src/config.json.example b/src/config.ts.example similarity index 100% rename from src/config.json.example rename to src/config.ts.example diff --git a/src/interfaces/IConfig.ts b/src/interfaces/IConfig.ts new file mode 100644 index 0000000..7f95b8e --- /dev/null +++ b/src/interfaces/IConfig.ts @@ -0,0 +1,5 @@ +export default interface IConfig { + SEASONED_URL: string; + ELASTIC_URL: string; + ELASTIC_INDEX: string; +} diff --git a/src/interfaces/IList.ts b/src/interfaces/IList.ts new file mode 100644 index 0000000..d92ff9c --- /dev/null +++ b/src/interfaces/IList.ts @@ -0,0 +1,56 @@ +export interface IList { + results: Array; + page: number; + total_results: number; + total_pages: number; +} + +export enum ListTypes { + Movie = "movie", + Show = "show", + Person = "person", + Request = "request" +} + +export enum RequestTypes { + Requested = "requested" +} + +export interface IMovie { + id: number; + title: string; + year: number; + overview: string; + poster: string; + backdrop: string; + release_date: string | Date; + rating: number; + type: ListTypes.Movie; +} + +export interface IShow { + id: number; + title: string; + year: number; + overview: string; + poster: string; + backdrop: string; + type: ListTypes.Show; +} + +export interface IPerson { + id: number; + title: string; + poster: string; + birthday: string | null; + deathday: string | null; + known_for_department: string; + adult: boolean; +} + +export interface IRequest extends IMovie { + requested_by: string; + ip: string; + status: string | RequestTypes; + user_agent: string; +} diff --git a/src/utils.js b/src/utils.ts similarity index 78% rename from src/utils.js rename to src/utils.ts index 7b29dd1..cbfb108 100644 --- a/src/utils.js +++ b/src/utils.ts @@ -1,14 +1,14 @@ -export const sortableSize = string => { +export const sortableSize = (string: string) => { const UNITS = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; const [numStr, unit] = string.split(" "); if (UNITS.indexOf(unit) === -1) return string; const exponent = UNITS.indexOf(unit) * 3; - return numStr * Math.pow(10, exponent); + return Number(numStr) * Math.pow(10, exponent); }; -export const parseJwt = token => { +export const parseJwt = (token: string) => { var base64Url = token.split(".")[1]; var base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/"); var jsonPayload = decodeURIComponent( @@ -23,7 +23,11 @@ export const parseJwt = token => { return JSON.parse(jsonPayload); }; -export const buildImageProxyUrl = (width, height, asset) => { +export const buildImageProxyUrl = ( + width: number, + height: number, + asset: string +) => { const proxyHost = `http://imgproxy.schleppe:8080/insecure/`; const proxySizeOptions = `resize:fill:${Math.floor(width / 1)}:${Math.floor( height / 1 diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..118fe1c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "moduleResolution": "node", + "strict": false, + "jsx": "preserve", + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "lib": ["esnext", "dom"], + "outDir": "lib", + "baseUrl": "/", + "paths": { + "@": ["src"] + } + }, + "include": [ + "src/**/*.js", + "src/**/*.ts", + "src/**/*.d.ts", + "src/**/*.tsx", + "src/**/*.vue" + ], + "exclude": ["node_modules"] +} diff --git a/webpack.config.js b/webpack.config.js index e826038..dda7f31 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -35,6 +35,11 @@ module.exports = { test: /\.vue$/, use: ["vue-loader"] }, + { + test: /\.tsx?$/, + loader: "ts-loader", + exclude: /node_modules/ + }, { test: /\.scss$/, use: [ @@ -62,7 +67,7 @@ module.exports = { }) ], resolve: { - extensions: [".js", ".vue", ".json", ".scss"], + extensions: [".js", ".ts", ".vue", ".json", ".scss"], alias: { vue$: "vue/dist/vue.common.js", "@": path.resolve(__dirname, "src"),