create-bluecopa-react-app 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +76 -238
  2. package/package.json +1 -1
  3. package/templates/latest/{Agent.md → AGENT.md} +21 -27
  4. package/templates/latest/README.md +15 -38
  5. package/templates/latest/clean.sh +1 -0
  6. package/templates/latest/package-lock.json +8 -8
  7. package/templates/latest/package.json +1 -1
  8. package/templates/latest/setup.sh +5 -4
  9. package/templates/latest/src/App.tsx +11 -7
  10. package/templates/latest/src/components/charts/AreaChart.tsx +80 -0
  11. package/templates/latest/src/components/charts/DonutChart.tsx +73 -0
  12. package/templates/latest/src/components/charts/SparkAreaChart.tsx +52 -0
  13. package/templates/latest/src/components/layout/dashboard-header.tsx +1 -1
  14. package/templates/latest/src/components/layout/dashboard-layout.tsx +19 -11
  15. package/templates/latest/src/components/{page → layout}/navbar.tsx +2 -0
  16. package/templates/latest/src/components/layout/sidebar.tsx +2 -1
  17. package/templates/latest/src/components/page/dashboard/DashboardMetrics.tsx +97 -0
  18. package/templates/latest/src/components/page/dashboard/PaymentMethodsAnalysis.tsx +182 -0
  19. package/templates/latest/src/components/page/dashboard/RevenueAnalytics.tsx +505 -0
  20. package/templates/latest/src/components/page/dashboard/SalesAnalytics.tsx +313 -0
  21. package/templates/latest/src/components/page/dashboard/TransactionsTable.tsx +256 -0
  22. package/templates/latest/src/components/page/dashboard/dashboard-utils.ts +147 -0
  23. package/templates/latest/src/components/page/dashboard/dashboard.tsx +185 -0
  24. package/templates/latest/src/components/ui/bluecopa-logo.tsx +3 -0
  25. package/templates/latest/src/components/ui/label.tsx +0 -2
  26. package/templates/latest/src/components/ui/select.tsx +0 -2
  27. package/templates/latest/src/pages/Dashboard.tsx +1 -1
  28. package/templates/latest/src/single-spa.tsx +38 -28
  29. package/templates/latest/tailwind.config.js +1 -2
  30. package/templates/latest/tsconfig.app.json +6 -0
  31. package/templates/latest/tsconfig.json +6 -6
  32. package/templates/latest/tsconfig.node.json +5 -1
  33. package/templates/latest/vite.config.ts +1 -1
  34. package/templates/latest/src/components/page/dashboard.tsx +0 -1506
