/** @odoo-module **/ // Fusion Claims — Posting Period Countdown // Reads the submission_deadline_dt field, computes "Nd Xh to cutoff" client-side, // re-renders every 60 seconds, swaps colour class as the deadline approaches. // Copyright 2026 Nexa Systems Inc. // License OPL-1 import { Component, useState, onWillDestroy } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { standardFieldProps } from "@web/views/fields/standard_field_props"; class FcPostingCountdown extends Component { static template = "fusion_claims.PostingCountdown"; static props = { ...standardFieldProps }; setup() { this.state = useState({ text: "", level: "info" }); this._render(); this._timer = setInterval(() => this._render(), 60_000); onWillDestroy(() => { if (this._timer) { clearInterval(this._timer); this._timer = null; } }); } _render() { const deadline = this.props.record.data[this.props.name]; if (!deadline) { this.state.text = ""; this.state.level = "muted"; return; } // Odoo provides a luxon DateTime for Datetime fields const now = luxon.DateTime.now(); const diff = deadline.diff(now, ["days", "hours", "minutes"]).toObject(); if (diff.days < 0 || (diff.days === 0 && diff.hours < 0)) { this.state.text = "Cutoff passed"; this.state.level = "muted"; return; } const days = Math.floor(diff.days); const hours = Math.floor(diff.hours); if (days < 1) { this.state.text = `${hours}h to cutoff`; this.state.level = "danger"; } else if (days < 3) { this.state.text = `${days}d ${hours}h to cutoff`; this.state.level = "warning"; } else { this.state.text = `${days} days to cutoff`; this.state.level = "info"; } } } registry.category("fields").add("fc_posting_countdown", { component: FcPostingCountdown, });