mock sync group editing: edit, save, and delete listings

This commit is contained in:
2026-02-25 22:41:36 -07:00
parent ae031411b8
commit 85817a4adb
12 changed files with 1533 additions and 239 deletions
@@ -29,13 +29,12 @@
on setListing(listing)
call setFilledOut(true)
on resetListing
call setFilledOut(false)
"
>
<td class="text-nowrap">
{{/* TODO: filter out shops that are already selected */}}
{{/* filter out shops that are already selected */}}
{{- $shops := .Accounts.GetMockShops $acctID -}}
<select
class="min-w-fit cursor-pointer"
@@ -1,211 +0,0 @@
{{/* .SyncGroup: optional for performance */}}
{{- $syncGroupID := .PathParams.syncGroupID }}
{{- $acctID := .PathParams.acctID }}
{{- $isBeingEditing := .Accounts.MockSyncGroupIsBeingEdited $acctID $syncGroupID }}
{{- $open := or $isBeingEditing (and .Request (eq (.Request.URL.Query.Get "open") "true")) }}
{{- $grp := .SyncGroup }}
{{- if not $grp }}
{{- $grp = .Accounts.GetMockSyncGroup $acctID $syncGroupID }}
{{- end }}
{{- $id := (printf "sync-group-%d" $syncGroupID) }}
<li
id="{{$id}}"
class="mx-[1em]"
hx-get="{{ printf "/ui/accounts/%d/inventory/sync-groups/mock/%d/list-item" $acctID $syncGroupID }}"
hx-trigger="{{ printf "sse:accounts_%d_inventory_sync-groups_mock_%d" $acctID $syncGroupID }}"
hx-swap="morph:outerHTML"
hx-select="#{{$id}}"
hx-vals="js:{open: this.getElementsByTagName('details')[0].open}"
>
{{- define "sync-group-accordion-header" }}
<h3 class="text-center">
{{ .Group.Name }}
</h3>
{{- end }}
{{- define "sync-group-accordion-editing-header" }}
<div class="flex flex-col items-center">
<h3 class="text-center">
{{ .Group.Name }}
</h3>
<h5>
Editing
</h5>
</div>
{{- end }}
{{- define "sync-group-accordion-static-body" }}
{{- $acctID := .Identity.Account.AccountID }}
{{- $syncGroupID := .Group.SyncGroupID }}
<table id="sync-group-data-{{$syncGroupID}}">
<thead>
<tr>
<th>
Shop
</th>
<th>
Platform
</th>
<th>
Name
</th>
<th>
SKU
</th>
<th>
Description
</th>
<th>
Count
</th>
</tr>
</thead>
<tbody>
{{- $dot := . }}
{{- range $listing := .Group.Listings }}
<tr>
{{- $val := $dot.Accounts.GetMockListing $acctID $listing.Platform $listing.ShopID $listing.ListingID }}
<td class="text-nowrap">
{{ $val.ShopName }}
</td>
<td>
{{ $val.Platform }}
</td>
<td class="text-nowrap">
{{ $val.Name }}
</td>
<td class="text-nowrap">
{{ $val.SKU }}
</td>
<td class="text-nowrap">
{{ $val.Description }}
</td>
<td>
{{ $val.Count }}
</td>
</tr>
{{- end }}
</tbody>
</table>
<div
id="sync-group-{{$syncGroupID}}-buttons"
class="flex justify-center flex-grow-[1] gap-[0.5em]"
>
{{- component "button"
"Class" "mt-[1em]"
"Text" "Edit"
"HXPut" (printf "/api/accounts/%d/inventory/sync-groups/mock/editing" $acctID)
"HXVals" (printf `js:{"syncGroupID":%d}` $syncGroupID)
"HXSwap" "none"
}}
{{- component "button"
"Class" "mt-[1em]"
"Text" "Delete"
"HXDelete" (printf "/api/accounts/%d/inventory/sync-groups/mock/%d" $acctID $syncGroupID)
"HXSwap" "none"
}}
</div>
{{- end }}
{{- define "sync-group-accordion-form-body" }}
{{- $acctID := .Identity.Account.AccountID }}
{{- $syncGroupID := .Group.SyncGroupID }}
<form>
<table id="sync-group-{{$syncGroupID}}-form">
<thead>
<tr>
<th>
Shop
</th>
<th>
Platform
</th>
<th>
Name
</th>
<th>
SKU
</th>
<th>
Description
</th>
<th>
Count
</th>
</tr>
</thead>
<tbody>
{{- $dot := . }}
{{- range $listing := .Group.Listings }}
<tr>
{{- $val := $dot.Accounts.GetMockListing $acctID $listing.Platform $listing.ShopID $listing.ListingID }}
<td>
{{ $val.ShopName }}
</td>
<td>
{{ $val.Platform }}
</td>
<td>
{{ $val.Name }}
</td>
<td>
{{ $val.SKU }}
</td>
<td>
{{ $val.Description }}
</td>
<td>
{{ $val.Count }}
</td>
</tr>
{{- end }}
</tbody>
</table>
<div
id="sync-group-{{$syncGroupID}}-editing-buttons"
class="flex justify-center flex-grow-[1] gap-[0.5em]"
>
{{/* TODO: implement saving */}}
{{- component "button"
"Class" "mt-[1em]"
"Text" "Save"
"HXSwap" "none"
}}
{{- component "button"
"Class" "mt-[1em]"
"Text" "Cancel"
"HXDelete" (printf "/api/accounts/%d/inventory/sync-groups/mock/editing" $acctID)
"HXSwap" "none"
}}
</div>
</form>
{{- end }}
{{- $accordionHeader := "sync-group-accordion-header" }}
{{- $accordionBody := "sync-group-accordion-static-body" }}
{{- $summaryClass := "" }}
{{- if $isBeingEditing }}
{{- $accordionBody = "sync-group-accordion-form-body" }}
{{- $accordionHeader = "sync-group-accordion-editing-header" }}
{{- $summaryClass = "bg-accent-secondary" }}
{{- end }}
{{ component "accordion"
"Name" "sync-group-page"
"Open" $open
"GroupName" "sync-group"
"Group" $grp
"Smooth" false
"SummaryClass" $summaryClass
"#accordion-header" $accordionHeader
"#accordion-body" $accordionBody
}}
</li>
@@ -0,0 +1,117 @@
{{- $acctID := .Identity.Account.AccountID }}
{{- $syncGroupID := .PathParams.syncGroupID }}
<form class="w-full">
<table
id="sync-group-{{$syncGroupID}}-form"
class="w-full overflow-x-auto"
hx-get="/ui/accounts/{{$acctID}}/inventory/sync-groups/mock/{{$syncGroupID}}/list-item/edit-form"
hx-trigger="sse:{{ printf "accounts_%d_inventory_sync-groups_mock_%d_editing" $acctID $syncGroupID }},sse:{{ printf "accounts_%d_inventory_sync-groups_mock_editing" $acctID }}"
hx-select="#sync-group-{{$syncGroupID}}-form"
hx-swap="morph"
>
<thead>
<tr>
<th>
Shop
</th>
<th>
Platform
</th>
<th>
Listing
</th>
<th>
SKU
</th>
<th>
Description
</th>
<th>
Count
</th>
<th>
</th>
</tr>
</thead>
<tbody>
{{- $dot := . }}
{{- $editListings := .Accounts.GetMockSyncGroupEditingListings $acctID }}
{{- range $listing := $editListings }}
{{- component (printf "accounts/%d/inventory/sync-groups/mock/%d/list-item/edit-form/edit-form-listing/%d" $acctID $syncGroupID $listing.OrderIndex)
"Listing" $listing
"Listings" $editListings
}}
{{- end }}
</tbody>
{{- if gt (len $editListings) 5 }}
<tfoot class="sticky bottom-0 outline-1 outline-(--table-tfoot)">
<tr>
<th>
Shop
</th>
<th>
Platform
</th>
<th>
Listing
</th>
<th>
SKU
</th>
<th>
Description
</th>
<th>
Count
</th>
<th>
</th>
</tr>
</tfoot>
{{- end }}
</table>
<div
id="sync-group-{{$syncGroupID}}-editing-buttons"
class="flex justify-center flex-grow-[1] gap-[0.5em]"
>
{{/* TODO: implement */}}
{{- component "button"
"ID" "add-mock-sync-group-listing-button"
"Class" "mt-[1em]"
"Text" "Add Listing"
"HXPost" (printf "/api/accounts/%d/inventory/sync-groups/mock/editing/listings" $acctID)
"HXSwap" "none"
}}
{{- component "button"
"ID" "save-mock-sync-group-button"
"Class" "mt-[1em]"
"Text" "Save"
"HXPost" (printf "/api/accounts/%d/inventory/sync-groups/mock/editing" $acctID)
"HXSwap" "none"
}}
{{- component "button"
"Class" "mt-[1em]"
"Text" "Cancel"
"HXDelete" (printf "/api/accounts/%d/inventory/sync-groups/mock/editing" $acctID)
"HXSwap" "none"
}}
{{/*
<div
hidden
hx-get="{{ printf "/ui/accounts/%d/inventory/sync-groups/mock/draft/table/save-sync-group-button" $acctID }}"
hx-trigger="sse:{{ printf "accounts_%d_inventory_sync-groups_mock_%d_editing_listings" $acctID $syncGroupID }}"
hx-target="#save-mock-sync-group-button"
hx-swap="outerHTML"
>
</div>
*/}}
</div>
</form>
@@ -0,0 +1,140 @@
{{/* .Listing */}}
{{/* optional props: .Listings = .Accounts.GetMockSyncGroupListingDrafts */}}
{{- $acctID := .PathParams.acctID }}
{{- $syncGroupID := .PathParams.syncGroupID }}
{{- $orderIndex := .PathParams.orderIndex }}
{{- $entry := .Listing }}
{{- if not $entry }}
{{- $entry = .Accounts.GetMockSyncGroupEditingListing $acctID $syncGroupID $orderIndex }}
{{- end }}
{{- $selectedShopPlatform := $entry.Platform }}
{{- $selectedShopID := $entry.ShopID }}
{{- $selectedListingID := $entry.ListingID }}
{{- $listings := .Listings }}
{{- if not $listings }}
{{- $listings := .Accounts.GetMockSyncGroupEditingListings $acctID }}
{{- end }}
{{- $listing := .Listing }}
<tr id="{{$syncGroupID}}-editing-{{$orderIndex}}">
<td class="text-nowrap">
{{/* filter out shops that are already selected */}}
{{/* $listing.ShopName */}}
{{- $shops := .Accounts.GetMockShops $acctID -}}
<select
class="min-w-fit cursor-pointer"
hx-put="/api/accounts/{{$acctID}}/inventory/sync-groups/mock/{{$syncGroupID}}/editing/listings/{{$orderIndex}}/shop"
hx-vals='js:{
platform: event.target.value.replace(/-[^ ]*/, ""),
"shop-id": event.target.value.replace(/^[a-zA-Z_]*-/, "")
}'
hx-swap="none"
{{/* TODO: drop events if not used */}}
_="
on change
send resetListing() to closest <tr/>
"
>
<option disabled {{- if not $selectedShopID }} selected{{- end }}>- Shops -</option>
{{- range $shop := $shops }}
{{- $shopSelectedInOtherListing := false }}
{{- if not (eq $shop.ShopID $selectedShopID ) }}
{{- range $listing := $listings }}
{{- if eq $listing.ShopID $shop.ShopID }}
{{- $shopSelectedInOtherListing = true }}
{{- break }}
{{- end }}
{{- end }}
{{- if $shopSelectedInOtherListing }}
{{- continue }}
{{- end }}
{{- end }}
{{- $isSelectedShop := and
(eq $selectedShopPlatform $shop.Platform)
(eq $selectedShopID $shop.ShopID)
}}
<option
id="{{$shop.Platform}}-{{$shop.ShopID}}"
value="{{$shop.Platform}}-{{$shop.ShopID}}"
{{- if $isSelectedShop }} selected{{- end }}
>
{{ $shop.Name }}
</option>
{{- end }}
</select>
</td>
<td>
{{- if $entry.Platform }}{{ $entry.Platform }}{{ else }}-{{ end }}
</td>
<td>
{{/* $listing.Name */}}
{{- $selectedListing := "" }}
{{- if $selectedShopID }}
{{- $shopListings := .Accounts.GetMockListingsForShop $acctID $selectedShopPlatform $selectedShopID }}
{{- if $shopListings }}
<select
class="min-w-fit cursor-pointer"
hx-put="/api/accounts/{{$acctID}}/inventory/sync-groups/mock/{{$syncGroupID}}/editing/listings/{{$orderIndex}}/listing"
hx-vals='js:{
"listing-id": event.target.value,
}'
hx-swap="none"
_="
on input
set dataset to (my selectedOptions)[0].dataset
send setListing(listing: dataset) to the closest <tr/>
"
>
<option disabled {{if not $selectedListingID}}selected{{end}}>- Listings -</option>
{{- range $i, $shopListing := $shopListings }}
{{- if eq $selectedListingID $shopListing.ListingID }}
{{ $selectedListing = $shopListing }}
{{- end }}
<option
value="{{$shopListing.ListingID}}"
{{if eq $selectedListingID $shopListing.ListingID}}selected{{end}}
data-name="{{ $shopListing.Name }}"
data-sku="{{ $shopListing.SKU }}"
data-description="{{ $shopListing.Description }}"
data-count="{{ $shopListing.Count }}"
>
{{ $shopListing.Name }}
</option>
{{- end }}
</select>
{{- else }}
no listings found
{{- end }}
{{- else }}
-
{{- end }}
</td>
<td>
{{ $listing.SKU }}
</td>
<td>
{{ $listing.Description }}
</td>
<td>
{{ $listing.Count }}
</td>
<td>
{{ component "button"
"HXDelete" (printf "/api/accounts/%d/inventory/sync-groups/mock/%d/editing/listings/%d" $acctID $syncGroupID $orderIndex)
"HXTarget" "#accounts-acct-id-inventory-sync-groups-mock-draft-table"
"HXSwap" "none"
"Text" "Remove"
}}
</td>
</tr>
@@ -0,0 +1,76 @@
{{/* .SyncGroup: optional for performance */}}
{{- $syncGroupID := .PathParams.syncGroupID }}
{{- $acctID := .PathParams.acctID }}
{{- $isBeingEditing := .Accounts.MockSyncGroupIsBeingEdited $acctID $syncGroupID }}
{{- $open := or $isBeingEditing (and .Request (eq (.Request.URL.Query.Get "open") "true")) }}
{{- $grp := .SyncGroup }}
{{- if not $grp }}
{{- $grp = .Accounts.GetMockSyncGroup $acctID $syncGroupID }}
{{- end }}
{{- $id := (printf "sync-group-%d" $syncGroupID) }}
<li
id="{{$id}}"
class="mx-[1em]"
hx-get="{{ printf "/ui/accounts/%d/inventory/sync-groups/mock/%d/list-item" $acctID $syncGroupID }}"
hx-trigger="{{ printf "sse:accounts_%d_inventory_sync-groups_mock_%d" $acctID $syncGroupID }}"
hx-swap="morph:outerHTML"
hx-select="#{{$id}}"
hx-vals="js:{open: this.getElementsByTagName('details')[0].open}"
>
{{- define "sync-group-accordion-header" }}
<h3 class="text-center">
{{ .Group.Name }}
</h3>
{{- end }}
{{- define "sync-group-accordion-editing-header" }}
<div class="flex flex-col items-center">
<h3 class="text-center">
{{ .Group.Name }}
</h3>
<h5>
Editing
</h5>
</div>
{{- end }}
{{- define "sync-group-accordion-static-table" }}
{{- component (
printf "accounts/%d/inventory/sync-groups/mock/%d/list-item/static-table"
.Identity.Account.AccountID
.Group.SyncGroupID
)}}
{{- end }}
{{- define "sync-group-accordion-edit-form" }}
{{- component (
printf "accounts/%d/inventory/sync-groups/mock/%d/list-item/edit-form"
.Identity.Account.AccountID
.Group.SyncGroupID
)}}
{{- end }}
{{- $accordionHeader := "sync-group-accordion-header" }}
{{- $accordionBody := "sync-group-accordion-static-table" }}
{{- $summaryClass := "" }}
{{- if $isBeingEditing }}
{{- $accordionBody = "sync-group-accordion-edit-form" }}
{{- $accordionHeader = "sync-group-accordion-editing-header" }}
{{- $summaryClass = "bg-accent-secondary" }}
{{- end }}
{{ component "accordion"
"Name" "sync-group-page"
"Open" $open
"GroupName" "sync-group"
"Group" $grp
"Smooth" false
"SummaryClass" $summaryClass
"#accordion-header" $accordionHeader
"#accordion-body" $accordionBody
}}
</li>
@@ -0,0 +1,74 @@
{{/* .Group */}}
{{- $acctID := .Identity.Account.AccountID }}
{{- $syncGroupID := .PathParams.syncGroupID -}}
<table id="sync-group-data-{{$syncGroupID}}">
<thead>
<tr>
<th>
Shop
</th>
<th>
Platform
</th>
<th>
Name
</th>
<th>
SKU
</th>
<th>
Description
</th>
<th>
Count
</th>
</tr>
</thead>
<tbody>
{{- $dot := . }}
{{- range $listing := .Group.Listings }}
<tr>
{{- $val := $dot.Accounts.GetMockListing $acctID $listing.Platform $listing.ShopID $listing.ListingID }}
<td class="text-nowrap">
{{ $val.ShopName }}
</td>
<td>
{{ $val.Platform }}
</td>
<td class="text-nowrap">
{{ $val.Name }}
</td>
<td class="text-nowrap">
{{ $val.SKU }}
</td>
<td class="text-nowrap">
{{ $val.Description }}
</td>
<td>
{{ $val.Count }}
</td>
</tr>
{{- end }}
</tbody>
</table>
<div
id="sync-group-{{$syncGroupID}}-buttons"
class="flex justify-center flex-grow-[1] gap-[0.5em]"
>
{{- component "button"
"Class" "mt-[1em]"
"Text" "Edit"
"HXPut" (printf "/api/accounts/%d/inventory/sync-groups/mock/editing" $acctID)
"HXVals" (printf `js:{"syncGroupID":%d}` $syncGroupID)
"HXSwap" "none"
}}
{{- component "button"
"Class" "mt-[1em]"
"Text" "Delete"
"HXDelete" (printf "/api/accounts/%d/inventory/sync-groups/mock/%d" $acctID $syncGroupID)
"HXSwap" "none"
}}
</div>