populate events trough apicall and save active event in url

This commit is contained in:
j3d1 2019-12-05 04:32:33 +01:00
parent fbf6d9dc91
commit cc9ba38dac
11 changed files with 137 additions and 61 deletions

2
.env.example Normal file
View file

@ -0,0 +1,2 @@
VUE_APP_CONFIG_API_USER=rest api user
VUE_APP_CONFIG_API_PASSWORD=rest api password

1
.gitignore vendored
View file

@ -3,6 +3,7 @@ node_modules
/dist /dist
# local env files # local env files
.env
.env.local .env.local
.env.*.local .env.*.local

2
API.md
View file

@ -55,4 +55,4 @@ returns a list of all tracked events
### Files/Images ### Files/Images
#### ``GET /api/images/<file.hash>`` #### ``GET /api/<version.major>/images/<file.hash>``

View file

@ -11,15 +11,20 @@
"@fortawesome/fontawesome-svg-core": "^1.2.25", "@fortawesome/fontawesome-svg-core": "^1.2.25",
"@fortawesome/free-solid-svg-icons": "^5.11.2", "@fortawesome/free-solid-svg-icons": "^5.11.2",
"@fortawesome/vue-fontawesome": "^0.1.8", "@fortawesome/vue-fontawesome": "^0.1.8",
"axios": "^0.19.0",
"bootstrap": "^4.3.1", "bootstrap": "^4.3.1",
"core-js": "^3.3.2", "core-js": "^3.3.2",
"dotenv-webpack": "^1.7.0",
"jquery": "^3.4.1", "jquery": "^3.4.1",
"lodash": "^4.17.15",
"node-sass": "^4.13.0", "node-sass": "^4.13.0",
"popper.js": "^1.16.0", "popper.js": "^1.16.0",
"ramda": "^0.26.1", "ramda": "^0.26.1",
"sass-loader": "^8.0.0", "sass-loader": "^8.0.0",
"vue": "^2.6.10", "vue": "^2.6.10",
"vuex": "^3.1.2" "vue-router": "^3.1.3",
"vuex": "^3.1.2",
"vuex-router-sync": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "^4.0.0", "@vue/cli-plugin-babel": "^4.0.0",

View file

@ -1,46 +1,17 @@
<template> <template>
<div id="app"> <div id="app">
<Navbar/> <Navbar/>
<div class="container-fluid px-xl-5 mt-3"> <router-view></router-view>
<div class="row" v-if="layout === 'table'">
<div class="col-xl-8 offset-xl-2">
<Table
:columns="['uid', 'description', 'box', 'image']"
:items="loadedItems"
:keyName="'uid'"
/>
</div>
</div>
<Cards
v-if="layout === 'cards'"
:columns="['uid', 'description', 'box', 'image']"
:items="loadedItems"
:keyName="'uid'"
v-slot="{ item }"
>
<img
:src="`https://picsum.photos/id/${item.image + 50}/200/200`"
alt="item"
class="card-img-top img-fluid"
>
<div class="card-body">
<h6 class="card-title">{{ item.description }}</h6>
<h6 class="card-subtitle text-secondary">uid: {{ item.uid }} box: {{ item.box }}</h6>
</div>
</Cards>
</div>
</div> </div>
</template> </template>
<script> <script>
import Table from '@/components/Table';
import Navbar from '@/components/Navbar'; import Navbar from '@/components/Navbar';
import Cards from '@/components/Cards';
import { mapState } from 'vuex'; import { mapState } from 'vuex';
export default { export default {
name: 'app', name: 'app',
components: { Navbar, Table, Cards }, components: { Navbar },
computed: mapState(['loadedItems', 'layout']) computed: mapState(['loadedItems', 'layout'])
}; };
</script> </script>

View file

