update (end of the main panel feature I think)
This commit is contained in:
parent
4791bd8037
commit
79a24f6ae7
15 changed files with 814 additions and 71 deletions
|
@ -15,6 +15,7 @@
|
|||
"vue-apitator": "^0.0.16",
|
||||
"vue-class-component": "^7.2.3",
|
||||
"vue-croppa": "^1.3.8",
|
||||
"vue-input-facade": "^1.3.1",
|
||||
"vue-property-decorator": "^8.4.2",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuetify": "^2.2.11",
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>Forum virtuel des associaitons</title>
|
||||
<title>Forum virtuel des associations</title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons"/>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<v-dialog
|
||||
v-model="enabled"
|
||||
max-width="500px">
|
||||
:max-width="modalSize">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
{{ caption }}
|
||||
|
@ -13,8 +13,8 @@
|
|||
v-model="plugin"
|
||||
:show-remove-button="false"
|
||||
canvas-color="white"
|
||||
:width="size"
|
||||
:height="size"
|
||||
:width="width"
|
||||
:height="height"
|
||||
prevent-white-space
|
||||
:placeholder-font-size="22"
|
||||
@file-size-exceed="handleFileSizeExceed"
|
||||
|
@ -22,27 +22,29 @@
|
|||
placeholder="Choisissez une image"
|
||||
></croppa>
|
||||
</v-layout>
|
||||
<v-layout justify-center wrap>
|
||||
<v-layout justify-center>
|
||||
<v-btn
|
||||
class="mr-2"
|
||||
dark
|
||||
outlined
|
||||
color="indigo"
|
||||
@click="rotate()">
|
||||
Tourner 90°
|
||||
<v-icon>rotate_right</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="mr-2"
|
||||
dark
|
||||
outlined
|
||||
color="indigo"
|
||||
@click="rotate(-1)">
|
||||
Tourner -90°
|
||||
<v-icon>rotate_left</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
dark
|
||||
outlined
|
||||
color="purple"
|
||||
@click="clear">
|
||||
Supprimer
|
||||
<v-icon>clear</v-icon>
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
</v-card-text>
|
||||
|
@ -72,14 +74,25 @@ export default {
|
|||
name: 'AvatarEditor',
|
||||
data: () => ({
|
||||
enabled: false,
|
||||
plugin: {},
|
||||
size: 400
|
||||
plugin: {}
|
||||
}),
|
||||
props: {
|
||||
caption: {
|
||||
type: String,
|
||||
default: 'Modifier votre logo'
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 400
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 400
|
||||
},
|
||||
modalSize: {
|
||||
type: Number,
|
||||
default: 500
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
|
@ -130,7 +143,6 @@ export default {
|
|||
}
|
||||
.canvas-container canvas {
|
||||
border: 1px solid #bdc3c7;
|
||||
border-radius: 50%;
|
||||
}
|
||||
@media screen and (max-width: 959px) {
|
||||
.canvas-container canvas {
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
d="M504 256C504 119 393 8 256 8S8 119 8 256c0 123.78 90.69 226.38 209.25 245V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.28c-30.8 0-40.41 19.12-40.41 38.73V256h68.78l-11 71.69h-57.78V501C413.31 482.38 504 379.78 504 256z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
</template>
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
d="M224.1 141c-63.6 0-114.9 51.3-114.9 114.9s51.3 114.9 114.9 114.9S339 319.5 339 255.9 287.7 141 224.1 141zm0 189.6c-41.1 0-74.7-33.5-74.7-74.7s33.5-74.7 74.7-74.7 74.7 33.5 74.7 74.7-33.6 74.7-74.7 74.7zm146.4-194.3c0 14.9-12 26.8-26.8 26.8-14.9 0-26.8-12-26.8-26.8s12-26.8 26.8-26.8 26.8 12 26.8 26.8zm76.1 27.2c-1.7-35.9-9.9-67.7-36.2-93.9-26.2-26.2-58-34.4-93.9-36.2-37-2.1-147.9-2.1-184.9 0-35.8 1.7-67.6 9.9-93.9 36.1s-34.4 58-36.2 93.9c-2.1 37-2.1 147.9 0 184.9 1.7 35.9 9.9 67.7 36.2 93.9s58 34.4 93.9 36.2c37 2.1 147.9 2.1 184.9 0 35.9-1.7 67.7-9.9 93.9-36.2 26.2-26.2 34.4-58 36.2-93.9 2.1-37 2.1-147.8 0-184.8zM398.8 388c-7.8 19.6-22.9 34.7-42.6 42.6-29.5 11.7-99.5 9-132.1 9s-102.7 2.6-132.1-9c-19.6-7.8-34.7-22.9-42.6-42.6-11.7-29.5-9-99.5-9-132.1s-2.6-102.7 9-132.1c7.8-19.6 22.9-34.7 42.6-42.6 29.5-11.7 99.5-9 132.1-9s102.7-2.6 132.1 9c19.6 7.8 34.7 22.9 42.6 42.6 11.7 29.5 9 99.5 9 132.1s2.7 102.7-9 132.1z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
</template>
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
</template>
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
dark
|
||||
flat
|
||||
>
|
||||
<v-toolbar-title>Gestion de l'association We Robot</v-toolbar-title>
|
||||
<v-toolbar-title>{{ $store.state.delegateAdminName }}</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn outlined>
|
||||
<v-btn outlined class="mr-3">
|
||||
Publier
|
||||
</v-btn>
|
||||
<v-btn icon @click="logout()">
|
||||
|
@ -45,7 +45,7 @@
|
|||
</v-toolbar>
|
||||
<v-container fluid>
|
||||
<v-row class="justify-center">
|
||||
<v-col cols="12" sm="12" md="8">
|
||||
<v-col cols="12" sm="12" md="8" lg="7" xl="5">
|
||||
<router-view></router-view>
|
||||
<div class="mt-3 d-flex justify-end">
|
||||
<v-btn color="success" :loading="isSaving" @click="save()">Sauvegarder</v-btn>
|
||||
|
@ -66,7 +66,7 @@
|
|||
<p>
|
||||
Vous n'êtes pas encore connecté à l'interface de modification de votre association, veuillez copier-coller la clée qui vous a été envoyé par e-mail dans la boîte ci-dessous.
|
||||
</p>
|
||||
<v-text-field
|
||||
<v-text-field
|
||||
v-on:keydown.enter="submitForm()"
|
||||
autofocus
|
||||
label="Clée"
|
||||
|
@ -99,11 +99,13 @@ export default {
|
|||
created () {
|
||||
this.init()
|
||||
},
|
||||
watch: {
|
||||
$route (to, from) {
|
||||
this.selectRoute(to)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const path = this.$route.path.split('/')
|
||||
const name = path[path.length - 1]
|
||||
const routes = ['', 'gallery', 'presentation', 'schedule', 'pricing', 'contact']
|
||||
this.tab = routes.indexOf(name)
|
||||
this.selectRoute(this.$route)
|
||||
/**
|
||||
* this is very ugly I kown
|
||||
*/
|
||||
|
@ -121,6 +123,12 @@ export default {
|
|||
// }, 3000)
|
||||
},
|
||||
methods: {
|
||||
selectRoute (route) {
|
||||
const path = route.path.split('/')
|
||||
const name = path[path.length - 1]
|
||||
const routes = ['', 'gallery', 'presentation', 'schedule', 'pricing', 'contact']
|
||||
this.tab = routes.indexOf(name)
|
||||
},
|
||||
init () {
|
||||
this.enabled = false
|
||||
|
||||
|
@ -154,8 +162,15 @@ export default {
|
|||
clearTimeout(this.loadingHandle)
|
||||
this.loading = false
|
||||
this.enabled = true
|
||||
const organization = res.data.data
|
||||
const organization = res.data.data.organization
|
||||
const tags = res.data.data.tags
|
||||
if (organization.proposedVersion.tag !== undefined && organization.proposedVersion.tag !== null) {
|
||||
organization.proposedVersion.tag = organization.proposedVersion.tag._id
|
||||
}
|
||||
this.$store.commit('SET_DELEGATE_ADMIN_NAME', organization.adminName)
|
||||
this.$store.commit('SET_DELEGATE_EMAIL', organization.email)
|
||||
this.$store.commit('SET_DATA', organization.proposedVersion)
|
||||
this.$store.commit('SET_TAGS', tags)
|
||||
this.$nextTick(() => {
|
||||
setTimeout(this.$refs.tabs.callSlider, 200)
|
||||
setTimeout(this.$refs.tabs.callSlider, 400)
|
||||
|
@ -185,6 +200,16 @@ export default {
|
|||
delete i._id
|
||||
return i
|
||||
})
|
||||
data.schedule = data.schedule.map(i => {
|
||||
delete i._id
|
||||
if (Array.isArray(i.when) && i.when.length > 0) {
|
||||
i.when = i.when.map(w => {
|
||||
delete w._id
|
||||
return w
|
||||
})
|
||||
}
|
||||
return i
|
||||
})
|
||||
this.$apitator.put('/delegate', data, { withAuth: true }).then(() => {
|
||||
this.isSaving = false
|
||||
this.$store.commit('ADD_ALERT', {
|
||||
|
|
|
@ -21,7 +21,6 @@ const routes: Array<RouteConfig> = [
|
|||
|
||||
{
|
||||
path: '/admin',
|
||||
name: 'AdminLayout',
|
||||
component: () => import(/* webpackChunkName: "adminLayout" */ '../layouts/Admin.vue'),
|
||||
children: [
|
||||
{
|
||||
|
@ -39,7 +38,6 @@ const routes: Array<RouteConfig> = [
|
|||
|
||||
{
|
||||
path: '/delegate',
|
||||
name: 'DelegateLayout',
|
||||
component: () => import(/* webpackChunkName: "delegateLayout" */ '../layouts/Delegate.vue'),
|
||||
children: [
|
||||
{
|
||||
|
|
|
@ -11,6 +11,7 @@ export default new Vuex.Store({
|
|||
enabled: false
|
||||
},
|
||||
title: '',
|
||||
tags: [],
|
||||
data: {
|
||||
name: '',
|
||||
descriptionShort: '',
|
||||
|
@ -31,7 +32,9 @@ export default new Vuex.Store({
|
|||
email: '',
|
||||
phone: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
delegateAdminName: '',
|
||||
delegateEmail: ''
|
||||
},
|
||||
mutations: {
|
||||
SET_TITLE (state, payload) {
|
||||
|
@ -51,6 +54,15 @@ export default new Vuex.Store({
|
|||
if (payload !== null) {
|
||||
state.data = { ...state.data, ...payload }
|
||||
}
|
||||
},
|
||||
SET_TAGS (state, payload) {
|
||||
state.tags = payload
|
||||
},
|
||||
SET_DELEGATE_ADMIN_NAME (state, payload) {
|
||||
state.delegateAdminName = payload
|
||||
},
|
||||
SET_DELEGATE_EMAIL (state, payload) {
|
||||
state.delegateEmail = payload
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
|
|
@ -1,15 +1,27 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="mb-2">
|
||||
<p class="text-body">
|
||||
<div class="mb-3 pb-1">
|
||||
<v-alert
|
||||
border="left"
|
||||
colored-border
|
||||
type="info"
|
||||
elevation="1"
|
||||
>
|
||||
Ici vous pouvez préciser quelques manières de contacter votre association, aucun des champs indiqués n'est obligatoire.
|
||||
</p>
|
||||
</v-alert>
|
||||
</div>
|
||||
<v-text-field
|
||||
prepend-icon="person"
|
||||
label="Personne responsable"
|
||||
outlined
|
||||
v-model="$store.state.data.contacts.person" />
|
||||
|
||||
<v-text-field
|
||||
prepend-icon="alternate_email"
|
||||
label="Email"
|
||||
:rules="rules.email"
|
||||
outlined
|
||||
v-model="$store.state.data.contacts.email" />
|
||||
<v-text-field
|
||||
prepend-icon="call"
|
||||
label="Numéro de téléphone"
|
||||
|
@ -45,7 +57,22 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({}),
|
||||
data: () => ({
|
||||
rules: {
|
||||
email: [
|
||||
v => /.+@.+\..+/.test(v) || "L'email doit être valide"
|
||||
],
|
||||
facebook: [
|
||||
v => /(http(s)?:\/\/)?(www\.)?facebook\.com\/(\S+){3,}/.test(v) || 'Ce champs doit être une url facebook valide'
|
||||
],
|
||||
twitter: [
|
||||
v => /(http(s)?:\/\/)?(www\.)?twitter\.com\/(\S+){3,}/.test(v) || 'Ce champs doit être une url twitter valide'
|
||||
],
|
||||
instagram: [
|
||||
v => /(http(s)?:\/\/)?(www\.)?instagram\.com\/(\S+){3,}/.test(v) || 'Ce champs doit être une url instagram valide'
|
||||
]
|
||||
}
|
||||
}),
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,281 @@
|
|||
<template>
|
||||
<div>
|
||||
Gallery
|
||||
<!-- COVER START -->
|
||||
<div
|
||||
class="cover-common cover-container"
|
||||
:style="coverStyle">
|
||||
</div>
|
||||
<div class="cover-common cover-upper">
|
||||
<v-btn
|
||||
@click="$refs.avatarEditor.toggle()"
|
||||
color="white"
|
||||
>Changer la couverture</v-btn>
|
||||
</div>
|
||||
|
||||
<AvatarEditor
|
||||
ref="avatarEditor"
|
||||
:loading="coverLoading"
|
||||
caption="Modifier votre couverture"
|
||||
:width="960"
|
||||
:height="300"
|
||||
:modal-size="1000"
|
||||
@submitted="handleAvatarEditorSubmitted"
|
||||
/>
|
||||
<!-- COVER END -->
|
||||
<div class="d-flex justify-end mt-3 mb-3">
|
||||
<v-btn color="primary" outlined @click="addMediaModal = true">
|
||||
<v-icon left>add</v-icon>
|
||||
Ajouter une image
|
||||
</v-btn>
|
||||
</div>
|
||||
<div
|
||||
v-if="$store.state.data.gallery.length === 0"
|
||||
class="mb-8 mt-8">
|
||||
<v-alert
|
||||
border="left"
|
||||
color="grey darken-2"
|
||||
outlined
|
||||
type="info"
|
||||
>
|
||||
Aucun medias n'ont été ajoutés pour l'instant
|
||||
</v-alert>
|
||||
</div>
|
||||
<v-row v-else>
|
||||
<v-col
|
||||
v-for="(media, index) in $store.state.data.gallery"
|
||||
:key="media._id"
|
||||
cols="12"
|
||||
xs="12"
|
||||
sm="6"
|
||||
md="6"
|
||||
lg="4"
|
||||
>
|
||||
<v-card>
|
||||
<v-img
|
||||
:src="media.location"
|
||||
height="200"
|
||||
class="grey darken-4"
|
||||
></v-img>
|
||||
<v-card-actions>
|
||||
<v-btn
|
||||
icon
|
||||
color="gray"
|
||||
small
|
||||
:disabled="index === 0"
|
||||
@click="shiftLeftMedia(media)"
|
||||
>
|
||||
<v-icon>keyboard_arrow_left</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
icon
|
||||
color="gray"
|
||||
small
|
||||
:disabled="index + 1 === $store.state.data.gallery.length"
|
||||
@click="shiftRightMedia(media)"
|
||||
>
|
||||
<v-icon>keyboard_arrow_right</v-icon>
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn icon color="error" small @click="openDeleteMediaModal(media)">
|
||||
<v-icon small>delete</v-icon>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-dialog v-model="addMediaModal" max-width="600px">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
Ajouter un ou des médias dans la gallerie
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<div class="mt-2">
|
||||
<v-file-input
|
||||
v-model="files"
|
||||
chips
|
||||
multiple
|
||||
show-size
|
||||
counter
|
||||
label="Sélectionnez les images ou vidéos à importer">
|
||||
</v-file-input>
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn text color="primary" @click="addMediaModal = false">
|
||||
Fermer
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn text color="primary" @click="uploadMedias()" :loading="uploadLoading">
|
||||
Téléverser
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog v-model="deleteMediaModal" max-width="500px">
|
||||
<v-card>
|
||||
<v-card-title>Êtes vous sur de vouloir supprimer ce media ?</v-card-title>
|
||||
<v-card-actions>
|
||||
<v-btn color="primary" text @click="deleteMediaModal = false">
|
||||
Fermer
|
||||
</v-btn>
|
||||
<v-btn color="error" text @click="deleteMedia()">
|
||||
Supprimer
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AvatarEditor from '../../components/AvatarEditor'
|
||||
|
||||
export default {
|
||||
components: { AvatarEditor },
|
||||
|
||||
data: () => ({
|
||||
coverLoading: false,
|
||||
addMediaModal: false,
|
||||
uploadLoading: false,
|
||||
files: [],
|
||||
deleteMediaModal: false,
|
||||
mediaToDelete: {}
|
||||
}),
|
||||
|
||||
computed: {
|
||||
coverStyle () {
|
||||
if (this.$store.state.data.cover === undefined || this.$store.state.data.cover === null) {
|
||||
return {}
|
||||
}
|
||||
return { backgroundImage: 'url(' + this.$store.state.data.cover.location + ')' }
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleAvatarEditorSubmitted (blob) {
|
||||
const form = new FormData()
|
||||
form.append('file', blob, blob.filename)
|
||||
this.coverLoading = true
|
||||
this.$apitator.post('/delegate/cover', form, { withAuth: true }).then(res => {
|
||||
this.coverLoading = false
|
||||
this.$store.commit('SET_DATA', { cover: res.data.cover })
|
||||
this.$refs.avatarEditor.finish()
|
||||
this.$store.commit('ADD_ALERT', {
|
||||
color: 'success',
|
||||
text: 'Couverture mise à jour !'
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$store.commit('ADD_ALERT', {
|
||||
color: 'error',
|
||||
text: 'Impossible de mettre à jour la couverture'
|
||||
})
|
||||
this.coverLoading = false
|
||||
})
|
||||
},
|
||||
loadFile (file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.readAsArrayBuffer(file)
|
||||
reader.onloadend = (event) => {
|
||||
resolve(['file', event.target.result, file.name])
|
||||
}
|
||||
reader.onerror = () => {
|
||||
console.log(reader.error)
|
||||
reject(reader.error)
|
||||
}
|
||||
})
|
||||
},
|
||||
uploadMedias () {
|
||||
this.uploadLoading = true
|
||||
const promises = this.files.map(file => this.loadFile(file))
|
||||
Promise.all(promises).then(results => {
|
||||
const formData = new FormData()
|
||||
results.forEach(r => formData.append(r[0], new Blob([new Uint8Array(r[1])]), r[2]))
|
||||
|
||||
this.$apitator.post('/delegate/medias', formData, { withAuth: true }).then(res => {
|
||||
this.$store.commit('SET_DATA', { gallery: res.data.data.gallery })
|
||||
this.$store.commit('ADD_ALERT', {
|
||||
color: 'success',
|
||||
text: 'Les médias ont été téléversés'
|
||||
})
|
||||
this.uploadLoading = false
|
||||
this.addMediaModal = false
|
||||
this.files = []
|
||||
}).catch(() => {
|
||||
this.coverLoading = false
|
||||
this.$store.commit('ADD_ALERT', {
|
||||
color: 'error',
|
||||
text: 'Impossible de téleverser ces fichiers'
|
||||
})
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$store.commit('ADD_ALERT', {
|
||||
color: 'error',
|
||||
text: 'Erreur de chargement des fichiers'
|
||||
})
|
||||
})
|
||||
},
|
||||
openDeleteMediaModal (media) {
|
||||
this.deleteMediaModal = true
|
||||
this.mediaToDelete = media
|
||||
},
|
||||
deleteMedia () {
|
||||
this.deleteMediaModal = false
|
||||
let gallery = this.$store.state.data.gallery
|
||||
gallery = gallery.filter(media => this.mediaToDelete._id !== media._id)
|
||||
this.$store.commit('SET_DATA', { gallery })
|
||||
},
|
||||
shiftLeftMedia (media) {
|
||||
const originalGallery = this.$store.state.data.gallery
|
||||
const index = originalGallery.indexOf(media)
|
||||
if (index === 0) {
|
||||
return
|
||||
}
|
||||
const gallery = originalGallery.map((m, i) => {
|
||||
if (i === index - 1) {
|
||||
return originalGallery[index]
|
||||
}
|
||||
if (i === index) {
|
||||
return originalGallery[index - 1]
|
||||
}
|
||||
return m
|
||||
})
|
||||
this.$store.commit('SET_DATA', { gallery })
|
||||
},
|
||||
shiftRightMedia (media) {
|
||||
const originalGallery = this.$store.state.data.gallery
|
||||
const index = originalGallery.indexOf(media)
|
||||
if (index === originalGallery.length - 1) {
|
||||
return
|
||||
}
|
||||
const gallery = originalGallery.map((m, i) => {
|
||||
if (i === index + 1) {
|
||||
return originalGallery[index]
|
||||
}
|
||||
if (i === index) {
|
||||
return originalGallery[index + 1]
|
||||
}
|
||||
return m
|
||||
})
|
||||
this.$store.commit('SET_DATA', { gallery })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cover-common {
|
||||
height: 16em;
|
||||
border-radius: .5em;
|
||||
}
|
||||
.cover-container {
|
||||
background-size: cover;
|
||||
}
|
||||
.cover-upper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: -16em;
|
||||
background-color: rgba(41, 128, 185, 0.4);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,28 +1,37 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-row class="mb-5">
|
||||
<v-row class="mb-6 pb-2">
|
||||
<v-col cols="12" sm="12" md="6" style="align-items: center; justify-content: center; display: flex;">
|
||||
<v-avatar size="200" style="border: 2px solid #95a5a6">
|
||||
<img :src="$store.state.data.thumbnail.location" />
|
||||
</v-avatar>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6" style="align-items: center; justify-content: center; display: flex;">
|
||||
<v-btn @click="$refs.avatarEditor.toggle()" color="primary">Changer le logo</v-btn>
|
||||
<v-btn @click="$refs.avatarEditor.toggle()" color="primary" outlined>
|
||||
Changer le logo
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row style="align-items: center;">
|
||||
<v-col cols="12" sm="12" md="12">
|
||||
<v-text-field
|
||||
label="Nom de l'association"
|
||||
outlined
|
||||
prepend-icon="label"
|
||||
v-model="$store.state.data.name" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-text-field
|
||||
label="Nom de l'association"
|
||||
prepend-icon="tag"
|
||||
outlined
|
||||
v-model="$store.state.data.name" />
|
||||
|
||||
<v-select
|
||||
label="Catégorie de l'association"
|
||||
outlined
|
||||
prepend-icon="category"
|
||||
item-text="name"
|
||||
item-value="_id"
|
||||
v-model="$store.state.data.tag"
|
||||
:items="$store.state.tags">
|
||||
</v-select>
|
||||
|
||||
<v-textarea
|
||||
outlined
|
||||
prepend-icon="description"
|
||||
label="Description ou résumé rapide"
|
||||
placeholder="Courte description qui apparaitra sur la page d'accueil"
|
||||
:rules="rules.descriptionShort"
|
||||
|
|
|
@ -8,10 +8,15 @@
|
|||
</div>
|
||||
<div
|
||||
v-if="$store.state.data.pricing.length === 0"
|
||||
class="mb-2 mt-2 d-flex justify-center">
|
||||
<span class="text-gray">
|
||||
Pas de tarifs ajoutés
|
||||
</span>
|
||||
class="mb-8 mt-8">
|
||||
<v-alert
|
||||
border="left"
|
||||
color="grey darken-2"
|
||||
outlined
|
||||
type="info"
|
||||
>
|
||||
Aucune catégorie horaires ajoutées pour le moment
|
||||
</v-alert>
|
||||
</div>
|
||||
<v-row v-else>
|
||||
<v-col
|
||||
|
@ -40,16 +45,18 @@
|
|||
<v-btn
|
||||
@click="openDeleteModal(pricing)"
|
||||
icon
|
||||
outlined
|
||||
color="error"
|
||||
>
|
||||
<v-icon>delete</v-icon>
|
||||
<v-icon small>delete</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
@click="openEditModal(pricing)"
|
||||
icon
|
||||
outlined
|
||||
color="info"
|
||||
>
|
||||
<v-icon>edit</v-icon>
|
||||
<v-icon small>edit</v-icon>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
|
|
|
@ -1,9 +1,27 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="d-flex">
|
||||
<div class="d-flex justify-end">
|
||||
<v-btn @click="openAddCategoryModal()" color="teal" outlined>
|
||||
<v-icon left>add</v-icon>
|
||||
Ajouter une catégorie
|
||||
</v-btn>
|
||||
</div>
|
||||
<div
|
||||
v-if="$store.state.data.schedule.length === 0"
|
||||
class="mb-8 mt-8">
|
||||
<v-alert
|
||||
border="left"
|
||||
color="grey darken-2"
|
||||
outlined
|
||||
type="info"
|
||||
>
|
||||
Aucune catégorie horaires ajoutées pour le moment
|
||||
</v-alert>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div
|
||||
class="schedule-item"
|
||||
v-for="item in scheduleData"
|
||||
v-for="item in $store.state.data.schedule"
|
||||
:key="item.name"
|
||||
>
|
||||
<!--
|
||||
|
@ -12,27 +30,222 @@
|
|||
md="6"
|
||||
lg="6"
|
||||
-->
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<div class="subheading font-weight-bold">{{ item.name }}</div>
|
||||
<div class="text-subtitle-2">{{ item.description }}</div>
|
||||
</v-card-title>
|
||||
<v-card class="mt-4">
|
||||
<div class="schedule-content">
|
||||
<v-card-title class="flex-column justify-space-between">
|
||||
<div class="schedule-title-container">
|
||||
<div class="subheading font-weight-bold">{{ item.name }}</div>
|
||||
<div class="text-body-1">{{ item.description }}</div>
|
||||
</div>
|
||||
<div class="mt-5 schedule-actions">
|
||||
<div class="mr-3">
|
||||
<v-btn outlined icon small color="info" class="mr-2" @click="openEditCategoryModal(item)">
|
||||
<v-icon small>edit</v-icon>
|
||||
</v-btn>
|
||||
<v-btn outlined icon small color="error" @click="openDeleteCategoryModal(item)">
|
||||
<v-icon small>delete</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-btn
|
||||
@click="openAddWhenModal(item)"
|
||||
outlined
|
||||
small
|
||||
color="success">
|
||||
Ajouter un horaire
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-card-title>
|
||||
|
||||
<v-divider></v-divider>
|
||||
|
||||
<v-list dense>
|
||||
<v-list-item
|
||||
v-for="when in item.when"
|
||||
:key="when.day">
|
||||
<v-list-item-content>{{ when.day }}</v-list-item-content>
|
||||
<v-list-item-content class="align-end">
|
||||
{{ when.from }} - {{ when.to }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<div class="d-flex align-center schedule-days">
|
||||
<v-list
|
||||
v-if="Array.isArray(item.when) && item.when.length > 0"
|
||||
dense
|
||||
class="schedule-list">
|
||||
<v-divider />
|
||||
<div
|
||||
v-for="when in item.when"
|
||||
:key="when.day">
|
||||
<v-list-item>
|
||||
<v-list-item-content>
|
||||
<div class="d-flex justify-space-between">
|
||||
<div>{{ when.day }}</div>
|
||||
<div>{{ when.from }} - {{ when.to }}</div>
|
||||
</div>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<div class="d-flex justify-space-between">
|
||||
<v-btn icon color="info" @click="openEditWhenModal(when)">
|
||||
<v-icon small>
|
||||
edit
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon color="error" @click="openDeleteWhenModal(when)">
|
||||
<v-icon small>delete</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<v-divider />
|
||||
</div>
|
||||
</v-list>
|
||||
<div v-else class="grey--text text--darken-1">
|
||||
Pas d'interval horaires pour cette catégorie pour l'instant
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-card>
|
||||
</div>
|
||||
</div>
|
||||
<v-dialog
|
||||
max-width="500px"
|
||||
v-model="categoryModal">
|
||||
<v-card>
|
||||
<v-card-title v-text="modalTitle + ' une catégorie horaire'" />
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
v-model="category.name"
|
||||
label="Nom"
|
||||
hint="Requis"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="category.description"
|
||||
label="Description"
|
||||
hint="Optionel"
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn @click="categoryModal = false" text color="primary">
|
||||
Fermer
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
@click="saveCategory()"
|
||||
text
|
||||
color="success"
|
||||
:disabled="category.name.length < 3"
|
||||
>
|
||||
Valider
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog
|
||||
max-width="500px"
|
||||
v-model="deleteCategoryModal">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
Voulez vous vraiment supprimer cette catégorie horaire ?
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<v-btn @click="deleteCategoryModal = false" text color="primary">
|
||||
Fermer
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn @click="deleteCategory()" text color="error">
|
||||
Supprimer
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog
|
||||
max-width="500px"
|
||||
v-model="whenModal">
|
||||
<v-card>
|
||||
<v-card-title v-text="modalTitle + ' un interval horaire'" />
|
||||
<v-card-text>
|
||||
<v-select
|
||||
prepend-icon="event"
|
||||
v-model="when.day"
|
||||
:items="days"
|
||||
label="Sélectionnez un jour"
|
||||
></v-select>
|
||||
<v-menu
|
||||
ref="fromMenu"
|
||||
v-model="fromMenu"
|
||||
:close-on-content-click="false"
|
||||
:return-value.sync="when.from"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
min-width="290px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
v-model="when.from"
|
||||
label="Heure de début"
|
||||
prepend-icon="schedule"
|
||||
readonly
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
></v-text-field>
|
||||
</template>
|
||||
<v-time-picker v-model="when.from" format="24hr">
|
||||
<v-btn text color="primary" @click="fromMenu = false">Fermer</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn text color="primary" @click="$refs.fromMenu.save(when.from)">OK</v-btn>
|
||||
</v-time-picker>
|
||||
</v-menu>
|
||||
<v-menu
|
||||
ref="toMenu"
|
||||
v-model="toMenu"
|
||||
:close-on-content-click="false"
|
||||
:return-value.sync="when.to"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
min-width="290px"
|
||||
>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
v-model="when.to"
|
||||
label="Heure de fin"
|
||||
prepend-icon="schedule"
|
||||
readonly
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
></v-text-field>
|
||||
</template>
|
||||
<v-time-picker v-model="when.to" format="24hr">
|
||||
<v-btn text color="primary" @click="toMenu = false">Fermer</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
text
|
||||
color="primary"
|
||||
@click="$refs.toMenu.save(when.to)">OK</v-btn>
|
||||
</v-time-picker>
|
||||
</v-menu>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn @click="categoryModal = false" text color="primary">
|
||||
Fermer
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
@click="saveWhen()"
|
||||
text
|
||||
color="success"
|
||||
:disabled="when.day.length < 4 || when.to.length !== 5 || when.from.length !== 5">
|
||||
Valider
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog
|
||||
max-width="500px"
|
||||
v-model="deleteWhenModal">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
Voulez vous vraiment supprimer cette interval horaire ?
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<v-btn @click="deleteWhenModal = false" text color="primary">
|
||||
Fermer
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn @click="deleteWhen()" text color="error">
|
||||
Supprimer
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -103,13 +316,171 @@ export default {
|
|||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
mode: '',
|
||||
categoryModal: false,
|
||||
category: {
|
||||
name: '',
|
||||
description: ''
|
||||
},
|
||||
deleteCategoryModal: false,
|
||||
toDeleteCategory: {},
|
||||
oldEditCategory: {},
|
||||
whenModal: false,
|
||||
when: {
|
||||
day: '',
|
||||
from: '',
|
||||
to: ''
|
||||
},
|
||||
deleteWhenModal: false,
|
||||
toDeleteWhen: {},
|
||||
oldEditWhen: {},
|
||||
fromMenu: false,
|
||||
toMenu: false,
|
||||
days: [
|
||||
'Lundi',
|
||||
'Mardi',
|
||||
'Mercredi',
|
||||
'Jeudi',
|
||||
'Vendredi',
|
||||
'Samedi'
|
||||
]
|
||||
})
|
||||
}),
|
||||
|
||||
computed: {
|
||||
modalTitle () { return this.mode === 'add' ? 'Ajouter' : 'Editer' }
|
||||
},
|
||||
|
||||
methods: {
|
||||
openAddCategoryModal () {
|
||||
this.mode = 'add'
|
||||
this.categoryModal = true
|
||||
},
|
||||
openEditCategoryModal (item) {
|
||||
this.category = item
|
||||
this.oldEditCategory = item
|
||||
this.mode = 'edit'
|
||||
this.categoryModal = true
|
||||
},
|
||||
openDeleteCategoryModal (item) {
|
||||
this.deleteCategoryModal = true
|
||||
this.toDeleteCategory = item
|
||||
},
|
||||
saveCategory () {
|
||||
let schedule = this.$store.state.data.schedule
|
||||
if (this.mode === 'add') {
|
||||
this.category._id = Date.now().toString()
|
||||
schedule.push(this.category)
|
||||
} else {
|
||||
schedule = schedule.map(i => i.name === this.oldEditCategory.name && i.description === this.oldEditCategory.description ? this.category : i)
|
||||
}
|
||||
|
||||
this.category = {
|
||||
name: '',
|
||||
description: ''
|
||||
}
|
||||
this.$store.commit('SET_DATA', { schedule })
|
||||
this.categoryModal = false
|
||||
},
|
||||
deleteCategory () {
|
||||
let schedule = this.$store.state.data.schedule
|
||||
schedule = schedule.filter(item => item.name !== this.toDeleteCategory.name && item.description !== this.toDeleteCategory.description)
|
||||
this.$store.commit('SET_DATA', { schedule })
|
||||
this.deleteCategoryModal = false
|
||||
},
|
||||
|
||||
openAddWhenModal (parent) {
|
||||
this.mode = 'add'
|
||||
this.whenParent = parent
|
||||
this.whenModal = true
|
||||
},
|
||||
openEditWhenModal (item) {
|
||||
this.when = item
|
||||
this.oldEditWhen = item
|
||||
this.mode = 'edit'
|
||||
this.whenModal = true
|
||||
},
|
||||
openDeleteWhenModal (item) {
|
||||
this.deleteWhenModal = true
|
||||
this.toDeleteWhen = item
|
||||
},
|
||||
saveWhen () {
|
||||
let schedule = this.$store.state.data.schedule
|
||||
if (this.mode === 'add') {
|
||||
this.when._id = Date.now().toString()
|
||||
schedule = schedule.map(i => {
|
||||
if (this.whenParent._id === i._id) {
|
||||
if (!Array.isArray(i.when)) {
|
||||
i.when = []
|
||||
}
|
||||
i.when.push(this.when)
|
||||
}
|
||||
return i
|
||||
})
|
||||
} else {
|
||||
schedule = schedule.map(i => {
|
||||
if (this.whenParent._id === i._id) {
|
||||
i.when = i.when.map(w => w._id === this.when._id ? this.when : w)
|
||||
}
|
||||
return i
|
||||
})
|
||||
}
|
||||
this.when = {
|
||||
day: '',
|
||||
from: '10:00',
|
||||
to: '11:00'
|
||||
}
|
||||
this.$store.commit('SET_DATA', { schedule })
|
||||
this.whenModal = false
|
||||
},
|
||||
deleteWhen () {
|
||||
let schedule = this.$store.state.data.schedule
|
||||
schedule = schedule.map(i => {
|
||||
if (this.whenParent._id === i._id) {
|
||||
i.when = i.when.filter(w => w._id !== this.toDeleteWhen._id)
|
||||
}
|
||||
return i
|
||||
})
|
||||
this.$store.commit('SET_DATA', { schedule })
|
||||
this.deleteWhenModal = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.schedule-item {
|
||||
width: 25em;
|
||||
<style>
|
||||
.schedule-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
.schedule-title-container {
|
||||
width: 100%;
|
||||
word-break: break-word;
|
||||
}
|
||||
.schedule-list {
|
||||
width: 100%;
|
||||
}
|
||||
.schedule-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
.schedule-actions div:first-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.schedule-content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.schedule-days {
|
||||
margin-right: 0;
|
||||
}
|
||||
.schedule-actions {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.schedule-actions div:first-child {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -9120,6 +9120,11 @@ vue-hot-reload-api@^2.3.0:
|
|||
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
|
||||
integrity sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==
|
||||
|
||||
vue-input-facade@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-input-facade/-/vue-input-facade-1.3.1.tgz#87cdca62f75fcdf8205fc7345e4f6a560f4daaa8"
|
||||
integrity sha512-8tgWiBObwVT3v9XD9OruwPDdWFwbTxaGdtUd1vXqAwNMZceETxZdfsgkMjUtwT1u2tCY3Ptu09WNDPwiwa4huw==
|
||||
|
||||
vue-loader@^15.9.2:
|
||||
version "15.9.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.3.tgz#0de35d9e555d3ed53969516cac5ce25531299dda"
|
||||
|
|
Loading…
Reference in a new issue