stubbed mock shop creation route
This commit is contained in:
@@ -3,7 +3,6 @@ package accounts
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -13,6 +12,7 @@ import (
|
|||||||
"ruben/inventory2/internal/domains/accounts"
|
"ruben/inventory2/internal/domains/accounts"
|
||||||
"ruben/inventory2/internal/logging"
|
"ruben/inventory2/internal/logging"
|
||||||
"ruben/inventory2/internal/server/auth"
|
"ruben/inventory2/internal/server/auth"
|
||||||
|
"ruben/inventory2/internal/server/param"
|
||||||
"ruben/inventory2/internal/server/response"
|
"ruben/inventory2/internal/server/response"
|
||||||
"ruben/inventory2/internal/server/sse"
|
"ruben/inventory2/internal/server/sse"
|
||||||
)
|
)
|
||||||
@@ -41,6 +41,9 @@ func Routes(
|
|||||||
platformGroup.PUT("/order-index", response.Handler(as.setOrderOfPlatformOnAccountPage))
|
platformGroup.PUT("/order-index", response.Handler(as.setOrderOfPlatformOnAccountPage))
|
||||||
platformGroup.POST("/shops/mocks", response.Handler(as.createMockShop))
|
platformGroup.POST("/shops/mocks", response.Handler(as.createMockShop))
|
||||||
|
|
||||||
|
mockShops := platformGroup.Group("/shops/mocks/:shop-id")
|
||||||
|
mockShops.POST("/listings", response.Handler(as.addMockListing))
|
||||||
|
|
||||||
syncGroups := r.Group("/:acctID/inventory/sync-groups")
|
syncGroups := r.Group("/:acctID/inventory/sync-groups")
|
||||||
syncGroups.POST("", pub.Publish("/:acctID/inventory/sync-groups"), response.Handler(as.saveNewSyncGroup))
|
syncGroups.POST("", pub.Publish("/:acctID/inventory/sync-groups"), response.Handler(as.saveNewSyncGroup))
|
||||||
|
|
||||||
@@ -89,7 +92,7 @@ func (s *accountSubrouter) createSyncGroupListingDraft(c *gin.Context) (response
|
|||||||
return response.StatusCreated(), nil
|
return response.StatusCreated(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT /:acctID/inventory/sync-groups/draft/listings/{orderIndex}/shop
|
// PUT /:acctID/inventory/sync-groups/draft/listings/:orderIndex/shop
|
||||||
// @platform string
|
// @platform string
|
||||||
// @shopID string
|
// @shopID string
|
||||||
func (s *accountSubrouter) setShopInSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
|
func (s *accountSubrouter) setShopInSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
|
||||||
@@ -97,24 +100,19 @@ func (s *accountSubrouter) setShopInSyncGroupListingDraft(c *gin.Context) (respo
|
|||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
acctID := auth.GetIdentity(ctx).Account.AccountID
|
acctID := auth.GetIdentity(ctx).Account.AccountID
|
||||||
|
|
||||||
orderIndex, err := getOrderIndexForSyncGroupListingDraftFromPath(c)
|
var (
|
||||||
|
orderIndex int
|
||||||
|
platform accounts.Platform
|
||||||
|
shopID string
|
||||||
|
)
|
||||||
|
|
||||||
|
err := param.Path("orderIndex", param.Int(&orderIndex)).
|
||||||
|
Form("platform", param.Platform(&platform)).
|
||||||
|
Unmarshal(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
platformStr := r.FormValue("platform")
|
|
||||||
platform, err := accounts.NewPlatform(platformStr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, response.BadRequest().
|
|
||||||
Msgf("unrecognized platform: %s", platformStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
shopID := r.FormValue("shop-id")
|
|
||||||
if shopID == "" {
|
|
||||||
return nil, response.BadRequest().
|
|
||||||
Msg("no shop-id provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.accts.SetShopInSyncGroupListingDraft(ctx, acctID, orderIndex, platform, shopID); err != nil {
|
if err := s.accts.SetShopInSyncGroupListingDraft(ctx, acctID, orderIndex, platform, shopID); err != nil {
|
||||||
return nil, response.Errorf("failed to set shop: %w", response.ErrorFromConstant(err))
|
return nil, response.Errorf("failed to set shop: %w", response.ErrorFromConstant(err))
|
||||||
}
|
}
|
||||||
@@ -122,23 +120,24 @@ func (s *accountSubrouter) setShopInSyncGroupListingDraft(c *gin.Context) (respo
|
|||||||
return response.StatusOK(), nil
|
return response.StatusOK(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT /:acctID/inventory/sync-groups/draft/listings/{orderIndex}/listing
|
// PUT /:acctID/inventory/sync-groups/draft/listings/:orderIndex/listing
|
||||||
func (s *accountSubrouter) setListingInSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
|
func (s *accountSubrouter) setListingInSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
|
||||||
r := c.Request
|
r := c.Request
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
acctID := auth.GetIdentity(ctx).Account.AccountID
|
acctID := auth.GetIdentity(ctx).Account.AccountID
|
||||||
|
|
||||||
orderIndex, err := getOrderIndexForSyncGroupListingDraftFromPath(c)
|
var (
|
||||||
|
orderIndex int
|
||||||
|
listingID string
|
||||||
|
)
|
||||||
|
|
||||||
|
err := param.Path("orderIndex", param.Int(&orderIndex)).
|
||||||
|
Form("listing-id", param.Text(&listingID)).
|
||||||
|
Unmarshal(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
listingID := r.FormValue("listing-id")
|
|
||||||
if listingID == "" {
|
|
||||||
return nil, response.BadRequest().
|
|
||||||
Msg("no listing-id provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.accts.SetListingInSyncGroupListingDraft(ctx, acctID, orderIndex, listingID); err != nil {
|
if err := s.accts.SetListingInSyncGroupListingDraft(ctx, acctID, orderIndex, listingID); err != nil {
|
||||||
return nil, response.Errorf("failed to set listing: %w", response.ErrorFromConstant(err))
|
return nil, response.Errorf("failed to set listing: %w", response.ErrorFromConstant(err))
|
||||||
}
|
}
|
||||||
@@ -146,13 +145,18 @@ func (s *accountSubrouter) setListingInSyncGroupListingDraft(c *gin.Context) (re
|
|||||||
return response.StatusOK(), nil
|
return response.StatusOK(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE /:acctID/inventory/sync-groups/draft/listings/{orderIndex}
|
// DELETE /:acctID/inventory/sync-groups/draft/listings/:orderIndex
|
||||||
func (s *accountSubrouter) deleteSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
|
func (s *accountSubrouter) deleteSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
|
||||||
r := c.Request
|
r := c.Request
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
acctID := auth.GetIdentity(ctx).Account.AccountID
|
acctID := auth.GetIdentity(ctx).Account.AccountID
|
||||||
|
|
||||||
orderIndex, err := getOrderIndexForSyncGroupListingDraftFromPath(c)
|
var (
|
||||||
|
orderIndex int
|
||||||
|
)
|
||||||
|
|
||||||
|
err := param.Path("orderIndex", param.Int(&orderIndex)).
|
||||||
|
Unmarshal(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -177,22 +181,6 @@ func (s *accountSubrouter) saveNewSyncGroup(c *gin.Context) (response.Response,
|
|||||||
return response.StatusCreated(), nil
|
return response.StatusCreated(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOrderIndexForSyncGroupListingDraftFromPath(c *gin.Context) (int, error) {
|
|
||||||
orderIndexStr := c.Param("orderIndex")
|
|
||||||
if orderIndexStr == "" {
|
|
||||||
return 0, response.NotFound().
|
|
||||||
Msg("no orderIndex found")
|
|
||||||
}
|
|
||||||
|
|
||||||
orderIndex, err := strconv.Atoi(orderIndexStr)
|
|
||||||
if err != nil {
|
|
||||||
return 0, response.NotFound().
|
|
||||||
Msgf("invalid order index: %s", orderIndexStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return orderIndex, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT /:acctID/platforms/:platform/order-index"
|
// PUT /:acctID/platforms/:platform/order-index"
|
||||||
// this endpoint is called when dragging a platform tab in the accounts page.
|
// this endpoint is called when dragging a platform tab in the accounts page.
|
||||||
func (s *accountSubrouter) setOrderOfPlatformOnAccountPage(c *gin.Context) (response.Response, error) {
|
func (s *accountSubrouter) setOrderOfPlatformOnAccountPage(c *gin.Context) (response.Response, error) {
|
||||||
@@ -200,30 +188,16 @@ func (s *accountSubrouter) setOrderOfPlatformOnAccountPage(c *gin.Context) (resp
|
|||||||
|
|
||||||
// validate parameters
|
// validate parameters
|
||||||
|
|
||||||
var orderIndex int
|
var (
|
||||||
if v, ok := c.GetPostForm("order-index"); !ok {
|
platform accounts.Platform
|
||||||
return nil, response.BadRequest().
|
orderIndex int
|
||||||
Msg("no order-index provided")
|
)
|
||||||
} else if i, err := strconv.Atoi(v); err != nil {
|
|
||||||
return nil, response.BadRequest().
|
|
||||||
Msgf("order-index must be a non-negative integer: %s", v)
|
|
||||||
} else if i < 0 {
|
|
||||||
return nil, response.BadRequest().
|
|
||||||
Msgf("order-index must be a non-negative integer: %s", v)
|
|
||||||
} else {
|
|
||||||
orderIndex = i
|
|
||||||
}
|
|
||||||
|
|
||||||
var platform accounts.Platform
|
err := param.Path("platform", param.Platform(&platform)).
|
||||||
if v := c.Param("platform"); v == "" {
|
Form("orderIndex", param.Int(&orderIndex)).
|
||||||
return nil, response.BadRequest().
|
Unmarshal(c)
|
||||||
Msg("no platform provided")
|
if err != nil {
|
||||||
} else if p, err := accounts.NewPlatform(v); err != nil {
|
return nil, err
|
||||||
return nil, response.BadRequest().
|
|
||||||
Wrap(err).
|
|
||||||
Msgf("unrecognized platform: %v", v)
|
|
||||||
} else {
|
|
||||||
platform = p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the order
|
// update the order
|
||||||
@@ -260,24 +234,16 @@ func (s *accountSubrouter) createMockShop(c *gin.Context) (response.Response, er
|
|||||||
|
|
||||||
// validate parameters
|
// validate parameters
|
||||||
|
|
||||||
var platform accounts.Platform
|
var (
|
||||||
if v := c.Param("platform"); v == "" {
|
platform accounts.Platform
|
||||||
return nil, response.BadRequest().
|
name string
|
||||||
Msg("no platform provided")
|
)
|
||||||
} else if p, err := accounts.NewPlatform(v); err != nil {
|
|
||||||
return nil, response.BadRequest().
|
|
||||||
Wrap(err).
|
|
||||||
Msgf("unrecognized platform: %v", v)
|
|
||||||
} else {
|
|
||||||
platform = p
|
|
||||||
}
|
|
||||||
|
|
||||||
var name string
|
err := param.Path("platform", param.Platform(&platform)).
|
||||||
if v, ok := c.GetPostForm("name"); !ok || v == "" {
|
Form("name", param.Text(&name)).
|
||||||
return nil, response.BadRequest().
|
Unmarshal(c)
|
||||||
Msg("no order-index provided")
|
if err != nil {
|
||||||
} else {
|
return nil, err
|
||||||
name = v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.log.Warnf("not implemented: mock store created: account_id = %d; platform = %s; name = %s", acctID, platform, name)
|
s.log.Warnf("not implemented: mock store created: account_id = %d; platform = %s; name = %s", acctID, platform, name)
|
||||||
@@ -301,6 +267,35 @@ func (s *accountSubrouter) createMockShop(c *gin.Context) (response.Response, er
|
|||||||
return res.HXLocation(location), nil
|
return res.HXLocation(location), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST /:acctID/platforms/:platform/shops/mocks/:shop-id/listings
|
||||||
|
func (s *accountSubrouter) addMockListing(c *gin.Context) (response.Response, error) {
|
||||||
|
var (
|
||||||
|
platform accounts.Platform
|
||||||
|
shopID string
|
||||||
|
name string
|
||||||
|
sku string
|
||||||
|
description string
|
||||||
|
)
|
||||||
|
|
||||||
|
err := param.Path("platform", param.Platform(&platform)).
|
||||||
|
Path("shop-id", param.Text(&shopID)).
|
||||||
|
Form("name", param.Text(&name)).
|
||||||
|
Form("sku", param.Text(&sku)).
|
||||||
|
Form("description", param.Text(&description)).
|
||||||
|
Unmarshal(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.log.Debugf("platform: %v", platform)
|
||||||
|
s.log.Debugf("shopID: %v", shopID)
|
||||||
|
s.log.Debugf("name: %v", name)
|
||||||
|
s.log.Debugf("sku: %v", sku)
|
||||||
|
s.log.Debugf("description: %v", description)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func lowerSnakeCase(s accounts.Platform) string {
|
func lowerSnakeCase(s accounts.Platform) string {
|
||||||
return strings.ToLower(strings.Join(strings.Split(string(s), " "), "_"))
|
return strings.ToLower(strings.Join(strings.Split(string(s), " "), "_"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package param
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"ruben/inventory2/internal/domains/accounts"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// encoding.TextUnmarshaler instances for Spec
|
||||||
|
|
||||||
|
func Text(dst *string) encoding.TextUnmarshaler {
|
||||||
|
return (*rawText)(dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Int(dst *int) encoding.TextUnmarshaler {
|
||||||
|
return (*intText)(dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Platform(dst *accounts.Platform) encoding.TextUnmarshaler {
|
||||||
|
return (*platformText)(dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
rawText string
|
||||||
|
intText int
|
||||||
|
platformText accounts.Platform
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *rawText) UnmarshalText(text []byte) error {
|
||||||
|
*t = rawText(text)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *intText) UnmarshalText(text []byte) error {
|
||||||
|
i, err := strconv.Atoi(string(text))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*n = intText(i)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *platformText) UnmarshalText(text []byte) error {
|
||||||
|
v, err := accounts.NewPlatform(string(text))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*p = platformText(v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package param
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"ruben/inventory2/internal/server/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Spec is the entry point of the package.
|
||||||
|
// It's typically constructed via Path() or Form().
|
||||||
|
// But it's zero value is valid.
|
||||||
|
//
|
||||||
|
// It's methods support a builder pattern to minimize API bloat.
|
||||||
|
//
|
||||||
|
// To complete gin parameter parsing, call Unmarshal().
|
||||||
|
type Spec struct {
|
||||||
|
path map[string]encoding.TextUnmarshaler
|
||||||
|
form map[string]encoding.TextUnmarshaler
|
||||||
|
}
|
||||||
|
|
||||||
|
func Path(k string, dst encoding.TextUnmarshaler) Spec {
|
||||||
|
return Spec{
|
||||||
|
path: map[string]encoding.TextUnmarshaler{
|
||||||
|
k: dst,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Form(k string, dst encoding.TextUnmarshaler) Spec {
|
||||||
|
return Spec{
|
||||||
|
form: map[string]encoding.TextUnmarshaler{
|
||||||
|
k: dst,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Spec) Path(k string, dst encoding.TextUnmarshaler) Spec {
|
||||||
|
if s.path == nil {
|
||||||
|
s.path = make(map[string]encoding.TextUnmarshaler, 1)
|
||||||
|
}
|
||||||
|
s.path[k] = dst
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Spec) Form(k string, dst encoding.TextUnmarshaler) Spec {
|
||||||
|
if s.form == nil {
|
||||||
|
s.form = make(map[string]encoding.TextUnmarshaler, 1)
|
||||||
|
}
|
||||||
|
s.form[k] = dst
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Spec) Unmarshal(c *gin.Context) error {
|
||||||
|
for k, dst := range s.path {
|
||||||
|
v := c.Param(k)
|
||||||
|
if v == "" {
|
||||||
|
return response.NotFound().Msgf("no %s provided", k)
|
||||||
|
}
|
||||||
|
if err := dst.UnmarshalText([]byte(v)); err != nil {
|
||||||
|
return response.NotFound().Wrap(err).Msgf("invalid %s", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, dst := range s.form {
|
||||||
|
v, ok := c.GetPostForm(k)
|
||||||
|
if !ok || v == "" {
|
||||||
|
return response.BadRequest().Msgf("no %s provided", k)
|
||||||
|
}
|
||||||
|
if err := dst.UnmarshalText([]byte(v)); err != nil {
|
||||||
|
return response.BadRequest().Wrap(err).Msgf("invalid %s provided", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -100,6 +100,19 @@ func Routes(
|
|||||||
"rawHTML": func(s string) template.HTML {
|
"rawHTML": func(s string) template.HTML {
|
||||||
return template.HTML(s)
|
return template.HTML(s)
|
||||||
},
|
},
|
||||||
|
"rawHTMLAttr": func(s string) template.HTMLAttr {
|
||||||
|
return template.HTMLAttr(s)
|
||||||
|
},
|
||||||
|
"style": func(kvs ...string) (template.HTMLAttr, error) {
|
||||||
|
if len(kvs)%2 != 0 {
|
||||||
|
return "", fmt.Errorf("expected an even number of keys: %d", len(kvs))
|
||||||
|
}
|
||||||
|
parts := make([]string, len(kvs)/2)
|
||||||
|
for i := range parts {
|
||||||
|
parts[i] = fmt.Sprintf("%s: %s;", kvs[2*i], kvs[2*i+1])
|
||||||
|
}
|
||||||
|
return template.HTMLAttr(strings.Join(parts, " ")), nil
|
||||||
|
},
|
||||||
|
|
||||||
// json
|
// json
|
||||||
"prettyPrintJSON": func(j json.RawMessage) string {
|
"prettyPrintJSON": func(j json.RawMessage) string {
|
||||||
|
|||||||
+68
-54
@@ -195,6 +195,9 @@
|
|||||||
.col-3 {
|
.col-3 {
|
||||||
grid-column: 3;
|
grid-column: 3;
|
||||||
}
|
}
|
||||||
|
.col-span-2 {
|
||||||
|
grid-column: span 2 / span 2;
|
||||||
|
}
|
||||||
.container {
|
.container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
@@ -234,12 +237,6 @@
|
|||||||
.my-\[1rem\] {
|
.my-\[1rem\] {
|
||||||
margin-block: 1rem;
|
margin-block: 1rem;
|
||||||
}
|
}
|
||||||
.my-\[2em\] {
|
|
||||||
margin-block: 2em;
|
|
||||||
}
|
|
||||||
.my-\[5em\] {
|
|
||||||
margin-block: 5em;
|
|
||||||
}
|
|
||||||
.mt-\[0\.25em\] {
|
.mt-\[0\.25em\] {
|
||||||
margin-top: 0.25em;
|
margin-top: 0.25em;
|
||||||
}
|
}
|
||||||
@@ -336,6 +333,12 @@
|
|||||||
.basis-full {
|
.basis-full {
|
||||||
flex-basis: 100%;
|
flex-basis: 100%;
|
||||||
}
|
}
|
||||||
|
.border-collapse {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.transform {
|
||||||
|
transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);
|
||||||
|
}
|
||||||
.animate-pulse {
|
.animate-pulse {
|
||||||
animation: var(--animate-pulse);
|
animation: var(--animate-pulse);
|
||||||
}
|
}
|
||||||
@@ -354,15 +357,27 @@
|
|||||||
.list-none {
|
.list-none {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
.grid-cols-\[1fr_1fr\] {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
.grid-cols-\[2fr_8fr_2fr\] {
|
.grid-cols-\[2fr_8fr_2fr\] {
|
||||||
grid-template-columns: 2fr 8fr 2fr;
|
grid-template-columns: 2fr 8fr 2fr;
|
||||||
}
|
}
|
||||||
.grid-cols-\[6rem_10fr_6rem\] {
|
.grid-cols-\[6rem_10fr_6rem\] {
|
||||||
grid-template-columns: 6rem 10fr 6rem;
|
grid-template-columns: 6rem 10fr 6rem;
|
||||||
}
|
}
|
||||||
|
.grid-cols-\[max-content_1fr\] {
|
||||||
|
grid-template-columns: max-content 1fr;
|
||||||
|
}
|
||||||
.grid-cols-\[max-content_max-content\] {
|
.grid-cols-\[max-content_max-content\] {
|
||||||
grid-template-columns: max-content max-content;
|
grid-template-columns: max-content max-content;
|
||||||
}
|
}
|
||||||
|
.grid-rows-\[auto\] {
|
||||||
|
grid-template-rows: auto;
|
||||||
|
}
|
||||||
|
.grid-rows-\[auto_auto_auto\] {
|
||||||
|
grid-template-rows: auto auto auto;
|
||||||
|
}
|
||||||
.flex-col {
|
.flex-col {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@@ -381,6 +396,9 @@
|
|||||||
.justify-start {
|
.justify-start {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
.gap-\[0\.5em\] {
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
.gap-\[0\.25em\] {
|
.gap-\[0\.25em\] {
|
||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
}
|
}
|
||||||
@@ -421,18 +439,10 @@
|
|||||||
border-style: var(--tw-border-style);
|
border-style: var(--tw-border-style);
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
}
|
}
|
||||||
.border-\[0\.5px\] {
|
|
||||||
border-style: var(--tw-border-style);
|
|
||||||
border-width: 0.5px;
|
|
||||||
}
|
|
||||||
.border-\[1px\] {
|
.border-\[1px\] {
|
||||||
border-style: var(--tw-border-style);
|
border-style: var(--tw-border-style);
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
}
|
}
|
||||||
.border-\[10px\] {
|
|
||||||
border-style: var(--tw-border-style);
|
|
||||||
border-width: 10px;
|
|
||||||
}
|
|
||||||
.border-b-\[2px\] {
|
.border-b-\[2px\] {
|
||||||
border-bottom-style: var(--tw-border-style);
|
border-bottom-style: var(--tw-border-style);
|
||||||
border-bottom-width: 2px;
|
border-bottom-width: 2px;
|
||||||
@@ -484,6 +494,9 @@
|
|||||||
.py-\[0\.5em\] {
|
.py-\[0\.5em\] {
|
||||||
padding-block: 0.5em;
|
padding-block: 0.5em;
|
||||||
}
|
}
|
||||||
|
.py-\[1em\] {
|
||||||
|
padding-block: 1em;
|
||||||
|
}
|
||||||
.pt-\[1em\] {
|
.pt-\[1em\] {
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
}
|
}
|
||||||
@@ -505,6 +518,9 @@
|
|||||||
.font-display {
|
.font-display {
|
||||||
font-family: var(--display-family);
|
font-family: var(--display-family);
|
||||||
}
|
}
|
||||||
|
.font-text {
|
||||||
|
font-family: var(--text-family);
|
||||||
|
}
|
||||||
.text-2xl {
|
.text-2xl {
|
||||||
font-size: var(--text-2xl);
|
font-size: var(--text-2xl);
|
||||||
line-height: var(--tw-leading, var(--text-2xl--line-height));
|
line-height: var(--tw-leading, var(--text-2xl--line-height));
|
||||||
@@ -532,6 +548,9 @@
|
|||||||
.text-nowrap {
|
.text-nowrap {
|
||||||
text-wrap: nowrap;
|
text-wrap: nowrap;
|
||||||
}
|
}
|
||||||
|
.text-wrap {
|
||||||
|
text-wrap: wrap;
|
||||||
|
}
|
||||||
.capitalize {
|
.capitalize {
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
@@ -541,6 +560,10 @@
|
|||||||
.underline {
|
.underline {
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
}
|
}
|
||||||
|
.outline {
|
||||||
|
outline-style: var(--tw-outline-style);
|
||||||
|
outline-width: 1px;
|
||||||
|
}
|
||||||
.filter {
|
.filter {
|
||||||
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
||||||
}
|
}
|
||||||
@@ -663,11 +686,6 @@
|
|||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.open\:mb-\[2em\] {
|
|
||||||
&:is([open], :popover-open, :open) {
|
|
||||||
margin-bottom: 2em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.open\:grid {
|
.open\:grid {
|
||||||
&:is([open], :popover-open, :open) {
|
&:is([open], :popover-open, :open) {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -679,11 +697,6 @@
|
|||||||
border-bottom-width: 1px;
|
border-bottom-width: 1px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.open\:border-b-accent {
|
|
||||||
&:is([open], :popover-open, :open) {
|
|
||||||
border-bottom-color: var(--accent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.open\:border-b-background {
|
.open\:border-b-background {
|
||||||
&:is([open], :popover-open, :open) {
|
&:is([open], :popover-open, :open) {
|
||||||
border-bottom-color: var(--background);
|
border-bottom-color: var(--background);
|
||||||
@@ -694,11 +707,6 @@
|
|||||||
padding-bottom: 1em;
|
padding-bottom: 1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.open\:pb-\[2em\] {
|
|
||||||
&:is([open], :popover-open, :open) {
|
|
||||||
padding-bottom: 2em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.open\:details-content\:transform-\[translate\(0px\,0px\)\] {
|
.open\:details-content\:transform-\[translate\(0px\,0px\)\] {
|
||||||
&:is([open], :popover-open, :open) {
|
&:is([open], :popover-open, :open) {
|
||||||
&::details-content {
|
&::details-content {
|
||||||
@@ -1131,6 +1139,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@property --tw-rotate-x {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-rotate-y {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-rotate-z {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-skew-x {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-skew-y {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
@property --tw-border-style {
|
@property --tw-border-style {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
@@ -1140,6 +1168,11 @@
|
|||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
}
|
}
|
||||||
|
@property --tw-outline-style {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
initial-value: solid;
|
||||||
|
}
|
||||||
@property --tw-blur {
|
@property --tw-blur {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
inherits: false;
|
inherits: false;
|
||||||
@@ -1208,26 +1241,6 @@
|
|||||||
inherits: false;
|
inherits: false;
|
||||||
initial-value: 1;
|
initial-value: 1;
|
||||||
}
|
}
|
||||||
@property --tw-rotate-x {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-rotate-y {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-rotate-z {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-skew-x {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-skew-y {
|
|
||||||
syntax: "*";
|
|
||||||
inherits: false;
|
|
||||||
}
|
|
||||||
@property --tw-content {
|
@property --tw-content {
|
||||||
syntax: "*";
|
syntax: "*";
|
||||||
initial-value: "";
|
initial-value: "";
|
||||||
@@ -1245,8 +1258,14 @@
|
|||||||
@layer properties {
|
@layer properties {
|
||||||
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
|
||||||
*, ::before, ::after, ::backdrop {
|
*, ::before, ::after, ::backdrop {
|
||||||
|
--tw-rotate-x: initial;
|
||||||
|
--tw-rotate-y: initial;
|
||||||
|
--tw-rotate-z: initial;
|
||||||
|
--tw-skew-x: initial;
|
||||||
|
--tw-skew-y: initial;
|
||||||
--tw-border-style: solid;
|
--tw-border-style: solid;
|
||||||
--tw-font-weight: initial;
|
--tw-font-weight: initial;
|
||||||
|
--tw-outline-style: solid;
|
||||||
--tw-blur: initial;
|
--tw-blur: initial;
|
||||||
--tw-brightness: initial;
|
--tw-brightness: initial;
|
||||||
--tw-contrast: initial;
|
--tw-contrast: initial;
|
||||||
@@ -1263,11 +1282,6 @@
|
|||||||
--tw-scale-x: 1;
|
--tw-scale-x: 1;
|
||||||
--tw-scale-y: 1;
|
--tw-scale-y: 1;
|
||||||
--tw-scale-z: 1;
|
--tw-scale-z: 1;
|
||||||
--tw-rotate-x: initial;
|
|
||||||
--tw-rotate-y: initial;
|
|
||||||
--tw-rotate-z: initial;
|
|
||||||
--tw-skew-x: initial;
|
|
||||||
--tw-skew-y: initial;
|
|
||||||
--tw-content: "";
|
--tw-content: "";
|
||||||
--tw-leading: initial;
|
--tw-leading: initial;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@
|
|||||||
{{- range $shop := $shops }}
|
{{- range $shop := $shops }}
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href={{ printf "/ui/accounts/%d/platforms/%s/mock-shops/%s" $acctID $platform $shop.ShopID }}
|
href={{ printf "/ui/accounts/%d/platforms/%s/shops/mocks/%s" $acctID $platform $shop.ShopID }}
|
||||||
hx-boost="false"
|
hx-boost="false"
|
||||||
class="
|
class="
|
||||||
border-foreground
|
border-foreground
|
||||||
|
|||||||
-16
@@ -1,16 +0,0 @@
|
|||||||
{{ $acctID := .Identity.Account.AccountID }}
|
|
||||||
{{ $platform := parsePlatform .PathParams.platform }}
|
|
||||||
{{ $shopID := .PathParams.shopID }}
|
|
||||||
{{- $shop := .Accounts.GetMockShop $acctID $platform $shopID }}
|
|
||||||
|
|
||||||
<h1 class="mt-[1em] text-center">
|
|
||||||
{{ $shop.Name }}
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p class="m-[1em] text-center font-display">
|
|
||||||
{{ .PathParams.platform | splitSnakeCase | capitalize }}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 class="mt-[5em] text-center block">
|
|
||||||
A work in progress...
|
|
||||||
</h2>
|
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
{{ $acctID := .Identity.Account.AccountID }}
|
||||||
|
{{ $platform := parsePlatform .PathParams.platform }}
|
||||||
|
{{ $shopID := .PathParams.shopID }}
|
||||||
|
{{- $shop := .Accounts.GetMockShop $acctID $platform $shopID }}
|
||||||
|
|
||||||
|
<h1 class="mt-[1em] text-center">
|
||||||
|
{{ $shop.Name }}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p class="m-[1em] text-center font-display">
|
||||||
|
{{ .PathParams.platform | splitSnakeCase | capitalize }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<section
|
||||||
|
id="listing-section"
|
||||||
|
hx-get={{ printf "/ui/accounts/%d/platforms/amazon/shops/mocks/%s" $acctID $shopID }}
|
||||||
|
hx-trigger={{ printf "sse:accounts_%d_platforms_amazon_shops_mocks_%s_listings" $acctID $shopID }}
|
||||||
|
hx-select="#listing-section"
|
||||||
|
hx-swap="morph"
|
||||||
|
>
|
||||||
|
<header class="p-[1em]">
|
||||||
|
<h2 class="text-center">
|
||||||
|
Listings
|
||||||
|
</h2>
|
||||||
|
<h3 class="text-center">
|
||||||
|
Add listings to your mock store to begin mocking store synchronization
|
||||||
|
</h3>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-[1fr_1fr]">
|
||||||
|
<form
|
||||||
|
id="new-listing-form"
|
||||||
|
hx-post={{ printf "/api/accounts/%d/platforms/amazon/shops/mocks/%s/listings" $acctID $shopID }}
|
||||||
|
hx-swap="none"
|
||||||
|
class="
|
||||||
|
grid
|
||||||
|
grid-cols-[max-content_1fr]
|
||||||
|
grid-rows-[auto_auto_auto]
|
||||||
|
gap-[0.5em]
|
||||||
|
m-[0.5em]
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<label for="name">
|
||||||
|
Name:
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
required
|
||||||
|
minlength="5"
|
||||||
|
placeholder="What's in a name..."
|
||||||
|
class="bg-card p-[0.25em]"
|
||||||
|
/>
|
||||||
|
<label for="sku">
|
||||||
|
SKU:
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="sku"
|
||||||
|
required
|
||||||
|
class="bg-card p-[0.25em]"
|
||||||
|
/>
|
||||||
|
<label for="description">
|
||||||
|
Description:
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="description"
|
||||||
|
required
|
||||||
|
minlength="10"
|
||||||
|
placeholder="Anything will do..."
|
||||||
|
class="bg-card p-[0.25em]"
|
||||||
|
/>
|
||||||
|
{{ component "button"
|
||||||
|
"Text" "Save Listing"
|
||||||
|
"Class" "self-center p-[1em] col-span-2"
|
||||||
|
}}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Listing 1
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Listing 2
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Listing 3
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<h2 class="mt-[5em] text-center block">
|
||||||
|
A work in progress...
|
||||||
|
</h2>
|
||||||
Reference in New Issue
Block a user