Explorar o código

Merge branch 'master' into zzf-account

zhangzf hai 1 semana
pai
achega
88783e58c2

+ 2 - 5
src/app/globals.css

@@ -45,7 +45,7 @@ html {
 /* GLOBAL VARIABLES :root中定义常规变量,不被映射到工具类*/
 :root {
   /* Font families */
-  font-family: var(--font-outfit), system-ui, sans-serif;
+  font-family: var(--font-outfit-variable), system-ui, sans-serif;
   --background: #ffffff;
   --foreground: #000;
   --color-selected-black: #00000099;
@@ -70,9 +70,6 @@ html {
 
 /*theme中定义的变量可以被映射到实用程序类(需要注意映射规则,不是所有变量都能映射)*/
 @theme {
-  /* 仅保留字体族定义,其他通过 :root 变量注入 */
-  --font-family-outfit: var(--font-outfit), system-ui, sans-serif;
-
   /*自定义颜色*/
   --color-ly-inputborder: #e5e5e5;
   --color-ly-placeholder: #A6A6A6;
@@ -121,6 +118,7 @@ html {
   比如 定义了一个变量--color-background,--color-background引用的是另一个变量
 */
 @theme inline {
+  --font-outfit: var(--font-outfit-variable), system-ui, sans-serif;
   --color-background: var(--background);
   --color-foreground: var(--foreground);
   --color-font-color: var(--font-color);
@@ -137,7 +135,6 @@ html {
 body {
   background: var(--background);
   color: var(--foreground);
-  font-family: var(--font-outfit), system-ui, sans-serif;
 }
 
 @layer components {

+ 7 - 6
src/app/layout.tsx

@@ -1,5 +1,5 @@
 import Script from 'next/script'
-import { Outfit } from "next/font/google";
+import localFont from "next/font/local";
 import "./globals.css";
 import { GlobalProviders,ReduxProvider,PayPalWrapper,ConfigProvider } from "@/providers";
 import { generateMetadataForPage } from "@utils/helper";
@@ -30,11 +30,12 @@ const __srOnly: React.CSSProperties = {
   border: 0,
 };
 
-export const outfit = Outfit({
-  subsets: ["latin", "latin-ext"],
-  weight: ["400", "600"],
-  variable: "--font-outfit",
-  display: "optional",
+// https://nextjs.org/docs/app/api-reference/components/font#local-fonts
+export const outfit = localFont({
+  src: '../assets/fonts/Outfit_Variable_weight_100_900.woff2',
+  variable: "--font-outfit-variable",
+  weight: "100 900",
+  display: "swap",
   preload: true,
 });
 

BIN=BIN
src/assets/fonts/Outfit_Variable_weight_100_900.woff2


+ 36 - 0
src/components/catalog/type.ts

@@ -122,6 +122,9 @@ export interface ProductNode {
   };
   price?: string | number | { value?: number; currencyCode?: string } | null;
   minimumPrice?: string | number;
+  formattedPrice?: string;
+  formattedSpecialPrice?: string | null;
+  formattedMinimumPrice?: string;
   productOptions?: string | null;
   flexibleVariants?: Array<ProductFlexibleVariant>;
   priceHtml?: {
@@ -157,6 +160,39 @@ export interface ProductsResponse {
   };
 }
 
+export interface SearchProductsVariables {
+    query: string;
+    suggest?: boolean;
+    filter?: string;
+    sortKey?: string;
+    reverse?: boolean;
+    first?: number;
+    last?: number;
+    after?: string;
+    before?: string;
+    channel?: string;
+    locale?: string;
+}
+export interface SearchProductsResponse {
+  search: {
+    edges: Array<{ node: ProductNode }>;
+    pageInfo: {
+      endCursor: string;
+      startCursor: string;
+      hasNextPage: boolean;
+      hasPreviousPage: boolean;
+    };
+    totalCount: number;
+
+    searchMetadata: {
+      originalQuery: string;
+      effectiveQuery: string;
+      resultMessage: string;
+      searchInsteadMessage: string;
+    }
+  };
+}
+
 export interface ProductSectionNode {
   id: string;
   sku: string;

+ 2 - 2
src/components/customer/LoginForm.tsx

@@ -13,7 +13,7 @@ import { useCustomToast } from "@/utils/hooks/useToast";
 import { useMergeCart } from "@utils/hooks/useMergeCart";
 
 import { getCookie, setCookie } from "@/utils/cookie-tools";
-import { setLocalStorage } from "@/store/local-storage";
+
 import { useAppDispatch, useAppSelector } from "@/store/hooks";
 import { setUser } from "@/store/slices/user-slice";
 import { useCartDetail } from "@utils/hooks/useCartDetail";
@@ -62,7 +62,7 @@ export default function LoginForm() {
         return;
       }
       showToast("Welcome! Successfully logged in.", "success");
-      setLocalStorage("email", data?.username)
+
 
       const session = await getSession();
       const userToken: string | undefined = session?.user?.accessToken;

+ 0 - 2
src/components/customer/credentials/CredentialModal.tsx

@@ -17,7 +17,6 @@ import { logoutAction } from "@utils/actions";
 import { useAppDispatch, useAppSelector } from "@/store/hooks";
 import { clearUser } from "@/store/slices/user-slice";
 import { clearCart } from "@/store/slices/cart-slice";
-import { EMAIL, removeFromLocalStorage } from "@/store/local-storage";
 import { setCookie, deleteCookie } from "@utils/cookie-tools";
 import { IS_GUEST,GUEST_CART_TOKEN,GUEST_CART_ID } from "@/utils/constants";
 
@@ -86,7 +85,6 @@ export default function CredentialModal({
         router.push("/customer/login");
         router.refresh();
       }, 100);
-      removeFromLocalStorage(EMAIL)
     } catch (err: unknown) {
       const message = err instanceof Error ? err.message : "Logout failed";
       showToast(message, "danger");

+ 3 - 0
src/graphql/catalog/fragments/ProductCore.ts

@@ -7,6 +7,9 @@ export const PRODUCT_CORE_FRAGMENT = gql`
     type
     name
     price
+    formattedPrice
+    formattedSpecialPrice
+    formattedMinimumPrice
     urlKey
     baseImageUrl
     minimumPrice

+ 54 - 0
src/graphql/catalog/queries/SearchProducts.ts

@@ -0,0 +1,54 @@
+import { gql,TypedDocumentNode } from "@apollo/client";
+import { PRODUCT_CORE_FRAGMENT } from "../fragments";
+import { SearchProductsResponse } from "@/components/catalog/type";
+
+export const SEARCH_PRODUCTS: TypedDocumentNode<SearchProductsResponse> = gql`
+  ${PRODUCT_CORE_FRAGMENT}
+
+  query SearchProducts(
+    $query: String!
+    $suggest: Boolean
+    $sortKey: String
+    $reverse: Boolean
+    $first: Int
+    $last: Int
+    $after: String
+    $before: String
+    $channel: String
+    $locale: String
+    $filter: String
+  ) {
+    search(
+      query: $query
+      suggest: $suggest
+      filter: $filter
+      sortKey: $sortKey
+      reverse: $reverse
+      first: $first
+      last: $last
+      after: $after
+      before: $before
+      channel: $channel
+      locale: $locale
+      
+    ) {
+
+        totalCount
+        edges {
+            node { ...ProductCore }
+        }
+        pageInfo {
+            hasNextPage
+            hasPreviousPage
+            startCursor
+            endCursor
+        }
+        searchMetadata {
+            originalQuery
+            effectiveQuery
+            resultMessage
+            searchInsteadMessage
+        }
+    }
+  }
+`;

+ 0 - 113
src/store/local-storage.ts

@@ -1,113 +0,0 @@
-
-import { isArray, isObject } from "@/utils/type-guards";
-
-/**
- * Storage keys
- */
-export const CURRENCY_CODE = "current_currency";
-export const STORE_CODE = "current_store";
-export const STORE_CONFIG = "store_config";
-export const SELECTED_LOCATION = "elected_location";
-export const GUEST_CART = "guest_cart";
-export const CART_DATA = "cart_data";
-export const COUNTRIES = "countries";
-export const LAST_ORDER_ID = "last_order_id";
-export const MULTI_CHECKOUT = "ulti_checkout";
-export const SHIPPING_ADDRESS = "hipping_address";
-export const COMPARE_LIST = "recently_compared_product";
-export const COMPARE_ID = "compare_list_uid";
-export const IS_GUEST = "is_guest";
-export const CUSTOMER = "customer";
-export const IS_VIRTUAL_CART = "isVirtualCart";
-export const CURRENCY_RATES = "currency_rates";
-export const itemsArray = new Array(10).fill(0);
-export const SELECTED_STORE = "Store";
-export const DEFAULT_CURRENCY_CODE = "DEFAULT_CURRENCY_CODE";
-export const IS_AUTO_CURRENCY_SET = "IS_AUTO_CURRENCY_SET";
-export const EMAIL = "email";
-export const ORDER_DETAILS = "order-details";
-
-export const CACHED_KEYS = {
-  MEGA_MENU: "MEGA_MENU",
-  ROOT_CATEGORIES: "ROOT_CATEGORIES",
-};
-/**
- * Set local storage
- *
- * @param {string} key - Key for the storage
- * @param {any} data - Data to be stored
- * @returns void
- */
- 
-export const setLocalStorage = (key: string, data: any) => {
-  if (typeof window !== "undefined") {
-    if (isArray(data) || isObject(data)) {
-      data = JSON.stringify(data);
-    }
-    if (typeof data === "string") {
-      localStorage.setItem(key, data);
-    }
-  }
-};
-
-/**
- * Get data from local storage
- *
- * @param {string} key - Key for the storage
- * @param {boolean} needParsedData - Whether to parse the data or not
- * @returns any
- */
-export const getLocalStorage = (key: string, needParsedData = false) => {
-  try {
-    if (typeof window !== "undefined" && window) {
-      const data = localStorage.getItem(key);
-
-      if (!data || typeof data === "undefined") return null;
-      if (needParsedData) return JSON.parse(data);
-
-      return data;
-    }
-  } catch (error) {
-    console.error('Error:' , error)
-    return null;
-  }
-};
-
-/**
- * Get a specific key from local storage
- *
- * @param {string} storageKey - Key for the storage
- * @param {string} requiredKey - Required key
- * @returns any
- */
-export const getKeyFromStorage = (
-  storageKey: string ,
-  requiredKey: string 
-) => {
-  const data = getLocalStorage(storageKey, true);
-
-  return data?.[requiredKey] || null;
-};
-
-/**
- * Remove data from local storage
- *
- * @param {string} storageKey - Key for the storage
- * @returns void
- */
-export const removeFromLocalStorage = (storageKey: string) => {
-  if (typeof window !== "undefined") {
-    localStorage.removeItem(storageKey);
-  }
-};
-
-/**
- * Reset cart storage
- *
- * @returns void
- */
-export const resetCartStorage = () => {
-  removeFromLocalStorage(CART_DATA);
-  removeFromLocalStorage(GUEST_CART);
-  removeFromLocalStorage(SHIPPING_ADDRESS);
-};

+ 5 - 5
src/utils/bagisto/index.ts

@@ -19,7 +19,7 @@ import {
   CUSTOMER_REGISTRATION,
   FORGET_PASSWORD,
 } from "@/graphql/customer/mutations";
-import { DocumentNode } from "graphql";
+import { print, DocumentNode } from "graphql";
 import { 
   GRAPHQL_URL, 
   REST_API_URL,
@@ -172,12 +172,12 @@ export async function serverGraphqlFetch<
   TData,
   TVariables = Record<string, never>
 >({
-  cache = "force-cache",
+  cache = "no-store",
   headers,
   query,
   tags,
   variables,
-  revalidate = 60,
+  revalidate = 0,
   operationName = ''
 }: {
   cache?: RequestCache;
@@ -189,7 +189,7 @@ export async function serverGraphqlFetch<
   operationName?: string;
 }): Promise<FetchGraphqlResult<TData>> {
   try {
-    const queryString = typeof query === "string" ? query : (query.loc?.source?.body ?? "");
+    const queryString = typeof query === "string" ? query : print(query);
 
     let accessToken: string | undefined = undefined;
     let guestToken: string | undefined = undefined;
@@ -284,7 +284,7 @@ export async function bagistoFetch<T>({
 }): Promise<{ status: number; body: T } | never> {
   try {
     const queryString =
-      typeof query === "string" ? query : (query.loc?.source?.body ?? "");
+      typeof query === "string" ? query : print(query);
 
     let bagistoCartId = "";
     let accessToken: string | undefined = undefined;