Removed A LOT of the functionality in MoviesList and replaced it with the ResultsList component. Now loading of search results, lists (either directly by query or link) and users requests from profile are all separated out to their own page component; Search.vue, ListPage.vue and Profile.vue respectivly. With the change Home has been completly redone to use this new funcionality

This commit is contained in:
2019-10-22 23:24:08 +02:00
parent 1a014bea15
commit f45dcc560c
5 changed files with 397 additions and 17 deletions

View File

@@ -2,27 +2,84 @@
<section>
<LandingBanner />
<movies-list v-for="item in homepageLists" :propList="item" :shortList="true"></movies-list>
<div v-for="list in lists">
<list-header :title="list.title" :link="'/list/' + list.route" />
<results-list :results="list.data" :shortList="true" />
<loader v-if="!list.data.length" />
</div>
</section>
</template>
<script>
import storage from '../storage.js'
import LandingBanner from '@/components/LandingBanner.vue'
import MoviesList from './MoviesList.vue'
import ListHeader from '@/components/ListHeader.vue'
import ResultsList from '@/components/ResultsList.vue'
import Loader from '@/components/ui/Loader.vue'
import { getTmdbMovieListByName, getRequests } from '@/api'
export default {
name: 'home',
components: { LandingBanner, MoviesList },
components: { LandingBanner, ResultsList, ListHeader, Loader },
data(){
return {
homepageLists: storage.homepageLists,
imageFile: 'dist/pulp-fiction.jpg'
imageFile: 'dist/pulp-fiction.jpg',
requests: [],
nowplaying: [],
upcoming: [],
popular: []
}
},
computed: {
lists() {
return [
{
title: 'Requests',
route: 'request',
data: this.requests
},
{
title: 'Now playing',
route: 'now_playing',
data: this.nowplaying
},
{
title: 'Upcoming',
route: 'upcoming',
data: this.upcoming
},
{
title: 'Popular',
route: 'popular',
data: this.popular
}
]
}
},
methods: {
fetchRequests() {
getRequests()
.then(results => this.requests = results.results)
},
fetchNowPlaying() {
getTmdbMovieListByName('now_playing')
.then(results => this.nowplaying = results.results)
},
fetchUpcoming() {
getTmdbMovieListByName('upcoming')
.then(results => this.upcoming = results.results)
},
fetchPopular() {
getTmdbMovieListByName('popular')
.then(results => this.popular = results.results)
}
},
created(){
document.title = 'TMDb';
storage.backTitle = document.title;
this.fetchRequests()
this.fetchNowPlaying()
this.fetchUpcoming()
this.fetchPopular()
}
}
</script>
</script>

View File

@@ -0,0 +1,101 @@
<template>
<header :class="{ 'sticky': sticky }">
<h2>{{ title }}</h2>
<span v-if="info" class="result-count">{{ info }}</span>
<router-link v-else-if="link" :to="link" class='view-more'>
View All
</router-link>
</header>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true
},
sticky: {
type: Boolean,
required: false,
default: false
},
info: {
type: String,
required: false
},
link: {
type: String,
required: false
}
}
}
</script>
<style lang="scss" scoped>
@import './src/scss/variables';
@import './src/scss/media-queries';
header {
width: 100%;
display: flex;
justify-content: space-between;
padding: 1.8rem 12px;
&.sticky {
background-color: $background-color;
position: sticky;
position: -webkit-sticky;
top: $header-size;
z-index: 4;
padding-bottom: 1rem;
margin-bottom: 1.5rem;
}
h2 {
font-size: 18px;
font-weight: 300;
text-transform: capitalize;
line-height: 18px;
margin: 0;
color: $text-color;
}
.view-more {
font-size: 13px;
font-weight: 300;
letter-spacing: .5px;
color: $text-color-70;
text-decoration: none;
transition: color .5s ease;
cursor: pointer;
&:after{
content: " →";
}
&:hover{
color: $text-color;
}
}
.result-count {
font-size: 13px;
font-weight: 300;
letter-spacing: .5px;
color: $text-color;
text-decoration: none;
}
@include tablet-min {
padding-left: 1.25rem;;
}
@include desktop-lg-min {
padding-left: 1.75rem;
}
}
</style>

104
src/components/ListPage.vue Normal file
View File

