fix images and empty space
This commit is contained in:
@@ -8,6 +8,66 @@ import { createStompClient } from "@/lib/chatSocket";
|
|||||||
|
|
||||||
const API_BASE = "";
|
const API_BASE = "";
|
||||||
|
|
||||||
|
function isImageFilename(name) {
|
||||||
|
return /\.(jpe?g|png|gif|webp|bmp|svg)$/i.test(name || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function AttachmentPreview({ url, name, token }) {
|
||||||
|
const [blobUrl, setBlobUrl] = useState(null);
|
||||||
|
const isImage = isImageFilename(name);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!url || !token) return;
|
||||||
|
let objectUrl;
|
||||||
|
fetch(url, { headers: { Authorization: `Bearer ${token}` } })
|
||||||
|
.then((r) => (r.ok ? r.blob() : null))
|
||||||
|
.then((blob) => {
|
||||||
|
if (blob) {
|
||||||
|
objectUrl = URL.createObjectURL(blob);
|
||||||
|
setBlobUrl(objectUrl);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
return () => { if (objectUrl) URL.revokeObjectURL(objectUrl); };
|
||||||
|
}, [url, token]);
|
||||||
|
|
||||||
|
if (isImage) {
|
||||||
|
return (
|
||||||
|
<div style={{ marginTop: "0.5rem" }}>
|
||||||
|
{blobUrl ? (
|
||||||
|
<img
|
||||||
|
src={blobUrl}
|
||||||
|
alt={name || "attachment"}
|
||||||
|
style={{ maxWidth: "220px", maxHeight: "220px", borderRadius: "8px", cursor: "pointer", display: "block" }}
|
||||||
|
onClick={() => window.open(blobUrl, "_blank")}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span style={{ fontSize: "0.8rem", opacity: 0.7 }}>📎 Loading image…</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ marginTop: "0.4rem" }}>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
style={{ color: "inherit", fontSize: "0.85rem", opacity: 0.85 }}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!blobUrl) return;
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = blobUrl;
|
||||||
|
a.download = name || "attachment";
|
||||||
|
a.click();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
📎 {name || "Attachment"}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function AiChatPage() {
|
function AiChatPage() {
|
||||||
const { user, token, loading: authLoading } = useAuth();
|
const { user, token, loading: authLoading } = useAuth();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -501,16 +561,7 @@ function AiChatPage() {
|
|||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
{msg.attachmentUrl && (
|
{msg.attachmentUrl && (
|
||||||
<div style={s.attachment}>
|
<AttachmentPreview url={msg.attachmentUrl} name={msg.attachmentName} token={token} />
|
||||||
<a
|
|
||||||
href={msg.attachmentUrl}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
style={s.attachmentLink}
|
|
||||||
>
|
|
||||||
📎 {msg.attachmentName || "Attachment"}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
<div style={{ ...s.timestamp, ...(isOwn ? s.timestampUser : {}) }}>
|
<div style={{ ...s.timestamp, ...(isOwn ? s.timestampUser : {}) }}>
|
||||||
{msg.timestamp ? new Date(msg.timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : ""}
|
{msg.timestamp ? new Date(msg.timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : ""}
|
||||||
|
|||||||
@@ -8,6 +8,66 @@ import { createStompClient } from "@/lib/chatSocket";
|
|||||||
|
|
||||||
const API_BASE = "";
|
const API_BASE = "";
|
||||||
|
|
||||||
|
function isImageFilename(name) {
|
||||||
|
return /\.(jpe?g|png|gif|webp|bmp|svg)$/i.test(name || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function AttachmentPreview({ url, name, token }) {
|
||||||
|
const [blobUrl, setBlobUrl] = useState(null);
|
||||||
|
const isImage = isImageFilename(name);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!url || !token) return;
|
||||||
|
let objectUrl;
|
||||||
|
fetch(url, { headers: { Authorization: `Bearer ${token}` } })
|
||||||
|
.then((r) => (r.ok ? r.blob() : null))
|
||||||
|
.then((blob) => {
|
||||||
|
if (blob) {
|
||||||
|
objectUrl = URL.createObjectURL(blob);
|
||||||
|
setBlobUrl(objectUrl);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
return () => { if (objectUrl) URL.revokeObjectURL(objectUrl); };
|
||||||
|
}, [url, token]);
|
||||||
|
|
||||||
|
if (isImage) {
|
||||||
|
return (
|
||||||
|
<div style={{ marginTop: "0.5rem" }}>
|
||||||
|
{blobUrl ? (
|
||||||
|
<img
|
||||||
|
src={blobUrl}
|
||||||
|
alt={name || "attachment"}
|
||||||
|
style={{ maxWidth: "220px", maxHeight: "220px", borderRadius: "8px", cursor: "pointer", display: "block" }}
|
||||||
|
onClick={() => window.open(blobUrl, "_blank")}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span style={{ fontSize: "0.8rem", opacity: 0.7 }}>📎 Loading image…</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ marginTop: "0.4rem" }}>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
style={{ color: "inherit", fontSize: "0.85rem", opacity: 0.85 }}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!blobUrl) return;
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = blobUrl;
|
||||||
|
a.download = name || "attachment";
|
||||||
|
a.click();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
📎 {name || "Attachment"}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function ChatPage() {
|
function ChatPage() {
|
||||||
const { user, token, loading: authLoading } = useAuth();
|
const { user, token, loading: authLoading } = useAuth();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -532,16 +592,7 @@ function ChatPage() {
|
|||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
{msg.attachmentUrl && (
|
{msg.attachmentUrl && (
|
||||||
<div style={s.attachment}>
|
<AttachmentPreview url={msg.attachmentUrl} name={msg.attachmentName} token={token} />
|
||||||
<a
|
|
||||||
href={msg.attachmentUrl}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
style={s.attachmentLink}
|
|
||||||
>
|
|
||||||
📎 {msg.attachmentName || "Attachment"}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
<div style={{ ...s.timestamp, ...(isOwn ? s.timestampUser : {}) }}>
|
<div style={{ ...s.timestamp, ...(isOwn ? s.timestampUser : {}) }}>
|
||||||
{msg.timestamp ? new Date(msg.timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : ""}
|
{msg.timestamp ? new Date(msg.timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) : ""}
|
||||||
|
|||||||
@@ -683,8 +683,8 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.info-page {
|
.info-page {
|
||||||
min-height: 100vh;
|
|
||||||
background: linear-gradient(to bottom, #f9f9f9, #ffffff);
|
background: linear-gradient(to bottom, #f9f9f9, #ffffff);
|
||||||
|
padding-bottom: 4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-hero {
|
.info-hero {
|
||||||
|
|||||||
Reference in New Issue
Block a user