create-bluecopa-react-app 1.0.41 → 1.0.42

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 (102) hide show
  1. package/README.md +7 -5
  2. package/package.json +1 -1
  3. package/templates/latest/.claude/settings.local.json +56 -0
  4. package/templates/latest/.env.example +8 -0
  5. package/templates/latest/Agent.md +598 -775
  6. package/templates/latest/CLAUDE.md +759 -0
  7. package/templates/latest/README.md +11 -2
  8. package/templates/latest/app/app.css +292 -85
  9. package/templates/latest/app/app.tsx +48 -39
  10. package/templates/latest/app/components/bluecopa-logo.tsx +20 -0
  11. package/templates/latest/app/components/charts/bar-chart.tsx +132 -0
  12. package/templates/latest/app/components/charts/base-chart.tsx +149 -0
  13. package/templates/latest/app/components/charts/chart-provider.tsx +71 -0
  14. package/templates/latest/app/components/charts/chart-theme.ts +262 -0
  15. package/templates/latest/app/components/charts/chart-utils.ts +142 -0
  16. package/templates/latest/app/components/charts/donut-chart.tsx +110 -0
  17. package/templates/latest/app/components/charts/index.ts +5 -0
  18. package/templates/latest/app/components/layouts/app-layout.tsx +22 -0
  19. package/templates/latest/app/components/layouts/app-sidebar.tsx +88 -0
  20. package/templates/latest/app/components/layouts/nav-main.tsx +50 -0
  21. package/templates/latest/app/components/layouts/nav-user.tsx +38 -0
  22. package/templates/latest/app/components/layouts/site-header.tsx +93 -0
  23. package/templates/latest/app/components/loading-screen.tsx +41 -0
  24. package/templates/latest/app/components/ui/ag-grid-table.tsx +79 -0
  25. package/templates/latest/app/components/ui/button.tsx +23 -23
  26. package/templates/latest/app/components/ui/card.tsx +20 -20
  27. package/templates/latest/app/components/ui/dropdown-menu.tsx +54 -49
  28. package/templates/latest/app/components/ui/input.tsx +8 -8
  29. package/templates/latest/app/components/ui/label.tsx +8 -8
  30. package/templates/latest/app/components/ui/separator.tsx +7 -7
  31. package/templates/latest/app/components/ui/sheet.tsx +43 -32
  32. package/templates/latest/app/components/ui/sidebar.tsx +240 -235
  33. package/templates/latest/app/components/ui/skeleton.tsx +4 -4
  34. package/templates/latest/app/components/ui/sonner.tsx +6 -9
  35. package/templates/latest/app/components/ui/tabs.tsx +15 -15
  36. package/templates/latest/app/components/ui/tooltip.tsx +18 -12
  37. package/templates/latest/app/constants/index.ts +31 -0
  38. package/templates/latest/app/contexts/app-context.tsx +201 -0
  39. package/templates/latest/app/hooks/use-mobile.ts +13 -12
  40. package/templates/latest/app/main.tsx +1 -1
  41. package/templates/latest/app/pages/dashboard.tsx +246 -0
  42. package/templates/latest/app/pages/payments.tsx +182 -0
  43. package/templates/latest/app/pages/settings.tsx +128 -0
  44. package/templates/latest/app/routes/index.tsx +19 -0
  45. package/templates/latest/app/single-spa.tsx +69 -186
  46. package/templates/latest/app/types/index.ts +37 -0
  47. package/templates/latest/app/utils/ag-grid-datasource.ts +63 -0
  48. package/templates/latest/app/utils/ag-grid-license.ts +12 -0
  49. package/templates/latest/app/utils/ag-grid-theme.ts +9 -0
  50. package/templates/latest/app/utils/component-style.ts +7 -0
  51. package/templates/latest/app/utils/style-drivers.ts +24 -0
  52. package/templates/latest/app/utils/utils.ts +10 -0
  53. package/templates/latest/components.json +3 -3
  54. package/templates/latest/index.html +30 -2
  55. package/templates/latest/package-lock.json +15 -401
  56. package/templates/latest/package.json +8 -18
  57. package/templates/latest/preview/index.html +125 -285
  58. package/templates/latest/public/favicon.svg +1 -0
  59. package/templates/latest/vite.config.ts +2 -8
  60. package/templates/latest/app/components/app-sidebar.tsx +0 -182
  61. package/templates/latest/app/components/chart-area-interactive.tsx +0 -290
  62. package/templates/latest/app/components/data-table.tsx +0 -807
  63. package/templates/latest/app/components/nav-documents.tsx +0 -92
  64. package/templates/latest/app/components/nav-main.tsx +0 -40
  65. package/templates/latest/app/components/nav-secondary.tsx +0 -42
  66. package/templates/latest/app/components/nav-user.tsx +0 -111
  67. package/templates/latest/app/components/section-cards.tsx +0 -102
  68. package/templates/latest/app/components/site-header.tsx +0 -28
  69. package/templates/latest/app/components/ui/avatar.tsx +0 -53
  70. package/templates/latest/app/components/ui/badge.tsx +0 -46
  71. package/templates/latest/app/components/ui/breadcrumb.tsx +0 -109
  72. package/templates/latest/app/components/ui/chart.tsx +0 -352
  73. package/templates/latest/app/components/ui/checkbox.tsx +0 -30
  74. package/templates/latest/app/components/ui/drawer.tsx +0 -139
  75. package/templates/latest/app/components/ui/select.tsx +0 -183
  76. package/templates/latest/app/components/ui/table.tsx +0 -117
  77. package/templates/latest/app/components/ui/toggle-group.tsx +0 -73
  78. package/templates/latest/app/components/ui/toggle.tsx +0 -47
  79. package/templates/latest/app/data/data.json +0 -614
  80. package/templates/latest/app/data/mock-payments.json +0 -122
  81. package/templates/latest/app/data/mock-transactions.json +0 -128
  82. package/templates/latest/app/hooks/use-bluecopa-user.ts +0 -37
  83. package/templates/latest/app/lib/utils.ts +0 -6
  84. package/templates/latest/app/routes/apitest.tsx +0 -2118
  85. package/templates/latest/app/routes/comments.tsx +0 -588
  86. package/templates/latest/app/routes/dashboard.tsx +0 -36
  87. package/templates/latest/app/routes/payments.tsx +0 -342
  88. package/templates/latest/app/routes/statements.tsx +0 -493
  89. package/templates/latest/app/routes/websocket.tsx +0 -450
  90. package/templates/latest/app/routes.tsx +0 -22
  91. package/templates/latest/dist/assets/__federation_expose_App-D-lv9y21.js +0 -161
  92. package/templates/latest/dist/assets/__federation_fn_import-CzfA7kmP.js +0 -438
  93. package/templates/latest/dist/assets/__federation_shared_react-Bp6HVBS4.js +0 -16
  94. package/templates/latest/dist/assets/__federation_shared_react-dom-BCcRGiYp.js +0 -17
  95. package/templates/latest/dist/assets/client-Dms8K6Dw.js +0 -78879
  96. package/templates/latest/dist/assets/index-BrhXrqF7.js +0 -60
  97. package/templates/latest/dist/assets/index-BzNimew1.js +0 -69
  98. package/templates/latest/dist/assets/index-DMFtQdNS.js +0 -412
  99. package/templates/latest/dist/assets/remoteEntry.css +0 -3996
  100. package/templates/latest/dist/assets/remoteEntry.js +0 -88
  101. package/templates/latest/dist/favicon.ico +0 -0
  102. package/templates/latest/dist/index.html +0 -19
