Initial commit

Next.js + Express event management app for Hope Family Church.
This commit is contained in:
2026-07-23 15:26:47 +02:00
commit 3d381944d2
246 changed files with 57565 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
/** Levenshtein edit distance between two strings */
export function editDistance(a: string, b: string): number {
const m = a.length, n = b.length;
const dp: number[] = Array(n + 1).fill(0).map((_, j) => j);
for (let i = 1; i <= m; i++) {
let prev = dp[0];
dp[0] = i;
for (let j = 1; j <= n; j++) {
const temp = dp[j];
dp[j] = a[i - 1] === b[j - 1] ? prev : 1 + Math.min(prev, dp[j], dp[j - 1]);
prev = temp;
}
}
return dp[n];
}
/** Return a score 01 for how well a user matches a search query */
export function scoreUser(u: any, raw: string): number {
const q = raw.toLowerCase().trim();
if (!q || q.length < 2) return 0;
const name = (u.name || "").toLowerCase();
const email = (u.email || "").toLowerCase();
const phone = (u.phoneNumber || "").replace(/\D/g, "");
const qPhone = q.replace(/\D/g, "");
let best = 0;
// Exact substring matches — highest priority
if (name.includes(q)) best = Math.max(best, 1.0);
if (email.includes(q)) best = Math.max(best, 0.95);
if (qPhone.length >= 3 && phone.includes(qPhone)) best = Math.max(best, 0.95);
// Word-level starts-with (handles partial first/last name)
const words = name.split(/\s+/);
if (words.some((w: string) => w.startsWith(q))) best = Math.max(best, 0.85);
// Fuzzy edit-distance against each name word
const maxDist = q.length <= 4 ? 1 : q.length <= 7 ? 2 : 3;
for (const w of words) {
const slice = w.slice(0, q.length + 2); // compare against similar-length slice
const d = editDistance(q, slice);
if (d <= maxDist) best = Math.max(best, 0.75 - d * 0.15);
}
// Also fuzzy against the full name (catches "jhn smth" → "john smith")
const nameSlice = name.slice(0, q.length + 4);
const fullDist = editDistance(q, nameSlice);
if (fullDist <= maxDist + 1) best = Math.max(best, 0.6 - fullDist * 0.12);
return best;
}