feat: separate album view into multiple components and use vuex
This commit is contained in:
parent
22f9eb4dff
commit
7581d13d1c
|
@ -0,0 +1,177 @@
|
|||
<template>
|
||||
<div class="details">
|
||||
<h2>Public links for this album:</h2>
|
||||
|
||||
<b-table
|
||||
:data="details.links || []"
|
||||
:mobile-cards="true">
|
||||
<template slot-scope="props">
|
||||
<b-table-column field="identifier"
|
||||
label="Link"
|
||||
centered>
|
||||
<a :href="`${config.URL}/a/${props.row.identifier}`"
|
||||
target="_blank">
|
||||
{{ props.row.identifier }}
|
||||
</a>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="views"
|
||||
label="Views"
|
||||
centered>
|
||||
{{ props.row.views }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="enableDownload"
|
||||
label="Allow download"
|
||||
centered>
|
||||
<b-switch v-model="props.row.enableDownload"
|
||||
@input="linkOptionsChanged(props.row)" />
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="enabled"
|
||||
numeric>
|
||||
<button class="button is-danger"
|
||||
@click="promptDeleteAlbumLink(props.row.identifier)">Delete link</button>
|
||||
</b-table-column>
|
||||
</template>
|
||||
<template slot="empty">
|
||||
<div class="has-text-centered">
|
||||
<i class="icon-misc-mood-sad" />
|
||||
</div>
|
||||
<div class="has-text-centered">
|
||||
Nothing here
|
||||
</div>
|
||||
</template>
|
||||
<template slot="footer">
|
||||
<div class="level is-paddingless">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<button :class="{ 'is-loading': isCreatingLink }"
|
||||
class="button is-primary"
|
||||
style="float: left"
|
||||
@click="createLink(albumId)">Create new link</button>
|
||||
</div>
|
||||
<div class="level-item">
|
||||
<span class="has-text-default">{{ details.links.length }} / {{ config.maxLinksPerAlbum }} links created</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level-right">
|
||||
<div class="level-item">
|
||||
<button class="button is-danger"
|
||||
style="float: right"
|
||||
@click="promptDeleteAlbum(albumId)">Delete album</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
albumId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
details: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isCreatingLink: false
|
||||
}
|
||||
},
|
||||
computed: mapState(['config']),
|
||||
methods: {
|
||||
promptDeleteAlbum(id) {
|
||||
this.$buefy.dialog.confirm({
|
||||
message: 'Are you sure you want to delete this album?',
|
||||
onConfirm: () => this.deleteAlbum(id)
|
||||
});
|
||||
},
|
||||
async deleteAlbum(id) {
|
||||
const response = await this.$axios.$delete(`album/${id}`);
|
||||
this.getAlbums();
|
||||
return this.$buefy.toast.open(response.message);
|
||||
},
|
||||
promptDeleteAlbumLink(identifier) {
|
||||
this.$buefy.dialog.confirm({
|
||||
message: 'Are you sure you want to delete this album link?',
|
||||
onConfirm: () => this.deleteAlbumLink(identifier)
|
||||
});
|
||||
},
|
||||
async deleteAlbumLink(identifier) {
|
||||
const response = await this.$axios.$delete(`album/link/delete/${identifier}`);
|
||||
return this.$buefy.toast.open(response.message);
|
||||
},
|
||||
async linkOptionsChanged(link) {
|
||||
const response = await this.$axios.$post(`album/link/edit`,
|
||||
{
|
||||
identifier: link.identifier,
|
||||
enableDownload: link.enableDownload,
|
||||
enabled: link.enabled
|
||||
});
|
||||
this.$buefy.toast.open(response.message);
|
||||
},
|
||||
async createLink(album) {
|
||||
album.isCreatingLink = true;
|
||||
// Since we actually want to change the state even if the call fails, use a try catch
|
||||
try {
|
||||
const response = await this.$axios.$post(`album/link/new`,
|
||||
{ albumId: album.id });
|
||||
this.$buefy.toast.open(response.message);
|
||||
album.links.push({
|
||||
identifier: response.identifier,
|
||||
views: 0,
|
||||
enabled: true,
|
||||
enableDownload: true,
|
||||
expiresAt: null
|
||||
});
|
||||
} catch (error) {
|
||||
//
|
||||
} finally {
|
||||
album.isCreatingLink = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~/assets/styles/_colors.scss';
|
||||
|
||||
div.details {
|
||||
flex: 0 1 100%;
|
||||
padding-left: 2em;
|
||||
padding-top: 1em;
|
||||
min-height: 50px;
|
||||
|
||||
.b-table {
|
||||
padding: 2em 0em;
|
||||
|
||||
.table-wrapper {
|
||||
-webkit-box-shadow: $boxShadowLight;
|
||||
box-shadow: $boxShadowLight;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
@import '~/assets/styles/_colors.scss';
|
||||
|
||||
.b-table {
|
||||
.table-wrapper {
|
||||
-webkit-box-shadow: $boxShadowLight;
|
||||
box-shadow: $boxShadowLight;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,179 @@
|
|||
<template>
|
||||
<div class="album">
|
||||
<div class="arrow-container"
|
||||
@click="toggleDetails(album)">
|
||||
<i :class="{ active: isExpanded }"
|
||||
class="icon-arrow" />
|
||||
</div>
|
||||
<div class="thumb">
|
||||
<figure class="image is-64x64 thumb">
|
||||
<img src="~/assets/images/blank_darker.png">
|
||||
</figure>
|
||||
</div>
|
||||
<div class="info">
|
||||
<h4>
|
||||
<router-link :to="`/dashboard/albums/${album.id}`">{{ album.name }}</router-link>
|
||||
</h4>
|
||||
<span>Updated <timeago :since="album.editedAt" /></span>
|
||||
<span>{{ album.fileCount || 0 }} files</span>
|
||||
</div>
|
||||
<div class="latest is-hidden-mobile">
|
||||
<template v-if="album.fileCount > 0">
|
||||
<div v-for="file of album.files"
|
||||
:key="file.id"
|
||||
class="thumb">
|
||||
<figure class="image is-64x64">
|
||||
<a :href="file.url"
|
||||
target="_blank">
|
||||
<img :src="file.thumbSquare">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<div v-if="album.fileCount > 5"
|
||||
class="thumb more no-background">
|
||||
<router-link :to="`/dashboard/albums/${album.id}`">{{ album.fileCount - 5 }}+ more</router-link>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="no-files">Nothing to show here</span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<AlbumDetails v-if="isExpanded"
|
||||
:details="getDetails"
|
||||
:albumId="album.id" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import AlbumDetails from '~/components/album/AlbumDetails.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AlbumDetails
|
||||
},
|
||||
props: {
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
isExpandedGetter: 'albums/isExpanded',
|
||||
getDetailsGetter: 'albums/getDetails'
|
||||
}),
|
||||
isExpanded() {
|
||||
return this.isExpandedGetter(this.album.id);
|
||||
},
|
||||
getDetails() {
|
||||
return this.getDetailsGetter(this.album.id);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async toggleDetails(album) {
|
||||
if (!this.isExpanded) {
|
||||
await this.$store.dispatch('albums/fetchDetails', album.id);
|
||||
}
|
||||
this.$store.commit('albums/toggleExpandedState', album.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~/assets/styles/_colors.scss';
|
||||
|
||||
div.album {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
|
||||
div.arrow-container {
|
||||
width: 2em;
|
||||
height: 64px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
i {
|
||||
border: 2px solid $defaultTextColor;
|
||||
border-right: 0;
|
||||
border-top: 0;
|
||||
display: block;
|
||||
height: 1em;
|
||||
position: absolute;
|
||||
transform: rotate(-135deg);
|
||||
transform-origin: center;
|
||||
width: 1em;
|
||||
z-index: 4;
|
||||
top: 22px;
|
||||
|
||||
-webkit-transition: transform 0.1s linear;
|
||||
-moz-transition: transform 0.1s linear;
|
||||
-ms-transition: transform 0.1s linear;
|
||||
-o-transition: transform 0.1s linear;
|
||||
transition: transform 0.1s linear;
|
||||
|
||||
&.active {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.thumb {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
-webkit-box-shadow: $boxShadowLight;
|
||||
box-shadow: $boxShadowLight;
|
||||
}
|
||||
|
||||
div.info {
|
||||
margin-left: 15px;
|
||||
text-align: left;
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
a {
|
||||
color: $defaultTextColor;
|
||||
font-weight: 400;
|
||||
&:hover { text-decoration: underline; }
|
||||
}
|
||||
}
|
||||
span { display: block; }
|
||||
span:nth-child(3) {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
div.latest {
|
||||
flex-grow: 1;
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
margin-left: 15px;
|
||||
|
||||
span.no-files {
|
||||
font-size: 1.5em;
|
||||
color: #b1b1b1;
|
||||
padding-top: 17px;
|
||||
}
|
||||
|
||||
div.more {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
background: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
a {
|
||||
line-height: 1rem;
|
||||
color: $defaultTextColor;
|
||||
&:hover { text-decoration: underline; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.no-background { background: none !important; }
|
||||
</style>
|
||||
|
|
@ -25,118 +25,9 @@
|
|||
</div>
|
||||
|
||||
<div class="view-container">
|
||||
<div v-for="album in albums"
|
||||
<AlbumEntry v-for="album in albums.list"
|
||||
:key="album.id"
|
||||
class="album">
|
||||
<div class="arrow-container"
|
||||
@click="fetchAlbumDetails(album)">
|
||||
<i :class="{ active: album.isDetailsOpen }"
|
||||
class="icon-arrow" />
|
||||
</div>
|
||||
<div class="thumb">
|
||||
<figure class="image is-64x64 thumb">
|
||||
<img src="~/assets/images/blank_darker.png">
|
||||
</figure>
|
||||
</div>
|
||||
<div class="info">
|
||||
<h4>
|
||||
<router-link :to="`/dashboard/albums/${album.id}`">{{ album.name }}</router-link>
|
||||
</h4>
|
||||
<span>Updated <timeago :since="album.editedAt" /></span>
|
||||
<span>{{ album.fileCount || 0 }} files</span>
|
||||
</div>
|
||||
<div class="latest is-hidden-mobile">
|
||||
<template v-if="album.fileCount > 0">
|
||||
<div v-for="file of album.files"
|
||||
:key="file.id"
|
||||
class="thumb">
|
||||
<figure class="image is-64x64">
|
||||
<a :href="file.url"
|
||||
target="_blank">
|
||||
<img :src="file.thumbSquare">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<div v-if="album.fileCount > 5"
|
||||
class="thumb more no-background">
|
||||
<router-link :to="`/dashboard/albums/${album.id}`">{{ album.fileCount - 5 }}+ more</router-link>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="no-files">Nothing to show here</span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="album.isDetailsOpen"
|
||||
class="details">
|
||||
<h2>Public links for this album:</h2>
|
||||
|
||||
<b-table
|
||||
:data="album.links.length ? album.links : []"
|
||||
:mobile-cards="true">
|
||||
<template slot-scope="props">
|
||||
<b-table-column field="identifier"
|
||||
label="Link"
|
||||
centered>
|
||||
<a :href="`${config.URL}/a/${props.row.identifier}`"
|
||||
target="_blank">
|
||||
{{ props.row.identifier }}
|
||||
</a>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="views"
|
||||
label="Views"
|
||||
centered>
|
||||
{{ props.row.views }}
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="enableDownload"
|
||||
label="Allow download"
|
||||
centered>
|
||||
<b-switch v-model="props.row.enableDownload"
|
||||
@input="linkOptionsChanged(props.row)" />
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="enabled"
|
||||
numeric>
|
||||
<button class="button is-danger"
|
||||
@click="promptDeleteAlbumLink(props.row.identifier)">Delete link</button>
|
||||
</b-table-column>
|
||||
</template>
|
||||
<template slot="empty">
|
||||
<div class="has-text-centered">
|
||||
<i class="icon-misc-mood-sad" />
|
||||
</div>
|
||||
<div class="has-text-centered">
|
||||
Nothing here
|
||||
</div>
|
||||
</template>
|
||||
<template slot="footer">
|
||||
<div class="level is-paddingless">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<button :class="{ 'is-loading': album.isCreatingLink }"
|
||||
class="button is-primary"
|
||||
style="float: left"
|
||||
@click="createLink(album)">Create new link</button>
|
||||
</div>
|
||||
<div class="level-item">
|
||||
<span class="has-text-default">{{ album.links.length }} / {{ config.maxLinksPerAlbum }} links created</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level-right">
|
||||
<div class="level-item">
|
||||
<button class="button is-danger"
|
||||
style="float: right"
|
||||
@click="promptDeleteAlbum(album.id)">Delete album</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
</div>
|
||||
:album="album" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -146,87 +37,28 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import Sidebar from '~/components/sidebar/Sidebar.vue';
|
||||
import AlbumEntry from '~/components/album/AlbumEntry.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sidebar
|
||||
Sidebar,
|
||||
AlbumEntry
|
||||
},
|
||||
middleware: 'auth',
|
||||
middleware: ['auth', ({ store }) => {
|
||||
store.dispatch('albums/fetch');
|
||||
}],
|
||||
data() {
|
||||
return {
|
||||
albums: [],
|
||||
newAlbumName: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
config() {
|
||||
return this.$store.state.config;
|
||||
}
|
||||
},
|
||||
computed: mapState(['config', 'albums']),
|
||||
metaInfo() {
|
||||
return { title: 'Uploads' };
|
||||
},
|
||||
mounted() {
|
||||
this.getAlbums();
|
||||
},
|
||||
methods: {
|
||||
async fetchAlbumDetails(album) {
|
||||
const response = await this.$axios.$get(`album/${album.id}/links`);
|
||||
album.links = response.links;
|
||||
album.isDetailsOpen = !album.isDetailsOpen;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
promptDeleteAlbum(id) {
|
||||
this.$buefy.dialog.confirm({
|
||||
message: 'Are you sure you want to delete this album?',
|
||||
onConfirm: () => this.deleteAlbum(id)
|
||||
});
|
||||
},
|
||||
async deleteAlbum(id) {
|
||||
const response = await this.$axios.$delete(`album/${id}`);
|
||||
this.getAlbums();
|
||||
return this.$buefy.toast.open(response.message);
|
||||
},
|
||||
promptDeleteAlbumLink(identifier) {
|
||||
this.$buefy.dialog.confirm({
|
||||
message: 'Are you sure you want to delete this album link?',
|
||||
onConfirm: () => this.deleteAlbumLink(identifier)
|
||||
});
|
||||
},
|
||||
async deleteAlbumLink(identifier) {
|
||||
const response = await this.$axios.$delete(`album/link/delete/${identifier}`);
|
||||
return this.$buefy.toast.open(response.message);
|
||||
},
|
||||
async linkOptionsChanged(link) {
|
||||
const response = await this.$axios.$post(`album/link/edit`,
|
||||
{
|
||||
identifier: link.identifier,
|
||||
enableDownload: link.enableDownload,
|
||||
enabled: link.enabled
|
||||
});
|
||||
this.$buefy.toast.open(response.message);
|
||||
},
|
||||
async createLink(album) {
|
||||
album.isCreatingLink = true;
|
||||
// Since we actually want to change the state even if the call fails, use a try catch
|
||||
try {
|
||||
const response = await this.$axios.$post(`album/link/new`,
|
||||
{ albumId: album.id });
|
||||
this.$buefy.toast.open(response.message);
|
||||
album.links.push({
|
||||
identifier: response.identifier,
|
||||
views: 0,
|
||||
enabled: true,
|
||||
enableDownload: true,
|
||||
expiresAt: null
|
||||
});
|
||||
} catch (error) {
|
||||
//
|
||||
} finally {
|
||||
album.isCreatingLink = false;
|
||||
}
|
||||
},
|
||||
async createAlbum() {
|
||||
if (!this.newAlbumName || this.newAlbumName === '') return;
|
||||
const response = await this.$axios.$post(`album/new`,
|
||||
|
@ -234,17 +66,11 @@ export default {
|
|||
this.newAlbumName = null;
|
||||
this.$buefy.toast.open(response.message);
|
||||
this.getAlbums();
|
||||
},
|
||||
async getAlbums() {
|
||||
const response = await this.$axios.$get(`albums/mini`);
|
||||
for (const album of response.albums) {
|
||||
album.isDetailsOpen = false;
|
||||
}
|
||||
this.albums = response.albums;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~/assets/styles/_colors.scss';
|
||||
div.view-container {
|
||||
|
@ -256,121 +82,5 @@ export default {
|
|||
background-color: $base-2;
|
||||
}
|
||||
|
||||
div.album {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
|
||||
div.arrow-container {
|
||||
width: 2em;
|
||||
height: 64px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
i {
|
||||
border: 2px solid $defaultTextColor;
|
||||
border-right: 0;
|
||||
border-top: 0;
|
||||
display: block;
|
||||
height: 1em;
|
||||
position: absolute;
|
||||
transform: rotate(-135deg);
|
||||
transform-origin: center;
|
||||
width: 1em;
|
||||
z-index: 4;
|
||||
top: 22px;
|
||||
|
||||
-webkit-transition: transform 0.1s linear;
|
||||
-moz-transition: transform 0.1s linear;
|
||||
-ms-transition: transform 0.1s linear;
|
||||
-o-transition: transform 0.1s linear;
|
||||
transition: transform 0.1s linear;
|
||||
|
||||
&.active {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
div.thumb {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
-webkit-box-shadow: $boxShadowLight;
|
||||
box-shadow: $boxShadowLight;
|
||||
}
|
||||
|
||||
div.info {
|
||||
margin-left: 15px;
|
||||
text-align: left;
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
a {
|
||||
color: $defaultTextColor;
|
||||
font-weight: 400;
|
||||
&:hover { text-decoration: underline; }
|
||||
}
|
||||
}
|
||||
span { display: block; }
|
||||
span:nth-child(3) {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
div.latest {
|
||||
flex-grow: 1;
|
||||
justify-content: flex-end;
|
||||
display: flex;
|
||||
margin-left: 15px;
|
||||
|
||||
span.no-files {
|
||||
font-size: 1.5em;
|
||||
color: #b1b1b1;
|
||||
padding-top: 17px;
|
||||
}
|
||||
|
||||
div.more {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
background: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
a {
|
||||
line-height: 1rem;
|
||||
color: $defaultTextColor;
|
||||
&:hover { text-decoration: underline; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.details {
|
||||
flex: 0 1 100%;
|
||||
padding-left: 2em;
|
||||
padding-top: 1em;
|
||||
min-height: 50px;
|
||||
|
||||
.b-table {
|
||||
padding: 2em 0em;
|
||||
|
||||
.table-wrapper {
|
||||
-webkit-box-shadow: $boxShadowLight;
|
||||
box-shadow: $boxShadowLight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.column > h2.subtitle { padding-top: 1px; }
|
||||
|
||||
div.no-background { background: none !important; }
|
||||
</style>
|
||||
<style lang="scss">
|
||||
@import '~/assets/styles/_colors.scss';
|
||||
|
||||
.b-table {
|
||||
.table-wrapper {
|
||||
-webkit-box-shadow: $boxShadowLight;
|
||||
box-shadow: $boxShadowLight;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/* eslint-disable no-shadow */
|
||||
export const state = () => ({
|
||||
list: [],
|
||||
isListLoading: false,
|
||||
albumDetails: {},
|
||||
expandedAlbums: []
|
||||
});
|
||||
|
||||
export const getters = {
|
||||
isExpanded: state => id => state.expandedAlbums.indexOf(id) > -1,
|
||||
getDetails: state => id => state.albumDetails[id] || {}
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
async fetch({ commit, dispatch }) {
|
||||
try {
|
||||
commit('albumsRequest');
|
||||
const response = await this.$axios.$get(`albums/mini`);
|
||||
|
||||
commit('setAlbums', response.albums);
|
||||
} catch (e) {
|
||||
dispatch('alert/set', { text: e.message, error: true }, { root: true });
|
||||
}
|
||||
},
|
||||
async fetchDetails({ commit }, albumId) {
|
||||
const response = await this.$axios.$get(`album/${albumId}/links`);
|
||||
|
||||
commit('setDetails', {
|
||||
id: albumId,
|
||||
details: {
|
||||
links: response.links
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const mutations = {
|
||||
albumsRequest(state) {
|
||||
state.isLoading = true;
|
||||
},
|
||||
setAlbums(state, albums) {
|
||||
state.list = albums;
|
||||
state.isLoading = false;
|
||||
},
|
||||
setDetails(state, { id, details }) {
|
||||
state.albumDetails[id] = details;
|
||||
},
|
||||
toggleExpandedState(state, id) {
|
||||
const foundIndex = state.expandedAlbums.indexOf(id);
|
||||
if (foundIndex > -1) {
|
||||
state.expandedAlbums.splice(foundIndex, 1);
|
||||
} else {
|
||||
state.expandedAlbums.push(id);
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue