From f0fc70eac6ca130cc0c79c23ae9b4a03ad318bee Mon Sep 17 00:00:00 2001 From: H3ALY Date: Sun, 2 Nov 2025 09:11:48 +0000 Subject: [PATCH] Add in mark as reaad button to list view, use ajax to preform the action without page refresh. --- internal/domain/messages/domain.go | 5 +- internal/handlers/account/messages/read.go | 34 +++++++ internal/http/routes/accountroutes.go | 1 + .../platform/services/messages/service.go | 22 +++++ web/templates/account/messages/index.html | 99 +++++++++++++++++-- web/templates/account/messages/read.html | 58 +++++++++-- web/templates/main/topbar.html | 20 ++-- 7 files changed, 212 insertions(+), 27 deletions(-) diff --git a/internal/domain/messages/domain.go b/internal/domain/messages/domain.go index 2ae6554..2a61bed 100644 --- a/internal/domain/messages/domain.go +++ b/internal/domain/messages/domain.go @@ -19,8 +19,7 @@ type MessageService interface { GetByID(userID, id int64) (*Message, error) Create(userID int64, in CreateMessageInput) (int64, error) Archive(userID, id int64) error - //Restore() - //ToDo: implement Unarchive(userID, id int64) error - //MarkRead(userID, id int64) error + MarkRead(userID, id int64) error + //MarkUnread(userID, id int64) error } diff --git a/internal/handlers/account/messages/read.go b/internal/handlers/account/messages/read.go index 6c9ef0c..87da355 100644 --- a/internal/handlers/account/messages/read.go +++ b/internal/handlers/account/messages/read.go @@ -7,6 +7,7 @@ package accountMessageHandler import ( "bytes" + "database/sql" "net/http" "strconv" @@ -137,3 +138,36 @@ func (h *AccountMessageHandlers) ReadGet(c *gin.Context) { } c.Data(http.StatusOK, "text/html; charset=utf-8", buf.Bytes()) } + +func (h *AccountMessageHandlers) MarkReadPost(c *gin.Context) { + app := c.MustGet("app").(*bootstrap.App) + sm := app.SessionManager + userID := mustUserID(c) + + idStr := c.PostForm("id") + id, err := strconv.ParseInt(idStr, 10, 64) + if err != nil || id <= 0 { + sm.Put(c.Request.Context(), "flash", "Invalid message id.") + c.Redirect(http.StatusSeeOther, c.Request.Referer()) // back to where they came from + return + } + + if err := h.Svc.MarkRead(userID, id); err != nil { + logging.Info("❌ MarkRead error: %v", err) + if err == sql.ErrNoRows { + sm.Put(c.Request.Context(), "flash", "Message not found or not permitted.") + } else { + sm.Put(c.Request.Context(), "flash", "Could not mark message as read.") + } + c.Redirect(http.StatusSeeOther, "/account/messages") + return + } + + sm.Put(c.Request.Context(), "flash", "Message marked as read.") + // Redirect back to referer when possible so UX is smooth. + if ref := c.Request.Referer(); ref != "" { + c.Redirect(http.StatusSeeOther, ref) + } else { + c.Redirect(http.StatusSeeOther, "/account/messages") + } +} diff --git a/internal/http/routes/accountroutes.go b/internal/http/routes/accountroutes.go index 8f2c6bf..9fd9e96 100644 --- a/internal/http/routes/accountroutes.go +++ b/internal/http/routes/accountroutes.go @@ -72,6 +72,7 @@ func RegisterAccountRoutes(app *bootstrap.App) { messages.GET("/archive", msgH.ArchivedList) // view archived messages messages.POST("/archive", msgH.ArchivePost) // archive a message messages.POST("/restore", msgH.RestoreArchived) + messages.POST("/mark-read", msgH.MarkReadPost) } // Notifications (auth-required) diff --git a/internal/platform/services/messages/service.go b/internal/platform/services/messages/service.go index e784562..558c4b5 100644 --- a/internal/platform/services/messages/service.go +++ b/internal/platform/services/messages/service.go @@ -277,3 +277,25 @@ func (s *Service) Unarchive(userID, id int64) error { } return nil } + +func (s *Service) MarkRead(userID, id int64) error { + ctx, cancel := context.WithTimeout(context.Background(), s.Timeout) + defer cancel() + + q := ` + UPDATE user_messages + SET is_read = 1 + WHERE id = ? AND recipientId = ? + ` + q = s.bind(q) + + res, err := s.DB.ExecContext(ctx, q, id, userID) + if err != nil { + return err + } + n, _ := res.RowsAffected() + if n == 0 { + return sql.ErrNoRows + } + return nil +} diff --git a/web/templates/account/messages/index.html b/web/templates/account/messages/index.html index 3a8e1a4..f8e5e9c 100644 --- a/web/templates/account/messages/index.html +++ b/web/templates/account/messages/index.html @@ -5,16 +5,33 @@ {{ if .Messages }} @@ -49,4 +66,74 @@ View Archived + +{{/* AJAX enhancement: unobtrusive — safe fallback to regular form when JS disabled */}} + {{ end }} diff --git a/web/templates/account/messages/read.html b/web/templates/account/messages/read.html index de29ef3..328f3aa 100644 --- a/web/templates/account/messages/read.html +++ b/web/templates/account/messages/read.html @@ -6,17 +6,63 @@

{{ .Message.Body }}

-
- - - -
+
+ - Back to Inbox +
+ + + +
+ + Back to Inbox +
{{ else }}
Message not found or access denied.
{{ end }} + + {{ end }} diff --git a/web/templates/main/topbar.html b/web/templates/main/topbar.html index ca383b2..3ca0605 100644 --- a/web/templates/main/topbar.html +++ b/web/templates/main/topbar.html @@ -31,7 +31,8 @@ aria-expanded="false"> {{ if gt .NotificationCount 0 }} - + {{ if gt .NotificationCount 15 }}15+{{ else }}{{ .NotificationCount }}{{ end }} {{ end }} @@ -41,7 +42,6 @@ aria-labelledby="notificationDropdown">
  • - {{ $total := len .Notifications }} {{ range $i, $n := .Notifications }}
  • @@ -55,15 +55,11 @@
  • - {{ if lt (add $i 1) $total }} -
  • + {{ if lt (add $i 1) $total }}
  • {{ end }} {{ end }} - {{ end }} - {{ if not .Notifications }}
  • No notifications
  • {{ end }} -
  • View all notifications
  • @@ -75,7 +71,8 @@ aria-expanded="false"> {{ if gt .MessageCount 0 }} - + {{ if gt .MessageCount 15 }}15+{{ else }}{{ .MessageCount }}{{ end }} {{ end }} @@ -85,7 +82,6 @@ aria-labelledby="messageDropdown">
  • - {{ if .Messages }} {{ range $i, $m := .Messages }}
  • @@ -103,15 +99,15 @@ {{ else }}
  • No messages
  • {{ end }} -
  • View all messages
  • - +