package email import ( "fmt" "strings" ) func renderTemplate(notifType NotificationType, data interface{}, siteName, siteURL string) string { var content string switch notifType { case TypeWelcome: d := data.(WelcomeData) content = renderWelcome(d) case TypeEmailVerify: d := data.(EmailVerifyData) content = renderEmailVerify(d) case TypePasswordReset: d := data.(PasswordResetData) content = renderPasswordReset(d) case TypeLimitWarning: d := data.(LimitWarningData) content = renderLimitWarning(d) case TypeSpaceInvite: d := data.(SpaceInviteData) content = renderSpaceInvite(d) case TypeSystemAlert: d := data.(SystemAlertData) content = renderSystemAlert(d) default: content = "

Уведомление

" } return wrapBase(content, siteName, siteURL) } func wrapBase(content, siteName, siteURL string) string { return fmt.Sprintf(` %s
%s
%s

Вы получили это письмо, потому что зарегистрированы на %s

Настроить уведомления

`, siteName, siteURL, siteName, content, siteURL, siteName, siteURL) } func renderWelcome(d WelcomeData) string { return fmt.Sprintf(`

Добро пожаловать, %s!

Мы рады, что вы присоединились. GooSeek — это ваш AI-помощник для поиска, анализа и работы с информацией.

Вот что вы можете делать:

🔍 Умный поиск с AI-ответами
💬 Чат с нейросетью
📚 Библиотека и коллекции
Начать работу `, escapeHTML(d.Name), d.SiteURL) } func renderEmailVerify(d EmailVerifyData) string { return fmt.Sprintf(`

Подтвердите email

Здравствуйте, %s! Для завершения регистрации подтвердите ваш email-адрес.

Подтвердить email

Если кнопка не работает, скопируйте ссылку:
%s

Ссылка действительна 24 часа.

`, escapeHTML(d.Name), d.VerifyURL, d.VerifyURL, d.VerifyURL) } func renderPasswordReset(d PasswordResetData) string { return fmt.Sprintf(`

Сброс пароля

Здравствуйте, %s! Мы получили запрос на сброс пароля для вашего аккаунта.

Сбросить пароль

Если кнопка не работает, скопируйте ссылку:
%s

Ссылка действительна 1 час. Если вы не запрашивали сброс — проигнорируйте это письмо.

`, escapeHTML(d.Name), d.ResetURL, d.ResetURL, d.ResetURL) } func renderLimitWarning(d LimitWarningData) string { barColor := "#f59e0b" if d.Percentage >= 100 { barColor = "#ef4444" } tierLabel := "Бесплатный" switch d.Tier { case "pro": tierLabel = "Pro" case "business": tierLabel = "Business" } barWidth := d.Percentage if barWidth > 100 { barWidth = 100 } return fmt.Sprintf(`

Лимит запросов

Здравствуйте, %s! Вы использовали %d%% дневного лимита запросов на тарифе %s.

%d из %d запросов

Увеличить лимит `, escapeHTML(d.Name), d.Percentage, tierLabel, barColor, barWidth, d.UsageCount, d.LimitCount, d.UpgradeURL) } func renderSpaceInvite(d SpaceInviteData) string { return fmt.Sprintf(`

Приглашение в Space

%s приглашает вас присоединиться к пространству «%s».

Принять приглашение

Если кнопка не работает, скопируйте ссылку:
%s

`, escapeHTML(d.InviterName), escapeHTML(d.SpaceName), d.InviteURL, d.InviteURL, d.InviteURL) } func renderSystemAlert(d SystemAlertData) string { detailsBlock := "" if d.Details != "" { detailsBlock = fmt.Sprintf(`
%s
`, escapeHTML(d.Details)) } return fmt.Sprintf(`

%s

%s

%s `, escapeHTML(d.Title), escapeHTML(d.Message), detailsBlock) } func escapeHTML(s string) string { r := strings.NewReplacer( "&", "&", "<", "<", ">", ">", `"`, """, "'", "'", ) return r.Replace(s) }