Fixed partnerui message viewer
This commit is contained in:
@@ -2123,7 +2123,8 @@ export function DashboardPage() {
|
||||
===================================================================== */}
|
||||
{selectedNotification && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/80 backdrop-blur-md p-4 animate-in fade-in duration-200">
|
||||
<div className="w-full max-w-2xl rounded-2xl bg-[#0d1322] border border-white/10 shadow-2xl overflow-hidden flex flex-col max-h-[90vh]">
|
||||
<div className="w-full max-w-3xl xl:max-w-4xl rounded-2xl bg-[#0d1322] border border-white/10 shadow-2xl overflow-hidden flex flex-col max-h-[90vh]">
|
||||
{/* Modal Header */}
|
||||
<div className="p-5 border-b border-white/[0.08] flex items-center justify-between bg-[#0b101d] shrink-0">
|
||||
<div className="min-w-0 pr-4">
|
||||
<h3 className="text-base font-bold text-white truncate">
|
||||
@@ -2141,38 +2142,42 @@ export function DashboardPage() {
|
||||
<X className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="p-5 space-y-4 overflow-y-auto flex-1">
|
||||
|
||||
{/* Scrollable Modal Body containing the Message Reading Pane */}
|
||||
<div className="p-4 sm:p-5 overflow-y-auto overflow-x-hidden flex-1 min-h-0 [scrollbar-width:thin] [scrollbar-color:#334155_transparent]">
|
||||
<MessageViewer
|
||||
content={selectedNotification.message || ''}
|
||||
platform={selectedNotification.platform}
|
||||
subject={selectedNotification.subject}
|
||||
/>
|
||||
<div className="flex items-center justify-end gap-3 pt-3 border-t border-white/[0.08] shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSelectedNotification(null)}
|
||||
className="px-4 py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-300 text-xs font-semibold cursor-pointer transition"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const subj = selectedNotification.subject || 'Notification';
|
||||
setSelectedNotification(null);
|
||||
setContactTarget({
|
||||
organisation: partnerSummary.primaryFundingOrg,
|
||||
projectTitle: 'Reply',
|
||||
});
|
||||
setMessageSubject(subj.startsWith('Re:') ? subj : `Re: ${subj}`);
|
||||
setMessageBody('');
|
||||
}}
|
||||
className="px-4 py-2 rounded-xl bg-emerald-500 hover:bg-emerald-400 text-slate-950 font-semibold text-xs flex items-center gap-1.5 cursor-pointer transition shadow-lg shadow-emerald-500/20"
|
||||
>
|
||||
<Send className="w-3.5 h-3.5" />
|
||||
<span>Reply</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sticky Modal Footer */}
|
||||
<div className="px-5 py-3.5 border-t border-white/[0.08] bg-[#0b101d] flex items-center justify-end gap-3 shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSelectedNotification(null)}
|
||||
className="px-4 py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-300 text-xs font-semibold cursor-pointer transition"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const subj = selectedNotification.subject || 'Notification';
|
||||
setSelectedNotification(null);
|
||||
setContactTarget({
|
||||
organisation: partnerSummary.primaryFundingOrg,
|
||||
projectTitle: 'Reply',
|
||||
});
|
||||
setMessageSubject(subj.startsWith('Re:') ? subj : `Re: ${subj}`);
|
||||
setMessageBody('');
|
||||
}}
|
||||
className="px-4 py-2 rounded-xl bg-emerald-500 hover:bg-emerald-400 text-slate-950 font-semibold text-xs flex items-center gap-1.5 cursor-pointer transition shadow-lg shadow-emerald-500/20"
|
||||
>
|
||||
<Send className="w-3.5 h-3.5" />
|
||||
<span>Reply</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,6 +17,7 @@ export interface MessageViewerProps {
|
||||
subject?: string;
|
||||
className?: string;
|
||||
showFormatHeader?: boolean;
|
||||
maxHeightClass?: string;
|
||||
}
|
||||
|
||||
export const MessageViewer: React.FC<MessageViewerProps> = ({
|
||||
@@ -25,6 +26,7 @@ export const MessageViewer: React.FC<MessageViewerProps> = ({
|
||||
subject,
|
||||
className = '',
|
||||
showFormatHeader = true,
|
||||
maxHeightClass = 'max-h-[60vh]',
|
||||
}) => {
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [showRaw, setShowRaw] = useState(false);
|
||||
@@ -90,10 +92,10 @@ export const MessageViewer: React.FC<MessageViewerProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`flex flex-col rounded-2xl bg-slate-900/50 border border-white/10 overflow-hidden ${className}`}>
|
||||
<div className={`flex flex-col rounded-2xl bg-slate-900/50 border border-white/10 overflow-hidden w-full max-w-full ${className}`}>
|
||||
{/* Format Header & Controls Bar */}
|
||||
{showFormatHeader && (
|
||||
<div className="px-4 py-2.5 border-b border-white/[0.08] bg-[#0b101d]/90 flex items-center justify-between text-xs text-slate-400 gap-3">
|
||||
<div className="px-4 py-2.5 border-b border-white/[0.08] bg-[#0b101d]/90 flex items-center justify-between text-xs text-slate-400 gap-3 shrink-0">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
{isEmail ? (
|
||||
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-cyan-500/10 border border-cyan-500/20 text-cyan-300 font-semibold text-[11px]">
|
||||
@@ -112,7 +114,7 @@ export const MessageViewer: React.FC<MessageViewerProps> = ({
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className="flex items-center gap-1.5 shrink-0">
|
||||
{/* View Mode Toggle: Formatted vs Raw */}
|
||||
<button
|
||||
type="button"
|
||||
@@ -156,22 +158,22 @@ export const MessageViewer: React.FC<MessageViewerProps> = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Message Body Content */}
|
||||
<div className="p-5 sm:p-6 overflow-x-auto max-h-[55vh] overflow-y-auto text-sm leading-relaxed text-slate-200">
|
||||
{/* Message Body Content - with explicit max height, max width, word wrapping, and automatic scrollbars */}
|
||||
<div className={`w-full max-w-full p-4 sm:p-6 overflow-x-auto overflow-y-auto ${maxHeightClass} text-sm leading-relaxed text-slate-200 [scrollbar-width:thin] [scrollbar-color:#334155_transparent]`}>
|
||||
{showRaw ? (
|
||||
<pre className="font-mono text-xs text-slate-300 whitespace-pre-wrap break-words bg-[#080d18] p-4 rounded-xl border border-white/5">
|
||||
<pre className="font-mono text-xs text-slate-300 whitespace-pre-wrap break-words [word-break:break-word] bg-[#080d18] p-4 rounded-xl border border-white/5 max-w-full overflow-x-auto [scrollbar-width:thin] [scrollbar-color:#334155_transparent]">
|
||||
{content}
|
||||
</pre>
|
||||
) : (
|
||||
<div
|
||||
className="prose prose-invert max-w-none text-xs sm:text-sm leading-relaxed text-slate-200 [&_h1]:text-white [&_h1]:text-xl [&_h1]:font-bold [&_h1]:mb-3 [&_h2]:text-white [&_h2]:text-lg [&_h2]:font-bold [&_h2]:mb-2 [&_h3]:text-white [&_h3]:text-base [&_h3]:font-bold [&_h3]:mb-2 [&_h4]:text-white [&_h4]:font-semibold [&_a]:text-emerald-400 [&_a:hover]:underline [&_ul]:list-disc [&_ul]:pl-5 [&_ul]:my-2 [&_ol]:list-decimal [&_ol]:pl-5 [&_ol]:my-2 [&_li]:text-slate-300 [&_table]:w-full [&_table]:border-collapse [&_th]:border [&_th]:border-slate-700 [&_th]:bg-slate-800/80 [&_th]:p-2 [&_td]:border [&_td]:border-slate-800 [&_td]:p-2 [&_blockquote]:border-l-4 [&_blockquote]:border-emerald-500 [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:my-2 [&_code]:bg-slate-800 [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-emerald-300"
|
||||
className="prose prose-invert max-w-full w-full break-words [word-break:break-word] text-xs sm:text-sm leading-relaxed text-slate-200 [&_h1]:text-white [&_h1]:text-xl [&_h1]:font-bold [&_h1]:mb-3 [&_h2]:text-white [&_h2]:text-lg [&_h2]:font-bold [&_h2]:mb-2 [&_h3]:text-white [&_h3]:text-base [&_h3]:font-bold [&_h3]:mb-2 [&_h4]:text-white [&_h4]:font-semibold [&_a]:text-emerald-400 [&_a:hover]:underline [&_ul]:list-disc [&_ul]:pl-5 [&_ul]:my-2 [&_ol]:list-decimal [&_ol]:pl-5 [&_ol]:my-2 [&_li]:text-slate-300 [&_table]:w-full [&_table]:max-w-full [&_table]:border-collapse [&_table]:my-3 [&_th]:border [&_th]:border-slate-700 [&_th]:bg-slate-800/80 [&_th]:p-2.5 [&_th]:break-words [&_td]:border [&_td]:border-slate-800 [&_td]:p-2.5 [&_td]:break-words [&_blockquote]:border-l-4 [&_blockquote]:border-emerald-500 [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:my-2 [&_code]:bg-slate-800 [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-emerald-300 [&_code]:break-all [&_pre]:max-w-full [&_pre]:overflow-x-auto [&_img]:max-w-full [&_img]:h-auto [&_iframe]:max-w-full"
|
||||
dangerouslySetInnerHTML={{ __html: renderedHtml }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Footer Info Stamp */}
|
||||
<div className="px-5 py-2.5 border-t border-white/[0.08] bg-[#090e1a] flex items-center justify-between text-[11px] text-slate-400">
|
||||
<div className="px-5 py-2.5 border-t border-white/[0.08] bg-[#090e1a] flex items-center justify-between text-[11px] text-slate-400 shrink-0">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<ShieldCheck className="w-3.5 h-3.5 text-emerald-400" />
|
||||
<span>PFM Communications • {isEmail ? 'Email HTML Format' : 'In-App Markup Format'}</span>
|
||||
|
||||
Reference in New Issue
Block a user