feat: sidebar CTA removal, delete phase/task, public dashboard UX, chat panel
1. AdminSidebar: removed yellow "Genera preventivo" CTA (duplicated Preventivi tab nav item) 2. Delete phase/task: new deletePhase/deleteTask server actions with FK cascade and phase-status recompute; DeletePhaseTaskButton client component with window.confirm; trash icons in PhasesTab per phase and per task 3. Public dashboard: extend activeOffers query with offer_macros join (offer_name, offer_type); reorder sidebar 1°Offerte 2°Pagamenti 3°Documenti; OffersSection shows macro public_name as heading (never tier letter/internal_name); PaymentStatus gains totalLabel/overrideAmount/hideRows props — retainer=monthly label + no Acconto/Saldo rows 4. Offer editor: Descrizione textarea (nota interna) and Modalità toggle moved directly under title; Tags section now contains only Categoria/Ticket/Tipo/Obiettivo 5. Basecamp chat: API route supports entity_type="phase" with authorization scoping; comments scope in client-view broadened to include phaseIds and client_id (general); CommentsTab updated with phase/general entities; ChatProvider React context; ChatPanel fixed slide-in panel with FAB (bottom-right) and composer tag selector (Generale + phases); PhaseCard gets chat-bubble icon pre-tagging that phase; inline ChatSection block removed from dashboard main column Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { Progress } from "@/components/ui/progress";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { ApproveButton } from "@/components/client/ApproveButton";
|
||||
import { useChatContext } from "@/components/client/ChatProvider";
|
||||
import type { ClientView } from "@/lib/client-view";
|
||||
|
||||
type Phase = ClientView["phases"][number];
|
||||
@@ -75,6 +76,7 @@ export function PhaseCard({
|
||||
defaultOpen: boolean;
|
||||
}) {
|
||||
const [open, setOpen] = useState(defaultOpen);
|
||||
const { openChat } = useChatContext();
|
||||
const doneCount = phase.tasks.filter((t) => t.status === "done").length;
|
||||
|
||||
return (
|
||||
@@ -95,6 +97,20 @@ export function PhaseCard({
|
||||
<Badge className={`text-xs ${phaseStatusStyle[phase.status]}`}>
|
||||
{phaseStatusLabel[phase.status]}
|
||||
</Badge>
|
||||
{/* Chat bubble — opens panel pre-tagged with this phase */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation(); // don't toggle accordion
|
||||
openChat(phase.id);
|
||||
}}
|
||||
aria-label="Apri chat per questa fase"
|
||||
className="p-1 rounded-md text-[#999999] hover:text-[#1A463C] hover:bg-[#f0f7f4] transition-colors"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" strokeWidth={1.8} viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M8 10h.01M12 10h.01M16 10h.01M21 12c0 4.418-4.03 8-9 8a9.77 9.77 0 01-4-.83L3 20l1.09-3.27C3.39 15.56 3 13.83 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
|
||||
</svg>
|
||||
</button>
|
||||
<svg
|
||||
className={`w-4 h-4 text-[#999999] transition-transform ${open ? "rotate-180" : ""}`}
|
||||
fill="none"
|
||||
|
||||
Reference in New Issue
Block a user