index.tsx 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import Link from "next/link";
  2. import {Suspense} from "react";
  3. import LogoIcon from "@components/common/icons/LogoIcon";
  4. import MobileMenuTrigger from "./MobileMenuTrigger";
  5. import { NavbarActions } from "./NavbarActions";
  6. import { NavbarErrorBoundary } from "@/components/error/ErrorBoundary";
  7. import {
  8. GET_TREEFRONT_MENUS } from "@/graphql";
  9. import { serverGraphqlFetch } from "@utils/bagisto/index";
  10. import NavbarSearchIcon from "./NavbarSearchIcon"
  11. import type { GetTreefrontMenusResult } from "@/types/theme/menus";
  12. import { auth } from "@/utils/auth/auth-helper";
  13. import TopSwiperBanner from "./TopSwiperBanner"
  14. import { restApiFetch } from "@utils/bagisto/index";
  15. import type { AnnouncementItem } from "./TopSwiperBanner";
  16. import type { RestfulGetThemeCustomizations } from '@/types/theme/theme-customization';
  17. export default async function Navbar() {
  18. // 2. 服务端 fetch 请求我们自己的 Next.js API
  19. const topBarPromise:Promise<AnnouncementItem[]> = restApiFetch<{data:RestfulGetThemeCustomizations}>({
  20. api: `/shop/theme-customizations?name=Top_Bar`,
  21. method: "GET",
  22. isRoute: false,
  23. takeAuthorization: false,
  24. }).then((result) => {
  25. const themeItem = result.body[0];
  26. const optionsStr = themeItem?.translation?.options;
  27. if (optionsStr) {
  28. const parsed = JSON.parse(optionsStr);
  29. return parsed?.images ?? [];
  30. } else {
  31. return [];
  32. }
  33. }).catch((err) => {
  34. // 获取top_bar失败不应该阻止用户访问网站
  35. console.error('get top_bar error: ', err);
  36. return [];
  37. });
  38. const session = await auth();// 游客是null
  39. const isGuest = session === null;
  40. const { data: menudata } = await serverGraphqlFetch<
  41. GetTreefrontMenusResult
  42. >({
  43. query: GET_TREEFRONT_MENUS,
  44. takeAuthorization: false,
  45. });
  46. console.log('GetTreefrontMenusResult --- ',menudata)
  47. const menudatas =menudata? menudata.treefrontMenus:[];
  48. return (
  49. <NavbarErrorBoundary>
  50. <header className="sticky top-0 z-10">
  51. <Suspense fallback={<div className="flex items-center justify-center h-10 w-full overflow-hidden bg-ly-middlegreen text-ly-14 text-white">Loading top bar...</div>}>
  52. <TopSwiperBanner topBarPromise={topBarPromise} />
  53. </Suspense>
  54. <nav className="relative flex flex-col items-center justify-between gap-4 bg-neutral-50 p-4 pt-3 pb-3 dark:bg-neutral-900 md:flex-row lg:px-6 lg:py-4">
  55. <div className="flex w-full items-center justify-between gap-0 sm:gap-4">
  56. {/* 1. THE STATIC SHELL (Visible Instantly) */}
  57. <div className="flex items-center max-w-fit gap-5 xl:gap-6">
  58. {/* 2. STATIC HOLE: Categories (Suspended) */}
  59. <MobileMenuTrigger isGuest={isGuest} menuData={menudatas} />
  60. <div className="flex-1 justify-center flex">
  61. {/* <Suspense fallback={<SearchSkeleton />}>
  62. <Search search={false} />
  63. </Suspense> */}
  64. <NavbarSearchIcon/>
  65. </div>
  66. </div>
  67. <Link
  68. className="flex-initial h-9 w-36.5"
  69. href="/"
  70. aria-label="Go to homepage"
  71. >
  72. <LogoIcon />
  73. </Link>
  74. <NavbarActions isGuest={isGuest} />
  75. </div>
  76. </nav>
  77. </header>
  78. </NavbarErrorBoundary>
  79. );
  80. }