@ -28,11 +28,11 @@
</div> </div>
</div> </div>
<div class="col-lg-9 col-xl-8"> <div class="col-lg-9 col-xl-8">
<transition-group name="card-list" tag="div" class="card-columns"> <div class="card-columns">
<div class="card-list-item card bg-dark text-light" v-for="item in internalItems" :key="item[keyName]"> <div class="card-list-item card bg-dark text-light" v-for="item in internalItems" :key="item[keyName]">
<slot v-bind:item="item"/> <slot v-bind:item="item"/>
</div> </div>
</transition-group> </div>
</div> </div>
</div> </div>
</template> </template>
@ -48,14 +48,3 @@ export default {
} }
}; };
</script> </script>
<style>
.card-list-enter, .card-list-leave-to {
opacity: 0;
}
.card-list-leave-active {
position: absolute;
}
</style>

View file

@ -3,11 +3,11 @@
<div class="dropdown"> <div class="dropdown">
<button class="btn text-light dropdown-toggle btn-heading" type="button" id="dropdownMenuButton" <button class="btn text-light dropdown-toggle btn-heading" type="button" id="dropdownMenuButton"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ activeEvent.slug }} {{getEventSlug}}
</button> </button>
<div class="dropdown-menu bg-dark" aria-labelledby="dropdownMenuButton"> <div class="dropdown-menu bg-dark" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item text-light" href="#" v-for="(event, index) in events" v-bind:key="index" <a class="dropdown-item text-light" href="#" v-for="(event, index) in events" v-bind:key="index"
:class="{ active: event === activeEvent }" @click="changeEvent(event)">{{ event.slug }}</a> :class="{ active: event.slug === getEventSlug }" @click="changeEvent(event)">{{ event.slug }}</a>
</div> </div>
</div> </div>
@ -58,7 +58,7 @@
</template> </template>
<script> <script>
import { mapState, mapActions, mapMutations } from 'vuex'; import { mapState, mapActions, mapMutations, mapGetters} from 'vuex';
export default { export default {
@ -79,6 +79,7 @@ export default {
}), }),
computed: { computed: {
...mapState(['events', 'activeEvent', 'layout']), ...mapState(['events', 'activeEvent', 'layout']),
...mapGetters(['getEventSlug']),
}, },
methods: { methods: {
...mapActions(['changeEvent']), ...mapActions(['changeEvent']),

View file

@ -1,6 +1,8 @@
import Vue from 'vue'; import Vue from 'vue';
import App from './App.vue'; import App from './App.vue';
import store from './store'; import store from './store';
import router from './router';
import { sync } from 'vuex-router-sync';
// bootstrap // bootstrap
import 'jquery/dist/jquery.min.js'; import 'jquery/dist/jquery.min.js';
@ -12,12 +14,17 @@ import { library } from '@fortawesome/fontawesome-svg-core';
import { faPlus, faCheckCircle, faEdit, faTrash, faCat, faSyncAlt, faSort, faSortUp, faSortDown, faTh, faList, faWindowClose } from '@fortawesome/free-solid-svg-icons'; import { faPlus, faCheckCircle, faEdit, faTrash, faCat, faSyncAlt, faSort, faSortUp, faSortDown, faTh, faList, faWindowClose } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
library.add(faPlus, faCheckCircle, faEdit, faTrash, faCat, faSyncAlt, faSort, faSortUp, faSortDown, faTh, faList, faWindowClose); library.add(faPlus, faCheckCircle, faEdit, faTrash, faCat, faSyncAlt, faSort, faSortUp, faSortDown, faTh, faList, faWindowClose);
Vue.component('font-awesome-icon', FontAwesomeIcon); Vue.component('font-awesome-icon', FontAwesomeIcon);
sync(store, router);
new Vue({ new Vue({
el: '#app', el: '#app',
store, store,
router,
render: h => h(App), render: h => h(App),
}); });

18
src/router.js Normal file
View file

@ -0,0 +1,18 @@
import Items from './views/Items';
import VueRouter from 'vue-router';
import Vue from 'vue';
Vue.use(VueRouter);
const routes = [
{ path: '/:event', component: Items},
];
const router = new VueRouter({
mode: 'history',
routes
});
export default router;

View file

@ -1,16 +1,14 @@
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import axios from 'axios';
//import * as _ from 'lodash/fp';
import router from '../router';
Vue.use(Vuex); Vue.use(Vuex);
export default new Vuex.Store({ const store = new Vuex.Store({
state: { state: {
events: [ events: Array,
{'slug': '35C3'},
{'slug': 'camp19'},
{'slug': '36C3'}
],
activeEvent: {'slug': '36C3'},
layout: 'cards', layout: 'cards',
loadedItems: [ loadedItems: [
{ uid: 1, description: 'sleeping bag', box: 7, image: 41 }, { uid: 1, description: 'sleeping bag', box: 7, image: 41 },
@ -29,19 +27,55 @@ export default new Vuex.Store({
{ uid: 14, description: 'toy truck', box: 6, image: 51 } { uid: 14, description: 'toy truck', box: 6, image: 51 }
] ]
}, },
getters: {
getEventSlug: state => state.route.params.event,
},
mutations: { mutations: {
replaceEvents(state, events) {
state.events = events;
//if (!state.activeEvent || !events.includes(state.activeEvent))
// state.activeEvent = _.reverse(events)[0];
},
changeEvent(state, event) { changeEvent(state, event) {
state.activeEvent = event; router.push({path: `/${event.slug}`});
},
replaceLoadedItems(state, newItems) {
state.loadedItems = newItems;
}, },
setLayout(state, layout) { setLayout(state, layout) {
state.layout = layout; state.layout = layout;
} }
}, },
actions: { actions: {
changeEvent({ commit }, event) { async loadEvents({ commit }) {
// todo: load items from server const resp = await axios.get('https://c3lf.de/api/1/events', {
// todo: load items from server auth: {
commit('changeEvent', event); username: process.env.VUE_APP_CONFIG_API_USER,
password: process.env.VUE_APP_CONFIG_API_PASSWORD
}
});
commit('replaceEvents', resp.data);
},
changeEvent({ commit, dispatch }, eventName) {
commit('changeEvent', eventName);
dispatch('loadEventItems', eventName);
},
async loadEventItems({ commit, state }) {
const resp = await axios.get(`https://c3lf.de/api/1/${state.route.params.event}/items`, {
auth: {
username: process.env.VUE_APP_CONFIG_API_USER,
password: process.env.VUE_APP_CONFIG_API_PASSWORD
}
});
console.log(resp.data);
commit('replaceLoadedItems', resp.data);
} }
} }
}); });
export default store;
store.dispatch('loadEvents');

48
src/views/Items.vue Normal file
View file

@ -0,0 +1,48 @@
<template>
<div class="container-fluid px-xl-5 mt-3">
<div class="row" v-if="layout === 'table'">
<div class="col-xl-8 offset-xl-2">
<Table
:columns="['uid', 'description', 'box', 'image']"
:items="loadedItems"
:keyName="'uid'"
/>
</div>
</div>
<Cards
v-if="layout === 'cards'"
:columns="['uid', 'description', 'box', 'image']"
:items="loadedItems"
:keyName="'uid'"
v-slot="{ item }"
>
<img
:src="`https://picsum.photos/id/${item.image + 50}/200/200`"
alt="item"
class="card-img-top img-fluid"
>
<div class="card-body">
<h6 class="card-title">{{ item.description }}</h6>
<h6 class="card-subtitle text-secondary">uid: {{ item.uid }} box: {{ item.box }}</h6>
</div>
</Cards>
</div>
</template>
<script>
import Table from '@/components/Table';
import Cards from '@/components/Cards';
import { mapState } from 'vuex';
export default {
name: 'Items',
components: { Table, Cards },
created() {
console.log(this.$route.params.event);
},
computed: mapState(['loadedItems', 'layout']),
};
</script>
<style scoped>
</style>