diff --git a/package-lock.json b/package-lock.json index 0f1a53ea..9022ef8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -275,6 +275,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -812,6 +813,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -853,6 +855,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -880,6 +883,7 @@ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", "license": "MIT", + "peer": true, "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", @@ -1100,6 +1104,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -2761,6 +2766,7 @@ "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^14.21.3 || >=16" }, @@ -2911,6 +2917,7 @@ "integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "playwright": "1.57.0" }, @@ -2947,6 +2954,7 @@ "integrity": "sha512-QXFT+N/bva/QI2qoXmjBzL7D6aliPffIwP+81AdTGq0FXDoLxLkWivGMawG8iM5B9BKfxLIXxfWWAF6wbuJU6g==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=18.18" }, @@ -5376,6 +5384,7 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -5749,6 +5758,7 @@ "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -5781,6 +5791,7 @@ "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -5791,6 +5802,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -5855,6 +5867,7 @@ "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.48.1", "@typescript-eslint/types": "8.48.1", @@ -6616,6 +6629,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7030,6 +7044,7 @@ "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/types": "^7.26.0" } @@ -7163,6 +7178,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -8290,7 +8306,8 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/embla-carousel-react": { "version": "8.6.0", @@ -8657,6 +8674,7 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -8842,6 +8860,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -9181,6 +9200,7 @@ "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -11787,6 +11807,7 @@ "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", "license": "MIT", + "peer": true, "dependencies": { "@next/env": "16.1.6", "@swc/helpers": "0.5.15", @@ -11984,6 +12005,7 @@ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.11.tgz", "integrity": "sha512-gnXhNRE0FNhD7wPSCGhdNh46Hs6nm+uTyg+Kq0cZukNQiYdnCsoQjodNP9BQVG9XrcK/v6/MgpAPBUFyzh9pvw==", "license": "MIT-0", + "peer": true, "engines": { "node": ">=6.0.0" } @@ -12570,6 +12592,7 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", "license": "MIT", + "peer": true, "dependencies": { "pg-connection-string": "^2.9.1", "pg-pool": "^3.10.1", @@ -12730,6 +12753,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -12850,6 +12874,7 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -12902,6 +12927,7 @@ "integrity": "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@prisma/config": "6.19.0", "@prisma/engines": "6.19.0" @@ -13095,6 +13121,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -13125,6 +13152,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -13137,6 +13165,7 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.68.0.tgz", "integrity": "sha512-oNN3fjrZ/Xo40SWlHf1yCjlMK417JxoSJVUXQjGdvdRCU07NTFei1i1f8ApUAts+IVh14e4EdakeLEA+BEAs/Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=18.0.0" }, @@ -14631,6 +14660,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -14811,6 +14841,7 @@ "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" @@ -14963,6 +14994,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15268,6 +15300,7 @@ "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -15381,6 +15414,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -15394,6 +15428,7 @@ "integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.0.16", "@vitest/mocker": "4.0.16", @@ -15954,6 +15989,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/app/api/store/[slug]/orders/route.ts b/src/app/api/store/[slug]/orders/route.ts index 55bb6794..d1e6d7c0 100644 --- a/src/app/api/store/[slug]/orders/route.ts +++ b/src/app/api/store/[slug]/orders/route.ts @@ -79,9 +79,9 @@ function generateOrderNumber(): string { * Format currency for display */ function formatCurrency(amount: number, currency: string = 'BDT'): string { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency, + return 'BDT ' + new Intl.NumberFormat('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2, }).format(amount); } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8a60b811..ce5e8a6c 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -26,7 +26,11 @@ export const metadata: Metadata = { keywords: ["Next.js", "React", "TypeScript", "SaaS", "Multi-tenant", "Authentication"], authors: [{ name: "StormCom Team" }], creator: "StormCom", - metadataBase: new URL(process.env.NEXTAUTH_URL || "http://localhost:3000"), + metadataBase: new URL( + (typeof process.env.NEXTAUTH_URL === 'string' && process.env.NEXTAUTH_URL.length > 0) + ? process.env.NEXTAUTH_URL.replace(/^["']|["']$/g, '').trim() + : "http://localhost:3000" + ), openGraph: { type: "website", locale: "en_US", diff --git a/src/components/analytics-dashboard.tsx b/src/components/analytics-dashboard.tsx index 0d7f3860..8809702f 100644 --- a/src/components/analytics-dashboard.tsx +++ b/src/components/analytics-dashboard.tsx @@ -95,9 +95,7 @@ export function AnalyticsDashboard({ storeId, dateRange }: AnalyticsDashboardPro // Format currency const formatCurrency = (amount: number) => { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'BDT', + return 'BDT ' + new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(amount); diff --git a/src/components/analytics/analytics-dashboard.tsx b/src/components/analytics/analytics-dashboard.tsx index 230f6167..6eb1058c 100644 --- a/src/components/analytics/analytics-dashboard.tsx +++ b/src/components/analytics/analytics-dashboard.tsx @@ -146,9 +146,9 @@ export function AnalyticsDashboard({ storeId: propStoreId }: AnalyticsDashboardP }, [timeRange, storeId]); const formatCurrency = (value: number) => { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'BDT', + return 'BDT ' + new Intl.NumberFormat('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2, }).format(value); }; diff --git a/src/components/analytics/customer-metrics.tsx b/src/components/analytics/customer-metrics.tsx index 89a2a932..7d4b1f3f 100644 --- a/src/components/analytics/customer-metrics.tsx +++ b/src/components/analytics/customer-metrics.tsx @@ -75,9 +75,9 @@ export function CustomerMetrics({ storeId, timeRange }: CustomerMetricsProps) { const formatCurrency = (value: number | undefined | null) => { if (value === null || value === undefined) return 'BDT 0.00'; - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'BDT', + return 'BDT ' + new Intl.NumberFormat('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2, }).format(value); }; diff --git a/src/components/analytics/revenue-chart.tsx b/src/components/analytics/revenue-chart.tsx index aa2b7ac8..3ebb2234 100644 --- a/src/components/analytics/revenue-chart.tsx +++ b/src/components/analytics/revenue-chart.tsx @@ -88,10 +88,9 @@ export function RevenueChart({ storeId, timeRange }: RevenueChartProps) { } const formatCurrency = (value: number) => { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'BDT', + return 'BDT ' + new Intl.NumberFormat('en-US', { minimumFractionDigits: 0, + maximumFractionDigits: 0, }).format(value); }; diff --git a/src/components/analytics/top-products-table.tsx b/src/components/analytics/top-products-table.tsx index 4ed752e7..30b73594 100644 --- a/src/components/analytics/top-products-table.tsx +++ b/src/components/analytics/top-products-table.tsx @@ -57,10 +57,9 @@ export function TopProductsTable({ storeId, timeRange }: TopProductsTableProps) }, [storeId, timeRange]); const formatCurrency = (value: number) => { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'BDT', + return 'BDT ' + new Intl.NumberFormat('en-US', { minimumFractionDigits: 0, + maximumFractionDigits: 0, }).format(value); }; diff --git a/src/components/customers/customer-detail-dialog.tsx b/src/components/customers/customer-detail-dialog.tsx index 2c3c04aa..c9629bbf 100644 --- a/src/components/customers/customer-detail-dialog.tsx +++ b/src/components/customers/customer-detail-dialog.tsx @@ -44,9 +44,9 @@ export function CustomerDetailDialog({ onOpenChange, }: CustomerDetailDialogProps) { const formatCurrency = (value: number) => { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'BDT', + return 'BDT ' + new Intl.NumberFormat('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2, }).format(value); }; diff --git a/src/components/customers/customers-list.tsx b/src/components/customers/customers-list.tsx index ae4de694..1ed1a114 100644 --- a/src/components/customers/customers-list.tsx +++ b/src/components/customers/customers-list.tsx @@ -150,9 +150,9 @@ export function CustomersList({ storeId }: CustomersListProps) { }; const formatCurrency = (value: number) => { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'BDT', + return 'BDT ' + new Intl.NumberFormat('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2, }).format(value); }; diff --git a/src/components/order-detail-client.tsx b/src/components/order-detail-client.tsx index 2467b413..a1b29fc7 100644 --- a/src/components/order-detail-client.tsx +++ b/src/components/order-detail-client.tsx @@ -319,9 +319,9 @@ export function OrderDetailClient({ orderId, storeId }: OrderDetailClientProps) // Format currency const formatCurrency = (amount: number) => { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'BDT', + return 'BDT ' + new Intl.NumberFormat('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2, }).format(amount); }; diff --git a/src/components/orders-table.tsx b/src/components/orders-table.tsx index 5b842e9b..f0784b4c 100644 --- a/src/components/orders-table.tsx +++ b/src/components/orders-table.tsx @@ -150,9 +150,9 @@ const paymentStatusColors: Record = { // Format currency const formatCurrency = (amount: number) => { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'BDT', + return 'BDT ' + new Intl.NumberFormat('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2, }).format(amount); }; diff --git a/src/components/orders/refund-dialog.tsx b/src/components/orders/refund-dialog.tsx index 8d706f98..8438655d 100644 --- a/src/components/orders/refund-dialog.tsx +++ b/src/components/orders/refund-dialog.tsx @@ -54,7 +54,10 @@ export function RefundDialog({ const refundableBalance = totalAmount - refundedAmount; const formatCurrency = (amount: number) => - new Intl.NumberFormat('en-US', { style: 'currency', currency: 'BDT' }).format(amount); + 'BDT ' + new Intl.NumberFormat('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }).format(amount); const handleRefund = async () => { setError(''); diff --git a/src/lib/utils.ts b/src/lib/utils.ts index bf12c16c..a6c6ac7f 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -16,9 +16,7 @@ export function formatCurrency( currency: string = "BDT", locale: string = "en-US" ): string { - return new Intl.NumberFormat(locale, { - style: "currency", - currency, + return currency + ' ' + new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(amount / 100); // Assuming amounts are stored in paisa @@ -35,9 +33,7 @@ export function formatCurrencyFromTaka( currency: string = "BDT", locale: string = "en-US" ): string { - return new Intl.NumberFormat(locale, { - style: "currency", - currency, + return currency + ' ' + new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(amount);