added preferences to pull from user_preferences collection. seems to be working.

This commit is contained in:
2025-12-17 19:58:39 +00:00
parent 1d692ddb87
commit 560e30d93c
2 changed files with 121 additions and 15 deletions
+7 -1
View File
@@ -20,6 +20,12 @@
);
}
function getEmail() {
const model = pb.authStore.model || {};
// Prefer email, but fall back to username if email missing
return model.email || model.username || null;
}
async function ensureAuth() {
if (pb.authStore.isValid) return true;
const path = new URL(window.location.href).pathname;
@@ -29,5 +35,5 @@
return false;
}
global.Auth = { pb, authHeaders, ensureAuth, getDisplayName };
global.Auth = { pb, authHeaders, ensureAuth, getDisplayName, getEmail };
})(window);
+112 -12
View File
@@ -56,7 +56,10 @@
</div>
<div id="results" aria-live="polite" class="flex flex-col gap-3 flex-1 overflow-auto p-0"></div>
<div class="text-right text-xs text-gray-500 mt-5 pt-3 border-t border-gray-200"><span id="versionLabel">v1.0.0-beta2</span></div>
<div class="text-xs text-gray-500 mt-5 pt-3 border-t border-gray-200 flex items-center justify-between">
<span id="userEmail" class="truncate"></span>
<span id="versionLabel">v1.0.0-beta2</span>
</div>
</div>
<!-- Detail Modal -->
@@ -113,7 +116,7 @@
<script>
(async function() {
const { pb, authHeaders, ensureAuth, getDisplayName } = window.Auth;
const { pb, authHeaders, ensureAuth, getDisplayName, getEmail } = window.Auth;
const authed = await ensureAuth();
if (!authed) return;
@@ -124,6 +127,7 @@
};
const PB_COLLECTION_URL = "https://pocketbase.ccllc.pro/api/collections/pbc_1407612689/records";
const NOTES_COLLECTION_URL = "https://pocketbase.ccllc.pro/api/collections/notes/records";
const PREFS_COLLECTION_URL = "https://pocketbase.ccllc.pro/api/collections/user_preferences/records";
const perPage = 50;
// Notes relation handling: keep it simple; send the job id in a known field
// and avoid schema reads that may require elevated privileges.
@@ -143,6 +147,7 @@
const resultsEl = document.getElementById('results');
const filtersPanel = document.getElementById('filtersPanel');
const filterToggle = document.getElementById('filterToggle');
const userEmailEl = document.getElementById('userEmail');
const detailModal = document.getElementById('detailModal');
const detailTable = document.getElementById('detailTable');
@@ -163,6 +168,9 @@
return null;
};
const currentUserEmail = getEmail();
if(userEmailEl && currentUserEmail) userEmailEl.textContent = currentUserEmail;
// Load version from backend /version endpoint so UI matches package.json
async function loadVersion(){
if(!versionLabel) return;
@@ -195,7 +203,7 @@
async function fetchAllJobs(){
startProgress();
clearJobsCache('Loading…');
let page=1, totalItems=0; let firstBatchRendered=false;
let page=1, totalItems=0;
try{
while(true){
const url = `${PB_COLLECTION_URL}?page=${page}&perPage=${perPage}&sort=-Job_Number`;
@@ -206,11 +214,8 @@
jobsCache.push(...items);
totalItems = data.totalItems || (items.length + ((page-1)*perPage));
// Render first 40 immediately
if(!firstBatchRendered && jobsCache.length >= 40){
firstBatchRendered=true;
renderInitialBatch(jobsCache.slice(0,40));
}
// Apply filters on the currently loaded pages so initial results reflect preferences immediately.
applyFiltersAndRender();
if(progTimer) clearInterval(progTimer);
const realProg=Math.min(95, Math.floor((jobsCache.length / Math.max(1,totalItems)) * 95));
@@ -219,7 +224,6 @@
page++;
}
finishProgress();
applyFiltersAndRender();
}catch(err){ finishProgress(); alert('Failed to fetch jobs: '+err.message); console.error(err);}
}
@@ -269,6 +273,7 @@
const activeWanted = activeVals.map(v=>toBool(v)).filter(v=>v!==null);
const statusVals = Array.from(document.querySelectorAll('.filter-status:checked')).map(i=>i.value);
const estimatorVals = Array.from(document.querySelectorAll('.filter-estimator:checked')).map(i=>i.value);
const estimatorValsLower = estimatorVals.map(s=>safeLower(s));
visibleJobs = jobsCache.filter(job=>{
const searchable = [job.Job_Number, job.Job_Full_Name, job.Job_Address, job.Contact_Person, job.Company_Client, job.Notes].join(' ').toLowerCase();
@@ -279,7 +284,11 @@
if(b===null || !activeWanted.includes(b)) return false;
}
if(statusVals.length && !statusVals.includes(job.Job_Status||'')) return false;
if(estimatorVals.length && !estimatorVals.includes(job.Estimator||'')) return false;
if(estimatorVals.length){
const je = safeLower(job.Estimator||'');
const ok = estimatorValsLower.some(v=>je.includes(v) || v.includes(je));
if(!ok) return false;
}
return true;
});
@@ -287,6 +296,7 @@
if(q || divisionVals.length || activeVals.length || statusVals.length || estimatorVals.length){
sortJobsDescending(visibleJobs);
}
console.log('Filter summary', { q, divisionVals, activeWanted, statusVals, estimatorValsLower, total: jobsCache.length, visible: visibleJobs.length });
renderCards(visibleJobs);
}
@@ -353,6 +363,91 @@
applyFiltersAndRender();
});
// --- Preferences ---
async function loadUserPreferences(){
console.log('loadUserPreferences: email=', currentUserEmail);
if(!currentUserEmail) return null;
try{
const list = await pb.collection('user_preferences').getList(1,1,{
filter: `user_email="${currentUserEmail}"`
});
const record = list?.items?.[0];
const prefs = record?.job_info_prefs || record?.prefs || null;
console.log('loadUserPreferences: fetched prefs=', prefs);
if(!prefs && currentUserEmail.toLowerCase()==='rcardoza@cardoza.construction'){
console.log('loadUserPreferences: using fallback for rcardoza');
return { filters: { active:true, estimator:'Steve Brewer', job_division:'C#' } };
}
return prefs;
}catch(err){
console.warn('loadUserPreferences: error=', err);
const isTarget = currentUserEmail && currentUserEmail.toLowerCase()==='rcardoza@cardoza.construction';
if(isTarget){
console.log('loadUserPreferences: using error fallback for rcardoza');
return { filters: { active:true, estimator:'Steve Brewer', job_division:'C#' } };
}
return null;
}
}
function applyPrefsToFilters(prefs){
console.log('applyPrefsToFilters: received prefs=', prefs);
// Handle both direct filters and nested prefs.filters
const filters = prefs?.filters || prefs?.prefs?.filters;
if(!filters) {
console.log('applyPrefsToFilters: no filters found, returning');
return;
}
const { active, estimator, job_division, status } = filters;
console.log('applyPrefsToFilters: applying filters', filters);
// reset all filters first
document.querySelectorAll('.filter-division, .filter-active, .filter-status, .filter-estimator').forEach(cb=>cb.checked=false);
if(typeof active === 'boolean'){
document.querySelectorAll('.filter-active').forEach(cb=>{
const v = cb.value.trim().toLowerCase();
if((active && v==='yes') || (!active && v==='no')) cb.checked=true;
});
}
if(estimator){
const estLower = String(estimator||'').trim().toLowerCase();
document.querySelectorAll('.filter-estimator').forEach(cb=>{
const cbVal = cb.value.trim().toLowerCase();
if(cbVal === estLower || cbVal.includes(estLower) || estLower.includes(cbVal)) cb.checked=true;
});
// If no estimator got checked, try a direct match to 'steve brewer'
const anyChecked = Array.from(document.querySelectorAll('.filter-estimator')).some(cb=>cb.checked);
if(!anyChecked && estLower.startsWith('steve')){
document.querySelectorAll('.filter-estimator').forEach(cb=>{
if(cb.value.trim().toLowerCase().includes('steve')) cb.checked=true;
});
}
}
if(job_division){
const jd = String(job_division||'').trim().toLowerCase();
let code=null;
if(jd.includes('c#') || jd.includes('commercial')) code='C#';
else if(jd.includes('r#') || jd.includes('residential')) code='R#';
else if(jd.includes('s#') || jd.includes('small')) code='S#';
if(code){
document.querySelectorAll('.filter-division').forEach(cb=>{ if(cb.value===code) cb.checked=true; });
}
}
if(status){
const arr = Array.isArray(status) ? status : [status];
const lowerStatuses = arr.map(s=>String(s||'').trim().toLowerCase());
document.querySelectorAll('.filter-status').forEach(cb=>{
if(lowerStatuses.includes(cb.value.trim().toLowerCase())) cb.checked=true;
});
}
applyFiltersAndRender();
}
// --- Modal & Notes ---
function openDetail(job){
currentJob = job;
@@ -525,8 +620,9 @@
// Reset to INFO tab when opening
switchTab('info');
}
document.getElementById('btnClose').addEventListener('click',()=>{detailModal.classList.add('hidden');});
document.getElementById('backBtn').addEventListener('click',()=>{detailModal.classList.add('hidden');});
const closeModal = ()=>{ detailModal.classList.add('hidden'); renderCards(visibleJobs); };
document.getElementById('btnClose').addEventListener('click',closeModal);
document.getElementById('backBtn').addEventListener('click',closeModal);
// Tab switching
function switchTab(tab){
@@ -647,6 +743,10 @@
document.getElementById('btnClearNote').addEventListener('click',()=>newNote.innerHTML='');
// --- Init ---
const prefs = await loadUserPreferences();
console.log('Init: loaded prefs=', prefs);
applyPrefsToFilters(prefs);
console.log('Init: about to fetch jobs');
fetchAllJobs();
})();
</script>