mock shop page: can delete listings
This commit is contained in:
@@ -365,6 +365,41 @@ func (db *Store) UpdateMockListing(ctx context.Context, listing MockListing) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Store) DeleteMockListing(ctx context.Context, ids AccountShopListingIDs) error {
|
||||
_, listingTableName, err := getMockShopAndListingsTableNames(ids.Platform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tag, err := db.db.Exec(
|
||||
ctx,
|
||||
fmt.Sprintf(
|
||||
`
|
||||
DELETE FROM
|
||||
%s
|
||||
WHERE
|
||||
account_id = @account_id
|
||||
AND shop_id = @shop_id
|
||||
AND listing_id = @listing_id
|
||||
`,
|
||||
listingTableName,
|
||||
),
|
||||
pgx.NamedArgs{
|
||||
"account_id": ids.AccountID,
|
||||
"shop_id": ids.ShopID,
|
||||
"listing_id": ids.ListingID,
|
||||
},
|
||||
)
|
||||
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) {
|
||||
shopTableName, listingsTableName, err := getMockShopAndListingsTableNames(platform)
|
||||
if err != nil {
|
||||
|
||||
@@ -72,6 +72,10 @@ func (v_ctx *StoreWithContext) UpdateMockListing(listing MockListing) error {
|
||||
return v_ctx.Store.UpdateMockListing(v_ctx.ctx, listing)
|
||||
}
|
||||
|
||||
func (v_ctx *StoreWithContext) DeleteMockListing(ids AccountShopListingIDs) error {
|
||||
return v_ctx.Store.DeleteMockListing(v_ctx.ctx, ids)
|
||||
}
|
||||
|
||||
func (v_ctx *StoreWithContext) ListMockListingsForShop(acctID int64, platform Platform, shopID string) ([]MockListing, error) {
|
||||
return v_ctx.Store.ListMockListingsForShop(v_ctx.ctx, acctID, platform, shopID)
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ func Routes(
|
||||
mockShops := platformGroup.Group("/shops/mocks/:shop-id")
|
||||
mockShops.POST("/listings", response.Handler(as.addMockListing))
|
||||
mockShops.PUT("/listings/:listing-id", response.Handler(as.updateMockListing))
|
||||
mockShops.DELETE("/listings/:listing-id", response.Handler(as.deleteMockListing))
|
||||
|
||||
syncGroups := r.Group("/:acctID/inventory/sync-groups")
|
||||
syncGroups.POST("", pub.Publish("/:acctID/inventory/sync-groups"), response.Handler(as.saveNewSyncGroup))
|
||||
@@ -344,12 +345,43 @@ func (s *accountSubrouter) updateMockListing(c *gin.Context) (response.Response,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update new listing: %w", err)
|
||||
return nil, fmt.Errorf("failed to update listing: %w", err)
|
||||
}
|
||||
|
||||
return response.StatusOK(), nil
|
||||
}
|
||||
|
||||
// DELETE /:acctID/platforms/:platform/shops/mocks/:shop-id/listings/:listing-id
|
||||
func (s *accountSubrouter) deleteMockListing(c *gin.Context) (response.Response, error) {
|
||||
acctID := auth.GetIdentity(c).Account.AccountID
|
||||
|
||||
var (
|
||||
platform accounts.Platform
|
||||
shopID string
|
||||
listingID string
|
||||
)
|
||||
|
||||
err := param.Path("platform", param.Platform(&platform)).
|
||||
Path("shop-id", param.Text(&shopID)).
|
||||
Path("listing-id", param.Text(&listingID)).
|
||||
Unmarshal(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.accts.DeleteMockListing(
|
||||
c,
|
||||
accounts.NewAccountIDs(acctID).
|
||||
ShopID(platform, shopID).
|
||||
ListingID(listingID),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to delete listing: %w", err)
|
||||
}
|
||||
|
||||
return response.StatusNoContent(), nil
|
||||
}
|
||||
|
||||
func lowerSnakeCase(s accounts.Platform) string {
|
||||
return strings.ToLower(strings.Join(strings.Split(string(s), " "), "_"))
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"ruben/inventory2/internal/consts"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@@ -46,11 +47,23 @@ func HandleErrors(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
var err error
|
||||
var (
|
||||
err error
|
||||
status int
|
||||
statusFound bool
|
||||
)
|
||||
for _, e := range c.Errors {
|
||||
err = errors.Join(err, e)
|
||||
if !statusFound {
|
||||
status, statusFound = mapErrorConstantsToStatus(e)
|
||||
}
|
||||
}
|
||||
c.String(http.StatusInternalServerError, err.Error())
|
||||
|
||||
if !statusFound {
|
||||
status = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
c.String(status, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -131,3 +144,24 @@ func GetStatusFromError(err error) int {
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
func mapErrorConstantsToStatus(err error) (int, bool) {
|
||||
for {
|
||||
switch err {
|
||||
case consts.ErrBadRequest:
|
||||
return http.StatusBadRequest, true
|
||||
case consts.ErrNotFound:
|
||||
return http.StatusNotFound, true
|
||||
case consts.ErrConflict:
|
||||
return http.StatusConflict, true
|
||||
default:
|
||||
werr, ok := err.(interface {
|
||||
Unwrap() error
|
||||
})
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
err = werr.Unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,6 +536,9 @@
|
||||
.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.no-underline {
|
||||
text-decoration-line: none;
|
||||
}
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
@@ -764,6 +767,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.hover\:no-underline {
|
||||
&:hover {
|
||||
@media (hover: hover) {
|
||||
text-decoration-line: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.hover\:underline {
|
||||
&:hover {
|
||||
@media (hover: hover) {
|
||||
|
||||
+45
-25
@@ -297,9 +297,12 @@
|
||||
id="listing-{{$listing.ListingID}}"
|
||||
class="
|
||||
p-[1em]
|
||||
grid grid-cols-[max-content_1fr] gap-x-[1em]
|
||||
bg-card
|
||||
rounded-lg
|
||||
|
||||
flex
|
||||
flex-col
|
||||
items-stretch
|
||||
"
|
||||
_="
|
||||
on click
|
||||
@@ -318,33 +321,50 @@
|
||||
remove .border from me
|
||||
"
|
||||
>
|
||||
<span>
|
||||
Name:
|
||||
</span>
|
||||
<span class="listing-name">
|
||||
{{ $listing.Name }}
|
||||
</span>
|
||||
<table class="mb-[0.5em]" style="display: table;">
|
||||
<tr>
|
||||
<th>
|
||||
Name:
|
||||
</th>
|
||||
<td class="listing-name">
|
||||
{{ $listing.Name }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<span>
|
||||
SKU:
|
||||
</span>
|
||||
<span>
|
||||
{{ $listing.SKU }}
|
||||
</span>
|
||||
<tr>
|
||||
<th>
|
||||
SKU:
|
||||
</th>
|
||||
<td>
|
||||
{{ $listing.SKU }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<span>
|
||||
Description:
|
||||
</span>
|
||||
<span>
|
||||
{{ $listing.Description }}
|
||||
</span>
|
||||
<tr>
|
||||
<th>
|
||||
Description:
|
||||
</th>
|
||||
<td>
|
||||
{{ $listing.Description }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<span>
|
||||
Count:
|
||||
</span>
|
||||
<span>
|
||||
{{ $listing.Count }}
|
||||
</span>
|
||||
<tr>
|
||||
<th>
|
||||
Count:
|
||||
</th>
|
||||
<td>
|
||||
{{ $listing.Count }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
{{ component "button"
|
||||
"Title" "Delete Listing"
|
||||
"Text" (rawHTML "🗑")
|
||||
"HXDelete" (printf "/api/accounts/%d/platforms/amazon/shops/mocks/%s/listings/%s" $acctID $shopID $listing.ListingID)
|
||||
"_" "on click event.preventDefault() then event.stopPropagation()"
|
||||
}}
|
||||
</li>
|
||||
{{- end }}
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user