populate events trough apicall and save active event in url
This commit is contained in:
parent
fbf6d9dc91
commit
cc9ba38dac
11 changed files with 137 additions and 61 deletions
2
.env.example
Normal file
2
.env.example
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
VUE_APP_CONFIG_API_USER=rest api user
|
||||||
|
VUE_APP_CONFIG_API_PASSWORD=rest api password
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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
2
API.md
|
@ -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>``
|
|
@ -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",
|
||||||
|
|
33
src/App.vue
33
src/App.vue
|
@ -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>
|
||||||
|
|
|
@ -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>
|
|
|
@ -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']),
|
||||||
|
|
|
@ -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
18
src/router.js
Normal 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;
|
|
@ -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
48
src/views/Items.vue
Normal 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>
|
Loading…
Reference in a new issue