@@ -0,0 +1,147 @@
1
+ // Helper function to render query state
2
+ export const renderQueryState = (query: any, title: string) => {
3
+ if (query.isLoading) {
4
+ return {
5
+ status: 'loading',
6
+ message: `${title}: Loading...`
7
+ };
8
+ }
9
+
10
+ if (query.isError) {
11
+ return {
12
+ status: 'error',
13
+ message: `${title}: Error`
14
+ };
15
+ }
16
+
17
+ if (query.isSuccess) {
18
+ return {
19
+ status: 'success',
20
+ message: `${title}: Success`
21
+ };
22
+ }
23
+
24
+ return {
25
+ status: 'idle',
26
+ message: `${title}: Idle`
27
+ };
28
+ };
29
+
30
+ // Process data for ecommerce metrics and charts
31
+ export const processOrderData = (rawData: any[]) => {
32
+ return rawData.reduce((acc: any, transaction: any) => {
33
+ const existing = acc.find((item: any) => item.category === transaction.category);
34
+ if (existing) {
35
+ existing.total += transaction.total_amount;
36
+ existing.count += 1;
37
+ } else {
38
+ acc.push({
39
+ category: transaction.category,
40
+ total: transaction.total_amount,
41
+ count: 1
42
+ });
43
+ }
44
+ return acc;
45
+ }, []);
46
+ };
47
+
48
+ export const processPaymentMethodData = (rawData: any[]) => {
49
+ return rawData.reduce((acc: any, transaction: any) => {
50
+ const existing = acc.find((item: any) => item.method === transaction.payment_method);
51
+ if (existing) {
52
+ existing.total += transaction.total_amount;
53
+ existing.count += 1;
54
+ } else {
55
+ acc.push({
56
+ method: transaction.payment_method,
57
+ total: transaction.total_amount,
58
+ count: 1
59
+ });
60
+ }
61
+ return acc;
62
+ }, []);
63
+ };
64
+
65
+ export const processMonthlyRevenueData = (rawData: any[]) => {
66
+ return rawData.reduce((acc: any, transaction: any) => {
67
+ if (!transaction.transaction_date) return acc;
68
+
69
+ const date = new Date(transaction.transaction_date);
70
+ const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
71
+
72
+ const existing = acc.find((item: any) => item.month === monthKey);
73
+ if (existing) {
74
+ existing.revenue += transaction.total_amount;
75
+ existing.orders += 1;
76
+ } else {
77
+ acc.push({
78
+ month: monthKey,
79
+ revenue: transaction.total_amount,
80
+ orders: 1
81
+ });
82
+ }
83
+ return acc;
84
+ }, []).sort((a: any, b: any) => a.month.localeCompare(b.month));
85
+ };
86
+
87
+ export const processRecentTransactions = (rawData: any[]) => {
88
+ return rawData
89
+ .slice(0, 10)
90
+ .map((transaction: any) => ({
91
+ id: transaction.transaction_id,
92
+ customer: transaction.customer_name || 'N/A',
93
+ amount: transaction.total_amount,
94
+ category: transaction.category,
95
+ payment_method: transaction.payment_method,
96
+ date: transaction.transaction_date ? new Date(transaction.transaction_date).toLocaleDateString() : 'N/A'
97
+ }));
98
+ };
99
+
100
+ export const calculateMetrics = (rawData: any[]) => {
101
+ const totalOrders = rawData.length || 0;
102
+ const totalRevenue = rawData.reduce((sum: number, t: any) => sum + t.total_amount, 0);
103
+ const averageOrderValue = totalOrders > 0 ? totalRevenue / totalOrders : 0;
104
+
105
+ return {
106
+ totalOrders,
107
+ totalRevenue,
108
+ averageOrderValue
109
+ };
110
+ };
111
+
112
+ export const createEcommerceMetrics = (totalRevenue: number, totalOrders: number, averageOrderValue: number) => {
113
+ return [
114
+ {
115
+ title: 'Total Revenue',
116
+ value: `$${totalRevenue.toLocaleString()}`,
117
+ change: '+12.5%',
118
+ trend: 'up' as const,
119
+ icon: 'DollarSign',
120
+ color: 'text-green-600'
121
+ },
122
+ {
123
+ title: 'Orders',
124
+ value: totalOrders.toLocaleString(),
125
+ change: '+8.2%',
126
+ trend: 'up' as const,
127
+ icon: 'ShoppingCart',
128
+ color: 'text-blue-600'
129
+ },
130
+ {
131
+ title: 'Average Order Value',
132
+ value: `$${averageOrderValue.toFixed(2)}`,
133
+ change: '+3.1%',
134
+ trend: 'up' as const,
135
+ icon: 'TrendingUp',
136
+ color: 'text-purple-600'
137
+ },
138
+ {
139
+ title: 'Total Customers',
140
+ value: '2,847',
141
+ change: '+15.3%',
142
+ trend: 'up' as const,
143
+ icon: 'Users',
144
+ color: 'text-orange-600'
145
+ }
146
+ ];
147
+ };
@@ -0,0 +1,185 @@
1
+ 'use client'
2
+
3
+ import { Button } from '@/components/ui/button'
4
+ import { Alert, AlertDescription } from '@/components/ui/alert'
5
+ import { useMetricDataDemo, useDatasetDataDemo, useUserData } from '@/hooks/use-api'
6
+ import {
7
+ RefreshCw,
8
+ Loader2,
9
+ AlertCircle,
10
+ CheckCircle,
11
+ Clock
12
+ } from 'lucide-react'
13
+ import { DashboardMetrics } from './DashboardMetrics'
14
+ import { SalesAnalytics } from './SalesAnalytics'
15
+ import { PaymentMethodsAnalysis } from './PaymentMethodsAnalysis'
16
+ import { TransactionsTable } from './TransactionsTable'
17
+ import { RevenueAnalytics } from './RevenueAnalytics'
18
+ import {
19
+ processOrderData,
20
+ processPaymentMethodData,
21
+ processMonthlyRevenueData,
22
+ processRecentTransactions,
23
+ calculateMetrics,
24
+ createEcommerceMetrics,
25
+ renderQueryState as renderQueryStateUtil
26
+ } from './dashboard-utils'
27
+
28
+
29
+ export default function Dashboard() {
30
+ const metricQuery = useMetricDataDemo()
31
+ const datasetQuery = useDatasetDataDemo()
32
+ const userQuery = useUserData()
33
+
34
+ // Process data for ecommerce metrics and charts
35
+ const rawApiData = datasetQuery.data?.data?.data || []
36
+
37
+ // Fallback sample data when API returns empty data
38
+ const sampleTransactionData = [
39
+ { transaction_id: '001', customer_name: 'John Doe', total_amount: 1250, category: 'Electronics', payment_method: 'Credit Card', transaction_date: '2024-01-15', state: 'CA' },
40
+ { transaction_id: '002', customer_name: 'Jane Smith', total_amount: 780, category: 'Clothing', payment_method: 'PayPal', transaction_date: '2024-01-18', state: 'NY' },
41
+ { transaction_id: '003', customer_name: 'Mike Johnson', total_amount: 2100, category: 'Electronics', payment_method: 'Credit Card', transaction_date: '2024-02-02', state: 'TX' },
42
+ { transaction_id: '004', customer_name: 'Sarah Wilson', total_amount: 450, category: 'Books', payment_method: 'Debit Card', transaction_date: '2024-02-05', state: 'FL' },
43
+ { transaction_id: '005', customer_name: 'David Brown', total_amount: 890, category: 'Sports', payment_method: 'Credit Card', transaction_date: '2024-02-10', state: 'CA' },
44
+ { transaction_id: '006', customer_name: 'Lisa Garcia', total_amount: 1650, category: 'Electronics', payment_method: 'PayPal', transaction_date: '2024-02-15', state: 'WA' },
45
+ { transaction_id: '007', customer_name: 'Robert Lee', total_amount: 320, category: 'Books', payment_method: 'Cash', transaction_date: '2024-02-20', state: 'OR' },
46
+ { transaction_id: '008', customer_name: 'Emily Davis', total_amount: 950, category: 'Clothing', payment_method: 'Credit Card', transaction_date: '2024-03-01', state: 'NY' },
47
+ { transaction_id: '009', customer_name: 'Alex Rodriguez', total_amount: 1480, category: 'Sports', payment_method: 'Debit Card', transaction_date: '2024-03-05', state: 'TX' },
48
+ { transaction_id: '010', customer_name: 'Maria Martinez', total_amount: 670, category: 'Beauty', payment_method: 'PayPal', transaction_date: '2024-03-08', state: 'FL' },
49
+ { transaction_id: '011', customer_name: 'Chris Anderson', total_amount: 2200, category: 'Electronics', payment_method: 'Credit Card', transaction_date: '2024-03-12', state: 'CA' },
50
+ { transaction_id: '012', customer_name: 'Amanda White', total_amount: 520, category: 'Clothing', payment_method: 'Debit Card', transaction_date: '2024-03-15', state: 'WA' },
51
+ { transaction_id: '013', customer_name: 'James Taylor', total_amount: 1100, category: 'Sports', payment_method: 'Credit Card', transaction_date: '2024-03-18', state: 'OR' },
52
+ { transaction_id: '014', customer_name: 'Jennifer Moore', total_amount: 380, category: 'Books', payment_method: 'Cash', transaction_date: '2024-03-22', state: 'NY' },
53
+ { transaction_id: '015', customer_name: 'Kevin Jackson', total_amount: 1850, category: 'Electronics', payment_method: 'PayPal', transaction_date: '2024-03-25', state: 'TX' },
54
+ { transaction_id: '016', customer_name: 'Nicole Thompson', total_amount: 760, category: 'Beauty', payment_method: 'Credit Card', transaction_date: '2024-04-01', state: 'FL' },
55
+ { transaction_id: '017', customer_name: 'Brian Wilson', total_amount: 1320, category: 'Sports', payment_method: 'Debit Card', transaction_date: '2024-04-05', state: 'CA' },
56
+ { transaction_id: '018', customer_name: 'Jessica Clark', total_amount: 590, category: 'Clothing', payment_method: 'Credit Card', transaction_date: '2024-04-08', state: 'WA' },
57
+ { transaction_id: '019', customer_name: 'Michael Lewis', total_amount: 2400, category: 'Electronics', payment_method: 'PayPal', transaction_date: '2024-04-12', state: 'OR' },
58
+ { transaction_id: '020', customer_name: 'Ashley Hall', total_amount: 450, category: 'Books', payment_method: 'Cash', transaction_date: '2024-04-15', state: 'NY' }
59
+ ]
60
+
61
+ // Use real data if available, otherwise use sample data
62
+ const rawData = rawApiData.length > 0 ? rawApiData : sampleTransactionData
63
+
64
+ const orderData = processOrderData(rawData)
65
+ const paymentMethodData = processPaymentMethodData(rawData)
66
+ const monthlyRevenueData = processMonthlyRevenueData(rawData)
67
+ const recentTransactions = processRecentTransactions(rawData)
68
+ const { totalOrders, totalRevenue, averageOrderValue } = calculateMetrics(rawData)
69
+ const ecommerceMetrics = createEcommerceMetrics(totalRevenue, totalOrders, averageOrderValue)
70
+
71
+ // Helper function to render query state
72
+ const renderQueryState = (query: any, title: string) => {
73
+ const result = renderQueryStateUtil(query, title)
74
+
75
+ if (result.status === 'loading') {
76
+ return (
77
+ <div className="flex items-center gap-2 text-blue-600">
78
+ <Loader2 className="h-4 w-4 animate-spin" />
79
+ <span className="text-sm">{result.message}</span>
80
+ </div>
81
+ )
82
+ }
83
+
84
+ if (result.status === 'error') {
85
+ return (
86
+ <div className="flex items-center gap-2 text-red-600">
87
+ <AlertCircle className="h-4 w-4" />
88
+ <span className="text-sm">{result.message}</span>
89
+ </div>
90
+ )
91
+ }
92
+
93
+ if (result.status === 'success') {
94
+ return (
95
+ <div className="flex items-center gap-2 text-green-600">
96
+ <CheckCircle className="h-4 w-4" />
97
+ <span className="text-sm">{result.message}</span>
98
+ </div>
99
+ )
100
+ }
101
+
102
+ return (
103
+ <div className="flex items-center gap-2 text-gray-500">
104
+ <Clock className="h-4 w-4" />
105
+ <span className="text-sm">{result.message}</span>
106
+ </div>
107
+ )
108
+ }
109
+
110
+ return (
111
+ <div className="space-y-6">
112
+ {/* API Status */}
113
+ <div className="flex items-center justify-between">
114
+ <div className="flex items-center space-x-4">
115
+ {renderQueryState(metricQuery, 'Metrics API')}
116
+ {renderQueryState(datasetQuery, 'Dataset API')}
117
+ {renderQueryState(userQuery, 'User API')}
118
+ </div>
119
+ <Button
120
+ variant="outline"
121
+ size="sm"
122
+ onClick={() => {
123
+ metricQuery.refetch()
124
+ datasetQuery.refetch()
125
+ userQuery.refetch()
126
+ }}
127
+ disabled={metricQuery.isLoading || datasetQuery.isLoading || userQuery.isLoading ||
128
+ metricQuery.isFetching || datasetQuery.isFetching || userQuery.isFetching}
129
+ >
130
+ {(metricQuery.isFetching || datasetQuery.isFetching || userQuery.isFetching) ? (
131
+ <Loader2 className="h-4 w-4 mr-2 animate-spin" />
132
+ ) : (
133
+ <RefreshCw className="h-4 w-4 mr-2" />
134
+ )}
135
+ Refresh Data
136
+ </Button>
137
+ </div>
138
+
139
+ {/* Key Metrics */}
140
+ <DashboardMetrics
141
+ ecommerceMetrics={ecommerceMetrics}
142
+ monthlyRevenueData={monthlyRevenueData}
143
+ />
144
+
145
+ {/* Sales Analytics */}
146
+ <SalesAnalytics
147
+ orderData={orderData}
148
+ totalOrders={totalOrders}
149
+ totalRevenue={totalRevenue}
150
+ averageOrderValue={averageOrderValue}
151
+ />
152
+
153
+ {/* Payment Methods Analysis */}
154
+ <PaymentMethodsAnalysis
155
+ paymentMethodData={paymentMethodData}
156
+ />
157
+
158
+ {/* Recent Transactions */}
159
+ <TransactionsTable
160
+ recentTransactions={recentTransactions}
161
+ totalOrders={totalOrders}
162
+ />
163
+
164
+ {/* Revenue Analytics */}
165
+ <RevenueAnalytics
166
+ orderData={orderData}
167
+ monthlyRevenueData={monthlyRevenueData}
168
+ totalOrders={totalOrders}
169
+ totalRevenue={totalRevenue}
170
+ averageOrderValue={averageOrderValue}
171
+ />
172
+
173
+ {/* Data Source Info */}
174
+ {userQuery.data?.user && (
175
+ <Alert>
176
+ <AlertCircle className="h-4 w-4" />
177
+ <AlertDescription>
178
+ Data is being fetched from Copa-lib APIs. Current user: {userQuery.data.user.name}
179
+ ({userQuery.data.user.organization || 'No organization'})
180
+ </AlertDescription>
181
+ </Alert>
182
+ )}
183
+ </div>
184
+ )
185
+ }
@@ -20,6 +20,9 @@ export const BluecopaLogo: React.FC<BluecopaLogoProps> = ({
20
20
  width={width}
21
21
  height={height}
22
22
  className={className}
23
+ role="img"
24
+ aria-hidden="true"
25
+ focusable="false"
23
26
  >
24
27
  <defs>
25
28
  <style>
@@ -1,5 +1,3 @@
1
- "use client"
2
-
3
1
  import * as React from "react"
4
2
  import { cn } from "@/lib/utils"
5
3
 
@@ -1,5 +1,3 @@
1
- "use client"
2
-
3
1
  import * as React from "react"
4
2
  import { ChevronDown } from "lucide-react"
5
3
  import { cn } from "@/lib/utils"
@@ -1,5 +1,5 @@
1
1
  import DashboardLayout from '@/components/layout/dashboard-layout'
2
- import Dashboard from '@/components/page/dashboard'
2
+ import Dashboard from '@/components/page/dashboard/dashboard'
3
3
 
4
4
  export default function DashboardPage() {
5
5
  return (
@@ -1,8 +1,9 @@
1
- import React from 'react';
2
- import { createRoot, Root } from 'react-dom/client';
3
- import singleSpaReact from 'single-spa-react';
4
- import { MemoryRouter, BrowserRouter } from 'react-router-dom';
5
- import App from './App';
1
+ import React from "react";
2
+ import { createRoot, Root } from "react-dom/client";
3
+ import singleSpaReact from "single-spa-react";
4
+ import { MemoryRouter, BrowserRouter } from "react-router-dom";
5
+ import App from "./App";
6
+ import { AppProps } from "single-spa";
6
7
 
7
8
  // Single-spa lifecycle props interface
8
9
  interface LifecycleProps {
@@ -18,15 +19,15 @@ interface LifecycleProps {
18
19
  let root: Root | null = null;
19
20
 
20
21
  // Root component wrapper that handles routing
21
- const PnLExplorerRoot: React.FC<{ basename?: string; isMicroFrontend?: boolean }> = ({
22
- basename = '/',
23
- isMicroFrontend = false
24
- }) => {
22
+ const MicrofrontendRoot: React.FC<{
23
+ basename?: string;
24
+ isMicroFrontend?: boolean;
25
+ }> = ({ basename = "/", isMicroFrontend = false }) => {
25
26
  // Use MemoryRouter for micro-frontend to avoid conflicts with host routing
26
27
  // Use BrowserRouter for standalone mode
27
28
  const Router = isMicroFrontend ? MemoryRouter : BrowserRouter;
28
29
  const routerProps = isMicroFrontend ? {} : { basename };
29
-
30
+
30
31
  return (
31
32
  <Router {...routerProps}>
32
33
  <App />
@@ -38,13 +39,22 @@ const PnLExplorerRoot: React.FC<{ basename?: string; isMicroFrontend?: boolean }
38
39
  const lifecycles = singleSpaReact({
39
40
  React,
40
41
  ReactDOMClient: { createRoot },
41
- rootComponent: (props) => <PnLExplorerRoot isMicroFrontend={true} basename={props.basename} />,
42
- errorBoundary: (err, info, props) => {
43
- console.error('PnL Explorer Single-spa Error:', err, info);
44
- return <div>Something went wrong loading PnL Explorer</div>;
42
+ rootComponent: (props: AppProps & { basename: string }) => (
43
+ <MicrofrontendRoot isMicroFrontend={true} basename={props.basename} />
44
+ ),
45
+ errorBoundary: (err, info) => {
46
+ console.error("Microfrontend Single-spa Error:", err, info);
47
+ return <div>Something went wrong loading Microfrontend</div>;
48
+ },
49
+ renderType: "createRoot",
50
+ domElementGetter: () => {
51
+ const el = document.getElementById("single-spa-application:pnl-explorer");
52
+ if (!el)
53
+ throw new Error(
54
+ "Mount target #single-spa-application:pnl-explorer not found"
55
+ );
56
+ return el;
45
57
  },
46
- renderType: 'createRoot',
47
- domElementGetter: () => document.getElementById('single-spa-application:pnl-explorer') || document.body
48
58
  });
49
59
 
50
60
  // Export the single-spa lifecycle functions
@@ -53,7 +63,7 @@ export const { mount, unmount, bootstrap } = lifecycles;
53
63
  // Export a manual mount function for direct usage
54
64
  export const manualMount = async (props: LifecycleProps) => {
55
65
  if (!props.domElement) {
56
- throw new Error('domElement is required for mounting PnL Explorer');
66
+ throw new Error("domElement is required for mounting the application");
57
67
  }
58
68
 
59
69
  try {
@@ -65,20 +75,20 @@ export const manualMount = async (props: LifecycleProps) => {
65
75
 
66
76
  // Create new root
67
77
  root = createRoot(props.domElement);
68
-
78
+
69
79
  // Mount the application with the provided basename as micro-frontend
70
80
  root.render(
71
- <PnLExplorerRoot
81
+ <MicrofrontendRoot
72
82
  isMicroFrontend={true}
73
- basename={props.basename || '/app/external/pnl-explorer'}
83
+ basename={props.basename || "/app/external/microfrontend"}
74
84
  />
75
85
  );
76
86
 
77
- console.log('PnL Explorer mounted successfully');
78
- return Promise.resolve();
87
+ console.log("Microfrontend mounted successfully");
88
+ return;
79
89
  } catch (error) {
80
- console.error('Failed to mount PnL Explorer:', error);
81
- return Promise.reject(error);
90
+ console.error("Failed to mount Microfrontend:", error);
91
+ throw error;
82
92
  }
83
93
  };
84
94
 
@@ -89,10 +99,10 @@ export const manualUnmount = async () => {
89
99
  root.unmount();
90
100
  root = null;
91
101
  }
92
- console.log('PnL Explorer unmounted successfully');
102
+ console.log("Microfrontend unmounted successfully");
93
103
  return Promise.resolve();
94
104
  } catch (error) {
95
- console.error('Failed to unmount PnL Explorer:', error);
105
+ console.error("Failed to unmount Microfrontend:", error);
96
106
  return Promise.reject(error);
97
107
  }
98
108
  };
@@ -101,5 +111,5 @@ export const manualUnmount = async () => {
101
111
  export default {
102
112
  mount: manualMount,
103
113
  unmount: manualUnmount,
104
- bootstrap: () => Promise.resolve()
105
- };
114
+ bootstrap: () => Promise.resolve(),
115
+ };
@@ -2,8 +2,7 @@
2
2
  module.exports = {
3
3
  darkMode: ["class"],
4
4
  content: [
5
- './src/**/*.{ts,tsx}',
6
- './node_modules/@tremor/**/*.{js,ts,jsx,tsx}',
5
+ './src/**/*.{ts,tsx}'
7
6
  ],
8
7
  prefix: "",
9
8
  theme: {
@@ -14,6 +14,12 @@
14
14
  "noEmit": true,
15
15
  "jsx": "react-jsx",
16
16
 
17
+ /* Path aliases */
18
+ "baseUrl": ".",
19
+ "paths": {
20
+ "@/*": ["./src/*"]
21
+ },
22
+
17
23
  /* Linting */
18
24
  "strict": true,
19
25
  "noUnusedLocals": true,
@@ -9,11 +9,11 @@
9
9
  "paths": {
10
10
  "@/*": ["./src/*"]
11
11
  },
12
- "noImplicitAny": false,
13
- "noUnusedParameters": false,
14
- "skipLibCheck": true,
15
- "allowJs": true,
16
- "noUnusedLocals": false,
17
- "strictNullChecks": false
12
+ "strict": true,
13
+ "noImplicitAny": true,
14
+ "strictNullChecks": true,
15
+ "noUnusedParameters": true,
16
+ "noUnusedLocals": true,
17
+ "skipLibCheck": true
18
18
  }
19
19
  }
@@ -4,7 +4,11 @@
4
4
  "skipLibCheck": true,
5
5
  "module": "ESNext",
6
6
  "moduleResolution": "bundler",
7
- "allowSyntheticDefaultImports": true
7
+ "allowSyntheticDefaultImports": true,
8
+ "baseUrl": ".",
9
+ "paths": {
10
+ "@/*": ["./src/*"]
11
+ }
8
12
  },
9
13
  "include": ["vite.config.ts"]
10
14
  }
@@ -29,7 +29,7 @@ export default defineConfig(({ mode }) => {
29
29
  },
30
30
  shared: ["react", "react-dom"],
31
31
  }),
32
- ].filter(Boolean),
32
+ ],
33
33
  resolve: {
34
34
  alias: {
35
35
  "@": path.resolve(__dirname, "./src"),