@@ -2,7 +2,6 @@
2
2
 
3
3
  A modern, production-ready template for building full-stack React applications using React Router v7 and shadcn/ui components.
4
4
 
5
-
6
5
  ## Features
7
6
 
8
7
  - 🚀 **React Router v7** - Latest React Router with server-side rendering
@@ -59,11 +58,13 @@ Your application will be available at `http://localhost:8080`.
59
58
  This template includes a comprehensive set of shadcn/ui components:
60
59
 
61
60
  ### Layout Components
61
+
62
62
  - **Sidebar** - Collapsible navigation sidebar with mobile support
63
63
  - **Sheet** - Slide-out panels for mobile navigation
64
64
  - **Drawer** - Bottom drawer for mobile interactions
65
65
 
66
66
  ### Form Components
67
+
67
68
  - **Button** - Multiple variants and sizes
68
69
  - **Input** - Text input with validation states
69
70
  - **Select** - Dropdown selection with search
@@ -71,6 +72,7 @@ This template includes a comprehensive set of shadcn/ui components:
71
72
  - **Label** - Accessible form labels
72
73
 
73
74
  ### Data Display
75
+
74
76
  - **Table** - Sortable, filterable data tables with TanStack Table
75
77
  - **Card** - Content containers with header, content, and footer
76
78
  - **Badge** - Status indicators and labels
@@ -78,16 +80,19 @@ This template includes a comprehensive set of shadcn/ui components:
78
80
  - **Skeleton** - Loading placeholders
79
81
 
80
82
  ### Navigation
83
+
81
84
  - **Tabs** - Tabbed content organization
