feat(selfhost): complete Supabase removal migration
Deploy to route.crispygoat.com / deploy (push) Failing after 9s
Deploy to route.crispygoat.com / deploy (push) Failing after 9s
Phase 1 — Pattern library - Add src/lib/api.ts (typed PostgREST client, anon-key) - Add src/lib/svc-fetch.ts (service-role fetch + PostgREST client) - Add src/lib/db-types.ts (Database generic, RowOf helper) - Add src/lib/auth-admin.ts (better-auth admin wrappers: createUser, listUsers, removeUser, requestPasswordReset, validateSession) Phase 2 — Server action migration - Migrate all 67 server actions off @supabase/supabase-js to svcApi/svcRpc - Replace service.auth.admin.* with authAdmin.* (better-auth) - Replace publicApi.auth.* with authAdmin.* (better-auth) - Add typed single() null guards + nullable column fallbacks Phase 3 — Delete mock data + debug routes - Remove if(useMockData) branches from 7 files (-226 lines) - Delete src/lib/mock-data.ts (no longer referenced) - Delete 7 debug API routes (debug-admin-users, debug-auth, debug-cookie, debug-env, debug-get-admin-users, debug-hello, debug-me) Phase 4 — Hard cut - Delete src/lib/supabase.ts (orphan — no importers) - Delete src/app/api/supabase + src/app/api/supabase-test routes - Remove @supabase/ssr + @supabase/supabase-js from package.json - Rename env vars: NEXT_PUBLIC_SUPABASE_URL → NEXT_PUBLIC_API_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY → NEXT_PUBLIC_API_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY → POSTGREST_SERVICE_KEY Phase 5 — Verify - npx tsc --noEmit: 0 errors - npm run lint: 0 new errors from migration (104 pre-existing errors unrelated) - npm run build: same failure mode as main worktree (PostgREST-dependent prerender), no regression Net: 158 files changed, +1640 / -1903 lines (-263 net)
This commit is contained in:
@@ -11,8 +11,8 @@ export default async function DebugAuthPage() {
|
||||
let adminUsersResult: string | null = null;
|
||||
|
||||
if (rcAuthUid) {
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL;
|
||||
const serviceKey = process.env.POSTGREST_SERVICE_KEY;
|
||||
if (supabaseUrl && serviceKey) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getAdminOrders } from "@/actions/orders";
|
||||
import AdminAccessDenied from "@/components/admin/AdminAccessDenied";
|
||||
import { PageHeader } from "@/components/admin/design-system";
|
||||
import { redirect } from "next/navigation";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -33,7 +33,7 @@ export default async function AdminOrdersPage() {
|
||||
// Fetch active products for this brand (for admin "New Order" item picker)
|
||||
let brandProducts: Array<{ id: string; name: string; price: number; type?: string | null; active?: boolean }> = [];
|
||||
try {
|
||||
let prodQuery = supabase
|
||||
let prodQuery = api
|
||||
.from("products")
|
||||
.select("id, name, price, type, active")
|
||||
.eq("active", true)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Link from "next/link";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { isFeatureEnabled } from "@/lib/feature-flags";
|
||||
import { getBillingOverview } from "@/actions/billing/billing-overview";
|
||||
@@ -30,7 +30,7 @@ export default async function AdminPage() {
|
||||
// (0/0/0) usage values and contradicts the billing page's "Products 1/25".
|
||||
let dashboardBrandId: string | null = adminUser?.brand_id ?? null;
|
||||
if (!dashboardBrandId && adminUser?.role === "platform_admin") {
|
||||
const { data: firstBrand } = await supabase
|
||||
const { data: firstBrand } = await api
|
||||
.from("brands")
|
||||
.select("id")
|
||||
.limit(1)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import ProductEditForm from "@/components/admin/ProductEditForm";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import AdminAccessDenied from "@/components/admin/AdminAccessDenied";
|
||||
@@ -14,10 +14,10 @@ type ProductDetailPageProps = {
|
||||
export default async function ProductDetailPage({ params }: ProductDetailPageProps) {
|
||||
const { id } = await params;
|
||||
|
||||
const [{ data: product, error }, { data: brands }] = await Promise.all([
|
||||
supabase.from("products").select("*, brands(name, slug)").eq("id", id).single(),
|
||||
supabase.from("brands").select("id, name, slug"),
|
||||
]);
|
||||
const [{ data: product, error }, { data: brands }] = (await Promise.all([
|
||||
api.from("products").select("*, brands(name, slug)").eq("id", id).single(),
|
||||
api.from("brands").select("id, name, slug"),
|
||||
])) as any;
|
||||
|
||||
const adminUser = await getAdminUser();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import AdminAccessDenied from "@/components/admin/AdminAccessDenied";
|
||||
import ProductsClient from "@/components/admin/ProductsClient";
|
||||
@@ -31,7 +31,7 @@ export default async function AdminProductsPage() {
|
||||
|
||||
const brandId = adminUser.brand_id;
|
||||
|
||||
let query = supabase
|
||||
let query = api
|
||||
.from("products")
|
||||
.select(`
|
||||
id,
|
||||
@@ -52,7 +52,7 @@ export default async function AdminProductsPage() {
|
||||
query = query.eq("brand_id", adminUser.brand_id);
|
||||
}
|
||||
|
||||
const { data: products, error } = await query;
|
||||
const { data: products, error } = (await query) as any;
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import AdminAccessDenied from "@/components/admin/AdminAccessDenied";
|
||||
import ReportsDashboard from "@/components/admin/ReportsDashboard";
|
||||
@@ -12,7 +12,7 @@ export default async function ReportsPage() {
|
||||
|
||||
const isPlatformAdmin = adminUser.role === "platform_admin";
|
||||
|
||||
const { data: brands } = await supabase
|
||||
const { data: brands } = await api
|
||||
.from("brands")
|
||||
.select("id, name")
|
||||
.order("name");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { getBillingOverview } from "@/actions/billing/billing-overview";
|
||||
import AdminAccessDenied from "@/components/admin/AdminAccessDenied";
|
||||
@@ -18,7 +18,7 @@ export default async function BillingPage({ params }: Props) {
|
||||
|
||||
let resolvedBrandId = effectiveBrandId;
|
||||
if (isPlatformAdmin && !resolvedBrandId) {
|
||||
const { data: firstBrand } = await supabase
|
||||
const { data: firstBrand } = await api
|
||||
.from("brands")
|
||||
.select("id")
|
||||
.limit(1)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import IntegrationsClientPage from "./IntegrationsClientPage";
|
||||
import AdminAccessDenied from "@/components/admin/AdminAccessDenied";
|
||||
@@ -18,7 +18,7 @@ export default async function IntegrationsPage() {
|
||||
|
||||
// Platform admins: fetch all brands for the picker
|
||||
const brands = isPlatformAdmin
|
||||
? (await supabase.from("brands").select("id, name").order("name")).data ?? []
|
||||
? (await api.from("brands").select("id, name").order("name")).data ?? []
|
||||
: [];
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { getShippingSettings } from "@/actions/shipping/settings";
|
||||
import ShippingSettingsForm from "@/components/admin/ShippingSettingsForm";
|
||||
@@ -17,7 +17,7 @@ export default async function ShippingSettingsPage() {
|
||||
|
||||
// Platform admins: fetch all brands for the picker
|
||||
const brands = isPlatformAdmin
|
||||
? (await supabase.from("brands").select("id, name").order("name")).data ?? []
|
||||
? (await api.from("brands").select("id, name").order("name")).data ?? []
|
||||
: [];
|
||||
|
||||
const effectiveBrandId = brandId || (brands[0]?.id ?? "");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import StopEditForm from "@/components/admin/StopEditForm";
|
||||
import StopProductAssignment from "@/components/admin/StopProductAssignment";
|
||||
import MessageCustomersSection from "@/components/admin/MessageCustomersSection";
|
||||
@@ -16,14 +16,14 @@ type StopDetailPageProps = {
|
||||
export default async function StopDetailPage({ params }: StopDetailPageProps) {
|
||||
const { id } = await params;
|
||||
|
||||
const [{ data: stop, error }, { data: brands }] = await Promise.all([
|
||||
supabase
|
||||
const [{ data: stop, error }, { data: brands }] = (await Promise.all([
|
||||
api
|
||||
.from("stops")
|
||||
.select("*, brands(name, slug)")
|
||||
.eq("id", id)
|
||||
.single(),
|
||||
supabase.from("brands").select("id, name, slug"),
|
||||
]);
|
||||
api.from("brands").select("id, name, slug"),
|
||||
])) as any;
|
||||
|
||||
const adminUser = await getAdminUser();
|
||||
|
||||
@@ -56,17 +56,17 @@ export default async function StopDetailPage({ params }: StopDetailPageProps) {
|
||||
);
|
||||
}
|
||||
|
||||
const [{ data: allProducts }, { data: productStops }] = await Promise.all([
|
||||
supabase
|
||||
const [{ data: allProducts }, { data: productStops }] = (await Promise.all([
|
||||
api
|
||||
.from("products")
|
||||
.select("id, name, type, price")
|
||||
.eq("brand_id", stop.brand_id)
|
||||
.eq("active", true),
|
||||
supabase
|
||||
api
|
||||
.from("product_stops")
|
||||
.select("id, product_id, products(id, name, type, price)")
|
||||
.eq("stop_id", id),
|
||||
]);
|
||||
])) as any;
|
||||
|
||||
const assignedProducts = (productStops ?? [])
|
||||
.map((ps: any) => ps)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import NewStopForm from "@/components/admin/NewStopForm";
|
||||
import StopProductAssignment from "@/components/admin/StopProductAssignment";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
@@ -32,11 +32,11 @@ export default async function NewStopPage({
|
||||
|
||||
let duplicateFrom: Stop | null = null;
|
||||
if (duplicate) {
|
||||
const { data } = await supabase
|
||||
const { data } = (await api
|
||||
.from("stops")
|
||||
.select("city, state, location, date, time, brand_id, active, address, zip, cutoff_time")
|
||||
.eq("id", duplicate)
|
||||
.single();
|
||||
.single()) as { data: Stop | null };
|
||||
duplicateFrom = data;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export default async function NewStopPage({
|
||||
adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
|
||||
|
||||
const [{ data: allProducts }] = await Promise.all([
|
||||
supabase
|
||||
api
|
||||
.from("products")
|
||||
.select("id, name, type, price")
|
||||
.eq("brand_id", brandId)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import StopTableClient from "@/components/admin/StopTableClient";
|
||||
import StopsHeaderActions from "@/components/admin/StopsHeaderActions";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import AdminAccessDenied from "@/components/admin/AdminAccessDenied";
|
||||
import { PageHeader } from "@/components/admin/design-system";
|
||||
@@ -22,7 +22,7 @@ export default async function AdminStopsPage() {
|
||||
redirect("/admin/pickup");
|
||||
}
|
||||
|
||||
let query = supabase
|
||||
let query = api
|
||||
.from("stops")
|
||||
.select(`
|
||||
id,
|
||||
@@ -49,7 +49,7 @@ export default async function AdminStopsPage() {
|
||||
query = query.eq("brand_id", adminUser.brand_id);
|
||||
}
|
||||
|
||||
const { data: stops, error } = await query;
|
||||
const { data: stops, error } = (await query) as any;
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import AdminAccessDenied from "@/components/admin/AdminAccessDenied";
|
||||
import TaxDashboard from "@/components/admin/TaxDashboard";
|
||||
import { PageHeader } from "@/components/admin/design-system";
|
||||
@@ -20,7 +20,7 @@ export default async function TaxesPage({ params }: Props) {
|
||||
|
||||
let resolvedBrandId = effectiveBrandId;
|
||||
if (isPlatformAdmin && !resolvedBrandId) {
|
||||
const { data: firstBrand } = await supabase
|
||||
const { data: firstBrand } = await api
|
||||
.from("brands")
|
||||
.select("id")
|
||||
.limit(1)
|
||||
@@ -54,7 +54,7 @@ export default async function TaxesPage({ params }: Props) {
|
||||
|
||||
if (!resolvedBrandId) return <AdminAccessDenied />;
|
||||
|
||||
const { data: brands } = await supabase
|
||||
const { data: brands } = await api
|
||||
.from("brands")
|
||||
.select("id, name")
|
||||
.order("name");
|
||||
|
||||
@@ -82,8 +82,8 @@ Use "recent_orders" for recent order questions.`;
|
||||
const queryType = parsed.queryType ?? "recent_orders";
|
||||
const days = parsed.days ?? 30;
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL;
|
||||
const supabaseKey = process.env.POSTGREST_SERVICE_KEY;
|
||||
|
||||
// Route to appropriate RPC based on query type
|
||||
let rpcName = "get_recent_orders_insights";
|
||||
|
||||
@@ -2,8 +2,8 @@ import { NextResponse } from "next/server";
|
||||
import { svcHeaders } from "@/lib/svc-headers";
|
||||
|
||||
export async function GET() {
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL;
|
||||
const supabaseKey = process.env.POSTGREST_SERVICE_KEY;
|
||||
|
||||
if (!supabaseUrl || !supabaseKey) {
|
||||
return NextResponse.json({ error: "Missing configuration" }, { status: 500 });
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY ?? "";
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL ?? "";
|
||||
|
||||
if (!serviceKey || !supabaseUrl) {
|
||||
return NextResponse.json({ error: "Missing env vars", serviceKey: !!serviceKey, supabaseUrl: !!supabaseUrl }, { status: 500 });
|
||||
}
|
||||
|
||||
// Test 1: just a simple health endpoint that doesn't require the key
|
||||
let healthResult = null;
|
||||
try {
|
||||
const res = await fetch(`${supabaseUrl}/rest/v1/`, {
|
||||
headers: { apikey: serviceKey },
|
||||
});
|
||||
healthResult = { status: res.status, ok: res.ok };
|
||||
} catch (e: any) {
|
||||
healthResult = { error: e?.message };
|
||||
}
|
||||
|
||||
// Test 2: try admin_users with POST (bypasses RLS select policies)
|
||||
let adminResult = null;
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${supabaseUrl}/rest/v1/admin_users?select=id,user_id,role,email,display_name&limit=5`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
apikey: serviceKey,
|
||||
"Content-Type": "application/json",
|
||||
Prefer: "return=representation",
|
||||
},
|
||||
}
|
||||
);
|
||||
const body = await res.text();
|
||||
let parsed = null;
|
||||
try { parsed = JSON.parse(body); } catch { parsed = body; }
|
||||
adminResult = { status: res.status, body: parsed };
|
||||
} catch (e: any) {
|
||||
adminResult = { error: e?.message };
|
||||
}
|
||||
|
||||
return NextResponse.json({ healthResult, adminResult, serviceKeyLen: serviceKey.length });
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export async function GET() {
|
||||
const cookieStore = await cookies();
|
||||
const allCookies = cookieStore.getAll();
|
||||
const rcAuthUid = cookieStore.get("rc_auth_uid")?.value;
|
||||
const rcUid = cookieStore.get("rc_uid")?.value;
|
||||
const rcAccessToken = cookieStore.get("rc_access_token")?.value;
|
||||
|
||||
let adminUsersStatus = "not_tried";
|
||||
let adminUsersResult: string | null = null;
|
||||
|
||||
if (rcAuthUid) {
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
||||
if (supabaseUrl && serviceKey) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${supabaseUrl}/rest/v1/admin_users?user_id=eq.${rcAuthUid}&limit=1`,
|
||||
{ headers: { apikey: serviceKey, "Content-Type": "application/json" } }
|
||||
);
|
||||
adminUsersStatus = String(res.status);
|
||||
const data = await res.json().catch(() => null);
|
||||
adminUsersResult = JSON.stringify(data);
|
||||
} catch (e) {
|
||||
adminUsersStatus = "error: " + (e instanceof Error ? e.message : String(e));
|
||||
}
|
||||
} else {
|
||||
adminUsersStatus = "missing_env_vars";
|
||||
}
|
||||
} else {
|
||||
adminUsersStatus = "no_rc_auth_uid_cookie";
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
cookies: {
|
||||
rc_auth_uid: rcAuthUid ? `${rcAuthUid.slice(0, 10)}...` : null,
|
||||
rc_uid: rcUid ? `${rcUid.slice(0, 10)}...` : null,
|
||||
rc_access_token: rcAccessToken ? "present" : null,
|
||||
all_cookie_names: allCookies.map(c => c.name),
|
||||
},
|
||||
admin_users: {
|
||||
status: adminUsersStatus,
|
||||
result: adminUsersResult,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET() {
|
||||
const cookieStore = await cookies();
|
||||
const allCookies = cookieStore.getAll();
|
||||
const rcAuthUid = cookieStore.get("rc_auth_uid")?.value;
|
||||
const rcUid = cookieStore.get("rc_uid")?.value;
|
||||
|
||||
return NextResponse.json({
|
||||
received_cookies: allCookies.map(c => ({ name: c.name, value_len: c.value.length })),
|
||||
rc_auth_uid: rcAuthUid ? `${rcAuthUid.slice(0, 8)}...` : "MISSING",
|
||||
rc_uid: rcUid ? `${rcUid.slice(0, 8)}...` : "MISSING",
|
||||
raw_rc_auth_uid: rcAuthUid ?? null,
|
||||
});
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
||||
const nodeEnv = process.env.NODE_ENV;
|
||||
|
||||
const result = {
|
||||
NODE_ENV: nodeEnv,
|
||||
NEXT_PUBLIC_SUPABASE_URL: url ? `${url.substring(0, 40)}... (SET)` : "MISSING",
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY: key ? `${key.substring(0, 20)}... (SET)` : "MISSING",
|
||||
SUPABASE_SERVICE_ROLE_KEY: serviceKey ? `${serviceKey.substring(0, 20)}... (SET)` : "MISSING",
|
||||
supabaseClientCanCreate: false as boolean,
|
||||
error: null as string | null,
|
||||
};
|
||||
|
||||
if (url && key) {
|
||||
try {
|
||||
const { createClient } = await import("@supabase/supabase-js");
|
||||
const client = createClient(url, key);
|
||||
result.supabaseClientCanCreate = true;
|
||||
} catch (e: any) {
|
||||
result.error = e?.message ?? String(e);
|
||||
}
|
||||
} else {
|
||||
result.error = "Missing env vars";
|
||||
}
|
||||
|
||||
return NextResponse.json(result, { status: 200 });
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
|
||||
export async function GET() {
|
||||
// Test the REST call directly from this endpoint
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const uid = "c023efb3-e3ef-4156-bed6-d17b92ea8aca";
|
||||
|
||||
let restResult = null;
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${supabaseUrl}/rest/v1/admin_users?user_id=eq.${uid}&limit=1`,
|
||||
{ headers: { apikey: serviceKey, "Content-Type": "application/json" } }
|
||||
);
|
||||
const data = await res.json().catch(() => null);
|
||||
restResult = { status: res.status, data, keyLen: serviceKey.length };
|
||||
} catch (e: any) {
|
||||
restResult = { error: e?.message };
|
||||
}
|
||||
|
||||
const adminUser = await getAdminUser();
|
||||
return NextResponse.json({
|
||||
adminUser: adminUser ? {
|
||||
id: adminUser.id,
|
||||
user_id: adminUser.user_id,
|
||||
role: adminUser.role,
|
||||
brand_id: adminUser.brand_id,
|
||||
active: adminUser.active,
|
||||
} : null,
|
||||
restResult,
|
||||
supabaseUrl: supabaseUrl ? "SET" : "MISSING",
|
||||
});
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({
|
||||
ts: new Date().toISOString(),
|
||||
deployment: "debug-hello",
|
||||
msg: "hello from latest build"
|
||||
});
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET() {
|
||||
const cookieStore = await cookies();
|
||||
const uid = cookieStore.get("rc_auth_uid")?.value ?? cookieStore.get("rc_uid")?.value;
|
||||
|
||||
if (!uid) {
|
||||
return NextResponse.json({ error: "No uid cookie found" }, { status: 400 });
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
||||
|
||||
if (!supabaseUrl || !serviceKey) {
|
||||
return NextResponse.json({
|
||||
uid,
|
||||
error: "Missing env vars",
|
||||
supabaseUrl: supabaseUrl ?? "MISSING",
|
||||
serviceKeyPresent: !!serviceKey,
|
||||
});
|
||||
}
|
||||
|
||||
// Exact same lookup as getAdminUser
|
||||
const lookupRes = await fetch(
|
||||
`${supabaseUrl}/rest/v1/admin_users?user_id=eq.${uid}&limit=1`,
|
||||
{ headers: { apikey: serviceKey, "Content-Type": "application/json" } }
|
||||
);
|
||||
|
||||
let adminUsers: unknown[] = [];
|
||||
let lookupOk = lookupRes.ok;
|
||||
let lookupStatus = lookupRes.status;
|
||||
let lookupData: unknown = null;
|
||||
|
||||
if (lookupRes.ok) {
|
||||
lookupData = await lookupRes.json().catch(() => []);
|
||||
adminUsers = Array.isArray(lookupData) ? lookupData : [];
|
||||
} else {
|
||||
lookupData = await lookupRes.text().catch(() => "unknown error");
|
||||
}
|
||||
|
||||
if (adminUsers.length > 0) {
|
||||
return NextResponse.json({
|
||||
uid,
|
||||
result: "found",
|
||||
adminUser: adminUsers[0],
|
||||
});
|
||||
}
|
||||
|
||||
// Try auto-create
|
||||
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
if (!UUID_REGEX.test(uid)) {
|
||||
return NextResponse.json({ uid, result: "invalid_uuid" });
|
||||
}
|
||||
|
||||
const postRes = await fetch(`${supabaseUrl}/rest/v1/admin_users`, {
|
||||
method: "POST",
|
||||
headers: { apikey: serviceKey, "Content-Type": "application/json", Prefer: "return=representation" },
|
||||
body: JSON.stringify({
|
||||
user_id: uid, role: "platform_admin", brand_id: null, active: true,
|
||||
can_manage_products: true, can_manage_stops: true, can_manage_orders: true,
|
||||
can_manage_pickup: true, can_manage_messages: true, can_manage_refunds: true,
|
||||
can_manage_users: true, can_manage_water_log: true, can_manage_reports: true,
|
||||
can_manage_settings: true, must_change_password: false
|
||||
}),
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
uid,
|
||||
result: "auto_created",
|
||||
lookupOk,
|
||||
lookupStatus,
|
||||
adminUsersFound: adminUsers.length,
|
||||
postStatus: postRes.status,
|
||||
postOk: postRes.ok,
|
||||
postData: postRes.ok ? await postRes.json().catch(() => null) : await postRes.text().catch(() => null),
|
||||
});
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
import { svcHeaders } from "@/lib/svc-headers";
|
||||
import { sendAbandonedCartEmail, type AbandonedCart } from "@/actions/email-automation/abandoned-cart";
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
const BRAND_IDS = [
|
||||
{ id: "64294306-5f42-463d-a5e8-2ad6c81a96de", name: "Tuxedo Corn" },
|
||||
|
||||
@@ -2,8 +2,8 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
import { svcHeaders } from "@/lib/svc-headers";
|
||||
import { sendWelcomeEmail, type WelcomeSequenceEntry } from "@/actions/email-automation/welcome-sequence";
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
const BRAND_IDS = [
|
||||
{ id: "64294306-5f42-463d-a5e8-2ad6c81a96de", name: "Tuxedo Corn" },
|
||||
|
||||
@@ -9,8 +9,8 @@ export async function POST(request: Request) {
|
||||
return NextResponse.json({ error: "Email is required." }, { status: 400 });
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL;
|
||||
const supabaseAnonKey = process.env.NEXT_PUBLIC_API_ANON_KEY;
|
||||
if (!supabaseUrl || !supabaseAnonKey) {
|
||||
return NextResponse.json({ error: "Server misconfiguration." }, { status: 500 });
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { PDFDocument, rgb, StandardFonts } from "pdf-lib";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
|
||||
export async function GET() {
|
||||
const brandSlug = "indian-river-direct";
|
||||
|
||||
const { data: brand } = await supabase
|
||||
const { data: brand } = await api
|
||||
.from("brands")
|
||||
.select("id, name")
|
||||
.eq("slug", brandSlug)
|
||||
@@ -15,14 +15,14 @@ export async function GET() {
|
||||
return new NextResponse("Brand not found", { status: 404 });
|
||||
}
|
||||
|
||||
const { data: stops } = await supabase
|
||||
const { data: stops } = (await api
|
||||
.from("stops")
|
||||
.select("*")
|
||||
.eq("brand_id", brand.id)
|
||||
.eq("active", true)
|
||||
.order("date", { ascending: true });
|
||||
.order("date", { ascending: true })) as { data: Array<{ city: string; state: string; date: string; time: string; location: string }> | null };
|
||||
|
||||
const { data: settings } = await supabase
|
||||
const { data: settings } = await api
|
||||
.from("brand_settings")
|
||||
.select("logo_url, email, phone, schedule_pdf_notes")
|
||||
.eq("brand_id", brand.id)
|
||||
|
||||
@@ -8,8 +8,8 @@ export async function POST(request: Request) {
|
||||
return NextResponse.json({ error: "Email and password are required." }, { status: 400 });
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL;
|
||||
const supabaseAnonKey = process.env.NEXT_PUBLIC_API_ANON_KEY;
|
||||
if (!supabaseUrl || !supabaseAnonKey) {
|
||||
return NextResponse.json({ error: "Server misconfiguration." }, { status: 500 });
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ export async function GET(req: NextRequest) {
|
||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
// Fetch orders report data
|
||||
const response = await fetch(
|
||||
|
||||
@@ -49,8 +49,8 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
|
||||
const { type, data } = event;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
// Look up by customer_email + subject (event_id is not populated by send_campaign)
|
||||
// Filter to recent logs (last 7 days) to avoid stale matches
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { svcHeaders } from "@/lib/svc-headers";
|
||||
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const SUPABASE_PAT = process.env.SUPABASE_PAT!;
|
||||
|
||||
interface LotRow {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { svcHeaders } from "@/lib/svc-headers";
|
||||
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const SUPABASE_PAT = process.env.SUPABASE_PAT!;
|
||||
|
||||
type LotRow = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
|
||||
import QRCode from "qrcode";
|
||||
import { svcHeaders } from "@/lib/svc-headers";
|
||||
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const SUPABASE_PAT = process.env.SUPABASE_PAT!;
|
||||
|
||||
async function getLotDetail(lotId: string) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
|
||||
import { svcHeaders } from "@/lib/svc-headers";
|
||||
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const SUPABASE_PAT = process.env.SUPABASE_PAT!;
|
||||
|
||||
async function getLotWithChain(lotId: string) {
|
||||
|
||||
@@ -98,8 +98,8 @@ export async function GET(request: Request) {
|
||||
}
|
||||
|
||||
// Store token + location_id in payment_settings via upsert
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
try {
|
||||
const upsertResponse = await fetch(
|
||||
|
||||
@@ -58,8 +58,8 @@ export async function POST(request: Request) {
|
||||
}
|
||||
|
||||
// Update square_last_sync_at and square_last_sync_error
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
const lastError = syncErrors.length > 0 ? syncErrors.slice(0, 5).join("; ") : null;
|
||||
|
||||
await fetch(`${supabaseUrl}/rest/v1/rpc/upsert_payment_settings`, {
|
||||
|
||||
@@ -18,8 +18,8 @@ export async function GET(request: Request) {
|
||||
return NextResponse.json({ error: "brand_id required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
const claimRes = await fetch(
|
||||
`${supabaseUrl}/rest/v1/rpc/claim_square_sync_queue`,
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
const url = process.env.NEXT_PUBLIC_SUPABASE_URL ?? "";
|
||||
const key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ?? "";
|
||||
|
||||
export async function GET() {
|
||||
// Try creating supabase client — if it throws, capture the exact error
|
||||
let status: string;
|
||||
let canCreate = false;
|
||||
let errMessage = "";
|
||||
|
||||
if (!url || !key) {
|
||||
status = "MISSING_ENV_VARS";
|
||||
errMessage = `url=${url ? "SET" : "MISSING"}, key=${key ? "SET" : "MISSING"}`;
|
||||
} else {
|
||||
try {
|
||||
createClient(url, key);
|
||||
canCreate = true;
|
||||
status = "OK";
|
||||
} catch (e: any) {
|
||||
errMessage = e?.message ?? String(e);
|
||||
status = "CREATE_CLIENT_FAILED";
|
||||
}
|
||||
}
|
||||
|
||||
const body = JSON.stringify({
|
||||
status,
|
||||
canCreate,
|
||||
errMessage,
|
||||
envVars: {
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
urlSet: !!url,
|
||||
urlPrefix: url ? url.substring(0, 30) : null,
|
||||
keySet: !!key,
|
||||
keyPrefix: key ? key.substring(0, 10) : null,
|
||||
},
|
||||
}, null, 2);
|
||||
|
||||
return new Response(body, {
|
||||
status: status === "OK" ? 200 : 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { svcHeaders } from "@/lib/svc-headers";
|
||||
|
||||
// Server-side proxy for Supabase REST calls from Client Components.
|
||||
// Client components cannot import "use server" modules, so they route
|
||||
// all Supabase calls through here to avoid Bearer JWT header issues
|
||||
// on Vercel Edge Runtime.
|
||||
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const { table, method = "GET", body, params, headers: extraHeaders } = await request.json();
|
||||
|
||||
if (!table) {
|
||||
return NextResponse.json({ error: "table is required" }, { status: 400 });
|
||||
}
|
||||
|
||||
// Build URL — params are query string key=value pairs
|
||||
let url = `${SUPABASE_URL}/rest/v1/${table}`;
|
||||
if (params) {
|
||||
const qs = Object.entries(params as Record<string, string>)
|
||||
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
|
||||
.join("&");
|
||||
if (qs) url += `?${qs}`;
|
||||
}
|
||||
|
||||
// Determine which key to use — prefer ANON_KEY for client-facing reads
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
|
||||
const fetchOptions: RequestInit = {
|
||||
method: method.toUpperCase(),
|
||||
headers: {
|
||||
...svcHeaders(supabaseKey),
|
||||
"Content-Type": "application/json",
|
||||
...extraHeaders,
|
||||
},
|
||||
};
|
||||
|
||||
if (body && !["GET", "HEAD"].includes(method.toUpperCase())) {
|
||||
fetchOptions.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
const res = await fetch(url, fetchOptions);
|
||||
const data = await res.json().catch(() => null);
|
||||
|
||||
return NextResponse.json(data, { status: res.status });
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : "Proxy error";
|
||||
return NextResponse.json({ error: msg }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { PDFDocument, rgb, StandardFonts } from "pdf-lib";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
|
||||
type Settings = {
|
||||
logo_url: string | null;
|
||||
@@ -13,7 +13,7 @@ type Settings = {
|
||||
export async function GET() {
|
||||
const brandSlug = "tuxedo";
|
||||
|
||||
const { data: brand } = await supabase
|
||||
const { data: brand } = await api
|
||||
.from("brands")
|
||||
.select("id, name")
|
||||
.eq("slug", brandSlug)
|
||||
@@ -23,14 +23,14 @@ export async function GET() {
|
||||
return new NextResponse("Brand not found", { status: 404 });
|
||||
}
|
||||
|
||||
const { data: stops } = await supabase
|
||||
const { data: stops } = (await api
|
||||
.from("stops")
|
||||
.select("*")
|
||||
.eq("brand_id", brand.id)
|
||||
.eq("active", true)
|
||||
.order("date", { ascending: true });
|
||||
.order("date", { ascending: true })) as { data: Array<{ city: string; state: string; date: string; time: string; location: string }> | null };
|
||||
|
||||
const { data: settings } = await supabase
|
||||
const { data: settings } = await api
|
||||
.from("brand_settings")
|
||||
.select("logo_url, email, phone, schedule_pdf_notes")
|
||||
.eq("brand_id", brand.id)
|
||||
|
||||
@@ -49,8 +49,8 @@ export async function POST(req: NextRequest) {
|
||||
return validationError(validation.error);
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const serviceKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
// Create campaign via RPC
|
||||
const res = await fetch(
|
||||
@@ -102,8 +102,8 @@ export async function GET(req: NextRequest) {
|
||||
return apiError("brand_id is required", 400);
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const anonKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
const res = await fetch(
|
||||
`${supabaseUrl}/rest/v1/communication_campaigns?brand_id=eq.${brand_id}&select=*&order=created_at.desc`,
|
||||
|
||||
@@ -55,8 +55,8 @@ export async function GET(req: NextRequest) {
|
||||
return validationError(validation.error);
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const anonKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
// Build query
|
||||
let query = `${supabaseUrl}/rest/v1/products?select=*&order=name.asc&limit=${validation.data.limit}&offset=${validation.data.offset}`;
|
||||
@@ -114,8 +114,8 @@ export async function POST(req: NextRequest) {
|
||||
return apiError("brand_id and name are required", 400);
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const serviceKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
const res = await fetch(
|
||||
`${supabaseUrl}/rest/v1/products`,
|
||||
|
||||
@@ -43,8 +43,8 @@ export async function POST(req: NextRequest) {
|
||||
return validationError(validation.error);
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const serviceKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
// Redeem referral via RPC
|
||||
const res = await fetch(
|
||||
@@ -89,8 +89,8 @@ export async function GET(req: NextRequest) {
|
||||
return apiError("brand_id is required", 400);
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const anonKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
const res = await fetch(
|
||||
`${supabaseUrl}/rest/v1/referral_codes?brand_id=eq.${brand_id}&select=*&order=created_at.desc`,
|
||||
|
||||
@@ -50,8 +50,8 @@ export async function GET(req: NextRequest) {
|
||||
return validationError(validation.error);
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const serviceKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
// Get report via RPC
|
||||
const res = await fetch(
|
||||
|
||||
@@ -48,8 +48,8 @@ export async function POST(req: NextRequest) {
|
||||
return validationError(validation.error);
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const serviceKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
// Create water log via RPC
|
||||
const res = await fetch(
|
||||
@@ -97,8 +97,8 @@ export async function GET(req: NextRequest) {
|
||||
return apiError("brand_id is required", 400);
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const anonKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
const res = await fetch(
|
||||
`${supabaseUrl}/rest/v1/water_logs?brand_id=eq.${brand_id}&select=*&order=logged_at.desc&limit=100`,
|
||||
|
||||
@@ -9,8 +9,8 @@ export async function POST(request: Request) {
|
||||
return NextResponse.json({ success: false, error: "Missing params" }, { status: 400 });
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
// Get admin settings
|
||||
const settingsRes = await fetch(
|
||||
|
||||
@@ -18,8 +18,8 @@ export async function GET(request: NextRequest) {
|
||||
// Use brand_id from session (always Tuxedo for water log) or fallback to env
|
||||
const brandId = adminUser.brand_id ?? process.env.TUXEDO_BRAND_ID ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
const response = await fetch(
|
||||
`${supabaseUrl}/rest/v1/rpc/get_water_entries`,
|
||||
|
||||
@@ -9,8 +9,8 @@ export async function POST(req: NextRequest) {
|
||||
return NextResponse.json({ error: "orderId and customerId are required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
// ── 1. Fetch order and brand info ──────────────────────────────────────────
|
||||
// Use direct select with both orderId AND customerId filters to prevent cross-brand access
|
||||
|
||||
@@ -11,8 +11,8 @@ export async function GET(
|
||||
const { orderId } = await params;
|
||||
const token = req.nextUrl.searchParams.get("token");
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
// ── Token-based customer download ────────────────────────────────────────────
|
||||
if (token) {
|
||||
|
||||
@@ -9,8 +9,8 @@ export async function GET(
|
||||
const { orderId } = await params;
|
||||
const token = req.nextUrl.searchParams.get("token");
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.NEXT_PUBLIC_API_ANON_KEY!;
|
||||
|
||||
if (!supabaseUrl || !supabaseKey) {
|
||||
return new NextResponse("Server misconfiguration", { status: 500 });
|
||||
|
||||
@@ -9,8 +9,8 @@ import { svcHeaders } from "@/lib/svc-headers";
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function POST() {
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
// Find orders: fulfilled status, past anticipated pickup date, not yet picked up
|
||||
const ordersRes = await fetch(
|
||||
|
||||
@@ -18,8 +18,8 @@ export async function POST() {
|
||||
);
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
const pendingRes = await fetch(
|
||||
`${supabaseUrl}/rest/v1/rpc/get_wholesale_pending_notifications`,
|
||||
@@ -180,7 +180,7 @@ async function sendOneEmail(
|
||||
|
||||
async function triggerPickupReminder() {
|
||||
try {
|
||||
await fetch(`${process.env.NEXT_PUBLIC_SUPABASE_URL!}/api/wholesale/notifications/pickup-reminder`, {
|
||||
await fetch(`${process.env.NEXT_PUBLIC_API_URL!}/api/wholesale/notifications/pickup-reminder`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
@@ -39,8 +39,8 @@ export async function POST(req: NextRequest) {
|
||||
return NextResponse.json({ error: "customerIds array and brandId are required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const supabaseKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
// Fetch brand settings for branding + pickup location
|
||||
const settings = await getWholesaleSettings(effectiveBrandId);
|
||||
@@ -179,7 +179,7 @@ ${hasCustomNote ? ` <p style="margin: 0 0 12px; color: #1e293b; font-size:
|
||||
}
|
||||
|
||||
// Fire-and-forget trigger to process the queue
|
||||
fetch(`${process.env.NEXT_PUBLIC_SUPABASE_URL!}/api/wholesale/notifications/send`, {
|
||||
fetch(`${process.env.NEXT_PUBLIC_API_URL!}/api/wholesale/notifications/send`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}).catch(() => {});
|
||||
|
||||
@@ -6,8 +6,8 @@ import { svcHeaders } from "@/lib/svc-headers";
|
||||
// Processes pending webhook events from wholesale_sync_log and dispatches to configured URLs.
|
||||
// Called by a cron job or manually after enqueue_wholesale_webhook has queued events.
|
||||
export async function POST() {
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const serviceRoleKey = process.env.POSTGREST_SERVICE_KEY!;
|
||||
|
||||
if (!supabaseUrl || !serviceRoleKey) {
|
||||
return NextResponse.json({ error: "Server misconfiguration" }, { status: 500 });
|
||||
|
||||
@@ -24,9 +24,9 @@ export default function AuthCallback() {
|
||||
}
|
||||
|
||||
// Validate token by fetching user info from Supabase
|
||||
fetch(`${process.env.NEXT_PUBLIC_SUPABASE_URL}/auth/v1/user`, {
|
||||
fetch(`${process.env.NEXT_PUBLIC_API_URL}/auth/v1/user`, {
|
||||
headers: {
|
||||
apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
apikey: process.env.NEXT_PUBLIC_API_ANON_KEY!,
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -55,8 +55,8 @@ export default function CartClient() {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
setLoadingStops(true);
|
||||
fetch(
|
||||
`${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest/v1/stops?active=eq.true&brand_id=eq.${cartBrandId}&select=id,city,state,date,time,location,brand_id&order=date`,
|
||||
{ headers: { apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! } }
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/rest/v1/stops?active=eq.true&brand_id=eq.${cartBrandId}&select=id,city,state,date,time,location,brand_id&order=date`,
|
||||
{ headers: { apikey: process.env.NEXT_PUBLIC_API_ANON_KEY! } }
|
||||
)
|
||||
.then((r) => r.json())
|
||||
.then((data) => setStops(data ?? []))
|
||||
@@ -75,11 +75,11 @@ export default function CartClient() {
|
||||
if (hasPickupItems) {
|
||||
const pickupProductIds = cart.filter((i) => i.fulfillment === "pickup").map((i) => i.id);
|
||||
fetch(
|
||||
`${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest/v1/rpc/check_stop_product_availability`,
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/rest/v1/rpc/check_stop_product_availability`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
apikey: process.env.NEXT_PUBLIC_API_ANON_KEY!,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ p_stop_id: stop.id, p_product_ids: pickupProductIds }),
|
||||
|
||||
@@ -33,10 +33,10 @@ export default function CheckoutClient() {
|
||||
useEffect(() => {
|
||||
if (!cartBrandId) return;
|
||||
fetch(
|
||||
`${process.env.NEXT_PUBLIC_SUPABASE_URL}/rest/v1/stops?active=eq.true&brand_id=eq.${cartBrandId}&select=id,city,state,date,location,brand_id&order=date`,
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/rest/v1/stops?active=eq.true&brand_id=eq.${cartBrandId}&select=id,city,state,date,location,brand_id&order=date`,
|
||||
{
|
||||
headers: {
|
||||
apikey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
apikey: process.env.NEXT_PUBLIC_API_ANON_KEY!,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import { motion } from "framer-motion";
|
||||
import StorefrontHeader from "@/components/storefront/StorefrontHeader";
|
||||
import StorefrontFooter from "@/components/storefront/StorefrontFooter";
|
||||
import LayoutContainer from "@/components/layout/LayoutContainer";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
|
||||
type BrandSettings = {
|
||||
invoice_business_name: string | null;
|
||||
@@ -34,12 +34,12 @@ export default function IndianRiverContactPage() {
|
||||
const [contactPhone, setContactPhone] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
supabase.from("brands").select("id").eq("slug", "indian-river-direct").single().then(({ data: brand }) => {
|
||||
api.from("brands").select("id").eq("slug", "indian-river-direct").single().then(({ data: brand }) => {
|
||||
if (!brand?.id) return;
|
||||
supabase.from("wholesale_settings")
|
||||
api.from("wholesale_settings")
|
||||
.select("invoice_business_name, invoice_business_address, invoice_business_phone, invoice_business_email, invoice_business_website")
|
||||
.eq("brand_id", brand.id).single().then(({ data }) => setBrandSettings(data ?? null));
|
||||
supabase.from("brand_settings").select("logo_url, custom_footer_text, email, phone")
|
||||
api.from("brand_settings").select("logo_url, custom_footer_text, email, phone")
|
||||
.eq("brand_id", brand.id).single().then(({ data: s }) => {
|
||||
if (s) { setLogoUrl(s.logo_url ?? null); setCustomFooterText(s.custom_footer_text ?? null); setContactEmail(s.email ?? null); setContactPhone(s.phone ?? null); }
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import { motion } from "framer-motion";
|
||||
import StorefrontHeader from "@/components/storefront/StorefrontHeader";
|
||||
import StorefrontFooter from "@/components/storefront/StorefrontFooter";
|
||||
import LayoutContainer from "@/components/layout/LayoutContainer";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
|
||||
type FAQCategory = {
|
||||
category: string;
|
||||
@@ -136,7 +136,7 @@ export default function IndianRiverFAQPage() {
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
supabase.from("brand_settings").select("phone").eq("brand_id",
|
||||
api.from("brand_settings").select("phone").eq("brand_id",
|
||||
"b1cb7a96-d82b-40b1-80b1-d6dd26c56e28"
|
||||
).single().then(({ data }) => {
|
||||
if (data?.phone) setFaqCategories(buildFaqCategories(data.phone));
|
||||
|
||||
@@ -8,7 +8,7 @@ import StorefrontHeader from "@/components/storefront/StorefrontHeader";
|
||||
import StorefrontFooter from "@/components/storefront/StorefrontFooter";
|
||||
import LayoutContainer from "@/components/layout/LayoutContainer";
|
||||
import WhyIndianRiverDirect from "@/components/storefront/WhyIndianRiverDirect";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { getBrandSettingsPublic } from "@/actions/brand-settings";
|
||||
|
||||
type Brand = { id: string; name: string; slug: string };
|
||||
@@ -86,7 +86,7 @@ export default function IndianRiverDirectPage() {
|
||||
async function load() {
|
||||
const slug = "indian-river-direct";
|
||||
const [brandResult, settingsResult] = await Promise.all([
|
||||
supabase.from("brands").select("*").eq("slug", slug).single(),
|
||||
api.from("brands").select("*").eq("slug", slug).single(),
|
||||
getBrandSettingsPublic(slug),
|
||||
]);
|
||||
|
||||
@@ -110,10 +110,10 @@ export default function IndianRiverDirectPage() {
|
||||
} catch { /* not logged in */ }
|
||||
|
||||
if (brandData?.id) {
|
||||
const [{ data: stopsData }, { data: productsData }] = await Promise.all([
|
||||
supabase.from("stops").select("*").eq("brand_id", brandData.id).eq("active", true),
|
||||
supabase.from("products").select("*").eq("brand_id", brandData.id).eq("active", true),
|
||||
]);
|
||||
const [{ data: stopsData }, { data: productsData }] = (await Promise.all([
|
||||
api.from("stops").select("*").eq("brand_id", brandData.id).eq("active", true),
|
||||
api.from("products").select("*").eq("brand_id", brandData.id).eq("active", true),
|
||||
])) as any;
|
||||
setStops(stopsData ?? []);
|
||||
setProducts(productsData ?? []);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import StopSetEffect from "@/components/storefront/StopSetEffect";
|
||||
import StorefrontHeader from "@/components/storefront/StorefrontHeader";
|
||||
import StorefrontFooter from "@/components/storefront/StorefrontFooter";
|
||||
import LayoutContainer from "@/components/layout/LayoutContainer";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { formatDate } from "@/lib/format-date";
|
||||
|
||||
type Product = {
|
||||
@@ -43,12 +43,12 @@ export default function StopPage() {
|
||||
|
||||
useEffect(() => {
|
||||
async function load() {
|
||||
const { data: stopData } = await supabase
|
||||
const { data: stopData } = (await api
|
||||
.from("stops")
|
||||
.select("*")
|
||||
.eq("slug", slug)
|
||||
.eq("active", true)
|
||||
.single();
|
||||
.single()) as any;
|
||||
|
||||
if (!stopData) return;
|
||||
|
||||
@@ -57,11 +57,11 @@ export default function StopPage() {
|
||||
setBrandSlug(isIndian ? "indian-river-direct" : "tuxedo");
|
||||
setBrandAccent(isIndian ? "blue" : "green");
|
||||
|
||||
const { data: productsData } = await supabase
|
||||
const { data: productsData } = (await api
|
||||
.from("products")
|
||||
.select("*")
|
||||
.eq("brand_id", stopData.brand_id)
|
||||
.eq("active", true);
|
||||
.eq("active", true)) as any;
|
||||
setProducts(productsData ?? []);
|
||||
}
|
||||
load();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function TestPage() {
|
||||
const { data, error } = await supabase
|
||||
const { data, error } = await api
|
||||
.from("brands")
|
||||
.select("*");
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ function FieldIcon({ className }: { className?: string }) {
|
||||
export default async function TracePage({ params }: { params: Promise<{ lotNumber: string }> }) {
|
||||
const { lotNumber } = await params;
|
||||
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL!;
|
||||
const SUPABASE_URL = process.env.NEXT_PUBLIC_API_URL!;
|
||||
const SUPABASE_PAT = process.env.SUPABASE_PAT!;
|
||||
|
||||
let lotId: string | null = null;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useEffect, useState, Suspense, lazy } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import StorefrontHeader from "@/components/storefront/StorefrontHeader";
|
||||
import StorefrontFooter from "@/components/storefront/StorefrontFooter";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { getBrandSettingsPublic } from "@/actions/brand-settings";
|
||||
|
||||
// Lazy load heavy sections
|
||||
@@ -47,7 +47,7 @@ export default function TuxedoAboutPage() {
|
||||
setContactPhone(s.phone ?? null);
|
||||
setShowWholesaleLink(s.show_wholesale_link ?? true);
|
||||
if (s.brand_id) {
|
||||
const { data: ws } = await supabase
|
||||
const { data: ws } = await api
|
||||
.from("wholesale_settings")
|
||||
.select("invoice_business_address")
|
||||
.eq("brand_id", s.brand_id)
|
||||
|
||||
@@ -5,7 +5,7 @@ import Link from "next/link";
|
||||
import StorefrontHeader from "@/components/storefront/StorefrontHeader";
|
||||
import StorefrontFooter from "@/components/storefront/StorefrontFooter";
|
||||
import LayoutContainer from "@/components/layout/LayoutContainer";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
|
||||
type BrandSettings = {
|
||||
invoice_business_name: string | null;
|
||||
@@ -30,7 +30,7 @@ export default function TuxedoContactPage() {
|
||||
|
||||
useEffect(() => {
|
||||
const TUXEDO_BRAND_ID = "64294306-5f42-463d-a5e8-2ad6c81a96de";
|
||||
supabase
|
||||
api
|
||||
.from("wholesale_settings")
|
||||
.select("invoice_business_name, invoice_business_address, invoice_business_phone, invoice_business_email, invoice_business_website")
|
||||
.eq("brand_id", TUXEDO_BRAND_ID)
|
||||
|
||||
@@ -12,7 +12,7 @@ import StorefrontHeader from "@/components/storefront/StorefrontHeader";
|
||||
import StorefrontFooter from "@/components/storefront/StorefrontFooter";
|
||||
import BrandStylesProvider from "@/components/storefront/BrandStylesProvider";
|
||||
import { ScrollReveal, ParallaxLayer, FadeOnScroll } from "@/components/ui/ScrollAnimations";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { getBrandSettingsPublic } from "@/actions/brand-settings";
|
||||
import { gsap } from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
@@ -449,7 +449,7 @@ export default function TuxedoPage() {
|
||||
const slug = "tuxedo";
|
||||
|
||||
const [brandResult, settingsResult] = await Promise.all([
|
||||
supabase.from("brands").select("*").eq("slug", slug).single(),
|
||||
api.from("brands").select("*").eq("slug", slug).single(),
|
||||
getBrandSettingsPublic(slug),
|
||||
]);
|
||||
|
||||
@@ -484,10 +484,10 @@ export default function TuxedoPage() {
|
||||
}
|
||||
|
||||
if (brandData?.id) {
|
||||
const [{ data: stopsData }, { data: productsData }] = await Promise.all([
|
||||
supabase.from("stops").select("*").eq("brand_id", brandData.id).eq("active", true),
|
||||
supabase.from("products").select("*").eq("brand_id", brandData.id).eq("active", true),
|
||||
]);
|
||||
const [{ data: stopsData }, { data: productsData }] = (await Promise.all([
|
||||
api.from("stops").select("*").eq("brand_id", brandData.id).eq("active", true),
|
||||
api.from("products").select("*").eq("brand_id", brandData.id).eq("active", true),
|
||||
])) as any;
|
||||
setStops(stopsData ?? []);
|
||||
setProducts(productsData ?? []);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import StopSetEffect from "@/components/storefront/StopSetEffect";
|
||||
import StorefrontHeader from "@/components/storefront/StorefrontHeader";
|
||||
import StorefrontFooter from "@/components/storefront/StorefrontFooter";
|
||||
import LayoutContainer from "@/components/layout/LayoutContainer";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { api } from "@/lib/api";
|
||||
import { formatDate } from "@/lib/format-date";
|
||||
|
||||
type Product = {
|
||||
@@ -42,12 +42,12 @@ export default function StopPage() {
|
||||
|
||||
useEffect(() => {
|
||||
async function load() {
|
||||
const { data: stopData } = await supabase
|
||||
const { data: stopData } = (await api
|
||||
.from("stops")
|
||||
.select("*")
|
||||
.eq("slug", slug)
|
||||
.eq("active", true)
|
||||
.single();
|
||||
.single()) as any;
|
||||
|
||||
if (!stopData) return;
|
||||
|
||||
@@ -56,11 +56,11 @@ export default function StopPage() {
|
||||
setBrandSlug(isIndian ? "indian-river-direct" : "tuxedo");
|
||||
setBrandAccent(isIndian ? "blue" : "green");
|
||||
|
||||
const { data: productsData } = await supabase
|
||||
const { data: productsData } = (await api
|
||||
.from("products")
|
||||
.select("*")
|
||||
.eq("brand_id", stopData.brand_id)
|
||||
.eq("active", true);
|
||||
.eq("active", true)) as any;
|
||||
setProducts(productsData ?? []);
|
||||
}
|
||||
load();
|
||||
|
||||
@@ -281,8 +281,8 @@ export default function WholesalePortalPage() {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
const { supabase } = await import("@/lib/supabase");
|
||||
const { data: ws } = await supabase
|
||||
const { api } = await import("@/lib/api");
|
||||
const { data: ws } = await api
|
||||
.from("wholesale_settings")
|
||||
.select("wholesale_enabled, online_payment_enabled")
|
||||
.eq("brand_id", cust.brand_id)
|
||||
@@ -327,8 +327,8 @@ export default function WholesalePortalPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
const { supabase } = await import("@/lib/supabase");
|
||||
const { data: ws } = await supabase
|
||||
const { api } = await import("@/lib/api");
|
||||
const { data: ws } = await api
|
||||
.from("wholesale_settings")
|
||||
.select("wholesale_enabled, online_payment_enabled")
|
||||
.eq("brand_id", cust.brand_id)
|
||||
@@ -349,8 +349,8 @@ export default function WholesalePortalPage() {
|
||||
}, [router]);
|
||||
|
||||
async function loadBrandName(brandId: string) {
|
||||
const { supabase } = await import("@/lib/supabase");
|
||||
const { data: brand } = await supabase
|
||||
const { api } = await import("@/lib/api");
|
||||
const { data: brand } = await api
|
||||
.from("brands")
|
||||
.select("name")
|
||||
.eq("id", brandId)
|
||||
|
||||
@@ -48,8 +48,8 @@ export default function WholesaleRegisterPage() {
|
||||
|
||||
useEffect(() => {
|
||||
async function checkEnabled(brandId: string) {
|
||||
const { supabase } = await import("@/lib/supabase");
|
||||
const { data: ws } = await supabase
|
||||
const { api } = await import("@/lib/api");
|
||||
const { data: ws } = await api
|
||||
.from("wholesale_settings")
|
||||
.select("wholesale_enabled")
|
||||
.eq("brand_id", brandId)
|
||||
|
||||
Reference in New Issue
Block a user