From 01fbae4fec2dd894c3d11cb1f5d531b813264e84 Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Wed, 25 Jan 2023 19:01:58 +0200 Subject: [PATCH] changes --- package-lock.json | 72 ++++++++ package.json | 4 + src/components/house-planner/HousePlanner.vue | 3 + src/enums/item-type.enum.ts | 14 ++ src/enums/storage-set-type.enum.ts | 11 ++ src/enums/storage-type.enum.ts | 14 ++ src/enums/transaction-type.enum.ts | 8 + src/interfaces/storage.interfaces.ts | 61 ++++++- src/interfaces/user.interfaces.ts | 7 + src/utils/is-storage-set.ts | 8 + src/utils/jfetch.ts | 4 +- src/views/building/floors/FloorView.vue | 171 ++++++++++++------ src/views/building/floors/ItemSelector.vue | 94 ++++++++++ src/views/building/floors/RoomPolygon.vue | 18 +- src/views/building/floors/StorageBubble.vue | 15 +- vite.config.ts | 6 +- 16 files changed, 438 insertions(+), 72 deletions(-) create mode 100644 src/enums/item-type.enum.ts create mode 100644 src/enums/storage-set-type.enum.ts create mode 100644 src/enums/storage-type.enum.ts create mode 100644 src/enums/transaction-type.enum.ts create mode 100644 src/utils/is-storage-set.ts create mode 100644 src/views/building/floors/ItemSelector.vue diff --git a/package-lock.json b/package-lock.json index 1ef81b3..84783eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,8 @@ "@heroicons/vue": "^2.0.13", "@vueuse/core": "^9.10.0", "jwt-decode": "^3.1.2", + "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", "pinia": "^2.0.28", "sass": "^1.57.1", "vue": "^3.2.45", @@ -20,6 +22,8 @@ "devDependencies": { "@tailwindcss/forms": "^0.5.3", "@tailwindcss/line-clamp": "^0.4.2", + "@types/lodash.omit": "^4.5.7", + "@types/lodash.pick": "^4.4.7", "@vitejs/plugin-vue": "^4.0.0", "autoprefixer": "^10.4.13", "postcss": "^8.4.21", @@ -469,6 +473,30 @@ "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" } }, + "node_modules/@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, + "node_modules/@types/lodash.omit": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/@types/lodash.omit/-/lodash.omit-4.5.7.tgz", + "integrity": "sha512-6q6cNg0tQ6oTWjSM+BcYMBhan54P/gLqBldG4AuXd3nKr0oeVekWNS4VrNEu3BhCSDXtGapi7zjhnna0s03KpA==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/lodash.pick": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@types/lodash.pick/-/lodash.pick-4.4.7.tgz", + "integrity": "sha512-HgdyKz7/1+oeoVzbpu1XiX/Bti9AUksHtOILH38T07aKvqoirzcdOsrO2+Yg3L51Hv/8m1MetvHZEUGeABiTiQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/web-bluetooth": { "version": "0.0.16", "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", @@ -1220,6 +1248,16 @@ "node": ">=10" } }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" + }, + "node_modules/lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==" + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -2174,6 +2212,30 @@ "dev": true, "requires": {} }, + "@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, + "@types/lodash.omit": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/@types/lodash.omit/-/lodash.omit-4.5.7.tgz", + "integrity": "sha512-6q6cNg0tQ6oTWjSM+BcYMBhan54P/gLqBldG4AuXd3nKr0oeVekWNS4VrNEu3BhCSDXtGapi7zjhnna0s03KpA==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, + "@types/lodash.pick": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@types/lodash.pick/-/lodash.pick-4.4.7.tgz", + "integrity": "sha512-HgdyKz7/1+oeoVzbpu1XiX/Bti9AUksHtOILH38T07aKvqoirzcdOsrO2+Yg3L51Hv/8m1MetvHZEUGeABiTiQ==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/web-bluetooth": { "version": "0.0.16", "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", @@ -2724,6 +2786,16 @@ "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", "dev": true }, + "lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==" + }, "magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", diff --git a/package.json b/package.json index a602359..907e5c9 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,8 @@ "@heroicons/vue": "^2.0.13", "@vueuse/core": "^9.10.0", "jwt-decode": "^3.1.2", + "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", "pinia": "^2.0.28", "sass": "^1.57.1", "vue": "^3.2.45", @@ -21,6 +23,8 @@ "devDependencies": { "@tailwindcss/forms": "^0.5.3", "@tailwindcss/line-clamp": "^0.4.2", + "@types/lodash.omit": "^4.5.7", + "@types/lodash.pick": "^4.4.7", "@vitejs/plugin-vue": "^4.0.0", "autoprefixer": "^10.4.13", "postcss": "^8.4.21", diff --git a/src/components/house-planner/HousePlanner.vue b/src/components/house-planner/HousePlanner.vue index 6b9bbe7..7e046b5 100644 --- a/src/components/house-planner/HousePlanner.vue +++ b/src/components/house-planner/HousePlanner.vue @@ -131,6 +131,7 @@ const emit = defineEmits<{ boundingBox?: Vec2Box ): void; (e: 'edited'): void; + (e: 'zoom', scale: number): void; }>(); const localFloorDocument = ref(deepUnref(props.floorDocument)); @@ -258,6 +259,7 @@ const events: Record void> = { 'hpc:position': (e: CustomEvent) => { canvasPos.value = e.detail.position; canvasZoom.value = e.detail.zoom; + emit('zoom', e.detail.zoom); }, 'hpc:save': (e: CustomEvent) => { updateLocalDocument(); @@ -297,6 +299,7 @@ onMounted(() => { ); canvasPos.value = setPos; canvasZoom.value = setZoom; + emit('zoom', setZoom); Object.keys(events).forEach((event) => canvas.value.addEventListener(event, events[event]) diff --git a/src/enums/item-type.enum.ts b/src/enums/item-type.enum.ts new file mode 100644 index 0000000..67860af --- /dev/null +++ b/src/enums/item-type.enum.ts @@ -0,0 +1,14 @@ +export enum ItemType { + ITEM = 'ITEM', + OBJECT = 'OBJECT', + TECHNOLOGY = 'TECHNOLOGY', + TOOL = 'TOOL', + FOOD = 'FOOD', + MEDICINE = 'MEDICINE', + ART = 'ART', + CRAFT = 'CRAFT', + COMPOSITION = 'COMPOSITION', + CLOTHING = 'CLOTHING', + SERVICE = 'SERVICE', + OTHER = 'OTHER', +} diff --git a/src/enums/storage-set-type.enum.ts b/src/enums/storage-set-type.enum.ts new file mode 100644 index 0000000..3da457e --- /dev/null +++ b/src/enums/storage-set-type.enum.ts @@ -0,0 +1,11 @@ +export enum StorageSetType { + DRAWERS = 'DRAWERS', + SHELVES = 'SHELVES', + CUPBOARD = 'CUPBOARD', + CLOSET = 'CLOSET', + FRIDGE = 'FRIDGE', + FREEZER = 'FREEZER', + BOX = 'BOX', + BOXES = 'BOXES', + OTHER = 'OTHER', +} diff --git a/src/enums/storage-type.enum.ts b/src/enums/storage-type.enum.ts new file mode 100644 index 0000000..daf8735 --- /dev/null +++ b/src/enums/storage-type.enum.ts @@ -0,0 +1,14 @@ +export enum StorageType { + DRAWER = 'DRAWER', + SHELF = 'SHELF', + ASSEMBLY = 'ASSEMBLY', + CUPBOARD = 'CUPBOARD', + CLOSET = 'CLOSET', + FRIDGE = 'FRIDGE', + FREEZER = 'FREEZER', + TABLE = 'TABLE', + BOX = 'BOX', + VIRTUAL = 'VIRTUAL', + PERSON = 'PERSON', + OTHER = 'OTHER', +} diff --git a/src/enums/transaction-type.enum.ts b/src/enums/transaction-type.enum.ts new file mode 100644 index 0000000..df986cd --- /dev/null +++ b/src/enums/transaction-type.enum.ts @@ -0,0 +1,8 @@ +export enum TransactionType { + ACQUIRED = 'ACQUIRED', + SOLD = 'SOLD', + DESTROYED = 'DESTROYED', + BINNED = 'BINNED', + MOVED = 'MOVED', + TRANSFERRED = 'TRANSFERRED', +} diff --git a/src/interfaces/storage.interfaces.ts b/src/interfaces/storage.interfaces.ts index 4a16d2d..fe27ae2 100644 --- a/src/interfaces/storage.interfaces.ts +++ b/src/interfaces/storage.interfaces.ts @@ -1,11 +1,66 @@ -export interface StorageListItem { +import { ItemType } from '../enums/item-type.enum'; +import { StorageSetType } from '../enums/storage-set-type.enum'; +import { StorageType } from '../enums/storage-type.enum'; +import { TransactionType } from '../enums/transaction-type.enum'; +import { AddedBy } from './user.interfaces'; + +export interface StorageSharedType { id: number; displayName: string; - type: string; location: string; locationDescription: string; color: string; - itemCount: number; createdAt: string; updatedAt: string; } + +export interface StorageListItem extends StorageSharedType { + type: StorageType; + items?: StoredItem[]; + itemCount: number; +} + +export interface StorageSetListItem extends StorageSharedType { + type: StorageSetType; + storages: StorageListItem[]; +} + +export interface StorageItem { + id: number; + displayName: string; + type: ItemType; + barcode?: string; + consumable?: boolean; + image?: string; + weight?: number; + url?: string; + notes?: string; + public: boolean; + createdAt: string; + updatedAt: string; +} + +export interface StoredItemTransaction { + id: number; + type: TransactionType; + price?: number; + currency?: string; + notes?: string; + actionAt: string; + createdAt: string; + updatedAt: string; + actor?: AddedBy; +} + +export interface StoredItem { + id: number; + notes: string; + expiresAt?: string; + acquiredAt?: string; + consumedAt?: string; + item: StorageItem; + addedBy: AddedBy; + createdAt: string; + updatedAt: string; + transactions?: StoredItemTransaction[]; +} diff --git a/src/interfaces/user.interfaces.ts b/src/interfaces/user.interfaces.ts index ec4e35d..48c93ab 100644 --- a/src/interfaces/user.interfaces.ts +++ b/src/interfaces/user.interfaces.ts @@ -5,3 +5,10 @@ export interface User { picture?: string; color?: string; } + +export interface AddedBy { + sub: string; + name: string; + picture?: string; + color?: string; +} diff --git a/src/utils/is-storage-set.ts b/src/utils/is-storage-set.ts new file mode 100644 index 0000000..4f2d40c --- /dev/null +++ b/src/utils/is-storage-set.ts @@ -0,0 +1,8 @@ +import { + StorageSetListItem, + StorageSharedType, +} from '../interfaces/storage.interfaces'; + +export default function isSet(storage: StorageSharedType) { + return !!(storage as StorageSetListItem).storages; +} diff --git a/src/utils/jfetch.ts b/src/utils/jfetch.ts index 017d90d..62b2153 100644 --- a/src/utils/jfetch.ts +++ b/src/utils/jfetch.ts @@ -1,3 +1,5 @@ +import deepUnref from './deep-unref'; + export class JFetchResponse { constructor( public statusCode: number, @@ -24,7 +26,7 @@ export default async function jfetch( if (opts['body'] && typeof opts['body'] === 'object') { opts['body'] = JSON.stringify(opts['body']); opts['headers'] = { - ...(opts['headers'] || {}), + ...deepUnref(opts['headers'] || {}), 'Content-Type': 'application/json', }; } diff --git a/src/views/building/floors/FloorView.vue b/src/views/building/floors/FloorView.vue index 2aa57a9..22b0033 100644 --- a/src/views/building/floors/FloorView.vue +++ b/src/views/building/floors/FloorView.vue @@ -53,67 +53,67 @@ transparent headless :floor-document="floorDocument" - @click="clickOnRoom(undefined, $event)" + @click="clickOnRoom()" + @zoom="(newZoom) => (canvasZoom = newZoom)" > -
-
- -
- -
- -
-
+ + diff --git a/src/views/building/floors/RoomPolygon.vue b/src/views/building/floors/RoomPolygon.vue index ace72e4..56cf0cd 100644 --- a/src/views/building/floors/RoomPolygon.vue +++ b/src/views/building/floors/RoomPolygon.vue @@ -13,6 +13,7 @@ class="absolute" :style="roomPolygonCSS" @click.stop="clickOnRoom($event)" + @mousemove="moveOverRoom($event)" > {{ room.displayName @@ -27,14 +28,25 @@ import { RoomLayoutObject } from '../../../interfaces/room.interfaces'; const props = defineProps<{ room: RoomLayoutObject; + zoom: number; highlighted?: number; }>(); const emit = defineEmits<{ - (e: 'clickedIn', ev: MouseEvent): void; + (e: 'clickedIn', x: number, y: number): void; + (e: 'mouseMovedIn', x: number, y: number): void; }>(); - -const clickOnRoom = (ev: MouseEvent) => emit('clickedIn', ev); +const mouseCoordsFromEvent = (ev: MouseEvent): [number, number] => { + const rect = (ev.target as HTMLElement).getBoundingClientRect(); + return [ + (ev.clientX - rect.left) / props.zoom, + (ev.clientY - rect.top) / props.zoom, + ]; +}; +const clickOnRoom = (ev: MouseEvent) => + emit('clickedIn', ...mouseCoordsFromEvent(ev)); +const moveOverRoom = (ev: MouseEvent) => + emit('mouseMovedIn', ...mouseCoordsFromEvent(ev)); const roomPolygonCSS = computed(() => { if (!props.room) return {}; diff --git a/src/views/building/floors/StorageBubble.vue b/src/views/building/floors/StorageBubble.vue index 85d136b..cc318e9 100644 --- a/src/views/building/floors/StorageBubble.vue +++ b/src/views/building/floors/StorageBubble.vue @@ -12,15 +12,26 @@ +