mock shop page allows updating of listings

This commit is contained in:
2026-02-05 10:17:19 -07:00
parent d187fbc0f4
commit 925e2b9db8
5 changed files with 233 additions and 39 deletions
+44 -1
View File
@@ -309,7 +309,7 @@ func (db *Store) CreateMockListing(ctx context.Context, listing MockListing) (Mo
"sku": listing.SKU, "sku": listing.SKU,
"name": listing.Name, "name": listing.Name,
"description": listing.Description, "description": listing.Description,
"count": listing.Count + 5, "count": listing.Count,
}, },
) )
if err != nil { if err != nil {
@@ -322,6 +322,49 @@ func (db *Store) CreateMockListing(ctx context.Context, listing MockListing) (Mo
return listing, nil return listing, nil
} }
// UpdateMockListing updates a mock listing, but not it's count
func (db *Store) UpdateMockListing(ctx context.Context, listing MockListing) error {
_, listingTableName, err := getMockShopAndListingsTableNames(listing.Platform)
if err != nil {
return err
}
tag, err := db.db.Exec(
ctx,
fmt.Sprintf(
`
UPDATE
%s
SET
sku = @sku,
name = @name,
description = @description
WHERE
account_id = @account_id
AND shop_id = @shop_id
AND listing_id = @listing_id
`,
listingTableName,
),
pgx.NamedArgs{
"account_id": listing.AccountID,
"shop_id": listing.ShopID,
"listing_id": listing.ListingID,
"sku": listing.SKU,
"name": listing.Name,
"description": listing.Description,
},
)
if err != nil {
return fmt.Errorf("failed to perform query: %w", err)
}
if tag.RowsAffected() == 0 {
return fmt.Errorf("%w: listing not found", consts.ErrNotFound)
}
return nil
}
func (db *Store) ListMockListingsForShop(ctx context.Context, acctID int64, platform Platform, shopID string) ([]MockListing, error) { func (db *Store) ListMockListingsForShop(ctx context.Context, acctID int64, platform Platform, shopID string) ([]MockListing, error) {
shopTableName, listingsTableName, err := getMockShopAndListingsTableNames(platform) shopTableName, listingsTableName, err := getMockShopAndListingsTableNames(platform)
if err != nil { if err != nil {
@@ -68,6 +68,10 @@ func (v_ctx *StoreWithContext) CreateMockListing(listing MockListing) (MockListi
return v_ctx.Store.CreateMockListing(v_ctx.ctx, listing) return v_ctx.Store.CreateMockListing(v_ctx.ctx, listing)
} }
func (v_ctx *StoreWithContext) UpdateMockListing(listing MockListing) error {
return v_ctx.Store.UpdateMockListing(v_ctx.ctx, listing)
}
func (v_ctx *StoreWithContext) ListMockListingsForShop(acctID int64, platform Platform, shopID string) ([]MockListing, error) { func (v_ctx *StoreWithContext) ListMockListingsForShop(acctID int64, platform Platform, shopID string) ([]MockListing, error) {
return v_ctx.Store.ListMockListingsForShop(v_ctx.ctx, acctID, platform, shopID) return v_ctx.Store.ListMockListingsForShop(v_ctx.ctx, acctID, platform, shopID)
} }
+44 -1
View File
@@ -43,6 +43,7 @@ func Routes(
mockShops := platformGroup.Group("/shops/mocks/:shop-id") mockShops := platformGroup.Group("/shops/mocks/:shop-id")
mockShops.POST("/listings", response.Handler(as.addMockListing)) mockShops.POST("/listings", response.Handler(as.addMockListing))
mockShops.PUT("/listings/:listing-id", response.Handler(as.updateMockListing))
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))
@@ -304,7 +305,49 @@ func (s *accountSubrouter) addMockListing(c *gin.Context) (response.Response, er
return nil, fmt.Errorf("failed to create new listing: %w", err) return nil, fmt.Errorf("failed to create new listing: %w", err)
} }
return nil, nil return response.StatusCreated(), nil
}
// PUT /:acctID/platforms/:platform/shops/mocks/:shop-id/listings/:listing-id
func (s *accountSubrouter) updateMockListing(c *gin.Context) (response.Response, error) {
acctID := auth.GetIdentity(c).Account.AccountID
var (
platform accounts.Platform
shopID string
listingID string
name string
sku string
description string
)
err := param.Path("platform", param.Platform(&platform)).
Path("shop-id", param.Text(&shopID)).
Path("listing-id", param.Text(&listingID)).
Form("name", param.Text(&name)).
Form("sku", param.Text(&sku)).
Form("description", param.Text(&description)).
Unmarshal(c)
if err != nil {
return nil, err
}
err = s.accts.UpdateMockListing(
c,
accounts.MockListing{
AccountShopListingIDs: accounts.NewAccountIDs(acctID).
ShopID(platform, shopID).
ListingID(listingID),
Name: name,
SKU: sku,
Description: description,
},
)
if err != nil {
return nil, fmt.Errorf("failed to update new listing: %w", err)
}
return response.StatusOK(), nil
} }
func lowerSnakeCase(s accounts.Platform) string { func lowerSnakeCase(s accounts.Platform) string {
+3 -11
View File
@@ -193,6 +193,9 @@
.col-3 { .col-3 {
grid-column: 3; grid-column: 3;
} }
.col-\[span_2\] {
grid-column: span 2;
}
.col-span-2 { .col-span-2 {
grid-column: span 2 / span 2; grid-column: span 2 / span 2;
} }
@@ -265,9 +268,6 @@
.ml-\[1em\] { .ml-\[1em\] {
margin-left: 1em; margin-left: 1em;
} }
.box-border {
box-sizing: border-box;
}
.block { .block {
display: block; display: block;
} }
@@ -355,9 +355,6 @@
.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;
} }
@@ -799,11 +796,6 @@
padding-block: calc(8vw - 0.5em); padding-block: calc(8vw - 0.5em);
} }
} }
.sm\:grid-cols-\[1fr_1fr\] {
@media (width >= 40rem) {
grid-template-columns: 1fr 1fr;
}
}
.md\:grid-cols-\[1fr_1fr\] { .md\:grid-cols-\[1fr_1fr\] {
@media (width >= 48rem) { @media (width >= 48rem) {
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
@@ -27,9 +27,32 @@
</h3> </h3>
</header> </header>
<div class="grid md:grid-cols-[1fr_1fr] gap-[1em] p-[1em]"> <div
id="listings-container"
class="grid md:grid-cols-[1fr_1fr] gap-[1em] p-[1em]"
_="
on startEditingExistingListing(
listingID,
name,
sku,
description
)
send hide to #new-listing-form
send show(
listingID: listingID,
name: name,
sku: sku,
description: description
) to #edit-listing-form
on startEditingNewListing
send show to #new-listing-form
send hide to #edit-listing-form
send reset to <li/> in <ul/> in me
"
>
<form <form
id="edit-listing-form" id="new-listing-form"
hx-post={{ printf "/api/accounts/%d/platforms/amazon/shops/mocks/%s/listings" $acctID $shopID }} hx-post={{ printf "/api/accounts/%d/platforms/amazon/shops/mocks/%s/listings" $acctID $shopID }}
hx-swap="none" hx-swap="none"
class=" class="
@@ -43,21 +66,22 @@
rounded-lg rounded-lg
" "
_=" _="
on editListing( on hide
listingID, add @disabled to <button#save-as-new-listing-button/>
name, add .hidden to me
sku, set the value of the first <input[name='name']/> in me to ''
description set the value of the first <input[name='sku']/> in me to ''
) set the value of the first <input[name='description']/> in me to ''
set the value of the first <input[name='name']/> in me to name on show
set the value of the first <input[name='sku']/> in me to sku remove .hidden from me
set the value of the first <input[name='description']/> in me to description
remove .hidden from <button#save-as-new-listing-button/>
remove @disabled from <button#save-as-new-listing-button/> remove @disabled from <button#save-as-new-listing-button/>
" "
> >
<h3 class="col-[span_2] text-center">
New Listing
</h3>
<label for="name"> <label for="name">
Name: Name:
</label> </label>
<input <input
type="text" type="text"
@@ -68,7 +92,7 @@
class="bg-accent p-[0.25em] rounded-sm" class="bg-accent p-[0.25em] rounded-sm"
/> />
<label for="sku"> <label for="sku">
SKU: SKU:
</label> </label>
<input <input
type="text" type="text"
@@ -77,7 +101,7 @@
class="bg-accent p-[0.25em] rounded-sm" class="bg-accent p-[0.25em] rounded-sm"
/> />
<label for="description"> <label for="description">
Description: Description:
</label> </label>
<input <input
type="text" type="text"
@@ -88,16 +112,104 @@
class="bg-accent p-[0.25em] rounded-sm" class="bg-accent p-[0.25em] rounded-sm"
/> />
{{ component "button" {{ component "button"
"Text" "Save Listing" "Text" "Save"
"Class" "self-center p-[1em] col-span-2" "Class" "self-center p-[1em] col-span-2"
"_" "on click send reset() to <li/> in next <ul/>" "ID" "save-as-new-listing-button"
}}
</form>
<form
id="edit-listing-form"
hx-put={{ printf "/api/accounts/%d/platforms/amazon/shops/mocks/%s/listings/{listingID}" $acctID $shopID }}
hx-swap="none"
class="
grid
grid-cols-[max-content_1fr]
grid-rows-[auto_auto_auto]
gap-[0.5em]
p-[1em]
bg-card
h-fit
rounded-lg
hidden
"
_="
on hide
add @disabled to <button#save-listing-button/>
add @disabled to <button#edit-new-listing-button/>
add .hidden to me
set the value of the first <input[name='name']/> in me to ''
set the value of the first <input[name='sku']/> in me to ''
set the value of the first <input[name='description']/> in me to ''
on show(
listingID,
name,
sku,
description
)
set :listingID to listingID
remove .hidden from me
remove @disabled from <button#save-listing-button/>
remove @disabled from <button#edit-new-listing-button/>
set the value of the first <input[name='listingID']/> in me to listingID
set the value of the first <input[name='name']/> in me to name
set the value of the first <input[name='sku']/> in me to sku
set the value of the first <input[name='description']/> in me to description
set the innerHTML of the <h3/> in me to ('Editing ' + name)
"
>
<h3 class="col-[span_2] text-center">
Edit Listing
</h3>
<label for="name">
Name:
</label>
<input
type="text"
name="name"
required
minlength="5"
placeholder="What's in a name..."
class="bg-accent p-[0.25em] rounded-sm"
/>
<label for="sku">
SKU:
</label>
<input
type="text"
name="sku"
required
class="bg-accent p-[0.25em] rounded-sm"
/>
<label for="description">
Description:
</label>
<input
type="text"
name="description"
required
minlength="10"
placeholder="Anything will do..."
class="bg-accent p-[0.25em] rounded-sm"
/>
<input
type="hidden"
name="listingID"
value=""
/>
{{ component "button"
"Text" "Save"
"Class" "self-center p-[1em] col-span-2"
"ID" "save-listing-button"
"Disabled" true
"_" "on click send reset to <li/> in next <ul/>"
}} }}
{{ component "button" {{ component "button"
"Text" "Save As New Listing" "Text" "New"
"Class" "self-center p-[1em] col-span-2 hidden" "Class" "self-center p-[1em] col-span-2"
"ID" "save-as-new-listing-button" "ID" "edit-new-listing-button"
"Disabled" true "Disabled" true
"_" "on click event.preventDefault() then send reset() to <li/> in next <ul/>" "_" "on click event.preventDefault() then send startEditingNewListing to #listings-container"
}} }}
</form> </form>
@@ -112,15 +224,15 @@
" "
_=" _="
on click on click
send reset() to <li/> in the closest <ul/> send startEditingExistingListing(
add .border-foreground to me
add .border to me
send editListing(
listingID: '{{$listing.ListingID}}', listingID: '{{$listing.ListingID}}',
name: '{{$listing.Name}}', name: '{{$listing.Name}}',
sku: '{{$listing.SKU}}', sku: '{{$listing.SKU}}',
description: '{{$listing.Description}}' description: '{{$listing.Description}}'
) to #edit-listing-form ) to #listings-container
send reset() to <li/> in the closest <ul/>
add .border-foreground to me
add .border to me
on reset on reset
remove .border-foreground from me remove .border-foreground from me