1.4.2 #78
20 changed files with 809 additions and 762 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -121,6 +121,6 @@ dist
|
||||||
dist
|
dist
|
||||||
yarn.lock
|
yarn.lock
|
||||||
public/css
|
public/css
|
||||||
public/css
|
public/js
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
dump
|
dump
|
||||||
|
|
46
gulpfile.js
Normal file
46
gulpfile.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
const { parallel, src, dest } = require("gulp");
|
||||||
|
|
||||||
|
const sourcemaps = require("gulp-sourcemaps");
|
||||||
|
const concat = require("gulp-concat");
|
||||||
|
|
||||||
|
const gulp = require("gulp");
|
||||||
|
const uglify = require("gulp-uglify");
|
||||||
|
const babel = require("gulp-babel");
|
||||||
|
|
||||||
|
const sourceJs = "javascripts/**/*.js";
|
||||||
|
const sourceRemoteJS = [
|
||||||
|
"./node_modules/vue/dist/vue.global.prod.js",
|
||||||
|
"./node_modules/axios/dist/axios.min.js",
|
||||||
|
];
|
||||||
|
|
||||||
|
const destination = "public/js";
|
||||||
|
|
||||||
|
// TASKS ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
const compileJs = function () {
|
||||||
|
return gulp
|
||||||
|
.src(sourceJs)
|
||||||
|
.pipe(sourcemaps.init())
|
||||||
|
.pipe(concat("main.js"))
|
||||||
|
.pipe(
|
||||||
|
babel({
|
||||||
|
presets: ["@babel/env"],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.pipe(uglify())
|
||||||
|
.pipe(sourcemaps.write("."))
|
||||||
|
.pipe(gulp.dest(destination));
|
||||||
|
};
|
||||||
|
const compileRemoteJs = function () {
|
||||||
|
return gulp
|
||||||
|
.src(sourceRemoteJS)
|
||||||
|
.pipe(sourcemaps.init())
|
||||||
|
.pipe(concat("libs.js"))
|
||||||
|
.pipe(sourcemaps.write("."))
|
||||||
|
.pipe(gulp.dest(destination));
|
||||||
|
};
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// COMMANDS -------------------------------------------------------------------
|
||||||
|
exports.default = parallel(compileJs, compileRemoteJs);
|
||||||
|
// ----------------------------------------------------------------------------
|
171
javascripts/ajouter-un-album.js
Normal file
171
javascripts/ajouter-un-album.js
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
Vue.createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
q: '',
|
||||||
|
year: '',
|
||||||
|
country: '',
|
||||||
|
format: '',
|
||||||
|
loading: false,
|
||||||
|
items: [],
|
||||||
|
details: {},
|
||||||
|
modalIsVisible: false,
|
||||||
|
formats: [
|
||||||
|
'Vinyl',
|
||||||
|
'Acetate',
|
||||||
|
'Flexi-disc',
|
||||||
|
'Lathe Cut',
|
||||||
|
'Mighty Tiny',
|
||||||
|
'Shellac',
|
||||||
|
'Sopic',
|
||||||
|
'Pathé Disc',
|
||||||
|
'Edison Disc',
|
||||||
|
'Cylinder',
|
||||||
|
'CD',
|
||||||
|
'CDr',
|
||||||
|
'CDV',
|
||||||
|
'DVD',
|
||||||
|
'DVDr',
|
||||||
|
'HD DVD',
|
||||||
|
'HD DVD-R',
|
||||||
|
'Blu-ray',
|
||||||
|
'Blu-ray-R',
|
||||||
|
'Ultra HD Blu-ray',
|
||||||
|
'SACD',
|
||||||
|
'4-Track Cartridge',
|
||||||
|
'8-Track Cartridge',
|
||||||
|
'Cassette',
|
||||||
|
'DC-International',
|
||||||
|
'Elcaset',
|
||||||
|
'PlayTape',
|
||||||
|
'RCA Tape Cartridge',
|
||||||
|
'DAT',
|
||||||
|
'DCC',
|
||||||
|
'Microcassette',
|
||||||
|
'NT Cassette',
|
||||||
|
'Pocket Rocker',
|
||||||
|
'Revere Magnetic Stereo Tape Ca',
|
||||||
|
'Tefifon',
|
||||||
|
'Reel-To-Reel',
|
||||||
|
'Sabamobil',
|
||||||
|
'Betacam',
|
||||||
|
'Betacam SP',
|
||||||
|
'Betamax',
|
||||||
|
'Cartrivision',
|
||||||
|
'MiniDV',
|
||||||
|
'Super VHS',
|
||||||
|
'U-matic',
|
||||||
|
'VHS',
|
||||||
|
'Video 2000',
|
||||||
|
'Video8',
|
||||||
|
'Film Reel',
|
||||||
|
'HitClips',
|
||||||
|
'Laserdisc',
|
||||||
|
'SelectaVision',
|
||||||
|
'VHD',
|
||||||
|
'Wire Recording',
|
||||||
|
'Minidisc',
|
||||||
|
'MVD',
|
||||||
|
'UMD',
|
||||||
|
'Floppy Disk',
|
||||||
|
'File',
|
||||||
|
'Memory Stick',
|
||||||
|
'Hybrid',
|
||||||
|
'All Media',
|
||||||
|
'Box Set',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
search(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if ( this.loading ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
let url = `/api/v1/search?q=${this.q}`;
|
||||||
|
|
||||||
|
if ( this.year ) {
|
||||||
|
url += `&year=${this.year}`;
|
||||||
|
}
|
||||||
|
if ( this.country ) {
|
||||||
|
url += `&country=${this.country}`;
|
||||||
|
}
|
||||||
|
if ( this.format ) {
|
||||||
|
url += `&format=${this.format}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.get(url)
|
||||||
|
.then( response => {
|
||||||
|
const {
|
||||||
|
results,
|
||||||
|
} = response.data;
|
||||||
|
let items = [];
|
||||||
|
|
||||||
|
for (let i = 0 ; i < results.length ; i += 1 ) {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
thumb,
|
||||||
|
year,
|
||||||
|
country,
|
||||||
|
format,
|
||||||
|
genre,
|
||||||
|
style,
|
||||||
|
} = results[i];
|
||||||
|
items.push({
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
thumb,
|
||||||
|
year,
|
||||||
|
country,
|
||||||
|
format,
|
||||||
|
genre,
|
||||||
|
style,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items = items;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
showToastr(err.response?.data?.message || "Aucun résultat trouvé :/");
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
toggleModal() {
|
||||||
|
this.modalIsVisible = !this.modalIsVisible;
|
||||||
|
},
|
||||||
|
loadDetails(discogsId) {
|
||||||
|
axios.get(`/api/v1/search/${discogsId}`)
|
||||||
|
.then( response => {
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
} = response;
|
||||||
|
|
||||||
|
this.details = data;
|
||||||
|
this.toggleModal();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
showToastr(err.response?.data?.message || "Impossible de charger les détails de cet album");
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
add() {
|
||||||
|
axios.post('/api/v1/albums', this.details)
|
||||||
|
.then(() => {
|
||||||
|
window.location.href = '/ma-collection';
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
showToastr(err.response?.data?.message || "Impossible d'ajouter cet album pour le moment…");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
orderedItems(items) {
|
||||||
|
return items.sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).mount('#ajouter-album');
|
133
javascripts/collection.js
Normal file
133
javascripts/collection.js
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
if ( typeof userId !== 'undefined' ) {
|
||||||
|
Vue.createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
moreFilters: false,
|
||||||
|
items: [],
|
||||||
|
total: 0,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
|
limit: 16,
|
||||||
|
artist: '',
|
||||||
|
format: '',
|
||||||
|
year: '',
|
||||||
|
genre: '',
|
||||||
|
style: '',
|
||||||
|
sortOrder: 'artists_sort-asc',
|
||||||
|
sort: 'artists_sort',
|
||||||
|
order: 'asc',
|
||||||
|
userId,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetch();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetch() {
|
||||||
|
this.loading = true;
|
||||||
|
this.total = 0;
|
||||||
|
|
||||||
|
const queryString = window.location.search;
|
||||||
|
const urlParams = new URLSearchParams(queryString);
|
||||||
|
const entries = urlParams.entries();
|
||||||
|
|
||||||
|
for(const entry of entries) {
|
||||||
|
switch(entry[0]) {
|
||||||
|
case 'artists_sort':
|
||||||
|
this.artist = entry[1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this[entry[0]] = entry[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = `/api/v1/albums?userId=${this.userId}&page=${this.page}&limit=${this.limit}&sort=${this.sort}&order=${this.order}`;
|
||||||
|
if ( this.artist ) {
|
||||||
|
url += `&artists_sort=${this.artist.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.format ) {
|
||||||
|
url += `&format=${this.format.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.year ) {
|
||||||
|
url += `&year=${this.year}`;
|
||||||
|
}
|
||||||
|
if ( this.genre ) {
|
||||||
|
url += `&genre=${this.genre.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.style ) {
|
||||||
|
url += `&style=${this.style.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.get(url)
|
||||||
|
.then( response => {
|
||||||
|
this.items = response.data.rows;
|
||||||
|
this.total = response.data.count || 0;
|
||||||
|
this.totalPages = parseInt(response.data.count / this.limit) + (response.data.count % this.limit > 0 ? 1 : 0);
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
showToastr(err.response?.data?.message || "Impossible de charger cette collection");
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
changeUrl() {
|
||||||
|
let url = `?page=${this.page}&limit=${this.limit}&sort=${this.sort}&order=${this.order}`;
|
||||||
|
if ( this.artist ) {
|
||||||
|
url += `&artists_sort=${this.artist.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.format ) {
|
||||||
|
url += `&format=${this.format.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.year ) {
|
||||||
|
url += `&year=${this.year}`;
|
||||||
|
}
|
||||||
|
if ( this.genre ) {
|
||||||
|
url += `&genre=${this.genre.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.style ) {
|
||||||
|
url += `&style=${this.style.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
location.href = url;
|
||||||
|
},
|
||||||
|
next(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.page += 1;
|
||||||
|
|
||||||
|
this.changeUrl();
|
||||||
|
},
|
||||||
|
previous(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.page -= 1;
|
||||||
|
|
||||||
|
this.changeUrl();
|
||||||
|
},
|
||||||
|
goTo(page) {
|
||||||
|
this.page = page;
|
||||||
|
|
||||||
|
this.changeUrl();
|
||||||
|
},
|
||||||
|
changeSort() {
|
||||||
|
const [sort,order] = this.sortOrder.split('-');
|
||||||
|
this.sort = sort;
|
||||||
|
this.order = order;
|
||||||
|
this.page = 1;
|
||||||
|
|
||||||
|
this.changeUrl();
|
||||||
|
},
|
||||||
|
changeFilter() {
|
||||||
|
this.page = 1;
|
||||||
|
|
||||||
|
this.changeUrl();
|
||||||
|
},
|
||||||
|
showMoreFilters() {
|
||||||
|
this.moreFilters = !this.moreFilters;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).mount('#collection-publique');
|
||||||
|
}
|
42
javascripts/conctact.js
Normal file
42
javascripts/conctact.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
if ( typeof contactMethod !== 'undefined' && contactMethod === 'smtp' ) {
|
||||||
|
Vue.createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
email: '',
|
||||||
|
name: '',
|
||||||
|
message: '',
|
||||||
|
captcha: '',
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
send(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if ( this.loading ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
const {
|
||||||
|
email,
|
||||||
|
message,
|
||||||
|
name,
|
||||||
|
captcha,
|
||||||
|
} = this;
|
||||||
|
|
||||||
|
axios.post('/api/v1/contact', {email, name, message, captcha})
|
||||||
|
.then( () => {
|
||||||
|
showToastr("Message correctement envoyé", true);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
showToastr(err.response?.data?.message || "Impossible d'envoyer votre message", false);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).mount('#contact');
|
||||||
|
}
|
|
@ -1,8 +1,13 @@
|
||||||
/**
|
const {
|
||||||
|
protocol,
|
||||||
|
host
|
||||||
|
} = window.location;
|
||||||
|
|
||||||
|
/**
|
||||||
* Fonction permettant d'afficher un message dans un toastr
|
* Fonction permettant d'afficher un message dans un toastr
|
||||||
* @param {String} message
|
* @param {String} message
|
||||||
*/
|
*/
|
||||||
function showToastr(message, success = false) {
|
function showToastr(message, success = false) {
|
||||||
let x = document.getElementById("toastr");
|
let x = document.getElementById("toastr");
|
||||||
if ( message ) {
|
if ( message ) {
|
||||||
x.getElementsByTagName("SPAN")[0].innerHTML = message;
|
x.getElementsByTagName("SPAN")[0].innerHTML = message;
|
26
javascripts/mon-compte/index.js
Normal file
26
javascripts/mon-compte/index.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
if ( typeof email !== 'undefined' && typeof username !== 'undefined' ) {
|
||||||
|
Vue.createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
email,
|
||||||
|
username,
|
||||||
|
oldPassword: '',
|
||||||
|
password: '',
|
||||||
|
passwordConfirm: '',
|
||||||
|
loading: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async updateProfil(event) {
|
||||||
|
// try {
|
||||||
|
// if ( this.password !== this.passwordConfirm ) {
|
||||||
|
// throw "La confirnation du mot de passe ne correspond pas";
|
||||||
|
// }
|
||||||
|
// } catch(err) {
|
||||||
|
// event.preventDefault();
|
||||||
|
// showToastr(err);
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}).mount('#mon-compte');
|
||||||
|
}
|
158
javascripts/mon-compte/ma-collection/details.js
Normal file
158
javascripts/mon-compte/ma-collection/details.js
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
if ( typeof item !== 'undefined' ) {
|
||||||
|
Vue.createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
item,
|
||||||
|
tracklist: [],
|
||||||
|
identifiers: [],
|
||||||
|
modalIsVisible: false,
|
||||||
|
identifiersMode: 'preview',
|
||||||
|
identifiersPreviewLength: 16,
|
||||||
|
preview: null,
|
||||||
|
index: null,
|
||||||
|
showModalDelete: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.setTrackList();
|
||||||
|
this.setIdentifiers();
|
||||||
|
|
||||||
|
window.addEventListener("keydown", this.changeImage);
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
window.removeEventListener('keydown', this.changeImage);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setIdentifiers() {
|
||||||
|
this.identifiers = [];
|
||||||
|
|
||||||
|
let max = this.identifiersMode == 'preview' && this.item.identifiers.length > this.identifiersPreviewLength ? this.identifiersPreviewLength : this.item.identifiers.length;
|
||||||
|
|
||||||
|
for ( let i = 0 ; i < max ; i += 1 ) {
|
||||||
|
this.identifiers.push(this.item.identifiers[i]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setTrackList() {
|
||||||
|
let subTrack = {
|
||||||
|
type: null,
|
||||||
|
title: null,
|
||||||
|
tracks: [],
|
||||||
|
};
|
||||||
|
for (let i = 0 ; i < this.item.tracklist.length ; i += 1 ) {
|
||||||
|
const {
|
||||||
|
type_,
|
||||||
|
title,
|
||||||
|
position,
|
||||||
|
duration,
|
||||||
|
extraartists,
|
||||||
|
} = this.item.tracklist[i];
|
||||||
|
|
||||||
|
if ( type_ === 'heading' ) {
|
||||||
|
if ( subTrack.type ) {
|
||||||
|
this.tracklist.push(subTrack);
|
||||||
|
subTrack = {
|
||||||
|
type: null,
|
||||||
|
title: null,
|
||||||
|
tracks: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
subTrack.type = type_;
|
||||||
|
subTrack.title = title;
|
||||||
|
} else {
|
||||||
|
subTrack.tracks.push({
|
||||||
|
title,
|
||||||
|
position,
|
||||||
|
duration,
|
||||||
|
extraartists
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tracklist.push(subTrack);
|
||||||
|
},
|
||||||
|
setImage() {
|
||||||
|
this.preview = this.item.images[this.index].uri;
|
||||||
|
},
|
||||||
|
showGallery(event) {
|
||||||
|
const item = event.target.tagName === 'IMG' ? event.target.parentElement : event.target;
|
||||||
|
|
||||||
|
const {
|
||||||
|
index,
|
||||||
|
} = item.dataset;
|
||||||
|
|
||||||
|
this.index = Number(index);
|
||||||
|
this.modalIsVisible = true;
|
||||||
|
|
||||||
|
this.setImage();
|
||||||
|
},
|
||||||
|
toggleModal() {
|
||||||
|
this.modalIsVisible = !this.modalIsVisible;
|
||||||
|
},
|
||||||
|
previous() {
|
||||||
|
this.index = this.index > 0 ? this.index - 1 : this.item.images.length -1;
|
||||||
|
this.setImage();
|
||||||
|
},
|
||||||
|
next() {
|
||||||
|
this.index = (this.index +1) === this.item.images.length ? 0 : this.index + 1;
|
||||||
|
this.setImage();
|
||||||
|
},
|
||||||
|
changeImage(event) {
|
||||||
|
const direction = event.code;
|
||||||
|
|
||||||
|
if ( this.modalIsVisible && ['ArrowRight', 'ArrowLeft', 'Escape'].indexOf(direction) !== -1 ) {
|
||||||
|
switch (direction) {
|
||||||
|
case 'ArrowRight':
|
||||||
|
return this.next();
|
||||||
|
case 'ArrowLeft':
|
||||||
|
return this.previous();
|
||||||
|
default:
|
||||||
|
this.modalIsVisible = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showAllIdentifiers() {
|
||||||
|
this.identifiersMode = 'all';
|
||||||
|
this.setIdentifiers();
|
||||||
|
},
|
||||||
|
showLessIdentifiers() {
|
||||||
|
this.identifiersMode = 'preview';
|
||||||
|
this.setIdentifiers();
|
||||||
|
|
||||||
|
document.querySelector('#identifiers').scrollIntoView({ behavior: 'smooth' });
|
||||||
|
},
|
||||||
|
showConfirmDelete() {
|
||||||
|
this.toggleModal();
|
||||||
|
},
|
||||||
|
toggleModal() {
|
||||||
|
this.showModalDelete = !this.showModalDelete;
|
||||||
|
},
|
||||||
|
updateItem() {
|
||||||
|
showToastr("Mise à jour en cours…", true);
|
||||||
|
axios.patch(`/api/v1/albums/${this.item._id}`)
|
||||||
|
.then( (res) => {
|
||||||
|
showToastr("Mise à jour réalisée avec succès", true);
|
||||||
|
this.item = res.data;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
showToastr(err.response?.data?.message || "Impossible de mettre à jour cet album", false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteItem() {
|
||||||
|
axios.delete(`/api/v1/albums/${this.item._id}`)
|
||||||
|
.then( () => {
|
||||||
|
window.location.href = "/ma-collection";
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
showToastr(err.response?.data?.message || "Impossible de supprimer cet album");
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.toggleModal();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
goToArtist() {
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).mount('#ma-collection-details');
|
||||||
|
}
|
18
javascripts/mon-compte/ma-collection/exporter.js
Normal file
18
javascripts/mon-compte/ma-collection/exporter.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
Vue.createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
format: 'xml',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
exportCollection(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
window.open(`/api/v1/albums?exportFormat=${this.format}`, '_blank');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}).mount('#exporter');
|
178
javascripts/mon-compte/ma-collection/index.js
Normal file
178
javascripts/mon-compte/ma-collection/index.js
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
if ( typeof isPublicCollection !== 'undefined' ) {
|
||||||
|
Vue.createApp({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
moreFilters: false,
|
||||||
|
items: [],
|
||||||
|
total: 0,
|
||||||
|
page: 1,
|
||||||
|
totalPages: 1,
|
||||||
|
limit: 16,
|
||||||
|
artist: '',
|
||||||
|
format: '',
|
||||||
|
year: '',
|
||||||
|
genre: '',
|
||||||
|
style: '',
|
||||||
|
sortOrder: 'artists_sort-asc',
|
||||||
|
sort: 'artists_sort',
|
||||||
|
order: 'asc',
|
||||||
|
itemId: null,
|
||||||
|
showModalDelete: false,
|
||||||
|
showModalShare: false,
|
||||||
|
shareLink: `${protocol}//${host}/collection/<%= user._id %>`,
|
||||||
|
isPublicCollection,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetch();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetch() {
|
||||||
|
this.loading = true;
|
||||||
|
this.total = 0;
|
||||||
|
|
||||||
|
const queryString = window.location.search;
|
||||||
|
const urlParams = new URLSearchParams(queryString);
|
||||||
|
const entries = urlParams.entries();
|
||||||
|
|
||||||
|
for(const entry of entries) {
|
||||||
|
switch(entry[0]) {
|
||||||
|
case 'artists_sort':
|
||||||
|
this.artist = entry[1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this[entry[0]] = entry[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = `/api/v1/albums?page=${this.page}&limit=${this.limit}&sort=${this.sort}&order=${this.order}`;
|
||||||
|
if ( this.artist ) {
|
||||||
|
url += `&artists_sort=${this.artist.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.format ) {
|
||||||
|
url += `&format=${this.format.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.year ) {
|
||||||
|
url += `&year=${this.year}`;
|
||||||
|
}
|
||||||
|
if ( this.genre ) {
|
||||||
|
url += `&genre=${this.genre.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.style ) {
|
||||||
|
url += `&style=${this.style.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.get(url)
|
||||||
|
.then( response => {
|
||||||
|
this.items = response.data.rows;
|
||||||
|
this.total = response.data.count || 0;
|
||||||
|
this.totalPages = parseInt(response.data.count / this.limit) + (response.data.count % this.limit > 0 ? 1 : 0);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
showToastr(err.response?.data?.message || "Impossible de charger votre collection");
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
changeUrl() {
|
||||||
|
let url = `?page=${this.page}&limit=${this.limit}&sort=${this.sort}&order=${this.order}`;
|
||||||
|
if ( this.artist ) {
|
||||||
|
url += `&artists_sort=${this.artist.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.format ) {
|
||||||
|
url += `&format=${this.format.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.year ) {
|
||||||
|
url += `&year=${this.year}`;
|
||||||
|
}
|
||||||
|
if ( this.genre ) {
|
||||||
|
url += `&genre=${this.genre.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
if ( this.style ) {
|
||||||
|
url += `&style=${this.style.replace('&', '%26')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
location.href = url;
|
||||||
|
},
|
||||||
|
next(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.page += 1;
|
||||||
|
|
||||||
|
this.changeUrl();
|
||||||
|
},
|
||||||
|
previous(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.page -= 1;
|
||||||
|
|
||||||
|
this.changeUrl();
|
||||||
|
},
|
||||||
|
goTo(page) {
|
||||||
|
this.page = page;
|
||||||
|
|
||||||
|
this.changeUrl();
|
||||||
|
},
|
||||||
|
changeSort() {
|
||||||
|
const [sort,order] = this.sortOrder.split('-');
|
||||||
|
this.sort = sort;
|
||||||
|
this.order = order;
|
||||||
|
this.page = 1;
|
||||||
|
|
||||||
|
this.changeUrl();
|
||||||
|
},
|
||||||
|
changeFilter() {
|
||||||
|
this.page = 1;
|
||||||
|
|
||||||
|
this.changeUrl();
|
||||||
|
},
|
||||||
|
showMoreFilters() {
|
||||||
|
this.moreFilters = !this.moreFilters;
|
||||||
|
},
|
||||||
|
toggleModal() {
|
||||||
|
this.showModalDelete = !this.showModalDelete;
|
||||||
|
},
|
||||||
|
toggleModalShare() {
|
||||||
|
this.showModalShare = !this.showModalShare;
|
||||||
|
},
|
||||||
|
showConfirmDelete(itemId) {
|
||||||
|
this.itemId = itemId;
|
||||||
|
this.toggleModal();
|
||||||
|
},
|
||||||
|
deleteItem() {
|
||||||
|
axios.delete(`/api/v1/albums/${this.itemId}`)
|
||||||
|
.then( () => {
|
||||||
|
this.fetch();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
showToastr(err.response?.data?.message || "Impossible de supprimer cet album");
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.toggleModal();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
shareCollection() {
|
||||||
|
axios.patch(`/api/v1/me`, {
|
||||||
|
isPublicCollection: !this.isPublicCollection,
|
||||||
|
})
|
||||||
|
.then( (res) => {
|
||||||
|
this.isPublicCollection = res.data.isPublicCollection;
|
||||||
|
|
||||||
|
if ( this.isPublicCollection ) {
|
||||||
|
showToastr("Votre collection est désormais publique", true);
|
||||||
|
} else {
|
||||||
|
showToastr("Votre collection n'est plus partagée", true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
showToastr(err.response?.data?.message || "Impossible de supprimer cet album");
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.toggleModalShare();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}).mount('#ma-collection');
|
||||||
|
}
|
11
package.json
11
package.json
|
@ -4,9 +4,10 @@
|
||||||
"description": "Simple application to manage your CD/Vinyl collection",
|
"description": "Simple application to manage your CD/Vinyl collection",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node ./dist/bin/www",
|
"start": "node ./dist/bin/www",
|
||||||
"run:all": "npm-run-all build sass start",
|
"run:all": "npm-run-all build sass uglify start",
|
||||||
"watch": "nodemon -e js,scss",
|
"watch": "nodemon -e js,scss",
|
||||||
"sass": "npx sass sass/index.scss public/css/main.css -s compressed --color",
|
"sass": "npx sass sass/index.scss public/css/main.css -s compressed --color",
|
||||||
|
"uglify": "npx gulp",
|
||||||
"prebuild": "rimraf dist",
|
"prebuild": "rimraf dist",
|
||||||
"build": "babel ./src --out-dir dist --copy-files",
|
"build": "babel ./src --out-dir dist --copy-files",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
|
@ -55,6 +56,11 @@
|
||||||
"excel4node": "^1.7.2",
|
"excel4node": "^1.7.2",
|
||||||
"express": "^4.17.2",
|
"express": "^4.17.2",
|
||||||
"express-session": "^1.17.2",
|
"express-session": "^1.17.2",
|
||||||
|
"gulp": "^4.0.2",
|
||||||
|
"gulp-babel": "^8.0.0",
|
||||||
|
"gulp-concat": "^2.6.1",
|
||||||
|
"gulp-sourcemaps": "^3.0.0",
|
||||||
|
"gulp-uglify": "^3.0.2",
|
||||||
"joi": "^17.6.0",
|
"joi": "^17.6.0",
|
||||||
"knacss": "^8.0.4",
|
"knacss": "^8.0.4",
|
||||||
"mongoose": "^6.2.1",
|
"mongoose": "^6.2.1",
|
||||||
|
@ -75,7 +81,8 @@
|
||||||
"exec": "yarn run:all",
|
"exec": "yarn run:all",
|
||||||
"watch": [
|
"watch": [
|
||||||
"src/*",
|
"src/*",
|
||||||
"sass/*"
|
"sass/*",
|
||||||
|
"javascripts/*"
|
||||||
],
|
],
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"**/__tests__/**",
|
"**/__tests__/**",
|
||||||
|
|
|
@ -75,14 +75,6 @@ app.set("views", path.join(__dirname, "../views"));
|
||||||
app.set("view engine", "ejs");
|
app.set("view engine", "ejs");
|
||||||
|
|
||||||
app.use(express.static(path.join(__dirname, "../public")));
|
app.use(express.static(path.join(__dirname, "../public")));
|
||||||
app.use(
|
|
||||||
"/libs/vue",
|
|
||||||
express.static(path.join(__dirname, "../node_modules/vue/dist"))
|
|
||||||
);
|
|
||||||
app.use(
|
|
||||||
"/libs/axios",
|
|
||||||
express.static(path.join(__dirname, "../node_modules/axios/dist"))
|
|
||||||
);
|
|
||||||
|
|
||||||
app.use("/", indexRouter);
|
app.use("/", indexRouter);
|
||||||
app.use("/mon-compte", monCompteRouter);
|
app.use("/mon-compte", monCompteRouter);
|
||||||
|
|
|
@ -16,9 +16,8 @@
|
||||||
|
|
||||||
<link href="/css/main.css" rel="stylesheet" />
|
<link href="/css/main.css" rel="stylesheet" />
|
||||||
|
|
||||||
<script src="/libs/axios/axios.min.js"></script>
|
<script defer src="/js/libs.js"></script>
|
||||||
<script src="/libs/vue/vue.global.prod.js"></script>
|
<script defer src="/js/main.js"></script>
|
||||||
<script src="/js/main.js"></script>
|
|
||||||
|
|
||||||
<% if ( config.matomoUrl ) { %>
|
<% if ( config.matomoUrl ) { %>
|
||||||
<!-- Matomo -->
|
<!-- Matomo -->
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<main class="layout-maxed ajouter-un-album" id="app">
|
<main class="layout-maxed ajouter-un-album" id="ajouter-album">
|
||||||
<h1>Ajouter un album</h1>
|
<h1>Ajouter un album</h1>
|
||||||
<form @submit="search">
|
<form @submit="search">
|
||||||
<div class="grid sm:grid-cols-2">
|
<div class="grid sm:grid-cols-2">
|
||||||
|
@ -169,178 +169,4 @@
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
|
||||||
Vue.createApp({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
q: '',
|
|
||||||
year: '',
|
|
||||||
country: '',
|
|
||||||
format: '',
|
|
||||||
loading: false,
|
|
||||||
items: [],
|
|
||||||
details: {},
|
|
||||||
modalIsVisible: false,
|
|
||||||
formats: [
|
|
||||||
'Vinyl',
|
|
||||||
'Acetate',
|
|
||||||
'Flexi-disc',
|
|
||||||
'Lathe Cut',
|
|
||||||
'Mighty Tiny',
|
|
||||||
'Shellac',
|
|
||||||
'Sopic',
|
|
||||||
'Pathé Disc',
|
|
||||||
'Edison Disc',
|
|
||||||
'Cylinder',
|
|
||||||
'CD',
|
|
||||||
'CDr',
|
|
||||||
'CDV',
|
|
||||||
'DVD',
|
|
||||||
'DVDr',
|
|
||||||
'HD DVD',
|
|
||||||
'HD DVD-R',
|
|
||||||
'Blu-ray',
|
|
||||||
'Blu-ray-R',
|
|
||||||
'Ultra HD Blu-ray',
|
|
||||||
'SACD',
|
|
||||||
'4-Track Cartridge',
|
|
||||||
'8-Track Cartridge',
|
|
||||||
'Cassette',
|
|
||||||
'DC-International',
|
|
||||||
'Elcaset',
|
|
||||||
'PlayTape',
|
|
||||||
'RCA Tape Cartridge',
|
|
||||||
'DAT',
|
|
||||||
'DCC',
|
|
||||||
'Microcassette',
|
|
||||||
'NT Cassette',
|
|
||||||
'Pocket Rocker',
|
|
||||||
'Revere Magnetic Stereo Tape Ca',
|
|
||||||
'Tefifon',
|
|
||||||
'Reel-To-Reel',
|
|
||||||
'Sabamobil',
|
|
||||||
'Betacam',
|
|
||||||
'Betacam SP',
|
|
||||||
'Betamax',
|
|
||||||
'Cartrivision',
|
|
||||||
'MiniDV',
|
|
||||||
'Super VHS',
|
|
||||||
'U-matic',
|
|
||||||
'VHS',
|
|
||||||
'Video 2000',
|
|
||||||
'Video8',
|
|
||||||
'Film Reel',
|
|
||||||
'HitClips',
|
|
||||||
'Laserdisc',
|
|
||||||
'SelectaVision',
|
|
||||||
'VHD',
|
|
||||||
'Wire Recording',
|
|
||||||
'Minidisc',
|
|
||||||
'MVD',
|
|
||||||
'UMD',
|
|
||||||
'Floppy Disk',
|
|
||||||
'File',
|
|
||||||
'Memory Stick',
|
|
||||||
'Hybrid',
|
|
||||||
'All Media',
|
|
||||||
'Box Set',
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
search(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
if ( this.loading ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loading = true;
|
|
||||||
let url = `/api/v1/search?q=${this.q}`;
|
|
||||||
|
|
||||||
if ( this.year ) {
|
|
||||||
url += `&year=${this.year}`;
|
|
||||||
}
|
|
||||||
if ( this.country ) {
|
|
||||||
url += `&country=${this.country}`;
|
|
||||||
}
|
|
||||||
if ( this.format ) {
|
|
||||||
url += `&format=${this.format}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
axios.get(url)
|
|
||||||
.then( response => {
|
|
||||||
const {
|
|
||||||
results,
|
|
||||||
} = response.data;
|
|
||||||
let items = [];
|
|
||||||
|
|
||||||
for (let i = 0 ; i < results.length ; i += 1 ) {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
title,
|
|
||||||
thumb,
|
|
||||||
year,
|
|
||||||
country,
|
|
||||||
format,
|
|
||||||
genre,
|
|
||||||
style,
|
|
||||||
} = results[i];
|
|
||||||
items.push({
|
|
||||||
id,
|
|
||||||
title,
|
|
||||||
thumb,
|
|
||||||
year,
|
|
||||||
country,
|
|
||||||
format,
|
|
||||||
genre,
|
|
||||||
style,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.items = items;
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
showToastr(err.response?.data?.message || "Aucun résultat trouvé :/");
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
toggleModal() {
|
|
||||||
this.modalIsVisible = !this.modalIsVisible;
|
|
||||||
},
|
|
||||||
loadDetails(discogsId) {
|
|
||||||
axios.get(`/api/v1/search/${discogsId}`)
|
|
||||||
.then( response => {
|
|
||||||
const {
|
|
||||||
data,
|
|
||||||
} = response;
|
|
||||||
|
|
||||||
this.details = data;
|
|
||||||
this.toggleModal();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
showToastr(err.response?.data?.message || "Impossible de charger les détails de cet album");
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
add() {
|
|
||||||
axios.post('/api/v1/albums', this.details)
|
|
||||||
.then(() => {
|
|
||||||
window.location.href = '/ma-collection';
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
showToastr(err.response?.data?.message || "Impossible d'ajouter cet album pour le moment…");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
orderedItems(items) {
|
|
||||||
return items.sort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).mount('#app');
|
|
||||||
</script>
|
|
|
@ -1,4 +1,4 @@
|
||||||
<main class="layout-maxed collection" id="app">
|
<main class="layout-maxed collection" id="collection-publique">
|
||||||
<h1>
|
<h1>
|
||||||
Collection de <%= page.username %>
|
Collection de <%= page.username %>
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -146,140 +146,5 @@
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const {
|
const userId = "<%= params.userId %>";
|
||||||
protocol,
|
|
||||||
host
|
|
||||||
} = window.location;
|
|
||||||
|
|
||||||
Vue.createApp({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loading: false,
|
|
||||||
moreFilters: false,
|
|
||||||
items: [],
|
|
||||||
total: 0,
|
|
||||||
page: 1,
|
|
||||||
totalPages: 1,
|
|
||||||
limit: 16,
|
|
||||||
artist: '',
|
|
||||||
format: '',
|
|
||||||
year: '',
|
|
||||||
genre: '',
|
|
||||||
style: '',
|
|
||||||
sortOrder: 'artists_sort-asc',
|
|
||||||
sort: 'artists_sort',
|
|
||||||
order: 'asc',
|
|
||||||
userId: "<%= params.userId %>",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.fetch();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
fetch() {
|
|
||||||
this.loading = true;
|
|
||||||
this.total = 0;
|
|
||||||
|
|
||||||
const queryString = window.location.search;
|
|
||||||
const urlParams = new URLSearchParams(queryString);
|
|
||||||
const entries = urlParams.entries();
|
|
||||||
|
|
||||||
for(const entry of entries) {
|
|
||||||
switch(entry[0]) {
|
|
||||||
case 'artists_sort':
|
|
||||||
this.artist = entry[1];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this[entry[0]] = entry[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let url = `/api/v1/albums?userId=${this.userId}&page=${this.page}&limit=${this.limit}&sort=${this.sort}&order=${this.order}`;
|
|
||||||
if ( this.artist ) {
|
|
||||||
url += `&artists_sort=${this.artist.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.format ) {
|
|
||||||
url += `&format=${this.format.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.year ) {
|
|
||||||
url += `&year=${this.year}`;
|
|
||||||
}
|
|
||||||
if ( this.genre ) {
|
|
||||||
url += `&genre=${this.genre.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.style ) {
|
|
||||||
url += `&style=${this.style.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
axios.get(url)
|
|
||||||
.then( response => {
|
|
||||||
this.items = response.data.rows;
|
|
||||||
this.total = response.data.count || 0;
|
|
||||||
this.totalPages = parseInt(response.data.count / this.limit) + (response.data.count % this.limit > 0 ? 1 : 0);
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
showToastr(err.response?.data?.message || "Impossible de charger cette collection");
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
changeUrl() {
|
|
||||||
let url = `?page=${this.page}&limit=${this.limit}&sort=${this.sort}&order=${this.order}`;
|
|
||||||
if ( this.artist ) {
|
|
||||||
url += `&artists_sort=${this.artist.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.format ) {
|
|
||||||
url += `&format=${this.format.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.year ) {
|
|
||||||
url += `&year=${this.year}`;
|
|
||||||
}
|
|
||||||
if ( this.genre ) {
|
|
||||||
url += `&genre=${this.genre.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.style ) {
|
|
||||||
url += `&style=${this.style.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
location.href = url;
|
|
||||||
},
|
|
||||||
next(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
this.page += 1;
|
|
||||||
|
|
||||||
this.changeUrl();
|
|
||||||
},
|
|
||||||
previous(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
this.page -= 1;
|
|
||||||
|
|
||||||
this.changeUrl();
|
|
||||||
},
|
|
||||||
goTo(page) {
|
|
||||||
this.page = page;
|
|
||||||
|
|
||||||
this.changeUrl();
|
|
||||||
},
|
|
||||||
changeSort() {
|
|
||||||
const [sort,order] = this.sortOrder.split('-');
|
|
||||||
this.sort = sort;
|
|
||||||
this.order = order;
|
|
||||||
this.page = 1;
|
|
||||||
|
|
||||||
this.changeUrl();
|
|
||||||
},
|
|
||||||
changeFilter() {
|
|
||||||
this.page = 1;
|
|
||||||
|
|
||||||
this.changeUrl();
|
|
||||||
},
|
|
||||||
showMoreFilters() {
|
|
||||||
this.moreFilters = !this.moreFilters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).mount('#app');
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<main class="layout-maxed collection" id="app">
|
<main class="layout-maxed collection" id="mon-compte">
|
||||||
<h1>
|
<h1>
|
||||||
Mon compte
|
Mon compte
|
||||||
</h1>
|
</h1>
|
||||||
|
@ -72,28 +72,6 @@
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
Vue.createApp({
|
const email = '<%= user.email %>';
|
||||||
data() {
|
const username = '<%= user.username %>';
|
||||||
return {
|
|
||||||
email: '<%= user.email %>',
|
|
||||||
username: '<%= user.username %>',
|
|
||||||
oldPassword: '',
|
|
||||||
password: '',
|
|
||||||
passwordConfirm: '',
|
|
||||||
loading: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async updateProfil(event) {
|
|
||||||
// try {
|
|
||||||
// if ( this.password !== this.passwordConfirm ) {
|
|
||||||
// throw "La confirnation du mot de passe ne correspond pas";
|
|
||||||
// }
|
|
||||||
// } catch(err) {
|
|
||||||
// event.preventDefault();
|
|
||||||
// showToastr(err);
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}).mount('#app');
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<main class="layout-maxed ma-collection-details" id="app" v-cloak @keyup="changeImage">
|
<main class="layout-maxed ma-collection-details" id="ma-collection-details" v-cloak @keyup="changeImage">
|
||||||
|
|
||||||
<h1>
|
<h1>
|
||||||
<a :href="`/ma-collection?page=1&limit=16&sort=year&order=asc&artists_sort=${item.artists_sort}`">{{item.artists_sort}}</a> - {{item.title}}
|
<a :href="`/ma-collection?page=1&limit=16&sort=year&order=asc&artists_sort=${item.artists_sort}`">{{item.artists_sort}}</a> - {{item.title}}
|
||||||
|
@ -176,160 +176,5 @@
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
Vue.createApp({
|
const item = <%- JSON.stringify(page.item) %>;
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
item: <%- JSON.stringify(page.item) %>,
|
|
||||||
tracklist: [],
|
|
||||||
identifiers: [],
|
|
||||||
modalIsVisible: false,
|
|
||||||
identifiersMode: 'preview',
|
|
||||||
identifiersPreviewLength: 16,
|
|
||||||
preview: null,
|
|
||||||
index: null,
|
|
||||||
showModalDelete: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.setTrackList();
|
|
||||||
this.setIdentifiers();
|
|
||||||
|
|
||||||
window.addEventListener("keydown", this.changeImage);
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
window.removeEventListener('keydown', this.changeImage);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
setIdentifiers() {
|
|
||||||
this.identifiers = [];
|
|
||||||
|
|
||||||
let max = this.identifiersMode == 'preview' && this.item.identifiers.length > this.identifiersPreviewLength ? this.identifiersPreviewLength : this.item.identifiers.length;
|
|
||||||
|
|
||||||
for ( let i = 0 ; i < max ; i += 1 ) {
|
|
||||||
this.identifiers.push(this.item.identifiers[i]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setTrackList() {
|
|
||||||
let subTrack = {
|
|
||||||
type: null,
|
|
||||||
title: null,
|
|
||||||
tracks: [],
|
|
||||||
};
|
|
||||||
for (let i = 0 ; i < this.item.tracklist.length ; i += 1 ) {
|
|
||||||
const {
|
|
||||||
type_,
|
|
||||||
title,
|
|
||||||
position,
|
|
||||||
duration,
|
|
||||||
extraartists,
|
|
||||||
} = this.item.tracklist[i];
|
|
||||||
|
|
||||||
if ( type_ === 'heading' ) {
|
|
||||||
if ( subTrack.type ) {
|
|
||||||
this.tracklist.push(subTrack);
|
|
||||||
subTrack = {
|
|
||||||
type: null,
|
|
||||||
title: null,
|
|
||||||
tracks: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
subTrack.type = type_;
|
|
||||||
subTrack.title = title;
|
|
||||||
} else {
|
|
||||||
subTrack.tracks.push({
|
|
||||||
title,
|
|
||||||
position,
|
|
||||||
duration,
|
|
||||||
extraartists
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.tracklist.push(subTrack);
|
|
||||||
},
|
|
||||||
setImage() {
|
|
||||||
this.preview = this.item.images[this.index].uri;
|
|
||||||
},
|
|
||||||
showGallery(event) {
|
|
||||||
const item = event.target.tagName === 'IMG' ? event.target.parentElement : event.target;
|
|
||||||
|
|
||||||
const {
|
|
||||||
index,
|
|
||||||
} = item.dataset;
|
|
||||||
|
|
||||||
this.index = Number(index);
|
|
||||||
this.modalIsVisible = true;
|
|
||||||
|
|
||||||
this.setImage();
|
|
||||||
},
|
|
||||||
toggleModal() {
|
|
||||||
this.modalIsVisible = !this.modalIsVisible;
|
|
||||||
},
|
|
||||||
previous() {
|
|
||||||
this.index = this.index > 0 ? this.index - 1 : this.item.images.length -1;
|
|
||||||
this.setImage();
|
|
||||||
},
|
|
||||||
next() {
|
|
||||||
this.index = (this.index +1) === this.item.images.length ? 0 : this.index + 1;
|
|
||||||
this.setImage();
|
|
||||||
},
|
|
||||||
changeImage(event) {
|
|
||||||
const direction = event.code;
|
|
||||||
|
|
||||||
if ( this.modalIsVisible && ['ArrowRight', 'ArrowLeft', 'Escape'].indexOf(direction) !== -1 ) {
|
|
||||||
switch (direction) {
|
|
||||||
case 'ArrowRight':
|
|
||||||
return this.next();
|
|
||||||
case 'ArrowLeft':
|
|
||||||
return this.previous();
|
|
||||||
default:
|
|
||||||
this.modalIsVisible = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showAllIdentifiers() {
|
|
||||||
this.identifiersMode = 'all';
|
|
||||||
this.setIdentifiers();
|
|
||||||
},
|
|
||||||
showLessIdentifiers() {
|
|
||||||
this.identifiersMode = 'preview';
|
|
||||||
this.setIdentifiers();
|
|
||||||
|
|
||||||
document.querySelector('#identifiers').scrollIntoView({ behavior: 'smooth' });
|
|
||||||
},
|
|
||||||
showConfirmDelete() {
|
|
||||||
this.toggleModal();
|
|
||||||
},
|
|
||||||
toggleModal() {
|
|
||||||
this.showModalDelete = !this.showModalDelete;
|
|
||||||
},
|
|
||||||
updateItem() {
|
|
||||||
showToastr("Mise à jour en cours…", true);
|
|
||||||
axios.patch(`/api/v1/albums/${this.item._id}`)
|
|
||||||
.then( (res) => {
|
|
||||||
showToastr("Mise à jour réalisée avec succès", true);
|
|
||||||
this.item = res.data;
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
showToastr(err.response?.data?.message || "Impossible de mettre à jour cet album", false);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deleteItem() {
|
|
||||||
axios.delete(`/api/v1/albums/${this.item._id}`)
|
|
||||||
.then( () => {
|
|
||||||
window.location.href = "/ma-collection";
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
showToastr(err.response?.data?.message || "Impossible de supprimer cet album");
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.toggleModal();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
goToArtist() {
|
|
||||||
return "";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).mount('#app');
|
|
||||||
</script>
|
</script>
|
|
@ -1,4 +1,4 @@
|
||||||
<main class="layout-maxed" id="app">
|
<main class="layout-maxed" id="exporter">
|
||||||
<h1>Exporter ma collection</h1>
|
<h1>Exporter ma collection</h1>
|
||||||
<p>
|
<p>
|
||||||
Les formats CSV et Excel sont facilement lisiblent par un humain. Dans ces 2 formats vous trouverez seulement les informations principales de vos albums, à savoir :
|
Les formats CSV et Excel sont facilement lisiblent par un humain. Dans ces 2 formats vous trouverez seulement les informations principales de vos albums, à savoir :
|
||||||
|
@ -44,25 +44,4 @@
|
||||||
Exporter
|
Exporter
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
|
||||||
Vue.createApp({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
format: 'xml',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
exportCollection(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
window.open(`/api/v1/albums?exportFormat=${this.format}`, '_blank');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}).mount('#app');
|
|
||||||
</script>
|
|
|
@ -1,4 +1,4 @@
|
||||||
<main class="layout-maxed collection" id="app">
|
<main class="layout-maxed collection" id="ma-collection">
|
||||||
<h1>
|
<h1>
|
||||||
Ma collection
|
Ma collection
|
||||||
<i class="icon-share" @click="toggleModalShare" aria-label="Partager ma collection" title="Votre collection sera visible en lecture aux personnes ayant le lien de partage"></i>
|
<i class="icon-share" @click="toggleModalShare" aria-label="Partager ma collection" title="Votre collection sera visible en lecture aux personnes ayant le lien de partage"></i>
|
||||||
|
@ -196,185 +196,5 @@
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const {
|
const isPublicCollection = <%= user.isPublicCollection ? 'true' : 'false' %>;
|
||||||
protocol,
|
</script>
|
||||||
host
|
|
||||||
} = window.location;
|
|
||||||
|
|
||||||
Vue.createApp({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loading: false,
|
|
||||||
moreFilters: false,
|
|
||||||
items: [],
|
|
||||||
total: 0,
|
|
||||||
page: 1,
|
|
||||||
totalPages: 1,
|
|
||||||
limit: 16,
|
|
||||||
artist: '',
|
|
||||||
format: '',
|
|
||||||
year: '',
|
|
||||||
genre: '',
|
|
||||||
style: '',
|
|
||||||
sortOrder: 'artists_sort-asc',
|
|
||||||
sort: 'artists_sort',
|
|
||||||
order: 'asc',
|
|
||||||
itemId: null,
|
|
||||||
showModalDelete: false,
|
|
||||||
showModalShare: false,
|
|
||||||
shareLink: `${protocol}//${host}/collection/<%= user._id %>`,
|
|
||||||
isPublicCollection: <%= user.isPublicCollection ? 'true' : 'false' %>,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.fetch();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
fetch() {
|
|
||||||
this.loading = true;
|
|
||||||
this.total = 0;
|
|
||||||
|
|
||||||
const queryString = window.location.search;
|
|
||||||
const urlParams = new URLSearchParams(queryString);
|
|
||||||
const entries = urlParams.entries();
|
|
||||||
|
|
||||||
for(const entry of entries) {
|
|
||||||
switch(entry[0]) {
|
|
||||||
case 'artists_sort':
|
|
||||||
this.artist = entry[1];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this[entry[0]] = entry[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let url = `/api/v1/albums?page=${this.page}&limit=${this.limit}&sort=${this.sort}&order=${this.order}`;
|
|
||||||
if ( this.artist ) {
|
|
||||||
url += `&artists_sort=${this.artist.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.format ) {
|
|
||||||
url += `&format=${this.format.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.year ) {
|
|
||||||
url += `&year=${this.year}`;
|
|
||||||
}
|
|
||||||
if ( this.genre ) {
|
|
||||||
url += `&genre=${this.genre.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.style ) {
|
|
||||||
url += `&style=${this.style.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
axios.get(url)
|
|
||||||
.then( response => {
|
|
||||||
this.items = response.data.rows;
|
|
||||||
this.total = response.data.count || 0;
|
|
||||||
this.totalPages = parseInt(response.data.count / this.limit) + (response.data.count % this.limit > 0 ? 1 : 0);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
showToastr(err.response?.data?.message || "Impossible de charger votre collection");
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
changeUrl() {
|
|
||||||
let url = `?page=${this.page}&limit=${this.limit}&sort=${this.sort}&order=${this.order}`;
|
|
||||||
if ( this.artist ) {
|
|
||||||
url += `&artists_sort=${this.artist.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.format ) {
|
|
||||||
url += `&format=${this.format.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.year ) {
|
|
||||||
url += `&year=${this.year}`;
|
|
||||||
}
|
|
||||||
if ( this.genre ) {
|
|
||||||
url += `&genre=${this.genre.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
if ( this.style ) {
|
|
||||||
url += `&style=${this.style.replace('&', '%26')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
location.href = url;
|
|
||||||
},
|
|
||||||
next(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
this.page += 1;
|
|
||||||
|
|
||||||
this.changeUrl();
|
|
||||||
},
|
|
||||||
previous(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
this.page -= 1;
|
|
||||||
|
|
||||||
this.changeUrl();
|
|
||||||
},
|
|
||||||
goTo(page) {
|
|
||||||
this.page = page;
|
|
||||||
|
|
||||||
this.changeUrl();
|
|
||||||
},
|
|
||||||
changeSort() {
|
|
||||||
const [sort,order] = this.sortOrder.split('-');
|
|
||||||
this.sort = sort;
|
|
||||||
this.order = order;
|
|
||||||
this.page = 1;
|
|
||||||
|
|
||||||
this.changeUrl();
|
|
||||||
},
|
|
||||||
changeFilter() {
|
|
||||||
this.page = 1;
|
|
||||||
|
|
||||||
this.changeUrl();
|
|
||||||
},
|
|
||||||
showMoreFilters() {
|
|
||||||
this.moreFilters = !this.moreFilters;
|
|
||||||
},
|
|
||||||
toggleModal() {
|
|
||||||
this.showModalDelete = !this.showModalDelete;
|
|
||||||
},
|
|
||||||
toggleModalShare() {
|
|
||||||
this.showModalShare = !this.showModalShare;
|
|
||||||
},
|
|
||||||
showConfirmDelete(itemId) {
|
|
||||||
this.itemId = itemId;
|
|
||||||
this.toggleModal();
|
|
||||||
},
|
|
||||||
deleteItem() {
|
|
||||||
axios.delete(`/api/v1/albums/${this.itemId}`)
|
|
||||||
.then( () => {
|
|
||||||
this.fetch();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
showToastr(err.response?.data?.message || "Impossible de supprimer cet album");
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.toggleModal();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
shareCollection() {
|
|
||||||
axios.patch(`/api/v1/me`, {
|
|
||||||
isPublicCollection: !this.isPublicCollection,
|
|
||||||
})
|
|
||||||
.then( (res) => {
|
|
||||||
this.isPublicCollection = res.data.isPublicCollection;
|
|
||||||
|
|
||||||
if ( this.isPublicCollection ) {
|
|
||||||
showToastr("Votre collection est désormais publique", true);
|
|
||||||
} else {
|
|
||||||
showToastr("Votre collection n'est plus partagée", true);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
showToastr(err.response?.data?.message || "Impossible de supprimer cet album");
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.toggleModalShare();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}).mount('#app');
|
|
||||||
</script>
|
|
|
@ -1,4 +1,4 @@
|
||||||
<section class="box" id="app">
|
<section class="box" id="contact">
|
||||||
<h1>Nous contacter</h1>
|
<h1>Nous contacter</h1>
|
||||||
<form @submit="send" <% if (config.mailMethod === 'formspree' ) { %> id="contact" method="POST" action="https://formspree.io/f/<%= config.formspreeId %>" <% } %>>
|
<form @submit="send" <% if (config.mailMethod === 'formspree' ) { %> id="contact" method="POST" action="https://formspree.io/f/<%= config.formspreeId %>" <% } %>>
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-16">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-16">
|
||||||
|
@ -34,47 +34,6 @@
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<% if (config.mailMethod === 'smtp' ) { %>
|
<script>
|
||||||
<script>
|
const contactMethod = '<%= config.mailMethod %>';
|
||||||
Vue.createApp({
|
</script>
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
email: '',
|
|
||||||
name: '',
|
|
||||||
message: '',
|
|
||||||
captcha: '',
|
|
||||||
loading: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
send(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
if ( this.loading ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loading = true;
|
|
||||||
|
|
||||||
const {
|
|
||||||
email,
|
|
||||||
message,
|
|
||||||
name,
|
|
||||||
captcha,
|
|
||||||
} = this;
|
|
||||||
|
|
||||||
axios.post('/api/v1/contact', {email, name, message, captcha})
|
|
||||||
.then( () => {
|
|
||||||
showToastr("Message correctement envoyé", true);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
showToastr(err.response?.data?.message || "Impossible d'envoyer votre message", false);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.loading = false;
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}).mount('#app');
|
|
||||||
</script>
|
|
||||||
<% } %>
|
|
Loading…
Reference in a new issue