Migrate a bunch of components

This commit is contained in:
wvffle 2022-07-05 22:34:11 +00:00 committed by Georg Krause
parent 0251789f82
commit 779d71abbc
7 changed files with 438 additions and 435 deletions

View File

@ -1,9 +1,159 @@
<script setup lang="ts">
import type { Playlist, Track, PlaylistTrack, BackendError, APIErrorResponse } from '~/types'
import { useStore } from '~/store'
import { useGettext } from 'vue3-gettext'
import { computed, ref } from 'vue'
import axios from 'axios'
import PlaylistForm from '~/components/playlists/Form.vue'
import draggable from 'vuedraggable'
import { useVModels } from '@vueuse/core'
import useQueue from '~/composables/audio/useQueue'
interface Props {
playlist: Playlist | null
playlistTracks: PlaylistTrack[]
}
const props = defineProps<Props>()
const emit = defineEmits(['update:playlist', 'update:playlistTracks'])
const { playlistTracks, playlist } = useVModels(props, emit)
const errors = ref([] as string[])
const duplicateTrackAddInfo = ref<APIErrorResponse | null>(null)
const showDuplicateTrackAddConfirmation = ref(false)
const { tracks: queueTracks } = useQueue()
interface ModifiedPlaylistTrack extends PlaylistTrack {
_id?: string
}
const tracks = computed({
get: () => playlistTracks.value.map((playlistTrack, index) => ({ ...playlistTrack, _id: `${index}-${playlistTrack.track.id}` } as ModifiedPlaylistTrack)),
set: (playlist) => {
playlistTracks.value = playlist.map((modifiedPlaylistTrack, index) => {
const res = { ...modifiedPlaylistTrack, index } as ModifiedPlaylistTrack
delete res._id
return res as PlaylistTrack
})
}
})
const { $pgettext } = useGettext()
const labels = computed(() => ({
copyTitle: $pgettext('Content/Playlist/Button.Tooltip/Verb', 'Copy the current queue to this playlist')
}))
const isLoading = ref(false)
const status = computed(() => isLoading.value
? 'loading'
: errors.value.length
? 'errored'
: showDuplicateTrackAddConfirmation.value
? 'confirmDuplicateAdd'
: 'saved'
)
const responseHandlers = {
success () {
errors.value = []
showDuplicateTrackAddConfirmation.value = false
},
errored (error: BackendError): void {
const { backendErrors, rawPayload } = error
// if backendErrors isn't populated (e.g. duplicate track exceptions raised by
// the playlist model), read directly from the response
// TODO (wvffle): Check if such case exists after rewrite
if (error.rawPayload?.playlist) {
error.backendErrors = error.rawPayload.playlist as string[]
error.rawPayload = undefined
return this.errored(error)
}
// TODO (wvffle): Test if it works
// if (errors.length === 1 && errors[0].code === 'tracks_already_exist_in_playlist') {
if (backendErrors.length === 1 && backendErrors[0] === 'Tracks already exist in playlist') {
duplicateTrackAddInfo.value = rawPayload ?? null
showDuplicateTrackAddConfirmation.value = true
return
}
errors.value = backendErrors
}
}
const store = useStore()
const reorder = async ({ oldIndex: from, newIndex: to }: { oldIndex: number, newIndex: number }) => {
isLoading.value = true
try {
await axios.post(`playlists/${playlist.value!.id}/move/`, { from, to })
await store.dispatch('playlists/fetchOwn')
responseHandlers.success()
} catch (error) {
responseHandlers.errored(error as BackendError)
}
isLoading.value = false
}
const removePlaylistTrack = async (index: number) => {
isLoading.value = true
try {
tracks.value.splice(index, 1)
await axios.post(`playlists/${playlist.value!.id}/remove/`, { index })
await store.dispatch('playlists/fetchOwn')
responseHandlers.success()
} catch (error) {
responseHandlers.errored(error as BackendError)
}
isLoading.value = false
}
const clearPlaylist = async () => {
isLoading.value = true
try {
tracks.value = []
await axios.post(`playlists/${playlist.value!.id}/clear/`)
await store.dispatch('playlists/fetchOwn')
responseHandlers.success()
} catch (error) {
responseHandlers.errored(error as BackendError)
}
isLoading.value = false
}
const insertMany = async (insertedTracks: Track[], allowDuplicates: boolean) => {
isLoading.value = true
try {
const response = await axios.post(`playlists/${playlist.value!.id}/add/`, {
allow_duplicates: allowDuplicates,
tracks: insertedTracks.map(track => track.id)
})
tracks.value.push(...response.data.results)
await store.dispatch('playlists/fetchOwn')
responseHandlers.success()
} catch (error) {
responseHandlers.errored(error as BackendError)
}
isLoading.value = false
}
</script>
<template>
<div class="ui text container component-playlist-editor">
<playlist-form
:title="false"
:playlist="playlist"
@updated="$emit('playlist-updated', $event)"
v-model:playlist="playlist"
/>
<h3 class="ui top attached header">
<translate translate-context="Content/Playlist/Title">
@ -43,14 +193,14 @@
class="ui warning message"
>
<p
v-translate="{playlist: playlist.name}"
v-translate="{playlist: playlist?.name}"
translate-context="Content/Playlist/Paragraph"
>
Some tracks in your queue are already in this playlist:
</p>
<ul class="ui relaxed divided list duplicate-tracks-list">
<li
v-for="(track, key) in duplicateTrackAddInfo.tracks"
v-for="(track, key) in duplicateTrackAddInfo?.tracks ?? []"
:key="key"
class="ui item"
>
@ -74,7 +224,7 @@
</div>
<div class="ui bottom attached segment">
<button
:disabled="queueTracks.length === 0 || null"
:disabled="queueTracks.length === 0"
:class="['ui', {disabled: queueTracks.length === 0}, 'labeled', 'icon', 'button']"
:title="labels.copyTitle"
@click="insertMany(queueTracks, false)"
@ -91,7 +241,7 @@
</button>
<dangerous-button
:disabled="plts.length === 0 || null"
:disabled="tracks.length === 0"
class="ui labeled right floated danger icon button"
:action="clearPlaylist"
>
@ -100,9 +250,9 @@
</translate>
<template #modal-header>
<p
v-translate="{playlist: playlist.name}"
v-translate="{playlist: playlist?.name}"
translate-context="Popup/Playlist/Title"
:translate-params="{playlist: playlist.name}"
:translate-params="{playlist: playlist?.name}"
>
Do you want to clear the playlist "%{ playlist }"?
</p>
@ -123,7 +273,7 @@
</template>
</dangerous-button>
<div class="ui hidden divider" />
<template v-if="plts.length > 0">
<template v-if="tracks.length > 0">
<p>
<translate translate-context="Content/Playlist/Paragraph/Call to action">
Drag and drop rows to reorder tracks in the playlist
@ -132,7 +282,7 @@
<div class="table-wrapper">
<table class="ui compact very basic unstackable table">
<draggable
v-model:list="plts"
v-model="tracks"
tag="tbody"
item-key="_id"
@update="reorder"
@ -163,7 +313,7 @@
<td class="right aligned">
<button
class="ui circular danger basic icon button"
@click.stop="removePlt(index)"
@click.stop="removePlaylistTrack(index)"
>
<i
class="trash icon"
@ -179,148 +329,3 @@
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
import { computed } from 'vue'
import axios from 'axios'
import PlaylistForm from '~/components/playlists/Form.vue'
import draggable from 'vuedraggable'
export default {
components: {
draggable,
PlaylistForm
},
props: {
playlist: { type: Object, required: true },
playlistTracks: { type: Array, required: true }
},
setup (props) {
const plts = computed(() => {
return props.playlistTracks.map((plt, index) => ({ ...plt, _id: `${index}-${plt.track.id}` }))
})
return { plts }
},
data () {
return {
isLoading: false,
errors: [],
duplicateTrackAddInfo: {},
showDuplicateTrackAddConfirmation: false
}
},
computed: {
...mapState({
queueTracks: state => state.queue.tracks
}),
labels () {
return {
copyTitle: this.$pgettext('Content/Playlist/Button.Tooltip/Verb', 'Copy the current queue to this playlist')
}
},
status () {
if (this.isLoading) {
return 'loading'
}
if (this.errors.length > 0) {
return 'errored'
}
if (this.showDuplicateTrackAddConfirmation) {
return 'confirmDuplicateAdd'
}
return 'saved'
}
},
watch: {
plts: {
handler (newValue) {
newValue.forEach((e, i) => {
e.index = i
})
this.$emit('tracks-updated', newValue)
},
deep: true
}
},
methods: {
success () {
this.isLoading = false
this.errors = []
this.showDuplicateTrackAddConfirmation = false
},
errored (errors) {
this.isLoading = false
if (errors.length === 1 && errors[0].code === 'tracks_already_exist_in_playlist') {
this.duplicateTrackAddInfo = errors[0]
this.showDuplicateTrackAddConfirmation = true
} else {
this.errors = errors
}
},
reorder ({ oldIndex, newIndex }) {
const self = this
self.isLoading = true
const url = `playlists/${this.playlist.id}/move`
axios.post(url, { from: oldIndex, to: newIndex }).then((response) => {
self.success()
}, error => {
self.errored(error.backendErrors)
})
},
removePlt (index) {
this.plts.splice(index, 1)
const self = this
self.isLoading = true
const url = `playlists/${this.playlist.id}/remove`
axios.post(url, { index }).then((response) => {
self.success()
self.$store.dispatch('playlists/fetchOwn')
}, error => {
self.errored(error.backendErrors)
})
},
clearPlaylist () {
this.plts = []
const self = this
self.isLoading = true
const url = 'playlists/' + this.playlist.id + '/clear'
axios.delete(url).then((response) => {
self.success()
self.$store.dispatch('playlists/fetchOwn')
}, error => {
self.errored(error.backendErrors)
})
},
insertMany (tracks, allowDuplicates) {
const self = this
const ids = tracks.map(t => {
return t.id
})
const payload = {
tracks: ids,
allow_duplicates: allowDuplicates
}
self.isLoading = true
const url = 'playlists/' + this.playlist.id + '/add/'
axios.post(url, payload).then((response) => {
response.data.results.forEach(r => {
self.plts.push(r)
})
self.success()
self.$store.dispatch('playlists/fetchOwn')
}, error => {
// if backendErrors isn't populated (e.g. duplicate track exceptions raised by
// the playlist model), read directly from the response
if (error.rawPayload.playlist) {
self.errored(error.rawPayload.playlist)
} else {
self.errored(error.backendErrors)
}
})
}
}
}
</script>