82
85
  - **Breadcrumb** - Navigation breadcrumbs
83
86
  - **Dropdown Menu** - Context menus and actions
84
87
  - **Tooltip** - Hover information
85
88
 
86
89
  ### Feedback
90
+
87
91
  - **Sonner** - Toast notifications
88
92
  - **Separator** - Visual content dividers
89
93
 
90
94
  ### Charts
95
+
91
96
  - **Interactive Charts** - Recharts integration with hover states
92
97
  - **Area Charts** - Time series data visualization
93
98
 
@@ -105,9 +110,11 @@ VITE_BLUECOPA_API_TOKEN=your_base64_encoded_token_here
105
110
  ```
106
111
 
107
112
  **Note:** `VITE_BLUECOPA_API_TOKEN` should be a base64-encoded JSON string containing an `accessToken` field, for example:
113
+
108
114
  ```json
109
- {"accessToken": "your_access_token_here"}
115
+ { "accessToken": "your_access_token_here" }
110
116
  ```
117
+
111
118
  encoded as base64.
112
119
 
113
120
  If the API errors out or is not configured, the application will show "Set Environment" as the user name with email "setenv@email.com" as a fallback.
@@ -124,6 +131,7 @@ This template includes a comprehensive example of using Bluecopa statement hooks
124
131
  - **useCreateStatementRun** - Creating new statement runs with mutations
125
132
 
126
133
  The example includes two pre-configured statement IDs:
134
+
127
135
  - Example 1: `MDYK9CU8NR1S41AFAOEX` (uses default view)
128
136
  - Example 2: `MGIZ7GD08NQJ71SK8RA7` with View ID `MGJ1ZF0JN53B0V0YH10Z`
129
137
 
@@ -193,6 +201,7 @@ npx shadcn-ui@latest add toast
193
201
  ## Styling
194
202
 
195
203
  This template comes with [Tailwind CSS v4](https://tailwindcss.com/) configured with:
204
+
196
205
  - CSS variables for theming
197
206
  - Dark mode support with next-themes
198
207
  - shadcn/ui design system
@@ -1,26 +1,82 @@
1
- @import "tailwindcss";
2
- @import "tw-animate-css";
1
+ /*
2
+ * MFE CSS Strategy:
3
+ * - NO global preflight — we skip Tailwind's base reset to avoid leaking into the host app
4
+ * - Scoped reset under .mfe-root — only affects the MFE subtree
5
+ * - copa: prefix on all utilities — prevents class name collisions
6
+ * - Custom utilities scoped under .mfe-root — prevents naming collisions
7
+ */
3
8
 
4
- @custom-variant dark (&:is(.dark *));
9
+ /* Import Tailwind WITHOUT preflight — preflight resets *, html, body globally which leaks into the host */
10
+ /* @import "tailwindcss/preflight" — INTENTIONALLY SKIPPED (global resets leak into host app) */
11
+ @import "tailwindcss/theme" prefix(copa);
12
+ @import "tailwindcss/utilities" prefix(copa);
13
+ @import "tw-animate-css";
5
14
 
15
+ /* ===== BUILD-TIME THEME (resolved at compile) ===== */
6
16
  @theme {
7
- --font-sans: "Satoshi", ui-sans-serif, system-ui, sans-serif;
8
- }
17
+ /* Breakpoints (required — Tailwind v4 prefix does not auto-include defaults) */
18
+ --breakpoint-sm: 40rem;
19
+ --breakpoint-md: 48rem;
20
+ --breakpoint-lg: 64rem;
21
+ --breakpoint-xl: 80rem;
22
+ --breakpoint-2xl: 96rem;
9
23
 
10
- html,
11
- body {
12
- @apply bg-white dark:bg-gray-950;
24
+ /* Font family */
25
+ --font-sans: "Satoshi", sans-serif;
26
+ --font-mono: "Satoshi", sans-serif;
13
27
 
14
- @media (prefers-color-scheme: dark) {
15
- color-scheme: dark;
16
- }
28
+ /* Fluid type scale (from Dream Light _typography.css — exact values) */
29
+ --text-xs: 0.702rem;
30
+ --text-xs--line-height: 1.053rem;
31
+ --text-sm: 0.835rem;
32
+ --text-sm--line-height: 1.258rem;
33
+ --text-md: 1.004rem;
34
+ --text-md--line-height: 1.513rem;
35
+ --text-lg: 1.21rem;
36
+ --text-lg--line-height: 1.815rem;
37
+ --text-xl: 1.452rem;
38
+ --text-xl--line-height: 2.190rem;
39
+ --text-2xl: 1.742rem;
40
+ --text-2xl--line-height: 2.626rem;
41
+ --text-3xl: 2.093rem;
42
+ --text-3xl--line-height: 3.146rem;
43
+ --text-4xl: 2.505rem;
44
+ --text-4xl--line-height: 3.763rem;
45
+ --text-5xl: 3.013rem;
46
+ --text-5xl--line-height: 4.513rem;
47
+
48
+ /* Heading scale */
49
+ --text-h1: 3rem;
50
+ --text-h1--line-height: 4.5rem;
51
+ --text-h2: 2.25rem;
52
+ --text-h2--line-height: 3.375rem;
53
+ --text-h3: 1.875rem;
54
+ --text-h3--line-height: 2.8125rem;
55
+ --text-h4: 1.5rem;
56
+ --text-h4--line-height: 2.25rem;
57
+ --text-h5: 1.25rem;
58
+ --text-h5--line-height: 1.875rem;
59
+ --text-h6: 1rem;
60
+ --text-h6--line-height: 1.5rem;
61
+ --text-body: 0.875rem;
62
+ --text-body--line-height: 1.2rem;
63
+ --text-caption: 0.75rem;
64
+ --text-caption--line-height: 0.95rem;
65
+
66
+ /* Radius (from Dream Light _spacing.css) */
67
+ --card-radius: 1.25rem;
68
+ --rounded-input: 12px;
17
69
  }
18
70
 
71
+ /* ===== RUNTIME THEME (CSS vars bound at runtime) ===== */
19
72
  @theme inline {
73
+ /* Radius (computed from --radius in .mfe-root) */
20
74
  --radius-sm: calc(var(--radius) - 4px);
21
75
  --radius-md: calc(var(--radius) - 2px);
22
76
  --radius-lg: var(--radius);
23
77
  --radius-xl: calc(var(--radius) + 4px);
78
+
79
+ /* Colors */
24
80
  --color-background: var(--background);
25
81
  --color-foreground: var(--foreground);
26
82
  --color-card: var(--card);
@@ -39,11 +95,8 @@ body {
39
95
  --color-border: var(--border);
40
96
  --color-input: var(--input);
41
97
  --color-ring: var(--ring);
42
- --color-chart-1: var(--chart-1);
43
- --color-chart-2: var(--chart-2);
44
- --color-chart-3: var(--chart-3);
45
- --color-chart-4: var(--chart-4);
46
- --color-chart-5: var(--chart-5);
98
+
99
+ /* Sidebar */
47
100
  --color-sidebar: var(--sidebar);
48
101
  --color-sidebar-foreground: var(--sidebar-foreground);
49
102
  --color-sidebar-primary: var(--sidebar-primary);
@@ -54,80 +107,234 @@ body {
54
107
  --color-sidebar-ring: var(--sidebar-ring);
55
108
  }
56
109
 
57
- :root {
58
- --radius: 0.65rem;
59
- --background: oklch(1 0 0);
60
- --foreground: oklch(0.141 0.005 285.823);
61
- --card: oklch(1 0 0);
62
- --card-foreground: oklch(0.141 0.005 285.823);
63
- --popover: oklch(1 0 0);
64
- --popover-foreground: oklch(0.141 0.005 285.823);
65
- --primary: oklch(0.623 0.214 259.815);
66
- --primary-foreground: oklch(0.97 0.014 254.604);
67
- --secondary: oklch(0.967 0.001 286.375);
68
- --secondary-foreground: oklch(0.21 0.006 285.885);
69
- --muted: oklch(0.967 0.001 286.375);
70
- --muted-foreground: oklch(0.552 0.016 285.938);
71
- --accent: oklch(0.967 0.001 286.375);
72
- --accent-foreground: oklch(0.21 0.006 285.885);
110
+ /* ===== MFE-SCOPED VARIABLES (light theme-modern from Dream Light _colors.css) ===== */
111
+ .mfe-root {
112
+ /* Radius (Dream Light _spacing.css) */
113
+ --radius: 1rem;
114
+
115
+ /* Colors (exact values from Dream Light _colors.css) */
116
+ --background: oklch(0.975 0.005 280);
117
+ --foreground: oklch(0.145 0 0);
118
+ --card: oklch(0.995 0.003 280 / 0.85);
119
+ --card-foreground: oklch(0.145 0 0);
120
+ --popover: oklch(0.995 0.003 280);
121
+ --popover-foreground: oklch(0.145 0 0);
122
+ --primary: #3548ff;
123
+ --primary-foreground: oklch(100% 0 0);
124
+ --primary-lighter: #ebf4ff;
125
+ --secondary: oklch(0.97 0.003 280);
126
+ --secondary-foreground: oklch(0.205 0 0);
127
+ --muted: oklch(0.97 0.003 280);
128
+ --muted-foreground: oklch(0.556 0 0);
129
+ --accent: oklch(0.97 0.003 280);
130
+ --accent-foreground: oklch(0.205 0 0);
73
131
  --destructive: oklch(0.577 0.245 27.325);
74
- --border: oklch(0.92 0.004 286.32);
75
- --input: oklch(0.92 0.004 286.32);
76
- --ring: oklch(0.623 0.214 259.815);
77
- --chart-1: oklch(0.646 0.222 41.116);
78
- --chart-2: oklch(0.6 0.118 184.704);
79
- --chart-3: oklch(0.398 0.07 227.392);
80
- --chart-4: oklch(0.828 0.189 84.429);
81
- --chart-5: oklch(0.769 0.188 70.08);
82
- --sidebar: oklch(0.985 0 0);
83
- --sidebar-foreground: oklch(0.141 0.005 285.823);
84
- --sidebar-primary: oklch(0.623 0.214 259.815);
85
- --sidebar-primary-foreground: oklch(0.97 0.014 254.604);
86
- --sidebar-accent: oklch(0.967 0.001 286.375);
87
- --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
88
- --sidebar-border: oklch(0.92 0.004 286.32);
89
- --sidebar-ring: oklch(0.623 0.214 259.815);
90
- }
132
+ --border: oklch(0.92 0.005 280);
133
+ --input: oklch(0.92 0.005 280);
134
+ --ring: oklch(0.25 0.08 9);
135
+
136
+ /* Sidebar (Dream Light — white panel, subtle border) */
137
+ --sidebar: oklch(1 0 0);
138
+ --sidebar-foreground: oklch(0.145 0 0);
139
+ --sidebar-primary: oklch(0.205 0 0);
140
+ --sidebar-primary-foreground: oklch(0.985 0 0);
141
+ --sidebar-accent: oklch(0.96 0.003 280);
142
+ --sidebar-accent-foreground: oklch(0.205 0 0);
143
+ --sidebar-border: oklch(0.92 0.004 280);
144
+ --sidebar-ring: oklch(0.708 0 0);
145
+
146
+ /* Semantic status colors */
147
+ --status-success: oklch(0.72 0.19 142);
148
+ --status-success-bg: oklch(0.95 0.05 142);
149
+ --status-success-border: oklch(0.80 0.12 142);
150
+ --status-warning: oklch(0.80 0.18 85);
151
+ --status-warning-bg: oklch(0.96 0.06 85);
152
+ --status-warning-border: oklch(0.85 0.12 85);
153
+ --status-error: oklch(0.63 0.24 25);
154
+ --status-error-bg: oklch(0.95 0.04 25);
155
+ --status-error-border: oklch(0.75 0.15 25);
156
+ --status-info: oklch(0.62 0.19 250);
157
+ --status-info-bg: oklch(0.95 0.04 250);
158
+ --status-info-border: oklch(0.75 0.12 250);
91
159
 
92
- .dark {
93
- --background: oklch(0.141 0.005 285.823);
94
- --foreground: oklch(0.985 0 0);
95
- --card: oklch(0.21 0.006 285.885);
96
- --card-foreground: oklch(0.985 0 0);
97
- --popover: oklch(0.21 0.006 285.885);
98
- --popover-foreground: oklch(0.985 0 0);
99
- --primary: oklch(0.546 0.245 262.881);
100
- --primary-foreground: oklch(0.379 0.146 265.522);
101
- --secondary: oklch(0.274 0.006 286.033);
102
- --secondary-foreground: oklch(0.985 0 0);
103
- --muted: oklch(0.274 0.006 286.033);
104
- --muted-foreground: oklch(0.705 0.015 286.067);
105
- --accent: oklch(0.274 0.006 286.033);
106
- --accent-foreground: oklch(0.985 0 0);
107
- --destructive: oklch(0.704 0.191 22.216);
108
- --border: oklch(1 0 0 / 10%);
109
- --input: oklch(1 0 0 / 15%);
110
- --ring: oklch(0.488 0.243 264.376);
111
- --chart-1: oklch(0.488 0.243 264.376);
112
- --chart-2: oklch(0.696 0.17 162.48);
113
- --chart-3: oklch(0.769 0.188 70.08);
114
- --chart-4: oklch(0.627 0.265 303.9);
115
- --chart-5: oklch(0.645 0.246 16.439);
116
- --sidebar: oklch(0.21 0.006 285.885);
117
- --sidebar-foreground: oklch(0.985 0 0);
118
- --sidebar-primary: oklch(0.546 0.245 262.881);
119
- --sidebar-primary-foreground: oklch(0.379 0.146 265.522);
120
- --sidebar-accent: oklch(0.274 0.006 286.033);
121
- --sidebar-accent-foreground: oklch(0.985 0 0);
122
- --sidebar-border: oklch(1 0 0 / 10%);
123
- --sidebar-ring: oklch(0.488 0.243 264.376);
160
+ /* Spacing (theme-modern preset) */
161
+ --spacing-sm: 0.5rem;
162
+ --spacing-md: 1rem;
163
+ --spacing-lg: 1.5rem;
164
+ --spacing-xl: 2rem;
165
+
166
+ /* Chart colors (Dream Light palette) */
167
+ --chart-1: oklch(0.55 0.15 255);
168
+ --chart-2: oklch(0.62 0.12 175);
169
+ --chart-3: oklch(0.70 0.13 80);
170
+ --chart-4: oklch(0.55 0.14 295);
171
+ --chart-5: oklch(0.62 0.12 15);
172
+
173
+ /* Motion tokens */
174
+ --duration-fast: 100ms;
175
+ --duration-normal: 200ms;
176
+ --duration-slow: 300ms;
177
+ --ease-default: cubic-bezier(0.4, 0, 0.2, 1);
178
+ --ease-out: cubic-bezier(0, 0, 0.2, 1);
179
+ --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
124
180
  }
125
181
 
182
+ /* ===== SCOPED BASE RESET ===== */
183
+ /* Tailwind preflight is scoped to .mfe-root so it only resets MFE elements, not the host app */
126
184
  @layer base {
127
- * {
128
- @apply border-border outline-ring/50;
185
+ .mfe-root {
186
+ @apply copa:bg-background copa:text-foreground;
187
+ font-family: var(--font-sans, "Satoshi", sans-serif);
188
+ line-height: 1.5;
189
+ -webkit-font-smoothing: antialiased;
190
+ -moz-osx-font-smoothing: grayscale;
191
+ }
192
+
193
+ .mfe-root *,
194
+ .mfe-root *::before,
195
+ .mfe-root *::after {
196
+ box-sizing: border-box;
197
+ border-width: 0;
198
+ border-style: solid;
199
+ @apply copa:border-border copa:outline-ring/50;
200
+ }
201
+
202
+ .mfe-root button,
203
+ .mfe-root a,
204
+ .mfe-root [role="menuitem"],
205
+ .mfe-root [role="option"],
206
+ .mfe-root [data-slot="sidebar-menu-button"],
207
+ .mfe-root [data-slot="dropdown-menu-trigger"],
208
+ .mfe-root [data-slot="dropdown-menu-item"] {
209
+ cursor: pointer;
129
210
  }
130
- body {
131
- @apply bg-background text-foreground;
211
+
212
+ .mfe-root img,
213
+ .mfe-root svg,
214
+ .mfe-root video {
215
+ display: block;
216
+ max-width: 100%;
217
+ }
218
+
219
+ .mfe-root h1, .mfe-root h2, .mfe-root h3,
220
+ .mfe-root h4, .mfe-root h5, .mfe-root h6 {
221
+ font-size: inherit;
222
+ font-weight: inherit;
132
223
  }
224
+
225
+ .mfe-root ol,
226
+ .mfe-root ul,
227
+ .mfe-root menu {
228
+ list-style: none;
229
+ margin: 0;
230
+ padding: 0;
231
+ }
232
+
233
+ .mfe-root p,
234
+ .mfe-root h1, .mfe-root h2, .mfe-root h3,
235
+ .mfe-root h4, .mfe-root h5, .mfe-root h6,
236
+ .mfe-root blockquote,
237
+ .mfe-root dl, .mfe-root dd,
238
+ .mfe-root figure,
239
+ .mfe-root fieldset,
240
+ .mfe-root legend,
241
+ .mfe-root pre {
242
+ margin: 0;
243
+ }
244
+
245
+ .mfe-root hr {
246
+ height: 0;
247
+ color: inherit;
248
+ border-top-width: 1px;
249
+ }
250
+
251
+ .mfe-root a {
252
+ color: inherit;
253
+ text-decoration: inherit;
254
+ }
255
+
256
+ .mfe-root button,
257
+ .mfe-root input,
258
+ .mfe-root optgroup,
259
+ .mfe-root select,
260
+ .mfe-root textarea {
261
+ font-family: inherit;
262
+ font-feature-settings: inherit;
263
+ font-variation-settings: inherit;
264
+ font-size: 100%;
265
+ font-weight: inherit;
266
+ line-height: inherit;
267
+ color: inherit;
268
+ margin: 0;
269
+ padding: 0;
270
+ }
271
+
272
+ .mfe-root table {
273
+ border-collapse: collapse;
274
+ border-spacing: 0;
275
+ text-indent: 0;
276
+ border-color: inherit;
277
+ }
278
+ }
279
+
280
+ /* ===== SCOPED TYPOGRAPHY UTILITIES ===== */
281
+ .mfe-root .text-page-title {
282
+ font-size: 1.5rem;
283
+ line-height: 2rem;
284
+ font-weight: 600;
285
+ }
286
+ .mfe-root .text-section-title {
287
+ font-size: 0.9375rem;
288
+ line-height: 1.375rem;
289
+ font-weight: 600;
290
+ }
291
+ .mfe-root .text-label {
292
+ font-size: 0.75rem;
293
+ line-height: 1rem;
294
+ font-weight: 500;
295
+ text-transform: uppercase;
296
+ letter-spacing: 0.025em;
297
+ }
298
+ .mfe-root .text-value {
299
+ font-size: 1.75rem;
300
+ line-height: 2.25rem;
301
+ font-weight: 700;
302
+ }
303
+ .mfe-root .text-nav-section {
304
+ font-size: 0.6875rem;
305
+ line-height: 1rem;
306
+ font-weight: 600;
307
+ text-transform: uppercase;
308
+ letter-spacing: 0.05em;
309
+ }
310
+
311
+ /* ===== SCOPED SHADOW UTILITIES ===== */
312
+ .mfe-root .shadow-soft-xs { box-shadow: 0 1px 8px rgba(0, 0, 0, 0.03); }
313
+ .mfe-root .shadow-soft-sm { box-shadow: 0 2px 15px rgba(0, 0, 0, 0.04); }
314
+ .mfe-root .shadow-soft { box-shadow: 0 4px 25px rgba(0, 0, 0, 0.05); }
315
+ .mfe-root .shadow-soft-md { box-shadow: 0 6px 30px rgba(0, 0, 0, 0.06); }
316
+ .mfe-root .shadow-soft-lg { box-shadow: 0 8px 40px rgba(0, 0, 0, 0.07); }
317
+ .mfe-root .shadow-card {
318
+ box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 4px 8px rgba(0,0,0,0.02), 0 8px 16px rgba(0,0,0,0.01);
319
+ }
320
+ .mfe-root .shadow-card-hover {
321
+ box-shadow: 0 2px 4px rgba(0,0,0,0.06), 0 8px 16px rgba(0,0,0,0.04), 0 16px 32px rgba(0,0,0,0.02);
322
+ }
323
+
324
+ /* ===== ANIMATION KEYFRAMES (keyframes are global but unique names prevent collisions) ===== */
325
+ @keyframes copa-fade-in-up {
326
+ from { opacity: 0; transform: translateY(8px); }
327
+ to { opacity: 1; transform: translateY(0); }
328
+ }
329
+ @keyframes copa-fade-in-down {
330
+ from { opacity: 0; transform: translateY(-8px); }
331
+ to { opacity: 1; transform: translateY(0); }
332
+ }
333
+ @keyframes copa-scale-in {
334
+ from { opacity: 0; transform: scale(0.95); }
335
+ to { opacity: 1; transform: scale(1); }
336
+ }
337
+ @keyframes copa-shimmer {
338
+ 0% { background-position: -200% 0; }
339
+ 100% { background-position: 200% 0; }
133
340
  }
@@ -1,51 +1,60 @@
1
- import { Suspense, useEffect, useState } from 'react'
1
+ import "./app.css";
2
+ import { useState, useEffect } from "react";
2
3
  import { reactQuery, ReactQueryDevtools, copaSetConfig } from "@bluecopa/react";
3
- import { Toaster } from "sonner";
4
- import RouteConfig from './routes';
5
-
6
- import './app.css'
4
+ import { Toaster } from "~/components/ui/sonner";
5
+ import { AppProvider } from "~/contexts/app-context";
6
+ import { ChartProvider } from "~/components/charts";
7
+ import { LoadingScreen } from "~/components/loading-screen";
8
+ import RouteConfig from "./routes";
9
+ import type { MfeProps } from "~/types";
10
+ import { DEFAULT_API_BASE_URL, DEFAULT_WORKSPACE_ID, QUERY_DEFAULTS } from "~/constants";
11
+ import { initAgGridLicense } from "~/utils/ag-grid-license";
7
12
 
8
13
  const { QueryClient, QueryClientProvider } = reactQuery;
9
14
 
10
- export default function App(props: any) {
11
- const [queryClient] = useState(() => new QueryClient({
12
- defaultOptions: {
13
- queries: {
14
- staleTime: 60 * 1000, // 1 minute
15
- refetchOnWindowFocus: false,
16
- },
17
- },
18
- }));
15
+ export default function App(props: MfeProps) {
16
+ const [isConfigured, setIsConfigured] = useState(false);
17
+ const [queryClient] = useState(
18
+ () =>
19
+ new QueryClient({
20
+ defaultOptions: {
21
+ queries: { staleTime: QUERY_DEFAULTS.STALE_TIME, retry: QUERY_DEFAULTS.RETRY },
22
+ },
23
+ }),
24
+ );
19
25
 
20
26
  useEffect(() => {
21
- // Configure Bluecopa API
22
- let copaUser = {} as any;
23
- try {
24
- const copaToken = import.meta.env.VITE_BLUECOPA_API_TOKEN
25
- ? atob(import.meta.env.VITE_BLUECOPA_API_TOKEN)
26
- : '{}';
27
- copaUser = JSON.parse(copaToken);
28
- } catch (error) {
29
- console.warn('Failed to parse VITE_BLUECOPA_API_TOKEN:', error);
30
- }
31
-
32
- console.log("Copa User", import.meta.env.VITE_BLUECOPA_API_URL);
33
-
27
+ initAgGridLicense();
34
28
  copaSetConfig({
35
- apiBaseUrl: props.apiBaseUrl || import.meta.env.VITE_BLUECOPA_API_URL || 'https://develop.bluecopa.com',
36
- workspaceId: props.workspaceId || import.meta.env.VITE_BLUECOPA_WORKSPACE_ID || '',
37
- accessToken: props.accessToken || copaUser?.accessToken || import.meta.env.VITE_BLUECOPA_API_TOKEN || '',
38
- userId: props.userId || copaUser.userId || ''
39
- } as any);
40
- }, []);
29
+ apiBaseUrl:
30
+ props.apiBaseUrl ||
31
+ import.meta.env.VITE_BLUECOPA_API_URL ||
32
+ DEFAULT_API_BASE_URL,
33
+ accessToken: props.accessToken || "",
34
+ workspaceId:
35
+ props.workspaceId ||
36
+ import.meta.env.VITE_BLUECOPA_WORKSPACE_ID ||
37
+ DEFAULT_WORKSPACE_ID,
38
+ userId: props.userId || "",
39
+ });
40
+ setIsConfigured(true);
41
+ }, [props.apiBaseUrl, props.accessToken, props.workspaceId, props.userId]);
42
+
43
+ if (!isConfigured) {
44
+ return <LoadingScreen message="Initializing..." />;
45
+ }
41
46
 
42
47
  return (
43
48
  <QueryClientProvider client={queryClient}>
44
- <Suspense fallback={<div className="p-4 text-sm text-muted-foreground">Loading…</div>}>
45
- <RouteConfig />
46
- <ReactQueryDevtools initialIsOpen={false} />
47
- <Toaster />
48
- </Suspense>
49
+ <div className="mfe-root copa:min-h-svh copa:animate-in copa:fade-in copa:duration-300">
50
+ <ChartProvider>
51
+ <AppProvider>
52
+ <RouteConfig />
53
+ <Toaster />
54
+ </AppProvider>
55
+ </ChartProvider>
56
+ {import.meta.env.DEV && <ReactQueryDevtools initialIsOpen={false} />}
57
+ </div>
49
58
  </QueryClientProvider>
50
- )
59
+ );
51
60
  }
@@ -0,0 +1,20 @@
1
+ export function BluecopaLogo(props: React.SVGProps<SVGSVGElement>) {
2
+ return (
3
+ <svg
4
+ xmlns="http://www.w3.org/2000/svg"
5
+ viewBox="0 0 1820 1774.9"
6
+ {...props}
7
+ >
8
+ <circle fill="#fff" cx="1054.53" cy="779.52" r="386.21" />
9
+ <path
10
+ fill="#8ac2ff"
11
+ d="M5.91,1004.47L0,1768.96l764.5,5.91c422.08,3.27,767.15-336.52,770.42-758.58,3.26-422.06-336.51-767.14-758.59-770.41C350.68,242.59,9.18,582.4,5.91,1004.47Z"
12
+ />
13
+ <path
14
+ fill="#3548ff"
15
+ d="M1820,764.52V0h-764.52C633.38,0,290.95,342.44,290.95,764.52s342.43,764.52,764.52,764.52,764.52-342.44,764.52-764.52Z"
16
+ />
17
+ <circle fill="#fff" cx="1055.48" cy="780.55" r="382.26" />
18
+ </svg>
19
+ );
20
+ }