fix(17): own messages right-aligned; restore .divide-y for SSE compatibility
- 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>
This commit is contained in:
parent
56194cfdb5
commit
d8e52f695b
3 changed files with 34 additions and 19 deletions
|
|
@ -22,14 +22,14 @@ type DiscussionDeps struct {
|
|||
Realtime DiscussionRealtime
|
||||
}
|
||||
|
||||
func loadDiscussionTabData(w http.ResponseWriter, r *http.Request, q *sqlc.Queries, tablo sqlc.Tablo) (templates.DiscussionTabData, bool) {
|
||||
func loadDiscussionTabData(w http.ResponseWriter, r *http.Request, q *sqlc.Queries, tablo sqlc.Tablo, currentUserID uuid.UUID) (templates.DiscussionTabData, bool) {
|
||||
rows, err := q.ListDiscussionMessagesByTablo(r.Context(), tablo.ID)
|
||||
if err != nil {
|
||||
slog.Default().Error("discussion: ListDiscussionMessagesByTablo failed", "tablo_id", tablo.ID, "err", err)
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
return templates.DiscussionTabData{}, false
|
||||
}
|
||||
data := templates.DiscussionTabData{Messages: templates.DiscussionMessagesFromRows(rows)}
|
||||
data := templates.DiscussionTabData{Messages: templates.DiscussionMessagesFromRows(rows, currentUserID)}
|
||||
return data, true
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ func TabloDiscussionTabHandler(deps DiscussionDeps) http.HandlerFunc {
|
|||
if !ok {
|
||||
return
|
||||
}
|
||||
data, ok := loadDiscussionTabData(w, r, deps.Queries, tablo)
|
||||
data, ok := loadDiscussionTabData(w, r, deps.Queries, tablo, user.ID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
|
@ -118,9 +118,9 @@ func DiscussionMessageCreateHandler(deps DiscussionDeps) http.HandlerFunc {
|
|||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
data := templates.DiscussionTabData{Messages: []templates.DiscussionMessageView{templates.DiscussionMessageFromRow(row)}}
|
||||
message := templates.DiscussionMessageFromRow(row, row.AuthorUserID == user.ID)
|
||||
data := templates.DiscussionTabData{Messages: []templates.DiscussionMessageView{message}}
|
||||
markDiscussionRead(r, deps.Queries, tablo, user.ID, data)
|
||||
message := templates.DiscussionMessageFromRow(row)
|
||||
if deps.Realtime != nil {
|
||||
html, err := renderDiscussionMessageHTML(r, message)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -19,12 +19,14 @@ templ DiscussionTabFragment(tablo sqlc.Tablo, data DiscussionTabData, form Discu
|
|||
if len(data.Messages) == 0 {
|
||||
@DiscussionEmptyState()
|
||||
} else {
|
||||
<div class="divide-y divide-slate-100">
|
||||
for i, message := range data.Messages {
|
||||
if DiscussionShowDaySeparator(data.Messages, i) {
|
||||
@DiscussionDaySeparator(message.CreatedAt)
|
||||
}
|
||||
@DiscussionMessageRow(message)
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@DiscussionComposer(tablo, form, errs, csrfToken)
|
||||
|
|
@ -45,6 +47,15 @@ templ DiscussionDaySeparator(createdAt time.Time) {
|
|||
}
|
||||
|
||||
templ DiscussionMessageRow(message DiscussionMessageView) {
|
||||
if message.IsOwn {
|
||||
<article id={ "discussion-message-" + message.ID.String() } data-message-id={ message.ID.String() } class="message-row message-own">
|
||||
<div class="message-meta">
|
||||
<span class="message-author">{ message.AuthorEmail }</span>
|
||||
<time class="message-timestamp" datetime={ message.CreatedAt.Format(time.RFC3339) }>{ DiscussionTimestampLabel(message.CreatedAt) }</time>
|
||||
</div>
|
||||
<div class="message-bubble">{ message.Body }</div>
|
||||
</article>
|
||||
} else {
|
||||
<article id={ "discussion-message-" + message.ID.String() } data-message-id={ message.ID.String() } class="message-row message-other">
|
||||
<div class="message-meta">
|
||||
<span class="message-author">{ message.AuthorEmail }</span>
|
||||
|
|
@ -52,6 +63,7 @@ templ DiscussionMessageRow(message DiscussionMessageView) {
|
|||
</div>
|
||||
<div class="message-bubble">{ message.Body }</div>
|
||||
</article>
|
||||
}
|
||||
}
|
||||
|
||||
templ DiscussionComposer(tablo sqlc.Tablo, form DiscussionForm, errs DiscussionErrors, csrfToken string) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ type DiscussionMessageView struct {
|
|||
AuthorEmail string
|
||||
Body string
|
||||
CreatedAt time.Time
|
||||
IsOwn bool
|
||||
}
|
||||
|
||||
type DiscussionTabData struct {
|
||||
|
|
@ -52,7 +53,7 @@ func DiscussionStreamURL(tabloID uuid.UUID) string {
|
|||
return "/tablos/" + tabloID.String() + "/discussion/stream"
|
||||
}
|
||||
|
||||
func DiscussionMessagesFromRows(rows []sqlc.ListDiscussionMessagesByTabloRow) []DiscussionMessageView {
|
||||
func DiscussionMessagesFromRows(rows []sqlc.ListDiscussionMessagesByTabloRow, currentUserID uuid.UUID) []DiscussionMessageView {
|
||||
messages := make([]DiscussionMessageView, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
messages = append(messages, DiscussionMessageView{
|
||||
|
|
@ -60,17 +61,19 @@ func DiscussionMessagesFromRows(rows []sqlc.ListDiscussionMessagesByTabloRow) []
|
|||
AuthorEmail: row.AuthorEmail,
|
||||
Body: row.Body,
|
||||
CreatedAt: row.CreatedAt.Time,
|
||||
IsOwn: row.AuthorUserID == currentUserID,
|
||||
})
|
||||
}
|
||||
return messages
|
||||
}
|
||||
|
||||
func DiscussionMessageFromRow(row sqlc.GetDiscussionMessageWithAuthorRow) DiscussionMessageView {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue