ecommerce 2/3
This commit is contained in:
parent
152bd98533
commit
1b34cb5922
@ -1,5 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
"dev": "turbo run dev",
|
||||
|
||||
@ -1,10 +1,22 @@
|
||||
import { CartState } from './types';
|
||||
/**
|
||||
* Global cart store.
|
||||
* Global cart store — persisted to localStorage.
|
||||
*
|
||||
* Usage:
|
||||
* ```tsx
|
||||
* const { items, addItem, subtotal } = useCartStore();
|
||||
* ```
|
||||
*/
|
||||
export declare const useCartStore: import('zustand').UseBoundStore<import('zustand').StoreApi<CartState>>;
|
||||
export declare const useCartStore: import('zustand').UseBoundStore<Omit<import('zustand').StoreApi<CartState>, "setState" | "persist"> & {
|
||||
setState(partial: CartState | Partial<CartState> | ((state: CartState) => CartState | Partial<CartState>), replace?: false): unknown;
|
||||
setState(state: CartState | ((state: CartState) => CartState), replace: true): unknown;
|
||||
persist: {
|
||||
setOptions: (options: Partial<import('zustand/middleware').PersistOptions<CartState, CartState, unknown>>) => void;
|
||||
clearStorage: () => void;
|
||||
rehydrate: () => Promise<void> | void;
|
||||
hasHydrated: () => boolean;
|
||||
onHydrate: (fn: (state: CartState) => void) => () => void;
|
||||
onFinishHydration: (fn: (state: CartState) => void) => () => void;
|
||||
getOptions: () => Partial<import('zustand/middleware').PersistOptions<CartState, CartState, unknown>>;
|
||||
};
|
||||
}>;
|
||||
|
||||
@ -16,6 +16,8 @@ export interface CheckoutPageProps {
|
||||
}) => void;
|
||||
/** Called when user clicks "Back to Cart". */
|
||||
onBackToCart?: () => void;
|
||||
/** Pre-fill shipping form fields (e.g. from user profile). */
|
||||
initialShipping?: Partial<ShippingAddress>;
|
||||
/** Pre-filled tax amount, if known. */
|
||||
tax?: number;
|
||||
/** Pre-filled shipping cost. */
|
||||
@ -27,4 +29,4 @@ export interface CheckoutPageProps {
|
||||
* Checkout page — two-column layout with shipping form + payment selector on
|
||||
* the left and an OrderSummary on the right.
|
||||
*/
|
||||
export declare function CheckoutPage({ onPlaceOrder, onBackToCart, tax, shipping, className, }: CheckoutPageProps): import("react/jsx-runtime").JSX.Element;
|
||||
export declare function CheckoutPage({ onPlaceOrder, onBackToCart, initialShipping, tax, shipping, className, }: CheckoutPageProps): import("react/jsx-runtime").JSX.Element;
|
||||
|
||||
12
packages/ecommerce/dist-lib/lib-export.d.ts
vendored
12
packages/ecommerce/dist-lib/lib-export.d.ts
vendored
@ -8,3 +8,15 @@ export { OrderSummary } from './checkout/OrderSummary';
|
||||
export type { OrderSummaryProps } from './checkout/OrderSummary';
|
||||
export { CheckoutPage } from './checkout/CheckoutPage';
|
||||
export type { CheckoutPageProps, ShippingAddress, PaymentMethod, } from './checkout/CheckoutPage';
|
||||
export { PolicyPage } from './policies/PolicyPage';
|
||||
export type { PolicyPageProps } from './policies/PolicyPage';
|
||||
export { ShippingPage } from './policies/ShippingPage';
|
||||
export type { ShippingPageProps, ShippingRate } from './policies/ShippingPage';
|
||||
export { ReturnsPage } from './policies/ReturnsPage';
|
||||
export type { ReturnsPageProps } from './policies/ReturnsPage';
|
||||
export { PrivacyPolicyPage } from './policies/PrivacyPolicyPage';
|
||||
export type { PrivacyPolicyPageProps } from './policies/PrivacyPolicyPage';
|
||||
export { TermsPage } from './policies/TermsPage';
|
||||
export type { TermsPageProps } from './policies/TermsPage';
|
||||
export { PolicyLinks } from './policies/PolicyLinks';
|
||||
export type { PolicyLinksProps, PolicyLink } from './policies/PolicyLinks';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
12
packages/ecommerce/dist-lib/policies/PolicyLinks.d.ts
vendored
Normal file
12
packages/ecommerce/dist-lib/policies/PolicyLinks.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
export interface PolicyLink {
|
||||
label: string;
|
||||
href: string;
|
||||
}
|
||||
export interface PolicyLinksProps {
|
||||
links?: PolicyLink[];
|
||||
className?: string;
|
||||
}
|
||||
/**
|
||||
* Small footer row of policy links for cart / checkout pages.
|
||||
*/
|
||||
export declare function PolicyLinks({ links, className }: PolicyLinksProps): import("react/jsx-runtime").JSX.Element;
|
||||
14
packages/ecommerce/dist-lib/policies/PolicyPage.d.ts
vendored
Normal file
14
packages/ecommerce/dist-lib/policies/PolicyPage.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
import { default as React } from 'react';
|
||||
export interface PolicyPageProps {
|
||||
/** Page title override. */
|
||||
title?: string;
|
||||
/** Rich content to render inside the page body (JSX). */
|
||||
children?: React.ReactNode;
|
||||
/** Optional extra class names. */
|
||||
className?: string;
|
||||
}
|
||||
/**
|
||||
* Generic policy/info page shell — centered card with title + prose body.
|
||||
* Used by ShippingPage, ReturnsPage, PrivacyPolicyPage, TermsPage.
|
||||
*/
|
||||
export declare function PolicyPage({ title, children, className }: PolicyPageProps): import("react/jsx-runtime").JSX.Element;
|
||||
10
packages/ecommerce/dist-lib/policies/PrivacyPolicyPage.d.ts
vendored
Normal file
10
packages/ecommerce/dist-lib/policies/PrivacyPolicyPage.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
export interface PrivacyPolicyPageProps {
|
||||
/** Business / site name used in the policy text. */
|
||||
siteName?: string;
|
||||
/** Contact email for privacy inquiries. */
|
||||
contactEmail?: string;
|
||||
/** Optional extra class names. */
|
||||
className?: string;
|
||||
}
|
||||
/** Public page with privacy / cookie information. */
|
||||
export declare function PrivacyPolicyPage({ siteName, contactEmail, className, }: PrivacyPolicyPageProps): import("react/jsx-runtime").JSX.Element;
|
||||
8
packages/ecommerce/dist-lib/policies/ReturnsPage.d.ts
vendored
Normal file
8
packages/ecommerce/dist-lib/policies/ReturnsPage.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
export interface ReturnsPageProps {
|
||||
/** Number of days for return window. */
|
||||
returnWindowDays?: number;
|
||||
/** Optional extra class names. */
|
||||
className?: string;
|
||||
}
|
||||
/** Public page with refund / return policy. */
|
||||
export declare function ReturnsPage({ returnWindowDays, className }: ReturnsPageProps): import("react/jsx-runtime").JSX.Element;
|
||||
14
packages/ecommerce/dist-lib/policies/ShippingPage.d.ts
vendored
Normal file
14
packages/ecommerce/dist-lib/policies/ShippingPage.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
export interface ShippingRate {
|
||||
region: string;
|
||||
method: string;
|
||||
estimate: string;
|
||||
price: string;
|
||||
}
|
||||
export interface ShippingPageProps {
|
||||
/** Custom shipping rates to display. Falls back to placeholder content. */
|
||||
rates?: ShippingRate[];
|
||||
/** Optional extra class names. */
|
||||
className?: string;
|
||||
}
|
||||
/** Public page with shipping info and rates. */
|
||||
export declare function ShippingPage({ rates, className }: ShippingPageProps): import("react/jsx-runtime").JSX.Element;
|
||||
10
packages/ecommerce/dist-lib/policies/TermsPage.d.ts
vendored
Normal file
10
packages/ecommerce/dist-lib/policies/TermsPage.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
export interface TermsPageProps {
|
||||
/** Business / site name. */
|
||||
siteName?: string;
|
||||
/** Contact email for legal inquiries. */
|
||||
contactEmail?: string;
|
||||
/** Optional extra class names. */
|
||||
className?: string;
|
||||
}
|
||||
/** Optional terms of service page. */
|
||||
export declare function TermsPage({ siteName, contactEmail, className, }: TermsPageProps): import("react/jsx-runtime").JSX.Element;
|
||||
364
packages/ecommerce/package-lock.json
generated
364
packages/ecommerce/package-lock.json
generated
@ -7,6 +7,127 @@
|
||||
"": {
|
||||
"name": "@polymech/ecommerce",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@google/genai": "^1.34.0",
|
||||
"@google/generative-ai": "^0.24.1",
|
||||
"@hookform/resolvers": "^3.10.0",
|
||||
"@mdxeditor/editor": "^3.47.0",
|
||||
"@milkdown/core": "^7.16.0",
|
||||
"@milkdown/crepe": "^7.16.0",
|
||||
"@milkdown/utils": "^7.16.0",
|
||||
"@playwright/test": "^1.55.1",
|
||||
"@polymech/ui": "file:../ui",
|
||||
"@radix-ui/react-accordion": "^1.2.11",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.14",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
||||
"@radix-ui/react-avatar": "^1.1.10",
|
||||
"@radix-ui/react-checkbox": "^1.3.2",
|
||||
"@radix-ui/react-collapsible": "^1.1.11",
|
||||
"@radix-ui/react-context-menu": "^2.2.15",
|
||||
"@radix-ui/react-dialog": "^1.1.14",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
||||
"@radix-ui/react-hover-card": "^1.1.14",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-menubar": "^1.1.15",
|
||||
"@radix-ui/react-navigation-menu": "^1.2.13",
|
||||
"@radix-ui/react-popover": "^1.1.14",
|
||||
"@radix-ui/react-progress": "^1.1.7",
|
||||
"@radix-ui/react-radio-group": "^1.3.7",
|
||||
"@radix-ui/react-scroll-area": "^1.2.9",
|
||||
"@radix-ui/react-select": "^2.2.5",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slider": "^1.3.5",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-switch": "^1.2.5",
|
||||
"@radix-ui/react-tabs": "^1.1.12",
|
||||
"@radix-ui/react-toast": "^1.2.14",
|
||||
"@radix-ui/react-toggle": "^1.1.9",
|
||||
"@radix-ui/react-toggle-group": "^1.1.10",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@supabase-cache-helpers/postgrest-swr": "^2.0.3",
|
||||
"@supabase/supabase-js": "^2.58.0",
|
||||
"@tanstack/react-query": "^5.83.0",
|
||||
"@types/dompurify": "^3.2.0",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@uppy/tus": "^5.0.2",
|
||||
"@vidstack/react": "^1.12.13",
|
||||
"@xyflow/react": "^12.8.6",
|
||||
"axios": "^1.12.2",
|
||||
"buffer": "^6.0.3",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"date-fns": "^3.6.0",
|
||||
"dompurify": "^3.2.7",
|
||||
"dotenv": "^17.2.3",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"exifreader": "^4.33.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"hls.js": "^1.6.13",
|
||||
"idb-keyval": "^6.2.2",
|
||||
"input-otp": "^1.4.2",
|
||||
"jszip": "^3.10.1",
|
||||
"lucide-react": "^0.462.0",
|
||||
"marked": "^16.3.0",
|
||||
"next-themes": "^0.3.0",
|
||||
"openai": "^6.0.0",
|
||||
"playwright": "^1.55.1",
|
||||
"prismjs": "^1.30.0",
|
||||
"react": "^18.3.1",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hook-form": "^7.61.1",
|
||||
"react-intersection-observer": "^10.0.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-resizable-panels": "^2.1.9",
|
||||
"react-router-dom": "^6.30.1",
|
||||
"react-zoom-pan-pinch": "^3.7.0",
|
||||
"recharts": "^2.15.4",
|
||||
"replicate": "^1.2.0",
|
||||
"rollup-plugin-visualizer": "^6.0.5",
|
||||
"sonner": "^1.7.4",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"swr": "^2.3.7",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"vaul": "^0.9.9",
|
||||
"vite-bundle-analyzer": "^1.3.1",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-pwa": "^1.0.3",
|
||||
"vue": "^3.5.22",
|
||||
"workbox-core": "^7.4.0",
|
||||
"zod": "^3.25.76",
|
||||
"zod-to-json-schema": "^3.24.6",
|
||||
"zustand": "^5.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.32.0",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@types/node": "^22.16.5",
|
||||
"@types/react": "^18.3.23",
|
||||
"@types/react-dom": "^18.3.7",
|
||||
"@vitejs/plugin-react-swc": "^3.11.0",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^9.32.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^15.15.0",
|
||||
"lovable-tagger": "^1.1.10",
|
||||
"postcss": "^8.5.6",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.38.0",
|
||||
"vite": "^5.4.19",
|
||||
"vite-plugin-dts": "^4.5.4",
|
||||
"workbox-precaching": "^7.4.0",
|
||||
"workbox-routing": "^7.4.0",
|
||||
"workbox-window": "^7.4.0"
|
||||
}
|
||||
},
|
||||
"../ui": {
|
||||
"name": "@polymech/ui",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@google/genai": "^1.34.0",
|
||||
"@google/generative-ai": "^0.24.1",
|
||||
@ -97,7 +218,7 @@
|
||||
"workbox-core": "^7.4.0",
|
||||
"zod": "^3.25.76",
|
||||
"zod-to-json-schema": "^3.24.6",
|
||||
"zustand": "^5.0.11"
|
||||
"zustand": "^5.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.32.0",
|
||||
@ -2872,9 +2993,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/brace-expansion": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
|
||||
"integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz",
|
||||
"integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@isaacs/balanced-match": "^4.0.1"
|
||||
@ -3479,9 +3600,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/api-extractor": {
|
||||
"version": "7.55.2",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.55.2.tgz",
|
||||
"integrity": "sha512-1jlWO4qmgqYoVUcyh+oXYRztZde/pAi7cSVzBz/rc+S7CoVzDasy8QE13dx6sLG4VRo8SfkkLbFORR6tBw4uGQ==",
|
||||
"version": "7.56.3",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.56.3.tgz",
|
||||
"integrity": "sha512-fRqok4aRNq5GpgGBv2fKlSSKbirPKTJ75vQefthB5x9dwt4Zz+AezUzdc1p/AG4wUBIgmhjcEwn/Rj+N4Wh4Mw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -3490,11 +3611,11 @@
|
||||
"@microsoft/tsdoc-config": "~0.18.0",
|
||||
"@rushstack/node-core-library": "5.19.1",
|
||||
"@rushstack/rig-package": "0.6.0",
|
||||
"@rushstack/terminal": "0.19.5",
|
||||
"@rushstack/ts-command-line": "5.1.5",
|
||||
"@rushstack/terminal": "0.21.0",
|
||||
"@rushstack/ts-command-line": "5.2.0",
|
||||
"diff": "~8.0.2",
|
||||
"lodash": "~4.17.15",
|
||||
"minimatch": "10.0.3",
|
||||
"lodash": "~4.17.23",
|
||||
"minimatch": "10.1.2",
|
||||
"resolve": "~1.22.1",
|
||||
"semver": "~7.5.4",
|
||||
"source-map": "~0.6.1",
|
||||
@ -3540,13 +3661,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/api-extractor/node_modules/minimatch": {
|
||||
"version": "10.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
|
||||
"integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
|
||||
"version": "10.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz",
|
||||
"integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/brace-expansion": "^5.0.0"
|
||||
"@isaacs/brace-expansion": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
@ -4040,6 +4161,10 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@polymech/ui": {
|
||||
"resolved": "../ui",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@protobufjs/aspromise": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||
@ -6388,9 +6513,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rushstack/terminal": {
|
||||
"version": "0.19.5",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.19.5.tgz",
|
||||
"integrity": "sha512-6k5tpdB88G0K7QrH/3yfKO84HK9ggftfUZ51p7fePyCE7+RLLHkWZbID9OFWbXuna+eeCFE7AkKnRMHMxNbz7Q==",
|
||||
"version": "0.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.21.0.tgz",
|
||||
"integrity": "sha512-cLaI4HwCNYmknM5ns4G+drqdEB6q3dCPV423+d3TZeBusYSSm09+nR7CnhzJMjJqeRcdMAaLnrA4M/3xDz4R3w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -6424,13 +6549,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rushstack/ts-command-line": {
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.1.5.tgz",
|
||||
"integrity": "sha512-YmrFTFUdHXblYSa+Xc9OO9FsL/XFcckZy0ycQ6q7VSBsVs5P0uD9vcges5Q9vctGlVdu27w+Ct6IuJ458V0cTQ==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.2.0.tgz",
|
||||
"integrity": "sha512-lYxCX0nDdkDtCkVpvF0m25ymf66SaMWuppbD6b7MdkIzvGXKBXNIVZlwBH/C0YfkanrupnICWf2n4z3AKSfaHw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rushstack/terminal": "0.19.5",
|
||||
"@rushstack/terminal": "0.21.0",
|
||||
"@types/argparse": "1.0.38",
|
||||
"argparse": "~1.0.9",
|
||||
"string-argv": "~0.3.1"
|
||||
@ -7129,17 +7254,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.1.tgz",
|
||||
"integrity": "sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz",
|
||||
"integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.12.2",
|
||||
"@typescript-eslint/scope-manager": "8.53.1",
|
||||
"@typescript-eslint/type-utils": "8.53.1",
|
||||
"@typescript-eslint/utils": "8.53.1",
|
||||
"@typescript-eslint/visitor-keys": "8.53.1",
|
||||
"@typescript-eslint/scope-manager": "8.56.0",
|
||||
"@typescript-eslint/type-utils": "8.56.0",
|
||||
"@typescript-eslint/utils": "8.56.0",
|
||||
"@typescript-eslint/visitor-keys": "8.56.0",
|
||||
"ignore": "^7.0.5",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^2.4.0"
|
||||
@ -7152,8 +7277,8 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.53.1",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"@typescript-eslint/parser": "^8.56.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
@ -7168,17 +7293,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.1.tgz",
|
||||
"integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz",
|
||||
"integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.53.1",
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"@typescript-eslint/typescript-estree": "8.53.1",
|
||||
"@typescript-eslint/visitor-keys": "8.53.1",
|
||||
"@typescript-eslint/scope-manager": "8.56.0",
|
||||
"@typescript-eslint/types": "8.56.0",
|
||||
"@typescript-eslint/typescript-estree": "8.56.0",
|
||||
"@typescript-eslint/visitor-keys": "8.56.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -7189,19 +7314,19 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.1.tgz",
|
||||
"integrity": "sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz",
|
||||
"integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.53.1",
|
||||
"@typescript-eslint/types": "^8.53.1",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.56.0",
|
||||
"@typescript-eslint/types": "^8.56.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@ -7216,14 +7341,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.1.tgz",
|
||||
"integrity": "sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz",
|
||||
"integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"@typescript-eslint/visitor-keys": "8.53.1"
|
||||
"@typescript-eslint/types": "8.56.0",
|
||||
"@typescript-eslint/visitor-keys": "8.56.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -7234,9 +7359,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.1.tgz",
|
||||
"integrity": "sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz",
|
||||
"integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -7251,15 +7376,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.1.tgz",
|
||||
"integrity": "sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz",
|
||||
"integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"@typescript-eslint/typescript-estree": "8.53.1",
|
||||
"@typescript-eslint/utils": "8.53.1",
|
||||
"@typescript-eslint/types": "8.56.0",
|
||||
"@typescript-eslint/typescript-estree": "8.56.0",
|
||||
"@typescript-eslint/utils": "8.56.0",
|
||||
"debug": "^4.4.3",
|
||||
"ts-api-utils": "^2.4.0"
|
||||
},
|
||||
@ -7271,14 +7396,14 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz",
|
||||
"integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz",
|
||||
"integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -7290,16 +7415,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.1.tgz",
|
||||
"integrity": "sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz",
|
||||
"integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.53.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.53.1",
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"@typescript-eslint/visitor-keys": "8.53.1",
|
||||
"@typescript-eslint/project-service": "8.56.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.56.0",
|
||||
"@typescript-eslint/types": "8.56.0",
|
||||
"@typescript-eslint/visitor-keys": "8.56.0",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^9.0.5",
|
||||
"semver": "^7.7.3",
|
||||
@ -7344,16 +7469,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.1.tgz",
|
||||
"integrity": "sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz",
|
||||
"integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
"@typescript-eslint/scope-manager": "8.53.1",
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"@typescript-eslint/typescript-estree": "8.53.1"
|
||||
"@typescript-eslint/scope-manager": "8.56.0",
|
||||
"@typescript-eslint/types": "8.56.0",
|
||||
"@typescript-eslint/typescript-estree": "8.56.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -7363,19 +7488,19 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.1.tgz",
|
||||
"integrity": "sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz",
|
||||
"integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
"@typescript-eslint/types": "8.56.0",
|
||||
"eslint-visitor-keys": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -7385,6 +7510,19 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz",
|
||||
"integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@ungap/structured-clone": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
|
||||
@ -7848,9 +7986,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ajv-formats/node_modules/ajv": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
|
||||
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -8086,13 +8224,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
|
||||
"integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
|
||||
"version": "1.13.5",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
|
||||
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.4",
|
||||
"follow-redirects": "^1.15.11",
|
||||
"form-data": "^4.0.5",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@ -9246,9 +9384,9 @@
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
|
||||
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz",
|
||||
"integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
@ -11820,15 +11958,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"version": "4.17.23",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
||||
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.22",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.22.tgz",
|
||||
"integrity": "sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==",
|
||||
"version": "4.17.23",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz",
|
||||
"integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash._baseiteratee": {
|
||||
@ -15374,9 +15512,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
||||
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
@ -16424,16 +16562,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.53.1.tgz",
|
||||
"integrity": "sha512-gB+EVQfP5RDElh9ittfXlhZJdjSU4jUSTyE2+ia8CYyNvet4ElfaLlAIqDvQV9JPknKx0jQH1racTYe/4LaLSg==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.0.tgz",
|
||||
"integrity": "sha512-c7toRLrotJ9oixgdW7liukZpsnq5CZ7PuKztubGYlNppuTqhIoWfhgHo/7EU0v06gS2l/x0i2NEFK1qMIf0rIg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.53.1",
|
||||
"@typescript-eslint/parser": "8.53.1",
|
||||
"@typescript-eslint/typescript-estree": "8.53.1",
|
||||
"@typescript-eslint/utils": "8.53.1"
|
||||
"@typescript-eslint/eslint-plugin": "8.56.0",
|
||||
"@typescript-eslint/parser": "8.56.0",
|
||||
"@typescript-eslint/typescript-estree": "8.56.0",
|
||||
"@typescript-eslint/utils": "8.56.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -16443,7 +16581,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
@ -17748,9 +17886,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/workbox-build/node_modules/ajv": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
|
||||
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
"@milkdown/crepe": "^7.16.0",
|
||||
"@milkdown/utils": "^7.16.0",
|
||||
"@playwright/test": "^1.55.1",
|
||||
"@polymech/ui": "file:../ui",
|
||||
"@radix-ui/react-accordion": "^1.2.11",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.14",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
||||
@ -148,4 +149,4 @@
|
||||
"workbox-routing": "^7.4.0",
|
||||
"workbox-window": "^7.4.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import { Separator } from "@/components/ui/separator";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useCartStore } from "./useCartStore";
|
||||
import { CartItemRow } from "./CartItem";
|
||||
import { PolicyLinks } from "@/policies/PolicyLinks";
|
||||
|
||||
export interface CartPageProps {
|
||||
/** Called when user clicks "Proceed to Checkout". */
|
||||
@ -81,6 +82,8 @@ export function CartPage({ onCheckout, className }: CartPageProps) {
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
|
||||
<PolicyLinks className="pt-2" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import type { CartItem, CartState } from "./types";
|
||||
|
||||
/** Recompute derived totals from items array. */
|
||||
@ -10,51 +11,58 @@ function computeTotals(items: CartItem[]) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Global cart store.
|
||||
* Global cart store — persisted to localStorage.
|
||||
*
|
||||
* Usage:
|
||||
* ```tsx
|
||||
* const { items, addItem, subtotal } = useCartStore();
|
||||
* ```
|
||||
*/
|
||||
export const useCartStore = create<CartState>((set) => ({
|
||||
items: [],
|
||||
subtotal: 0,
|
||||
itemCount: 0,
|
||||
export const useCartStore = create<CartState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
items: [],
|
||||
subtotal: 0,
|
||||
itemCount: 0,
|
||||
|
||||
addItem: (incoming) =>
|
||||
set((state) => {
|
||||
const existing = state.items.find((i) => i.id === incoming.id);
|
||||
let items: CartItem[];
|
||||
if (existing) {
|
||||
items = state.items.map((i) =>
|
||||
i.id === incoming.id
|
||||
? { ...i, quantity: i.quantity + (incoming.quantity ?? 1) }
|
||||
: i,
|
||||
);
|
||||
} else {
|
||||
items = [...state.items, { ...incoming, quantity: incoming.quantity ?? 1 }];
|
||||
}
|
||||
return { items, ...computeTotals(items) };
|
||||
addItem: (incoming) =>
|
||||
set((state) => {
|
||||
const existing = state.items.find((i) => i.id === incoming.id);
|
||||
let items: CartItem[];
|
||||
if (existing) {
|
||||
items = state.items.map((i) =>
|
||||
i.id === incoming.id
|
||||
? { ...i, quantity: i.quantity + (incoming.quantity ?? 1) }
|
||||
: i,
|
||||
);
|
||||
} else {
|
||||
items = [...state.items, { ...incoming, quantity: incoming.quantity ?? 1 }];
|
||||
}
|
||||
return { items, ...computeTotals(items) };
|
||||
}),
|
||||
|
||||
removeItem: (id) =>
|
||||
set((state) => {
|
||||
const items = state.items.filter((i) => i.id !== id);
|
||||
return { items, ...computeTotals(items) };
|
||||
}),
|
||||
|
||||
updateQuantity: (id, quantity) =>
|
||||
set((state) => {
|
||||
if (quantity <= 0) {
|
||||
const items = state.items.filter((i) => i.id !== id);
|
||||
return { items, ...computeTotals(items) };
|
||||
}
|
||||
const items = state.items.map((i) =>
|
||||
i.id === id ? { ...i, quantity } : i,
|
||||
);
|
||||
return { items, ...computeTotals(items) };
|
||||
}),
|
||||
|
||||
clearCart: () => set({ items: [], subtotal: 0, itemCount: 0 }),
|
||||
}),
|
||||
|
||||
removeItem: (id) =>
|
||||
set((state) => {
|
||||
const items = state.items.filter((i) => i.id !== id);
|
||||
return { items, ...computeTotals(items) };
|
||||
}),
|
||||
|
||||
updateQuantity: (id, quantity) =>
|
||||
set((state) => {
|
||||
if (quantity <= 0) {
|
||||
const items = state.items.filter((i) => i.id !== id);
|
||||
return { items, ...computeTotals(items) };
|
||||
}
|
||||
const items = state.items.map((i) =>
|
||||
i.id === id ? { ...i, quantity } : i,
|
||||
);
|
||||
return { items, ...computeTotals(items) };
|
||||
}),
|
||||
|
||||
clearCart: () => set({ items: [], subtotal: 0, itemCount: 0 }),
|
||||
}));
|
||||
{
|
||||
name: "pm-ecommerce-cart",
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@ -8,6 +8,7 @@ import { Separator } from "@/components/ui/separator";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useCartStore } from "@/cart/useCartStore";
|
||||
import { OrderSummary } from "./OrderSummary";
|
||||
import { PolicyLinks } from "@/policies/PolicyLinks";
|
||||
|
||||
/** Shipping address fields collected at checkout. */
|
||||
export interface ShippingAddress {
|
||||
@ -29,6 +30,8 @@ export interface CheckoutPageProps {
|
||||
}) => void;
|
||||
/** Called when user clicks "Back to Cart". */
|
||||
onBackToCart?: () => void;
|
||||
/** Pre-fill shipping form fields (e.g. from user profile). */
|
||||
initialShipping?: Partial<ShippingAddress>;
|
||||
/** Pre-filled tax amount, if known. */
|
||||
tax?: number;
|
||||
/** Pre-filled shipping cost. */
|
||||
@ -44,6 +47,7 @@ export interface CheckoutPageProps {
|
||||
export function CheckoutPage({
|
||||
onPlaceOrder,
|
||||
onBackToCart,
|
||||
initialShipping,
|
||||
tax,
|
||||
shipping,
|
||||
className,
|
||||
@ -52,12 +56,12 @@ export function CheckoutPage({
|
||||
|
||||
const [paymentMethod, setPaymentMethod] = useState<PaymentMethod>("shopify");
|
||||
const [form, setForm] = useState<ShippingAddress>({
|
||||
fullName: "",
|
||||
email: "",
|
||||
address: "",
|
||||
city: "",
|
||||
zip: "",
|
||||
country: "",
|
||||
fullName: initialShipping?.fullName ?? "",
|
||||
email: initialShipping?.email ?? "",
|
||||
address: initialShipping?.address ?? "",
|
||||
city: initialShipping?.city ?? "",
|
||||
zip: initialShipping?.zip ?? "",
|
||||
country: initialShipping?.country ?? "",
|
||||
});
|
||||
|
||||
const field = (key: keyof ShippingAddress, value: string) =>
|
||||
@ -232,6 +236,8 @@ export function CheckoutPage({
|
||||
← Back to Cart
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<PolicyLinks className="pt-4" />
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
|
||||
@ -19,3 +19,22 @@ export type {
|
||||
ShippingAddress,
|
||||
PaymentMethod,
|
||||
} from "./checkout/CheckoutPage";
|
||||
|
||||
// === Policies ===
|
||||
export { PolicyPage } from "./policies/PolicyPage";
|
||||
export type { PolicyPageProps } from "./policies/PolicyPage";
|
||||
|
||||
export { ShippingPage } from "./policies/ShippingPage";
|
||||
export type { ShippingPageProps, ShippingRate } from "./policies/ShippingPage";
|
||||
|
||||
export { ReturnsPage } from "./policies/ReturnsPage";
|
||||
export type { ReturnsPageProps } from "./policies/ReturnsPage";
|
||||
|
||||
export { PrivacyPolicyPage } from "./policies/PrivacyPolicyPage";
|
||||
export type { PrivacyPolicyPageProps } from "./policies/PrivacyPolicyPage";
|
||||
|
||||
export { TermsPage } from "./policies/TermsPage";
|
||||
export type { TermsPageProps } from "./policies/TermsPage";
|
||||
|
||||
export { PolicyLinks } from "./policies/PolicyLinks";
|
||||
export type { PolicyLinksProps, PolicyLink } from "./policies/PolicyLinks";
|
||||
|
||||
37
packages/ecommerce/src/policies/PolicyLinks.tsx
Normal file
37
packages/ecommerce/src/policies/PolicyLinks.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface PolicyLink {
|
||||
label: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
const defaultLinks: PolicyLink[] = [
|
||||
{ label: "Returns & Refunds", href: "/returns" },
|
||||
{ label: "Shipping", href: "/shipping" },
|
||||
{ label: "Privacy Policy", href: "/privacy" },
|
||||
{ label: "Terms of Service", href: "/terms" },
|
||||
];
|
||||
|
||||
export interface PolicyLinksProps {
|
||||
links?: PolicyLink[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Small footer row of policy links for cart / checkout pages.
|
||||
*/
|
||||
export function PolicyLinks({ links = defaultLinks, className }: PolicyLinksProps) {
|
||||
return (
|
||||
<nav className={cn("flex flex-wrap items-center justify-center gap-x-4 gap-y-1 text-xs text-muted-foreground", className)}>
|
||||
{links.map((l, i) => (
|
||||
<React.Fragment key={l.href}>
|
||||
{i > 0 && <span className="hidden sm:inline" aria-hidden>·</span>}
|
||||
<a href={l.href} className="hover:text-foreground hover:underline transition-colors">
|
||||
{l.label}
|
||||
</a>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
33
packages/ecommerce/src/policies/PolicyPage.tsx
Normal file
33
packages/ecommerce/src/policies/PolicyPage.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React from "react";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface PolicyPageProps {
|
||||
/** Page title override. */
|
||||
title?: string;
|
||||
/** Rich content to render inside the page body (JSX). */
|
||||
children?: React.ReactNode;
|
||||
/** Optional extra class names. */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic policy/info page shell — centered card with title + prose body.
|
||||
* Used by ShippingPage, ReturnsPage, PrivacyPolicyPage, TermsPage.
|
||||
*/
|
||||
export function PolicyPage({ title, children, className }: PolicyPageProps) {
|
||||
return (
|
||||
<div className={cn("mx-auto max-w-3xl py-8", className)}>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-2xl">{title}</CardTitle>
|
||||
</CardHeader>
|
||||
<Separator />
|
||||
<CardContent className="prose prose-sm dark:prose-invert max-w-none pt-6">
|
||||
{children}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
85
packages/ecommerce/src/policies/PrivacyPolicyPage.tsx
Normal file
85
packages/ecommerce/src/policies/PrivacyPolicyPage.tsx
Normal file
@ -0,0 +1,85 @@
|
||||
import React from "react";
|
||||
import { PolicyPage } from "./PolicyPage";
|
||||
|
||||
export interface PrivacyPolicyPageProps {
|
||||
/** Business / site name used in the policy text. */
|
||||
siteName?: string;
|
||||
/** Contact email for privacy inquiries. */
|
||||
contactEmail?: string;
|
||||
/** Optional extra class names. */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/** Public page with privacy / cookie information. */
|
||||
export function PrivacyPolicyPage({
|
||||
siteName = "Our Store",
|
||||
contactEmail = "privacy@example.com",
|
||||
className,
|
||||
}: PrivacyPolicyPageProps) {
|
||||
return (
|
||||
<PolicyPage title="Privacy Policy" className={className}>
|
||||
<p>
|
||||
At <strong>{siteName}</strong>, we are committed to protecting your personal information
|
||||
and your right to privacy. This policy explains what information we collect, how we use
|
||||
it, and what rights you have in relation to it.
|
||||
</p>
|
||||
|
||||
<h3>Information We Collect</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Personal information:</strong> name, email, shipping address, and payment
|
||||
details provided during checkout.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Usage data:</strong> pages visited, time spent, browser type, and device
|
||||
information collected automatically.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Cookies:</strong> small data files stored on your device to improve your
|
||||
browsing experience and remember your preferences.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>How We Use Your Information</h3>
|
||||
<ul>
|
||||
<li>To process and fulfill your orders.</li>
|
||||
<li>To communicate with you about orders, updates, and promotions.</li>
|
||||
<li>To improve our website and services.</li>
|
||||
<li>To comply with legal obligations.</li>
|
||||
</ul>
|
||||
|
||||
<h3>Data Sharing</h3>
|
||||
<p>
|
||||
We do not sell your personal data. We share information only with service providers
|
||||
necessary to fulfill your order (e.g., payment processors, shipping carriers) and as
|
||||
required by law.
|
||||
</p>
|
||||
|
||||
<h3>Cookies</h3>
|
||||
<p>
|
||||
We use essential cookies for site functionality and optional analytics cookies to
|
||||
understand usage patterns. You can manage cookie preferences through your browser
|
||||
settings.
|
||||
</p>
|
||||
|
||||
<h3>Your Rights</h3>
|
||||
<p>
|
||||
You may request access to, correction of, or deletion of your personal data at any
|
||||
time by contacting us at{" "}
|
||||
<a href={`mailto:${contactEmail}`} className="text-primary underline">
|
||||
{contactEmail}
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
|
||||
<h3>Contact Us</h3>
|
||||
<p>
|
||||
If you have questions about this privacy policy, please contact us at{" "}
|
||||
<a href={`mailto:${contactEmail}`} className="text-primary underline">
|
||||
{contactEmail}
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</PolicyPage>
|
||||
);
|
||||
}
|
||||
62
packages/ecommerce/src/policies/ReturnsPage.tsx
Normal file
62
packages/ecommerce/src/policies/ReturnsPage.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import React from "react";
|
||||
import { RotateCcw, CheckCircle, XCircle, Clock } from "lucide-react";
|
||||
import { PolicyPage } from "./PolicyPage";
|
||||
|
||||
export interface ReturnsPageProps {
|
||||
/** Number of days for return window. */
|
||||
returnWindowDays?: number;
|
||||
/** Optional extra class names. */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/** Public page with refund / return policy. */
|
||||
export function ReturnsPage({ returnWindowDays = 30, className }: ReturnsPageProps) {
|
||||
return (
|
||||
<PolicyPage title="Returns & Refund Policy" className={className}>
|
||||
{/* Quick summary */}
|
||||
<div className="not-prose mb-8 grid gap-4 sm:grid-cols-2">
|
||||
{[
|
||||
{ icon: Clock, label: `${returnWindowDays}-day return window` },
|
||||
{ icon: RotateCcw, label: "Free returns on defective items" },
|
||||
{ icon: CheckCircle, label: "Full refund to original payment" },
|
||||
{ icon: XCircle, label: "No restocking fees" },
|
||||
].map(({ icon: Icon, label }) => (
|
||||
<div
|
||||
key={label}
|
||||
className="flex items-center gap-3 rounded-lg border border-border/50 bg-accent/5 p-4"
|
||||
>
|
||||
<Icon className="h-5 w-5 shrink-0 text-primary" />
|
||||
<span className="text-sm font-medium">{label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<h3>Eligibility</h3>
|
||||
<p>
|
||||
Items must be returned within <strong>{returnWindowDays} days</strong> of delivery in their
|
||||
original, unused condition with all tags and packaging intact.
|
||||
</p>
|
||||
|
||||
<h3>How to Initiate a Return</h3>
|
||||
<ol>
|
||||
<li>Contact our support team with your order number.</li>
|
||||
<li>Receive a prepaid return label (for defective items) or return instructions.</li>
|
||||
<li>Ship the item back using the provided label or your preferred carrier.</li>
|
||||
</ol>
|
||||
|
||||
<h3>Refund Processing</h3>
|
||||
<p>
|
||||
Once we receive and inspect the returned item, your refund will be processed within
|
||||
5–10 business days to your original payment method. You will receive an email
|
||||
confirmation when the refund has been issued.
|
||||
</p>
|
||||
|
||||
<h3>Exceptions</h3>
|
||||
<p>
|
||||
The following items are not eligible for return: gift cards, downloadable products,
|
||||
and items marked as final sale. Perishable goods cannot be returned unless they arrive
|
||||
damaged or defective.
|
||||
</p>
|
||||
</PolicyPage>
|
||||
);
|
||||
}
|
||||
88
packages/ecommerce/src/policies/ShippingPage.tsx
Normal file
88
packages/ecommerce/src/policies/ShippingPage.tsx
Normal file
@ -0,0 +1,88 @@
|
||||
import React from "react";
|
||||
import { Truck, Clock, Globe, DollarSign } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { PolicyPage } from "./PolicyPage";
|
||||
|
||||
export interface ShippingRate {
|
||||
region: string;
|
||||
method: string;
|
||||
estimate: string;
|
||||
price: string;
|
||||
}
|
||||
|
||||
export interface ShippingPageProps {
|
||||
/** Custom shipping rates to display. Falls back to placeholder content. */
|
||||
rates?: ShippingRate[];
|
||||
/** Optional extra class names. */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const defaultRates: ShippingRate[] = [
|
||||
{ region: "Domestic", method: "Standard", estimate: "5–7 business days", price: "$4.99" },
|
||||
{ region: "Domestic", method: "Express", estimate: "2–3 business days", price: "$12.99" },
|
||||
{ region: "International", method: "Standard", estimate: "10–20 business days", price: "$14.99" },
|
||||
{ region: "International", method: "Express", estimate: "5–8 business days", price: "$29.99" },
|
||||
];
|
||||
|
||||
/** Public page with shipping info and rates. */
|
||||
export function ShippingPage({ rates = defaultRates, className }: ShippingPageProps) {
|
||||
return (
|
||||
<PolicyPage title="Shipping Information" className={className}>
|
||||
{/* Highlights */}
|
||||
<div className="not-prose mb-8 grid gap-4 sm:grid-cols-2">
|
||||
{[
|
||||
{ icon: Truck, label: "Free shipping on orders over $75" },
|
||||
{ icon: Clock, label: "Same-day dispatch on orders before 2 PM" },
|
||||
{ icon: Globe, label: "We ship worldwide" },
|
||||
{ icon: DollarSign, label: "No hidden fees at checkout" },
|
||||
].map(({ icon: Icon, label }) => (
|
||||
<div
|
||||
key={label}
|
||||
className="flex items-center gap-3 rounded-lg border border-border/50 bg-accent/5 p-4"
|
||||
>
|
||||
<Icon className="h-5 w-5 shrink-0 text-primary" />
|
||||
<span className="text-sm font-medium">{label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Rates table */}
|
||||
<h3>Shipping Rates</h3>
|
||||
<div className="not-prose overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b text-left text-muted-foreground">
|
||||
<th className="pb-2 pr-4 font-medium">Region</th>
|
||||
<th className="pb-2 pr-4 font-medium">Method</th>
|
||||
<th className="pb-2 pr-4 font-medium">Estimate</th>
|
||||
<th className="pb-2 font-medium text-right">Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rates.map((r, i) => (
|
||||
<tr key={i} className={cn("border-b border-border/30", i % 2 === 0 && "bg-accent/5")}>
|
||||
<td className="py-2.5 pr-4">{r.region}</td>
|
||||
<td className="py-2.5 pr-4">{r.method}</td>
|
||||
<td className="py-2.5 pr-4 text-muted-foreground">{r.estimate}</td>
|
||||
<td className="py-2.5 text-right font-medium">{r.price}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>Processing Time</h3>
|
||||
<p>
|
||||
Orders placed before 2:00 PM (local time) on business days are typically processed and
|
||||
shipped the same day. Orders placed after this cut-off or on weekends/holidays will be
|
||||
processed the next business day.
|
||||
</p>
|
||||
|
||||
<h3>Tracking</h3>
|
||||
<p>
|
||||
Once your order ships, you will receive a confirmation email with a tracking number.
|
||||
You can use this number to track your package on the carrier's website.
|
||||
</p>
|
||||
</PolicyPage>
|
||||
);
|
||||
}
|
||||
77
packages/ecommerce/src/policies/TermsPage.tsx
Normal file
77
packages/ecommerce/src/policies/TermsPage.tsx
Normal file
@ -0,0 +1,77 @@
|
||||
import React from "react";
|
||||
import { PolicyPage } from "./PolicyPage";
|
||||
|
||||
export interface TermsPageProps {
|
||||
/** Business / site name. */
|
||||
siteName?: string;
|
||||
/** Contact email for legal inquiries. */
|
||||
contactEmail?: string;
|
||||
/** Optional extra class names. */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/** Optional terms of service page. */
|
||||
export function TermsPage({
|
||||
siteName = "Our Store",
|
||||
contactEmail = "legal@example.com",
|
||||
className,
|
||||
}: TermsPageProps) {
|
||||
return (
|
||||
<PolicyPage title="Terms of Service" className={className}>
|
||||
<p>
|
||||
By accessing and using <strong>{siteName}</strong>, you agree to be bound by these
|
||||
Terms of Service.
|
||||
</p>
|
||||
|
||||
<h3>Use of the Site</h3>
|
||||
<p>
|
||||
You agree to use this site only for lawful purposes and in a manner that does not
|
||||
infringe on the rights of others or restrict their use and enjoyment of the site.
|
||||
</p>
|
||||
|
||||
<h3>Products & Pricing</h3>
|
||||
<p>
|
||||
All product descriptions and prices are subject to change without notice. We reserve
|
||||
the right to modify or discontinue any product at any time. Prices are displayed in
|
||||
the store's base currency and may exclude taxes and shipping costs, which are
|
||||
calculated at checkout.
|
||||
</p>
|
||||
|
||||
<h3>Orders & Payment</h3>
|
||||
<p>
|
||||
By placing an order, you make an offer to purchase the selected products. We reserve
|
||||
the right to refuse or cancel any order for any reason, including pricing errors or
|
||||
suspected fraud.
|
||||
</p>
|
||||
|
||||
<h3>Intellectual Property</h3>
|
||||
<p>
|
||||
All content on this site — including text, images, logos, and software — is the
|
||||
property of {siteName} or its licensors and is protected by applicable intellectual
|
||||
property laws.
|
||||
</p>
|
||||
|
||||
<h3>Limitation of Liability</h3>
|
||||
<p>
|
||||
To the fullest extent permitted by law, {siteName} shall not be liable for any
|
||||
indirect, incidental, or consequential damages arising from your use of the site or
|
||||
purchase of products.
|
||||
</p>
|
||||
|
||||
<h3>Changes to These Terms</h3>
|
||||
<p>
|
||||
We may update these Terms of Service from time to time. Continued use of the site
|
||||
after changes constitutes acceptance of the revised terms.
|
||||
</p>
|
||||
|
||||
<h3>Contact</h3>
|
||||
<p>
|
||||
For questions about these terms, contact us at{" "}
|
||||
<a href={`mailto:${contactEmail}`} className="text-primary underline">
|
||||
{contactEmail}
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</PolicyPage>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user