feat: reconcile application vertical slices
Backfill the completed acquisitions, sales, dashboard, pricing, search, public detail, worker, migration, contracts, validation, tests, and implementation-status changes into one verified application slice.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
function requiredString(value, fieldName) {
|
||||
if (typeof value !== 'string') {
|
||||
if (typeof value !== "string") {
|
||||
throw new Error(`${fieldName} must be a string.`);
|
||||
}
|
||||
|
||||
@@ -7,16 +7,16 @@ function requiredString(value, fieldName) {
|
||||
}
|
||||
|
||||
export function normalizeSearchQuery(value) {
|
||||
return requiredString(value, 'Search query')
|
||||
return requiredString(value, "Search query")
|
||||
.trim()
|
||||
.normalize('NFKC')
|
||||
.replace(/[^\p{L}\p{N}\s]+/gu, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.normalize("NFKC")
|
||||
.replace(/[^\p{L}\p{N}\s]+/gu, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
export function createSearchQuery({
|
||||
query = '',
|
||||
query = "",
|
||||
category,
|
||||
conditionId,
|
||||
minPriceMinor,
|
||||
@@ -24,54 +24,68 @@ export function createSearchQuery({
|
||||
page = 1,
|
||||
limit = 20,
|
||||
includeSold = false,
|
||||
sort = 'recent',
|
||||
sort = "recent",
|
||||
}) {
|
||||
const text = normalizeSearchQuery(query);
|
||||
|
||||
if (!Number.isInteger(page) || page < 1) {
|
||||
throw new Error('page must be >= 1');
|
||||
throw new Error("page must be >= 1");
|
||||
}
|
||||
|
||||
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
||||
throw new Error('limit must be between 1 and 100');
|
||||
}
|
||||
|
||||
if (typeof minPriceMinor !== 'undefined' && (!Number.isInteger(minPriceMinor) || minPriceMinor < 0)) {
|
||||
throw new Error('minPriceMinor must be a non-negative integer');
|
||||
}
|
||||
|
||||
if (typeof maxPriceMinor !== 'undefined' && (!Number.isInteger(maxPriceMinor) || maxPriceMinor < 0)) {
|
||||
throw new Error('maxPriceMinor must be a non-negative integer');
|
||||
throw new Error("limit must be between 1 and 100");
|
||||
}
|
||||
|
||||
if (
|
||||
typeof minPriceMinor !== 'undefined' &&
|
||||
typeof maxPriceMinor !== 'undefined' &&
|
||||
minPriceMinor > maxPriceMinor
|
||||
typeof minPriceMinor !== "undefined" &&
|
||||
(!Number.isInteger(minPriceMinor) || minPriceMinor < 0)
|
||||
) {
|
||||
throw new Error('minPriceMinor must be <= maxPriceMinor');
|
||||
throw new Error("minPriceMinor must be a non-negative integer");
|
||||
}
|
||||
|
||||
if (!['recent', 'price_low', 'price_high'].includes(sort)) {
|
||||
throw new Error('sort must be recent, price_low, or price_high');
|
||||
if (
|
||||
typeof maxPriceMinor !== "undefined" &&
|
||||
(!Number.isInteger(maxPriceMinor) || maxPriceMinor < 0)
|
||||
) {
|
||||
throw new Error("maxPriceMinor must be a non-negative integer");
|
||||
}
|
||||
|
||||
if (
|
||||
typeof minPriceMinor !== "undefined" &&
|
||||
typeof maxPriceMinor !== "undefined" &&
|
||||
minPriceMinor > maxPriceMinor
|
||||
) {
|
||||
throw new Error("minPriceMinor must be <= maxPriceMinor");
|
||||
}
|
||||
|
||||
if (!["recent", "price_low", "price_high"].includes(sort)) {
|
||||
throw new Error("sort must be recent, price_low, or price_high");
|
||||
}
|
||||
|
||||
return {
|
||||
text,
|
||||
...(typeof category === 'string' && category.trim().length > 0 ? { category: category.trim() } : {}),
|
||||
...(typeof conditionId === 'string' && conditionId.trim().length > 0 ? { conditionId: conditionId.trim() } : {}),
|
||||
...(typeof minPriceMinor === 'number' ? { minPriceMinor } : {}),
|
||||
...(typeof maxPriceMinor === 'number' ? { maxPriceMinor } : {}),
|
||||
...(typeof category === "string" && category.trim().length > 0
|
||||
? { category: category.trim() }
|
||||
: {}),
|
||||
...(typeof conditionId === "string" && conditionId.trim().length > 0
|
||||
? { conditionId: conditionId.trim() }
|
||||
: {}),
|
||||
...(typeof minPriceMinor === "number" ? { minPriceMinor } : {}),
|
||||
...(typeof maxPriceMinor === "number" ? { maxPriceMinor } : {}),
|
||||
page,
|
||||
limit,
|
||||
includeSold,
|
||||
...(sort !== 'recent' ? { sort } : {}),
|
||||
...(sort !== "recent" ? { sort } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildSearchFilters({ includeSold = false, status = 'AVAILABLE', sort = ['recently_added'] }) {
|
||||
export function buildSearchFilters({
|
||||
includeSold = false,
|
||||
status = "AVAILABLE",
|
||||
sort = ["recently_added"],
|
||||
}) {
|
||||
return {
|
||||
status: includeSold ? 'ALL' : status,
|
||||
status: includeSold ? "ALL" : status,
|
||||
includeSold,
|
||||
sort,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user