Files
rothbard/templates/dashboard.html
2025-11-09 21:58:02 -08:00

435 lines
23 KiB
HTML

{% extends 'base.html' %}
{% block content %}
<div class="h-full flex flex-col" x-data="columnConfig()">
<h1 class="text-xl font-semibold mb-4">Projects for {{ case_email }}</h1>
{% set profile = get_user_profile(session.uid) %}
{% if profile.is_admin %}
<div class="mb-4 flex w-[400px]">
<label for="simulateCaseEmail" class=" text-sm font-medium text-slate-700 mb-1">Simulate case email:</label>
<input type="text"
id="simulateCaseEmail"
x-model="case_email_sim"
@keyup.debounce.1000ms="window.location.href=`/dashboard/1?case_email=${encodeURIComponent($data.case_email_sim)}`"
class="w-full px-3 py-2 border w-64 border-slate-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Enter case email to simulate">
</div>
{% endif %}
<!-- Configure Visible Columns Link -->
<div class="mb-4">
<button @click="showColumnModal = true"
class="text-blue-600 hover:text-blue-800 text-sm font-medium underline">
Configure Visible Columns...
</button>
</div>
<!-- Column Configuration Modal -->
<div x-show="showColumnModal"
x-cloak
x-transition
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
@click.self="showColumnModal = false">
<div class="bg-white rounded-lg p-6 max-w-2xl w-full max-h-[80vh] overflow-y-auto">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">Configure Visible Columns</h3>
<button @click="showColumnModal = false" class="text-gray-500 hover:text-gray-700">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<div class="mb-4">
<label class="flex items-center">
<input type="checkbox"
x-model="selectAll"
@change="toggleAllColumns()"
class="mr-2 rounded border-gray-300 text-blue-600 focus:ring-blue-500">
<span class="text-sm font-medium">Select All / Deselect All</span>
</label>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 max-h-96 overflow-y-auto">
<template x-for="(column, index) in columns" :key="index">
<label class="flex items-center p-2 hover:bg-slate-50 rounded cursor-pointer">
<input type="checkbox"
:value="column"
x-model="visibleColumns"
@change="saveColumnSettings()"
:checked="visibleColumns.includes(column)"
class="mr-2 rounded border-gray-300 text-blue-600 focus:ring-blue-500">
<span class="text-sm" x-text="column"></span>
</label>
</template>
</div>
<div class="flex justify-end space-x-3 mt-6">
<button @click="resetToDefault()"
class="px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-md transition-colors">
Reset to Default
</button>
<button @click="showColumnModal = false;"
class="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-md transition-colors">
Apply Changes
</button>
</div>
</div>
</div>
<div class="overflow-scroll">
<table class="w-full whitespace-nowrap shadow-md border border-slate-200">
<thead class=" text-left text-sm sticky top-0 z-10 border-b border-blue-800 text-white font-medium"
style="background-color: rgb(89, 121, 142);">
<tr>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Matter Num')}">Matter Num</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Client / Property')}">Client / Property</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Matter Description')}">Matter Description</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Defendant 1')}">Defendant 1</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Matter Open')}">Matter Open</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Practice Area')}">Practice Area</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Notice Type')}">Notice Type</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Case Number')}">Case Number</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Premises Address')}">Premises Address</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Premises City')}">Premises City</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Assigned Attorney')}">Assigned Attorney</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Primary Contact')}">Primary Contact</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Secondary Paralegal')}">Secondary Paralegal</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Documents')}">Documents</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Matter Stage')}">Matter Stage</th>
<th class="px-4 py-3 w-[400px]" :class="{'hidden': !isColumnVisible('Completed Tasks')}">Completed Tasks</th>
<th class="px-4 py-3 w-[400px]" :class="{'hidden': !isColumnVisible('Pending Tasks')}">Pending Tasks</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Notice Service Date')}">Notice Service Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Notice Expir. Date')}">Notice Expir. Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Date Case Filed')}">Date Case Filed</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Daily Rent Damages')}">Daily Rent Damages</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Default Date')}">Default Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Default Entered On')}">Default Entered On</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Motions:')}">Motions:</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Demurrer Hearing Date')}">Demurrer Hearing Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Motion To Strike Hearing Date')}">Motion To Strike Hearing Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Motion to Quash Hearing Date')}">Motion to Quash Hearing Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Other Motion Hearing Date')}">Other Motion Hearing Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('MSC Date')}">MSC Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('MSC Time')}">MSC Time</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('MSC Address')}">MSC Address</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('MSC Div/ Dept/ Room')}">MSC Div/ Dept/ Room</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Trial Date')}">Trial Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Trial Time')}">Trial Time</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Trial Address')}">Trial Address</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Trial Div/ Dept/ Room')}">Trial Div/ Dept/ Room</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Final Result of Trial/ MSC')}">Final Result of Trial/ MSC</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Date of Settlement')}">Date of Settlement</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Final Obligation Under the Stip')}">Final Obligation Under the Stip</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Def\'s Comply with the Stip?')}">Def's Comply with the Stip?</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Judgment Date')}">Judgment Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Writ Issued Date')}">Writ Issued Date</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Scheduled Lockout')}">Scheduled Lockout</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Oppose Stays?')}">Oppose Stays?</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Premises Safety or Access Issues')}">Premises Safety or Access Issues</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Matter Gate or Entry Code')}">Matter Gate or Entry Code</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Date Possession Recovered')}">Date Possession Recovered</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Attorney\'s Fees')}">Attorney's Fees</th>
<th class="px-4 py-3" :class="{'hidden': !isColumnVisible('Costs')}">Costs</th>
</tr>
</thead>
<tbody class="bg-slate-100 divide-y divide-slate-300">
{% for r in rows %}
<tr class="hover:bg-slate-200 transition-colors duration-150 ease-in-out">
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Matter Num')}"></td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Client / Property')}">{{ r.client }}</td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Matter Description')}">{{ r.matter_description }}</td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Defendant 1')}">{{ r.defendant_1 }}</td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Matter Open')}">{{ r.matter_open }}</td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Practice Area')}"></td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Notice Type')}">{{ r.notice_type }}</td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Case Number')}">{{ r.case_number }}</td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Premises Address')}">{{ r.premises_address }}</td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Premises City')}">{{ r.premises_city }}</td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Assigned Attorney')}">
{{ r.responsible_attorney }}
</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Primary Contact')}">
{{ r.staff_person }}
</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Secondary Paralegal')}">
{{ r.staff_person_2 }}
</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Documents')}">
{% if r.documents_url %}
<a href="{{ r.documents_url }}">Documents</a>
{% endif %}</td>
<td class="px-4 py-3 text-sm text-slate-800" :class="{'hidden': !isColumnVisible('Matter Stage')}"> {{ r.phase_name }}</td>
<td class="px-4 py-3 text-sm align-top whitespace-normal w-[400px]" :class="{'hidden': !isColumnVisible('Completed Tasks')}" x-data="{ showCompletedModal: false}">
{% if r.completed_tasks %}
<div>
<table class="w-full text-xs">
<thead>
<tr>
<th class="text-left pb-1">Task</th>
<th class="text-right pb-1">Completed</th>
</tr>
</thead>
<tbody>
{% for x in r.completed_tasks[:2] %}
<tr>
<td class="py-1 pr-2 break-words">{{ x.description }}</td>
<td class="py-1 text-right whitespace-nowrap">{{ x.completed }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if r.completed_tasks|length > 2 %}
<button @click="showCompletedModal = true" class="text-blue-500 hover:text-blue-700 text-sm mt-1">Show more...</button>
{% endif %}
</div>
<div x-show="showCompletedModal"
x-cloak
x-transition
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
@click.self="showCompletedModal = false">
<div class="bg-white rounded-lg p-6 max-w-lg w-full max-h-[80vh] overflow-y-auto">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">Completed Tasks</h3>
<button @click="showCompletedModal = false" class="text-gray-500 hover:text-gray-700">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<table class="w-full">
<thead>
<tr class="border-b">
<th class="text-left pb-2">Task Description</th>
<th class="text-right pb-2">Completed Date</th>
</tr>
</thead>
<tbody>
{% for x in r.completed_tasks %}
<tr class="border-b border-slate-200">
<td class="py-2 break-words">{{ x.description }}</td>
<td class="py-2 text-right whitespace-nowrap">{{ x.completed }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
</td>
<td class="px-4 py-3 text-sm align-top whitespace-normal w-[400px] min-w-[400px]" :class="{'hidden': !isColumnVisible('Pending Tasks')}" x-data="{ showPendingModal: false }">
{% if r.pending_tasks %}
<div>
<table class="w-full text-xs">
<thead>
<tr>
<th class="text-left pb-1">Task</th>
</tr>
</thead>
<tbody>
{% for x in r.pending_tasks[:2] %}
<tr>
<td class="py-1 break-words">{{ x.description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if r.pending_tasks|length > 2 %}
<button @click="showPendingModal = true" class="text-blue-500 hover:text-blue-700 text-sm mt-1">Show more...</button>
{% endif %}
</div>
<div x-show="showPendingModal"
x-cloak
x-transition
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
@click.self="showPendingModal = false">
<div class="bg-white rounded-lg p-6 max-w-lg w-full max-h-[80vh] overflow-y-auto">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">Pending Tasks</h3>
<button @click="showPendingModal = false" class="text-gray-500 hover:text-gray-700">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<table class="w-full">
<thead>
<tr class="border-b">
<th class="text-left pb-2">Task Description</th>
</tr>
</thead>
<tbody>
{% for x in r.pending_tasks %}
<tr class="border-b border-slate-200">
<td class="py-2 break-words">{{ x.description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Notice Service Date')}">{{ r.notice_service_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Notice Expir. Date')}">{{ r.notice_expiration_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Date Case Filed')}">{{ r.case_field_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Daily Rent Damages')}">{% if r.daily_rent_damages %}${{ "{:,.2f}".format(r.daily_rent_damages) }}{% endif %}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Default Date')}">{{ r.default_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Default Entered On')}">{{ r.default_entered_on_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Motions:')}"></td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Demurrer Hearing Date')}">{{ r.demurrer_hearing_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Motion To Strike Hearing Date')}">{{ r.motion_to_strike_hearing_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Motion to Quash Hearing Date')}">{{ r.motion_to_quash_hearing_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Other Motion Hearing Date')}">{{ r.other_motion_hearing_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('MSC Date')}">{{ r.msc_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('MSC Time')}">{{ r.msc_time }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('MSC Address')}">{{ r.msc_address }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('MSC Div/ Dept/ Room')}">{{ r.msc_div_dept_room }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Trial Date')}">{{ r.trial_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Trial Time')}">{{ r.trial_time }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Trial Address')}">{{ r.trial_address }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Trial Div/ Dept/ Room')}">{{ r.trial_div_dept_room }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Final Result of Trial/ MSC')}">{{ r.final_result }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Date of Settlement')}">{{ r.date_of_settlement }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Final Obligation Under the Stip')}">{{ r.final_obligation }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Def\'s Comply with the Stip?')}">{{ r.def_comply_stip }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Judgment Date')}">{{ r.judgment_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Writ Issued Date')}">{{ r.writ_issued_date }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Scheduled Lockout')}">{{ r.scheduled_lockout }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Oppose Stays?')}">{{ r.oppose_stays }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Premises Safety or Access Issues')}">{{ r.premises_safety }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Matter Gate or Entry Code')}">{{ r.matter_gate_code }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Date Possession Recovered')}">{{ r.date_possession_recovered }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Attorney\'s Fees')}">{{ r.attorney_fees }}</td>
<td class="px-4 py-3 text-sm" :class="{'hidden': !isColumnVisible('Costs')}">{{ r.costs }}</td>
</tr>
{% else %}
<tr>
<td colspan="53" class="px-4 py-6 text-center text-slate-500">No matching projects found.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination -->
{% include '_pagination.html' %}
<script>
function columnConfig() {
return {
showColumnModal: false,
case_email_sim: '',
columns: [
'Matter Num',
'Client / Property',
'Matter Description',
'Defendant 1',
'Matter Open',
'Practice Area',
'Notice Type',
'Case Number',
'Premises Address',
'Premises City',
'Assigned Attorney',
'Primary Contact',
'Secondary Paralegal',
'Documents',
'Matter Stage',
'Completed Tasks',
'Pending Tasks',
'Notice Service Date',
'Notice Expir. Date',
'Date Case Filed',
'Daily Rent Damages',
'Default Date',
'Default Entered On',
'Motions:',
'Demurrer Hearing Date',
'Motion To Strike Hearing Date',
'Motion to Quash Hearing Date',
'Other Motion Hearing Date',
'MSC Date',
'MSC Time',
'MSC Address',
'MSC Div/ Dept/ Room',
'Trial Date',
'Trial Time',
'Trial Address',
'Trial Div/ Dept/ Room',
'Final Result of Trial/ MSC',
'Date of Settlement',
'Final Obligation Under the Stip',
'Def\'s Comply with the Stip?',
'Judgment Date',
'Writ Issued Date',
'Scheduled Lockout',
'Oppose Stays?',
'Premises Safety or Access Issues',
'Matter Gate or Entry Code',
'Date Possession Recovered',
'Attorney\'s Fees',
'Costs'
],
selectAll: true,
visibleColumns: [],
init() {
this.loadColumnSettings();
// Extract case_email from URL query parameter
const urlParams = new URLSearchParams(window.location.search);
const caseEmail = urlParams.get('case_email');
if (caseEmail) {
this.case_email_sim = caseEmail;
}
},
isColumnVisible(columnName) {
return this.visibleColumns.includes(columnName);
},
loadColumnSettings() {
const stored = localStorage.getItem('dashboardColumnVisibility');
if (stored) {
this.visibleColumns = JSON.parse(stored);
this.selectAll = this.visibleColumns.length === this.columns.length;
} else {
// Default to showing all columns
this.visibleColumns = [...this.columns];
this.selectAll = true;
}
},
saveColumnSettings() {
localStorage.setItem('dashboardColumnVisibility', JSON.stringify(this.visibleColumns));
},
toggleAllColumns() {
if (this.selectAll) {
this.visibleColumns = [];
} else {
this.visibleColumns = [...this.columns];
}
this.selectAll = !this.selectAll;
this.saveColumnSettings();
},
resetToDefault() {
this.visibleColumns = [...this.columns];
this.selectAll = true;
this.saveColumnSettings();
}
}
}
</script>
</div>
<!--
<div class="flex flex-col m-4">
<div class=" w-full flex-grow overflow-scroll rounded-2xl overflow-hidden">
</div>
-->
{% endblock %}