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:
@@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, useContext, useState, useCallback } from "react";
|
||||
import type { ClientView } from "@/lib/client-view";
|
||||
|
||||
interface ChatContextValue {
|
||||
isOpen: boolean;
|
||||
selectedPhaseId: string | null; // null = "Generale"
|
||||
phases: ClientView["phases"];
|
||||
clientId: string;
|
||||
openChat: (phaseId?: string) => void;
|
||||
closeChat: () => void;
|
||||
}
|
||||
|
||||
const ChatContext = createContext<ChatContextValue | null>(null);
|
||||
|
||||
export function useChatContext() {
|
||||
const ctx = useContext(ChatContext);
|
||||
if (!ctx) throw new Error("useChatContext must be used inside ChatProvider");
|
||||
return ctx;
|
||||
}
|
||||
|
||||
export function ChatProvider({
|
||||
children,
|
||||
phases,
|
||||
clientId,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
phases: ClientView["phases"];
|
||||
clientId: string;
|
||||
}) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [selectedPhaseId, setSelectedPhaseId] = useState<string | null>(null);
|
||||
|
||||
const openChat = useCallback((phaseId?: string) => {
|
||||
setSelectedPhaseId(phaseId ?? null);
|
||||
setIsOpen(true);
|
||||
}, []);
|
||||
|
||||
const closeChat = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ChatContext.Provider value={{ isOpen, selectedPhaseId, phases, clientId, openChat, closeChat }}>
|
||||
{children}
|
||||
</ChatContext.Provider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user