mirror of
https://github.com/temetro/temetro.git
synced 2026-08-27 19:06:52 +00:00
feat: email provider, admin password reset, portal new-patient, chat pill
Chat: history pill now shows a History icon + a Start-new-chat (SquarePen) button; removed the duplicate chat-history list from the sidebar. Email: deployment-wide email provider config (Resend/Postmark/SendGrid/SMTP) in Settings → Developers, with encrypted API key and a Send-test action. sendEmail dispatches via the chosen provider (REST via fetch; SMTP via nodemailer). Forgot password with no provider: alert the clinic admin(s) via a "System" message card in Messages + a bell notification (seeded system user + per-clinic System conversation); clicking deep-links to /settings?tab=careTeam&member=<id>. Admins can set a member's password directly from the employee dialog (PATCH /api/staff/:id/password via Better Auth's internal context — no admin plugin needed). Patient Portal: "New patient" booking path registers a demographics-only patient then books; bookings reject double-booked slots (409). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
CalendarClock,
|
||||
Download,
|
||||
FileText,
|
||||
KeyRound,
|
||||
Mail,
|
||||
Paperclip,
|
||||
Plus,
|
||||
@@ -93,7 +94,32 @@ const GROUP_WINDOW_MS = 5 * 60 * 1000;
|
||||
// shared-appointment card. Alignment (left/right) comes from the parent column.
|
||||
function SentAttachment({ att }: { att: MessageAttachment }) {
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
const [apptOpen, setApptOpen] = useState(false);
|
||||
if (att.kind === "passwordReset") {
|
||||
return (
|
||||
<button
|
||||
className="max-w-[75%] rounded-2xl border border-warning/40 bg-warning/5 p-3 text-left text-sm transition-colors hover:bg-warning/10"
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/settings?tab=careTeam&member=${encodeURIComponent(att.userId)}`,
|
||||
)
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
<div className="flex items-center gap-1.5 text-warning text-xs">
|
||||
<KeyRound className="size-3.5" />
|
||||
{t("messages.system.label")}
|
||||
</div>
|
||||
<p className="mt-1 font-medium text-foreground">
|
||||
{t("messages.system.passwordResetTitle")}
|
||||
</p>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t("messages.system.passwordResetBody", { name: att.userName })}
|
||||
</p>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
if (att.kind === "file") {
|
||||
return (
|
||||
<button
|
||||
@@ -668,7 +694,9 @@ export function MessagesView() {
|
||||
<span className="max-w-40 truncate">
|
||||
{att.kind === "file"
|
||||
? att.fileName
|
||||
: att.appointment.name}
|
||||
: att.kind === "appointment"
|
||||
? att.appointment.name
|
||||
: ""}
|
||||
</span>
|
||||
<button
|
||||
aria-label={t("messages.attach.remove")}
|
||||
|
||||
Reference in New Issue
Block a user