mock shop sync group listing draft page

This commit is contained in:
2026-02-08 12:31:10 -07:00
parent e3b2dd3377
commit b155280081
19 changed files with 1519 additions and 166 deletions
@@ -0,0 +1,20 @@
BEGIN;
DROP TABLE mock.shop_amazon_sync_group_listing_drafts;
DROP TABLE mock.shop_big_cartel_sync_group_listing_drafts;
DROP TABLE mock.shop_ebay_sync_group_listing_drafts;
DROP TABLE mock.shop_ecwid_sync_group_listing_drafts;
DROP TABLE mock.shop_etsy_sync_group_listing_drafts;
DROP TABLE mock.shop_shopify_sync_group_listing_drafts;
DROP TABLE mock.shop_square_online_sync_group_listing_drafts;
DROP TABLE mock.shop_squarespace_sync_group_listing_drafts;
DROP TABLE mock.shop_tiktok_sync_group_listing_drafts;
DROP TABLE mock.shop_walmart_marketplace_sync_group_listing_drafts;
DROP TABLE mock.shop_wix_sync_group_listing_drafts;
DROP TABLE mock.shop_woo_commerce_sync_group_listing_drafts;
DROP TABLE mock.shop_zoho_sync_group_listing_drafts;
DROP TABLE mock.sync_group_listing_draft_order_indexes;
COMMIT;
@@ -0,0 +1,155 @@
BEGIN;
CREATE TABLE mock.sync_group_listing_draft_order_indexes (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL CHECK (order_index >= 0),
PRIMARY KEY (account_id, order_index)
);
CREATE TABLE mock.shop_amazon_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_big_cartel_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_ebay_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_ecwid_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_etsy_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_shopify_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_square_online_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_squarespace_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_tiktok_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_walmart_marketplace_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_wix_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_woo_commerce_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
CREATE TABLE mock.shop_zoho_sync_group_listing_drafts (
account_id INTEGER NOT NULL REFERENCES mock.accounts,
order_index INTEGER NOT NULL,
shop_id TEXT NOT NULL,
listing_id TEXT,
PRIMARY KEY (account_id, order_index),
UNIQUE (account_id, shop_id),
FOREIGN KEY (account_id, order_index) REFERENCES mock.sync_group_listing_draft_order_indexes ON DELETE CASCADE
);
COMMIT;
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 321 KiB

