🎨 **True Light/Dark Mode** - Implemented proper light mode with inverted color scheme - Smooth theme transitions (0.3s ease) - Light mode colors: white backgrounds, dark text, vibrant accents - System theme detection with proper class application 🌈 **Enhanced Theme System** - 4 color themes work in both light and dark modes - Cyber (cyan/magenta), Ocean (blue/teal), Forest (green/lime), Sunset (orange/purple) - Theme-specific glassmorphism effects - Proper contrast in light mode ✨ **Premium Animations** - Float, glow-pulse, slide-in, scale-in, rotate-in animations - Smooth page transitions - Hover effects with depth (lift, glow, scale) - Micro-interactions on all interactive elements 🎯 **Visual Polish** - Enhanced glassmorphism for light/dark modes - Custom scrollbar with theme colors - Beautiful text selection - Focus indicators for accessibility - Premium utility classes 🔧 **Technical Improvements** - Updated UIStore to properly apply light/dark classes - Added data-theme attribute for CSS targeting - Smooth scroll behavior - Optimized transitions The app is now a visual masterpiece with perfect light/dark mode support!
182 lines
4.4 KiB
Go
182 lines
4.4 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"veza-backend-api/internal/database"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// NotificationService handles notification operations
|
|
type NotificationService struct {
|
|
db *database.Database
|
|
logger *zap.Logger
|
|
}
|
|
|
|
// Notification represents a notification
|
|
type Notification struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
|
Type string `json:"type" db:"type"`
|
|
Title string `json:"title" db:"title"`
|
|
Content string `json:"content" db:"content"`
|
|
Link string `json:"link" db:"link"`
|
|
Read bool `json:"read" db:"read"`
|
|
CreatedAt string `json:"created_at" db:"created_at"`
|
|
}
|
|
|
|
// NewNotificationService creates a new notification service
|
|
func NewNotificationService(db *database.Database, logger *zap.Logger) *NotificationService {
|
|
return &NotificationService{
|
|
db: db,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// CreateNotification creates a new notification
|
|
func (ns *NotificationService) CreateNotification(userID uuid.UUID, notificationType, title, content, link string) error {
|
|
ctx := context.Background()
|
|
|
|
_, err := ns.db.ExecContext(ctx, `
|
|
INSERT INTO notifications (user_id, type, title, content, link)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
`, userID, notificationType, title, content, link)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create notification: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetNotifications retrieves notifications for a user
|
|
func (ns *NotificationService) GetNotifications(userID uuid.UUID, unreadOnly bool) ([]Notification, error) {
|
|
ctx := context.Background()
|
|
|
|
query := `
|
|
SELECT id, user_id, type, title, content, link, read, created_at
|
|
FROM notifications
|
|
WHERE user_id = $1
|
|
`
|
|
args := []interface{}{userID}
|
|
|
|
if unreadOnly {
|
|
query += " AND read = FALSE"
|
|
}
|
|
|
|
query += " ORDER BY created_at DESC LIMIT 50"
|
|
|
|
rows, err := ns.db.QueryContext(ctx, query, args...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get notifications: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var notifications []Notification
|
|
for rows.Next() {
|
|
var notification Notification
|
|
if err := rows.Scan(
|
|
¬ification.ID,
|
|
¬ification.UserID,
|
|
¬ification.Type,
|
|
¬ification.Title,
|
|
¬ification.Content,
|
|
¬ification.Link,
|
|
¬ification.Read,
|
|
¬ification.CreatedAt,
|
|
); err != nil {
|
|
continue
|
|
}
|
|
notifications = append(notifications, notification)
|
|
}
|
|
|
|
return notifications, nil
|
|
}
|
|
|
|
// MarkAsRead marks a notification as read
|
|
func (ns *NotificationService) MarkAsRead(userID uuid.UUID, notificationID uuid.UUID) error {
|
|
ctx := context.Background()
|
|
|
|
_, err := ns.db.ExecContext(ctx, `
|
|
UPDATE notifications
|
|
SET read = TRUE
|
|
WHERE id = $1 AND user_id = $2
|
|
`, notificationID, userID)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to mark notification as read: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// MarkAllAsRead marks all notifications as read for a user
|
|
func (ns *NotificationService) MarkAllAsRead(userID uuid.UUID) error {
|
|
ctx := context.Background()
|
|
|
|
_, err := ns.db.ExecContext(ctx, `
|
|
UPDATE notifications
|
|
SET read = TRUE
|
|
WHERE user_id = $1 AND read = FALSE
|
|
`, userID)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to mark all notifications as read: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetUnreadCount returns the count of unread notifications
|
|
func (ns *NotificationService) GetUnreadCount(userID uuid.UUID) (int, error) {
|
|
ctx := context.Background()
|
|
|
|
var count int
|
|
err := ns.db.QueryRowContext(ctx, `
|
|
SELECT COUNT(*)
|
|
FROM notifications
|
|
WHERE user_id = $1 AND read = FALSE
|
|
`, userID).Scan(&count)
|
|
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to get unread count: %w", err)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// DeleteNotification deletes a notification
|
|
func (ns *NotificationService) DeleteNotification(userID uuid.UUID, notificationID uuid.UUID) error {
|
|
ctx := context.Background()
|
|
|
|
_, err := ns.db.ExecContext(ctx, `
|
|
DELETE FROM notifications
|
|
WHERE id = $1 AND user_id = $2
|
|
`, notificationID, userID)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete notification: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DeleteAllNotifications deletes all notifications for a user
|
|
func (ns *NotificationService) DeleteAllNotifications(userID uuid.UUID) error {
|
|
ctx := context.Background()
|
|
|
|
_, err := ns.db.ExecContext(ctx, `
|
|
DELETE FROM notifications
|
|
WHERE user_id = $1
|
|
`, userID)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete all notifications: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|