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

Let users add icons to categories

parent f34dfb55
This diff is collapsed.
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
"vue-head": "2.0.12", "vue-head": "2.0.12",
"vue-router": "3.0.1", "vue-router": "3.0.1",
"vuetify": "1.2.3", "vuetify": "1.2.3",
"vuetify-upload-button": "^1.2.0",
"vuex": "3.0.1", "vuex": "3.0.1",
"vuex-persist": "^2.0.0" "vuex-persist": "^2.0.0"
}, },
......
...@@ -18,11 +18,11 @@ function create (category) { ...@@ -18,11 +18,11 @@ function create (category) {
} }
function update (category) { function update (category) {
const { name, description, id } = category const { name, description, id, icon } = category
return service({ return service({
method: 'patch', method: 'patch',
url: '/category', url: '/category',
data: { name, description, id }, data: { name, description, id, icon },
params: { params: {
id: `eq.${id}` id: `eq.${id}`
}, },
......
...@@ -24,6 +24,10 @@ ...@@ -24,6 +24,10 @@
</v-list-tile-sub-title> </v-list-tile-sub-title>
</v-list-tile-content> </v-list-tile-content>
<v-list-tile-avatar>
<img :src="category.icon">
</v-list-tile-avatar>
<v-list-tile-action> <v-list-tile-action>
<v-btn icon ripple @click.stop="toDelete = index"> <v-btn icon ripple @click.stop="toDelete = index">
<v-icon color="grey">delete</v-icon> <v-icon color="grey">delete</v-icon>
...@@ -74,6 +78,17 @@ ...@@ -74,6 +78,17 @@
import api from '@/api' import api from '@/api'
import CategoryEdit from '@/components/CategoryEdit' 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 { export default {
name: 'Categories', name: 'Categories',
components: { components: {
...@@ -104,7 +119,14 @@ export default { ...@@ -104,7 +119,14 @@ export default {
getCategories: function () { getCategories: function () {
const schoolId = this.$store.getters.selected_school const schoolId = this.$store.getters.selected_school
api.category.get(schoolId).then((res) => { 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 () { deleteCategory: function () {
......
...@@ -22,6 +22,13 @@ ...@@ -22,6 +22,13 @@
required required
> >
</v-text-field> </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-text>
<v-card-actions> <v-card-actions>
<v-btn flat @click="this.submit" v-if="this.editingId == null">Erstellen</v-btn> <v-btn flat @click="this.submit" v-if="this.editingId == null">Erstellen</v-btn>
...@@ -49,6 +56,7 @@ ...@@ -49,6 +56,7 @@
<script> <script>
import api from '@/api' import api from '@/api'
import { isUserMemberOf } from '../utils/permissions' import { isUserMemberOf } from '../utils/permissions'
import UploadButton from 'vuetify-upload-button'
export default { export default {
$_veeValidate: { validator: 'new' }, $_veeValidate: { validator: 'new' },
...@@ -60,10 +68,24 @@ export default { ...@@ -60,10 +68,24 @@ export default {
description: '', description: '',
editingId: null, editingId: null,
showSnackbar: false, 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'], props: ['handleSuccess', 'handleCancel', 'category'],
watch: { watch: {
...@@ -76,6 +98,7 @@ export default { ...@@ -76,6 +98,7 @@ export default {
this.name = next.name this.name = next.name
this.description = next.description this.description = next.description
this.editingId = next.id this.editingId = next.id
this.iconUrl = next.icon
} }
} }
}, },
...@@ -85,8 +108,23 @@ export default { ...@@ -85,8 +108,23 @@ export default {
this.editingId = null this.editingId = null
this.name = '' this.name = ''
this.description = '' this.description = ''
this.iconFile = ''
this.iconUrl = ''
this.$nextTick(() => this.$validator.reset()) 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 () { submit: function () {
this.$validator.validate() this.$validator.validate()
.then(isFormValid => { .then(isFormValid => {
...@@ -106,7 +144,8 @@ export default { ...@@ -106,7 +144,8 @@ export default {
const category = { const category = {
school_id: this.$store.getters.selected_school, school_id: this.$store.getters.selected_school,
name: this.name, name: this.name,
description: this.description description: this.description,
icon: this.iconUrl
} }
// Select the appripriate api depending on whether // Select the appripriate api depending on whether
...@@ -143,4 +182,7 @@ export default { ...@@ -143,4 +182,7 @@ export default {
.card { .card {
padding: 10px; padding: 10px;
} }
.inlineinput {
display: inline-block;
}
</style> </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