aboutsummaryrefslogtreecommitdiff
path: root/src/components/item_selector.vue
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/item_selector.vue')
-rw-r--r--src/components/item_selector.vue176
1 files changed, 176 insertions, 0 deletions
diff --git a/src/components/item_selector.vue b/src/components/item_selector.vue
new file mode 100644
index 0000000..5dc9b84
--- /dev/null
+++ b/src/components/item_selector.vue
@@ -0,0 +1,176 @@
+<script setup lang="ts">
+import { ref, toRaw, onMounted } from 'vue'
+import axios from 'axios'
+import { useToast } from 'vue-toast-notification'
+import InvoiceItem from "./../classes/invoice_item"
+
+const props = defineProps(["invoiceId"])
+const emit = defineEmits(["added"])
+
+const toast = useToast({
+ position: 'top-right'
+})
+
+const gettingData = ref(true) // for when getting all item(s)
+const submitting = ref(false) // shows spinner on add button
+const allItems = ref([])
+
+const item = ref(new InvoiceItem())
+const itemSelection = ref(null)
+
+const getAllItems = async () => {
+ allItems.value = []
+ gettingData.value = true
+
+ try {
+ const r = await axios.get('/item')
+ if (r.status === 200) {
+ allItems.value = r.data.data
+ } else if (r.status === 204) {
+ toast.warning('No items found')
+ }
+ } catch (err) {
+ toast.error('An unhandled exception occoured. Please check logs')
+ console.error(err)
+ }
+
+ gettingData.value = false
+}
+
+const submit = async (e: Event) => {
+ e.preventDefault()
+ submitting.value = true
+
+ try {
+ await axios.post(`/invoice/${props.invoiceId}/item`, toRaw(item.value))
+ itemSelection.value = null
+ item.value = new InvoiceItem()
+ emit("added")
+ } catch (err: any) {
+ const statusCode: any = err.request.status
+ const res: any = JSON.parse(err.request.response)
+
+ switch (statusCode) {
+ case 400:
+ toast.error(res.error)
+ break
+ case 409:
+ toast.error(res.error)
+ break
+ default:
+ console.error(err)
+ toast.error('An unhandled exception occoured. Please check logs')
+ }
+ }
+
+ submitting.value = false
+}
+
+// when item is selected,
+// set item to the newly selected item
+const itemSelected = async () => {
+ const is: any = toRaw(itemSelection.value)
+ const i = new InvoiceItem()
+ i.Name = is.Name
+ i.Description = is.Description
+ i.HSN = is.HSN
+ i.UnitPrice = is.UnitPrice
+ i.GSTPercentage = is.GSTPercentage
+ i.UnitOfMeasure = is.UnitOfMeasure
+ i.BrandName = is.Brand.Name
+ i.Quantity = "1"
+
+ item.value = i
+}
+
+onMounted(() => {
+ getAllItems()
+})
+</script>
+
+<template>
+ <form class="row g-3" v-on:submit="submit">
+ <div class="col-md-1"><!-- spacer --></div>
+
+ <div class="col-md-3">
+ <label for="item-brand-input" class="form-label">Item</label>
+ <select
+ v-model="itemSelection"
+ @change="itemSelected()"
+ class="form-select"
+ aria-label="Select Item"
+ id="item-input"
+ >
+ <option selected disabled value="null">Select Item</option>
+ <option v-for="item in allItems" :value="item" :key="item['id']">
+ {{ item["Name"] }} ({{ item["Brand"]["Name"] }})
+ </option>
+ </select>
+ </div>
+
+ <div class="col-md-3">
+ <label for="inputDescription" class="form-label">Description</label>
+ <input
+ type="text"
+ class="form-control"
+ id="inputDescription"
+ v-model="item.Description"
+ />
+ </div>
+
+ <div class="col-md-1">
+ <label for="inputHSN" class="form-label">HSN</label>
+ <input
+ type="text"
+ class="form-control"
+ id="inputHSN"
+ v-model="item.HSN"
+ />
+ </div>
+
+ <div class="col-md-1">
+ <label for="inputQty" class="form-label">Quantity {{ item.UnitOfMeasure === "" ? "" : `(${item.UnitOfMeasure})` }}</label>
+ <input
+ type="text"
+ class="form-control"
+ id="inputQty"
+ v-model="item.Quantity"
+ />
+ </div>
+
+ <div class="col-md-1">
+ <label for="inputUnitPrice" class="form-label">Unit Price</label>
+ <input
+ type="text"
+ class="form-control"
+ id="inputUnitPrice"
+ v-model="item.UnitPrice"
+ />
+ </div>
+
+ <div class="col-md-1">
+ <label for="inputGST" class="form-label">GST (%)</label>
+ <input
+ type="text"
+ class="form-control"
+ id="inputGST"
+ v-model="item.GSTPercentage"
+ />
+ </div>
+
+ <div class="col-md-10"><!-- spacer --></div>
+
+ <div class="col-md-1 d-flex align-items-end justify-content-end">
+ <button
+ type="submit"
+ class="btn btn-primary btn-block"
+ :class="{ disabled: submitting || gettingData || itemSelection === null }"
+ >
+ Add
+ <div v-if="submitting" class="spinner-border spinner-border-sm ms-1" role="status">
+ <span class="sr-only"></span>
+ </div>
+ </button>
+ </div>
+ </form>
+</template>