View File

@ -1,3 +1,101 @@
<script setup lang="ts">
import type { Playlist, PrivacyLevel, BackendError } from '~/types'
import $ from 'jquery'
import axios from 'axios'
import { useVModels, useCurrentElement } from '@vueuse/core'
import { useGettext } from 'vue3-gettext'
import { useStore } from '~/store'
import { ref, computed, onMounted, nextTick } from 'vue'
import useLogger from '~/composables/useLogger'
import useSharedLabels from '~/composables/locale/useSharedLabels'
interface Props {
title?: boolean
create?: boolean
playlist?: Playlist | null
}
const props = withDefaults(defineProps<Props>(), {
title: true,
create: false,
playlist: null
})
const emit = defineEmits(['update:playlist'])
const { playlist } = useVModels(props, emit)
const logger = useLogger()
const errors = ref([] as string[])
const success = ref(false)
const store = useStore()
const name = ref(playlist.value?.name ?? '')
const privacyLevel = ref(playlist.value?.privacy_level ?? store.state.auth.profile?.privacy_level ?? 'me')
const { $pgettext } = useGettext()
const labels = computed(() => ({
placeholder: $pgettext('Content/Playlist/Input.Placeholder', 'My awesome playlist')
}))
const sharedLabels = useSharedLabels()
const privacyLevelChoices = computed(() => [
{
value: 'me',
label: sharedLabels.fields.privacy_level.choices.me
},
{
value: 'instance',
label: sharedLabels.fields.privacy_level.choices.instance
},
{
value: 'everyone',
label: sharedLabels.fields.privacy_level.choices.everyone
}
] as { value: PrivacyLevel, label: string }[])
const el = useCurrentElement()
onMounted(async () => {
await nextTick()
// @ts-expect-error dropdown is from semantic ui
$(el.value).find('.dropdown').dropdown()
})
const isLoading = ref(false)
const submit = async () => {
isLoading.value = true
success.value = false
errors.value = []
try {
const url = props.create ? 'playlists/' : `playlists/${playlist.value!.id}/`
const method = props.create ? 'post' : 'patch'
const data = {
name: name.value,
privacy_level: privacyLevel.value
}
const response = await axios.request({ method, url, data })
success.value = true
if (props.create) {
name.value = ''
} else {
playlist.value = response.data
}
store.dispatch('playlists/fetchOwn')
} catch (error) {
logger.error('Error while creating playlist')
errors.value = (error as BackendError).backendErrors
}
isLoading.value = false
}
</script>
<template>
<form
class="ui form"
@ -96,100 +194,3 @@
</div>
</form>
</template>
<script>
import $ from 'jquery'
import axios from 'axios'
import useLogger from '~/composables/useLogger'
import useSharedLabels from '~/composables/locale/useSharedLabels'
const logger = useLogger()
export default {
props: {
title: { type: Boolean, default: true },
playlist: { type: Object, default: null }
},
setup () {
const sharedLabels = useSharedLabels()
return { sharedLabels }
},
data () {
const d = {
errors: [],
success: false,
isLoading: false
}
if (this.playlist) {
d.name = this.playlist.name
d.privacyLevel = this.playlist.privacy_level
} else {
d.privacyLevel = this.$store.state.auth.profile.privacy_level
d.name = ''
}
return d
},
computed: {
labels () {
return {
placeholder: this.$pgettext('Content/Playlist/Input.Placeholder', 'My awesome playlist')
}
},
privacyLevelChoices: function () {
return [
{
value: 'me',
label: this.sharedLabels.fields.privacy_level.choices.me
},
{
value: 'instance',
label: this.sharedLabels.fields.privacy_level.choices.instance
},
{
value: 'everyone',
label: this.sharedLabels.fields.privacy_level.choices.everyone
}
]
}
},
mounted () {
$(this.$el).find('.dropdown').dropdown()
},
methods: {
submit () {
this.isLoading = true
this.success = false
this.errors = []
const self = this
const payload = {
name: this.name,
privacy_level: this.privacyLevel
}
let promise
let url
if (this.playlist) {
url = `playlists/${this.playlist.id}/`
promise = axios.patch(url, payload)
} else {
url = 'playlists/'
promise = axios.post(url, payload)
}
return promise.then(response => {
self.success = true
self.isLoading = false
if (!self.playlist) {
self.name = ''
}
self.$emit('updated', response.data)
self.$store.dispatch('playlists/fetchOwn')
}, error => {
logger.error('Error while creating playlist')
self.isLoading = false
self.errors = error.backendErrors
})
}
}
}
</script>

