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:
@@ -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>
|
||||
|
||||
101
src/components/ListHeader.vue
Normal file
101
src/components/ListHeader.vue
Normal 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
104
src/components/ListPage.vue
Normal 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>
|
||||
@@ -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
104
src/components/Search.vue
Normal 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>
|
||||
Reference in New Issue
Block a user