- controllers/portal.py: FamilyLawPortal with 8 routes (cases list, case detail, calculator pre-fill, caselaw library, deadline complete AJAX, public intake landing/form/submit) - views/portal_case_templates.xml: portal home card, case list, full case detail with timeline widget, AI summary, DV safety banner - views/portal_calculator_templates.xml: FL 61.30 interactive calculator - views/portal_caselaw_templates.xml: searchable case law library (EN/ES) - views/website_intake_templates.xml: public 4-step intake form with DV quick-exit, fee waiver, and intake confirmation page - static/src/css/familylaw_portal.css: full portal/website CSS (EN/ES lang toggle, deadline card color coding, timeline, AI summary box) - static/src/js/fl_calculator.js: FL 61.30 schedule lookup, above- schedule formula, FL 61.30(11)(b) substantial timesharing calculation - static/src/js/fl_timeline.js: deadline timeline widget with filter buttons and mark-complete AJAX - __init__.py: import controllers package - __manifest__.py: add Phase 6 portal view files Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
202 lines
13 KiB
XML
202 lines
13 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- Portal Case Law Library — /my/cases/caselaw
|
|
Searchable FL case law browser for pro se litigants.
|
|
Bilingual EN/ES. Filterable by issue tag.
|
|
-->
|
|
<odoo>
|
|
<data>
|
|
|
|
<template id="portal_caselaw" name="FL Case Law Library — Portal">
|
|
<t t-call="portal.portal_layout">
|
|
<div class="container fl-portal mt-4">
|
|
|
|
<!-- Breadcrumb -->
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="/my/home">Home</a></li>
|
|
<li class="breadcrumb-item active">Case Law Library</li>
|
|
</ol>
|
|
</nav>
|
|
|
|
<!-- Language toggle -->
|
|
<div class="fl-lang-toggle">
|
|
<button class="btn btn-outline-secondary btn-sm fl-lang-btn btn-primary" data-lang="en">EN</button>
|
|
<button class="btn btn-outline-secondary btn-sm fl-lang-btn" data-lang="es">ES</button>
|
|
</div>
|
|
|
|
<!-- Header -->
|
|
<div class="fl-case-header mb-4">
|
|
<h2>
|
|
<span data-lang="en">Florida Family Law — Case Law Library</span>
|
|
<span data-lang="es" style="display:none;">Derecho de Familia de Florida — Biblioteca de Jurisprudencia</span>
|
|
</h2>
|
|
<div class="fl-case-meta">
|
|
<span data-lang="en">Key cases for child support modification, income imputation, timesharing, and more</span>
|
|
<span data-lang="es" style="display:none;">Casos clave para modificación de manutención, imputación de ingresos, tiempo compartido y más</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Disclaimer -->
|
|
<div class="alert alert-info mb-4" style="font-size:0.88rem;">
|
|
<span data-lang="en">
|
|
<strong>Note:</strong> These case summaries are for educational purposes only.
|
|
Always verify citations with the official Florida Reporter before citing in court.
|
|
Holdings are summaries — read the full opinion for complete analysis.
|
|
</span>
|
|
<span data-lang="es" style="display:none;">
|
|
<strong>Nota:</strong> Estos resúmenes de casos son solo para fines educativos.
|
|
Siempre verifique las citas con el Florida Reporter oficial antes de citar en el tribunal.
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Filter bar -->
|
|
<div class="mb-4">
|
|
<div class="row g-2 align-items-center">
|
|
<div class="col-md-5">
|
|
<input type="text" id="caselaw-search" class="form-control form-control-sm"
|
|
placeholder="Search cases, citations, holdings..."/>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<select id="caselaw-tag-filter" class="form-select form-select-sm">
|
|
<option value="">All Issues</option>
|
|
<option value="modification_threshold">Modification Threshold (FL 61.30(1)(b))</option>
|
|
<option value="income_imputation">Income Imputation</option>
|
|
<option value="self_employment_income">Self-Employment Income</option>
|
|
<option value="timesharing_deviation">Timesharing / FL 61.30(11)(b)</option>
|
|
<option value="domestic_violence">Domestic Violence</option>
|
|
<option value="default_judgment">Default Judgment</option>
|
|
<option value="residency">Residency Requirement</option>
|
|
<option value="parenting_class">Parenting Class</option>
|
|
<option value="fee_waiver">Fee Waiver</option>
|
|
<option value="post_order">Post-Order / Modification</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<select id="caselaw-court-filter" class="form-select form-select-sm">
|
|
<option value="">All Courts</option>
|
|
<option value="fl_supreme">FL Supreme Court</option>
|
|
<option value="3rd_dca">3rd DCA (Miami-Dade)</option>
|
|
<option value="4th_dca">4th DCA</option>
|
|
<option value="2nd_dca">2nd DCA</option>
|
|
<option value="1st_dca">1st DCA</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Case list -->
|
|
<div id="caselaw-list">
|
|
<t t-foreach="cases" t-as="cl">
|
|
<div class="fl-section-card mb-3 caselaw-item"
|
|
t-att-data-tags="','.join(cl.issue_tag_ids.mapped('name'))"
|
|
t-att-data-court="cl.court"
|
|
t-att-data-text="(cl.citation + ' ' + cl.holding).lower()">
|
|
<div class="fl-section-header d-flex justify-content-between align-items-center">
|
|
<span>
|
|
<em><t t-esc="cl.citation"/></em>
|
|
</span>
|
|
<span>
|
|
<t t-foreach="cl.issue_tag_ids" t-as="tag">
|
|
<span class="badge bg-secondary ms-1" style="font-size:0.72rem;">
|
|
<t t-esc="tag.name"/>
|
|
</span>
|
|
</t>
|
|
</span>
|
|
</div>
|
|
<div class="fl-section-body">
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="mb-2">
|
|
<strong data-lang="en">Holding:</strong>
|
|
<strong data-lang="es" style="display:none;">Decisión:</strong>
|
|
<span style="font-size:0.9rem;"> <t t-esc="cl.holding"/></span>
|
|
</div>
|
|
<t t-if="cl.plain_english">
|
|
<div class="fl-ai-summary" style="padding:10px;">
|
|
<div class="fl-ai-header" data-lang="en">Plain English</div>
|
|
<div class="fl-ai-header" data-lang="es" style="display:none;">En Español Simple</div>
|
|
<div class="fl-ai-text" data-lang="en" style="font-size:0.88rem;">
|
|
<t t-esc="cl.plain_english"/>
|
|
</div>
|
|
<div class="fl-ai-text" data-lang="es" style="display:none;font-size:0.88rem;">
|
|
<t t-esc="cl.plain_english_es or cl.plain_english"/>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<table class="table table-sm" style="font-size:0.82rem;">
|
|
<tr>
|
|
<td class="text-muted">Court:</td>
|
|
<td>
|
|
<t t-esc="dict([('fl_supreme','FL Supreme Court'),('3rd_dca','3rd DCA'),('4th_dca','4th DCA'),('2nd_dca','2nd DCA'),('1st_dca','1st DCA'),('5th_dca','5th DCA')]).get(cl.court, cl.court)"/>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="text-muted">Year:</td>
|
|
<td><t t-esc="cl.year"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td class="text-muted">Favorable to:</td>
|
|
<td>
|
|
<t t-esc="dict([('petitioner','Petitioner'),('respondent','Respondent'),('neutral','Neutral'),('depends','Depends')]).get(cl.favorable_to, cl.favorable_to)"/>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<t t-if="cl.google_scholar_url">
|
|
<a t-att-href="cl.google_scholar_url" target="_blank"
|
|
class="btn btn-sm btn-outline-secondary w-100"
|
|
rel="noopener noreferrer">
|
|
View on Google Scholar →
|
|
</a>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
|
|
<t t-if="not cases">
|
|
<div class="alert alert-info">No cases in the library yet.</div>
|
|
</t>
|
|
</div>
|
|
|
|
<!-- No results message (shown by JS) -->
|
|
<div id="caselaw-no-results" class="alert alert-warning" style="display:none;">
|
|
<span data-lang="en">No cases match your search. Try different keywords or clear the filter.</span>
|
|
<span data-lang="es" style="display:none;">Ningún caso coincide con su búsqueda. Pruebe diferentes palabras clave o elimine el filtro.</span>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Inline filter/search JS -->
|
|
<script type="text/javascript">
|
|
(function() {
|
|
function filterCases() {
|
|
var search = document.getElementById('caselaw-search').value.toLowerCase();
|
|
var tag = document.getElementById('caselaw-tag-filter').value;
|
|
var court = document.getElementById('caselaw-court-filter').value;
|
|
var items = document.querySelectorAll('.caselaw-item');
|
|
var visible = 0;
|
|
items.forEach(function(item) {
|
|
var matchText = !search || (item.dataset.text || '').includes(search);
|
|
var matchTag = !tag || (item.dataset.tags || '').split(',').includes(tag);
|
|
var matchCourt = !court || item.dataset.court === court;
|
|
var show = matchText && matchTag && matchCourt;
|
|
item.style.display = show ? '' : 'none';
|
|
if (show) visible++;
|
|
});
|
|
document.getElementById('caselaw-no-results').style.display = visible === 0 ? '' : 'none';
|
|
}
|
|
document.getElementById('caselaw-search').addEventListener('input', filterCases);
|
|
document.getElementById('caselaw-tag-filter').addEventListener('change', filterCases);
|
|
document.getElementById('caselaw-court-filter').addEventListener('change', filterCases);
|
|
})();
|
|
</script>
|
|
|
|
</t>
|
|
</template>
|
|
|
|
</data>
|
|
</odoo>
|