package views
import (
"nebula/layouts"
"nebula/models"
"strconv"
"strings"
"time"
)
templ SettingsPage(data models.SettingsData, activeTab string) {
@layouts.DashboardLayout("Settings - Sonr", layouts.WalletUser{Name: "Sonr Wallet", Address: "sonr1x9f...7k2m"}, "settings") {
@settingsStyles()
Profile
Devices
OAuth
Notifications
Emails
Phone Numbers
Developer
@ProfileTab(data.Profile)
@DevicesTab(data.Devices)
@OAuthTab(data.OAuth)
@NotificationsTab(data.Notifications)
@EmailsTab(data.Emails)
@PhonesTab(data.Phones, data.SMSSettings)
@DeveloperTab(data.Developer)
@AddEmailDialog()
@AddPhoneDialog()
@AddDeviceDialog()
@GenerateKeyDialog()
@AddWebhookDialog()
@settingsScripts()
}
}
templ ProfileTab(profile models.ProfileSettings) {
}
templ DevicesTab(devices []models.Device) {
Linked Devices
Passkeys and security keys registered with your account
Add Device
for _, device := range devices {
@DeviceItem(device)
}
Security Recommendation
Register at least 2 devices to ensure account recovery if one is lost.
}
templ DeviceItem(device models.Device) {
{ device.Name }
if device.IsCurrent {
Current
}
if device.Browser != "" {
{ device.Browser } on { device.OS } -
}
{ device.AuthType }
Added { formatDate(device.AddedAt) }
Last used: { formatRelativeTime(device.LastUsed) }
Rename
Remove
}
func deviceIcon(deviceType string) string {
switch deviceType {
case "laptop":
return "laptop"
case "mobile":
return "mobile"
case "key":
return "key"
case "desktop":
return "desktop"
default:
return "laptop"
}
}
templ OAuthTab(oauth models.OAuthSettings) {
OAuth Settings
Configure your identity provider settings
Authorized Clients
View All
for _, client := range oauth.Clients {
@AuthorizedClientCard(client)
}
Cancel
Save Changes
}
templ AuthorizedClientCard(client models.AuthorizedClient) {
{ client.Name }
{ client.Domain }
if client.Status == "active" {
Active
} else {
Idle
}
Revoke
}
templ NotificationsTab(prefs models.NotificationPrefs) {
Notification Preferences
Choose how and when you receive notifications
Security Alerts
for _, item := range prefs.SecurityAlerts {
@NotificationRow(item)
}
Transaction Notifications
for _, item := range prefs.Transactions {
@NotificationRow(item)
}
App Notifications
for _, item := range prefs.Apps {
@NotificationRow(item)
}
Marketing & Updates
for _, item := range prefs.Marketing {
@NotificationRow(item)
}
Save Preferences
}
templ NotificationRow(item models.NotificationItem) {
{ item.Title }
{ item.Description }
if item.Threshold > 0 {
USD
} else {
}
}
templ EmailsTab(emails []models.Email) {
Email Addresses
Manage email addresses linked to your account
Add Email
for _, email := range emails {
@EmailItem(email)
}
Your primary email is used for account recovery and important notifications. You must have at least one verified email.
}
templ EmailItem(email models.Email) {
}
templ PhonesTab(phones []models.Phone, smsSettings models.SMSSettings) {
Phone Numbers
Manage phone numbers for 2FA and recovery
Add Phone
for _, phone := range phones {
@PhoneItem(phone)
}
SMS Authentication
Enable SMS 2FA
Receive codes via SMS for high-risk actions
SMS recovery codes
Allow account recovery via SMS
SMS Security Notice
SMS-based authentication is less secure than passkeys. We recommend using passkeys as your primary authentication method.
}
templ PhoneItem(phone models.Phone) {
}
templ DeveloperTab(dev models.DeveloperSettings) {
Developer Settings
API access and integration options
API Keys
Generate Key
for _, key := range dev.APIKeys {
@APIKeyCard(key)
}
Webhooks
Add Endpoint
for _, wh := range dev.Webhooks {
@WebhookCard(wh)
}
@OAuthAppConfigCard(dev.OAuthApp)
Developer Mode
Enable debug logging
Log detailed API requests and responses
Test mode
Use testnet for all transactions
Show raw responses
Display JSON in UI for debugging
Cancel
Save Changes
}
templ APIKeyCard(key models.APIKey) {
{ key.Name }
Created { formatDate(key.CreatedAt) }
if key.Environment == "live" {
Active
} else {
Test Mode
}
{ key.KeyPreview }
}
templ WebhookCard(wh models.Webhook) {
{ wh.URL }
if wh.Status == "active" {
Active
} else {
Failing
}
if wh.Status == "failing" {
{ formatEvents(wh.Events) } events - { itoa(wh.FailureCount) } failures in last hour
} else {
{ formatEvents(wh.Events) } events - Last triggered { formatRelativeTime(wh.LastTriggered) }
}
Edit
Send Test
View Logs
Delete
}
templ OAuthAppConfigCard(config models.OAuthAppConfig) {
OAuth Application
Redirect URIs
for _, uri := range config.RedirectURIs {
}
Add URI
}
templ AddEmailDialog() {
We'll send a verification link to this address.
Cancel
Send Verification
}
templ AddPhoneDialog() {
+1
+44
+49
+33
+81
We'll send a verification code via SMS.
Cancel
Send Code
}
templ AddDeviceDialog() {
Register a Passkey
Use your device's built-in authenticator (Face ID, Touch ID, Windows Hello) or a security key.
Register Device
or
Use Security Key
Cancel
}
templ GenerateKeyDialog() {
Test Mode
Production
Full Access
Read Only
Write Only
Your secret key will only be shown once. Store it securely.
Cancel
Generate Key
}
templ AddWebhookDialog() {
Events to Subscribe
transaction.*
All transaction events
connection.*
App connection events
signature.*
Signature request events
account.*
Account update events
Cancel
Create Webhook
}
func itoa(i int) string {
return strconv.Itoa(i)
}
func formatDate(t time.Time) string {
return t.Format("Jan 2, 2006")
}
func formatRelativeTime(t time.Time) string {
diff := time.Since(t)
if diff < time.Minute {
return "Just now"
}
if diff < time.Hour {
mins := int(diff.Minutes())
if mins == 1 {
return "1 minute ago"
}
return strconv.Itoa(mins) + " minutes ago"
}
if diff < 24*time.Hour {
hours := int(diff.Hours())
if hours == 1 {
return "1 hour ago"
}
return strconv.Itoa(hours) + " hours ago"
}
days := int(diff.Hours() / 24)
if days == 1 {
return "1 day ago"
}
if days < 14 {
return strconv.Itoa(days) + " days ago"
}
weeks := days / 7
if weeks == 1 {
return "1 week ago"
}
return strconv.Itoa(weeks) + " weeks ago"
}
func formatEvents(events []string) string {
if len(events) == 1 && events[0] == "*" {
return "All"
}
return strings.Join(events, ", ")
}
templ settingsStyles() {
}
templ settingsScripts() {
}