2024-10-01 01:32:42 +00:00
|
|
|
package pages
|
|
|
|
|
|
|
|
|
|
import (
|
2024-10-01 03:49:03 +00:00
|
|
|
"chat/chat"
|
2024-10-03 16:38:40 +00:00
|
|
|
"chat/internal/db"
|
2024-10-02 03:26:03 +00:00
|
|
|
"chat/partials"
|
2024-10-01 03:08:52 +00:00
|
|
|
"fmt"
|
|
|
|
|
"github.com/go-chi/chi/v5"
|
2024-10-01 01:32:42 +00:00
|
|
|
"github.com/maddalax/htmgo/framework/h"
|
|
|
|
|
"github.com/maddalax/htmgo/framework/js"
|
2024-10-01 17:42:01 +00:00
|
|
|
"time"
|
2024-10-01 01:32:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func ChatRoom(ctx *h.RequestContext) *h.Page {
|
2024-10-01 03:08:52 +00:00
|
|
|
roomId := chi.URLParam(ctx.Request, "id")
|
2024-10-01 01:32:42 +00:00
|
|
|
return h.NewPage(
|
|
|
|
|
RootPage(
|
|
|
|
|
h.Div(
|
2024-10-04 16:12:38 +00:00
|
|
|
h.TriggerChildren(),
|
2024-10-01 17:09:22 +00:00
|
|
|
|
2024-10-04 16:22:48 +00:00
|
|
|
h.Attribute("sse-connect", fmt.Sprintf("/sse/chat/%s", roomId)),
|
2024-10-01 17:09:22 +00:00
|
|
|
|
2024-10-02 03:26:03 +00:00
|
|
|
h.HxOnSseOpen(
|
2024-10-01 17:09:22 +00:00
|
|
|
js.ConsoleLog("Connected to chat room"),
|
|
|
|
|
),
|
|
|
|
|
|
2024-10-02 16:06:00 +00:00
|
|
|
h.HxOnSseError(
|
2024-10-01 17:56:16 +00:00
|
|
|
js.EvalJs(fmt.Sprintf(`
|
2024-10-02 04:04:04 +00:00
|
|
|
const reason = e.detail.event.data
|
2024-10-01 18:42:14 +00:00
|
|
|
if(['invalid room', 'no session', 'invalid user'].includes(reason)) {
|
2024-10-01 17:56:16 +00:00
|
|
|
window.location.href = '/?roomId=%s';
|
2024-10-01 17:42:01 +00:00
|
|
|
} else if(e.detail.event.code === 1011) {
|
|
|
|
|
window.location.reload()
|
2024-10-01 18:42:14 +00:00
|
|
|
} else if (e.detail.event.code === 1008 || e.detail.event.code === 1006) {
|
2024-10-03 17:04:49 +00:00
|
|
|
window.location.href = '/?roomId=%s';
|
2024-10-01 17:09:22 +00:00
|
|
|
} else {
|
2024-10-01 17:42:01 +00:00
|
|
|
console.error('Connection closed:', e.detail.event)
|
2024-10-01 17:09:22 +00:00
|
|
|
}
|
2024-10-01 18:42:14 +00:00
|
|
|
`, roomId, roomId)),
|
2024-10-01 17:09:22 +00:00
|
|
|
),
|
|
|
|
|
|
2024-10-03 17:04:49 +00:00
|
|
|
// Adjusted flex properties for responsive layout
|
2024-10-04 16:52:54 +00:00
|
|
|
h.Class("flex flex-row h-screen bg-neutral-100 overflow-x-hidden"),
|
2024-10-03 17:04:49 +00:00
|
|
|
|
|
|
|
|
// Collapse Button for mobile
|
|
|
|
|
CollapseButton(),
|
2024-10-01 03:08:52 +00:00
|
|
|
|
|
|
|
|
// Sidebar for connected users
|
|
|
|
|
UserSidebar(),
|
|
|
|
|
|
2024-10-01 01:32:42 +00:00
|
|
|
h.Div(
|
2024-10-03 17:04:49 +00:00
|
|
|
// Adjusted to fill height and width
|
|
|
|
|
h.Class("flex flex-col h-full w-full bg-white p-4 overflow-hidden"),
|
2024-10-01 17:42:01 +00:00
|
|
|
|
|
|
|
|
// Room name at the top, fixed
|
|
|
|
|
CachedRoomHeader(ctx),
|
|
|
|
|
|
2024-10-02 03:26:03 +00:00
|
|
|
h.HxAfterSseMessage(
|
2024-10-01 17:09:22 +00:00
|
|
|
js.EvalJsOnSibling("#messages",
|
|
|
|
|
`element.scrollTop = element.scrollHeight;`),
|
|
|
|
|
),
|
2024-10-01 03:08:52 +00:00
|
|
|
|
|
|
|
|
// Chat Messages
|
2024-10-01 01:32:42 +00:00
|
|
|
h.Div(
|
|
|
|
|
h.Id("messages"),
|
2024-10-03 17:04:49 +00:00
|
|
|
// Adjusted flex properties and removed max-width
|
|
|
|
|
h.Class("flex flex-col gap-4 mb-4 overflow-auto flex-grow w-full pt-[50px]"),
|
2024-10-01 03:08:52 +00:00
|
|
|
),
|
|
|
|
|
|
|
|
|
|
// Chat Input at the bottom
|
2024-10-03 17:04:49 +00:00
|
|
|
Form(),
|
2024-10-01 01:32:42 +00:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-01 19:02:32 +00:00
|
|
|
var CachedRoomHeader = h.CachedPerKeyT(time.Hour, func(ctx *h.RequestContext) (string, h.GetElementFunc) {
|
|
|
|
|
roomId := chi.URLParam(ctx.Request, "id")
|
|
|
|
|
return roomId, func() *h.Element {
|
|
|
|
|
return roomNameHeader(ctx)
|
|
|
|
|
}
|
2024-10-01 17:42:01 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
func roomNameHeader(ctx *h.RequestContext) *h.Element {
|
|
|
|
|
roomId := chi.URLParam(ctx.Request, "id")
|
|
|
|
|
service := chat.NewService(ctx.ServiceLocator())
|
|
|
|
|
room, err := service.GetRoom(roomId)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return h.Div()
|
|
|
|
|
}
|
|
|
|
|
return h.Div(
|
|
|
|
|
h.Class("bg-neutral-700 text-white p-3 shadow-sm w-full fixed top-0 left-0 flex justify-center z-10"),
|
|
|
|
|
h.H2F(room.Name, h.Class("text-lg font-bold")),
|
2024-10-01 17:56:16 +00:00
|
|
|
h.Div(
|
|
|
|
|
h.Class("absolute right-5 top-3 cursor-pointer"),
|
|
|
|
|
h.Text("Share"),
|
|
|
|
|
h.OnClick(
|
|
|
|
|
js.EvalJs(`
|
|
|
|
|
alert("Share this url with your friends:\n " + window.location.href)
|
|
|
|
|
`),
|
|
|
|
|
),
|
|
|
|
|
),
|
2024-10-01 17:42:01 +00:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-01 03:08:52 +00:00
|
|
|
func UserSidebar() *h.Element {
|
|
|
|
|
return h.Div(
|
2024-10-03 17:04:49 +00:00
|
|
|
h.Class("sidebar h-full pt-[67px] min-w-48 w-48 bg-neutral-200 p-4 flex-col justify-between gap-3 rounded-l-lg hidden md:flex"),
|
2024-10-01 17:42:01 +00:00
|
|
|
h.Div(
|
|
|
|
|
h.H3F("Connected Users", h.Class("text-lg font-bold")),
|
2024-10-03 16:38:40 +00:00
|
|
|
chat.ConnectedUsers(make([]db.User, 0), ""),
|
2024-10-01 17:42:01 +00:00
|
|
|
),
|
|
|
|
|
h.A(
|
|
|
|
|
h.Class("cursor-pointer"),
|
|
|
|
|
h.Href("/"),
|
|
|
|
|
h.Text("Leave Room"),
|
|
|
|
|
),
|
2024-10-01 03:08:52 +00:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-03 17:04:49 +00:00
|
|
|
func CollapseButton() *h.Element {
|
|
|
|
|
return h.Div(
|
|
|
|
|
h.Class("fixed top-0 left-4 md:hidden z-50"), // Always visible on mobile
|
|
|
|
|
h.Button(
|
|
|
|
|
h.Class("p-2 text-2xl bg-neutral-700 text-white rounded-md"), // Styling the button
|
|
|
|
|
h.OnClick(
|
|
|
|
|
js.EvalJs(`
|
|
|
|
|
const sidebar = document.querySelector('.sidebar');
|
|
|
|
|
sidebar.classList.toggle('hidden');
|
|
|
|
|
sidebar.classList.toggle('flex');
|
|
|
|
|
`),
|
|
|
|
|
),
|
|
|
|
|
h.UnsafeRaw("☰"), // The icon for collapsing the sidebar
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-01 01:32:42 +00:00
|
|
|
func MessageInput() *h.Element {
|
|
|
|
|
return h.Input("text",
|
|
|
|
|
h.Id("message-input"),
|
|
|
|
|
h.Required(),
|
2024-10-04 16:18:33 +00:00
|
|
|
h.Class("p-4 rounded-md border border-slate-200 w-full focus:outline-none focus:ring focus:ring-slate-200"),
|
|
|
|
|
h.Name("message"),
|
|
|
|
|
h.MaxLength(1000),
|
|
|
|
|
h.Placeholder("Type a message..."),
|
2024-10-02 03:26:03 +00:00
|
|
|
h.HxAfterSseMessage(
|
2024-10-01 01:32:42 +00:00
|
|
|
js.SetValue(""),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-01 17:42:01 +00:00
|
|
|
func Form() *h.Element {
|
2024-10-01 01:32:42 +00:00
|
|
|
return h.Div(
|
2024-10-01 03:08:52 +00:00
|
|
|
h.Class("flex gap-4 items-center"),
|
2024-10-01 01:32:42 +00:00
|
|
|
h.Form(
|
2024-10-02 03:26:03 +00:00
|
|
|
h.NoSwap(),
|
|
|
|
|
h.PostPartial(partials.SendMessage),
|
2024-10-04 16:18:33 +00:00
|
|
|
h.Attribute("ws-send", ""),
|
2024-10-01 03:08:52 +00:00
|
|
|
h.Class("flex flex-grow"),
|
2024-10-01 01:32:42 +00:00
|
|
|
MessageInput(),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
}
|