Standardize phone number formatting in member service and MembersView
Integrated phone number standardization in the member service to ensure consistent formatting during member updates and contact creation. Added a new utility function in MembersView for phone number standardization, enhancing data integrity and user experience when adding or updating member information.
This commit is contained in:
@@ -8,6 +8,7 @@ import fs from 'fs';
|
||||
import sharp from 'sharp';
|
||||
|
||||
import { devLog } from '../utils/logger.js';
|
||||
import { standardizePhoneNumber } from '../utils/phoneUtils.js';
|
||||
class MemberService {
|
||||
async getApprovalRequests(userToken, clubId) {
|
||||
await checkAccess(userToken, clubId);
|
||||
@@ -93,7 +94,7 @@ class MemberService {
|
||||
member.city = city;
|
||||
if (postalCode !== undefined) member.postalCode = postalCode;
|
||||
member.birthDate = birthdate;
|
||||
member.phone = phone;
|
||||
member.phone = phone ? standardizePhoneNumber(phone) : phone;
|
||||
member.email = email;
|
||||
member.active = active;
|
||||
member.testMembership = testMembership;
|
||||
@@ -111,10 +112,15 @@ class MemberService {
|
||||
// Create new contacts
|
||||
for (const contact of contacts) {
|
||||
if (contact.value && contact.type) {
|
||||
// Standardisiere Telefonnummern
|
||||
let standardizedValue = contact.value;
|
||||
if (contact.type === 'phone') {
|
||||
standardizedValue = standardizePhoneNumber(contact.value);
|
||||
}
|
||||
await MemberContact.create({
|
||||
memberId: member.id,
|
||||
type: contact.type,
|
||||
value: contact.value,
|
||||
value: standardizedValue,
|
||||
isParent: contact.isParent || false,
|
||||
parentName: contact.parentName || null,
|
||||
isPrimary: contact.isPrimary || false
|
||||
@@ -130,7 +136,7 @@ class MemberService {
|
||||
city: city,
|
||||
postalCode: postalCode || null,
|
||||
birthDate: birthdate,
|
||||
phone: phone,
|
||||
phone: phone ? standardizePhoneNumber(phone) : phone,
|
||||
email: email,
|
||||
clubId: clubId,
|
||||
active: active,
|
||||
@@ -146,10 +152,15 @@ class MemberService {
|
||||
if (Array.isArray(contacts)) {
|
||||
for (const contact of contacts) {
|
||||
if (contact.value && contact.type) {
|
||||
// Standardisiere Telefonnummern
|
||||
let standardizedValue = contact.value;
|
||||
if (contact.type === 'phone') {
|
||||
standardizedValue = standardizePhoneNumber(contact.value);
|
||||
}
|
||||
await MemberContact.create({
|
||||
memberId: newMember.id,
|
||||
type: contact.type,
|
||||
value: contact.value,
|
||||
value: standardizedValue,
|
||||
isParent: contact.isParent || false,
|
||||
parentName: contact.parentName || null,
|
||||
isPrimary: contact.isPrimary || false
|
||||
|
||||
136
backend/utils/phoneUtils.js
Normal file
136
backend/utils/phoneUtils.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Standardisiert eine Telefonnummer im Format: 0179 - 12 34 56 7
|
||||
*
|
||||
* Die Vorwahl wird durch das erste Trennzeichen (Leerzeichen, Punkt, Bindestrich,
|
||||
* Unterstrich, Schrägstrich) zwischen Zahlen identifiziert.
|
||||
*
|
||||
* @param {string} phoneNumber - Die zu standardisierende Telefonnummer
|
||||
* @returns {string} - Die standardisierte Telefonnummer im Format "0179 - 12 34 56 7"
|
||||
*/
|
||||
function standardizePhoneNumber(phoneNumber) {
|
||||
if (!phoneNumber || typeof phoneNumber !== 'string') {
|
||||
return phoneNumber || '';
|
||||
}
|
||||
|
||||
// Trennzeichen, die die Vorwahl abkapseln können
|
||||
const separators = [' ', '.', '-', '_', '/'];
|
||||
|
||||
// Entferne alle Zeichen außer Zahlen und Trennzeichen
|
||||
let cleaned = phoneNumber.replace(/[^\d\s.\-_\/]/g, '');
|
||||
|
||||
// Extrahiere nur die Zahlen
|
||||
const digitsOnly = cleaned.replace(/[^\d]/g, '');
|
||||
|
||||
if (digitsOnly.length === 0) {
|
||||
return phoneNumber; // Falls keine Zahlen gefunden, Original zurückgeben
|
||||
}
|
||||
|
||||
// Finde das erste Trennzeichen zwischen Zahlen
|
||||
let areaCodeEndIndex = -1;
|
||||
for (let i = 0; i < cleaned.length - 1; i++) {
|
||||
if (separators.includes(cleaned[i])) {
|
||||
// Prüfe, ob vor und nach dem Trennzeichen eine Zahl steht
|
||||
const beforeIsDigit = i > 0 && /\d/.test(cleaned[i - 1]);
|
||||
const afterIsDigit = /\d/.test(cleaned[i + 1]);
|
||||
if (beforeIsDigit && afterIsDigit) {
|
||||
areaCodeEndIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let areaCode = '';
|
||||
let rest = '';
|
||||
|
||||
if (areaCodeEndIndex !== -1) {
|
||||
// Extrahiere die Vorwahl direkt aus dem String vor dem Trennzeichen
|
||||
const beforeSeparator = cleaned.substring(0, areaCodeEndIndex);
|
||||
areaCode = beforeSeparator.replace(/[^\d]/g, ''); // Nur Ziffern aus dem Teil vor dem Trennzeichen
|
||||
|
||||
// Prüfe, ob die Vorwahl plausibel ist (typische deutsche Vorwahlen: 3-5 Ziffern)
|
||||
// Wenn die Vorwahl zu lang ist (>=5 Ziffern) oder wenn nach dem Trennzeichen zu wenige Ziffern sind,
|
||||
// versuche eine kürzere Vorwahl
|
||||
if (digitsOnly.startsWith('0')) {
|
||||
const afterSeparator = cleaned.substring(areaCodeEndIndex + 1);
|
||||
const restDigits = afterSeparator.replace(/[^\d]/g, '');
|
||||
|
||||
// Wenn die Vorwahl >= 5 Ziffern hat oder wenn nach dem Trennzeichen zu wenige Ziffern sind (<6),
|
||||
// versuche eine kürzere Vorwahl
|
||||
if (areaCode.length >= 5 || (areaCode.length > 3 && restDigits.length < 6)) {
|
||||
// Versuche typische Vorwahl-Längen: 4 für Mobilnummern (01xx), 3 für Festnetz
|
||||
if (digitsOnly.substring(0, 2) === '01' && digitsOnly.length >= 4) {
|
||||
areaCode = digitsOnly.substring(0, 4);
|
||||
} else if (digitsOnly.length >= 3) {
|
||||
areaCode = digitsOnly.substring(0, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finde die Position der Vorwahl in digitsOnly und extrahiere den Rest
|
||||
// Die Vorwahl sollte am Anfang von digitsOnly stehen
|
||||
if (digitsOnly.startsWith(areaCode)) {
|
||||
rest = digitsOnly.substring(areaCode.length);
|
||||
} else {
|
||||
// Fallback: Wenn die Vorwahl nicht am Anfang steht, verwende die Länge
|
||||
rest = digitsOnly.substring(areaCode.length);
|
||||
}
|
||||
} else {
|
||||
// Kein Trennzeichen gefunden - versuche, die Vorwahl zu erraten
|
||||
// Typische deutsche Vorwahlen: 3-5 Ziffern (z.B. 0179, 030, 040)
|
||||
// Wenn die Nummer mit 0 beginnt, ist es wahrscheinlich eine Mobilnummer (4 Ziffern) oder Festnetz (3-5 Ziffern)
|
||||
if (digitsOnly.startsWith('0')) {
|
||||
// Mobilnummern beginnen meist mit 01 und haben 4 Ziffern Vorwahl
|
||||
if (digitsOnly.length >= 4 && digitsOnly.substring(0, 2) === '01') {
|
||||
areaCode = digitsOnly.substring(0, 4);
|
||||
rest = digitsOnly.substring(4);
|
||||
} else if (digitsOnly.length >= 3) {
|
||||
// Festnetz: 3-5 Ziffern, versuche 3 als Standard
|
||||
areaCode = digitsOnly.substring(0, 3);
|
||||
rest = digitsOnly.substring(3);
|
||||
} else {
|
||||
// Zu kurz, keine Vorwahl
|
||||
areaCode = '';
|
||||
rest = digitsOnly;
|
||||
}
|
||||
} else {
|
||||
// Keine führende 0 - wahrscheinlich keine Vorwahl oder internationale Nummer
|
||||
// Nehme die ersten 3-4 Ziffern als Vorwahl
|
||||
if (digitsOnly.length >= 4) {
|
||||
areaCode = digitsOnly.substring(0, 4);
|
||||
rest = digitsOnly.substring(4);
|
||||
} else {
|
||||
areaCode = '';
|
||||
rest = digitsOnly;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Formatiere den Rest in Zweierblöcke
|
||||
let formattedRest = '';
|
||||
for (let i = 0; i < rest.length; i += 2) {
|
||||
if (i > 0) {
|
||||
formattedRest += ' ';
|
||||
}
|
||||
// Wenn es die letzte Gruppe ist und nur eine Ziffer übrig ist, füge sie ohne Leerzeichen hinzu
|
||||
if (i + 2 >= rest.length) {
|
||||
formattedRest += rest.substring(i);
|
||||
break;
|
||||
} else {
|
||||
formattedRest += rest.substring(i, i + 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Kombiniere Vorwahl und Rest
|
||||
if (areaCode && formattedRest) {
|
||||
return `${areaCode} - ${formattedRest}`;
|
||||
} else if (areaCode) {
|
||||
return areaCode;
|
||||
} else if (formattedRest) {
|
||||
return formattedRest;
|
||||
} else {
|
||||
return phoneNumber; // Fallback: Original zurückgeben
|
||||
}
|
||||
}
|
||||
|
||||
export { standardizePhoneNumber };
|
||||
|
||||
@@ -643,6 +643,130 @@ export default {
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
},
|
||||
standardizePhoneNumber(phoneNumber) {
|
||||
if (!phoneNumber || typeof phoneNumber !== 'string') {
|
||||
return phoneNumber || '';
|
||||
}
|
||||
|
||||
// Trennzeichen, die die Vorwahl abkapseln können
|
||||
const separators = [' ', '.', '-', '_', '/'];
|
||||
|
||||
// Entferne alle Zeichen außer Zahlen und Trennzeichen
|
||||
let cleaned = phoneNumber.replace(/[^\d\s.\-_\/]/g, '');
|
||||
|
||||
// Extrahiere nur die Zahlen
|
||||
const digitsOnly = cleaned.replace(/[^\d]/g, '');
|
||||
|
||||
if (digitsOnly.length === 0) {
|
||||
return phoneNumber; // Falls keine Zahlen gefunden, Original zurückgeben
|
||||
}
|
||||
|
||||
// Finde das erste Trennzeichen zwischen Zahlen
|
||||
let areaCodeEndIndex = -1;
|
||||
for (let i = 0; i < cleaned.length - 1; i++) {
|
||||
if (separators.includes(cleaned[i])) {
|
||||
// Prüfe, ob vor und nach dem Trennzeichen eine Zahl steht
|
||||
const beforeIsDigit = i > 0 && /\d/.test(cleaned[i - 1]);
|
||||
const afterIsDigit = /\d/.test(cleaned[i + 1]);
|
||||
if (beforeIsDigit && afterIsDigit) {
|
||||
areaCodeEndIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let areaCode = '';
|
||||
let rest = '';
|
||||
|
||||
if (areaCodeEndIndex !== -1) {
|
||||
// Extrahiere die Vorwahl direkt aus dem String vor dem Trennzeichen
|
||||
const beforeSeparator = cleaned.substring(0, areaCodeEndIndex);
|
||||
areaCode = beforeSeparator.replace(/[^\d]/g, ''); // Nur Ziffern aus dem Teil vor dem Trennzeichen
|
||||
|
||||
// Prüfe, ob die Vorwahl plausibel ist (typische deutsche Vorwahlen: 3-5 Ziffern)
|
||||
// Wenn die Vorwahl zu lang ist (>=5 Ziffern) oder wenn nach dem Trennzeichen zu wenige Ziffern sind,
|
||||
// versuche eine kürzere Vorwahl
|
||||
if (digitsOnly.startsWith('0')) {
|
||||
const afterSeparator = cleaned.substring(areaCodeEndIndex + 1);
|
||||
const restDigits = afterSeparator.replace(/[^\d]/g, '');
|
||||
|
||||
// Wenn die Vorwahl >= 5 Ziffern hat oder wenn nach dem Trennzeichen zu wenige Ziffern sind (<6),
|
||||
// versuche eine kürzere Vorwahl
|
||||
if (areaCode.length >= 5 || (areaCode.length > 3 && restDigits.length < 6)) {
|
||||
// Versuche typische Vorwahl-Längen: 4 für Mobilnummern (01xx), 3 für Festnetz
|
||||
if (digitsOnly.substring(0, 2) === '01' && digitsOnly.length >= 4) {
|
||||
areaCode = digitsOnly.substring(0, 4);
|
||||
} else if (digitsOnly.length >= 3) {
|
||||
areaCode = digitsOnly.substring(0, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finde die Position der Vorwahl in digitsOnly und extrahiere den Rest
|
||||
// Die Vorwahl sollte am Anfang von digitsOnly stehen
|
||||
if (digitsOnly.startsWith(areaCode)) {
|
||||
rest = digitsOnly.substring(areaCode.length);
|
||||
} else {
|
||||
// Fallback: Wenn die Vorwahl nicht am Anfang steht, verwende die Länge
|
||||
rest = digitsOnly.substring(areaCode.length);
|
||||
}
|
||||
} else {
|
||||
// Kein Trennzeichen gefunden - versuche, die Vorwahl zu erraten
|
||||
// Typische deutsche Vorwahlen: 3-5 Ziffern (z.B. 0179, 030, 040)
|
||||
// Wenn die Nummer mit 0 beginnt, ist es wahrscheinlich eine Mobilnummer (4 Ziffern) oder Festnetz (3-5 Ziffern)
|
||||
if (digitsOnly.startsWith('0')) {
|
||||
// Mobilnummern beginnen meist mit 01 und haben 4 Ziffern Vorwahl
|
||||
if (digitsOnly.length >= 4 && digitsOnly.substring(0, 2) === '01') {
|
||||
areaCode = digitsOnly.substring(0, 4);
|
||||
rest = digitsOnly.substring(4);
|
||||
} else if (digitsOnly.length >= 3) {
|
||||
// Festnetz: 3-5 Ziffern, versuche 3 als Standard
|
||||
areaCode = digitsOnly.substring(0, 3);
|
||||
rest = digitsOnly.substring(3);
|
||||
} else {
|
||||
// Zu kurz, keine Vorwahl
|
||||
areaCode = '';
|
||||
rest = digitsOnly;
|
||||
}
|
||||
} else {
|
||||
// Keine führende 0 - wahrscheinlich keine Vorwahl oder internationale Nummer
|
||||
// Nehme die ersten 3-4 Ziffern als Vorwahl
|
||||
if (digitsOnly.length >= 4) {
|
||||
areaCode = digitsOnly.substring(0, 4);
|
||||
rest = digitsOnly.substring(4);
|
||||
} else {
|
||||
areaCode = '';
|
||||
rest = digitsOnly;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Formatiere den Rest in Zweierblöcke
|
||||
let formattedRest = '';
|
||||
for (let i = 0; i < rest.length; i += 2) {
|
||||
if (i > 0) {
|
||||
formattedRest += ' ';
|
||||
}
|
||||
// Wenn es die letzte Gruppe ist und nur eine Ziffer übrig ist, füge sie ohne Leerzeichen hinzu
|
||||
if (i + 2 >= rest.length) {
|
||||
formattedRest += rest.substring(i);
|
||||
break;
|
||||
} else {
|
||||
formattedRest += rest.substring(i, i + 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Kombiniere Vorwahl und Rest
|
||||
if (areaCode && formattedRest) {
|
||||
return `${areaCode} - ${formattedRest}`;
|
||||
} else if (areaCode) {
|
||||
return areaCode;
|
||||
} else if (formattedRest) {
|
||||
return formattedRest;
|
||||
} else {
|
||||
return phoneNumber; // Fallback: Original zurückgeben
|
||||
}
|
||||
},
|
||||
async addNewMember() {
|
||||
// Prepare contacts array
|
||||
const contacts = [];
|
||||
@@ -650,7 +774,7 @@ export default {
|
||||
if (phone.value && phone.value.trim()) {
|
||||
contacts.push({
|
||||
type: 'phone',
|
||||
value: phone.value.trim(),
|
||||
value: this.standardizePhoneNumber(phone.value.trim()),
|
||||
isParent: phone.isParent || false,
|
||||
parentName: phone.isParent ? (phone.parentName || null) : null,
|
||||
isPrimary: phone.isPrimary || false
|
||||
@@ -676,7 +800,7 @@ export default {
|
||||
city: this.newCity,
|
||||
postalCode: this.newPostalCode || null,
|
||||
birthdate: this.newBirthdate,
|
||||
phone: this.newPhone, // Keep for backward compatibility
|
||||
phone: this.newPhone ? this.standardizePhoneNumber(this.newPhone) : this.newPhone, // Keep for backward compatibility
|
||||
email: this.newEmail, // Keep for backward compatibility
|
||||
gender: this.newGender,
|
||||
active: this.newActive,
|
||||
|
||||
Reference in New Issue
Block a user