Browse Source

跳转问题修改

feature/video-erase
Luckyu_js 1 week ago
parent
commit
8dc6e8bbf6
  1. 10
      src/app/api/env-status/route.ts
  2. 4
      src/app/page.tsx
  3. 20
      src/components/__tests__/QuickstartInitialView.test.tsx
  4. 5
      src/components/quickstart/QuickstartInitialView.tsx
  5. 54
      src/hooks/useSiteExploreUrl.ts
  6. 8
      src/utils/loginUrl.ts

10
src/app/api/env-status/route.ts

@ -11,14 +11,23 @@ export interface EnvStatusResponse {
kie: boolean;
wavespeed: boolean;
smartGenerateUpload: boolean;
siteExploreUrl: string;
}
const FALSE_VALUES = new Set(["0", "false", "no", "off"]);
// Fallback site used when POPIART_API_BASE_URL is not configured (production).
const DEFAULT_SITE_BASE_URL = "https://www.popi.art";
function isSmartGenerateUploadEnabled(): boolean {
return !FALSE_VALUES.has((process.env.SMART_GENERATE_UPLOAD_ENABLED || "").trim().toLowerCase());
}
function getSiteExploreUrl(): string {
const base = (process.env.POPIART_API_BASE_URL || "").trim().replace(/\/+$/, "");
return `${base || DEFAULT_SITE_BASE_URL}/explore`;
}
export async function GET() {
// Check which API keys are configured via environment variables
const status: EnvStatusResponse = {
@ -32,6 +41,7 @@ export async function GET() {
kie: false,
wavespeed: false,
smartGenerateUpload: isSmartGenerateUploadEnabled(),
siteExploreUrl: getSiteExploreUrl(),
};
return NextResponse.json(status);

4
src/app/page.tsx

@ -13,6 +13,7 @@ import { HomeProjectsContent } from "@/components/HomeProjectsContent";
import { authFetch } from "@/utils/authFetch";
import { useUserStore } from "@/store/userStore";
import { useAppConfigStore } from "@/store/appConfigStore";
import { useSiteExploreUrl } from "@/hooks/useSiteExploreUrl";
import { openLoginModal } from "@/store/loginModalStore";
import { LANGUAGE_OPTIONS, useI18n } from "@/i18n";
import {
@ -130,6 +131,7 @@ function Header() {
const initializeConfig = useAppConfigStore((state) => state.initializeConfig);
const rawConfig = useAppConfigStore((state) => state.rawConfig) as ConfigResponse | null;
const systemConfig = rawConfig?.data?.systemConfig ?? rawConfig?.systemConfig;
const siteExploreUrl = useSiteExploreUrl();
const languageMenuItems: MenuProps["items"] = useMemo(
() =>
@ -190,7 +192,7 @@ function Header() {
<nav className="flex items-center gap-3" aria-label={t("home.mainNav")}>
<div className="hidden items-center gap-3 md:flex">
<Link
href="https://www.popi.art/explore"
href={siteExploreUrl}
target="_blank"
rel="noopener noreferrer"
className="group flex h-[33px] items-center justify-center gap-1 rounded-full bg-[#f9f9f9] px-3 text-[14px] font-medium !text-[#333] hover:bg-[#f0f0f0]"

20
src/components/__tests__/QuickstartInitialView.test.tsx

@ -1,5 +1,5 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
const {
resetMockUserState,
@ -73,10 +73,18 @@ describe("QuickstartInitialView", () => {
beforeEach(() => {
vi.clearAllMocks();
resetMockUserState();
vi.stubGlobal(
"fetch",
vi.fn(async () => ({
ok: true,
json: async () => ({ siteExploreUrl: "https://wwwtest.popi.art/explore" }),
})),
);
});
afterEach(() => {
vi.restoreAllMocks();
vi.unstubAllGlobals();
});
const renderView = () =>
@ -118,13 +126,15 @@ describe("QuickstartInitialView", () => {
expect(mockOnSelectVibe).toHaveBeenCalledTimes(1);
});
it("renders sign-in status actions when not signed in", () => {
it("renders sign-in status actions when not signed in", async () => {
renderView();
expect(screen.getByText("Not signed in")).toBeInTheDocument();
expect(screen.getByRole("link", { name: "Log in" })).toHaveAttribute(
"href",
"https://wwwtest.popi.art/explore"
await waitFor(() =>
expect(screen.getByRole("link", { name: "Log in" })).toHaveAttribute(
"href",
"https://wwwtest.popi.art/explore"
)
);
});

5
src/components/quickstart/QuickstartInitialView.tsx

@ -2,7 +2,7 @@
import { useI18n } from "@/i18n";
import { useUserStore } from "@/store/userStore";
import { LOGIN_REDIRECT_URL } from "@/utils/loginUrl";
import { useSiteExploreUrl } from "@/hooks/useSiteExploreUrl";
interface QuickstartInitialViewProps {
onNewProject: () => void;
@ -90,6 +90,7 @@ function AuthStatusPanel() {
const { t } = useI18n();
const userInfo = useUserStore((state) => state.userInfo);
const isLoadingUserInfo = useUserStore((state) => state.isLoadingUserInfo);
const siteExploreUrl = useSiteExploreUrl();
const statusLabel = isLoadingUserInfo
? t("quickstart.authChecking")
@ -119,7 +120,7 @@ function AuthStatusPanel() {
{!userInfo && !isLoadingUserInfo && (
<div className="mt-3 flex flex-wrap items-center gap-2">
<a
href={LOGIN_REDIRECT_URL}
href={siteExploreUrl}
className="rounded-md bg-neutral-100 px-3 py-1.5 text-xs font-medium text-neutral-900 transition-colors hover:bg-white"
>
{t("quickstart.loginAction")}

54
src/hooks/useSiteExploreUrl.ts

@ -0,0 +1,54 @@
"use client";
import { useEffect, useState } from "react";
import { DEFAULT_SITE_EXPLORE_URL } from "@/utils/loginUrl";
// Cache the resolved URL across component mounts so the link does not flicker
// once /api/env-status has answered for the current environment.
let cachedExploreUrl: string | null = null;
let pendingRequest: Promise<string> | null = null;
function fetchSiteExploreUrl(): Promise<string> {
if (cachedExploreUrl) return Promise.resolve(cachedExploreUrl);
if (pendingRequest) return pendingRequest;
pendingRequest = fetch("/api/env-status")
.then((response) => (response.ok ? response.json() : null))
.then((status) => {
const url =
typeof status?.siteExploreUrl === "string" && status.siteExploreUrl
? status.siteExploreUrl
: DEFAULT_SITE_EXPLORE_URL;
cachedExploreUrl = url;
return url;
})
.catch(() => DEFAULT_SITE_EXPLORE_URL)
.finally(() => {
pendingRequest = null;
});
return pendingRequest;
}
/**
* Resolves the Popi site explore URL for the current deployment environment
* (test -> https://wwwtest.popi.art/explore, prod -> https://www.popi.art/explore).
* Derived server-side from POPIART_API_BASE_URL and exposed via /api/env-status.
*/
export function useSiteExploreUrl(): string {
const [exploreUrl, setExploreUrl] = useState<string>(
cachedExploreUrl ?? DEFAULT_SITE_EXPLORE_URL,
);
useEffect(() => {
let cancelled = false;
void fetchSiteExploreUrl().then((url) => {
if (!cancelled) setExploreUrl(url);
});
return () => {
cancelled = true;
};
}, []);
return exploreUrl;
}

8
src/utils/loginUrl.ts

@ -1 +1,7 @@
export const LOGIN_REDIRECT_URL = "https://wwwtest.popi.art/explore";
// Fallback explore URL used before /api/env-status resolves, or if it fails.
// The real per-environment URL is derived server-side from POPIART_API_BASE_URL
// (see /api/env-status) and consumed via the useSiteExploreUrl() hook.
export const DEFAULT_SITE_EXPLORE_URL = "https://www.popi.art/explore";
/** @deprecated Use the useSiteExploreUrl() hook so the target follows the deployment environment. */
export const LOGIN_REDIRECT_URL = DEFAULT_SITE_EXPLORE_URL;

Loading…
Cancel
Save