Skip to content

Commit

Permalink
refactor(ContributionAssistant): Moved proof upload as first step
Browse files Browse the repository at this point in the history
  • Loading branch information
TTalex committed Nov 16, 2024
1 parent 3861825 commit 1ddd49e
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 114 deletions.
11 changes: 7 additions & 4 deletions src/components/ContributionAssistantDrawCanvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
default: null
}
},
emits: ['croppedImages'],
emits: ['croppedImages', 'loaded'],
data() {
return {
isDrawing: false,
Expand All @@ -30,9 +30,11 @@
rectangles: []
}
},
watch: {
image(newImage) {
newImage.onload = this.init
mounted() {
if (this.image.complete) {
this.init()
} else {
this.image.onload = this.init
}
},
methods: {
Expand All @@ -59,6 +61,7 @@
this.rectangles = [] // reset rectangles
this.drawRectangles(); // Draw previous rectangles after resizing
this.$emit('loaded')
},
startDrawing(event) {
if (event.type == "touchstart") {
Expand Down
164 changes: 54 additions & 110 deletions src/views/ContributionAssistant.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<v-container>
<v-tabs v-model="tab">
<v-tab value="LocationDate" :disabled="disableLocationDateTab">
1. Location & Date
<v-tab value="ProofSelect" :disabled="disableProofSelectTab">
1. Proof selection
</v-tab>
<v-tab value="Crop" :disabled="disableCropTab">
2. Image crop
Expand All @@ -15,51 +15,36 @@
</v-tab>
</v-tabs>
<v-tabs-window v-model="tab">
<v-tabs-window-item value="LocationDate">
<v-tabs-window-item value="ProofSelect">
<v-container>
<v-row>
<v-col cols="12" md="6">
<LocationInputRow :locationForm="locationForm" />
<ProofMetadataInputRow :proofMetadataForm="proofMetadataForm" />
<br>
<v-btn class="mt-4" color="success" :disabled="!locationForm.location_osm_id" @click="tab='Crop'">
Next
</v-btn>
<ProofInputRow :proofForm="proofForm" @proof="setProof($event)" />
</v-col>
</v-row>
</v-container>
</v-tabs-window-item>
<v-tabs-window-item value="Crop">
<v-container>
<v-row>
<v-col cols="12">
<h3 class="mb-4">
1. Select an image containing labels
</h3>
<ProofImageInputRow :hideProofImagePreview="true" :hideRecentProofChoice="false" @proof="setProof($event)" />
<p v-if="recentProof" class="mb-2">
<i>Selecting a recent proof has overwritten location, date and currency.</i>
</p>
</v-col>
</v-row>
<v-row>
<v-col cols="12" lg="6">
<h3 class="mb-4">
2. Draw squares around the labels
1. Draw squares around the labels
</h3>
<ContributionAssistantDrawCanvas ref="ContributionAssistantdrawCanvas" :image="image" @croppedImages="onCroppedImages($event)" />
<v-progress-circular v-if="!drawCanvasLoaded" indeterminate />
<ContributionAssistantDrawCanvas ref="ContributionAssistantdrawCanvas" :image="image" @croppedImages="onCroppedImages($event)" @loaded="drawCanvasLoaded = true" />
</v-col>
<v-col cols="12" lg="6">
<h3 class="mb-4">
3. Check the readability of labels
2. Check the readability of labels
</h3>
<ContributionAssistantCropImageList :croppedImages="croppedImages" @removeCrop="removeCrop($event)" />
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<h3 class="mb-4">
4. Send the cropped images for automatic processing
3. Send the cropped images for automatic processing
</h3>
<v-btn color="success" :disabled="!croppedImages.length" :loading="processCroppedImagesLoading" @click="processCroppedImages">
Process Cropped Images
Expand Down Expand Up @@ -88,11 +73,8 @@
type="info"
variant="outlined"
>
<p v-if="recentProof">
{{ productPriceForms.length }} price{{ productPriceForms.length > 1 ? 's' : '' }} will be added to an existing proof on the {{ recentProof.date }} at {{ locationName }}.
</p>
<p v-if="!recentProof">
1 proof and {{ productPriceForms.length }} price{{ productPriceForms.length > 1 ? 's' : '' }} will be added on the {{ proofMetadataForm.date }} at {{ locationName }}.
<p>
{{ productPriceForms.length }} price{{ productPriceForms.length > 1 ? 's' : '' }} will be added to an existing proof on the {{ proofForm.date }} at {{ locationName }}.
</p>
</v-alert>
<v-btn class="mt-4" color="success" :loading="addPricesLoading" @click="addPrices">
Expand All @@ -110,16 +92,6 @@
Please wait for upload
</h3>
<v-progress-linear
v-if="addProofLoading"
color="info"
height="25"
stripped
indeterminate
>
<strong>Uploading proof...</strong>
</v-progress-linear>
<v-progress-linear
v-if="!addProofLoading"
v-model="numberOfPricesAdded"
:max="productPriceForms.length"
:color="productPriceForms.length == numberOfPricesAdded ? 'success' : 'info'"
Expand All @@ -128,14 +100,14 @@
>
<strong>{{ numberOfPricesAdded }} / {{ productPriceForms.length }} prices added</strong>
</v-progress-linear>
<v-btn to="/dashboard" class="mt-4" :aria-label="$t('Common.Dashboard')" :disabled="addPricesLoading">
<v-btn to="/dashboard" class="mt-4" :aria-label="$t('Common.Dashboard')" :disabled="!allDone">
Go to your dashboard
</v-btn>
<v-btn v-if="recentProof" :to="'/proofs/' + recentProof.id" class="mt-4 ml-4" :disabled="addPricesLoading">
<v-btn :to="'/proofs/' + proofForm.id" class="mt-4 ml-4" :disabled="!allDone">
Go to proof
</v-btn>
<v-btn class="mt-4 ml-4" :disabled="addPricesLoading" @click="tab = 'Crop'">
Add a new image for location
<v-btn class="mt-4 ml-4" :disabled="!allDone" @click="reloadPage">
Add a new proof
</v-btn>
</v-col>
</v-row>
Expand All @@ -146,111 +118,96 @@
</template>

<script>
import Compressor from 'compressorjs'
import { defineAsyncComponent } from 'vue'
import { mapStores } from 'pinia'
import { useAppStore } from '../store'
import api from '../services/api'
import utils from '../utils.js'
import constants from '../constants'
export default {
components: {
ContributionAssistantPriceFormCard: defineAsyncComponent(() => import('../components/ContributionAssistantPriceFormCard.vue')),
LocationInputRow: defineAsyncComponent(() => import('../components/LocationInputRow.vue')),
ProofImageInputRow: defineAsyncComponent(() => import('../components/ProofImageInputRow.vue')),
ContributionAssistantDrawCanvas: defineAsyncComponent(() => import('../components/ContributionAssistantDrawCanvas.vue')),
ContributionAssistantCropImageList: defineAsyncComponent(() => import('../components/ContributionAssistantCropImageList.vue')),
ProofMetadataInputRow: defineAsyncComponent(() => import('../components/ProofMetadataInputRow.vue')),
ProofInputRow: defineAsyncComponent(() => import('../components/ProofInputRow.vue')),
},
data() {
return {
tab: 'LocationDate',
originalProofImage: null,
recentProof: null,
tab: 'ProofSelect',
drawCanvasLoaded: false,
image: new Image(),
croppedImages: [],
croppedBlobs: [],
productPriceForms : [],
locationForm: {
proofForm: {
type: constants.PROOF_TYPE_PRICE_TAG,
id: null,
location_id: null,
location_osm_id: null,
location_osm_type: null
},
proofMetadataForm: {
location_osm_type: null,
date: utils.currentDate(),
currency: null,
receipt_price_count: null,
receipt_price_total: null
receipt_price_total: null,
},
processCroppedImagesLoading: false,
addPricesLoading: false,
addProofLoading: false,
numberOfPricesAdded: 0
}
},
computed: {
...mapStores(useAppStore),
locationName() {
const recentLocations = this.appStore.getRecentLocations()
const location = recentLocations.find((location) => location.properties.osm_id === this.locationForm.location_osm_id)
const location = recentLocations.find((location) => location.properties.osm_id === this.proofForm.location_osm_id)
if (location) {
if (location.type === 'ONLINE') return location.website_url
return utils.getLocationOSMTitle(location, true, true, true)
}
return ''
},
disableLocationDateTab() {
// LocationDate tab should disabled during api calls to add prices
return this.addPricesLoading
disableProofSelectTab() {
// ProofSelect tab should disabled on summary step
return this.tab == "Summary"
},
disableCropTab() {
// Crop tab should only be enabled after the location is selected
// It should also be disabled during api calls to add prices
return !this.locationForm.location_osm_id || this.addPricesLoading
// Crop tab should only be enabled after the proof is selected
// It should also be disabled on summary step
return !this.proofForm.id || this.tab == "Summary"
},
disableCleanupTab() {
// Cleanup tab should only be enabled after the gemini analysis is done
// It should also be disabled during api calls to add prices
return !this.productPriceForms.length || this.addPricesLoading
// Cleanup tab should only be enabled after the ai analysis is done
// It should also be disabled on summary step
return !this.productPriceForms.length || this.tab == "Summary"
},
allDone() {
return this.numberOfPricesAdded > 0 && this.productPriceForms.length == this.numberOfPricesAdded
},
disableSummaryTab() {
// Summary tab should be enabled when there are product prices to be added and the add prices process is either running or done
const enableSummaryTab = this.productPriceForms.length && (this.addPricesLoading || this.productPriceForms.length == this.numberOfPricesAdded)
const enableSummaryTab = this.productPriceForms.length && (this.addPricesLoading || this.allDone)
return !enableSummaryTab
}
},
mounted() {
this.proofMetadataForm.currency = this.appStore.getUserLastCurrencyUsed
this.proofForm.currency = this.appStore.getUserLastCurrencyUsed
},
methods: {
reloadPage(){
window.location.reload()
},
setProof(event) {
if (event instanceof File) {
// A new file was selected
this.recentProof = null
this.originalProofImage = event
const reader = new FileReader()
reader.onload = (e) => {
const image = new Image()
image.src = e.target.result
this.image = image
};
reader.readAsDataURL(event)
} else {
// An existing proof was selected
this.recentProof = event
this.originalProofImage = null
const image = new Image()
image.src = `${import.meta.env.VITE_OPEN_PRICES_APP_URL}/img/${event.file_path}`
image.crossOrigin = 'Anonymous'
this.image = image
this.proofMetadataForm.date = event.date
this.proofMetadataForm.currency = event.currency
this.locationForm.location_osm_id = event.location_osm_id
this.locationForm.location_osm_type = event.location_osm_type
}
const image = new Image()
image.src = `${import.meta.env.VITE_OPEN_PRICES_APP_URL}/img/${event.file_path}`
image.crossOrigin = 'Anonymous'
this.image = image
this.proofForm = event
this.croppedImages = []
this.croppedBlobs = []
this.productPriceForms = []
this.tab = "Crop"
},
onCroppedImages(eventData) {
this.croppedImages = eventData[0]
Expand Down Expand Up @@ -299,19 +256,6 @@ export default {
this.addPricesLoading = true
this.numberOfPricesAdded = 0
this.tab = "Summary"
let proof = this.recentProof // Can be null if new proof
if (!proof) { // Implies an originalProofImage was set
this.addProofLoading = true
const proofImageCompressed = await new Promise((resolve, reject) => {
new Compressor(this.originalProofImage, {
success: resolve,
error: reject
})
})
proof = await api.createProof(proofImageCompressed, Object.assign({type: 'PRICE_TAG'}, this.locationForm, this.proofMetadataForm), this.$route.path)
this.addProofLoading = false
}
this.recentProof = proof
for (let i = 0; i < this.productPriceForms.length; i++) {
const productPriceForm = this.productPriceForms[i]
Expand All @@ -325,11 +269,11 @@ export default {
const priceData = {
...productPriceForm,
origins_tags: origins_tags,
date: proof.date,
location_id: proof.location_id,
location_osm_id: proof.location_osm_id,
location_osm_type: proof.location_osm_type,
proof_id: proof.id
date: this.proofForm.date,
location_id: this.proofForm.location_id,
location_osm_id: this.proofForm.location_osm_id,
location_osm_type: this.proofForm.location_osm_type,
proof_id: this.proofForm.id
}
// Cleanup unwanted fields for API
if (productPriceForm.mode == 'barcode') {
Expand Down

0 comments on commit 1ddd49e

Please sign in to comment.