feat: initial commit — storefront, convex backend, and shared packages

Completes the first milestone of The Pet Loft ecommerce platform:
- apps/storefront: full customer-facing Next.js app with HeroUI (cart,
  checkout, orders, wishlist, product detail, shop, search, auth)
- convex/: serverless backend with schema, queries, mutations, actions,
  HTTP routes, Stripe/Shippo integrations, and co-located tests
- packages/types, packages/utils, packages/convex: shared workspace packages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 09:31:18 +03:00
commit cc15338ad9
361 changed files with 45005 additions and 0 deletions

View File

@@ -0,0 +1,145 @@
/**
* @vitest-environment happy-dom
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useRef } from "react";
import { useClickOutside } from "./useClickOutside";
function fireMouseDown(target: EventTarget) {
target.dispatchEvent(new MouseEvent("mousedown", { bubbles: true }));
}
describe("useClickOutside", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("does not call handler when enabled is false", () => {
const handler = vi.fn();
const { result } = renderHook(() => {
const ref = useRef<HTMLDivElement>(document.createElement("div"));
useClickOutside([ref], handler, false);
return ref;
});
act(() => fireMouseDown(document.body));
expect(handler).not.toHaveBeenCalled();
});
it("calls handler when clicking outside all refs", () => {
const handler = vi.fn();
const el = document.createElement("div");
document.body.appendChild(el);
renderHook(() => {
const ref = useRef<HTMLDivElement>(el);
useClickOutside([ref], handler, true);
});
act(() => fireMouseDown(document.body));
expect(handler).toHaveBeenCalledTimes(1);
document.body.removeChild(el);
});
it("does not call handler when clicking inside the ref element", () => {
const handler = vi.fn();
const el = document.createElement("div");
document.body.appendChild(el);
renderHook(() => {
const ref = useRef<HTMLDivElement>(el);
useClickOutside([ref], handler, true);
});
act(() => fireMouseDown(el));
expect(handler).not.toHaveBeenCalled();
document.body.removeChild(el);
});
it("does not call handler when clicking inside a child of the ref element", () => {
const handler = vi.fn();
const parent = document.createElement("div");
const child = document.createElement("button");
parent.appendChild(child);
document.body.appendChild(parent);
renderHook(() => {
const ref = useRef<HTMLDivElement>(parent);
useClickOutside([ref], handler, true);
});
act(() => fireMouseDown(child));
expect(handler).not.toHaveBeenCalled();
document.body.removeChild(parent);
});
it("does not call handler when clicking inside any of multiple refs", () => {
const handler = vi.fn();
const el1 = document.createElement("div");
const el2 = document.createElement("div");
document.body.appendChild(el1);
document.body.appendChild(el2);
renderHook(() => {
const ref1 = useRef<HTMLDivElement>(el1);
const ref2 = useRef<HTMLDivElement>(el2);
useClickOutside([ref1, ref2], handler, true);
});
act(() => fireMouseDown(el1));
expect(handler).not.toHaveBeenCalled();
act(() => fireMouseDown(el2));
expect(handler).not.toHaveBeenCalled();
document.body.removeChild(el1);
document.body.removeChild(el2);
});
it("stops calling handler after enabled becomes false", () => {
const handler = vi.fn();
const el = document.createElement("div");
document.body.appendChild(el);
const { rerender } = renderHook(
({ enabled }: { enabled: boolean }) => {
const ref = useRef<HTMLDivElement>(el);
useClickOutside([ref], handler, enabled);
},
{ initialProps: { enabled: true } },
);
act(() => fireMouseDown(document.body));
expect(handler).toHaveBeenCalledTimes(1);
rerender({ enabled: false });
act(() => fireMouseDown(document.body));
expect(handler).toHaveBeenCalledTimes(1); // no additional calls
document.body.removeChild(el);
});
it("removes listener on unmount", () => {
const handler = vi.fn();
const el = document.createElement("div");
document.body.appendChild(el);
const { unmount } = renderHook(() => {
const ref = useRef<HTMLDivElement>(el);
useClickOutside([ref], handler, true);
});
unmount();
act(() => fireMouseDown(document.body));
expect(handler).not.toHaveBeenCalled();
document.body.removeChild(el);
});
});