- Add IsOwn bool to DiscussionMessageView; set via user.ID comparison in DiscussionMessagesFromRows and DiscussionMessageFromRow - Thread currentUserID through loadDiscussionTabData and all call sites - discussion.templ: branch message-own vs message-other on message.IsOwn - Restore .divide-y wrapper inside #discussion-messages (discussion-sse.js depends on it to locate the message list before appending SSE events) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
132 lines
3.1 KiB
Go
132 lines
3.1 KiB
Go
package templates
|
|
|
|
import (
|
|
"strconv"
|
|
"time"
|
|
|
|
"backend/internal/db/sqlc"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const DiscussionMaxBodyLength = 10000
|
|
|
|
type DiscussionForm struct {
|
|
Body string
|
|
}
|
|
|
|
type DiscussionErrors struct {
|
|
Body string
|
|
General string
|
|
}
|
|
|
|
type DiscussionMessageView struct {
|
|
ID uuid.UUID
|
|
AuthorEmail string
|
|
Body string
|
|
CreatedAt time.Time
|
|
IsOwn bool
|
|
}
|
|
|
|
type DiscussionTabData struct {
|
|
Messages []DiscussionMessageView
|
|
}
|
|
|
|
type TabloCardView struct {
|
|
Tablo sqlc.Tablo
|
|
DiscussionUnreadCount int64
|
|
}
|
|
|
|
func DiscussionPostURL(tabloID uuid.UUID) string {
|
|
return "/tablos/" + tabloID.String() + "/discussion/messages"
|
|
}
|
|
|
|
func DiscussionMaxBodyLengthString() string {
|
|
return strconv.Itoa(DiscussionMaxBodyLength)
|
|
}
|
|
|
|
func DiscussionURL(tabloID uuid.UUID) string {
|
|
return "/tablos/" + tabloID.String() + "/discussion"
|
|
}
|
|
|
|
func DiscussionStreamURL(tabloID uuid.UUID) string {
|
|
return "/tablos/" + tabloID.String() + "/discussion/stream"
|
|
}
|
|
|
|
func DiscussionMessagesFromRows(rows []sqlc.ListDiscussionMessagesByTabloRow, currentUserID uuid.UUID) []DiscussionMessageView {
|
|
messages := make([]DiscussionMessageView, 0, len(rows))
|
|
for _, row := range rows {
|
|
messages = append(messages, DiscussionMessageView{
|
|
ID: row.ID,
|
|
AuthorEmail: row.AuthorEmail,
|
|
Body: row.Body,
|
|
CreatedAt: row.CreatedAt.Time,
|
|
IsOwn: row.AuthorUserID == currentUserID,
|
|
})
|
|
}
|
|
return messages
|
|
}
|
|
|
|
func DiscussionMessageFromRow(row sqlc.GetDiscussionMessageWithAuthorRow, isOwn bool) DiscussionMessageView {
|
|
return DiscussionMessageView{
|
|
ID: row.ID,
|
|
AuthorEmail: row.AuthorEmail,
|
|
Body: row.Body,
|
|
CreatedAt: row.CreatedAt.Time,
|
|
IsOwn: isOwn,
|
|
}
|
|
}
|
|
|
|
func TabloCardsFromUnreadRows(rows []sqlc.ListTablosByUserWithDiscussionUnreadRow) []TabloCardView {
|
|
cards := make([]TabloCardView, 0, len(rows))
|
|
for _, row := range rows {
|
|
cards = append(cards, TabloCardView{
|
|
Tablo: sqlc.Tablo{
|
|
ID: row.ID,
|
|
UserID: row.UserID,
|
|
Title: row.Title,
|
|
Description: row.Description,
|
|
Color: row.Color,
|
|
CreatedAt: row.CreatedAt,
|
|
UpdatedAt: row.UpdatedAt,
|
|
},
|
|
DiscussionUnreadCount: row.DiscussionUnreadCount,
|
|
})
|
|
}
|
|
return cards
|
|
}
|
|
|
|
func TabloCardFromTablo(tablo sqlc.Tablo) TabloCardView {
|
|
return TabloCardView{Tablo: tablo}
|
|
}
|
|
|
|
func DiscussionUnreadDisplay(count int64) string {
|
|
if count > 99 {
|
|
return "99+"
|
|
}
|
|
return strconv.FormatInt(count, 10)
|
|
}
|
|
|
|
func DiscussionUnreadAriaLabel(count int64) string {
|
|
if count == 1 {
|
|
return "1 unread discussion message"
|
|
}
|
|
return strconv.FormatInt(count, 10) + " unread discussion messages"
|
|
}
|
|
|
|
func DiscussionDateLabel(t time.Time) string {
|
|
return t.Local().Format("January 2, 2006")
|
|
}
|
|
|
|
func DiscussionTimestampLabel(t time.Time) string {
|
|
return t.Local().Format("January 2, 2006 15:04")
|
|
}
|
|
|
|
func DiscussionShowDaySeparator(messages []DiscussionMessageView, index int) bool {
|
|
if index == 0 {
|
|
return true
|
|
}
|
|
current := messages[index].CreatedAt.Local()
|
|
previous := messages[index-1].CreatedAt.Local()
|
|
return current.Year() != previous.Year() || current.YearDay() != previous.YearDay()
|
|
}
|