package lib import ( "fmt" "time" ) // Broadcast logic — answer published → notify all linked requesters. // Uses the broadcasts table for idempotency. // NotifyAnswerPublished broadcasts a published answer to all linked requesters. Stub. func NotifyAnswerPublished(db *DB, cfg *Config, answerID string) error { // TODO: implementation steps: // 1. Query answer_links WHERE answer_id = ? AND status = 'confirmed' // 2. For each linked request, find the origin_id (buyer) // 3. Check broadcasts table for idempotency // 4. Send notification (email, in-app, etc.) // 5. Record in broadcasts table return nil } // NotifyTaskAssigned notifies a user that a task has been assigned to them. Stub. func NotifyTaskAssigned(db *DB, cfg *Config, entryID, assigneeID string) error { // TODO: implement notification return nil } // NotifyChainComplete fires when a routing chain completes back to origin. Stub. func NotifyChainComplete(db *DB, cfg *Config, entryID string) error { // TODO: implement chain completion notification return nil } // ---- Email Notification Functions ---- // NotifyInvite sends an invitation email to a new user. func NotifyInvite(m *Mailer, to, inviterName, inviterOrg, projectName, inviteURL string) error { if !m.Enabled() { return nil } subject := fmt.Sprintf("You've been invited to join %s on Dealspace", projectName) data := InviteData{ InviterName: inviterName, InviterOrg: inviterOrg, ProjectName: projectName, InviteURL: inviteURL, ExpiresIn: "7 days", } return m.SendTemplate(to, subject, "invite.html", data) } // NotifyTasksAssigned sends an email when new tasks are assigned to a user. func NotifyTasksAssigned(m *Mailer, to, projectName string, tasks []string) error { if !m.Enabled() { return nil } count := len(tasks) var subject string if count == 1 { subject = fmt.Sprintf("You have 1 new task on %s", projectName) } else { subject = fmt.Sprintf("You have %d new tasks on %s", count, projectName) } // Convert task strings to TaskItem (simplified — in real usage, you'd pass full task data) taskItems := make([]TaskItem, 0, len(tasks)) for _, t := range tasks { taskItems = append(taskItems, TaskItem{ Title: t, }) } data := TasksAssignedData{ ProjectName: projectName, Count: count, Tasks: taskItems, TasksURL: "https://app.muskepo.com/app/tasks", } return m.SendTemplate(to, subject, "tasks_assigned.html", data) } // NotifyAnswerSubmitted notifies an IB member that a seller submitted an answer. func NotifyAnswerSubmitted(m *Mailer, to, answererName, requestTitle, wsName, reviewURL string) error { if !m.Enabled() { return nil } subject := fmt.Sprintf("%s submitted an answer for: %s", answererName, requestTitle) data := AnswerSubmittedData{ AnswererName: answererName, RequestTitle: requestTitle, WorkstreamName: wsName, ReviewURL: reviewURL, } return m.SendTemplate(to, subject, "answer_submitted.html", data) } // NotifyAnswerApproved notifies a seller that their answer was approved. func NotifyAnswerApproved(m *Mailer, to, requestTitle string, published bool) error { if !m.Enabled() { return nil } subject := "Your answer was approved ✓" data := AnswerApprovedData{ RequestTitle: requestTitle, Published: published, } return m.SendTemplate(to, subject, "answer_approved.html", data) } // NotifyAnswerRejected notifies a seller that their answer was rejected. func NotifyAnswerRejected(m *Mailer, to, requestTitle, reason, requestURL string) error { if !m.Enabled() { return nil } subject := "Your answer needs revision" data := AnswerRejectedData{ RequestTitle: requestTitle, Reason: reason, RequestURL: requestURL, } return m.SendTemplate(to, subject, "answer_rejected.html", data) } // NotifyRequestForwarded notifies a user that a request was forwarded to them. func NotifyRequestForwarded(m *Mailer, to, senderName, requestTitle, requestURL string, dueAt *time.Time) error { if !m.Enabled() { return nil } subject := fmt.Sprintf("%s forwarded a request to you: %s", senderName, requestTitle) data := RequestForwardedData{ SenderName: senderName, RequestTitle: requestTitle, RequestURL: requestURL, HasDueDate: dueAt != nil, } if dueAt != nil { data.DueDate = dueAt.Format("January 2, 2006") } return m.SendTemplate(to, subject, "request_forwarded.html", data) } // NotifyWelcome sends a welcome email to a new user after accepting an invite. func NotifyWelcome(m *Mailer, to, name, tasksURL string) error { if !m.Enabled() { return nil } subject := "Welcome to Dealspace" data := WelcomeData{ RecipientName: name, TasksURL: tasksURL, } return m.SendTemplate(to, subject, "welcome.html", data) }