feat: build IPTEK company website with full bilingual support

- Complete Next.js 16 app with App Router: Home, About, Products, Contact, Privacy pages
- Product detail pages: ZappCare, Unified TMS, EMR Clinic
- Bilingual support (Indonesian/English) via LanguageContext + translations.ts
- Language switcher pill button (🇮🇩 ID / 🇬🇧 EN) in Navbar with localStorage persistence
- Navbar with logo, responsive mobile menu, translated nav links
- Contact form with captcha, server action email sending, translated labels
- Material Design 3 color tokens, Manrope + Inter fonts, Material Symbols icons
- Local product image assets and company logo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Wira Basalamah
2026-04-21 12:25:03 +07:00
parent c96a117764
commit c955792497
25 changed files with 2671 additions and 85 deletions

View File

@ -0,0 +1,67 @@
"use server";
import nodemailer from "nodemailer";
export type ContactPayload = {
name: string;
email: string;
company: string;
phone: string;
topic: string;
message: string;
};
export type SendResult = { ok: true } | { ok: false; error: string };
export async function sendContactEmail(data: ContactPayload): Promise<SendResult> {
const { SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS } = process.env;
if (!SMTP_HOST || !SMTP_USER || !SMTP_PASS) {
return { ok: false, error: "Konfigurasi email server belum diatur." };
}
const transporter = nodemailer.createTransport({
host: SMTP_HOST,
port: Number(SMTP_PORT ?? 587),
secure: Number(SMTP_PORT) === 465,
auth: { user: SMTP_USER, pass: SMTP_PASS },
});
const html = `
<div style="font-family: Inter, sans-serif; max-width: 600px; margin: 0 auto; color: #191c1e;">
<div style="background: linear-gradient(135deg, #004cca, #0062ff); padding: 32px; border-radius: 12px 12px 0 0;">
<h1 style="color: white; margin: 0; font-size: 24px;">Pesan Baru dari Website IPTEK</h1>
</div>
<div style="background: #f7f9fb; padding: 32px; border-radius: 0 0 12px 12px; border: 1px solid #e0e3e5;">
<table style="width: 100%; border-collapse: collapse;">
<tr><td style="padding: 8px 0; color: #737687; width: 140px; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;">Nama</td><td style="padding: 8px 0; font-weight: 500;">${data.name}</td></tr>
<tr><td style="padding: 8px 0; color: #737687; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;">Email</td><td style="padding: 8px 0;"><a href="mailto:${data.email}" style="color: #004cca;">${data.email}</a></td></tr>
<tr><td style="padding: 8px 0; color: #737687; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;">Perusahaan</td><td style="padding: 8px 0;">${data.company || "-"}</td></tr>
<tr><td style="padding: 8px 0; color: #737687; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;">WhatsApp</td><td style="padding: 8px 0;">${data.phone || "-"}</td></tr>
<tr><td style="padding: 8px 0; color: #737687; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;">Topik</td><td style="padding: 8px 0;"><span style="background: #dbe1ff; color: #004cca; padding: 3px 10px; border-radius: 99px; font-size: 13px; font-weight: 600;">${data.topic}</span></td></tr>
</table>
<div style="margin-top: 24px; padding-top: 24px; border-top: 1px solid #e0e3e5;">
<p style="color: #737687; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 10px;">Pesan</p>
<p style="margin: 0; line-height: 1.7; white-space: pre-wrap;">${data.message}</p>
</div>
<div style="margin-top: 24px; padding-top: 16px; border-top: 1px solid #e0e3e5; font-size: 12px; color: #737687;">
Dikirim pada ${new Date().toLocaleString("id-ID", { timeZone: "Asia/Jakarta", dateStyle: "long", timeStyle: "short" })} WIB
</div>
</div>
</div>
`;
try {
await transporter.sendMail({
from: `"IPTEK Website" <${SMTP_USER}>`,
to: "support@iptek.co",
replyTo: data.email,
subject: `[${data.topic}] Pesan dari ${data.name} IPTEK Website`,
html,
});
return { ok: true };
} catch (err) {
console.error("Email send error:", err);
return { ok: false, error: "Gagal mengirim pesan. Silakan coba lagi atau hubungi kami langsung." };
}
}