feat(brand): add brand sort order and drag-to-reorder

Add a sort_order column to brands with a migration, expose a
PUT /api/tenant/brands/order reorder endpoint, and wire the
admin-web BrandsView with drag-and-drop reordering plus i18n.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-08 21:48:20 +08:00
parent fbc69c01b0
commit 71233b6715
16 changed files with 608 additions and 31 deletions
@@ -12,26 +12,33 @@ import (
)
const createBrand = `-- name: CreateBrand :one
INSERT INTO brands (tenant_id, name, description, status)
VALUES ($1, $2, $3, 'active')
RETURNING id, created_at
INSERT INTO brands (tenant_id, name, description, status, sort_order)
VALUES ($1, $2, $3, 'active', $4)
RETURNING id, sort_order, created_at
`
type CreateBrandParams struct {
TenantID int64 `json:"tenant_id"`
Name string `json:"name"`
Description pgtype.Text `json:"description"`
SortOrder int32 `json:"sort_order"`
}
type CreateBrandRow struct {
ID int64 `json:"id"`
SortOrder int32 `json:"sort_order"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
func (q *Queries) CreateBrand(ctx context.Context, arg CreateBrandParams) (CreateBrandRow, error) {
row := q.db.QueryRow(ctx, createBrand, arg.TenantID, arg.Name, arg.Description)
row := q.db.QueryRow(ctx, createBrand,
arg.TenantID,
arg.Name,
arg.Description,
arg.SortOrder,
)
var i CreateBrandRow
err := row.Scan(&i.ID, &i.CreatedAt)
err := row.Scan(&i.ID, &i.SortOrder, &i.CreatedAt)
return i, err
}
@@ -119,7 +126,7 @@ func (q *Queries) CreateQuestion(ctx context.Context, arg CreateQuestionParams)
}
const getBrandByID = `-- name: GetBrandByID :one
SELECT id, tenant_id, name, description, status, created_at, updated_at
SELECT id, tenant_id, name, description, status, sort_order, created_at, updated_at
FROM brands
WHERE id = $1 AND tenant_id = $2 AND deleted_at IS NULL
`
@@ -135,6 +142,7 @@ type GetBrandByIDRow struct {
Name string `json:"name"`
Description pgtype.Text `json:"description"`
Status string `json:"status"`
SortOrder int32 `json:"sort_order"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
@@ -148,6 +156,7 @@ func (q *Queries) GetBrandByID(ctx context.Context, arg GetBrandByIDParams) (Get
&i.Name,
&i.Description,
&i.Status,
&i.SortOrder,
&i.CreatedAt,
&i.UpdatedAt,
)
@@ -155,10 +164,10 @@ func (q *Queries) GetBrandByID(ctx context.Context, arg GetBrandByIDParams) (Get
}
const listBrands = `-- name: ListBrands :many
SELECT id, tenant_id, name, description, status, created_at, updated_at
SELECT id, tenant_id, name, description, status, sort_order, created_at, updated_at
FROM brands
WHERE tenant_id = $1 AND deleted_at IS NULL
ORDER BY created_at DESC
ORDER BY sort_order ASC, created_at DESC, id DESC
`
type ListBrandsRow struct {
@@ -167,6 +176,7 @@ type ListBrandsRow struct {
Name string `json:"name"`
Description pgtype.Text `json:"description"`
Status string `json:"status"`
SortOrder int32 `json:"sort_order"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
@@ -186,6 +196,7 @@ func (q *Queries) ListBrands(ctx context.Context, tenantID int64) ([]ListBrandsR
&i.Name,
&i.Description,
&i.Status,
&i.SortOrder,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {