sahab-utils 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -10,10 +10,12 @@ export declare const CAR_REVIEW_QUEUES: readonly ["pending", "declined", "needs_
|
|
|
10
10
|
export type CarReviewQueue = (typeof CAR_REVIEW_QUEUES)[number];
|
|
11
11
|
/** An alias document counts toward this many per model, so a fix can find every key with one `in` query (Firestore allows 30). */
|
|
12
12
|
export declare const MAX_ALIASES = 29;
|
|
13
|
+
/** `ar` is the model's official Arabic name (`nameAr`); aliases are never shown to customers. */
|
|
13
14
|
export type CarPickerEntry = {
|
|
14
15
|
id: string;
|
|
15
16
|
name: string;
|
|
16
17
|
size: CarSize;
|
|
18
|
+
ar?: string;
|
|
17
19
|
};
|
|
18
20
|
/** `car_makes/{makeKey}`. `T` is the timestamp type of whichever Firestore SDK reads or writes it. */
|
|
19
21
|
export type CarMakeDoc<T = TimestampType> = {
|
|
@@ -31,6 +33,8 @@ export type CarModelDoc<T = TimestampType> = {
|
|
|
31
33
|
makeEn: string;
|
|
32
34
|
status: CarModelStatus;
|
|
33
35
|
name: string;
|
|
36
|
+
/** The one official Arabic name, set by staff. Other Arabic spellings are aliases and stay internal. */
|
|
37
|
+
nameAr?: string;
|
|
34
38
|
size: CarSize;
|
|
35
39
|
aliasKeys?: string[];
|
|
36
40
|
aliases?: string[];
|
|
@@ -55,6 +59,7 @@ export type CarQueueSort = (typeof CAR_QUEUE_SORTS)[number];
|
|
|
55
59
|
export type CarCatalogueEntry = {
|
|
56
60
|
modelId: string;
|
|
57
61
|
name: string;
|
|
62
|
+
nameAr?: string;
|
|
58
63
|
aliases: string[];
|
|
59
64
|
size: CarSize;
|
|
60
65
|
source: CarModelSource;
|
|
@@ -123,7 +128,10 @@ export declare function isCarVerified(car: Partial<Car> | undefined): boolean;
|
|
|
123
128
|
/** The active models of a make as the customer picker lists them: sorted by name, never an alias, pending or declined model. */
|
|
124
129
|
export declare function buildPicker(models: ({
|
|
125
130
|
id: string;
|
|
126
|
-
|
|
131
|
+
ar?: string;
|
|
132
|
+
} & Pick<CarModelDoc, 'status' | 'name' | 'size' | 'nameAr'>)[]): CarPickerEntry[];
|
|
133
|
+
/** An official Arabic name: trimmed, one line, at most `CAR_NAME_MAX_LENGTH` characters and written in Arabic. */
|
|
134
|
+
export declare const isValidArabicName: (value: unknown) => value is string;
|
|
127
135
|
/** The picker with one active model added, or replaced if it is already there. */
|
|
128
136
|
export declare function withPickerEntry(picker: CarPickerEntry[] | undefined, entry: CarPickerEntry): CarPickerEntry[];
|
|
129
137
|
/** Every key a model's cars may carry: its own and those of the aliases merged into it. */
|
package/dist/ts/carCatalogue.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PLATE_NUMBER_MAX = exports.PLATE_LETTERS_MAX = exports.CAR_CATALOGUE_INDEX_ID = exports.joinModelKey = exports.isCarSize = exports.CAR_SIZE_INFO = exports.CAR_QUEUE_SORTS = exports.MAX_ALIASES = exports.CAR_REVIEW_QUEUES = exports.CAR_MODEL_STATUSES = exports.CAR_NAME_MAX_LENGTH = exports.CAR_MODEL_MAX_LENGTH = void 0;
|
|
3
|
+
exports.PLATE_NUMBER_MAX = exports.PLATE_LETTERS_MAX = exports.CAR_CATALOGUE_INDEX_ID = exports.isValidArabicName = exports.joinModelKey = exports.isCarSize = exports.CAR_SIZE_INFO = exports.CAR_QUEUE_SORTS = exports.MAX_ALIASES = exports.CAR_REVIEW_QUEUES = exports.CAR_MODEL_STATUSES = exports.CAR_NAME_MAX_LENGTH = exports.CAR_MODEL_MAX_LENGTH = void 0;
|
|
4
4
|
exports.normalizeCarText = normalizeCarText;
|
|
5
5
|
exports.carModelKey = carModelKey;
|
|
6
6
|
exports.parseTypedCarModel = parseTypedCarModel;
|
|
@@ -80,9 +80,16 @@ function isCarVerified(car) {
|
|
|
80
80
|
function buildPicker(models) {
|
|
81
81
|
return models
|
|
82
82
|
.filter((model) => model.status === 'active')
|
|
83
|
-
.map(({ id, name, size }) =>
|
|
83
|
+
.map(({ id, name, size, nameAr, ar }) => {
|
|
84
|
+
const arabic = nameAr || ar;
|
|
85
|
+
return Object.assign({ id, name, size }, (arabic ? { ar: arabic } : {}));
|
|
86
|
+
})
|
|
84
87
|
.sort((a, b) => a.name.localeCompare(b.name) || a.id.localeCompare(b.id));
|
|
85
88
|
}
|
|
89
|
+
const ARABIC_LETTER = /[\u0600-\u06FF]/;
|
|
90
|
+
/** An official Arabic name: trimmed, one line, at most `CAR_NAME_MAX_LENGTH` characters and written in Arabic. */
|
|
91
|
+
const isValidArabicName = (value) => typeof value === 'string' && value === value.trim() && value.length > 0 && value.length <= exports.CAR_NAME_MAX_LENGTH && !/[\r\n]/.test(value) && ARABIC_LETTER.test(value);
|
|
92
|
+
exports.isValidArabicName = isValidArabicName;
|
|
86
93
|
/** The picker with one active model added, or replaced if it is already there. */
|
|
87
94
|
function withPickerEntry(picker, entry) {
|
|
88
95
|
return buildPicker([...(picker !== null && picker !== void 0 ? picker : []).filter((existing) => existing.id !== entry.id), entry].map((item) => (Object.assign(Object.assign({}, item), { status: 'active' }))));
|