diff --git a/internal/db/bookings.sql.go b/internal/db/bookings.sql.go
index bceef5a..92b56ab 100644
--- a/internal/db/bookings.sql.go
+++ b/internal/db/bookings.sql.go
@@ -105,6 +105,83 @@ func (q *Queries) GetBooking(ctx context.Context, id int64) (GetBookingRow, erro
return i, err
}
+const listAllBookingsWithDetails = `-- name: ListAllBookingsWithDetails :many
+SELECT
+ b.id,
+ b.user_id,
+ b.service_id,
+ b.event_date,
+ b.address,
+ b.notes,
+ b.created_at,
+ b.status,
+ b.service_option,
+ b.event_type,
+ u.email as user_email,
+ s.name as service_name,
+ s.description as service_description,
+ s.price_cents as service_price_cents
+FROM bookings b
+JOIN users u ON b.user_id = u.id
+JOIN services s ON b.service_id = s.id
+ORDER BY b.created_at DESC
+`
+
+type ListAllBookingsWithDetailsRow struct {
+ ID int64 `json:"id"`
+ UserID sql.NullInt64 `json:"user_id"`
+ ServiceID sql.NullInt64 `json:"service_id"`
+ EventDate time.Time `json:"event_date"`
+ Address sql.NullString `json:"address"`
+ Notes sql.NullString `json:"notes"`
+ CreatedAt sql.NullTime `json:"created_at"`
+ Status sql.NullString `json:"status"`
+ ServiceOption sql.NullString `json:"service_option"`
+ EventType sql.NullString `json:"event_type"`
+ UserEmail string `json:"user_email"`
+ ServiceName string `json:"service_name"`
+ ServiceDescription sql.NullString `json:"service_description"`
+ ServicePriceCents int32 `json:"service_price_cents"`
+}
+
+func (q *Queries) ListAllBookingsWithDetails(ctx context.Context) ([]ListAllBookingsWithDetailsRow, error) {
+ rows, err := q.db.QueryContext(ctx, listAllBookingsWithDetails)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+ items := []ListAllBookingsWithDetailsRow{}
+ for rows.Next() {
+ var i ListAllBookingsWithDetailsRow
+ if err := rows.Scan(
+ &i.ID,
+ &i.UserID,
+ &i.ServiceID,
+ &i.EventDate,
+ &i.Address,
+ &i.Notes,
+ &i.CreatedAt,
+ &i.Status,
+ &i.ServiceOption,
+ &i.EventType,
+ &i.UserEmail,
+ &i.ServiceName,
+ &i.ServiceDescription,
+ &i.ServicePriceCents,
+ ); err != nil {
+ return nil, err
+ }
+ items = append(items, i)
+ }
+ if err := rows.Close(); err != nil {
+ return nil, err
+ }
+ if err := rows.Err(); err != nil {
+ return nil, err
+ }
+ return items, nil
+}
+
const listBookingsByUser = `-- name: ListBookingsByUser :many
SELECT id, user_id, service_id, event_date, address, notes, created_at, status, service_option, event_type
FROM bookings
@@ -232,3 +309,19 @@ func (q *Queries) ListBookingsWithServiceByUser(ctx context.Context, userID sql.
}
return items, nil
}
+
+const updateBookingStatus = `-- name: UpdateBookingStatus :exec
+UPDATE bookings
+SET status = $2
+WHERE id = $1
+`
+
+type UpdateBookingStatusParams struct {
+ ID int64 `json:"id"`
+ Status sql.NullString `json:"status"`
+}
+
+func (q *Queries) UpdateBookingStatus(ctx context.Context, arg UpdateBookingStatusParams) error {
+ _, err := q.db.ExecContext(ctx, updateBookingStatus, arg.ID, arg.Status)
+ return err
+}
diff --git a/internal/db/models.go b/internal/db/models.go
index fc3c3a3..f962fad 100644
--- a/internal/db/models.go
+++ b/internal/db/models.go
@@ -43,4 +43,5 @@ type User struct {
Email string `json:"email"`
CreatedAt sql.NullTime `json:"created_at"`
OryIdentityID sql.NullString `json:"ory_identity_id"`
+ IsAdmin sql.NullBool `json:"is_admin"`
}
diff --git a/internal/db/queries/bookings.sql b/internal/db/queries/bookings.sql
index 9958077..cf62079 100644
--- a/internal/db/queries/bookings.sql
+++ b/internal/db/queries/bookings.sql
@@ -33,3 +33,29 @@ ORDER BY b.event_date DESC;
SELECT id, user_id, service_id, event_date, address, notes, created_at, status, service_option, event_type
FROM bookings
WHERE id = $1;
+
+-- name: ListAllBookingsWithDetails :many
+SELECT
+ b.id,
+ b.user_id,
+ b.service_id,
+ b.event_date,
+ b.address,
+ b.notes,
+ b.created_at,
+ b.status,
+ b.service_option,
+ b.event_type,
+ u.email as user_email,
+ s.name as service_name,
+ s.description as service_description,
+ s.price_cents as service_price_cents
+FROM bookings b
+JOIN users u ON b.user_id = u.id
+JOIN services s ON b.service_id = s.id
+ORDER BY b.created_at DESC;
+
+-- name: UpdateBookingStatus :exec
+UPDATE bookings
+SET status = $2
+WHERE id = $1;
diff --git a/internal/db/users.sql.go b/internal/db/users.sql.go
index b289e3c..e36d3bc 100644
--- a/internal/db/users.sql.go
+++ b/internal/db/users.sql.go
@@ -13,7 +13,7 @@ import (
const createUser = `-- name: CreateUser :one
INSERT INTO users (email, ory_identity_id)
VALUES ($1, $2)
-RETURNING id, email, created_at, ory_identity_id
+RETURNING id, email, created_at, ory_identity_id, is_admin
`
type CreateUserParams struct {
@@ -29,12 +29,13 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, e
&i.Email,
&i.CreatedAt,
&i.OryIdentityID,
+ &i.IsAdmin,
)
return i, err
}
const getUserByEmail = `-- name: GetUserByEmail :one
-SELECT id, email, created_at, ory_identity_id FROM users WHERE email = $1 LIMIT 1
+SELECT id, email, created_at, ory_identity_id, is_admin FROM users WHERE email = $1 LIMIT 1
`
func (q *Queries) GetUserByEmail(ctx context.Context, email string) (User, error) {
@@ -45,12 +46,13 @@ func (q *Queries) GetUserByEmail(ctx context.Context, email string) (User, error
&i.Email,
&i.CreatedAt,
&i.OryIdentityID,
+ &i.IsAdmin,
)
return i, err
}
const getUserByOryID = `-- name: GetUserByOryID :one
-SELECT id, email, created_at, ory_identity_id FROM users WHERE ory_identity_id = $1 LIMIT 1
+SELECT id, email, created_at, ory_identity_id, is_admin FROM users WHERE ory_identity_id = $1 LIMIT 1
`
func (q *Queries) GetUserByOryID(ctx context.Context, oryIdentityID sql.NullString) (User, error) {
@@ -61,6 +63,7 @@ func (q *Queries) GetUserByOryID(ctx context.Context, oryIdentityID sql.NullStri
&i.Email,
&i.CreatedAt,
&i.OryIdentityID,
+ &i.IsAdmin,
)
return i, err
}
@@ -69,7 +72,7 @@ const updateUserOryID = `-- name: UpdateUserOryID :one
UPDATE users
SET ory_identity_id = $1
WHERE email = $2
-RETURNING id, email, created_at, ory_identity_id
+RETURNING id, email, created_at, ory_identity_id, is_admin
`
type UpdateUserOryIDParams struct {
@@ -85,6 +88,7 @@ func (q *Queries) UpdateUserOryID(ctx context.Context, arg UpdateUserOryIDParams
&i.Email,
&i.CreatedAt,
&i.OryIdentityID,
+ &i.IsAdmin,
)
return i, err
}
diff --git a/internal/handlers/catalog.go b/internal/handlers/catalog.go
index b697d24..da492a6 100644
--- a/internal/handlers/catalog.go
+++ b/internal/handlers/catalog.go
@@ -4,10 +4,12 @@ import (
"html/template"
"net/http"
+ ory "github.com/ory/client-go"
+
"decor-by-hannahs/internal/db"
)
-func CatalogHandler(q *db.Queries, tmpl *template.Template) http.HandlerFunc {
+func CatalogHandler(q *db.Queries, tmpl *template.Template, oryClient *ory.APIClient) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
svcs, err := q.ListServices(r.Context())
if err != nil {
@@ -15,10 +17,17 @@ func CatalogHandler(q *db.Queries, tmpl *template.Template) http.HandlerFunc {
return
}
type data struct {
- Services []db.Service
- ActivePage string
+ Services []db.Service
+ ActivePage string
+ Authenticated bool
+ OryLoginURL string
}
- if err := tmpl.ExecuteTemplate(w, "catalog.tmpl", data{Services: svcs, ActivePage: "catalog"}); err != nil {
+ if err := tmpl.ExecuteTemplate(w, "catalog.tmpl", data{
+ Services: svcs,
+ ActivePage: "catalog",
+ Authenticated: isAuthenticated(r, oryClient),
+ OryLoginURL: "/login",
+ }); err != nil {
http.Error(w, "Failed to render page", http.StatusInternalServerError)
}
}
diff --git a/internal/handlers/gallery.go b/internal/handlers/gallery.go
index b45dfda..8044703 100644
--- a/internal/handlers/gallery.go
+++ b/internal/handlers/gallery.go
@@ -7,6 +7,8 @@ import (
"path/filepath"
"sort"
+ ory "github.com/ory/client-go"
+
"decor-by-hannahs/internal/db"
)
@@ -15,7 +17,7 @@ type Photo struct {
Caption string
}
-func GalleryHandler(q *db.Queries, tmpl *template.Template) http.HandlerFunc {
+func GalleryHandler(q *db.Queries, tmpl *template.Template, oryClient *ory.APIClient) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var photos []Photo
@@ -40,10 +42,17 @@ func GalleryHandler(q *db.Queries, tmpl *template.Template) http.HandlerFunc {
})
type data struct {
- Photos []Photo
- ActivePage string
+ Photos []Photo
+ ActivePage string
+ Authenticated bool
+ OryLoginURL string
}
- if err := tmpl.ExecuteTemplate(w, "gallery.tmpl", data{Photos: photos, ActivePage: "gallery"}); err != nil {
+ if err := tmpl.ExecuteTemplate(w, "gallery.tmpl", data{
+ Photos: photos,
+ ActivePage: "gallery",
+ Authenticated: isAuthenticated(r, oryClient),
+ OryLoginURL: "/login",
+ }); err != nil {
http.Error(w, "Failed to render page", http.StatusInternalServerError)
}
}
diff --git a/internal/tmpl/_partials.tmpl b/internal/tmpl/_partials.tmpl
index 0a70383..bfaf051 100644
--- a/internal/tmpl/_partials.tmpl
+++ b/internal/tmpl/_partials.tmpl
@@ -54,8 +54,8 @@
-
- Decor By Hannah's
+
+ Decor By Hannahs
@@ -83,7 +83,7 @@
{{end}}
diff --git a/internal/tmpl/home.tmpl b/internal/tmpl/home.tmpl
index 0a110c2..6e75f26 100644
--- a/internal/tmpl/home.tmpl
+++ b/internal/tmpl/home.tmpl
@@ -24,7 +24,7 @@
We take care of all the headache for your party decorations so you don't have to
- Decor By Hannah's
+
+ Decor By Hannahs