Files
gmail-hook/apps/web/src/pages/Message.jsx
T
nsrbandCursor 46a2e2a7b0 feat: add gmail-hook monorepo with watcher, api, and web
Ship the receipt pipeline (Livin/Grab/BRI), PocketBase spendings, PM2 ecosystem, and a proper .gitignore that excludes secrets, SQLite data, and media dumps.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-13 22:58:47 +07:00

81 lines
2.3 KiB
React

import { useEffect, useState } from "react";
import { Link, useParams } from "react-router-dom";
import { api } from "../api.js";
function formatDate(value) {
if (!value) return "";
const parsed = new Date(value);
if (Number.isNaN(parsed.getTime())) return value;
return parsed.toLocaleString();
}
export default function Message() {
const { id } = useParams();
const [message, setMessage] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
setLoading(true);
setError(null);
api(`/api/messages/${encodeURIComponent(id)}`)
.then((data) => {
if (!cancelled) setMessage(data);
})
.catch((err) => {
if (!cancelled) setError(err.message);
})
.finally(() => {
if (!cancelled) setLoading(false);
});
return () => {
cancelled = true;
};
}, [id]);
return (
<div className="space-y-4">
<Link to="/" className="btn btn-ghost btn-sm">
← Inbox
</Link>
{loading ? (
<div className="flex justify-center py-16">
<span className="loading loading-spinner loading-lg" />
</div>
) : error ? (
<div role="alert" className="alert alert-error text-sm">
{error}
</div>
) : message ? (
<article className="card bg-base-100 shadow">
<div className="card-body gap-4">
<h1 className="card-title text-xl">{message.subject}</h1>
<dl className="grid gap-1 text-sm">
<div className="flex gap-2">
<dt className="opacity-60">From</dt>
<dd>{message.from}</dd>
</div>
{message.to ? (
<div className="flex gap-2">
<dt className="opacity-60">To</dt>
<dd>{message.to}</dd>
</div>
) : null}
<div className="flex gap-2">
<dt className="opacity-60">Date</dt>
<dd>{formatDate(message.date)}</dd>
</div>
</dl>
<div className="divider my-0" />
<div className="message-body text-sm">
{message.body || message.snippet || "(empty message)"}
</div>
</div>
</article>
) : null}
</div>
);
}