+207 -30
View File
@@ -18,7 +18,7 @@ entity "**shop_amazon**" {
}
entity "**shop_amazon_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -28,6 +28,15 @@ entity "**shop_amazon_listings**" {
*""description"": //text //
}
entity "**shop_amazon_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK][FK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_amazon_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
@@ -46,7 +55,7 @@ entity "**shop_big_cartel**" {
}
entity "**shop_big_cartel_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -56,6 +65,15 @@ entity "**shop_big_cartel_listings**" {
*""description"": //text //
}
entity "**shop_big_cartel_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK][FK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_big_cartel_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
@@ -74,7 +92,7 @@ entity "**shop_ebay**" {
}
entity "**shop_ebay_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -84,6 +102,15 @@ entity "**shop_ebay_listings**" {
*""description"": //text //
}
entity "**shop_ebay_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_ebay_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
@@ -102,7 +129,7 @@ entity "**shop_ecwid**" {
}
entity "**shop_ecwid_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -112,6 +139,15 @@ entity "**shop_ecwid_listings**" {
*""description"": //text //
}
entity "**shop_ecwid_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK][FK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_ecwid_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
@@ -130,7 +166,7 @@ entity "**shop_etsy**" {
}
entity "**shop_etsy_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -140,13 +176,22 @@ entity "**shop_etsy_listings**" {
*""description"": //text //
}
entity "**shop_etsy_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_etsy_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
*""sync_group_id"": //integer [FK]//
*""shop_id"": //text [FK]//
*""listing_id"": //text //
*""order_index"": //integer //
*""order_index"": //integer [FK]//
}
entity "**shop_shopify**" {
@@ -158,7 +203,7 @@ entity "**shop_shopify**" {
}
entity "**shop_shopify_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -168,13 +213,22 @@ entity "**shop_shopify_listings**" {
*""description"": //text //
}
entity "**shop_shopify_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK][FK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_shopify_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
*""sync_group_id"": //integer [FK]//
*""shop_id"": //text [FK]//
*""listing_id"": //text //
*""order_index"": //integer //
*""listing_id"": //text [FK]//
*""order_index"": //integer [FK]//
}
entity "**shop_square_online**" {
@@ -186,7 +240,7 @@ entity "**shop_square_online**" {
}
entity "**shop_square_online_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -196,6 +250,15 @@ entity "**shop_square_online_listings**" {
*""description"": //text //
}
entity "**shop_square_online_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK][FK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_square_online_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
@@ -214,7 +277,7 @@ entity "**shop_squarespace**" {
}
entity "**shop_squarespace_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -224,6 +287,15 @@ entity "**shop_squarespace_listings**" {
*""description"": //text //
}
entity "**shop_squarespace_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK][FK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_squarespace_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
@@ -242,7 +314,7 @@ entity "**shop_tiktok**" {
}
entity "**shop_tiktok_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -252,6 +324,15 @@ entity "**shop_tiktok_listings**" {
*""description"": //text //
}
entity "**shop_tiktok_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK][FK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_tiktok_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
@@ -270,7 +351,7 @@ entity "**shop_walmart_marketplace**" {
}
entity "**shop_walmart_marketplace_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -280,12 +361,21 @@ entity "**shop_walmart_marketplace_listings**" {
*""description"": //text //
}
entity "**shop_walmart_marketplace_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK][FK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_walmart_marketplace_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
*""sync_group_id"": //integer [FK]//
*""shop_id"": //text [FK]//
*""listing_id"": //text //
*""listing_id"": //text [FK]//
*""order_index"": //integer //
}
@@ -298,7 +388,7 @@ entity "**shop_wix**" {
}
entity "**shop_wix_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -308,6 +398,15 @@ entity "**shop_wix_listings**" {
*""description"": //text //
}
entity "**shop_wix_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_wix_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
@@ -326,7 +425,7 @@ entity "**shop_woo_commerce**" {
}
entity "**shop_woo_commerce_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -336,6 +435,15 @@ entity "**shop_woo_commerce_listings**" {
*""description"": //text //
}
entity "**shop_woo_commerce_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK][FK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_woo_commerce_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
@@ -354,7 +462,7 @@ entity "**shop_zoho**" {
}
entity "**shop_zoho_listings**" {
+ ""shop_id"": //text [PK]//
+ ""shop_id"": //text [PK][FK]//
+ ""listing_id"": //text [PK]//
--
*""account_id"": //integer [FK]//
@@ -364,6 +472,15 @@ entity "**shop_zoho_listings**" {
*""description"": //text //
}
entity "**shop_zoho_sync_group_listing_drafts**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK]//
--
*""account_id"": //integer //
*""shop_id"": //text //
""listing_id"": //text //
}
entity "**shop_zoho_sync_group_listings**" {
--
*""account_id"": //integer [FK]//
@@ -373,6 +490,12 @@ entity "**shop_zoho_sync_group_listings**" {
*""order_index"": //integer //
}
entity "**sync_group_listing_draft_order_indexes**" {
+ ""account_id"": //integer [PK][FK]//
+ ""order_index"": //integer [PK]//
--
}
entity "**sync_group_listing_order_indexes**" {
--
*""sync_group_id"": //integer [FK]//
@@ -396,7 +519,11 @@ entity "**sync_groups**" {
"**shop_amazon_listings**" }-- "**accounts**"
"**shop_amazon_listings**" }-- "**shop_amazon**"
"**shop_amazon_listings**" ||-|| "**shop_amazon**"
"**shop_amazon_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_amazon_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_amazon_sync_group_listings**" }-- "**accounts**"
@@ -416,7 +543,11 @@ entity "**sync_groups**" {
"**shop_big_cartel_listings**" }-- "**accounts**"
"**shop_big_cartel_listings**" }-- "**shop_big_cartel**"
"**shop_big_cartel_listings**" ||-|| "**shop_big_cartel**"
"**shop_big_cartel_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_big_cartel_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_big_cartel_sync_group_listings**" }-- "**sync_group_listing_order_indexes**"
@@ -436,7 +567,11 @@ entity "**sync_groups**" {
"**shop_ebay_listings**" }-- "**accounts**"
"**shop_ebay_listings**" }-- "**shop_ebay**"
"**shop_ebay_listings**" ||-|| "**shop_ebay**"
"**shop_ebay_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_ebay_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_ebay_sync_group_listings**" }-- "**accounts**"
@@ -456,7 +591,11 @@ entity "**sync_groups**" {
"**shop_ecwid_listings**" }-- "**accounts**"
"**shop_ecwid_listings**" }-- "**shop_ecwid**"
"**shop_ecwid_listings**" ||-|| "**shop_ecwid**"
"**shop_ecwid_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_ecwid_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_ecwid_sync_group_listings**" }-- "**accounts**"
@@ -476,7 +615,11 @@ entity "**sync_groups**" {
"**shop_etsy_listings**" }-- "**accounts**"
"**shop_etsy_listings**" }-- "**shop_etsy**"
"**shop_etsy_listings**" ||-|| "**shop_etsy**"
"**shop_etsy_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_etsy_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_etsy_sync_group_listings**" }-- "**accounts**"
@@ -496,7 +639,11 @@ entity "**sync_groups**" {
"**shop_shopify_listings**" }-- "**accounts**"
"**shop_shopify_listings**" }-- "**shop_shopify**"
"**shop_shopify_listings**" ||-|| "**shop_shopify**"
"**shop_shopify_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_shopify_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_shopify_sync_group_listings**" }-- "**accounts**"
@@ -516,7 +663,11 @@ entity "**sync_groups**" {
"**shop_square_online_listings**" }-- "**accounts**"
"**shop_square_online_listings**" }-- "**shop_square_online**"
"**shop_square_online_listings**" ||-|| "**shop_square_online**"
"**shop_square_online_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_square_online_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_square_online_sync_group_listings**" }-- "**sync_group_listing_order_indexes**"
@@ -536,7 +687,11 @@ entity "**sync_groups**" {
"**shop_squarespace_listings**" }-- "**accounts**"
"**shop_squarespace_listings**" }-- "**shop_squarespace**"
"**shop_squarespace_listings**" ||-|| "**shop_squarespace**"
"**shop_squarespace_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_squarespace_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_squarespace_sync_group_listings**" }-- "**sync_group_listing_order_indexes**"
@@ -556,7 +711,11 @@ entity "**sync_groups**" {
"**shop_tiktok_listings**" }-- "**accounts**"
"**shop_tiktok_listings**" }-- "**shop_tiktok**"
"**shop_tiktok_listings**" ||-|| "**shop_tiktok**"
"**shop_tiktok_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_tiktok_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_tiktok_sync_group_listings**" }-- "**accounts**"
@@ -576,7 +735,11 @@ entity "**sync_groups**" {
"**shop_walmart_marketplace_listings**" }-- "**accounts**"
"**shop_walmart_marketplace_listings**" }-- "**shop_walmart_marketplace**"
"**shop_walmart_marketplace_listings**" ||-|| "**shop_walmart_marketplace**"
"**shop_walmart_marketplace_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_walmart_marketplace_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_walmart_marketplace_sync_group_listings**" }-- "**sync_group_listing_order_indexes**"
@@ -596,7 +759,11 @@ entity "**sync_groups**" {
"**shop_wix_listings**" }-- "**accounts**"
"**shop_wix_listings**" }-- "**shop_wix**"
"**shop_wix_listings**" ||-|| "**shop_wix**"
"**shop_wix_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_wix_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_wix_sync_group_listings**" }-- "**accounts**"
@@ -616,7 +783,11 @@ entity "**sync_groups**" {
"**shop_woo_commerce_listings**" }-- "**accounts**"
"**shop_woo_commerce_listings**" }-- "**shop_woo_commerce**"
"**shop_woo_commerce_listings**" ||-|| "**shop_woo_commerce**"
"**shop_woo_commerce_sync_group_listing_drafts**" ||-|| "**sync_group_listing_draft_order_indexes**"
"**shop_woo_commerce_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_woo_commerce_sync_group_listings**" }-- "**sync_group_listing_order_indexes**"
@@ -636,7 +807,11 @@ entity "**sync_groups**" {
"**shop_zoho_listings**" }-- "**accounts**"
"**shop_zoho_listings**" }-- "**shop_zoho**"
"**shop_zoho_listings**" ||-|| "**shop_zoho**"
"**shop_zoho_sync_group_listing_drafts**" }-- "**accounts**"
"**shop_zoho_sync_group_listing_drafts**" }-- "**sync_group_listing_draft_order_indexes**"
"**shop_zoho_sync_group_listings**" }-- "**accounts**"
@@ -648,6 +823,8 @@ entity "**sync_groups**" {
"**shop_zoho_sync_group_listings**" }-- "**sync_group_listing_order_indexes**"
"**sync_group_listing_draft_order_indexes**" }-- "**accounts**"
"**sync_group_listing_order_indexes**" }-- "**sync_groups**"
"**sync_groups**" }-- "**accounts**"
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 59 KiB

