mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage-server
synced 2026-05-18 20:08:19 +00:00
fix(slots): hide past slots today even on cache hit
Previous flow cached the unfiltered slot list AND applied the "hide past slots" filter — but only on the fresh-fetch path. A cache hit returned the stored list untouched, so by lunchtime agents saw morning slots that had already passed. Refactored into a post-cache filterPastSlotsForToday() helper applied on both cache-hit and fresh paths. Cache stores the full day's slots (keyed by doctorId + dayOfWeek), so same-weekday reuse across weeks stays correct. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -124,8 +124,12 @@ export class MasterdataService implements OnModuleInit {
|
||||
const dayOfWeek = new Date(date).toLocaleDateString('en-US', { weekday: 'long' }).toUpperCase();
|
||||
const cacheKey = `masterdata:slots:${doctorId}:${dayOfWeek}`;
|
||||
|
||||
// Cache stores the UNFILTERED full-day slot list (keyed by dayOfWeek,
|
||||
// so it's reusable across dates that fall on the same weekday). The
|
||||
// "hide past slots on today" filter is applied AFTER cache read so it
|
||||
// stays correct as real-time advances without cache churn.
|
||||
const cached = await this.cache.getCache(cacheKey);
|
||||
if (cached) return JSON.parse(cached);
|
||||
if (cached) return this.filterPastSlotsForToday(JSON.parse(cached), date);
|
||||
|
||||
const auth = `Bearer ${this.apiKey}`;
|
||||
const data = await this.platform.queryWithAuth<any>(
|
||||
@@ -169,21 +173,35 @@ export class MasterdataService implements OnModuleInit {
|
||||
// Sort by time
|
||||
slots.sort((a, b) => a.time.localeCompare(b.time));
|
||||
|
||||
// Cache the full UNFILTERED list so reuse across dates (same dayOfWeek)
|
||||
// doesn't mis-serve filtered data from an earlier date.
|
||||
await this.cache.setCache(cacheKey, JSON.stringify(slots), CACHE_TTL);
|
||||
this.logger.log(`Generated ${slots.length} slots for doctor ${doctorId} on ${dayOfWeek}`);
|
||||
|
||||
// Filter out past time slots when the requested date is today (IST).
|
||||
// Cache stores the full day's slots — filtering happens post-cache
|
||||
// so slots become available as the day progresses without cache churn.
|
||||
const todayIST = new Date().toLocaleDateString('en-CA', { timeZone: 'Asia/Kolkata' });
|
||||
if (date === todayIST) {
|
||||
const nowHHMM = new Date().toLocaleTimeString('en-GB', { timeZone: 'Asia/Kolkata', hour: '2-digit', minute: '2-digit' });
|
||||
const filtered = slots.filter(s => s.time >= nowHHMM);
|
||||
this.logger.log(`[SLOTS] Today filter: ${slots.length} total → ${filtered.length} remaining (now=${nowHHMM} IST)`);
|
||||
return filtered;
|
||||
}
|
||||
return this.filterPastSlotsForToday(slots, date);
|
||||
}
|
||||
|
||||
return slots;
|
||||
// When the requested date is today (IST), hide slots whose time has
|
||||
// already passed (30-min buffer so we don't offer the impossible-to-keep
|
||||
// "in 5 minutes" slot). Applies to both cache-hit and fresh fetch paths.
|
||||
private filterPastSlotsForToday(
|
||||
slots: Array<{ time: string; label: string; clinicId: string; clinicName: string }>,
|
||||
date: string,
|
||||
): Array<{ time: string; label: string; clinicId: string; clinicName: string }> {
|
||||
const todayIst = new Date().toLocaleDateString('en-CA', { timeZone: 'Asia/Kolkata' });
|
||||
if (date !== todayIst) return slots;
|
||||
|
||||
const nowHHMM = new Date().toLocaleTimeString('en-GB', {
|
||||
timeZone: 'Asia/Kolkata', hour: '2-digit', minute: '2-digit',
|
||||
});
|
||||
const [nowH, nowM] = nowHHMM.split(':').map(Number);
|
||||
const cutoff = nowH * 60 + nowM + 30; // 30-min buffer
|
||||
const filtered = slots.filter((s) => {
|
||||
const [h, m] = s.time.split(':').map(Number);
|
||||
return h * 60 + m >= cutoff;
|
||||
});
|
||||
this.logger.log(`[SLOTS] Today filter: ${slots.length} → ${filtered.length} (now=${nowHHMM} IST, cutoff=${Math.floor(cutoff / 60)}:${String(cutoff % 60).padStart(2, '0')})`);
|
||||
return filtered;
|
||||
}
|
||||
|
||||
async invalidateAll(): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user