217 lines
9.2 KiB
JavaScript
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
|
|
}
|
|
}
|
|
};
|