firebase-os 1.1.4 → 1.1.6

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 (124) hide show
  1. package/dist/FirebaseOS.d.ts +15 -0
  2. package/dist/firebase-os.cjs.js +5 -20
  3. package/dist/firebase-os.es.js +95 -90
  4. package/dist/index.d.ts +3 -0
  5. package/dist/lib/ConfigContext.d.ts +12 -0
  6. package/package.json +3 -2
  7. package/scripts/postinstall.js +86 -15
  8. package/src/App.css +184 -0
  9. package/src/App.tsx +214 -0
  10. package/src/FirebaseOS.tsx +81 -0
  11. package/src/assets/hero.png +0 -0
  12. package/src/assets/react.svg +1 -0
  13. package/src/assets/vite.svg +1 -0
  14. package/src/components/AdminNotifications.test.tsx +98 -0
  15. package/src/components/AdminNotifications.tsx +194 -0
  16. package/src/components/Button.test.tsx +22 -0
  17. package/src/components/Button.tsx +53 -0
  18. package/src/components/ConfirmModal.test.tsx +98 -0
  19. package/src/components/ConfirmModal.tsx +73 -0
  20. package/src/components/ContactPopup.test.tsx +98 -0
  21. package/src/components/ContactPopup.tsx +437 -0
  22. package/src/components/CustomSelect.test.tsx +47 -0
  23. package/src/components/CustomSelect.tsx +89 -0
  24. package/src/components/DashboardNav.test.tsx +98 -0
  25. package/src/components/DashboardNav.tsx +281 -0
  26. package/src/components/Input.test.tsx +33 -0
  27. package/src/components/Input.tsx +61 -0
  28. package/src/components/JsonEditor.tsx +579 -0
  29. package/src/components/Navbar.test.tsx +98 -0
  30. package/src/components/Navbar.tsx +563 -0
  31. package/src/configs/forms/contactForm.config.ts +15 -0
  32. package/src/configs/forms/index.ts +29 -0
  33. package/src/configs/forms/pubForm.config.ts +11 -0
  34. package/src/configs/forms/supportForm.config.ts +14 -0
  35. package/src/configs/forms/userForm.config.ts +11 -0
  36. package/src/configs/pages/admin.config.ts +29 -0
  37. package/src/configs/pages/contact.config.ts +6 -0
  38. package/src/configs/pages/home.config.ts +18 -0
  39. package/src/configs/pages/mem.config.ts +2 -0
  40. package/src/configs/pages/menuOrders.config.ts +11 -0
  41. package/src/configs/pages/pub.config.ts +11 -0
  42. package/src/configs/pages/shared.config.ts +29 -0
  43. package/src/configs/pages/support.config.ts +7 -0
  44. package/src/configs/pages/tabOrders.config.ts +33 -0
  45. package/src/configs/pages/user.config.ts +29 -0
  46. package/src/configs/theme.config.ts +93 -0
  47. package/src/index.css +403 -0
  48. package/src/index.ts +22 -0
  49. package/src/lib/AuthContext.test.tsx +88 -0
  50. package/src/lib/AuthContext.tsx +191 -0
  51. package/src/lib/ConfigContext.tsx +45 -0
  52. package/src/lib/ThemeContext.tsx +233 -0
  53. package/src/lib/firebase.ts +91 -0
  54. package/src/main.tsx +22 -0
  55. package/src/microcomponents/AdminExampleContent.tsx +44 -0
  56. package/src/microcomponents/PrivateExampleContent.tsx +39 -0
  57. package/src/microcomponents/Public.tsx +126 -0
  58. package/src/microcomponents/SharedExampleContent.tsx +53 -0
  59. package/src/pages/Dashboard.test.tsx +98 -0
  60. package/src/pages/Dashboard.tsx +60 -0
  61. package/src/pages/DynamicPage.tsx +237 -0
  62. package/src/pages/FormsAdmin.test.tsx +98 -0
  63. package/src/pages/FormsAdmin.tsx +459 -0
  64. package/src/pages/Home.test.tsx +98 -0
  65. package/src/pages/Home.tsx +144 -0
  66. package/src/pages/Login.test.tsx +98 -0
  67. package/src/pages/Login.tsx +108 -0
  68. package/src/pages/PagesAdmin.test.tsx +98 -0
  69. package/src/pages/PagesAdmin.tsx +1022 -0
  70. package/src/pages/Profile.test.tsx +98 -0
  71. package/src/pages/Profile.tsx +319 -0
  72. package/src/pages/Register.test.tsx +98 -0
  73. package/src/pages/Register.tsx +116 -0
  74. package/src/pages/Requests.test.tsx +95 -0
  75. package/src/pages/Requests.tsx +422 -0
  76. package/src/pages/ResetPassword.test.tsx +98 -0
  77. package/src/pages/ResetPassword.tsx +92 -0
  78. package/src/pages/Settings.test.tsx +98 -0
  79. package/src/pages/Settings.tsx +393 -0
  80. package/src/pages/Setup.tsx +407 -0
  81. package/src/pages/StorageAdmin.test.tsx +150 -0
  82. package/src/pages/StorageAdmin.tsx +769 -0
  83. package/src/pages/Submissions.test.tsx +95 -0
  84. package/src/pages/Submissions.tsx +378 -0
  85. package/src/pages/Templates.test.tsx +98 -0
  86. package/src/pages/Templates.tsx +103 -0
  87. package/src/pages/ThemeAdmin.test.tsx +144 -0
  88. package/src/pages/ThemeAdmin.tsx +1000 -0
  89. package/src/pages/Users.test.tsx +95 -0
  90. package/src/pages/Users.tsx +334 -0
  91. package/src/pages/Verify.test.tsx +98 -0
  92. package/src/pages/Verify.tsx +95 -0
  93. package/src/prompts/index.ts +13 -0
  94. package/src/prompts/pages/publicPage.ts +44 -0
  95. package/src/prompts/sharedConstants.ts +12 -0
  96. package/src/prompts/tabs/board/adminboard.ts +32 -0
  97. package/src/prompts/tabs/board/privateboard.ts +36 -0
  98. package/src/prompts/tabs/board/publicboard.ts +36 -0
  99. package/src/prompts/tabs/calendar/admincalendar.ts +32 -0
  100. package/src/prompts/tabs/calendar/privatecalendar.ts +36 -0
  101. package/src/prompts/tabs/calendar/publiccalendar.ts +36 -0
  102. package/src/prompts/tabs/crud/admin.ts +54 -0
  103. package/src/prompts/tabs/crud/private.ts +55 -0
  104. package/src/prompts/tabs/crud/shared.ts +53 -0
  105. package/src/prompts/tabs/table/admintable.ts +32 -0
  106. package/src/prompts/tabs/table/privatetable.ts +36 -0
  107. package/src/prompts/tabs/table/publictable.ts +36 -0
  108. package/src/setupTests.ts +1 -0
  109. package/src/templates/AdminPageTemplate.tsx +678 -0
  110. package/src/templates/PrivatePageTemplate.tsx +594 -0
  111. package/src/templates/PublicPageTemplate.tsx +92 -0
  112. package/src/templates/SharedPageTemplate.tsx +551 -0
  113. package/src/templates/TemplateBoard.test.tsx +106 -0
  114. package/src/templates/TemplateBoard.tsx +642 -0
  115. package/src/templates/TemplateCalendar.test.tsx +106 -0
  116. package/src/templates/TemplateCalendar.tsx +848 -0
  117. package/src/templates/TemplateConfirmation.test.tsx +106 -0
  118. package/src/templates/TemplateConfirmation.tsx +145 -0
  119. package/src/templates/TemplateInlineForm.test.tsx +106 -0
  120. package/src/templates/TemplateInlineForm.tsx +129 -0
  121. package/src/templates/TemplatePopupForm.test.tsx +106 -0
  122. package/src/templates/TemplatePopupForm.tsx +174 -0
  123. package/src/templates/TemplateTable.test.tsx +106 -0
  124. package/src/templates/TemplateTable.tsx +675 -0
