diff --git a/next.config.mjs b/next.config.mjs index 89fd540..2fcd5d7 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -34,10 +34,33 @@ const nextConfig = { ], }, async rewrites() { + // The same build is deployed to two domains, each with its own backend: + // - test: opplenz.com -> https://admin.opplenz.com/admin/v1 + // - production: opplens.com -> https://admin.opplens.com/admin/v1 + // Routing is host-based so neither deploy needs a custom env. A + // `BACKEND_API_BASE_URL` env var (if set) overrides both — handy for local + // dev pointing at e.g. http://localhost:8080/admin/v1. + const override = process.env.BACKEND_API_BASE_URL; + if (override) { + return [ + { + source: "/api/proxy/:path*", + destination: `${override}/:path*`, + }, + ]; + } + return [ + // Production: any opplens.com host (apex or subdomain like www.). { source: "/api/proxy/:path*", - destination: `https://admin.opplenz.com/admin/v1/:path*`, + has: [{ type: "host", value: "(.*\\.)?opplens\\.com" }], + destination: "https://admin.opplens.com/admin/v1/:path*", + }, + // Default (test opplenz.com + local dev). + { + source: "/api/proxy/:path*", + destination: "https://admin.opplenz.com/admin/v1/:path*", }, ]; }, diff --git a/src/components/forms/companies/CreateCompany.tsx b/src/components/forms/companies/CreateCompany.tsx index c9027dd..459d6dc 100644 --- a/src/components/forms/companies/CreateCompany.tsx +++ b/src/components/forms/companies/CreateCompany.tsx @@ -210,11 +210,15 @@ const CreateCompany = ({ defaultValues, editMode, id }: IProps) => { value: 100, message: FormErrorMessages.maxLength(100), }, + pattern: { + value: REGEX.URL, + message: FormErrorMessages.invalidPattern, + }, })} label="Website" required name="website" - type="url" + type="text" placeholder="https://www.example.com" /> {errors.website && ( diff --git a/src/lib/api/config.ts b/src/lib/api/config.ts index 48a9e6d..f58fabf 100644 --- a/src/lib/api/config.ts +++ b/src/lib/api/config.ts @@ -1,21 +1,38 @@ import { API_ENDPOINTS } from "./endpoints"; +const TEST_API_BASE_URL = "https://admin.opplenz.com/admin/v1"; +const PRODUCTION_API_BASE_URL = "https://admin.opplens.com/admin/v1"; + /** - * Absolute base URL of the backend admin API. + * Absolute base URL of the backend admin API for the current deploy. * - * Mirrors the rewrite target in `next.config.mjs` (`/api/proxy/* -> - * https://admin.opplenz.com/admin/v1/*`). Axios calls use the relative - * `/api/proxy/` base so the browser attaches auth headers same-origin, but - * values that are persisted on the backend (e.g. a `profile_image` download - * URL) must be absolute so they resolve from anywhere — not the proxy path. + * Mirrors the host-based proxy in `next.config.mjs`: + * - production (`opplens.com`) -> admin.opplens.com/admin/v1 + * - test (`opplenz.com`) + dev -> admin.opplenz.com/admin/v1 + * + * Axios calls use the relative `/api/proxy/` base (so the browser attaches auth + * headers same-origin and the rewrite picks the right backend), but values that + * get persisted on the backend (e.g. a `profile_image` download URL) must be + * absolute and domain-correct. Resolved at call time because the host is only + * known in the browser. */ -export const BACKEND_API_BASE_URL = - process.env.NEXT_PUBLIC_BACKEND_API_BASE_URL ?? - "https://admin.opplenz.com/admin/v1"; +export const getBackendApiBaseUrl = (): string => { + const override = process.env.NEXT_PUBLIC_BACKEND_API_BASE_URL; + if (override) return override; + + if ( + typeof window !== "undefined" && + /(^|\.)opplens\.com$/.test(window.location.hostname) + ) { + return PRODUCTION_API_BASE_URL; + } + + return TEST_API_BASE_URL; +}; /** Absolute, directly-loadable URL for a stored GridFS file. */ export const buildFileDownloadUrl = (fileId: string) => - `${BACKEND_API_BASE_URL}/${API_ENDPOINTS.FILES.DOWNLOAD(fileId)}`; + `${getBackendApiBaseUrl()}/${API_ENDPOINTS.FILES.DOWNLOAD(fileId)}`; /** Pull the GridFS file id out of a stored download URL, if it is one. */ export const extractFileId = (url: string): string | undefined =>