phosphat-report-app/app/routes/mail-settings.tsx
2025-07-24 12:39:15 +03:00

266 lines
9.3 KiB
TypeScript

import { json, type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/node";
import { Form, useActionData, useLoaderData } from "@remix-run/react";
import { PrismaClient } from "@prisma/client";
import { requireAuthLevel } from "~/utils/auth.server";
import { testEmailConnection } from "~/utils/mail.server";
import DashboardLayout from "~/components/DashboardLayout";
import { useState } from "react";
const prisma = new PrismaClient();
export async function loader({ request }: LoaderFunctionArgs) {
// Require auth level 3 to access mail settings
const user = await requireAuthLevel(request, 3);
const mailSettings = await prisma.mailSettings.findFirst();
return json({ mailSettings, user });
}
export async function action({ request }: ActionFunctionArgs) {
// Require auth level 3 to modify mail settings
await requireAuthLevel(request, 3);
const formData = await request.formData();
const action = formData.get("_action");
if (action === "test") {
const result = await testEmailConnection();
return json(result);
}
const host = formData.get("host") as string;
const port = parseInt(formData.get("port") as string);
const secure = formData.get("secure") === "on";
const username = formData.get("username") as string;
const password = formData.get("password") as string;
const fromName = formData.get("fromName") as string;
const fromEmail = formData.get("fromEmail") as string;
if (!host || !port || !username || !password || !fromName || !fromEmail) {
return json({ error: "All fields are required" }, { status: 400 });
}
try {
// Check if settings exist
const existingSettings = await prisma.mailSettings.findFirst();
if (existingSettings) {
// Update existing settings
await prisma.mailSettings.update({
where: { id: existingSettings.id },
data: {
host,
port,
secure,
username,
password,
fromName,
fromEmail,
},
});
} else {
// Create new settings
await prisma.mailSettings.create({
data: {
host,
port,
secure,
username,
password,
fromName,
fromEmail,
},
});
}
return json({ success: "Mail settings saved successfully" });
} catch (error) {
return json({ error: "Failed to save mail settings" }, { status: 500 });
}
}
export default function MailSettings() {
const { mailSettings, user } = useLoaderData<typeof loader>();
const actionData = useActionData<typeof action>();
const [showPassword, setShowPassword] = useState(false);
return (
<DashboardLayout user={user}>
<div className="max-w-2xl mx-auto p-6">
<h1 className="text-2xl font-bold mb-6">Mail Settings</h1>
{/* SMTP Configuration Examples */}
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6">
<h3 className="text-lg font-semibold text-blue-800 mb-2">Common SMTP Settings</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
<div>
<h4 className="font-medium text-blue-700">Gmail</h4>
<p>Host: smtp.gmail.com</p>
<p>Port: 587 (TLS) or 465 (SSL)</p>
<p>Note: Use App Password, not regular password</p>
</div>
<div>
<h4 className="font-medium text-blue-700">Outlook/Hotmail</h4>
<p>Host: smtp-mail.outlook.com</p>
<p>Port: 587 (TLS)</p>
<p>Secure: No (uses STARTTLS)</p>
</div>
<div>
<h4 className="font-medium text-blue-700">Yahoo</h4>
<p>Host: smtp.mail.yahoo.com</p>
<p>Port: 587 (TLS) or 465 (SSL)</p>
<p>Note: Enable "Less secure apps"</p>
</div>
<div>
<h4 className="font-medium text-blue-700">Custom SMTP</h4>
<p>Contact your email provider</p>
<p>Port 587 (TLS) is most common</p>
<p>Port 465 (SSL) for secure connections</p>
</div>
</div>
</div>
{actionData?.error && (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
{actionData.error}
</div>
)}
{actionData?.success && (
<div className="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4">
{actionData.success}
</div>
)}
<Form method="post" className="space-y-4">
<div>
<label htmlFor="host" className="block text-sm font-medium text-gray-700">
SMTP Host
</label>
<input
type="text"
id="host"
name="host"
defaultValue={mailSettings?.host || ""}
className="mt-1 p-2 h-9 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
placeholder="smtp.gmail.com"
required
/>
</div>
<div>
<label htmlFor="port" className="block text-sm font-medium text-gray-700">
SMTP Port
</label>
<input
type="number"
id="port"
name="port"
defaultValue={mailSettings?.port || 587}
className="mt-1 block p-2 h-9 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
required
/>
</div>
<div>
<label className="flex items-center">
<input
type="checkbox"
name="secure"
defaultChecked={mailSettings?.secure || false}
className="rounded p-2 h-9 border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
/>
<span className="ml-2 text-sm text-gray-700">Use SSL/TLS</span>
</label>
</div>
<div>
<label htmlFor="username" className="block text-sm font-medium text-gray-700">
Username
</label>
<input
type="text"
id="username"
name="username"
defaultValue={mailSettings?.username || ""}
className="mt-1 block p-2 h-9 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
required
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-gray-700">
Password
</label>
<div className="relative">
<input
type={showPassword ? "text" : "password"}
id="password"
name="password"
defaultValue={mailSettings?.password || ""}
className="mt-1 block w-full p-2 h-9 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 pr-10"
required
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute inset-y-0 right-0 pr-3 flex items-center text-sm leading-5"
>
{showPassword ? "Hide" : "Show"}
</button>
</div>
</div>
<div>
<label htmlFor="fromName" className="block text-sm font-medium text-gray-700">
From Name
</label>
<input
type="text"
id="fromName"
name="fromName"
defaultValue={mailSettings?.fromName || ""}
className="mt-1 block w-full p-2 h-9 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
placeholder="Your Company Name"
required
/>
</div>
<div>
<label htmlFor="fromEmail" className="block text-sm font-medium text-gray-700">
From Email
</label>
<input
type="email"
id="fromEmail"
name="fromEmail"
defaultValue={mailSettings?.fromEmail || ""}
className="mt-1 block p-2 h-9 w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
placeholder="noreply@yourcompany.com"
required
/>
</div>
<div className="flex space-x-4">
<button
type="submit"
className="flex-1 flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Save Mail Settings
</button>
<button
type="submit"
name="_action"
value="test"
className="flex-1 flex justify-center py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Test Connection
</button>
</div>
</Form>
</div>
</DashboardLayout>
);
}