diff --git a/db/schema.sql b/db/schema.sql index e2f2e31..d492d05 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -24,10 +24,9 @@ CREATE TABLE invoices( user_id INTEGER NOT NULL REFERENCES users(id), msats BIGINT NOT NULL, msats_received BIGINT, - preimage TEXT NOT NULL UNIQUE, hash TEXT NOT NULL UNIQUE, bolt11 TEXT NOT NULL, - created_at TIMESTAMP WITH TIME ZONE NOT NULL, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, expires_at TIMESTAMP WITH TIME ZONE NOT NULL, confirmed_at TIMESTAMP WITH TIME ZONE, held_since TIMESTAMP WITH TIME ZONE, @@ -37,7 +36,8 @@ CREATE TABLE invoices( CREATE TABLE markets( id SERIAL PRIMARY KEY, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, - description TEXT NOT NULL, + question TEXT NOT NULL, + description TEXT, end_date TIMESTAMP WITH TIME ZONE NOT NULL, settled_at TIMESTAMP WITH TIME ZONE, user_id INTEGER NOT NULL REFERENCES users(id), diff --git a/public/css/_tw-input.css b/public/css/_tw-input.css index 8a84091..aa0aa80 100644 --- a/public/css/_tw-input.css +++ b/public/css/_tw-input.css @@ -31,13 +31,15 @@ a:not(.no-link), button[hx-get], - button[hx-post] { + button[hx-post], + button[type="submit"] { transition: background-color 150ms ease-in, color 150ms ease-in; } a:not(.no-link):hover, button[hx-get]:hover, - button[hx-post]:hover { + button[hx-post]:hover, + button[type="submit"]:hover { background-color: var(--color); color: var(--background); } @@ -47,13 +49,15 @@ text-decoration: underline; } - button[hx-post] { + button[hx-post], + button[type="submit"] { border-width: 1px; } nav a, button[hx-get], - button[hx-post] { + button[hx-post], + button[type="submit"] { padding: 0 0.25em; } @@ -105,4 +109,8 @@ .nostr:hover { filter: brightness(125%) drop-shadow(0 0 0.33rem var(--nostr)); } + + #modal { + backdrop-filter: blur(10px); + } } \ No newline at end of file diff --git a/server/router/handler/market.go b/server/router/handler/market.go new file mode 100644 index 0000000..686b56b --- /dev/null +++ b/server/router/handler/market.go @@ -0,0 +1,74 @@ +package handler + +import ( + "database/sql" + "time" + + "git.ekzyis.com/ekzyis/delphi.market/server/router/context" + "git.ekzyis.com/ekzyis/delphi.market/server/router/pages/components" + "git.ekzyis.com/ekzyis/delphi.market/types" + "github.com/a-h/templ" + "github.com/labstack/echo/v4" + "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwire" +) + +func HandleCreate(sc context.Context) echo.HandlerFunc { + return func(c echo.Context) error { + var ( + db = sc.Db + lnd = sc.Lnd + tx *sql.Tx + ctx = c.Request().Context() + u = c.Get("session").(types.User) + question = c.FormValue("question") + description = c.FormValue("description") + endDate = c.FormValue("end_date") + hash lntypes.Hash + paymentRequest string + amount = lnwire.MilliSatoshi(1000) + expiry = int64(600) + expiresAt = time.Now().Add(time.Second * time.Duration(expiry)) + invoiceId int + qr templ.Component + err error + ) + // TODO: validation + + if tx, err = db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelReadCommitted}); err != nil { + return err + } + + if hash, paymentRequest, err = lnd.Client.AddInvoice(ctx, + &invoicesrpc.AddInvoiceData{ + Value: amount, + Expiry: expiry, + }); err != nil { + return err + } + + if err = db.QueryRowContext(ctx, ""+ + "INSERT INTO invoices (user_id, msats, hash, bolt11, expires_at) "+ + "VALUES ($1, $2, $3, $4, $5) "+ + "RETURNING id", + u.Id, amount, hash.String(), paymentRequest, expiresAt).Scan(&invoiceId); err != nil { + return err + } + + if _, err = tx.ExecContext(ctx, ""+ + "INSERT INTO markets (question, description, end_date, user_id, invoice_id) "+ + "VALUES ($1, $2, $3, $4, $5)", + question, description, endDate, u.Id, invoiceId); err != nil { + return err + } + + if err = tx.Commit(); err != nil { + return err + } + + qr = components.Qr(paymentRequest, "lightning:"+paymentRequest) + + return components.Modal(qr).Render(context.RenderContext(sc, c), c.Response().Writer) + } +} diff --git a/server/router/pages/components/modal.templ b/server/router/pages/components/modal.templ new file mode 100644 index 0000000..0323390 --- /dev/null +++ b/server/router/pages/components/modal.templ @@ -0,0 +1,21 @@ +package components + +templ Modal(component templ.Component) { + if component != nil { + + } else { + + } +} diff --git a/server/router/pages/index.templ b/server/router/pages/index.templ index 7247772..ba684ec 100644 --- a/server/router/pages/index.templ +++ b/server/router/pages/index.templ @@ -1,6 +1,9 @@ package pages -import "git.ekzyis.com/ekzyis/delphi.market/server/router/pages/components" +import ( + c "git.ekzyis.com/ekzyis/delphi.market/server/router/context" + "git.ekzyis.com/ekzyis/delphi.market/server/router/pages/components" +) templ Index() { @@ -9,9 +12,81 @@ templ Index() { @components.Nav()
@components.Figlet("random", "delphi") -
A prediction market using the lightning network
+
A prediction market using the lightning network
+
+
+ + +
+ if ctx.Value(c.ReqPathContextKey).(string) == "/" { +
+ +
+ } else { +
+ + +
+ + optional +
+ + + + +
+ } +
+ @components.Modal(nil) @components.Footer() } + +func tabStyle(path string, tab string) string { + class := "!no-underline" + if path == tab { + class += " font-bold border-b-none" + } + return class +} diff --git a/server/router/router.go b/server/router/router.go index 804f890..51ed1c9 100644 --- a/server/router/router.go +++ b/server/router/router.go @@ -14,6 +14,8 @@ func Init(e *echo.Echo, sc Context) { e.Use(middleware.Session(sc)) e.GET("/", handler.HandleIndex(sc)) + e.GET("/create", handler.HandleIndex(sc)) + e.POST("/create", handler.HandleCreate(sc), middleware.SessionGuard(sc)) e.GET("/about", handler.HandleAbout(sc)) e.GET("/login", handler.HandleAuth(sc, "login"))