View File

@ -52,7 +52,7 @@ const addToPlaylist = async (playlistId: number, allowDuplicates: boolean) => {
lastSelectedPlaylist.value = playlistId
try {
await axios.post(`playlists/${playlistId}/add`, {
await axios.post(`playlists/${playlistId}/add/`, {
tracks: [track.value?.id].filter(i => i),
allow_duplicates: allowDuplicates
})
@ -106,7 +106,7 @@ const addToPlaylist = async (playlistId: number, allowDuplicates: boolean) => {
</translate>
</h4>
<div class="scrolling content">
<playlist-form :key="formKey" />
<playlist-form :create="true" :key="formKey" />
<div class="ui divider" />
<div v-if="playlists.length > 0">
<div

View File

@ -1,3 +1,4 @@
import type { User } from '~/types'
import type { Module } from 'vuex'
import type { RootState } from '~/store/index'
@ -11,21 +12,11 @@ export interface State {
username: string
fullUsername: string
availablePermissions: Record<Permission, boolean>,
profile: null | Profile
profile: null | User
oauth: OAuthTokens
scopedTokens: ScopedTokens
}
interface Profile {
id: string
avatar?: string
username: string
full_username: string
instance_support_message_display_date: string
funkwhale_support_message_display_date: string
is_superuser: boolean
}
interface ScopedTokens {
listen: null | string
}
@ -136,13 +127,13 @@ const store: Module<State, RootState> = {
permission: (state, { key, status }: { key: Permission, status: boolean }) => {
state.availablePermissions[key] = status
},
profilePartialUpdate: (state, payload: Profile) => {
profilePartialUpdate: (state, payload: User) => {
if (!state.profile) {
state.profile = {} as Profile
state.profile = {} as User
}
for (const [key, value] of Object.entries(payload)) {
state.profile[key as keyof Profile] = value as never
state.profile[key as keyof User] = value as never
}
},
oauthApp: (state, payload) => {
@ -160,7 +151,7 @@ const store: Module<State, RootState> = {
const form = useFormData(credentials)
return axios.post('users/login', form).then(() => {
logger.info('Successfully logged in as', credentials.username)
dispatch('fetchProfile').then(() => {
dispatch('fetchUser').then(() => {
// Redirect to a specified route
import('~/router').then((router) => {
return router.default.push(next)
@ -190,11 +181,11 @@ const store: Module<State, RootState> = {
})
logger.info('Log out, goodbye!')
},
fetchProfile ({ dispatch }) {
fetchUser ({ dispatch }) {
return new Promise((resolve, reject) => {
axios.get('users/me/').then((response) => {
logger.info('Successfully fetched user profile')
dispatch('updateProfile', response.data)
dispatch('updateUser', response.data)
dispatch('ui/fetchUnreadNotifications', null, { root: true })
if (response.data.permissions.library) {
dispatch('ui/fetchPendingReviewEdits', null, { root: true })
@ -215,7 +206,7 @@ const store: Module<State, RootState> = {
})
})
},
updateProfile ({ commit }, data) {
updateUser ({ commit }, data) {
commit('authenticated', true)
commit('profile', data)
commit('username', data.username)
@ -253,7 +244,7 @@ const store: Module<State, RootState> = {
{ headers: { 'Content-Type': 'multipart/form-data' } }
)
commit('oauthToken', response.data)
await dispatch('fetchProfile')
await dispatch('fetchUser')
},
async refreshOauthToken ({ state, commit }) {
const payload = {

View File

@ -159,7 +159,24 @@ export interface License {
export interface Playlist {
id: string
name: string
modification_date: Date // TODO (wvffle): Find correct type
modification_date: string
user: User
privacy_level: PrivacyLevel
tracks_count: number
duration: number
is_playable: boolean
}
export interface PlaylistTrack {
track: Track
position?: number
}
export interface Radio {
id: string
name: string
user: User
}
// API stuff
@ -253,6 +270,7 @@ export interface FSLogs {
// Profile stuff
export interface Actor {
id: string
fid?: string
name?: string
icon?: Cover
@ -263,6 +281,17 @@ export interface Actor {
domain: string
}
export interface User {
id: string
avatar?: string
username: string
full_username: string
instance_support_message_display_date: string
funkwhale_support_message_display_date: string
is_superuser: boolean
privacy_level: PrivacyLevel
}
// Settings stuff
export type SettingsId = 'instance'
export interface SettingsGroup {

View File

@ -1,3 +1,74 @@
<script setup lang="ts">
import type { PlaylistTrack, Playlist } from '~/types'
import axios from 'axios'
import TrackTable from '~/components/audio/track/Table.vue'
import PlayButton from '~/components/audio/PlayButton.vue'
import PlaylistEditor from '~/components/playlists/Editor.vue'
import EmbedWizard from '~/components/audio/EmbedWizard.vue'
import Modal from '~/components/semantic/Modal.vue'
import { ref, computed } from 'vue'
import { useGettext } from 'vue3-gettext'
import { useRouter } from 'vue-router'
import { useStore } from '~/store'
interface Props {
id: string
defaultEdit?: boolean
}
const props = withDefaults(defineProps<Props>(), {
defaultEdit: false
})
const store = useStore()
const router = useRouter()
const edit = ref(props.defaultEdit)
const playlist = ref<Playlist | null>(null)
const playlistTracks = ref<PlaylistTrack[]>([])
const showEmbedModal = ref(false)
const tracks = computed(() => playlistTracks.value.map(({ track }, index) => ({ ...track, position: index + 1 })))
const { $pgettext } = useGettext()
const labels = computed(() => ({
playlist: $pgettext('*/*/*', 'Playlist')
}))
const isLoading = ref(false)
const fetchData = async () => {
isLoading.value = true
try {
const [playlistResponse, tracksResponse] = await Promise.all([
axios.get(`playlists/${props.id}/`),
axios.get(`playlists/${props.id}/tracks/`),
])
playlist.value = playlistResponse.data
playlistTracks.value = tracksResponse.data.results
} catch (error) {
// TODO (wvffle): Handle error
}
isLoading.value = false
}
fetchData()
const deletePlaylist = async () => {
try {
await axios.delete(`playlists/${props.id}/`)
store.dispatch('playlists/fetchOwn')
return router.push({ path: '/library' })
} catch (error) {
// TODO (wvffle): Handle error
}
}
</script>
<template>
<main>
<div
@ -45,7 +116,7 @@
</div>
<div class="ui buttons">
<button
v-if="$store.state.auth.profile && playlist.user.id === $store.state.auth.profile.id"
v-if="$store.state.auth.profile && playlist.user.id === $store.state.auth.profile?.id"
class="ui icon labeled button"
@click="edit = !edit"
>
@ -137,10 +208,8 @@
<section class="ui vertical stripe segment">
<template v-if="edit">
<playlist-editor
:playlist="playlist"
:playlist-tracks="playlistTracks"
@playlist-updated="playlist = $event"
@tracks-updated="updatePlts"
v-model:playlist="playlist"
v-model:playlist-tracks="playlistTracks"
/>
</template>
<template v-else-if="tracks.length > 0">
@ -177,81 +246,3 @@
</section>
</main>
</template>
<script>
import axios from 'axios'
import TrackTable from '~/components/audio/track/Table.vue'
import PlayButton from '~/components/audio/PlayButton.vue'
import PlaylistEditor from '~/components/playlists/Editor.vue'
import EmbedWizard from '~/components/audio/EmbedWizard.vue'
import Modal from '~/components/semantic/Modal.vue'
export default {
components: {
PlaylistEditor,
TrackTable,
PlayButton,
Modal,
EmbedWizard
},
props: {
id: { type: [Number, String], required: true },
defaultEdit: { type: Boolean, default: false }
},
data: function () {
return {
edit: this.defaultEdit,
isLoading: false,
playlist: null,
tracks: [],
playlistTracks: [],
showEmbedModal: false
}
},
computed: {
labels () {
return {
playlist: this.$pgettext('*/*/*', 'Playlist')
}
}
},
created: function () {
this.fetch()
},
methods: {
updatePlts (v) {
this.playlistTracks = v
this.tracks = v.map((e, i) => {
const track = e.track
track.position = i + 1
return track
})
},
fetch: function () {
const self = this
self.isLoading = true
const url = 'playlists/' + this.id + '/'
axios.get(url).then(response => {
self.playlist = response.data
axios
.get(url + 'tracks/')
.then(response => {
self.updatePlts(response.data.results)
})
.then(() => {
self.isLoading = false
})
})
},
deletePlaylist () {
const self = this
const url = 'playlists/' + this.id + '/'
axios.delete(url).then(response => {
self.$store.dispatch('playlists/fetchOwn')
self.$router.push({
path: '/library'
})
})
}
}
}
</script>

View File

@ -1,3 +1,63 @@
<script setup lang="ts">
import type { Track, Radio } from "~/types"
import axios from 'axios'
import TrackTable from '~/components/audio/track/Table.vue'
import RadioButton from '~/components/radios/Button.vue'
import Pagination from '~/components/vui/Pagination.vue'
import { ref, computed, watch } from 'vue'
import { useGettext } from 'vue3-gettext'
import { useRouter } from 'vue-router'
interface Props {
id: string
}
const props = defineProps<Props>()
const radio = ref<Radio | null>(null)
const tracks = ref([] as Track[])
const totalTracks = ref(0)
const page = ref(1)
const { $pgettext } = useGettext()
const labels = computed(() => ({
title: $pgettext('Head/Radio/Title', 'Radio')
}))
const isLoading = ref(false)
const fetchData = async () => {
isLoading.value = true
const url = `radios/radios/${props.id}/`
try {
const radioResponse = await axios.get(url)
radio.value = radioResponse.data
const tracksResponse = await axios.get(url + 'tracks/', { params: { page: page.value }})
totalTracks.value = tracksResponse.data.count
tracks.value = tracksResponse.data.results
} catch (error) {
// TODO (wvffle): Handle error
}
isLoading.value = false
}
watch(page, fetchData, { immediate: true })
const router = useRouter()
const deleteRadio = async () => {
try {
await axios.delete(`radios/radios/${props.id}/`)
return router.push({ path: '/library' })
} catch (error) {
// TODO (wvffle): Handle error
}
}
</script>
<template>
<main>
<div
@ -81,10 +141,9 @@
<div class="ui center aligned basic segment">
<pagination
v-if="totalTracks > 25"
:current="page"
v-model:current="page"
:paginate-by="25"
:total="totalTracks"
@page-changed="selectPage"
/>
</div>
</section>
@ -101,9 +160,9 @@
</translate>
</div>
<router-link
v-if="$store.state.auth.username === radio.user.username"
v-if="$store.state.auth.username === radio?.user.username"
class="ui success icon labeled button"
:to="{name: 'library.radios.edit', params: {id: radio.id}}"
:to="{name: 'library.radios.edit', params: { id: radio?.id }}"
>
<i class="pencil icon" />
Edit
@ -111,76 +170,3 @@
</div>
</main>
</template>
<script>
import axios from 'axios'
import TrackTable from '~/components/audio/track/Table.vue'
import RadioButton from '~/components/radios/Button.vue'
import Pagination from '~/components/vui/Pagination.vue'
export default {
components: {
TrackTable,
RadioButton,
Pagination
},
props: {
id: { type: Number, required: true }
},
data: function () {
return {
isLoading: false,
radio: null,
tracks: [],
totalTracks: 0,
page: 1
}
},
computed: {
labels () {
return {
title: this.$pgettext('Head/Radio/Title', 'Radio')
}
}
},
watch: {
page: function () {
this.fetch()
}
},
created: function () {
this.fetch()
},
methods: {
selectPage: function (page) {
this.page = page
},
fetch: function () {
const self = this
self.isLoading = true
const url = 'radios/radios/' + this.id + '/'
axios.get(url).then(response => {
self.radio = response.data
axios
.get(url + 'tracks/', { params: { page: this.page } })
.then(response => {
this.totalTracks = response.data.count
this.tracks = response.data.results
})
.then(() => {
self.isLoading = false
})
})
},
deleteRadio () {
const self = this
const url = 'radios/radios/' + this.id + '/'
axios.delete(url).then(response => {
self.$router.push({
path: '/library'
})
})
}
}
}
</script>