diff --git a/frontend/src/router.js b/frontend/src/router.js index 79de8c5..6459e53 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -3,10 +3,11 @@ import Dashboard from '@/views/Dashboard.vue'; import Login from '@/views/Login.vue'; import Register from '@/views/Register.vue'; import store from '@/store'; -import Friends from "@/views/Friends.vue"; +import Friends from '@/views/Friends.vue'; import Inventory from '@/views/Inventory.vue'; -import InventoryDetail from "@/views/InventoryDetail.vue"; -import InventoryEdit from "./views/InventoryEdit.vue"; +import InventoryDetail from '@/views/InventoryDetail.vue'; +import InventoryNew from '@/views/InventoryNew.vue'; +import InventoryEdit from '@/views/InventoryEdit.vue'; const routes = [ @@ -14,6 +15,7 @@ const routes = [ {path: '/inventory', component: Inventory, meta: {requiresAuth: true}}, {path: '/inventory/:id', component: InventoryDetail, meta: {requiresAuth: true}, props: true}, {path: '/inventory/:id/edit', component: InventoryEdit, meta: {requiresAuth: true}, props: true}, + {path: '/inventory/new', component: InventoryNew, meta: {requiresAuth: true}}, {path: '/friends', component: Friends, meta: {requiresAuth: true}}, {path: '/login', component: Login, meta: {requiresAuth: false}}, {path: '/register', component: Register, meta: {requiresAuth: false}}, diff --git a/frontend/src/store.js b/frontend/src/store.js index 6d87356..0cadaff 100644 --- a/frontend/src/store.js +++ b/frontend/src/store.js @@ -160,6 +160,13 @@ export default createStore({ commit('setInventoryItems', {url: '/', items}) return items }, + async createInventoryItem({state, dispatch, getters}, item) { + const servers = await dispatch('getHomeServers') + const data = {availability_policy: 'private', ...item} + const reply = await servers.post(getters.signAuth, '/api/inventory_items/', data) + state.last_load.files = 0 + return reply + }, async updateInventoryItem({state, dispatch, getters}, item) { const servers = await dispatch('getHomeServers') const data = {availability_policy: 'friends', ...item} diff --git a/frontend/src/views/Inventory.vue b/frontend/src/views/Inventory.vue index 1a60922..8687fa6 100644 --- a/frontend/src/views/Inventory.vue +++ b/frontend/src/views/Inventory.vue @@ -7,8 +7,14 @@ <div class="card"> <div class="card-header"> <h5 class="card-title">{{ user }}'s Inventory</h5> + <button v-if="layout === 'grid'" @click="layout = 'table'" class="btn"> + <b-icon-list></b-icon-list> + </button> + <button v-else @click="layout = 'grid'" class="btn"> + <b-icon-grid></b-icon-grid> + </button> </div> - <table class="table table-striped"> + <table class="table table-striped" v-if="layout === 'table'"> <thead> <tr> <th style="width:40%;">Name</th> @@ -22,7 +28,9 @@ <td> <router-link :to="`/inventory/${item.id}`">{{ item.name }}</router-link> </td> - <td class="d-none d-md-table-cell">{{ item.availability_policy }}</td> + <td class="d-none d-md-table-cell"> + <span class="badge bg-secondary text-white">{{ item.availability_policy }}</span> + </td> <td class="d-none d-md-table-cell">{{ item.owned_quantity }}</td> <td class="table-action"> <router-link :to="`/inventory/${item.id}/edit`"> @@ -35,6 +43,36 @@ </tr> </tbody> </table> + <div class="card-body" v-else> + <div class="row"> + <div class="col-12 col-md-6 col-lg-4 col-xl-3" v-for="item in inventory_items" + :key="item.id"> + <div class="card"> + <img :src="item.image" class="card-img-top" :alt="item.image || '...'"> + <div class="card-body"> + <h5 class="card-title mb-0">{{ item.name }}</h5> + <div class="card-text text-black-50"> + <span class="badge bg-secondary text-white">{{ item.availability_policy }}</span> + <span class="float-right">{{ item.owned_quantity }}</span> + </div> + <div class="btn-group"> + <!--router-link :to="`/inventory/${item.id}`" + class="btn btn-primary btn-sm"> + View + </router-link> + <button class="btn btn-danger btn-sm" + @click="deleteInventoryItem(item.id)">Delete + </button> + <router-link :to="`/inventory/${item.id}/edit`" + class="btn btn-primary btn-sm">Edit + </router-link--> + </div> + </div> + </div> + </div> + </div> + </div> + </div> <div class="card"> <button class="btn" @click="fetchInventoryItems">Refresh</button> @@ -54,6 +92,11 @@ import BaseLayout from "@/components/BaseLayout.vue"; export default { name: "Inventory", + data() { + return { + layout: "grid", + } + }, components: { BaseLayout, ...BIcons diff --git a/frontend/src/views/InventoryNew.vue b/frontend/src/views/InventoryNew.vue new file mode 100644 index 0000000..9612642 --- /dev/null +++ b/frontend/src/views/InventoryNew.vue @@ -0,0 +1,98 @@ +<template> + <BaseLayout> + <main class="content"> + <div class="row"> + <div class="col"> + <div class="card"> + <div class="card-header">Create New Item</div> + <div class="card-body"> + <div class="mb-3"> + <label for="name" class="form-label">Name</label> + <input type="text" class="form-control" id="name" name="name" + placeholder="Enter item name" v-model="item.name"> + </div> + <div class="mb-3"> + <label for="description" class="form-label">Description</label> + <textarea class="form-control" id="description" name="description" + placeholder="Enter description" v-model="item.description"></textarea> + </div> + <div class="mb-3"> + <label for="tags" class="form-label">Tags</label> + <tag-field :value="item.tags"></tag-field> + </div> + <div class="mb-3"> + <label for="property" class="form-label">Property</label> + <property-field :value="item.properties"></property-field> + </div> + <div class="mb-3"> + <label for="quantity" class="form-label">Quantity</label> + <input type="number" class="form-control" id="quantity" name="quantity" + placeholder="Enter quantity" v-model="item.owned_quantity"> + </div> + <div class="mb-3"> + <label for="availablity_policy" class="form-label">Availablity Policy</label> + <select class="form-select" id="availablity_policy" name="availablity_policy" + v-model="item.availability_policy"> + <option v-for="policy in availability_policies" :value="policy.slug" + :selected="policy.slug === item.availability_policy"> + {{ policy.text }} + </option> + </select> + </div> + <div class="mb-3"> + <button type="submit" class="btn btn-primary" style="width: 100%" + @click="createInventoryItem(item).then(() => $router.push('/inventory'))">Add + </button> + </div> + </div> + </div> + </div> + </div> + </main> + </BaseLayout> +</template> + +<script> +import * as BIcons from "bootstrap-icons-vue"; +import {mapActions, mapState} from "vuex"; +import BaseLayout from "@/components/BaseLayout.vue"; +import TagField from "@/components/TagField.vue"; +import PropertyField from "@/components/PropertyField.vue"; + +export default { + name: "InventoryNew", + components: { + BaseLayout, + TagField, + PropertyField, + ...BIcons + }, + data() { + return { + item: { + name: "", + description: "", + owned_quantity: 0, + availability_policy: "", + image: "", + tags: [], + properties: [], + files: [] + } + } + }, + methods: { + ...mapActions(['createInventoryItem', 'fetchInfo']) + }, + computed: { + ...mapState(["availability_policies"]), + }, + async mounted() { + await this.fetchInfo(); + } +} +</script> + +<style scoped> + +</style> \ No newline at end of file