package/src/main.tsx ADDED
@@ -0,0 +1,22 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.tsx'
5
+
6
+ import { ThemeProvider } from './lib/ThemeContext.tsx'
7
+ import { ConfigProvider } from './lib/ConfigContext.tsx'
8
+
9
+ // Keep body reset in standalone mode (FirebaseOS.tsx doesn't inject this)
10
+ document.body.style.margin = '0';
11
+
12
+ createRoot(document.getElementById('root')!).render(
13
+ <StrictMode>
14
+ <ConfigProvider config={{}}>
15
+ <ThemeProvider>
16
+ <div className="firebase-os">
17
+ <App />
18
+ </div>
19
+ </ThemeProvider>
20
+ </ConfigProvider>
21
+ </StrictMode>,
22
+ )
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import { Users, Server, ShieldAlert, Activity } from 'lucide-react';
4
+
5
+ export default function AdminExampleContent() {
6
+ return (
7
+ <div className="flex flex-col gap-6 p-4 md:p-8 w-full max-w-7xl mx-auto">
8
+ <div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
9
+ <div>
10
+ <h2 className="text-2xl font-bold tracking-tight text-foreground">System Overview</h2>
11
+ <p className="text-foreground/60 text-sm mt-1">Monitor your infrastructure and user metrics.</p>
12
+ </div>
13
+ <div className="flex bg-accent/10 text-accent px-4 py-2 rounded-xl text-sm font-bold border border-accent/20">
14
+ <Activity className="w-4 h-4 mr-2" />
15
+ System Healthy
16
+ </div>
17
+ </div>
18
+
19
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
20
+ <div className="glass-panel border border-[var(--panel-border)] p-6 rounded-3xl flex flex-col">
21
+ <div className="w-10 h-10 rounded-xl bg-blue-500/10 text-blue-500 flex items-center justify-center mb-4">
22
+ <Users className="w-5 h-5" />
23
+ </div>
24
+ <p className="text-foreground/60 text-sm font-medium">Total Users</p>
25
+ <p className="text-3xl font-bold text-foreground mt-1">1,204</p>
26
+ </div>
27
+ <div className="glass-panel border border-[var(--panel-border)] p-6 rounded-3xl flex flex-col">
28
+ <div className="w-10 h-10 rounded-xl bg-emerald-500/10 text-emerald-500 flex items-center justify-center mb-4">
29
+ <Server className="w-5 h-5" />
30
+ </div>
31
+ <p className="text-foreground/60 text-sm font-medium">Active Nodes</p>
32
+ <p className="text-3xl font-bold text-foreground mt-1">42</p>
33
+ </div>
34
+ <div className="glass-panel border border-[var(--panel-border)] p-6 rounded-3xl flex flex-col border-yellow-500/30">
35
+ <div className="w-10 h-10 rounded-xl bg-yellow-500/10 text-yellow-500 flex items-center justify-center mb-4">
36
+ <ShieldAlert className="w-5 h-5" />
37
+ </div>
38
+ <p className="text-foreground/60 text-sm font-medium">Security Alerts</p>
39
+ <p className="text-3xl font-bold text-yellow-500 mt-1">3 Needs Review</p>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ );
44
+ }
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import { FileText, Clock, Star } from 'lucide-react';
4
+ import { Button } from '../components/Button';
5
+
6
+ export default function PrivateExampleContent() {
7
+ return (
8
+ <div className="flex flex-col gap-6 p-4 md:p-8 w-full max-w-5xl mx-auto">
9
+ <div className="glass-panel border border-[var(--panel-border)] p-8 rounded-3xl flex flex-col md:flex-row items-center justify-between gap-6">
10
+ <div>
11
+ <h2 className="text-2xl font-bold tracking-tight text-foreground">Welcome back!</h2>
12
+ <p className="text-foreground/60 text-sm mt-2 max-w-md">Here is your personal workspace. You can manage your private documents and settings here.</p>
13
+ </div>
14
+ <Button className="shrink-0 px-6 tracking-wide">Create New</Button>
15
+ </div>
16
+
17
+ <h3 className="text-lg font-bold text-foreground mt-4 ml-2">Recent Items</h3>
18
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
19
+ {[1, 2].map((i) => (
20
+ <div key={i} className="glass-panel border border-[var(--panel-border)] p-4 rounded-2xl flex items-center gap-4 hover:border-accent/40 transition-colors cursor-pointer group">
21
+ <div className="w-12 h-12 rounded-xl bg-accent/10 flex items-center justify-center text-accent shrink-0 group-hover:scale-110 transition-transform">
22
+ <FileText className="w-6 h-6" />
23
+ </div>
24
+ <div className="flex-1 min-w-0">
25
+ <p className="font-bold text-foreground truncate">Private Document {i}</p>
26
+ <div className="flex items-center gap-2 mt-1 text-xs text-foreground/40 font-medium">
27
+ <Clock className="w-3 h-3" />
28
+ <span>Updated 2 days ago</span>
29
+ </div>
30
+ </div>
31
+ <button className="p-2 text-foreground/20 hover:text-yellow-400 transition-colors">
32
+ <Star className="w-5 h-5" />
33
+ </button>
34
+ </div>
35
+ ))}
36
+ </div>
37
+ </div>
38
+ );
39
+ }
@@ -0,0 +1,126 @@
1
+ import React from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import { ArrowRight, Layers, Zap, Shield, Code, Layout, Sparkles, CheckCircle2 } from 'lucide-react';
4
+ import { Button } from '../components/Button';
5
+
6
+ // This is an example of what gets injected inside the PublicPageTemplate.tsx content box.
7
+ // It relies on infinite height expansion native to the page container.
8
+ export default function PublicExample() {
9
+ return (
10
+ <div className="flex flex-col gap-10 p-4 md:p-8 w-full max-w-5xl mx-auto">
11
+
12
+ {/* Hero Section */}
13
+ <div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-6">
14
+ <div className="max-w-2xl">
15
+ <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-accent/10 border border-accent/20 text-accent text-[12px] font-bold tracking-wide mb-4">
16
+ <Sparkles className="w-3.5 h-3.5" />
17
+ <span>v2.0 Architecture</span>
18
+ </div>
19
+ <h2 className="text-3xl md:text-5xl font-extrabold tracking-tight text-foreground mb-4">
20
+ Custom Page Injection
21
+ </h2>
22
+ <p className="text-foreground/60 text-[15px] leading-relaxed max-w-xl font-medium">
23
+ Seamlessly build and deploy custom React components directly into the Firebase OS dashboard.
24
+ Enjoy native theming, routing, and deep authentication out of the box.
25
+ </p>
26
+ </div>
27
+ <div className="flex shrink-0 gap-3">
28
+ <Button variant="secondary" className="px-6 py-2.5 rounded-xl font-bold shadow-sm">View Docs</Button>
29
+ <Button className="px-6 py-2.5 rounded-xl shadow-lg shadow-accent/20 font-bold">Start Building</Button>
30
+ </div>
31
+ </div>
32
+
33
+ {/* Code Banner */}
34
+ <motion.div
35
+ initial={{ opacity: 0, y: 10 }}
36
+ animate={{ opacity: 1, y: 0 }}
37
+ className="glass-panel border border-[var(--panel-border)] rounded-3xl p-6 md:p-10 relative overflow-hidden bg-gradient-to-br from-background/50 to-foreground/[0.02]"
38
+ >
39
+ <div className="absolute top-0 right-0 p-8 opacity-[0.03] pointer-events-none transform translate-x-1/4 -translate-y-1/4">
40
+ <Code className="w-64 h-64" />
41
+ </div>
42
+ <div className="relative z-10 flex flex-col md:flex-row gap-10 items-center">
43
+ <div className="flex-1 space-y-4">
44
+ <h3 className="text-2xl font-bold text-foreground tracking-tight">Zero-Config Deployment</h3>
45
+ <p className="text-[14px] text-foreground/60 leading-relaxed max-w-md">
46
+ When you prompt the AI to generate a component for this page, it automatically wires up your component inside the <code className="bg-foreground/5 px-2 py-0.5 rounded-md text-accent font-mono text-[12px] border border-accent/10">src/components/pages/</code> directory and dynamically mounts it here.
47
+ </p>
48
+ <ul className="space-y-3 mt-6 pt-4 border-t border-[var(--panel-border)]/50">
49
+ {[
50
+ 'Full access to global CSS variables & tokens',
51
+ 'Native Light / Dark mode compatibility',
52
+ 'Responsive mobile-first structural integrity'
53
+ ].map((item, i) => (
54
+ <li key={i} className="flex items-center gap-3 text-[13px] text-foreground/80 font-medium">
55
+ <div className="w-5 h-5 rounded-full bg-emerald-500/10 flex items-center justify-center shrink-0">
56
+ <CheckCircle2 className="w-3.5 h-3.5 text-emerald-500" />
57
+ </div>
58
+ {item}
59
+ </li>
60
+ ))}
61
+ </ul>
62
+ </div>
63
+
64
+ <div className="w-full md:w-5/12 bg-background border border-[var(--panel-border)] rounded-2xl p-5 shadow-2xl relative group">
65
+ <div className="absolute inset-0 bg-gradient-to-tr from-accent/5 to-transparent rounded-2xl opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none" />
66
+ <div className="flex items-center gap-2 mb-4 pb-4 border-b border-[var(--panel-border)]">
67
+ <div className="w-3 h-3 rounded-full bg-red-400/80 shadow-[0_0_10px_rgba(248,113,113,0.5)]" />
68
+ <div className="w-3 h-3 rounded-full bg-yellow-400/80 shadow-[0_0_10px_rgba(250,204,21,0.5)]" />
69
+ <div className="w-3 h-3 rounded-full bg-green-400/80 shadow-[0_0_10px_rgba(74,222,128,0.5)]" />
70
+ <span className="ml-3 text-[10px] font-mono tracking-widest text-foreground/40 uppercase font-bold">page_content.tsx</span>
71
+ </div>
72
+ <pre className="font-mono text-[12px] text-foreground/70 leading-loose overflow-x-auto selection:bg-accent/20">
73
+ <span className="text-accent">export default function</span> <span className="text-blue-400 font-bold">CustomPage</span>() {'{\n'}
74
+ {' '}<span className="text-accent">return</span> (<br/>
75
+ {' '}&lt;<span className="text-emerald-500">div</span> <span className="text-purple-400">className</span>=<span className="text-orange-400">"glass-panel border-..."</span>&gt;<br/>
76
+ {' '}<span className="text-foreground/40 italic">{'// Your injected logic here'}</span><br/>
77
+ {' '}&lt;/<span className="text-emerald-500">div</span>&gt;<br/>
78
+ {' '});<br/>
79
+ {'}'}
80
+ </pre>
81
+ </div>
82
+ </div>
83
+ </motion.div>
84
+
85
+ {/* Features Grid */}
86
+ <div className="pt-4">
87
+ <h3 className="text-xl font-bold mb-6 px-1 tracking-tight">Core Capabilities</h3>
88
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-5">
89
+ {[
90
+ { icon: Layout, title: 'Glassmorphism', desc: 'Beautiful transparent blurred panels seamlessly mirroring system visuals globally.' },
91
+ { icon: Shield, title: 'Secure Context', desc: 'Components inherit active Firebase auth sessions and role states automatically.' },
92
+ { icon: Zap, title: 'Hot Loaded', desc: 'Every layout change updates instantly without disrupting the application state.' }
93
+ ].map((feature, idx) => (
94
+ <motion.div
95
+ key={idx}
96
+ whileHover={{ y: -5 }}
97
+ className="glass-panel border border-[var(--panel-border)] bg-background/40 p-6 rounded-3xl flex flex-col group hover:border-accent/40 transition-all cursor-default shadow-sm hover:shadow-xl hover:shadow-accent/5"
98
+ >
99
+ <div className="w-12 h-12 rounded-xl bg-accent/10 border border-accent/20 flex items-center justify-center text-accent mb-5 group-hover:scale-110 transition-transform duration-300 shadow-inner">
100
+ <feature.icon className="w-6 h-6" />
101
+ </div>
102
+ <h4 className="text-[16px] font-bold tracking-tight mb-2 text-foreground">{feature.title}</h4>
103
+ <p className="text-[13.5px] text-foreground/60 leading-relaxed flex-1">
104
+ {feature.desc}
105
+ </p>
106
+ </motion.div>
107
+ ))}
108
+ </div>
109
+ </div>
110
+
111
+ {/* Bottom CTA */}
112
+ <div className="mt-6 flex flex-col items-center text-center p-10 glass-panel border border-[var(--panel-border)] rounded-3xl bg-gradient-to-b from-transparent to-accent/[0.03] relative overflow-hidden">
113
+ <div className="w-full h-1 bg-gradient-to-r from-transparent via-accent/30 to-transparent absolute top-0 left-0" />
114
+ <Layers className="w-12 h-12 text-accent/40 mb-5" />
115
+ <h3 className="text-2xl font-bold mb-3 tracking-tight">Ready to inject your custom code?</h3>
116
+ <p className="text-[15px] text-foreground/60 max-w-lg mx-auto mb-8 leading-relaxed font-medium">
117
+ Click the <strong className="text-foreground">robot icon</strong> at the top of this template to copy the exact AI prompt needed to scaffold your next integration.
118
+ </p>
119
+ <button className="flex items-center gap-2 group text-[14px] font-bold text-accent hover:text-accent/80 transition-colors bg-accent/10 hover:bg-accent/15 px-6 py-2.5 rounded-xl border border-accent/20">
120
+ Show documentation <ArrowRight className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
121
+ </button>
122
+ </div>
123
+
124
+ </div>
125
+ );
126
+ }
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import { MessageSquare, ThumbsUp, User } from 'lucide-react';
4
+ import { Button } from '../components/Button';
5
+ import { Input } from '../components/Input';
6
+
7
+ export default function SharedExampleContent() {
8
+ return (
9
+ <div className="flex flex-col gap-6 p-4 md:p-8 w-full max-w-4xl mx-auto">
10
+ <div className="glass-panel border border-[var(--panel-border)] p-6 rounded-3xl">
11
+ <h2 className="text-xl font-bold tracking-tight text-foreground mb-4">Community Discussion</h2>
12
+ <div className="flex gap-4">
13
+ <div className="w-10 h-10 rounded-full bg-accent/20 flex items-center justify-center text-accent shrink-0 border border-accent/30">
14
+ <User className="w-5 h-5" />
15
+ </div>
16
+ <div className="flex-1 flex flex-col gap-3">
17
+ <Input placeholder="Share something with the team..." className="w-full" />
18
+ <div className="flex justify-end">
19
+ <Button className="px-6 rounded-xl">Post</Button>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </div>
24
+
25
+ <div className="flex flex-col gap-4 mt-2">
26
+ {[1, 2].map((i) => (
27
+ <div key={i} className="glass-panel border border-[var(--panel-border)] p-5 rounded-2xl flex gap-4">
28
+ <div className="w-10 h-10 rounded-full bg-foreground/10 flex items-center justify-center text-foreground/60 shrink-0">
29
+ <User className="w-5 h-5" />
30
+ </div>
31
+ <div className="flex-1">
32
+ <div className="flex items-center gap-2 mb-1">
33
+ <span className="font-bold text-[14px]">Team Member {i}</span>
34
+ <span className="text-[12px] text-foreground/40 font-medium">2 hours ago</span>
35
+ </div>
36
+ <p className="text-foreground/80 text-[14px] leading-relaxed">
37
+ This is an example of a shared component where all authenticated members can see and interact with the data.
38
+ </p>
39
+ <div className="flex items-center gap-4 mt-4 text-foreground/50">
40
+ <button className="flex items-center gap-1.5 text-[12px] font-bold hover:text-accent transition-colors">
41
+ <ThumbsUp className="w-4 h-4" /> Like
42
+ </button>
43
+ <button className="flex items-center gap-1.5 text-[12px] font-bold hover:text-accent transition-colors">
44
+ <MessageSquare className="w-4 h-4" /> Reply
45
+ </button>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ ))}
50
+ </div>
51
+ </div>
52
+ );
53
+ }
@@ -0,0 +1,98 @@
1
+ // @generated-test
2
+ import { describe, it, expect, vi } from 'vitest';
3
+ import { render, screen, act } from '@testing-library/react';
4
+ import { BrowserRouter } from 'react-router-dom';
5
+ import { AuthProvider } from '../lib/AuthContext';
6
+ import { ThemeProvider } from '../lib/ThemeContext';
7
+ import { Dashboard } from './Dashboard';
8
+
9
+ // Global mocks
10
+ Object.defineProperty(window, 'matchMedia', {
11
+ writable: true,
12
+ value: vi.fn().mockImplementation(query => ({
13
+ matches: false,
14
+ media: query,
15
+ onchange: null,
16
+ addListener: vi.fn(),
17
+ removeListener: vi.fn(),
18
+ addEventListener: vi.fn(),
19
+ removeEventListener: vi.fn(),
20
+ dispatchEvent: vi.fn(),
21
+ })),
22
+ });
23
+
24
+ vi.mock('../lib/AuthContext', () => ({
25
+ AuthProvider: ({ children }: any) => <>{children}</>,
26
+ useAuth: () => ({
27
+ user: { uid: 'mock-user-123', email: 'test@example.com' },
28
+ userWorkspaces: [],
29
+ activeWorkspace: null,
30
+ activeOrg: null,
31
+ loading: false
32
+ })
33
+ }));
34
+
35
+ vi.mock('../lib/ThemeContext', () => ({
36
+ ThemeProvider: ({ children }: any) => <>{children}</>,
37
+ useTheme: () => ({ themeMode: 'light', setThemeMode: vi.fn(), activeConfig: {} })
38
+ }));
39
+
40
+ vi.mock('firebase/auth', () => ({
41
+ getAuth: vi.fn(() => ({})),
42
+ onAuthStateChanged: vi.fn((auth, cb) => { cb({ uid: 'mock-user-123', email: 'test@example.com', getIdToken: vi.fn(() => Promise.resolve('mock-token')) }); return () => {}; })
43
+ }));
44
+ vi.mock('firebase/firestore', () => ({
45
+ getFirestore: vi.fn(() => ({})),
46
+ collection: vi.fn(),
47
+ doc: vi.fn(),
48
+ setDoc: vi.fn(() => Promise.resolve()),
49
+ addDoc: vi.fn(() => Promise.resolve()),
50
+ updateDoc: vi.fn(() => Promise.resolve()),
51
+ deleteDoc: vi.fn(() => Promise.resolve()),
52
+ query: vi.fn(),
53
+ where: vi.fn(),
54
+ orderBy: vi.fn(),
55
+ limit: vi.fn(),
56
+ getDoc: vi.fn(() => Promise.resolve({ exists: () => true, data: () => ({ role: 'super_admin' }) })),
57
+ getDocs: vi.fn(() => Promise.resolve({ docs: [], forEach: vi.fn() })),
58
+ onSnapshot: vi.fn((...args: any[]) => {
59
+ let cb = args[1];
60
+ if (typeof args[2] === 'function') {
61
+ cb = args[2];
62
+ }
63
+ if (typeof cb === 'function') {
64
+ cb({docs: [], forEach: vi.fn(), data: () => ({}), exists: () => true});
65
+ }
66
+ return () => {};
67
+ })
68
+ }));
69
+ vi.mock('firebase/storage', () => ({
70
+ getStorage: vi.fn(() => ({})),
71
+ ref: vi.fn(),
72
+ listAll: vi.fn(() => Promise.resolve({ items: [], prefixes: [] })),
73
+ getDownloadURL: vi.fn(() => Promise.resolve('mock-url')),
74
+ getMetadata: vi.fn(() => Promise.resolve({ size: 1024, timeCreated: new Date().toISOString() }))
75
+ }));
76
+
77
+ describe('Dashboard Component', () => {
78
+ it('renders without crashing', async () => {
79
+ // Wrap in standard application providers inside act to process async side effects and prevent warnings
80
+ await act(async () => {
81
+ render(
82
+ <BrowserRouter>
83
+ <AuthProvider>
84
+ <ThemeProvider>
85
+ {/* @ts-ignore */}
86
+ <Dashboard />
87
+ </ThemeProvider>
88
+ </AuthProvider>
89
+ </BrowserRouter>
90
+ );
91
+ // Wait a tick to flush background state updates
92
+ await new Promise(resolve => setTimeout(resolve, 0));
93
+ });
94
+
95
+ // Check if the document has anything rendered without throwing
96
+ expect(document.body).toBeDefined();
97
+ });
98
+ });
@@ -0,0 +1,60 @@
1
+ import { motion, AnimatePresence } from 'framer-motion';
2
+ import { useAuth } from '../lib/AuthContext';
3
+ import { Database, Zap } from 'lucide-react';
4
+ import { DashboardNav } from '../components/DashboardNav';
5
+
6
+ export function Dashboard() {
7
+ const { user } = useAuth();
8
+
9
+ const rawName = user?.displayName || user?.email?.split('@')[0] || 'there';
10
+ const firstName = rawName.split(' ')[0];
11
+ const capitalizedName = firstName.charAt(0).toUpperCase() + firstName.slice(1);
12
+
13
+ return (
14
+ <main className="flex-1 w-full max-w-7xl mx-auto p-4 md:p-8 z-10 flex flex-col">
15
+
16
+ {/* Header */}
17
+ <motion.div
18
+ initial={{ opacity: 0, y: 20 }}
19
+ animate={{ opacity: 1, y: 0 }}
20
+ className="mb-8"
21
+ >
22
+ <h1 className="w-fit inline-block text-3xl md:text-4xl lg:text-5xl font-extrabold tracking-tight mb-3 text-gradient mt-1">
23
+ Welcome back, {capitalizedName}.
24
+ </h1>
25
+ <div className="flex items-center gap-2 text-foreground/40 font-bold uppercase tracking-[0.2em] text-[11px]">
26
+ <span className="w-8 h-[1px] bg-foreground/10" />
27
+ /dashboard
28
+ </div>
29
+ </motion.div>
30
+
31
+ {/* Main Content Area */}
32
+ <div className="flex flex-col gap-4 flex-1 min-h-[500px]">
33
+ <div className="flex justify-start">
34
+ <DashboardNav />
35
+ </div>
36
+ {/* Content Box */}
37
+ <div className="w-full flex-1 glass-panel rounded-3xl p-8 md:p-12 flex items-center justify-center relative overflow-hidden border border-[var(--panel-border)] shadow-2xl bg-[var(--panel-bg)]">
38
+ {/* Subtle background glow */}
39
+ <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-64 h-64 bg-accent/10 blur-[100px] rounded-full pointer-events-none" />
40
+
41
+ <AnimatePresence mode="wait">
42
+ <motion.div
43
+ initial={{ opacity: 0, scale: 0.95 }}
44
+ animate={{ opacity: 1, scale: 1 }}
45
+ exit={{ opacity: 0, scale: 0.95 }}
46
+ transition={{ duration: 0.3 }}
47
+ className="text-center z-10"
48
+ >
49
+ <div className="w-16 h-16 rounded-3xl bg-accent/10 border border-accent/20 flex items-center justify-center text-accent mx-auto mb-6 shadow-inner">
50
+ <Database className="w-6 h-6" />
51
+ </div>
52
+ <h2 className="text-2xl font-extrabold text-foreground mb-2">No data added here yet</h2>
53
+ <p className="text-foreground/40 font-medium">Keep moving forward, your data will appear here.</p>
54
+ </motion.div>
55
+ </AnimatePresence>
56
+ </div>
57
+ </div>
58
+ </main>
59
+ );
60
+ }