Fix local startup defaults and add MVP tests
This commit is contained in:
106
web/src/lib/helpers.js
Normal file
106
web/src/lib/helpers.js
Normal file
@@ -0,0 +1,106 @@
|
||||
export function extractDomain(fromAddr) {
|
||||
const m = String(fromAddr || '').match(/@([A-Za-z0-9.-]+)/);
|
||||
return m ? m[1].toLowerCase() : '';
|
||||
}
|
||||
|
||||
export function extractFirstJobNumber(text) {
|
||||
const t = String(text || '');
|
||||
// heuristic: prefer 8+ digit job numbers (e.g., 0222600001)
|
||||
const m = t.match(/\b\d{8,}\b/);
|
||||
return m ? m[0] : '';
|
||||
}
|
||||
|
||||
export function validatePassword(pw) {
|
||||
const p = String(pw || '');
|
||||
if (p.length < 12) return 'Password must be at least 12 characters.';
|
||||
if (!/[A-Z]/.test(p)) return 'Password must include an uppercase letter.';
|
||||
if (!/[a-z]/.test(p)) return 'Password must include a lowercase letter.';
|
||||
if (!/\d/.test(p)) return 'Password must include a number.';
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function applyRulesToEmail(emailRow, rules) {
|
||||
const from = (emailRow.from_addr || '').toLowerCase();
|
||||
const subj = (emailRow.subject || '').toLowerCase();
|
||||
const body = (emailRow.body_text || '').toLowerCase();
|
||||
const thread = (emailRow.thread_key || '').toLowerCase();
|
||||
|
||||
for (const r of rules) {
|
||||
if (!r.enabled) continue;
|
||||
const v = (r.match_value || '').toLowerCase();
|
||||
let hit = false;
|
||||
if (r.match_type === 'from_domain') {
|
||||
hit = v && from.includes('@') && from.split('@').pop()?.includes(v.replace(/^@/, ''));
|
||||
} else if (r.match_type === 'from_contains') {
|
||||
hit = v && from.includes(v);
|
||||
} else if (r.match_type === 'subject_contains') {
|
||||
hit = v && subj.includes(v);
|
||||
} else if (r.match_type === 'body_contains') {
|
||||
hit = v && body.includes(v);
|
||||
} else if (r.match_type === 'thread_key') {
|
||||
hit = v && thread && thread === v;
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
return { projectId: r.project_id, confidence: 0.9, ruleId: r.id };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function buildPCOBody(email, project) {
|
||||
return [
|
||||
`# Potential Change Order (PCO) — Draft`,
|
||||
``,
|
||||
`**Project:** ${project?.name || ''}`,
|
||||
`**Job #:** ${project?.job_number || ''}`,
|
||||
`**Source email:** ${email?.subject || ''} (${email?.id || ''})`,
|
||||
`**From:** ${email?.from_addr || ''}`,
|
||||
`**Date:** ${email?.date || ''}`,
|
||||
``,
|
||||
`## Description / Change event`,
|
||||
`- (Describe what changed and why)`,
|
||||
``,
|
||||
`## Contract / drawing references`,
|
||||
`- (Sheet/spec refs)`,
|
||||
``,
|
||||
`## Cost / schedule impact`,
|
||||
`- Labor:`,
|
||||
`- Material:`,
|
||||
`- Equipment:`,
|
||||
`- Schedule impact:`,
|
||||
``,
|
||||
`## Supporting info`,
|
||||
`- Email excerpt:`,
|
||||
``,
|
||||
`> ${String(email?.body_text || '').slice(0, 1200).replace(/\n/g, '\n> ')}`
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
export function buildRFIBody(email, project) {
|
||||
return [
|
||||
`# RFI — Draft`,
|
||||
``,
|
||||
`**Project:** ${project?.name || ''}`,
|
||||
`**Job #:** ${project?.job_number || ''}`,
|
||||
`**Source email:** ${email?.subject || ''} (${email?.id || ''})`,
|
||||
`**From:** ${email?.from_addr || ''}`,
|
||||
`**Date:** ${email?.date || ''}`,
|
||||
``,
|
||||
`## Question`,
|
||||
`- (Write the question clearly)`,
|
||||
``,
|
||||
`## Background`,
|
||||
`- (Why this is needed / conflict)`,
|
||||
``,
|
||||
`## Drawing/spec references`,
|
||||
`- (Sheet/detail/spec section)`,
|
||||
``,
|
||||
`## Proposed resolution (optional)`,
|
||||
`-`,
|
||||
``,
|
||||
`## Supporting excerpt`,
|
||||
`> ${String(email?.body_text || '').slice(0, 1200).replace(/\n/g, '\n> ')}`
|
||||
].join('\n');
|
||||
}
|
||||
Reference in New Issue
Block a user