Skip to content

Commit

Permalink
Reorder setlist entries
Browse files Browse the repository at this point in the history
  • Loading branch information
sbont committed Oct 5, 2024
1 parent ab08c56 commit fbea725
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 69 deletions.
6 changes: 3 additions & 3 deletions frontend/src/components/RepertoireMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
</router-link>
</li>
<li v-for="(setlist) in allSetlists" :key="setlist.id" class="droppable"
@drop="dropSong($event, setlist._links.self.href)" @dragover.prevent @dragenter.prevent>
@drop="dropSong($event, setlist._links!.self.href)" @dragover.prevent @dragenter.prevent>
<router-link :to="{ name: 'Setlist', params: { id: setlist.id } }" append>{{ setlist.name }}</router-link>
</li>
</ul>
Expand Down Expand Up @@ -67,7 +67,7 @@ onMounted(() => {
// Methods
const dropSong = (event: DragEvent, setlistUri: string) => {
let songUri = event.dataTransfer?.getData("text");
let entry = { setlist: setlistUri, song: songUri }
api.postSetlistEntry(entry);
if (songUri)
setlistStore.addSetlistEntry(setlistUri, songUri)
}
</script>
48 changes: 2 additions & 46 deletions frontend/src/components/Songs.vue
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
<template>
<div class="p-2">
<!-- <div class="is-flex is-justify-content-space-between">
<h1 class="title">Repertoire</h1>
<router-link class="button is-primary" to="song/new" append tag="button">Add +</router-link>
</div> -->
<progress v-if="loading" class="progress is-medium is-info" max="100"></progress>
<div v-if="error" class="error" @click="handleErrorClick">
ERROR: {{ error }}
</div>
<table class="table is-hoverable is-fullwidth song-table" v-if="!loading" v-cloak>
<thead>
<tr>
<th class="col1" title="number"></th>
<th class="col2">Title</th>
<th class="col3">Composer</th>
<th class="col4">Songbook</th>
<th class="col5">No.</th>
<th class="col7">Last Played</th>
<th class="category-col">Categories</th>
<th v-if="!!setlistId"></th>
</tr>
</thead>
<tbody>
<tr v-for="(song, index) in songs" class="song" :key="song.id" draggable="true"
Expand All @@ -37,14 +34,6 @@
</span>
</div>
</td>
<td v-if="!!setlistId" class="p-1b">
<button class="button is-danger is-inverted is-small" :class="{ 'is-loading': deleting }"
@click="removeSongFromSetlist(song as SetlistSong)">
<span class="icon is-small">
<i class="fas fa-times"></i>
</span>
</button>
</td>
</tr>
</tbody>
<tfoot></tfoot>
Expand All @@ -66,9 +55,6 @@ import { SetlistEntry, Song, User, WithEmbedded } from "@/types";
// Types
type DraftSong = Partial<Song>
interface SetlistSong extends Song {
setlistEntryUri: string
}
const emit = defineEmits(["remove"])
Expand All @@ -94,11 +80,6 @@ const pluralize = function (n: number) {
const loadSongs = function () {
const sorter = (data: Array<Song>) => data.sort((songA, songB) => songA.title.localeCompare(songB.title));
const setlistExtractor = (entries: Array<SetlistEntry & WithEmbedded<"song", Song>>) => {
let sorted = entries.sort((entryA, entryB) => entryA.number - entryB.number);
return sorted.map(entry => Object.assign(entry._embedded.song, { setlistEntryUri: entry?._links?.self.href })) as Array<SetlistSong>;
}
const routeName = route.name;
let id = Number(route.params.id);
let songsLoaded;
Expand All @@ -110,19 +91,10 @@ const loadSongs = function () {
case 'CategoryLiturgical':
songsLoaded = api.getSongsByCategoryId(id).then(response => songs.value = sorter(response.data));
break;
case 'Setlist':
setlistId.value = id;
songsLoaded = api.getSetlistEntries(id).then(response => songs.value = setlistExtractor(response.data));
break;
}
songsLoaded!.finally(() => (loading.value = false));
}
const removeSong = function (song: Song) {
// notice NOT using "=>" syntax
songs.value.splice(songs.value.indexOf(song), 1);
}
const handleErrorClick = function () {
error.value = null;
}
Expand All @@ -136,22 +108,6 @@ const startDrag = function (event: DragEvent, song: Song) {
}
}
const removeSongFromSetlist = function (song: SetlistSong) {
loading.value = true;
deleting.value = true;
let entryUri = song.setlistEntryUri;
api.deleteByUri(entryUri)
.then((response) => {
removeSong(song);
})
.catch((error) => {
error.value = "Failed to remove entry";
})
.finally(() => {
loading.value = false;
deleting.value = false;
});
}
</script>

<style>
Expand Down
76 changes: 70 additions & 6 deletions frontend/src/stores/setlistStore.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import {defineStore} from "pinia";
import api from "../api";
import { CacheMap } from "@/types/CacheMaps";
import { Setlist } from "@/types";
import {CacheListMap, CacheMap} from "@/types/CacheMaps";
import {Setlist, SetlistEntry, Song, WithEmbedded} from "@/types";
import {useSongs} from "@/stores/songStore";

export const useSetlists = defineStore('setlists', {
state: () => ({
setlists: new CacheMap<number, Setlist>(),
entriesBySetlistId: new CacheListMap<number, SetlistEntry & WithEmbedded<"song", Song>>(),
loading: false,
error: null as string | null
error: null as string | null,
songStore: useSongs()
}),
getters: {
allSetlists(state) {
Expand All @@ -34,6 +37,55 @@ export const useSetlists = defineStore('setlists', {
return response.data;
},

async fetchEntries(setlistId: number) {
this.loading = true
const response = await api.getSetlistEntries(setlistId)
response.data.forEach(entry => {
const song = entry._embedded.song;
this.songStore.put(song)
});
this.entriesBySetlistId.set(setlistId, response.data)
this.sortEntries(setlistId)
return this.entriesBySetlistId.getOrEmpty(setlistId)
},

sortEntries(setlistId: number) {
let entries = this.entriesBySetlistId.get(setlistId)
if (entries) {
let sorted = entries.sort((entryA, entryB) => entryA.number - entryB.number);
this.entriesBySetlistId.set(setlistId, sorted)
}
},

async move(setlistId: number, entryNumber: number, direction: number) {
let entries = this.entriesBySetlistId.get(setlistId)
console.log(entries);
if (!entries) return;

let originalIndex = entryNumber - 1
let original = entries[originalIndex]
let newIndex = originalIndex + direction;
let swapped = entries[newIndex]
console.log(originalIndex);
console.log(original);
console.log(newIndex);
console.log(swapped);
if (!swapped) return;

original.number = newIndex + 1
swapped.number = originalIndex + 1
this.sortEntries(setlistId)

let saveFirst = this.saveEntryToServer(original);
let saveSecond = this.saveEntryToServer(swapped);
Promise.all([saveFirst, saveSecond]).catch(error => {
console.log(error);
original.number = originalIndex + 1
swapped.number = newIndex + 1
this.sortEntries(setlistId)
})
},

async get(setlistId: number) {
if (!this.setlists.has(setlistId)) {
return await this.fetch(setlistId);
Expand All @@ -54,11 +106,23 @@ export const useSetlists = defineStore('setlists', {
return api.createNewSetlist(setlist);
}
},

async addSetlistEntry(setlistUri: string, songUri: string) {
let entry = { setlist: setlistUri, song: songUri }
await api.postSetlistEntry(entry);
},

async saveEntryToServer(entry: SetlistEntry) {
if (entry.id) {
return api.update(entry._links!.self.href, entry);
} else {
return api.postSetlistEntry(entry);
}
},

async remove(setlistId: number) {
return api.deleteSetlistForId(setlistId)
.then((response) => {
this.setlists.delete(setlistId);
});
.then((_) => this.setlists.delete(setlistId));
}
}
})
4 changes: 0 additions & 4 deletions frontend/src/stores/songStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,6 @@ export const useSongs = defineStore('songs', {
this.songsBySetlistId.set(setlistId, songs)
},

removeSetlist(song: Song, setlistId: number) {
api.deleteSetlistEntry
},

save(song: Song) {
const savePromise = this.saveToServer(song);
savePromise.then(response => this.songs.set(response.data.id, response.data));
Expand Down
Loading

0 comments on commit fbea725

Please sign in to comment.