+9 -9
View File
@@ -38,10 +38,10 @@ entity "**etsy_oauth_requests**" {
entity "**etsy_store_events**" {
+ ""store_id"": //text [PK]//
+ ""event_timestamp"": //timestamp with time zone [PK]//
+ ""event_timestamp"": //timestamp with time zone [PK][FK]//
+ ""event_id"": //text [PK]//
--
*""platform"": //text [FK]//
*""platform"": //text //
}
entity "**etsy_users**" {
@@ -125,18 +125,18 @@ entity "**sync_groups**" {
entity "**tiktok_store_events**" {
+ ""store_id"": //text [PK]//
+ ""event_timestamp"": //timestamp with time zone [PK]//
+ ""event_timestamp"": //timestamp with time zone [PK][FK]//
+ ""event_id"": //text [PK]//
--
*""platform"": //text [FK]//
*""platform"": //text //
}
entity "**wix_store_events**" {
+ ""store_id"": //text [PK]//
+ ""event_timestamp"": //timestamp with time zone [PK]//
+ ""event_timestamp"": //timestamp with time zone [PK][FK]//
+ ""event_id"": //text [PK]//
--
*""platform"": //text [FK]//
*""platform"": //text //
}
"**accounts**" }-- "**oauth_users**"
@@ -145,7 +145,7 @@ entity "**wix_store_events**" {
"**etsy_oauth_requests**" }-- "**accounts**"
"**etsy_store_events**" }-- "**raw_store_events**"
"**etsy_store_events**" ||-|| "**raw_store_events**"
"**etsy_users**" }-- "**accounts**"
@@ -157,7 +157,7 @@ entity "**wix_store_events**" {
"**sync_groups**" }-- "**accounts**"
"**tiktok_store_events**" }-- "**raw_store_events**"
"**tiktok_store_events**" ||-|| "**raw_store_events**"
"**wix_store_events**" }-- "**raw_store_events**"
"**wix_store_events**" ||-|| "**raw_store_events**"
@enduml
+117
View File
@@ -277,6 +277,63 @@ func (db *Store) GetShops(ctx context.Context, acctID int64) ([]AccountShop, err
return shops, nil
}
func (db *Store) GetMockShops(ctx context.Context, acctID int64) ([]AccountShop, error) {
infos := getAllMockShopSchemaInfos()
lists := make([][]AccountShop, len(infos))
numShops := 0
for i, in := range infos {
rows, err := db.db.Query(
ctx,
fmt.Sprintf(
`
SELECT
shop_id,
name
FROM
%s
WHERE
account_id = @account_id
`,
in.shopTable,
),
pgx.NamedArgs{
"account_id": acctID,
},
)
if err != nil {
return nil, fmt.Errorf("failed to perform query: %w", err)
}
vs, err := pgx.CollectRows(rows, pgx.RowToStructByNameLax[struct {
Shop_id string
Name string
}])
if err != nil {
return nil, fmt.Errorf("failed to scan rows: %w", err)
}
list := make([]AccountShop, len(vs))
for i, v := range vs {
list[i] = AccountShop{
AccountShopIDs: NewAccountIDs(acctID).
ShopID(in.platform, v.Shop_id),
Name: v.Name,
}
}
lists[i] = list
numShops += len(list)
}
shops := make([]AccountShop, 0, numShops)
for _, list := range lists {
shops = append(shops, list...)
}
return shops, nil
}
func (db *Store) GetListingsForShop(ctx context.Context, acctID int64, platform Platform, shopID string) ([]Listing, error) {
var vs []Listing
for _, v := range getDevListings(acctID) {
@@ -292,6 +349,66 @@ func (db *Store) GetListingsForShop(ctx context.Context, acctID int64, platform
return vs, nil
}
func (db *Store) GetMockListingsForShop(ctx context.Context, acctID int64, platform Platform, shopID string) ([]Listing, error) {
in, ok := getMockShopSchemaInfo(platform)
if !ok {
return nil, consts.ErrNotFound
}
rows, err := db.db.Query(
ctx,
fmt.Sprintf(
`
SELECT
listing_id,
sku,
name,
description,
"count"
FROM
%s
WHERE
account_id = @account_id
AND shop_id = @shop_id
`,
in.listingsTable,
),
pgx.NamedArgs{
"account_id": acctID,
"shop_id": shopID,
},
)
if err != nil {
return nil, fmt.Errorf("failed to perform query: %w", err)
}
vs, err := pgx.CollectRows(rows, pgx.RowToStructByNameLax[struct {
Listing_id string
SKU string
Name string
Description string
Count int64
}])
if err != nil {
return nil, fmt.Errorf("failed to scan rows: %w", err)
}
listings := make([]Listing, len(vs))
for i, v := range vs {
listings[i] = Listing{
AccountShopListingIDs: NewAccountIDs(acctID).
ShopID(in.platform, shopID).
ListingID(v.Listing_id),
SKU: v.SKU,
Name: v.Name,
Description: v.Description,
Count: v.Count,
}
}
return listings, nil
}
// additional context
func (db *Store) GetAccountPointerByUserID(ctx context.Context, userID string) (*Account, error) {
+112 -21
View File
@@ -412,28 +412,19 @@ func (db *Store) ListMockListingsForShop(ctx context.Context, acctID int64, plat
ctx,
fmt.Sprintf(
`
WITH shop_exists(shop_exists) AS (
SELECT
true
true AS shop_exists,
l.listing_id,
l.sku,
l.name,
l.description,
l."count"
FROM
%s
WHERE
account_id = @account_id
AND shop_id = @shop_id
)
SELECT
COALESCE(shop_exists, false) AS shop_exists,
listing_id,
sku,
name,
description,
"count"
FROM
shop_exists
%s AS s
LEFT JOIN
%s
ON
TRUE
%s AS l
USING
(account_id, shop_id)
WHERE
(account_id IS NULL OR account_id = @account_id)
AND (shop_id IS NULL OR shop_id = @shop_id)
@@ -466,11 +457,11 @@ func (db *Store) ListMockListingsForShop(ctx context.Context, acctID int64, plat
// check if the shop exists, and confirm there were actually listings (LEFT JOIN)
if len(vs) == 0 || !vs[0].Shop_exists {
fmt.Println("TEST")
if len(vs) == 0 {
return nil, fmt.Errorf("%w: shop not found", consts.ErrNotFound)
}
if !vs[0].SKU.Valid {
// shop exists, but there are not listings
return nil, nil
}
@@ -530,6 +521,106 @@ func getMockShopTableName(platform Platform) (string, error) {
}
}
type mockShopSchemaInfo struct {
platform Platform
shopTable string
listingsTable string
syncGroupListingDraftsTable string
}
func getMockShopSchemaInfo(platform Platform) (mockShopSchemaInfo, bool) {
for _, in := range getAllMockShopSchemaInfos() {
if in.platform == platform {
return in, true
}
}
return mockShopSchemaInfo{}, false
}
func getAllMockShopSchemaInfos() []mockShopSchemaInfo {
return []mockShopSchemaInfo{
{
platform: Amazon,
shopTable: "mock.shop_amazon",
listingsTable: "mock.shop_amazon_listings",
syncGroupListingDraftsTable: "mock.shop_amazon_sync_group_listing_drafts",
},
{
platform: BigCartel,
shopTable: "mock.shop_big_cartel",
listingsTable: "mock.shop_big_cartel_listings",
syncGroupListingDraftsTable: "mock.shop_big_cartel_sync_group_listing_drafts",
},
{
platform: Ebay,
shopTable: "mock.shop_ebay",
listingsTable: "mock.shop_ebay_listings",
syncGroupListingDraftsTable: "mock.shop_ebay_sync_group_listing_drafts",
},
{
platform: Ecwid,
shopTable: "mock.shop_ecwid",
listingsTable: "mock.shop_ecwid_listings",
syncGroupListingDraftsTable: "mock.shop_ecwid_sync_group_listing_drafts",
},
{
platform: Etsy,
shopTable: "mock.shop_etsy",
listingsTable: "mock.shop_etsy_listings",
syncGroupListingDraftsTable: "mock.shop_etsy_sync_group_listing_drafts",
},
{
platform: Shopify,
shopTable: "mock.shop_shopify",
listingsTable: "mock.shop_shopify_listings",
syncGroupListingDraftsTable: "mock.shop_shopify_sync_group_listing_drafts",
},
{
platform: SquareOnline,
shopTable: "mock.shop_square_online",
listingsTable: "mock.shop_square_online_listings",
syncGroupListingDraftsTable: "mock.shop_square_online_sync_group_listing_drafts",
},
{
platform: Squarespace,
shopTable: "mock.shop_squarespace",
listingsTable: "mock.shop_squarespace_listings",
syncGroupListingDraftsTable: "mock.shop_squarespace_sync_group_listing_drafts",
},
{
platform: Tiktok,
shopTable: "mock.shop_tiktok",
listingsTable: "mock.shop_tiktok_listings",
syncGroupListingDraftsTable: "mock.shop_tiktok_sync_group_listing_drafts",
},
{
platform: WalmartMarketplace,
shopTable: "mock.shop_walmart_marketplace",
listingsTable: "mock.shop_walmart_marketplace_listings",
syncGroupListingDraftsTable: "mock.shop_walmart_marketplace_sync_group_listing_drafts",
},
{
platform: Wix,
shopTable: "mock.shop_wix",
listingsTable: "mock.shop_wix_listings",
syncGroupListingDraftsTable: "mock.shop_wix_sync_group_listing_drafts",
},
{
platform: WooCommerce,
shopTable: "mock.shop_woo_commerce",
listingsTable: "mock.shop_woo_commerce_listings",
syncGroupListingDraftsTable: "mock.shop_woo_commerce_sync_group_listing_drafts",
},
{
platform: Zoho,
shopTable: "mock.shop_zoho",
listingsTable: "mock.shop_zoho_listings",
syncGroupListingDraftsTable: "mock.shop_zoho_sync_group_listing_drafts",
},
}
}
func getMockShopAndListingsTableNames(platform Platform) (shop string, listing string, err error) {
shop, err = getMockShopTableName(platform)
if err != nil {
@@ -44,10 +44,18 @@ func (v_ctx *StoreWithContext) GetShops(acctID int64) ([]AccountShop, error) {
return v_ctx.Store.GetShops(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) GetMockShops(acctID int64) ([]AccountShop, error) {
return v_ctx.Store.GetMockShops(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) GetListingsForShop(acctID int64, platform Platform, shopID string) ([]Listing, error) {
return v_ctx.Store.GetListingsForShop(v_ctx.ctx, acctID, platform, shopID)
}
func (v_ctx *StoreWithContext) GetMockListingsForShop(acctID int64, platform Platform, shopID string) ([]Listing, error) {
return v_ctx.Store.GetMockListingsForShop(v_ctx.ctx, acctID, platform, shopID)
}
func (v_ctx *StoreWithContext) GetAccountPointerByUserID(userID string) (*Account, error) {
return v_ctx.Store.GetAccountPointerByUserID(v_ctx.ctx, userID)
}
@@ -96,26 +104,50 @@ func (v_ctx *StoreWithContext) CreateSyncGroupListingDraft(acctID int64) (int, e
return v_ctx.Store.CreateSyncGroupListingDraft(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) CreateMockSyncGroupListingDraft(acctID int64) (int, error) {
return v_ctx.Store.CreateMockSyncGroupListingDraft(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) GetSyncGroupListingDraft(acctID int64, orderIndex int) (SyncGroupListingDraft, error) {
return v_ctx.Store.GetSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex)
}
func (v_ctx *StoreWithContext) GetMockSyncGroupListingDraft(acctID int64, orderIndex int) (SyncGroupListingDraft, error) {
return v_ctx.Store.GetMockSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex)
}
func (v_ctx *StoreWithContext) SetShopInSyncGroupListingDraft(acctID int64, orderIndex int, platform Platform, shopID string) error {
return v_ctx.Store.SetShopInSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex, platform, shopID)
}
func (v_ctx *StoreWithContext) SetShopInMockSyncGroupListingDraft(acctID int64, orderIndex int, platform Platform, shopID string) error {
return v_ctx.Store.SetShopInMockSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex, platform, shopID)
}
func (v_ctx *StoreWithContext) SetListingInSyncGroupListingDraft(acctID int64, orderIndex int, listingID string) error {
return v_ctx.Store.SetListingInSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex, listingID)
}
func (v_ctx *StoreWithContext) SetListingInMockSyncGroupListingDraft(acctID int64, orderIndex int, listingID string) error {
return v_ctx.Store.SetListingInMockSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex, listingID)
}
func (v_ctx *StoreWithContext) DeleteSyncGroupListingDraft(acctID int64, orderIndex int) (int, error) {
return v_ctx.Store.DeleteSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex)
}
func (v_ctx *StoreWithContext) DeleteMockSyncGroupListingDraft(acctID int64, orderIndex int) error {
return v_ctx.Store.DeleteMockSyncGroupListingDraft(v_ctx.ctx, acctID, orderIndex)
}
func (v_ctx *StoreWithContext) GetSyncGroupListingDrafts(acctID int64) ([]SyncGroupListingDraft, error) {
return v_ctx.Store.GetSyncGroupListingDrafts(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) GetMockSyncGroupListingDrafts(acctID int64) ([]SyncGroupListingDraft, error) {
return v_ctx.Store.GetMockSyncGroupListingDrafts(v_ctx.ctx, acctID)
}
func (v_ctx *StoreWithContext) SaveNewSyncGroup(acctID int64) (SyncGroup, error) {
return v_ctx.Store.SaveNewSyncGroup(v_ctx.ctx, acctID)
}
+381 -5
View File
@@ -8,6 +8,7 @@ import (
"slices"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
)
type (
@@ -28,6 +29,7 @@ type (
SyncGroupID int64
}
// TODO: the id ACTUALLY is the account_id and order_index
SyncGroupListingDraft struct {
AccountShopIDs
ListingID string
@@ -75,6 +77,44 @@ func (db *Store) CreateSyncGroupListingDraft(ctx context.Context, acctID int64)
return orderIndex, nil
}
func (db *Store) CreateMockSyncGroupListingDraft(ctx context.Context, acctID int64) (orderIndex int, err error) {
rows, err := db.db.Query(
ctx,
`
WITH max_order_index(max_index) AS (
SELECT
MAX(order_index) AS max_index
FROM
mock.sync_group_listing_draft_order_indexes
)
INSERT INTO
mock.sync_group_listing_draft_order_indexes (
account_id,
order_index
)
SELECT
@account_id,
COALESCE(max_index, -1) + 1
FROM
max_order_index
RETURNING
order_index
`,
pgx.NamedArgs{
"account_id": acctID,
},
)
if err != nil {
return 0, fmt.Errorf("failed to perform query: %w", err)
}
if orderIndex, err = pgx.CollectExactlyOneRow(rows, pgx.RowTo[int]); err != nil {
return 0, fmt.Errorf("failed to scan rows: %w", err)
}
return orderIndex, nil
}
func (db *Store) GetSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int) (SyncGroupListingDraft, error) {
rows, err := db.db.Query(
ctx,
@@ -124,8 +164,96 @@ func (db *Store) GetSyncGroupListingDraft(ctx context.Context, acctID int64, ord
}, nil
}
func (db *Store) GetMockSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int) (SyncGroupListingDraft, error) {
tx, err := db.db.BeginTx(ctx, pgx.TxOptions{
AccessMode: pgx.ReadOnly,
})
if err != nil {
return SyncGroupListingDraft{}, fmt.Errorf("failed to begin transaction: %w", err)
}
defer tx.Rollback(ctx)
rows, err := tx.Query(
ctx,
`
SELECT
true
FROM
mock.sync_group_listing_draft_order_indexes
WHERE
account_id = @account_id
AND order_index = @order_index
`,
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
},
)
if err != nil {
return SyncGroupListingDraft{}, fmt.Errorf("failed to scan rows: %w", err)
}
if _, err := pgx.CollectExactlyOneRow(rows, pgx.RowTo[bool]); err != nil {
return SyncGroupListingDraft{}, fmt.Errorf("failed to scan rows: %w", err)
}
for _, info := range getAllMockShopSchemaInfos() {
rows, err := tx.Query(
ctx,
fmt.Sprintf(
`
SELECT
shop_id,
listing_id
FROM
%s
WHERE
account_id = @account_id
AND order_index = @order_index
`,
info.syncGroupListingDraftsTable,
),
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
},
)
if err != nil {
return SyncGroupListingDraft{}, fmt.Errorf("failed to perform query: %w", err)
}
v, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByNameLax[struct {
Shop_id pgtype.Text
Listing_id pgtype.Text
}])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
continue
}
return SyncGroupListingDraft{}, fmt.Errorf("faild to scan row: %w", err)
}
return SyncGroupListingDraft{
AccountShopIDs: NewAccountIDs(acctID).
ShopID(info.platform, v.Shop_id.String),
ListingID: v.Listing_id.String,
OrderIndex: orderIndex,
}, nil
}
if err := tx.Commit(ctx); err != nil {
return SyncGroupListingDraft{}, fmt.Errorf("failed to commit transaction: %w", err)
}
return SyncGroupListingDraft{
AccountShopIDs: NewAccountIDs(acctID).
ShopID("", ""),
OrderIndex: orderIndex,
}, nil
}
func (db *Store) SetShopInSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int, platform Platform, shopID string) error {
tags, err := db.db.Exec(
tag, err := db.db.Exec(
ctx,
`
UPDATE
@@ -148,15 +276,106 @@ func (db *Store) SetShopInSyncGroupListingDraft(ctx context.Context, acctID int6
if err != nil {
return fmt.Errorf("failed to perform query: %w", err)
}
if tags.RowsAffected() != 1 {
if tag.RowsAffected() != 1 {
return consts.ErrNotFound
}
return nil
}
func (db *Store) SetShopInMockSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int, platform Platform, shopID string) error {
info, ok := getMockShopSchemaInfo(platform)
if !ok {
return fmt.Errorf("%w: unrecognized platform: %s", consts.ErrNotFound, platform)
}
tx, err := db.db.Begin(ctx)
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
}
defer tx.Rollback(ctx)
_, err = tx.Exec(
ctx,
`
DELETE FROM
mock.sync_group_listing_draft_order_indexes
WHERE
account_id = @account_id
AND order_index = @order_index
RETURNING
account_id,
order_index
`,
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
},
)
if err != nil {
return fmt.Errorf("failed to perform query deleting existing index: %w", err)
}
_, err = tx.Exec(
ctx,
`
INSERT INTO
mock.sync_group_listing_draft_order_indexes (
account_id,
order_index
)
VALUES (
@account_id,
@order_index
)
`,
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
},
)
if err != nil {
// TODO: handle error where account doesn't exist?
return fmt.Errorf("failed to perform query inserting new index: %w", err)
}
_, err = tx.Exec(
ctx,
fmt.Sprintf(
`
INSERT INTO
%s (
account_id,
order_index,
shop_id
)
VALUES (
@account_id,
@order_index,
@shop_id
)
`,
info.syncGroupListingDraftsTable,
),
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
"shop_id": shopID,
},
)
if err != nil {
return fmt.Errorf("failed to perform query inserting specific shop index: %w", err)
}
if err := tx.Commit(ctx); err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
return nil
}
func (db *Store) SetListingInSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int, listingID string) error {
tags, err := db.db.Exec(
tag, err := db.db.Exec(
ctx,
`
UPDATE
@@ -176,13 +395,47 @@ func (db *Store) SetListingInSyncGroupListingDraft(ctx context.Context, acctID i
if err != nil {
return fmt.Errorf("failed to perform query: %w", err)
}
if tags.RowsAffected() != 1 {
if tag.RowsAffected() != 1 {
return consts.ErrNotFound
}
return nil
}
func (db *Store) SetListingInMockSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int, listingID string) error {
for _, info := range getAllMockShopSchemaInfos() {
tag, err := db.db.Exec(
ctx,
fmt.Sprintf(
`
UPDATE
%s
SET
listing_id = @listing_id
WHERE
account_id = @account_id
AND order_index = @order_index
`,
info.syncGroupListingDraftsTable,
),
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
"listing_id": listingID,
},
)
if err != nil {
return fmt.Errorf("failed to perform query: %w", err)
}
if tag.RowsAffected() > 0 {
return nil
}
}
return consts.ErrNotFound
}
func (db *Store) DeleteSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int) (numOfRows int, err error) {
rows, err := db.db.Query(
ctx,
@@ -238,6 +491,31 @@ func (db *Store) DeleteSyncGroupListingDraft(ctx context.Context, acctID int64,
return r.Num_rows, nil
}
func (db *Store) DeleteMockSyncGroupListingDraft(ctx context.Context, acctID int64, orderIndex int) error {
tag, err := db.db.Exec(
ctx,
`
DELETE FROM
mock.sync_group_listing_draft_order_indexes
WHERE
account_id = @account_id
AND order_index = @order_index
`,
pgx.NamedArgs{
"account_id": acctID,
"order_index": orderIndex,
},
)
if err != nil {
return fmt.Errorf("failed to perform query: %w", err)
}
if tag.RowsAffected() != 1 {
return consts.ErrNotFound
}
return nil
}
func (db *Store) GetSyncGroupListingDrafts(ctx context.Context, acctID int64) ([]SyncGroupListingDraft, error) {
rows, err := db.db.Query(
ctx,
@@ -296,7 +574,105 @@ func (db *Store) GetSyncGroupListingDrafts(ctx context.Context, acctID int64) ([
return listings, nil
}
// TODO: test
func (db *Store) GetMockSyncGroupListingDrafts(ctx context.Context, acctID int64) ([]SyncGroupListingDraft, error) {
tx, err := db.db.BeginTx(ctx, pgx.TxOptions{
AccessMode: pgx.ReadOnly,
})
if err != nil {
return nil, fmt.Errorf("failed to begin transaction: %w", err)
}
defer tx.Rollback(ctx)
rows, err := tx.Query(
ctx,
`
SELECT
order_index
FROM
mock.sync_group_listing_draft_order_indexes
WHERE
account_id = @account_id
`,
pgx.NamedArgs{
"account_id": acctID,
},
)
if err != nil {
return nil, fmt.Errorf("failed to perform query: %w", err)
}
indexes, err := pgx.CollectRows(rows, pgx.RowTo[int])
if err != nil {
return nil, fmt.Errorf("failed to scan rows: %w", err)
}
listingsByOrderIndex := make(map[int]SyncGroupListingDraft, len(indexes))
for _, n := range indexes {
listingsByOrderIndex[n] = SyncGroupListingDraft{
AccountShopIDs: NewAccountIDs(acctID).
ShopID("", ""),
OrderIndex: n,
}
}
for _, info := range getAllMockShopSchemaInfos() {
rows, err := tx.Query(
ctx,
fmt.Sprintf(
`
SELECT
shop_id,
order_index,
listing_id
FROM
%s
WHERE
account_id = @account_id
`,
info.syncGroupListingDraftsTable,
),
pgx.NamedArgs{
"account_id": acctID,
},
)
if err != nil {
return nil, fmt.Errorf("failed to perform query: %w", err)
}
vs, err := pgx.CollectRows(rows, pgx.RowToStructByNameLax[struct {
Shop_id pgtype.Text
Order_index pgtype.Int8
Listing_id pgtype.Text
}])
if err != nil {
return nil, fmt.Errorf("failed to scan rows: %w", err)
}
for _, v := range vs {
n := int(v.Order_index.Int64)
l := listingsByOrderIndex[n]
l.Platform = info.platform
l.ShopID = v.Shop_id.String
l.ListingID = v.Listing_id.String
listingsByOrderIndex[n] = l
}
}
listings := make([]SyncGroupListingDraft, 0, len(listingsByOrderIndex))
for _, v := range listingsByOrderIndex {
listings = append(listings, v)
}
slices.SortFunc(listings, func(a, b SyncGroupListingDraft) int {
return a.OrderIndex - b.OrderIndex
})
if err := tx.Commit(ctx); err != nil {
return nil, fmt.Errorf("failed to commit transaction: %w", err)
}
return listings, nil
}
func (db *Store) SaveNewSyncGroup(ctx context.Context, acctID int64) (SyncGroup, error) {
txn, err := db.db.Begin(ctx)
if err != nil {
+98
View File
@@ -54,6 +54,13 @@ func Routes(
draftListings.PUT("/:orderIndex/shop", response.Handler(as.setShopInSyncGroupListingDraft))
draftListings.PUT("/:orderIndex/listing", response.Handler(as.setListingInSyncGroupListingDraft))
draftListings.DELETE("/:orderIndex", response.Handler(as.deleteSyncGroupListingDraft))
mockSyncGroups := syncGroups.Group("/mock")
mockDraftListings := mockSyncGroups.Group("/draft/listings", pub.Publish("/:acctID/inventory/sync-groups/mock/draft/listings"))
mockDraftListings.POST("", response.Handler(as.createMockSyncGroupListingDraft))
mockDraftListings.PUT("/:orderIndex/shop", response.Handler(as.setShopInMockSyncGroupListingDraft))
mockDraftListings.PUT("/:orderIndex/listing", response.Handler(as.setListingInMockSyncGroupListingDraft))
mockDraftListings.DELETE("/:orderIndex", response.Handler(as.deleteMockSyncGroupListingDraft))
}
// POST /
@@ -110,6 +117,7 @@ func (s *accountSubrouter) setShopInSyncGroupListingDraft(c *gin.Context) (respo
err := param.Path("orderIndex", param.Int(&orderIndex)).
Form("platform", param.Platform(&platform)).
Form("shop-id", param.Text(&shopID)).
Unmarshal(c)
if err != nil {
return nil, err
@@ -388,6 +396,96 @@ func (s *accountSubrouter) deleteMockListing(c *gin.Context) (response.Response,
return response.StatusNoContent(), nil
}
// POST /:acctID/inventory/sync-groups/mock/draft/listings
func (s *accountSubrouter) createMockSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := auth.GetIdentity(ctx).Account.AccountID
if _, err := s.accts.CreateMockSyncGroupListingDraft(ctx, acctID); err != nil {
return nil, response.Errorf("failed to create new listing draft: %w", err)
}
return response.StatusCreated(), nil
}
// PUT /:acctID/inventory/sync-groups/mock/draft/listings/:orderIndex/shop
// @platform string
// @shopID string
func (s *accountSubrouter) setShopInMockSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := auth.GetIdentity(ctx).Account.AccountID
var (
orderIndex int
platform accounts.Platform
shopID string
)
err := param.Path("orderIndex", param.Int(&orderIndex)).
Form("platform", param.Platform(&platform)).
Form("shop-id", param.Text(&shopID)).
Unmarshal(c)
if err != nil {
return nil, err
}
if err := s.accts.SetShopInMockSyncGroupListingDraft(ctx, acctID, orderIndex, platform, shopID); err != nil {
return nil, response.Errorf("failed to set shop: %w", response.ErrorFromConstant(err))
}
return response.StatusOK(), nil
}
// PUT /:acctID/inventory/sync-groups/mock/draft/listings/:orderIndex/listing
func (s *accountSubrouter) setListingInMockSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := auth.GetIdentity(ctx).Account.AccountID
var (
orderIndex int
listingID string
)
err := param.Path("orderIndex", param.Int(&orderIndex)).
Form("listing-id", param.Text(&listingID)).
Unmarshal(c)
if err != nil {
return nil, err
}
if err := s.accts.SetListingInMockSyncGroupListingDraft(ctx, acctID, orderIndex, listingID); err != nil {
return nil, response.Errorf("failed to set listing: %w", response.ErrorFromConstant(err))
}
return response.StatusOK(), nil
}
// DELETE /:acctID/inventory/sync-groups/mock/draft/listings/:orderIndex
func (s *accountSubrouter) deleteMockSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := auth.GetIdentity(ctx).Account.AccountID
var (
orderIndex int
)
err := param.Path("orderIndex", param.Int(&orderIndex)).
Unmarshal(c)
if err != nil {
return nil, err
}
if err := s.accts.DeleteMockSyncGroupListingDraft(ctx, acctID, orderIndex); err != nil {
return nil, response.Errorf("failed to delete listing: %w", response.ErrorFromConstant(err))
}
return response.StatusOK(), nil
}
func lowerSnakeCase(s accounts.Platform) string {
return strings.ToLower(strings.Join(strings.Split(string(s), " "), "_"))
}
+3 -79
View File
@@ -250,9 +250,6 @@
.mt-\[3em\] {
margin-top: 3em;
}
.mt-\[5em\] {
margin-top: 5em;
}
.mb-\[0\.5em\] {
margin-bottom: 0.5em;
}
@@ -295,18 +292,9 @@
.h-fit {
height: fit-content;
}
.max-h-\[10vh\] {
max-height: 10vh;
}
.max-h-\[50em\] {
max-height: 50em;
}
.max-h-\[80vh\] {
max-height: 80vh;
}
.max-h-\[100vh\] {
max-height: 100vh;
}
.max-h-full {
max-height: 100%;
}
@@ -334,9 +322,6 @@
.flex-shrink {
flex-shrink: 1;
}
.flex-grow {
flex-grow: 1;
}
.grow {
flex-grow: 1;
}
@@ -364,9 +349,6 @@
.list-none {
list-style-type: none;
}
.grid-cols-\[2fr_8fr_2fr\] {
grid-template-columns: 2fr 8fr 2fr;
}
.grid-cols-\[6rem_10fr_6rem\] {
grid-template-columns: 6rem 10fr 6rem;
}
@@ -382,9 +364,6 @@
.flex-col {
flex-direction: column;
}
.content-center {
align-content: center;
}
.items-center {
align-items: center;
}
@@ -406,9 +385,6 @@
.gap-\[1em\] {
gap: 1em;
}
.gap-x-\[1em\] {
column-gap: 1em;
}
.gap-y-\[2em\] {
row-gap: 2em;
}
@@ -495,6 +471,9 @@
.py-\[0\.5em\] {
padding-block: 0.5em;
}
.py-\[2em\] {
padding-block: 2em;
}
.pt-\[1em\] {
padding-top: 1em;
}
@@ -545,9 +524,6 @@
.italic {
font-style: italic;
}
.no-underline {
text-decoration-line: none;
}
.underline {
text-decoration-line: underline;
}
@@ -652,48 +628,11 @@
}
}
}
.group-open\/create-mock-shop\:after\:content-\[\'-\'\] {
&:is(:where(.group\/create-mock-shop):is([open], :popover-open, :open) *) {
&::after {
--tw-content: '-';
content: var(--tw-content);
}
}
}
.group-open\/link-shops\:after\:content-\[\'-\'\] {
&:is(:where(.group\/link-shops):is([open], :popover-open, :open) *) {
&::after {
--tw-content: '-';
content: var(--tw-content);
}
}
}
.open\:mb-\[1em\] {
&:is([open], :popover-open, :open) {
margin-bottom: 1em;
}
}
.open\:grid {
&:is([open], :popover-open, :open) {
display: grid;
}
}
.open\:border-b-\[1px\] {
&:is([open], :popover-open, :open) {
border-bottom-style: var(--tw-border-style);
border-bottom-width: 1px;
}
}
.open\:border-b-background {
&:is([open], :popover-open, :open) {
border-bottom-color: var(--background);
}
}
.open\:pb-\[1em\] {
&:is([open], :popover-open, :open) {
padding-bottom: 1em;
}
}
.open\:details-content\:transform-\[translate\(0px\,0px\)\] {
&:is([open], :popover-open, :open) {
&::details-content {
@@ -717,14 +656,6 @@
}
}
}
.open\:details-content\:border-t-\[0\.225rem\] {
&:is([open], :popover-open, :open) {
&::details-content {
border-top-style: var(--tw-border-style);
border-top-width: 0.225rem;
}
}
}
.open\:details-content\:border-b-\[0px\] {
&:is([open], :popover-open, :open) {
&::details-content {
@@ -776,13 +707,6 @@
}
}
}
.hover\:no-underline {
&:hover {
@media (hover: hover) {
text-decoration-line: none;
}
}
}
.hover\:underline {
&:hover {
@media (hover: hover) {
@@ -0,0 +1,140 @@
{{/* optional props: .Listings = .Accounts.GetMockSyncGroupListingDrafts */}}
{{- $acctID := .PathParams.acctID }}
{{- $orderIndex := .PathParams.orderIndex }}
{{- $entry := .Accounts.GetMockSyncGroupListingDraft $acctID $orderIndex }}
{{- $selectedShopPlatform := $entry.Platform }}
{{- $selectedShopID := $entry.ShopID }}
{{- $selectedListingID := $entry.ListingID }}
{{/* TODO: is this supposed to be the mock listings (not draft listings)? */}}
{{- $listings := .Listings }}
{{- if not $listings }}
{{- $listings = .Accounts.GetMockSyncGroupListingDrafts $acctID }}
{{- end }}
<tr _="
init
set @data-filled-out to false
def setFilledOut(val)
set @data-filled-out to val
send rowUpdated() to closest <tbody/>
end
on setListing(listing)
call setFilledOut(true)
on resetListing
call setFilledOut(false)
"
>
<td>
{{/* TODO: filter out shops that are already selected */}}
{{- $shops := .Accounts.GetMockShops $acctID -}}
<select
class="min-w-fit cursor-pointer"
hx-put="/api/accounts/{{$acctID}}/inventory/sync-groups/mock/draft/listings/{{$orderIndex}}/shop"
hx-vals='js:{
platform: event.target.value.replace(/-[^ ]*/, ""),
"shop-id": event.target.value.replace(/^[a-zA-Z_]*-/, "")
}'
hx-swap="none"
_="
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
value="{{$shop.Platform}}-{{$shop.ShopID}}"
{{- if $isSelectedShop }}selected{{- end }}
>
{{ $shop.Name }} - {{$shop.Platform}} - {{$shop.ShopID}} - {{(eq $selectedShopPlatform $shop.Platform)}} - {{(eq $selectedShopID $shop.ShopID)}}
</option>
{{- end }}
</select>
</td>
<td>
{{- $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/draft/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 data-id="sku">
{{if $selectedListing}}{{$selectedListing.SKU}}{{else}}-{{end}}
</td>
<td data-id="description">
{{if $selectedListing}}{{$selectedListing.Description}}{{else}}-{{end}}
</td>
<td data-id="remove">
{{ component "button"
"HXDelete" (printf "/api/accounts/%d/inventory/sync-groups/mock/draft/listings/%d" $acctID $orderIndex)
"HXTarget" "#accounts-acct-id-inventory-sync-groups-mock-draft-table"
"HXSwap" "none"
"Text" "Remove"
}}
</td>
</tr>
@@ -0,0 +1,37 @@
{{- $acctID := .PathParams.acctID }}
{{- $button := component "button"
"HXPost" (printf "/api/accounts/%d/inventory/sync-groups/mock/draft/listings" $acctID)
"HXTarget" "#accounts-acct-id-inventory-sync-groups-mock-draft-table"
"HXSwap" "none"
"HXSelect" "#accounts-acct-id-inventory-sync-groups-mock-draft-table"
"ID" "sync-groups-mock-draft-table-add-listing-button"
"Class" "mt-[1em] mb-[1em]"
"Text" "Add Listing"
"_" `
on click
send rowUpdated to the first <tbody/> in #accounts-acct-id-inventory-sync-groups-mock-draft-table
`
}}
{{/* $button */}}
{{-
component "tutorial-tooltip"
"AnchorTag" "div"
"AnchorID" "sync-groups-mock-draft-table-add-listing-button"
"AnchorClickedEventName" "anchorClicked"
"AnchorContent" $button
"AnchorClass" ""
"AnchorStyle" "display: inline;"
"PopoverID" "add-listing-popover"
"PopoverContentIDPrefix" "add-listing-popover-content"
"PopoverContents" (
newHTMLSlice
"Click to add a listing"
"You need at least two to create a sync group!"
"Keep adding listing until done!"
)
}}
@@ -0,0 +1,104 @@
{{- .Auth.ByMatchingAccountID 2 }}
{{- $acctID := .PathParams.acctID }}
<table
id="accounts-acct-id-inventory-sync-groups-mock-draft-table"
class="max-w-full overflow-x-auto"
hx-get="{{ printf "/ui/accounts/%d/inventory/sync-groups/mock/draft/table" $acctID }}"
hx-trigger="sse:{{ printf "accounts_%d_inventory_sync-groups_mock_draft" $acctID }},sse:{{ printf "accounts_%d_inventory_sync-groups_mock_draft_listings" $acctID }}"
hx-select="#accounts-acct-id-inventory-sync-groups-mock-draft-table"
hx-swap="morph:outerHTML"
>
<thead>
<tr>
<th>
Shop
</th>
<th>
Listing
</th>
<th>
SKU
</th>
<th>
Description
</th>
<th>
</th>
</tr>
</thead>
<tbody
_="
init
set element allRowsFilledOut to false
set element numRows to 0
def checkIfAllRowsAreFilledOut()
set rows to my children
set element allRowsFilledOut to true
set element numRows to rows.length
for row in rows
set filledOut to row.dataset.filledOut is 'true'
if not filledOut then
set element allRowsFilledOut to false
break
end
end
end
on rowUpdated
checkIfAllRowsAreFilledOut()
send setDisabled(disabled: not allRowsFilledOut or numRows < 2) to #create-sync-group-button
"
>
{{- $listings := .Accounts.GetMockSyncGroupListingDrafts $acctID }}
{{- range $listing := $listings }}
{{- component (printf "accounts/%d/inventory/sync-groups/mock/draft/listings/%d" $acctID $listing.OrderIndex)
"Listings" $listings
}}
{{- end }}
</tbody>
<tfoot>
<tr>
<th>
Shop
</th>
<th>
Listing
</th>
<th>
SKU
</th>
<th>
Description
</th>
<th>
</th>
</tr>
</tfoot>
</table>
{{/*
<div
hidden
hx-get="{{ printf "/ui/accounts/%d/inventory/sync-groups/draft/table/add-listing-button" $acctID }}"
hx-trigger="{{ (printf "sse:accounts_%d_inventory_sync-groups_draft_listings" $acctID) }}"
hx-target="#sync-groups-draft-table-add-listing-button"
hx-swap="outerHTML"
>
</div>
*/}}
<div
hidden
hx-get="{{ printf "/ui/accounts/%d/inventory/sync-groups/mock/draft/table/save-sync-group-button" $acctID }}"
hx-trigger="{{ (printf "sse:accounts_%d_inventory_sync-groups_mock_draft_listings" $acctID) }}"
hx-target="#create-sync-group-button"
hx-swap="outerHTML"
>
</div>
@@ -0,0 +1,33 @@
{{/* TODO: save the listings as a sync group on click */}}
{{- $acctID := .PathParams.acctID }}
{{- $listings := .Accounts.GetSyncGroupListingDrafts $acctID }}
{{- $numCompletedListings := 0 }}
{{- range $l := $listings }}
{{- if and $l.ShopID $l.ListingID }}
{{- $numCompletedListings = (addInt $numCompletedListings 1) }}
{{- else }}
{{- end }}
{{- end }}
{{- $enoughListings := gt $numCompletedListings 1 }}
{{- $allCompleted := len $listings | eq $numCompletedListings }}
{{ component "button"
"ID" "create-sync-group-button"
"HXPost" (printf "/api/accounts/%d/sync-groups/mock" $acctID)
"Class" "mt-[1em] mb-[1em]"
"Text" "Save Sync Group"
"Disabled" (or (not $enoughListings) (not $allCompleted))
"_" `
on setDisabled(disabled)
if disabled then
add @disabled to me
else
remove @disabled from me
end
`
}}
@@ -4,7 +4,7 @@
{{- $stores := .Accounts.GetShops $acctID -}}
{{- define "title" }} Inventory++ {{ end }}
{{- define "title" }} Manage Inventory &sdot; Inventory++ {{ end }}
<h1 class="text-center mb-[0.5em]">Inventory</h1>
@@ -4,22 +4,70 @@
{{- $stores := .Accounts.GetShops $acctID -}}
{{- define "title" }} Inventory++ {{ end }}
{{- define "title" }} Manage Mock Inventory &sdot; Inventory++ {{ end }}
<h1 class="text-center mb-[0.5em]">Inventory</h1>
<h2 class="text-center mb-[0.5em]">Synced Listings</h2>
<section class="py-[2em] flex flex-col items-center">
<details
class="
group
<section class="w-full flex flex-col items-center">
<h3 class="mb-[1.25rem]">
Create a Sync Group
</h3>
{{/*
{{ component (printf "accounts/%d/inventory/sync-groups/draft/table" $acctID) }}
flex
flex-col
items-center
<div>
{{ component (printf "accounts/%d/inventory/sync-groups/draft/table/add-listing-button" $acctID) }}
{{ component (printf "accounts/%d/inventory/sync-groups/draft/table/save-sync-group-button" $acctID) }}
{{/* TODO: make custom class for all this */}}
details-content:opacity-[0]
open:details-content:opacity-[1]
details-content:transform-[translate(0px,-2em)]
open:details-content:transform-[translate(0px,0px)]
details-content:border-transparent
open:details-content:border-dotted
open:details-content:border-x-[0px]
open:details-content:border-x-transparent
open:details-content:border-b-[0px]
open:details-content:border-b-transparent
open:details-content:border-t-background
open:details-content:border-t-[0.25rem]
details-content:outline-transparent
details-content:transition-[opacity_transform]
"
hx-preserve
open
>
<summary
class="
flex
items-center
gap-[1em]
list-none
p-[1em]
mb-[1em]
cursor-pointer
bg-accent
rounded-lg
after:content-['+']
group-open:after:content-['-']
after:font-bold
after:text-[2em]
after:leading-[1em]
"
>
<h2 class="inline-block">
New Sync Group
</h2>
</summary>
{{ component (printf "accounts/%d/inventory/sync-groups/mock/draft/table" $acctID) }}
<div class="flex justify-center gap-[0.5em]">
{{ component (printf "accounts/%d/inventory/sync-groups/mock/draft/table/add-listing-button" $acctID) }}
{{ component (printf "accounts/%d/inventory/sync-groups/mock/draft/table/save-sync-group-button" $acctID) }}
</div>
*/}}
</details>
</section>
@@ -14,8 +14,8 @@
<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-get={{ printf "/ui/accounts/%d/platforms/%s/shops/mocks/%s" $acctID .PathParams.platform $shopID }}
hx-trigger={{ printf "sse:accounts_%d_platforms_%s_shops_mocks_%s_listings" $acctID .PathParams.platform $shopID }}
hx-select="#listing-section"
>
<header class="p-[1em]">
@@ -55,7 +55,7 @@
>
<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/%s/shops/mocks/%s/listings" $acctID .PathParams.platform $shopID }}
hx-swap="none"
class="
grid
@@ -132,7 +132,7 @@
<form
id="edit-listing-form"
hx-put={{ printf "/api/accounts/%d/platforms/amazon/shops/mocks/%s/listings/{listingID}" $acctID $shopID }}
hx-put={{ printf "/api/accounts/%d/platforms/%s/shops/mocks/%s/listings/{listingID}" $acctID .PathParams.platform $shopID }}
hx-swap="none"
class="
grid
@@ -316,6 +316,7 @@
</form>
<ul class="max-h-[80vh] overflow-y-auto flex flex-col gap-[1em]">
{{- $dot := . }}
{{- range $listing := .Accounts.ListMockListingsForShop $acctID $platform $shopID }}
<li
id="listing-{{$listing.ListingID}}"
@@ -387,7 +388,7 @@
{{ component "button"
"Title" "Delete Listing"
"Text" (rawHTML "&#128465;")
"HXDelete" (printf "/api/accounts/%d/platforms/amazon/shops/mocks/%s/listings/%s" $acctID $shopID $listing.ListingID)
"HXDelete" (printf "/api/accounts/%d/platforms/%s/shops/mocks/%s/listings/%s" $acctID $dot.PathParams.platform $shopID $listing.ListingID)
"_" "on click event.preventDefault() then event.stopPropagation()"
}}
</li>