Skip to content

Commit

Permalink
BREAKING: better API management, no more base64, better UI
Browse files Browse the repository at this point in the history
  • Loading branch information
kernoeb committed Dec 5, 2021
1 parent ed305b0 commit ca5ed12
Show file tree
Hide file tree
Showing 15 changed files with 353 additions and 322 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = {
],
// add your custom rules here
rules: {
curly: 'off'
curly: 'off',
'no-console': 'off'
}
}
2 changes: 1 addition & 1 deletion components/Crous.vue
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default {
someDate.getFullYear() === today.getFullYear()
},
getMenus () {
this.$axios.$get(this.$config.apiCrous).then((b) => {
this.$axios.$get(this.$config.publicUrl + '/api/v1/crous_menu').then((b) => {
this.menu = b
try {
this.$plausible.trackEvent('crous')
Expand Down
11 changes: 5 additions & 6 deletions components/ErrorAlert.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@
type="error"
:icon="mdiAlert"
>
<div v-if="status === 'semi'">
<span v-if="timestamp">{{ $config.i18n.error_db_only }} <small>({{ $config.i18n.error_saved }}&nbsp;{{ $moment(timestamp).format('dddd DD MMM à HH:mm') }})</small></span>
<div v-if="status === 'partial'">
<span v-if="plannings && plannings.length === 1 && plannings[0] && plannings[0].timestamp">{{ $config.i18n.error_db_only }} <small>({{ $config.i18n.error_saved }}&nbsp;{{ $moment(plannings[0].timestamp).format('dddd DD MMM à HH:mm') }})</small></span>
<span v-else>{{ $config.i18n.error_db_one }}&nbsp;({{ $config.i18n.error_saved2 }})</span>
</div>
<div v-else-if="status === 'off'">
<span>{{ $config.i18n.error_db_all }}</span>
</div>
<div v-else>
<span v-if="timestamp">{{ $config.i18n.error_db }}{{ $moment(timestamp).format('dddd DD MMM à HH:mm') }}.</span>
<span v-else>{{ $config.i18n.error_db2 }}</span>
{{ $config.i18n.error_db2 }}
</div>
</v-alert>
</template>
Expand All @@ -29,8 +28,8 @@ export default {
type: String,
default: 'on'
},
timestamp: {
type: Number,
plannings: {
type: Array,
default: null
}
},
Expand Down
244 changes: 189 additions & 55 deletions components/SelectPlanning.vue
Original file line number Diff line number Diff line change
@@ -1,52 +1,125 @@
<template>
<v-treeview
v-if="urls"
:expand-icon="mdiMenuDown"
:filter="filter"
:indeterminate-icon="mdiMinusBox"
:items="urls"
:off-icon="mdiCheckboxBlankOutline"
:on-icon="mdiCheckboxMarked"
:search="searchCalendar"
:value="selectedPlannings"
activatable
class="treeview_plannings"
dense
item-children="edts"
item-key="fullId"
item-text="title"
open-on-click
selectable
selection-type="independent"
transition
@input="$emit('selected-plannings', $event)"
@update:active="addPlanning"
>
<template #label="{item}">
<span :class="selectedPlannings.includes(item.fullId) ? 'selected_planning' : ''">{{ item.title }}</span>
</template>
</v-treeview>
<div v-else style="min-height: 330px;" class="d-flex justify-center align-center">
<v-progress-circular
indeterminate
color="yellow darken-2"
/>
<div>
<v-snackbar
v-model="showSnackbar"
:timeout="3000"
absolute
top
color="teal"
right
>
Copié dans le presse-papier !
</v-snackbar>
<v-snackbar
v-model="showSnackbarError"
:timeout="3000"
absolute
top
color="error"
right
>
Une erreur s'est produite, désolé.
</v-snackbar>
<v-card>
<v-toolbar
class="toolbar_edt"
flat
>
<v-card-title class="headline">
<v-icon class="mr-3">
{{ mdiCalendar }}
</v-icon>
<div>
<div style="font-size: 15px; height: 20px;">
{{ $config.i18n.chooseEdt }}
</div>
<div style="font-size: 12px;">
{{ (localPlannings && localPlannings.length) || 0 }} sélectionnés
</div>
</div>
</v-card-title>
<v-spacer />
<v-btn
v-tooltip="'Copier la sélection actuelle sous forme d\'URL dans le presse-papier'"
icon
@click="copyTextToClipboard($config.publicUrl + '/?p=' + localPlannings.join(','))"
>
<v-icon>{{ mdiContentCopy }}</v-icon>
</v-btn><v-btn
icon
@click="$emit('close')"
>
<v-icon>{{ mdiClose }}</v-icon>
</v-btn>
</v-toolbar>

<v-divider />

<v-text-field
v-model.trim="searchCalendar"
:label="$config.i18n.searchPlanning"
filled
clearable
:clear-icon="mdiClose"
hide-details
dense
/>
<v-btn text small color="green" @click="reset">
Réinitialiser
</v-btn>
<div v-if="urls">
<v-treeview
v-model="localPlannings"
style="max-height: calc(90vh - 200px); overflow: auto;"
:expand-icon="mdiMenuDown"
:filter="filter"
:indeterminate-icon="mdiMinusBox"
:items="urls"
:off-icon="mdiCheckboxBlankOutline"
:on-icon="mdiCheckboxMarked"
:search="searchCalendar"
class="treeview_plannings"
dense
item-children="edts"
item-key="fullId"
item-text="title"
open-on-click
selectable
selection-type="independent"
transition
@update:open="open"
>
<template #label="{item, selected}">
<span :class="(selected || (item && item.fullId && localPlannings.some(v => v.startsWith(item.fullId)))) ? 'selected_planning' : ''">{{ item.title }}</span>
</template>
</v-treeview>
</div>
<div v-else style="min-height: 330px;" class="d-flex justify-center align-center">
<v-progress-circular
indeterminate
color="yellow darken-2"
/>
</div>
<v-btn block :disabled="disabledValidate" @click="updatePlannings()">
Valider
</v-btn>
</v-card>
</div>
</template>

<script>
import { mdiMenuDown, mdiMinusBox, mdiCheckboxBlankOutline, mdiCheckboxMarked } from '@mdi/js'
import { mdiClose, mdiContentCopy, mdiCalendar, mdiMenuDown, mdiMinusBox, mdiCheckboxBlankOutline, mdiCheckboxMarked } from '@mdi/js'
export default {
name: 'SelectPlanning',
props: {
searchCalendar: {
type: String,
default: ''
},
selectedPlannings: {
type: Array,
default: () => []
},
plannings: {
type: Array,
default: () => []
}
},
data () {
Expand All @@ -55,32 +128,93 @@ export default {
mdiCheckboxMarked,
mdiMinusBox,
mdiMenuDown,
mdiCalendar,
mdiClose,
mdiContentCopy,
showSnackbar: false,
showSnackbarError: false,
searchCalendar: '',
activatedPlanning: null,
urls: null
urls: null,
localPlannings: []
}
},
computed: {
disabledValidate () {
return JSON.stringify(this.localPlannings) === JSON.stringify(this.selectedPlannings)
}
},
watch: {
selectedPlannings: {
handler (newVal, oldVal) {
if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
this.localPlannings = newVal
}
},
immediate: true
}
},
mounted () {
setTimeout(() => {
this.$axios.$get(this.$config.apiUrls).then((data) => {
this.urls = data
this.$emit('selected-plannings', [...this.selectedPlannings])
}).catch(() => {
})
}, 0)
this.$axios.$get(`${this.$config.publicUrl}/api/v1/urls`).then((data) => {
this.urls = data
}).catch((err) => {
console.log(err)
})
},
methods: {
filter: (item, search, textKey) => item[textKey].toUpperCase().includes(search.toUpperCase()),
addPlanning (event) {
let tmp = [...this.selectedPlannings]
if (event && event.length) {
if (tmp.includes(event?.[0])) tmp = tmp.filter(v => v !== event?.[0])
else tmp.push(event[0])
this.$emit('selected-plannings', tmp)
this.activatedPlanning = event?.[0]
} else {
this.$emit('selected-plannings', tmp.filter(v => v !== this.activatedPlanning))
// https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript
fallbackCopyTextToClipboard (text) {
const textArea = document.createElement('textarea')
textArea.value = text
// Avoid scrolling to bottom
textArea.style.top = '0'
textArea.style.left = '0'
textArea.style.position = 'fixed'
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
try {
const successful = document.execCommand('copy')
const msg = successful ? 'successful' : 'unsuccessful'
console.log('Fallback: Copying text command was ' + msg)
this.showSnackbar = true
} catch (err) {
console.error('Fallback: Oops, unable to copy', err)
this.showSnackbarError = true
}
document.body.removeChild(textArea)
},
copyTextToClipboard (text) {
if (!navigator.clipboard) {
this.fallbackCopyTextToClipboard(text)
return
}
navigator.clipboard.writeText(text).then(() => {
console.log('Async: Copying to clipboard was successful!')
this.showSnackbar = true
}, function (err) {
console.error('Async: Could not copy text: ', err)
this.showSnackbarError = true
})
},
reset () {
this.localPlannings = []
this.searchCalendar = ''
},
open (ev) {
console.log(ev)
},
filter: (item, search, textKey) => item[textKey].toUpperCase().includes(search.toUpperCase()),
updatePlannings () {
console.log(this.localPlannings)
this.$emit('selected-plannings', this.localPlannings)
}
}
}
Expand Down
Loading

0 comments on commit ca5ed12

Please sign in to comment.