Commit 50f5b06d authored by Vincent A's avatar Vincent A 🌱

Let users add icons to categories

parent f34dfb55
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -18,11 +18,11 @@ function create (category) {
}
function update (category) {
const { name, description, id } = category
const { name, description, id, icon } = category
return service({
method: 'patch',
url: '/category',
data: { name, description, id },
data: { name, description, id, icon },
params: {
id: `eq.${id}`
},
......
......@@ -24,6 +24,10 @@
</v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-avatar>
<img :src="category.icon">
</v-list-tile-avatar>
<v-list-tile-action>
<v-btn icon ripple @click.stop="toDelete = index">
<v-icon color="grey">delete</v-icon>
......@@ -74,6 +78,17 @@
import api from '@/api'
import CategoryEdit from '@/components/CategoryEdit'
// PostgREST retuns binary columns in hex encoded format
// this function can be used to return them back to an ascii representation
function hex2a (hexx) {
var hex = hexx.toString() // force conversion
var str = ''
for (var i = 0; (i < hex.length && hex.substr(i, 2) !== '00'); i += 2) {
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16))
}
return str
}
export default {
name: 'Categories',
components: {
......@@ -104,7 +119,14 @@ export default {
getCategories: function () {
const schoolId = this.$store.getters.selected_school
api.category.get(schoolId).then((res) => {
this.categories = res.data
const categories = res.data
// Decode icon file from hex
for (let i = 0; i < res.data.length; i++) {
if (categories[i].icon != null) {
categories[i].icon = hex2a(categories[i].icon)
}
}
this.categories = categories
})
},
deleteCategory: function () {
......
......@@ -22,6 +22,13 @@
required
>
</v-text-field>
<v-avatar class='inlineinput' size='36'><img :src="formIconUrl" /></v-avatar>
<upload-btn
class='inlineinput'
title='Kategorie-Bild auswählen'
accept="image/*"
:fileChangedCallback="handleIconSelected">
</upload-btn>
</v-card-text>
<v-card-actions>
<v-btn flat @click="this.submit" v-if="this.editingId == null">Erstellen</v-btn>
......@@ -49,6 +56,7 @@
<script>
import api from '@/api'
import { isUserMemberOf } from '../utils/permissions'
import UploadButton from 'vuetify-upload-button'
export default {
$_veeValidate: { validator: 'new' },
......@@ -60,10 +68,24 @@ export default {
description: '',
editingId: null,
showSnackbar: false,
snackbarMsg: ''
snackbarMsg: '',
iconFile: '',
iconUrl: ''
}
},
computed: {
formIconUrl: function () {
return (this.iconUrl == null || this.iconUrl.length === 0)
? '/static/img/placeholder_icon.png'
: this.iconUrl
}
},
components: {
'upload-btn': UploadButton
},
props: ['handleSuccess', 'handleCancel', 'category'],
watch: {
......@@ -76,6 +98,7 @@ export default {
this.name = next.name
this.description = next.description
this.editingId = next.id
this.iconUrl = next.icon
}
}
},
......@@ -85,8 +108,23 @@ export default {
this.editingId = null
this.name = ''
this.description = ''
this.iconFile = ''
this.iconUrl = ''
this.$nextTick(() => this.$validator.reset())
},
handleIconSelected: function (icon) {
if (icon !== undefined) {
const fr = new FileReader()
fr.readAsDataURL(icon)
fr.addEventListener('load', () => {
this.iconUrl = fr.result
this.iconFile = icon
})
} else {
this.iconFile = ''
this.iconUrl = ''
}
},
submit: function () {
this.$validator.validate()
.then(isFormValid => {
......@@ -106,7 +144,8 @@ export default {
const category = {
school_id: this.$store.getters.selected_school,
name: this.name,
description: this.description
description: this.description,
icon: this.iconUrl
}
// Select the appripriate api depending on whether
......@@ -143,4 +182,7 @@ export default {
.card {
padding: 10px;
}
.inlineinput {
display: inline-block;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment