92 lines
2.1 KiB
JavaScript
92 lines
2.1 KiB
JavaScript
import { useState, useEffect } from "react";
|
|
import { useLocalStorage } from "../../useLocalStorage";
|
|
|
|
const TYPE_VIN = "vin";
|
|
|
|
/**
|
|
* Match VIN with RegEx
|
|
* @param {string} vin - potential VIN
|
|
* @returns {[boolean, string]}
|
|
*/
|
|
function parseVin(vin = "") {
|
|
const prefix = new RegExp(`^${TYPE_VIN}:`);
|
|
if (vin.match(prefix)) {
|
|
return [true, vin.replace(prefix, "")];
|
|
}
|
|
|
|
vin = vin.replace(/[^\p{L}\d]/gu, '');
|
|
|
|
var re = new RegExp("^[A-HJ-NPR-Z0-9]{8}[0-9X][A-HJ-NPR-Z0-9]{2}[0-9]{6}$");
|
|
return [vin.match(re), vin];
|
|
}
|
|
|
|
/**
|
|
* Convert a string into a QueryPart tuple.
|
|
* @typedef {"search" | "vin"} Type - the type of value represented
|
|
* @typedef {string} Value - the value
|
|
* @typedef {[Type, Value]} QueryPart - a tuple representing a substring of a query
|
|
* @param {string} part - substring of a query to turn into a QueryPart
|
|
* @returns {QueryPart}
|
|
*/
|
|
function parseQueryPart(part) {
|
|
let type = "search";
|
|
|
|
const [isVin, vin] = parseVin(part)
|
|
if (isVin) {
|
|
type = TYPE_VIN;
|
|
part = vin;
|
|
}
|
|
|
|
return [type, part];
|
|
}
|
|
|
|
export default function useQuery() {
|
|
const [query, setQuery] = useLocalStorage("VEHICLE_SEARCH", "");
|
|
const [parts, setParts] = useState([]);
|
|
const [payload, setPayload] = useState({});
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
setLoading(true);
|
|
let vins = [];
|
|
let search = "";
|
|
const parts = query.replaceAll(" ", ",").split(",").map(parseQueryPart);
|
|
setParts(parts);
|
|
|
|
parts.forEach(([type, value]) => {
|
|
if (type === "vin") {
|
|
vins.push(value);
|
|
}
|
|
|
|
if (type === "search") {
|
|
search = `${search} ${value}`.trim();
|
|
}
|
|
});
|
|
|
|
setQuery(() => parts.map(([type, part]) => {
|
|
if (type !== "search") {
|
|
return `${type}:${part}`;
|
|
}
|
|
|
|
return part;
|
|
}).join(" ").replace(/\s{2,}/g, ' ').trim());
|
|
|
|
setPayload({
|
|
search,
|
|
vins: vins.join(","),
|
|
})
|
|
}, [query, setPayload, setQuery]);
|
|
|
|
useEffect(() => {
|
|
setLoading(false);
|
|
}, [payload, setLoading])
|
|
|
|
return {
|
|
parts,
|
|
payload,
|
|
query,
|
|
setQuery,
|
|
loading,
|
|
}
|
|
}
|