From d8be7f09e4caf7246627dbfb47d7232f6a002de0 Mon Sep 17 00:00:00 2001 From: jedi Date: Sun, 23 Jun 2024 02:58:31 +0200 Subject: [PATCH] add frontend to manage shipping vouchers --- web/src/router.js | 5 ++ web/src/store.js | 55 +++++++++++++++++- web/src/views/Ticket.vue | 31 ++++++++-- web/src/views/admin/Admin.vue | 3 + web/src/views/admin/Shipping.vue | 99 ++++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+), 8 deletions(-) create mode 100644 web/src/views/admin/Shipping.vue diff --git a/web/src/router.js b/web/src/router.js index 3490bc3..7d756e8 100644 --- a/web/src/router.js +++ b/web/src/router.js @@ -15,6 +15,7 @@ import Empty from "@/views/Empty.vue"; import Events from "@/views/admin/Events.vue"; import AccessControl from "@/views/admin/AccessControl.vue"; import {default as BoxesAdmin} from "@/views/admin/Boxes.vue" +import Shipping from "@/views/admin/Shipping.vue"; const routes = [ {path: '/', redirect: '/37C3/items', meta: {requiresAuth: false}}, @@ -69,6 +70,10 @@ const routes = [ path: 'boxes/', name: 'admin_boxes', component: BoxesAdmin, meta: {requiresAuth: true, requiresPermission: 'delete_event'} }, + { + path: 'shipping/', name: 'shipping', component: Shipping, meta: + {requiresAuth: true, requiresPermission: 'delete_event'} + }, ] }, {path: '/user', name: 'user', component: Empty, meta: {requiresAuth: true}}, diff --git a/web/src/store.js b/web/src/store.js index 7ee6614..e07c9e0 100644 --- a/web/src/store.js +++ b/web/src/store.js @@ -6,7 +6,6 @@ import * as utf8 from 'utf8'; import {ticketStateColorLookup, ticketStateIconLookup, http} from "@/utils"; import sharedStatePlugin from "@/shared-state-plugin"; import persistentStatePlugin from "@/persistent-state-plugin"; -import {triggerRef} from "vue"; const store = createStore({ state: { @@ -20,6 +19,8 @@ const store = createStore({ users: [], groups: [], state_options: [], + shippingVouchers: [], + lastEvent: '37C3', lastUsed: {}, remember: false, @@ -40,12 +41,22 @@ const store = createStore({ users: 0, groups: 0, states: 0, + shippingVouchers: 0, }, persistent_loaded: false, shared_loaded: false, afterInitHandlers: [], showAddBoxModal: false, + + shippingVoucherTypes: { + '2kg-de': '2kg Paket (DE)', + '5kg-de': '5kg Paket (DE)', + '10kg-de': '10kg Paket (DE)', + '2kg-eu': '2kg Paket (EU)', + '5kg-eu': '5kg Paket (EU)', + '10kg-eu': '10kg Paket (EU)', + } }, getters: { route: state => router.currentRoute.value, @@ -75,6 +86,12 @@ const store = createStore({ } } }, + availableShippingVoucherTypes: state => { + return Object.keys(state.shippingVoucherTypes).map(key => { + var count = state.shippingVouchers.filter(voucher => voucher.type === key && voucher.issue_thread === null).length; + return {id: key, count: count, name: state.shippingVoucherTypes[key]}; + }); + }, layout: (state, getters) => { if (router.currentRoute.value.query.layout) return router.currentRoute.value.query.layout; @@ -139,7 +156,6 @@ const store = createStore({ updateTicket(state, updatedTicket) { const ticket = state.tickets.filter(({id}) => id === updatedTicket.id)[0]; Object.assign(ticket, updatedTicket); - //triggerRef(state.tickets); state.tickets = [...state.tickets]; }, replaceUsers(state, users) { @@ -198,6 +214,10 @@ const store = createStore({ setThumbnail(state, {url, data}) { state.thumbnailCache[url] = data; }, + setShippingVouchers(state, codes) { + state.shippingVouchers = codes; + state.fetchedData = {...state.fetchedData, shippingVouchers: Date.now()}; + }, }, actions: { async login({commit}, {username, password, remember}) { @@ -412,6 +432,33 @@ const store = createStore({ async updateTicketPartial({commit, state}, {id, ...ticket}) { const {data, success} = await http.patch(`/2/tickets/${id}/`, ticket, state.user.token); commit('updateTicket', data); + }, + async fetchShippingVouchers({commit, state}) { + if (!state.user.token) return; + if (state.fetchedData.shippingVouchers > Date.now() - 1000 * 60 * 60 * 24) return; + const {data, success} = await http.get('/2/shipping_vouchers/', state.user.token); + if (data && success) { + commit('setShippingVouchers', data); + } + }, + async createShippingVoucher({dispatch, state}, code) { + const {data, success} = await http.post('/2/shipping_vouchers/', code, state.user.token); + if (data && success) { + state.fetchedData.shippingVouchers = 0; + dispatch('fetchShippingVouchers'); + } + }, + async claimShippingVoucher({dispatch, state}, {ticket, shipping_voucher_type}) { + const id = state.shippingVouchers.filter(voucher => voucher.type === shipping_voucher_type && voucher.issue_thread === null)[0].id; + const { + data, + success + } = await http.patch(`/2/shipping_vouchers/${id}/`, {issue_thread: ticket}, state.user.token); + if (data && success) { + state.fetchedData.shippingVouchers = 0; + state.fetchedData.tickets = 0; + await Promise.all([dispatch('loadTickets'), dispatch('fetchShippingVouchers')]); + } } }, plugins: [ @@ -427,7 +474,7 @@ const store = createStore({ ] }), sharedStatePlugin({ - debug: true, + debug: false, isLoadedKey: "shared_loaded", clearingMutation: "logout", afterInit: "afterSharedInit", @@ -440,6 +487,7 @@ const store = createStore({ "groups", "loadedBoxes", "loadedItems", + "shippingVouchers", ], watch: [ "test", @@ -450,6 +498,7 @@ const store = createStore({ "groups", "loadedBoxes", "loadedItems", + "shippingVouchers", ], mutations: [ //"replaceTickets", diff --git a/web/src/views/Ticket.vue b/web/src/views/Ticket.vue index b4d1e0e..e92fb8e 100644 --- a/web/src/views/Ticket.vue +++ b/web/src/views/Ticket.vue @@ -13,10 +13,6 @@ Delete - - - Copy DHL contact to clipboard -
+ + + +
+ @@ -41,15 +55,21 @@ + + \ No newline at end of file