@@ -0,0 +1,104 @@
<template>
<div>
<list-header :title="listTitle" :info="resultCount" :sticky="true" />
<results-list :results="results" v-if="results" />
<loader v-if="!results.length" />
<div v-if="page < totalPages" class="fullwidth-button">
<seasoned-button @click="loadMore">load more</seasoned-button>
</div>
</div>
</template>
<script>
import ListHeader from '@/components/ListHeader'
import ResultsList from '@/components/ResultsList'
import SeasonedButton from '@/components/ui/SeasonedButton'
import Loader from '@/components/ui/Loader'
import { getTmdbMovieListByName, getRequests } from '@/api'
import store from '@/store'
export default {
components: { ListHeader, ResultsList, SeasonedButton, Loader },
data() {
return {
legalTmdbLists: [ 'now_playing', 'upcoming', 'popular' ],
results: [],
page: 1,
totalPages: 0,
totalResults: 0
}
},
computed: {
listTitle() {
if (this.results.length === 0)
return ''
const routeListName = this.$route.params.name
console.log('routelistname', routeListName)
return routeListName.includes('_') ? routeListName.split('_').join(' ') : routeListName
},
resultCount() {
if (this.results.length === 0)
return ''
const loadedResults = this.results.length
const totalResults = this.totalResults < 10000 ? this.totalResults : '∞'
return `${loadedResults} of ${totalResults} results`
}
},
methods: {
loadMore() {
console.log(this.$route)
this.page++
window.history.replaceState({}, 'search', `/#/${this.$route.fullPath}?page=${this.page}`)
this.init()
},
init() {
const routeListName = this.$route.params.name
if (routeListName === 'request') {
getRequests(this.page)
.then(results => {
this.results = this.results.concat(...results.results)
this.page = results.page
this.totalPages = results.total_pages
this.totalResults = results.total_results
})
} else if (this.legalTmdbLists.includes(routeListName)) {
getTmdbMovieListByName(routeListName, this.page)
.then(results => {
this.results = this.results.concat(...results.results)
this.page = results.page
this.totalPages = results.total_pages
this.totalResults = results.total_results
})
} else {
// TODO handle if list is not found
console.log('404 this is not a tmdb list')
}
}
},
created() {
if (this.results.length === 0)
this.init()
store.dispatch('documentTitle/updateTitle', `${this.$router.history.current.name} ${this.$route.params.name}`)
}
}
</script>
<style lang="scss" scoped>
.fullwidth-button {
width: 100%;
margin: 1rem 0;
padding-bottom: 2rem;
display: flex;
justify-content: center;
}
</style>

View File

@@ -3,17 +3,18 @@
<div class="profile__content" v-if="userLoggedIn">
<header class="profile__header">
<h2 class="profile__title">{{ emoji }} Welcome {{ userName }}</h2>
<div class="button--group">
<seasoned-button @click="showSettings = !showSettings">{{ showSettings ? 'hide settings' : 'show settings' }}</seasoned-button>
<seasoned-button @click="logOut">Log out</seasoned-button>
</div>
</header>
<settings v-if="showSettings"></settings>
<movies-list :propList="user_requestsList"></movies-list>
<list-header title="User requests" :info="resultCount"/>
<results-list v-if="results" :results="results" />
</div>
<section class="not-found" v-if="!userLoggedIn">
@@ -29,21 +30,34 @@
<script>
import storage from '@/storage.js'
import MoviesList from '@/components/MoviesList.vue'
import store from '@/store.js'
import ListHeader from '@/components/ListHeader.vue'
import ResultsList from '@/components/ResultsList.vue'
import Settings from '@/components/Settings.vue'
import SeasonedButton from '@/components/ui/SeasonedButton.vue'
import { getEmoji } from '@/api.js'
import { getEmoji, getUserRequests } from '@/api.js'
export default {
components: { MoviesList, Settings, SeasonedButton },
components: { ListHeader, ResultsList, Settings, SeasonedButton },
data(){
return{
userLoggedIn: '',
userName: '',
emoji: '',
showSettings: false,
user_requestsList: storage.user_requestsList
results: undefined,
totalResults: undefined,
showSettings: false
}
},
computed: {
resultCount() {
if (this.results === undefined)
return
const loadedResults = this.results.length
const totalResults = this.totalResults < 10000 ? this.totalResults : '∞'
return `${loadedResults} of ${totalResults} results`
}
},
methods: {

104
src/components/Search.vue Normal file
View File

@@ -0,0 +1,104 @@
<template>
<div>
<list-header :title="title" :info="resultCount" :sticky="true" />
<results-list :results="results" />
<div v-if="page < totalPages" class="fullwidth-button">
<seasoned-button @click="loadMore">load more</seasoned-button>
</div>
<loader v-if="!results.length" />
</div>
</template>
<script>
import { searchTmdb } from '@/api'
import ListHeader from '@/components/ListHeader'
import ResultsList from '@/components/ResultsList'
import SeasonedButton from '@/components/ui/SeasonedButton'
import Loader from '@/components/ui/Loader'
export default {
components: { ListHeader, ResultsList, SeasonedButton, Loader },
props: {
propQuery: {
type: String,
required: false
},
propPage: {
type: Number,
required: false
}
},
data() {
return {
loading: true,
query: String,
title: String,
page: Number,
totalPages: 0,
results: [],
totalResults: []
}
},
computed: {
resultCount() {
const loadedResults = this.results.length
const totalResults = this.totalResults < 10000 ? this.totalResults : '∞'
return `${loadedResults} of ${totalResults} results`
}
},
methods: {
search(query=this.query, page=this.page) {
searchTmdb(query, page)
.then(this.parseResponse)
},
parseResponse(response) {
const data = response.data
if (this.results.length > 0) {
this.results.push(...data.results)
} else {
this.results = data.results
}
this.totalPages = data.total_pages
this.totalResults = data.total_results || data.results.length
this.loading = false
},
loadMore() {
this.page++
window.history.replaceState({}, 'search', `/#/search?query=${this.query}&page=${this.page}`)
this.search()
}
},
created() {
const { query, page } = this.$route.query
if (!query) {
// abort
console.error('abort, no query')
}
this.query = decodeURIComponent(query)
this.page = page ? page : 1
this.title = `Search results: ${this.query}`
this.search()
}
}
</script>
<style lang="scss" scoped>
.fullwidth-button {
width: 100%;
margin: 1rem 0;
padding-bottom: 2rem;
display: flex;
justify-content: center;
}
</style>