diff --git a/src/app/admin/products/page.tsx b/src/app/admin/products/page.tsx
index bc7914d..70db689 100644
--- a/src/app/admin/products/page.tsx
+++ b/src/app/admin/products/page.tsx
@@ -69,7 +69,7 @@ export default async function AdminProductsPage() {
return (
);
}
\ No newline at end of file
diff --git a/src/components/admin/HarvestReach/SegmentBuilderPage.tsx b/src/components/admin/HarvestReach/SegmentBuilderPage.tsx
index 1cfc9be..bf6020a 100644
--- a/src/components/admin/HarvestReach/SegmentBuilderPage.tsx
+++ b/src/components/admin/HarvestReach/SegmentBuilderPage.tsx
@@ -14,7 +14,7 @@ type Props = {
};
// Icon components
-const LayersIcon = (className: string) => (
+const LayersIcon = ({ className }: { className: string }) => (
);
-export default function ProductsClient({ products, brandId }: { products: Product[]; brandId: string }) {
+export default function ProductsClient({ products, brandId }: { products: Product[]; brandId?: string }) {
const router = useRouter();
const [, startTransition] = useTransition();
const [search, setSearch] = useState("");
@@ -234,6 +234,12 @@ export default function ProductsClient({ products, brandId }: { products: Produc
}
try {
+ if (!brandId) {
+ setError("Brand ID is required");
+ setSaving(false);
+ return;
+ }
+
let result;
const imageUrl = pendingImageUrl || formData.image_url || null;
diff --git a/test-results/.last-run.json b/test-results/.last-run.json
index cbcc1fb..9e24987 100644
--- a/test-results/.last-run.json
+++ b/test-results/.last-run.json
@@ -1,4 +1,8 @@
{
- "status": "passed",
- "failedTests": []
+ "status": "failed",
+ "failedTests": [
+ "9baefabce98ea24ee76d-2f6f670dfe942637faf7",
+ "9baefabce98ea24ee76d-f58eca1309366ec2998a",
+ "9baefabce98ea24ee76d-4a32d345869f5c6ceb12"
+ ]
}
\ No newline at end of file
diff --git a/test-results/login-login-flow-admin-session-persists-across-page-reloads-production/error-context.md b/test-results/login-login-flow-admin-session-persists-across-page-reloads-production/error-context.md
new file mode 100644
index 0000000..9122b57
--- /dev/null
+++ b/test-results/login-login-flow-admin-session-persists-across-page-reloads-production/error-context.md
@@ -0,0 +1,152 @@
+# Instructions
+
+- Following Playwright test failed.
+- Explain why, be concise, respect Playwright best practices.
+- Provide a snippet of code with the fix, if possible.
+
+# Test info
+
+- Name: login/login-flow.spec.ts >> admin session persists across page reloads
+- Location: tests/login/login-flow.spec.ts:65:5
+
+# Error details
+
+```
+Error: page.fill: value: expected string, got undefined
+```
+
+# Page snapshot
+
+```yaml
+- generic [active] [ref=e1]:
+ - banner [ref=e2]:
+ - generic [ref=e3]:
+ - link "Route Commerce" [ref=e4] [cursor=pointer]:
+ - /url: /
+ - navigation [ref=e5]:
+ - link "Tuxedo" [ref=e6] [cursor=pointer]:
+ - /url: /tuxedo
+ - link "IRD" [ref=e7] [cursor=pointer]:
+ - /url: /indian-river-direct
+ - link "Admin" [ref=e8] [cursor=pointer]:
+ - /url: /admin
+ - button "Switch to dark mode" [ref=e9]:
+ - img [ref=e10]
+ - link "Cart (0)" [ref=e12] [cursor=pointer]:
+ - /url: /cart
+ - main [ref=e13]:
+ - generic [ref=e14]:
+ - generic [ref=e15]:
+ - heading "Admin Login" [level=1] [ref=e16]
+ - paragraph [ref=e17]: Sign in with your account.
+ - generic [ref=e18]:
+ - generic [ref=e19]:
+ - generic [ref=e20]: Email
+ - textbox "Email" [ref=e21]:
+ - /placeholder: admin@example.com
+ - generic [ref=e22]:
+ - generic [ref=e23]: Password
+ - textbox "Password" [ref=e24]:
+ - /placeholder: ••••••••
+ - button "Sign In" [ref=e25]
+ - button "Forgot password?" [ref=e26]
+ - link "← Back to storefront" [ref=e27] [cursor=pointer]:
+ - /url: /
+ - contentinfo [ref=e28]:
+ - generic [ref=e30]:
+ - paragraph [ref=e31]: © 2026 Route Commerce. All rights reserved.
+ - navigation [ref=e32]:
+ - link "Privacy Policy" [ref=e33] [cursor=pointer]:
+ - /url: /privacy-policy
+ - link "Terms & Conditions" [ref=e34] [cursor=pointer]:
+ - /url: /terms-and-conditions
+ - link "Powered by Route Commerce" [ref=e35] [cursor=pointer]:
+ - /url: https://cielohermosa.com
+ - alert [ref=e36]
+```
+
+# Test source
+
+```ts
+ 1 | import { test, expect } from "@playwright/test";
+ 2 |
+ 3 | // ─────────────────────────────────────────────────────────────
+ 4 | // Login flow: credentials → /api/login JSON → redirect to /admin
+ 5 | // ─────────────────────────────────────────────────────────────
+ 6 | test("login with valid credentials redirects to /admin and shows admin dashboard", async ({
+ 7 | page,
+ 8 | }) => {
+ 9 | // Navigate to login page
+ 10 | await page.goto("/login");
+ 11 |
+ 12 | // Fill credentials
+ 13 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!);
+ 14 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!);
+ 15 |
+ 16 | // Submit form
+ 17 | await page.click('button[type="submit"]');
+ 18 |
+ 19 | // Wait for navigation to /admin — the JSON response + client nav must happen
+ 20 | await page.waitForURL("**/admin", { timeout: 10000 });
+ 21 |
+ 22 | // Admin dashboard must be rendered (Control Center heading or admin layout)
+ 23 | await expect(page.locator("body")).not.toContainText("Access Denied");
+ 24 | await expect(page.locator("body")).not.toContainText("Login failed");
+ 25 | });
+ 26 |
+ 27 | // ─────────────────────────────────────────────────────────────
+ 28 | // Login failure: bad password shows error, stays on /login
+ 29 | // ─────────────────────────────────────────────────────────────
+ 30 | test("login with wrong password shows error and stays on /login", async ({
+ 31 | page,
+ 32 | }) => {
+ 33 | await page.goto("/login");
+ 34 |
+ 35 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!);
+ 36 | await page.fill("#password", "wrongpassword123!");
+ 37 |
+ 38 | await page.click('button[type="submit"]');
+ 39 |
+ 40 | // Error message should appear
+ 41 | await expect(page.locator('[role="alert"]')).toBeVisible({ timeout: 5000 });
+ 42 | // Should NOT navigate away from login
+ 43 | await expect(page).toHaveURL(/\/login/);
+ 44 | });
+ 45 |
+ 46 | // ─────────────────────────────────────────────────────────────
+ 47 | // Login with missing fields shows validation error
+ 48 | // ─────────────────────────────────────────────────────────────
+ 49 | test("login with missing email shows validation error", async ({ page }) => {
+ 50 | await page.goto("/login");
+ 51 |
+ 52 | // Don't fill email, only password
+ 53 | await page.fill("#password", "something");
+ 54 |
+ 55 | await page.click('button[type="submit"]');
+ 56 |
+ 57 | // Browser validation should fire (email required)
+ 58 | await expect(page.locator("#email")).toHaveAttribute("required", "");
+ 59 | });
+ 60 |
+ 61 | // ─────────────────────────────────────────────────────────────
+ 62 | // Session persistence: after login, navigating to /admin
+ 63 | // should load without re-authenticating
+ 64 | // ─────────────────────────────────────────────────────────────
+ 65 | test("admin session persists across page reloads", async ({ page }) => {
+ 66 | // Login first
+ 67 | await page.goto("/login");
+> 68 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!);
+ | ^ Error: page.fill: value: expected string, got undefined
+ 69 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!);
+ 70 | await page.click('button[type="submit"]');
+ 71 | await page.waitForURL("**/admin", { timeout: 10000 });
+ 72 |
+ 73 | // Reload the page
+ 74 | await page.reload();
+ 75 |
+ 76 | // Should still be on /admin (session cookie keeps user logged in)
+ 77 | await expect(page).toHaveURL(/\/admin/);
+ 78 | await expect(page.locator("body")).not.toContainText("Access Denied");
+ 79 | });
+ 80 |
+```
\ No newline at end of file
diff --git a/test-results/login-login-flow-login-wit-18f75-ws-error-and-stays-on-login-production/error-context.md b/test-results/login-login-flow-login-wit-18f75-ws-error-and-stays-on-login-production/error-context.md
new file mode 100644
index 0000000..3daf2c5
--- /dev/null
+++ b/test-results/login-login-flow-login-wit-18f75-ws-error-and-stays-on-login-production/error-context.md
@@ -0,0 +1,152 @@
+# Instructions
+
+- Following Playwright test failed.
+- Explain why, be concise, respect Playwright best practices.
+- Provide a snippet of code with the fix, if possible.
+
+# Test info
+
+- Name: login/login-flow.spec.ts >> login with wrong password shows error and stays on /login
+- Location: tests/login/login-flow.spec.ts:30:5
+
+# Error details
+
+```
+Error: page.fill: value: expected string, got undefined
+```
+
+# Page snapshot
+
+```yaml
+- generic [active] [ref=e1]:
+ - banner [ref=e2]:
+ - generic [ref=e3]:
+ - link "Route Commerce" [ref=e4] [cursor=pointer]:
+ - /url: /
+ - navigation [ref=e5]:
+ - link "Tuxedo" [ref=e6] [cursor=pointer]:
+ - /url: /tuxedo
+ - link "IRD" [ref=e7] [cursor=pointer]:
+ - /url: /indian-river-direct
+ - link "Admin" [ref=e8] [cursor=pointer]:
+ - /url: /admin
+ - button "Switch to dark mode" [ref=e9]:
+ - img [ref=e10]
+ - link "Cart (0)" [ref=e12] [cursor=pointer]:
+ - /url: /cart
+ - main [ref=e13]:
+ - generic [ref=e14]:
+ - generic [ref=e15]:
+ - heading "Admin Login" [level=1] [ref=e16]
+ - paragraph [ref=e17]: Sign in with your account.
+ - generic [ref=e18]:
+ - generic [ref=e19]:
+ - generic [ref=e20]: Email
+ - textbox "Email" [ref=e21]:
+ - /placeholder: admin@example.com
+ - generic [ref=e22]:
+ - generic [ref=e23]: Password
+ - textbox "Password" [ref=e24]:
+ - /placeholder: ••••••••
+ - button "Sign In" [ref=e25]
+ - button "Forgot password?" [ref=e26]
+ - link "← Back to storefront" [ref=e27] [cursor=pointer]:
+ - /url: /
+ - contentinfo [ref=e28]:
+ - generic [ref=e30]:
+ - paragraph [ref=e31]: © 2026 Route Commerce. All rights reserved.
+ - navigation [ref=e32]:
+ - link "Privacy Policy" [ref=e33] [cursor=pointer]:
+ - /url: /privacy-policy
+ - link "Terms & Conditions" [ref=e34] [cursor=pointer]:
+ - /url: /terms-and-conditions
+ - link "Powered by Route Commerce" [ref=e35] [cursor=pointer]:
+ - /url: https://cielohermosa.com
+ - alert [ref=e36]
+```
+
+# Test source
+
+```ts
+ 1 | import { test, expect } from "@playwright/test";
+ 2 |
+ 3 | // ─────────────────────────────────────────────────────────────
+ 4 | // Login flow: credentials → /api/login JSON → redirect to /admin
+ 5 | // ─────────────────────────────────────────────────────────────
+ 6 | test("login with valid credentials redirects to /admin and shows admin dashboard", async ({
+ 7 | page,
+ 8 | }) => {
+ 9 | // Navigate to login page
+ 10 | await page.goto("/login");
+ 11 |
+ 12 | // Fill credentials
+ 13 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!);
+ 14 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!);
+ 15 |
+ 16 | // Submit form
+ 17 | await page.click('button[type="submit"]');
+ 18 |
+ 19 | // Wait for navigation to /admin — the JSON response + client nav must happen
+ 20 | await page.waitForURL("**/admin", { timeout: 10000 });
+ 21 |
+ 22 | // Admin dashboard must be rendered (Control Center heading or admin layout)
+ 23 | await expect(page.locator("body")).not.toContainText("Access Denied");
+ 24 | await expect(page.locator("body")).not.toContainText("Login failed");
+ 25 | });
+ 26 |
+ 27 | // ─────────────────────────────────────────────────────────────
+ 28 | // Login failure: bad password shows error, stays on /login
+ 29 | // ─────────────────────────────────────────────────────────────
+ 30 | test("login with wrong password shows error and stays on /login", async ({
+ 31 | page,
+ 32 | }) => {
+ 33 | await page.goto("/login");
+ 34 |
+> 35 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!);
+ | ^ Error: page.fill: value: expected string, got undefined
+ 36 | await page.fill("#password", "wrongpassword123!");
+ 37 |
+ 38 | await page.click('button[type="submit"]');
+ 39 |
+ 40 | // Error message should appear
+ 41 | await expect(page.locator('[role="alert"]')).toBeVisible({ timeout: 5000 });
+ 42 | // Should NOT navigate away from login
+ 43 | await expect(page).toHaveURL(/\/login/);
+ 44 | });
+ 45 |
+ 46 | // ─────────────────────────────────────────────────────────────
+ 47 | // Login with missing fields shows validation error
+ 48 | // ─────────────────────────────────────────────────────────────
+ 49 | test("login with missing email shows validation error", async ({ page }) => {
+ 50 | await page.goto("/login");
+ 51 |
+ 52 | // Don't fill email, only password
+ 53 | await page.fill("#password", "something");
+ 54 |
+ 55 | await page.click('button[type="submit"]');
+ 56 |
+ 57 | // Browser validation should fire (email required)
+ 58 | await expect(page.locator("#email")).toHaveAttribute("required", "");
+ 59 | });
+ 60 |
+ 61 | // ─────────────────────────────────────────────────────────────
+ 62 | // Session persistence: after login, navigating to /admin
+ 63 | // should load without re-authenticating
+ 64 | // ─────────────────────────────────────────────────────────────
+ 65 | test("admin session persists across page reloads", async ({ page }) => {
+ 66 | // Login first
+ 67 | await page.goto("/login");
+ 68 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!);
+ 69 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!);
+ 70 | await page.click('button[type="submit"]');
+ 71 | await page.waitForURL("**/admin", { timeout: 10000 });
+ 72 |
+ 73 | // Reload the page
+ 74 | await page.reload();
+ 75 |
+ 76 | // Should still be on /admin (session cookie keeps user logged in)
+ 77 | await expect(page).toHaveURL(/\/admin/);
+ 78 | await expect(page.locator("body")).not.toContainText("Access Denied");
+ 79 | });
+ 80 |
+```
\ No newline at end of file
diff --git a/test-results/login-login-flow-login-wit-e85a2-n-and-shows-admin-dashboard-production/error-context.md b/test-results/login-login-flow-login-wit-e85a2-n-and-shows-admin-dashboard-production/error-context.md
new file mode 100644
index 0000000..daa973b
--- /dev/null
+++ b/test-results/login-login-flow-login-wit-e85a2-n-and-shows-admin-dashboard-production/error-context.md
@@ -0,0 +1,152 @@
+# Instructions
+
+- Following Playwright test failed.
+- Explain why, be concise, respect Playwright best practices.
+- Provide a snippet of code with the fix, if possible.
+
+# Test info
+
+- Name: login/login-flow.spec.ts >> login with valid credentials redirects to /admin and shows admin dashboard
+- Location: tests/login/login-flow.spec.ts:6:5
+
+# Error details
+
+```
+Error: page.fill: value: expected string, got undefined
+```
+
+# Page snapshot
+
+```yaml
+- generic [active] [ref=e1]:
+ - banner [ref=e2]:
+ - generic [ref=e3]:
+ - link "Route Commerce" [ref=e4] [cursor=pointer]:
+ - /url: /
+ - navigation [ref=e5]:
+ - link "Tuxedo" [ref=e6] [cursor=pointer]:
+ - /url: /tuxedo
+ - link "IRD" [ref=e7] [cursor=pointer]:
+ - /url: /indian-river-direct
+ - link "Admin" [ref=e8] [cursor=pointer]:
+ - /url: /admin
+ - button "Switch to dark mode" [ref=e9]:
+ - img [ref=e10]
+ - link "Cart (0)" [ref=e12] [cursor=pointer]:
+ - /url: /cart
+ - main [ref=e13]:
+ - generic [ref=e14]:
+ - generic [ref=e15]:
+ - heading "Admin Login" [level=1] [ref=e16]
+ - paragraph [ref=e17]: Sign in with your account.
+ - generic [ref=e18]:
+ - generic [ref=e19]:
+ - generic [ref=e20]: Email
+ - textbox "Email" [ref=e21]:
+ - /placeholder: admin@example.com
+ - generic [ref=e22]:
+ - generic [ref=e23]: Password
+ - textbox "Password" [ref=e24]:
+ - /placeholder: ••••••••
+ - button "Sign In" [ref=e25]
+ - button "Forgot password?" [ref=e26]
+ - link "← Back to storefront" [ref=e27] [cursor=pointer]:
+ - /url: /
+ - contentinfo [ref=e28]:
+ - generic [ref=e30]:
+ - paragraph [ref=e31]: © 2026 Route Commerce. All rights reserved.
+ - navigation [ref=e32]:
+ - link "Privacy Policy" [ref=e33] [cursor=pointer]:
+ - /url: /privacy-policy
+ - link "Terms & Conditions" [ref=e34] [cursor=pointer]:
+ - /url: /terms-and-conditions
+ - link "Powered by Route Commerce" [ref=e35] [cursor=pointer]:
+ - /url: https://cielohermosa.com
+ - alert [ref=e36]
+```
+
+# Test source
+
+```ts
+ 1 | import { test, expect } from "@playwright/test";
+ 2 |
+ 3 | // ─────────────────────────────────────────────────────────────
+ 4 | // Login flow: credentials → /api/login JSON → redirect to /admin
+ 5 | // ─────────────────────────────────────────────────────────────
+ 6 | test("login with valid credentials redirects to /admin and shows admin dashboard", async ({
+ 7 | page,
+ 8 | }) => {
+ 9 | // Navigate to login page
+ 10 | await page.goto("/login");
+ 11 |
+ 12 | // Fill credentials
+> 13 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!);
+ | ^ Error: page.fill: value: expected string, got undefined
+ 14 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!);
+ 15 |
+ 16 | // Submit form
+ 17 | await page.click('button[type="submit"]');
+ 18 |
+ 19 | // Wait for navigation to /admin — the JSON response + client nav must happen
+ 20 | await page.waitForURL("**/admin", { timeout: 10000 });
+ 21 |
+ 22 | // Admin dashboard must be rendered (Control Center heading or admin layout)
+ 23 | await expect(page.locator("body")).not.toContainText("Access Denied");
+ 24 | await expect(page.locator("body")).not.toContainText("Login failed");
+ 25 | });
+ 26 |
+ 27 | // ─────────────────────────────────────────────────────────────
+ 28 | // Login failure: bad password shows error, stays on /login
+ 29 | // ─────────────────────────────────────────────────────────────
+ 30 | test("login with wrong password shows error and stays on /login", async ({
+ 31 | page,
+ 32 | }) => {
+ 33 | await page.goto("/login");
+ 34 |
+ 35 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!);
+ 36 | await page.fill("#password", "wrongpassword123!");
+ 37 |
+ 38 | await page.click('button[type="submit"]');
+ 39 |
+ 40 | // Error message should appear
+ 41 | await expect(page.locator('[role="alert"]')).toBeVisible({ timeout: 5000 });
+ 42 | // Should NOT navigate away from login
+ 43 | await expect(page).toHaveURL(/\/login/);
+ 44 | });
+ 45 |
+ 46 | // ─────────────────────────────────────────────────────────────
+ 47 | // Login with missing fields shows validation error
+ 48 | // ─────────────────────────────────────────────────────────────
+ 49 | test("login with missing email shows validation error", async ({ page }) => {
+ 50 | await page.goto("/login");
+ 51 |
+ 52 | // Don't fill email, only password
+ 53 | await page.fill("#password", "something");
+ 54 |
+ 55 | await page.click('button[type="submit"]');
+ 56 |
+ 57 | // Browser validation should fire (email required)
+ 58 | await expect(page.locator("#email")).toHaveAttribute("required", "");
+ 59 | });
+ 60 |
+ 61 | // ─────────────────────────────────────────────────────────────
+ 62 | // Session persistence: after login, navigating to /admin
+ 63 | // should load without re-authenticating
+ 64 | // ─────────────────────────────────────────────────────────────
+ 65 | test("admin session persists across page reloads", async ({ page }) => {
+ 66 | // Login first
+ 67 | await page.goto("/login");
+ 68 | await page.fill("#email", process.env.TEST_ADMIN_EMAIL!);
+ 69 | await page.fill("#password", process.env.TEST_ADMIN_PASSWORD!);
+ 70 | await page.click('button[type="submit"]');
+ 71 | await page.waitForURL("**/admin", { timeout: 10000 });
+ 72 |
+ 73 | // Reload the page
+ 74 | await page.reload();
+ 75 |
+ 76 | // Should still be on /admin (session cookie keeps user logged in)
+ 77 | await expect(page).toHaveURL(/\/admin/);
+ 78 | await expect(page.locator("body")).not.toContainText("Access Denied");
+ 79 | });
+ 80 |
+```
\ No newline at end of file