Add QR code error handling, mobile control enhancements, and POS flow updates:
- Added SweetAlert error notifications for untrusted QR codes in `LoginQR.vue`. - Updated `LoginForm.vue` to hide the QR code login button on desktop. - Enhanced POS mobile flow in `PosDepartmentStepMobileFlow.vue` with sound feedback for successful scans. - Implemented camera delay logic for improved capture management in `PosDepartmentStepMobile1.vue`. - Removed unused element in `PWADownload.vue` and adjusted geolocation visibility in `PosDepartmentStepMobile1Location.vue`.
This commit is contained in:
@@ -13,7 +13,7 @@ import PosDepartmentStep1MobileManualInput
|
||||
from "@/components/displays/department/pos/steps/mobile/views/PosDepartmentStep1MobileManualInput.vue";
|
||||
import PosDepartmentStepMobileButtonNextStep
|
||||
from "@/components/displays/department/pos/steps/mobile/elements/PosDepartmentStepMobileButtonNextStep.vue";
|
||||
import { manualInput, vehicles, camera } from "./objects/PosDepartmentStepMobileFlow.vue";
|
||||
import { manualInput, vehicles, camera, sounds } from "./objects/PosDepartmentStepMobileFlow.vue";
|
||||
import { PosSearchResult } from "./objects/PosSearchResult.vue";
|
||||
import RegistrationNumberSearchResult from "@/components/models/pos/step1/RegistrationNumberSearchResult.vue";
|
||||
import UnknownCustomer from "@/components/viewport/elements/icons/UnknownCustomer.vue";
|
||||
@@ -54,6 +54,10 @@ const handleLPRResult = () => {
|
||||
customerStatus: 'unknown'
|
||||
});
|
||||
if (searchResultIndex === vehicles.activeVehicleIndex.value) {
|
||||
// Only play the sound if the vehicle registration number is being set / changed.
|
||||
if (vehicles.getActiveVehicle()?.reg !== latestLPRResponse.value?.license_plate_number) {
|
||||
sounds.play(sounds.list.value.onAfterSuccessfulScan)
|
||||
}
|
||||
vehicles.select(searchResultIndex, {
|
||||
reg: latestLPRResponse.value?.license_plate_number || "",
|
||||
status: 'unknown'
|
||||
@@ -63,6 +67,11 @@ const handleLPRResult = () => {
|
||||
|
||||
|
||||
const parseImage = (image: string) => {
|
||||
// Check if the time since the last successful parse is enough
|
||||
if (!camera.hasDelayAfterSuccessPassed()) {
|
||||
console.log("Skipping parsing due to delay after success.");
|
||||
return;
|
||||
}
|
||||
if (lastParsedImage.value === image) {
|
||||
// If the image is the same as the last parsed one, skip parsing
|
||||
console.log("Skipping parsing for the same image.");
|
||||
@@ -79,6 +88,8 @@ const parseImage = (image: string) => {
|
||||
).then((response) => {
|
||||
latestLPRResponse.value = response.data.data as LPRResponse;
|
||||
console.log("LPR Response:", latestLPRResponse.value);
|
||||
// Set the last successful capture time
|
||||
camera.setLastSuccess();
|
||||
// Handle parsed result.
|
||||
handleLPRResult()
|
||||
|
||||
|
||||
+9
-7
@@ -26,17 +26,19 @@ watch(coords, (newCoords) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-show="false">
|
||||
<div v-show="true">
|
||||
<p>Latitude: {{ coords.latitude }}</p>
|
||||
<p>Longitude: {{ coords.longitude }}</p>
|
||||
<p>Located At: {{ new Date(locatedAt).toLocaleString() }}</p>
|
||||
<p v-if="error">Error: {{ error.message }}</p>
|
||||
<button @click="resume">Resume</button>
|
||||
<button @click="pause">Pause</button>
|
||||
<button @click="onUpdate({
|
||||
latitude: 55.613448,
|
||||
longitude: 12.495521
|
||||
})">Update Now</button>
|
||||
<template v-if="false">
|
||||
<button @click="resume">Resume</button>
|
||||
<button @click="pause">Pause</button>
|
||||
<button @click="onUpdate({
|
||||
latitude: 55.613448,
|
||||
longitude: 12.495521
|
||||
})">Update Now</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
+34
-3
@@ -459,8 +459,33 @@ const productList = {
|
||||
// Define the reactive properties
|
||||
const latestImage = ref<string | null>(null);
|
||||
const isCameraMounted = ref<boolean>(false);
|
||||
const cameraImageCaptureDelayInitial = ref<number>(3000); // Initial delay for camera image capture in milliseconds (First capture)
|
||||
const cameraImageCaptureDelaySubsequent = ref<number>(10000); // Further captures delay in milliseconds (Every capture after the first one)
|
||||
const cameraImageCaptureDelayInitial = ref<number>(2000); // Initial delay for camera image capture in milliseconds (First capture)
|
||||
const cameraImageCaptureDelaySubsequent = ref<number>(1000); // Further captures delay in milliseconds (Every capture after the first one)
|
||||
const cameraImageCaptureDelayAfterSuccess = ref<number>(5000); // Delay after a successful capture in milliseconds (After a successful capture, before the next one)
|
||||
const cameraImageCaptureLastSuccess = ref<number | null>(null); // Timestamp of the last successful capture
|
||||
|
||||
// Function to set the timestamp of the last successful capture
|
||||
const setCameraImageCaptureLastSuccess = (timestamp?: number | null) => {
|
||||
cameraImageCaptureLastSuccess.value = ( timestamp !== undefined ? timestamp : Date.now() );
|
||||
}
|
||||
// Function to get the timestamp of the last successful capture
|
||||
const getCameraImageCaptureLastSuccess = () => {
|
||||
return cameraImageCaptureLastSuccess.value;
|
||||
}
|
||||
// Function to get the delay after a successful capture
|
||||
const getCameraImageCaptureDelayAfterSuccess = () => {
|
||||
return cameraImageCaptureDelayAfterSuccess.value;
|
||||
}
|
||||
// Function to set the delay after a successful capture
|
||||
const setCameraImageCaptureDelayAfterSuccess = (delay: number) => {
|
||||
cameraImageCaptureDelayAfterSuccess.value = delay;
|
||||
}
|
||||
// Function to check if the delay after a successful capture has passed
|
||||
const hasCameraImageCaptureDelayAfterSuccessPassed = (): boolean => {
|
||||
if (cameraImageCaptureLastSuccess.value === null) return true; // No successful capture yet
|
||||
const currentTime = Date.now();
|
||||
return (currentTime - cameraImageCaptureLastSuccess.value) > cameraImageCaptureDelayAfterSuccess.value;
|
||||
}
|
||||
// Function to retrieve the latest image frame.
|
||||
const getLatestImage = async () => {
|
||||
return latestImage.value;
|
||||
@@ -503,7 +528,13 @@ const camera = {
|
||||
clearLatestImage,
|
||||
clearMounted: clearCameraMounted,
|
||||
getImageCaptureDelay: getCameraImageCaptureDelay,
|
||||
setImageCaptureDelay: setCameraImageCaptureDelay
|
||||
setImageCaptureDelay: setCameraImageCaptureDelay,
|
||||
// Capture delay after success functions
|
||||
getImageCaptureDelayAfterSuccess: getCameraImageCaptureDelayAfterSuccess,
|
||||
setImageCaptureDelayAfterSuccess: setCameraImageCaptureDelayAfterSuccess,
|
||||
setLastSuccess: setCameraImageCaptureLastSuccess,
|
||||
getLastSuccess: getCameraImageCaptureLastSuccess,
|
||||
hasDelayAfterSuccessPassed: hasCameraImageCaptureDelayAfterSuccessPassed,
|
||||
}
|
||||
|
||||
/** Metadata */
|
||||
|
||||
@@ -94,7 +94,7 @@ SessionUser.auth.reCAPTCHA.preCheck.get().then((response) => {
|
||||
<div class="control">
|
||||
<div class="buttons">
|
||||
<LoadButtonWhileAwait :loadFunction="login" class="button is-dark is-fullwidth" id="login-button">Login</LoadButtonWhileAwait>
|
||||
<LoadButtonWhileAwait :loadFunction="() => router.push('/login/qr')" class="button is-dark is-outlined is-fullwidth" id="qr-login-button">
|
||||
<LoadButtonWhileAwait :loadFunction="() => router.push('/login/qr')" class="button is-dark is-outlined is-fullwidth is-hidden-desktop" id="qr-login-button">
|
||||
<!-- QR code icon -->
|
||||
<span class="icon">
|
||||
<i class="fas fa-qrcode"></i>
|
||||
|
||||
@@ -9,6 +9,7 @@ import PosDepartmentStepMobileFixedBottomControl
|
||||
import { QrcodeStream, QrcodeDropZone, QrcodeCapture } from 'vue-qrcode-reader'
|
||||
import { sounds } from "@/components/displays/department/pos/steps/mobile/objects/PosDepartmentStepMobileFlow.vue";
|
||||
import PageLoader from "@/components/global/PageLoader.vue";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
const isProcessingQRCode = ref(false); // State to indicate if QR code is being processed
|
||||
const playCaptureSound = () => {
|
||||
@@ -52,6 +53,11 @@ const isValidUrl = (string: string) => {
|
||||
// Check if the url is from the same origin
|
||||
if (!string.startsWith(window.location.origin)) {
|
||||
console.log("URL is not from the same origin:", string, window.location.origin);
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Untrusted QR Code',
|
||||
text: 'The scanned QR code is not from a trusted source.',
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// Check if the url contains the token parameter
|
||||
|
||||
@@ -113,7 +113,6 @@ onUnmounted(() => {
|
||||
<span v-if="isInstalled">Pleno is installed</span>
|
||||
<span v-else-if="isInstallable">Install Pleno</span>
|
||||
<span v-else>Install Pleno through your browser menu</span>
|
||||
<span> Oh well </span>
|
||||
</a>
|
||||
</template>
|
||||
</WhiteBoxCard>
|
||||
|
||||
Reference in New Issue
Block a user