Add phone number validation and auto-formatting to the correct international format

This commit is contained in:
Pieter Vander Vennet 2020-07-26 19:13:52 +02:00
parent 1372027dac
commit 887e049f2c
4 changed files with 90 additions and 9 deletions

View file

@ -16,7 +16,9 @@ import {RadioButton} from "../UI/Input/RadioButton";
import Translations from "../UI/i18n/Translations"; import Translations from "../UI/i18n/Translations";
import Locale from "../UI/i18n/Locale"; import Locale from "../UI/i18n/Locale";
import * as EmailValidator from 'email-validator'; import * as EmailValidator from 'email-validator';
import { parsePhoneNumberFromString } from 'libphonenumber-js' import {parsePhoneNumberFromString} from 'libphonenumber-js'
export class TagRenderingOptions implements TagDependantUIElementConstructor { export class TagRenderingOptions implements TagDependantUIElementConstructor {
@ -27,11 +29,16 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor {
"nat": (str) => str.indexOf(".") < 0 && !isNaN(Number(str)) && Number(str) > 0, "nat": (str) => str.indexOf(".") < 0 && !isNaN(Number(str)) && Number(str) > 0,
"float": (str) => !isNaN(Number(str)), "float": (str) => !isNaN(Number(str)),
"email": (str) => EmailValidator.validate(str), "email": (str) => EmailValidator.validate(str),
"phone": (str) => parsePhoneNumberFromString(str).isValid() "phone": (str, country) => {
return parsePhoneNumberFromString(str, country.toUpperCase())?.isValid() ?? false;
}
} }
public static formatting = { public static formatting = {
"phone": (str) => parsePhoneNumberFromString(str).formatInternational() "phone": (str, country) => {
console.log("country formatting", country)
return parsePhoneNumberFromString(str, country.toUpperCase()).formatInternational()
}
} }
/** /**
@ -352,8 +359,9 @@ class TagRendering extends UIElement implements TagDependantUIElement {
const prepost = Translations.W(freeform.template).InnerRender().split("$"); const prepost = Translations.W(freeform.template).InnerRender().split("$");
const type = prepost[1]; const type = prepost[1];
let isValid = TagRenderingOptions.inputValidation[type]; let isValid = TagRenderingOptions.inputValidation[type];
if(isValid === undefined){ if (isValid === undefined) {
console.log("Invalid type for field type", type) console.log("Invalid type for field type", type)
isValid = (str) => true; isValid = (str) => true;
} }
@ -364,10 +372,10 @@ class TagRendering extends UIElement implements TagDependantUIElement {
if (string === "" || string === undefined) { if (string === "" || string === undefined) {
return undefined; return undefined;
} }
if (!isValid(string)) { if (!isValid(string, this._source.data._country)) {
return undefined; return undefined;
} }
const tag = new Tag(freeform.key, formatter(string)); const tag = new Tag(freeform.key, formatter(string, this._source.data._country));
if (freeform.extraTags === undefined) { if (freeform.extraTags === undefined) {
return tag; return tag;

View file

@ -8,7 +8,7 @@ import {GeoOperations} from "./GeoOperations";
import {UIElement} from "../UI/UIElement"; import {UIElement} from "../UI/UIElement";
import {LayerDefinition} from "../Customizations/LayerDefinition"; import {LayerDefinition} from "../Customizations/LayerDefinition";
import {UserDetails} from "./OsmConnection"; import {UserDetails} from "./OsmConnection";
import codegrid from "codegrid-js";
/*** /***
* A filtered layer is a layer which offers a 'set-data' function * A filtered layer is a layer which offers a 'set-data' function
* It is initialized with a tagfilter. * It is initialized with a tagfilter.
@ -45,6 +45,8 @@ export class FilteredLayer {
private _selectedElement: UIEventSource<{ feature: any }>; private _selectedElement: UIEventSource<{ feature: any }>;
private _showOnPopup: (tags: UIEventSource<any>, feature: any) => UIElement; private _showOnPopup: (tags: UIEventSource<any>, feature: any) => UIElement;
private static readonly grid = codegrid.CodeGrid();
constructor( constructor(
layerDef: LayerDefinition, layerDef: LayerDefinition,
map: Basemap, storage: ElementStorage, map: Basemap, storage: ElementStorage,
@ -106,12 +108,23 @@ export class FilteredLayer {
// feature.properties contains all the properties // feature.properties contains all the properties
var tags = TagUtils.proprtiesToKV(feature.properties); var tags = TagUtils.proprtiesToKV(feature.properties);
if (this.filters.matches(tags)) { if (this.filters.matches(tags)) {
const centerPoint = GeoOperations.centerpoint(feature);
feature.properties["_surface"] = GeoOperations.surfaceAreaInSqMeters(feature); feature.properties["_surface"] = GeoOperations.surfaceAreaInSqMeters(feature);
const lat = centerPoint.geometry.coordinates[1];
const lon = centerPoint.geometry.coordinates[0]
feature.properties["_lon"] = lat;
feature.properties["_lat"] = lon;
FilteredLayer.grid.getCode(lat, lon, (error, code) => {
if (error === null) {
feature.properties["_country"] = code;
}
})
if (feature.geometry.type !== "Point") { if (feature.geometry.type !== "Point") {
if (this._wayHandling === LayerDefinition.WAYHANDLING_CENTER_AND_WAY) { if (this._wayHandling === LayerDefinition.WAYHANDLING_CENTER_AND_WAY) {
selfFeatures.push(GeoOperations.centerpoint(feature)); selfFeatures.push(centerPoint);
} else if (this._wayHandling === LayerDefinition.WAYHANDLING_CENTER_ONLY) { } else if (this._wayHandling === LayerDefinition.WAYHANDLING_CENTER_ONLY) {
feature = GeoOperations.centerpoint(feature); feature = centerPoint;
} }
} }
selfFeatures.push(feature); selfFeatures.push(feature);

47
package-lock.json generated
View file

@ -1939,6 +1939,10 @@
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true "dev": true
}, },
"codegrid-js": {
"version": "git://github.com/hlaw/codegrid-js.git#38decfe10dced9006c6b722cc403d7c1217abe98",
"from": "git://github.com/hlaw/codegrid-js.git"
},
"collection-visit": { "collection-visit": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@ -4188,6 +4192,12 @@
"object-visit": "^1.0.0" "object-visit": "^1.0.0"
} }
}, },
"marked": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/marked/-/marked-1.1.1.tgz",
"integrity": "sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw==",
"dev": true
},
"md5.js": { "md5.js": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@ -5075,6 +5085,16 @@
"ws": "^5.1.1" "ws": "^5.1.1"
} }
}, },
"parcel-plugin-static-files-copy": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/parcel-plugin-static-files-copy/-/parcel-plugin-static-files-copy-2.4.3.tgz",
"integrity": "sha512-tUZn54XsZIZ9hhhNQkyaWaHLvjOj2wra8pp4yPjp1b5p1frQ+YEwG6eaNtaQVyA+UvORsZg+Wni7n9gIOBE8eA==",
"dev": true,
"requires": {
"minimatch": "3.0.4",
"path": "0.12.7"
}
},
"parse-asn1": { "parse-asn1": {
"version": "5.1.5", "version": "5.1.5",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz",
@ -5112,6 +5132,33 @@
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
}, },
"path": {
"version": "0.12.7",
"resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
"integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=",
"dev": true,
"requires": {
"process": "^0.11.1",
"util": "^0.10.3"
},
"dependencies": {
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true
},
"util": {
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
"integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
"dev": true,
"requires": {
"inherits": "2.0.3"
}
}
}
},
"path-browserify": { "path-browserify": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",

View file

@ -3,9 +3,19 @@
"version": "0.0.1", "version": "0.0.1",
"description": "A small website to edit OSM easily", "description": "A small website to edit OSM easily",
"main": "index.js", "main": "index.js",
"staticFiles": {
"staticPath": [
{
"staticPath": "tiles",
"staticOutDir": "tiles/"
}
]
},
"scripts": { "scripts": {
"start": "parcel *.html UI/** Logic/** assets/**/* vendor/* vendor/*/*", "start": "parcel *.html UI/** Logic/** assets/**/* vendor/* vendor/*/*",
"generate": "ts-node createLayouts.ts",
"build": "rm -rf dist/ && parcel build --public-url ./ *.html assets/* assets/*/* vendor/* vendor/*/*", "build": "rm -rf dist/ && parcel build --public-url ./ *.html assets/* assets/*/* vendor/* vendor/*/*",
"clean": "./clean.sh",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"keywords": [ "keywords": [
@ -15,6 +25,7 @@
"author": "pietervdvn", "author": "pietervdvn",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"codegrid-js": "git://github.com/hlaw/codegrid-js.git",
"email-validator": "^2.0.4", "email-validator": "^2.0.4",
"jquery": "latest", "jquery": "latest",
"leaflet": "^1.6.0", "leaflet": "^1.6.0",
@ -29,6 +40,8 @@
"@babel/polyfill": "^7.10.4", "@babel/polyfill": "^7.10.4",
"@types/node": "^7.0.5", "@types/node": "^7.0.5",
"fs": "0.0.1-security", "fs": "0.0.1-security",
"marked": "^1.1.1",
"parcel-plugin-static-files-copy": "^2.4.3",
"promise-svg2img": "^0.2.0", "promise-svg2img": "^0.2.0",
"read-file": "^0.2.0", "read-file": "^0.2.0",
"typescript": "^3.9.7", "typescript": "^3.9.7",