Files
hotline-planner/monolith/hlp quasar initial layout split/js/components/planner-grid.js
2026-02-23 14:02:44 +01:00

217 lines
9.2 KiB
JavaScript

const PlannerGrid = {
components: {
'agent-row': AgentRow
},
template: `
<div class="grid-viewport shadow-1" ref="viewport">
<div class="planner-content">
<!-- 1. EOD TARGETS -->
<div class="planner-row row-eod">
<div class="left-col pink text-overline text-weight-bolder">EOD TARGETS</div>
<div class="cells-area">
<div v-for="i in dates.length" :key="'e'+i" class="cell" style="height: var(--h-eod)">
<div class="text-weight-bold text-caption">94%</div>
<q-linear-progress :value="0.94" color="pink-7" size="3px" rounded style="width: 70%"></q-linear-progress>
</div>
</div>
</div>
<!-- 2. COVERAGE STATUS -->
<div class="planner-row row-status">
<div class="left-col white text-overline text-grey-6">COVERAGE STATUS</div>
<div class="cells-area">
<div v-for="(d, i) in dates" :key="'s'+i" class="cell" style="height: var(--h-status)">
<q-icon name="circle" :color="i % 7 === 0 ? 'red' : (i % 5 === 0 ? 'orange' : 'green')" size="10px"></q-icon>
</div>
</div>
</div>
<!-- 3. DATE LABELS + SEARCH -->
<div class="planner-row row-dates">
<div class="left-col grey">
<div class="grid-search-container">
<q-input
v-model="search"
dense
filled
placeholder="Find agent..."
class="grid-search-input"
bg-color="white"
>
<template v-slot:prepend>
<q-icon name="search" size="xs"></q-icon>
</template>
</q-input>
<q-btn flat round dense icon="calendar_today" color="indigo-9" size="sm">
<q-menu @show="initDateSelection">
<div class="column bg-white">
<div class="row items-center justify-between q-pa-sm border-b">
<div class="text-subtitle2">Jump to Date</div>
<q-btn-toggle
v-model="settings.weekStart"
class="my-custom-toggle"
no-caps
rounded
unelevated
toggle-color="indigo"
color="white"
text-color="indigo"
size="sm"
:options="[
{label: 'Mon', value: 1},
{label: 'Sun', value: 0}
]"
/>
</div>
<q-date
v-model="tempPickedDate"
mask="YYYY-MM-DD"
minimal
flat
color="indigo-9"
:first-day-of-week="settings.weekStart"
></q-date>
<div class="row justify-end q-pa-sm q-gutter-sm border-t">
<q-btn flat label="Cancel" color="grey-7" v-close-popup />
<q-btn flat label="OK" color="primary" @click="applyDateSelection" v-close-popup />
</div>
</div>
</q-menu>
<q-tooltip>Go to Date</q-tooltip>
</q-btn>
</div>
</div>
<div class="cells-area">
<div v-for="(date, i) in dates" :key="'d'+i"
class="cell column flex-center"
:class="[ValidationUtils.isWeekend(date) ? 'bg-weekend' : '']"
style="height: var(--h-dates)">
<div class="text-[9px] uppercase text-weight-black"
:class="getTextColorClass(date)">
{{ date.toLocaleDateString('en-US', {weekday: 'short'}) }}
</div>
<div class="text-subtitle2 text-weight-bold leading-none"
:class="getTextColorClass(date)">
{{ date.getDate() }}
</div>
</div>
</div>
</div>
<!-- DATA ROWS -->
<div v-for="dept in depts" :key="dept">
<div v-if="shouldShowDept(dept)" class="planner-row dept-divider">
<div class="left-col dept-divider border-r">{{ dept }} DIVISION</div>
<div class="cells-area"><div class="cell" style="flex: 1; height: 28px"></div></div>
</div>
<template v-if="shouldShowDept(dept)">
<agent-row
v-for="agent in getAgentsByDept(dept)"
:key="agent.id"
:agent="agent"
:dates="dates"
:is-compact="settings.isCompact"
:weekends-are-working-days="settings.weekendsAreWorkingDays"
></agent-row>
</template>
</div>
</div>
</div>
`,
setup() {
const { ref, computed, nextTick } = Vue;
const viewport = ref(null);
// Connect to store
const dates = computed(() => store.dates);
const settings = store.viewSettings;
const search = computed({
get: () => settings.searchQuery,
set: (val) => settings.searchQuery = val
});
// Filter Logic
const agents = computed(() => store.filteredAgents);
const shouldShowDept = (dept) => {
if (settings.activeDept !== 'All' && settings.activeDept !== dept) return false;
// If checking if any agents in this dept exist after filter
return agents.value.some(a => a.dept === dept);
};
const getAgentsByDept = (dept) => {
return agents.value.filter(a => a.dept === dept);
};
// Date Picker Logic
// Date Picker Logic
const tempPickedDate = ref(null);
const initDateSelection = () => {
// Initialize with current store start date
const current = new Date(settings.startDate);
// Format as YYYY-MM-DD
const y = current.getFullYear();
const m = String(current.getMonth() + 1).padStart(2, '0');
const d = String(current.getDate()).padStart(2, '0');
tempPickedDate.value = `${y}-${m}-${d}`;
};
const applyDateSelection = () => {
if (!tempPickedDate.value) return;
const val = tempPickedDate.value;
const target = new Date(val);
const targetStr = target.toDateString();
// Re-calculate store dates based on current view settings
// incase user changed start date previously
// Check if date is visible in current range?
// Actually, requirements say "jumps to that date".
// If date is outside current range, we should move the range start?
// Existing logic:
const index = dates.value.findIndex(d => d.toDateString() === targetStr);
if (index === -1) {
// Not in current view -> Move view directly
store.setStartDate(val);
nextTick(() => {
if (viewport.value) viewport.value.scrollLeft = 0;
});
} else {
// In current view -> Scroll to it
if (viewport.value) viewport.value.scrollLeft = index * 100; // 100 is cell width
}
};
const getTextColorClass = (date) => {
const isWeekend = ValidationUtils.isWeekend(date);
if (isWeekend && !settings.weekendsAreWorkingDays) {
return ValidationUtils.isSat(date) ? 'text-sat' : 'text-sun';
}
return 'text-grey-9'; // default
};
return {
viewport,
dates,
settings,
search,
depts: store.consts.DEPARTMENTS,
tempPickedDate,
initDateSelection,
applyDateSelection,
shouldShowDept,
getAgentsByDept,
ValidationUtils,
getTextColorClass
}
}
};