@ramme-io/create-app 1.2.0 → 1.2.2
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.
- package/package.json +1 -2
- package/template/package.json +41 -0
- package/template/pkg.json +1 -1
- package/template/src/App.tsx +65 -35
- package/template/src/components/AIChatWidget.tsx +2 -2
- package/template/src/components/AppHeader.tsx +2 -2
- package/template/src/components/AutoForm.tsx +13 -0
- package/template/src/{pages/styleguide → components}/NotFound.tsx +1 -1
- package/template/src/components/PageTitleUpdater.tsx +2 -2
- package/template/src/components/ProtectedRoute.tsx +18 -1
- package/template/src/components/ScrollToTop.tsx +19 -0
- package/template/src/config/app.manifest.ts +3 -1
- package/template/src/{core → config}/component-registry.tsx +1 -1
- package/template/src/config/navigation.ts +1 -1
- package/template/src/data/mock-charts.ts +32 -28
- package/template/src/{components → engine/renderers}/DynamicBlock.tsx +27 -7
- package/template/src/{pages → engine/renderers}/DynamicPage.tsx +23 -4
- package/template/src/{contexts → engine/runtime}/MqttContext.tsx +25 -11
- package/template/src/{contexts → engine/runtime}/SitemapContext.tsx +1 -1
- package/template/src/{core → engine/runtime}/data-seeder.ts +15 -5
- package/template/src/{hooks → engine/runtime}/useAction.ts +19 -8
- package/template/src/{hooks → engine/runtime}/useCrudLocalStorage.ts +27 -8
- package/template/src/{hooks → engine/runtime}/useDataQuery.ts +15 -1
- package/template/src/engine/runtime/useSignal.ts +51 -0
- package/template/src/engine/runtime/useSignalStore.ts +94 -0
- package/template/src/engine/runtime/useWorkflowEngine.ts +144 -0
- package/template/src/{core → engine/types}/manifest-types.ts +35 -3
- package/template/src/{types → engine/validation}/schema.ts +53 -2
- package/template/src/{pages → features/ai/pages}/AiChat.tsx +1 -1
- package/template/src/features/auth/AuthContext.tsx +118 -0
- package/template/src/features/auth/pages/AuthLayout.tsx +55 -0
- package/template/src/features/auth/pages/LoginPage.tsx +106 -0
- package/template/src/features/auth/pages/SignupPage.tsx +96 -0
- package/template/src/features/datagrid/SmartTable.tsx +222 -0
- package/template/src/features/onboarding/pages/Welcome.tsx +161 -0
- package/template/src/features/overview/index.ts +1 -0
- package/template/src/features/overview/pages/OverviewPage.tsx +127 -0
- package/template/src/{pages → features/playground/pages}/AccountingLedgerPage.tsx +1 -1
- package/template/src/{pages/prototypes → features/playground/pages}/ItemSelectorPage.tsx +1 -1
- package/template/src/{pages/settings → features/settings/pages}/BillingPage.tsx +1 -1
- package/template/src/features/settings/pages/ProfilePage.tsx +153 -0
- package/template/src/{pages/settings → features/settings/pages}/TeamPage.tsx +1 -1
- package/template/src/features/styleguide/Styleguide.tsx +75 -0
- package/template/src/features/users/components/UserDrawer.tsx +138 -0
- package/template/src/features/users/index.ts +2 -0
- package/template/src/features/users/pages/UsersPage.tsx +151 -0
- package/template/src/index.css +1 -1
- package/template/src/main.tsx +3 -3
- package/template/src/templates/dashboard/DashboardLayout.tsx +75 -106
- package/template/src/templates/dashboard/dashboard.sitemap.ts +34 -19
- package/template/src/templates/docs/DocsLayout.tsx +49 -38
- package/template/src/templates/docs/docs.sitemap.ts +22 -34
- package/template/src/templates/settings/SettingsLayout.tsx +83 -143
- package/template/src/templates/settings/settings.sitemap.ts +6 -6
- package/template/vite.config.ts +12 -9
- package/template/src/adaptors/.gitkeep +0 -0
- package/template/src/blocks/SmartTable.tsx +0 -191
- package/template/src/components/LocalSideNav.tsx +0 -120
- package/template/src/components/PageWithSideNav.tsx +0 -69
- package/template/src/config/dashboard.layout.ts +0 -110
- package/template/src/contexts/AuthContext.tsx +0 -64
- package/template/src/data/mockUsers.ts +0 -18
- package/template/src/generated/hooks.ts +0 -40
- package/template/src/hooks/useSignal.ts +0 -83
- package/template/src/hooks/useWorkflowEngine.ts +0 -6
- package/template/src/layouts/DataLayout.tsx +0 -37
- package/template/src/layouts/SideNavLayout.tsx +0 -28
- package/template/src/pages/Dashboard.tsx +0 -60
- package/template/src/pages/DataGridPage.tsx +0 -184
- package/template/src/pages/LoginPage.tsx +0 -58
- package/template/src/pages/settings/ProfilePage.tsx +0 -10
- package/template/src/pages/styleguide/Styleguide.tsx +0 -40
- package/template/src/templates/docs/pages/Introduction.tsx +0 -13
- package/template/src/types/signal.ts +0 -23
- /package/template/src/{core → engine/renderers}/route-generator.tsx +0 -0
- /package/template/src/{core → engine/types}/sitemap-entry.ts +0 -0
- /package/template/src/{pages → features}/GenericContentPage.tsx +0 -0
- /package/template/src/{hooks → features/assistant}/useMockChat.ts +0 -0
- /package/template/src/{components/dev → features/developer}/GhostOverlay.tsx +0 -0
- /package/template/src/{hooks → features/developer}/useDevTools.ts +0 -0
- /package/template/src/{pages → features}/styleguide/sections/charts/ChartsSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/colors/ColorsSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/elements/ElementsSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/feedback/FeedbackSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/forms/FormsSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/icons/IconsSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/layout/LayoutSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/navigation/NavigationSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/tables/TablesSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/templates/TemplatesSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/theming/ThemingSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/utilities/UtilitiesSection.tsx +0 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
3
|
+
import {
|
|
4
|
+
Card,
|
|
5
|
+
Button,
|
|
6
|
+
Icon,
|
|
7
|
+
Badge,
|
|
8
|
+
SectionHeader
|
|
9
|
+
} from '@ramme-io/ui';
|
|
10
|
+
|
|
11
|
+
const Welcome: React.FC = () => {
|
|
12
|
+
const navigate = useNavigate();
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700">
|
|
16
|
+
|
|
17
|
+
{/* HERO */}
|
|
18
|
+
<div className="relative overflow-hidden rounded-xl bg-gradient-to-r from-primary to-violet-600 text-primary-foreground p-8 md:p-12">
|
|
19
|
+
<div className="relative z-10 max-w-2xl">
|
|
20
|
+
<Badge variant="secondary" className="mb-4 bg-white/20 text-white border-none backdrop-blur-sm">
|
|
21
|
+
v1.2.0 Starter Kit
|
|
22
|
+
</Badge>
|
|
23
|
+
<h1 className="text-4xl md:text-5xl font-extrabold mb-4 tracking-tight">
|
|
24
|
+
Your Ramme App is Ready.
|
|
25
|
+
</h1>
|
|
26
|
+
<p className="text-lg md:text-xl text-primary-foreground/90 mb-8 leading-relaxed">
|
|
27
|
+
You have successfully scaffolded a production-ready prototype environment.
|
|
28
|
+
This kit comes pre-wired with Authentication, Mock Data, and the A.D.A.P.T. architecture.
|
|
29
|
+
</p>
|
|
30
|
+
<div className="flex flex-wrap gap-4">
|
|
31
|
+
<Button
|
|
32
|
+
size="lg"
|
|
33
|
+
variant="secondary"
|
|
34
|
+
className="font-semibold"
|
|
35
|
+
iconLeft="layout-dashboard"
|
|
36
|
+
onClick={() => navigate('/dashboard/app')}
|
|
37
|
+
>
|
|
38
|
+
Open Live Dashboard
|
|
39
|
+
</Button>
|
|
40
|
+
<Button
|
|
41
|
+
size="lg"
|
|
42
|
+
variant="outline"
|
|
43
|
+
className="bg-transparent border-white/30 text-white hover:bg-white/10 hover:text-white"
|
|
44
|
+
iconLeft="book-open"
|
|
45
|
+
onClick={() => navigate('/docs')}
|
|
46
|
+
>
|
|
47
|
+
Read Documentation
|
|
48
|
+
</Button>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
{/* Decorative Background Icon */}
|
|
53
|
+
<div className="absolute -right-10 -bottom-10 opacity-10 rotate-12">
|
|
54
|
+
<Icon name="box" size={300} />
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
59
|
+
|
|
60
|
+
{/* SECTION 1: ARCHITECTURE */}
|
|
61
|
+
<div className="space-y-4">
|
|
62
|
+
<SectionHeader title="Project Architecture" />
|
|
63
|
+
<div className="grid gap-4">
|
|
64
|
+
<Card className="p-4 flex gap-4 hover:border-primary/50 transition-colors cursor-default">
|
|
65
|
+
<div className="p-3 rounded-lg bg-blue-100 text-blue-600 dark:bg-blue-900/30 dark:text-blue-400 h-fit">
|
|
66
|
+
<Icon name="database" size={24} />
|
|
67
|
+
</div>
|
|
68
|
+
<div>
|
|
69
|
+
<h3 className="font-semibold text-foreground">Data Lake</h3>
|
|
70
|
+
<p className="text-sm text-muted-foreground mt-1">
|
|
71
|
+
Mock data is seeded into <code>localStorage</code> on boot.
|
|
72
|
+
Edit <code>src/data/mockData.ts</code> to change the schema.
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
</Card>
|
|
76
|
+
|
|
77
|
+
<Card className="p-4 flex gap-4 hover:border-primary/50 transition-colors cursor-default">
|
|
78
|
+
<div className="p-3 rounded-lg bg-purple-100 text-purple-600 dark:bg-purple-900/30 dark:text-purple-400 h-fit">
|
|
79
|
+
<Icon name="git-branch" size={24} />
|
|
80
|
+
</div>
|
|
81
|
+
<div>
|
|
82
|
+
<h3 className="font-semibold text-foreground">Logic Engine</h3>
|
|
83
|
+
<p className="text-sm text-muted-foreground mt-1">
|
|
84
|
+
Workflows and signals are processed in real-time by
|
|
85
|
+
<code>useWorkflowEngine.ts</code>. Supports MQTT and simulated sensors.
|
|
86
|
+
</p>
|
|
87
|
+
</div>
|
|
88
|
+
</Card>
|
|
89
|
+
|
|
90
|
+
<Card className="p-4 flex gap-4 hover:border-primary/50 transition-colors cursor-default">
|
|
91
|
+
<div className="p-3 rounded-lg bg-orange-100 text-orange-600 dark:bg-orange-900/30 dark:text-orange-400 h-fit">
|
|
92
|
+
<Icon name="layout" size={24} />
|
|
93
|
+
</div>
|
|
94
|
+
<div>
|
|
95
|
+
<h3 className="font-semibold text-foreground">Dynamic Routing</h3>
|
|
96
|
+
<p className="text-sm text-muted-foreground mt-1">
|
|
97
|
+
Pages are generated from <code>app.manifest.ts</code>.
|
|
98
|
+
Visual blocks connect automatically to data sources.
|
|
99
|
+
</p>
|
|
100
|
+
</div>
|
|
101
|
+
</Card>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
{/* SECTION 2: RESOURCES */}
|
|
106
|
+
<div className="space-y-4">
|
|
107
|
+
<SectionHeader title="Developer Resources" />
|
|
108
|
+
|
|
109
|
+
<Card className="p-6 space-y-6">
|
|
110
|
+
<div>
|
|
111
|
+
<h4 className="font-semibold flex items-center gap-2 mb-2">
|
|
112
|
+
<Icon name="palette" size={16} className="text-muted-foreground" />
|
|
113
|
+
Component Library
|
|
114
|
+
</h4>
|
|
115
|
+
<p className="text-sm text-muted-foreground mb-3">
|
|
116
|
+
Browse the full suite of accessible UI components available in this project.
|
|
117
|
+
</p>
|
|
118
|
+
<Button variant="outline" size="sm" onClick={() => navigate('/styleguide')}>
|
|
119
|
+
View Style Guide
|
|
120
|
+
</Button>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div className="border-t border-border pt-6">
|
|
124
|
+
<h4 className="font-semibold flex items-center gap-2 mb-2">
|
|
125
|
+
<Icon name="settings" size={16} className="text-muted-foreground" />
|
|
126
|
+
Configuration
|
|
127
|
+
</h4>
|
|
128
|
+
<p className="text-sm text-muted-foreground mb-3">
|
|
129
|
+
Manage global settings, user profile templates, and billing layouts.
|
|
130
|
+
</p>
|
|
131
|
+
<Button variant="outline" size="sm" onClick={() => navigate('/settings')}>
|
|
132
|
+
Open Settings
|
|
133
|
+
</Button>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<div className="border-t border-border pt-6">
|
|
137
|
+
<h4 className="font-semibold flex items-center gap-2 mb-2">
|
|
138
|
+
<Icon name="github" size={16} className="text-muted-foreground" />
|
|
139
|
+
Community
|
|
140
|
+
</h4>
|
|
141
|
+
<p className="text-sm text-muted-foreground mb-3">
|
|
142
|
+
Need help? Check the docs or open an issue on GitHub.
|
|
143
|
+
</p>
|
|
144
|
+
<a
|
|
145
|
+
href="https://github.com/ramme-io/create-app"
|
|
146
|
+
target="_blank"
|
|
147
|
+
rel="noreferrer"
|
|
148
|
+
className="inline-flex"
|
|
149
|
+
>
|
|
150
|
+
<Button variant="ghost" size="sm">GitHub Repo →</Button>
|
|
151
|
+
</a>
|
|
152
|
+
</div>
|
|
153
|
+
</Card>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export default Welcome;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { OverviewPage } from './pages/OverviewPage';
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
3
|
+
import {
|
|
4
|
+
PageHeader,
|
|
5
|
+
Card,
|
|
6
|
+
BarChart,
|
|
7
|
+
Button,
|
|
8
|
+
Icon,
|
|
9
|
+
Badge
|
|
10
|
+
} from '@ramme-io/ui';
|
|
11
|
+
|
|
12
|
+
// 1. REMOVE: The Zombie Service Import
|
|
13
|
+
// import { userService } from '../../users';
|
|
14
|
+
|
|
15
|
+
// 2. ADD: The Engine Hook & Shared Data
|
|
16
|
+
// (Adjust path '../../engine/...' if needed based on your folder structure)
|
|
17
|
+
import { useCrudLocalStorage } from '../../../engine/runtime/useCrudLocalStorage';
|
|
18
|
+
import { SEED_USERS, type User } from '../../../data/mockData';
|
|
19
|
+
|
|
20
|
+
// Mock Data for Chart
|
|
21
|
+
const revenueData = [
|
|
22
|
+
{ name: 'Mon', revenue: 4000, cost: 2400 },
|
|
23
|
+
{ name: 'Tue', revenue: 3000, cost: 1398 },
|
|
24
|
+
{ name: 'Wed', revenue: 2000, cost: 9800 },
|
|
25
|
+
{ name: 'Thu', revenue: 2780, cost: 3908 },
|
|
26
|
+
{ name: 'Fri', revenue: 1890, cost: 4800 },
|
|
27
|
+
{ name: 'Sat', revenue: 2390, cost: 3800 },
|
|
28
|
+
{ name: 'Sun', revenue: 3490, cost: 4300 },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
// Recreating the StatCard locally (since the old one was custom)
|
|
32
|
+
const StatCard = ({ title, value, trend, icon, onClick, className }: any) => (
|
|
33
|
+
<Card
|
|
34
|
+
className={`p-6 flex items-center justify-between space-x-4 transition-all hover:border-primary/50 ${className || ''}`}
|
|
35
|
+
onClick={onClick}
|
|
36
|
+
>
|
|
37
|
+
<div>
|
|
38
|
+
<p className="text-sm font-medium text-muted-foreground">{title}</p>
|
|
39
|
+
<h3 className="text-2xl font-bold mt-1">{value}</h3>
|
|
40
|
+
<div className={`flex items-center text-xs mt-1 ${trend > 0 ? 'text-green-500' : 'text-red-500'}`}>
|
|
41
|
+
<Icon name={trend > 0 ? 'trending-up' : 'trending-down'} className="h-3 w-3 mr-1" />
|
|
42
|
+
{Math.abs(trend)}% from last month
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
<div className="p-3 bg-muted/50 rounded-full">
|
|
46
|
+
<Icon name={icon} className="h-5 w-5 text-primary" />
|
|
47
|
+
</div>
|
|
48
|
+
</Card>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export const OverviewPage: React.FC = () => {
|
|
52
|
+
const navigate = useNavigate();
|
|
53
|
+
|
|
54
|
+
// 3. REPLACE: Manual fetching with the Reactive Engine
|
|
55
|
+
// This automatically connects to 'ramme_db_users' and keeps the count live
|
|
56
|
+
const { data: users } = useCrudLocalStorage<User>('ramme_db_users', SEED_USERS);
|
|
57
|
+
|
|
58
|
+
// Calculate count directly from the hook data
|
|
59
|
+
const userCount = users.length;
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className="space-y-8 pb-10">
|
|
63
|
+
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
|
64
|
+
<div>
|
|
65
|
+
<PageHeader
|
|
66
|
+
title="Dashboard"
|
|
67
|
+
description="Overview of your application performance."
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
<div className="flex gap-2">
|
|
71
|
+
<Button variant="outline" iconLeft="download">Export</Button>
|
|
72
|
+
<Button iconLeft="plus">New Report</Button>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
77
|
+
<StatCard
|
|
78
|
+
title="Total Users"
|
|
79
|
+
value={userCount} // ✅ Uses live data from Data Lake
|
|
80
|
+
trend={+12.5}
|
|
81
|
+
icon="users"
|
|
82
|
+
className="cursor-pointer bg-primary/5 border-primary/20"
|
|
83
|
+
onClick={() => navigate('/dashboard/users')}
|
|
84
|
+
/>
|
|
85
|
+
<StatCard title="Total Revenue" value="$45,231" trend={+20.1} icon="dollar-sign" />
|
|
86
|
+
<StatCard title="Sales" value="+12,234" trend={+19} icon="credit-card" />
|
|
87
|
+
<StatCard title="Active Now" value="+573" trend={-4} icon="activity" />
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
{/* Main Content Grid */}
|
|
91
|
+
<div className="grid grid-cols-1 lg:grid-cols-7 gap-8">
|
|
92
|
+
<Card className="lg:col-span-4 p-6">
|
|
93
|
+
<div className="flex items-center justify-between mb-6">
|
|
94
|
+
<h3 className="font-semibold text-lg">Revenue Overview</h3>
|
|
95
|
+
<Badge variant="outline">Weekly</Badge>
|
|
96
|
+
</div>
|
|
97
|
+
<div className="h-[350px] w-full">
|
|
98
|
+
<BarChart
|
|
99
|
+
data={revenueData}
|
|
100
|
+
dataKeyX="name"
|
|
101
|
+
barKeys={['revenue', 'cost']}
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
</Card>
|
|
105
|
+
|
|
106
|
+
<Card className="lg:col-span-3 p-6 flex flex-col">
|
|
107
|
+
<h3 className="font-semibold text-lg mb-4">Recent Activity</h3>
|
|
108
|
+
<div className="space-y-6 overflow-y-auto pr-2">
|
|
109
|
+
{[1, 2, 3].map((i) => (
|
|
110
|
+
<div key={i} className="flex items-start gap-4">
|
|
111
|
+
<span className="relative flex h-2 w-2 mt-2">
|
|
112
|
+
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
|
|
113
|
+
<span className="relative inline-flex rounded-full h-2 w-2 bg-primary"></span>
|
|
114
|
+
</span>
|
|
115
|
+
<div className="space-y-1">
|
|
116
|
+
<p className="text-sm font-medium leading-none">System Alert</p>
|
|
117
|
+
<p className="text-xs text-muted-foreground">Database backup completed.</p>
|
|
118
|
+
<p className="text-xs text-muted-foreground pt-1">Just now</p>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
))}
|
|
122
|
+
</div>
|
|
123
|
+
</Card>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
// 1. Import the specific event type for cell value changes
|
|
9
9
|
type CellValueChangedEvent,
|
|
10
10
|
} from '@ramme-io/ui';
|
|
11
|
-
import { mockLedgerData, type LedgerEntry } from '
|
|
11
|
+
import { mockLedgerData, type LedgerEntry } from '../../../data/mockLedger';
|
|
12
12
|
|
|
13
13
|
// --- Custom Renderer for Variance ---
|
|
14
14
|
// 2. Correctly type the component and ensure it returns a ReactNode (JSX or null)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
// --- 1. Import the new generic page ---
|
|
3
|
-
import GenericContentPage from '
|
|
3
|
+
import GenericContentPage from '../../GenericContentPage';
|
|
4
4
|
|
|
5
5
|
// A simple page component for settings
|
|
6
6
|
const BillingPage: React.FC = () => {
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
Input,
|
|
5
|
+
Card,
|
|
6
|
+
SectionHeader,
|
|
7
|
+
Icon,
|
|
8
|
+
Alert
|
|
9
|
+
} from '@ramme-io/ui';
|
|
10
|
+
import { useAuth } from '../../auth/AuthContext';
|
|
11
|
+
|
|
12
|
+
// 1. REMOVE Zombie Service
|
|
13
|
+
// import { userService } from '../../users/api/user.service';
|
|
14
|
+
|
|
15
|
+
// 2. ADD Engine Hooks & Data
|
|
16
|
+
import { useCrudLocalStorage } from '../../../engine/runtime/useCrudLocalStorage';
|
|
17
|
+
import { SEED_USERS, type User } from '../../../data/mockData';
|
|
18
|
+
|
|
19
|
+
const ProfilePage: React.FC = () => {
|
|
20
|
+
const { user } = useAuth();
|
|
21
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
22
|
+
const [success, setSuccess] = useState(false);
|
|
23
|
+
|
|
24
|
+
// 3. CONNECT to Data Lake
|
|
25
|
+
// We only need 'updateItem' here to modify the existing profile
|
|
26
|
+
const { updateItem } = useCrudLocalStorage<User>('ramme_db_users', SEED_USERS);
|
|
27
|
+
|
|
28
|
+
const [formData, setFormData] = useState({
|
|
29
|
+
name: '',
|
|
30
|
+
email: '',
|
|
31
|
+
role: '',
|
|
32
|
+
bio: 'Product Designer based in San Francisco.'
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Load current user data into form
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (user) {
|
|
38
|
+
setFormData({
|
|
39
|
+
name: user.name,
|
|
40
|
+
email: user.email,
|
|
41
|
+
role: user.role,
|
|
42
|
+
bio: 'Product Designer based in San Francisco.'
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}, [user]);
|
|
46
|
+
|
|
47
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
48
|
+
setFormData({ ...formData, [e.target.name]: e.target.value });
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const handleSave = async (e: React.FormEvent) => {
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
setIsLoading(true);
|
|
54
|
+
setSuccess(false);
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
if (user?.id) {
|
|
58
|
+
// 4. USE ENGINE to update the record in the Data Lake
|
|
59
|
+
// We merge the existing user object with the new form data
|
|
60
|
+
updateItem({ ...user, ...formData } as User);
|
|
61
|
+
|
|
62
|
+
// 5. REFRESH SESSION (Local hack to update UI header immediately)
|
|
63
|
+
// In a real app, AuthContext would listen to storage changes, but this is fine for a prototype.
|
|
64
|
+
localStorage.setItem('ramme_session', JSON.stringify({ ...user, ...formData }));
|
|
65
|
+
|
|
66
|
+
setSuccess(true);
|
|
67
|
+
setTimeout(() => setSuccess(false), 3000);
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error(error);
|
|
71
|
+
} finally {
|
|
72
|
+
setIsLoading(false);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className="max-w-4xl space-y-6">
|
|
78
|
+
<SectionHeader title="My Profile" />
|
|
79
|
+
|
|
80
|
+
{success && (
|
|
81
|
+
<Alert variant="info" title="Changes Saved">
|
|
82
|
+
Your profile has been updated successfully.
|
|
83
|
+
</Alert>
|
|
84
|
+
)}
|
|
85
|
+
|
|
86
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
87
|
+
{/* Left Column - Avatar Card */}
|
|
88
|
+
<Card className="p-6 flex flex-col items-center text-center space-y-4 h-fit">
|
|
89
|
+
<div className="relative group cursor-pointer">
|
|
90
|
+
<div className="h-24 w-24 rounded-full bg-primary/10 flex items-center justify-center text-2xl font-bold text-primary border-4 border-background shadow-sm">
|
|
91
|
+
{formData.name.charAt(0)}
|
|
92
|
+
</div>
|
|
93
|
+
<div className="absolute inset-0 bg-black/50 rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
|
|
94
|
+
<Icon name="camera" className="text-white" />
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
<div>
|
|
98
|
+
<h3 className="font-semibold text-lg">{formData.name}</h3>
|
|
99
|
+
<span className="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 border-transparent bg-primary text-primary-foreground hover:bg-primary/80 uppercase">
|
|
100
|
+
{formData.role}
|
|
101
|
+
</span>
|
|
102
|
+
</div>
|
|
103
|
+
<div className="w-full pt-4 border-t">
|
|
104
|
+
<p className="text-xs text-muted-foreground mb-4">Joined December 2024</p>
|
|
105
|
+
<Button variant="outline" className="w-full" size="sm">Change Avatar</Button>
|
|
106
|
+
</div>
|
|
107
|
+
</Card>
|
|
108
|
+
|
|
109
|
+
{/* Right Column - Form */}
|
|
110
|
+
<Card className="md:col-span-2 p-6">
|
|
111
|
+
<form onSubmit={handleSave} className="space-y-4">
|
|
112
|
+
<div className="grid gap-2">
|
|
113
|
+
<h3 className="font-semibold text-lg">Personal Information</h3>
|
|
114
|
+
<p className="text-sm text-muted-foreground">Update your personal details here.</p>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<div className="grid gap-4 py-4">
|
|
118
|
+
<Input
|
|
119
|
+
label="Full Name"
|
|
120
|
+
name="name"
|
|
121
|
+
value={formData.name}
|
|
122
|
+
onChange={handleChange}
|
|
123
|
+
/>
|
|
124
|
+
<Input
|
|
125
|
+
label="Email Address"
|
|
126
|
+
name="email"
|
|
127
|
+
value={formData.email}
|
|
128
|
+
onChange={handleChange}
|
|
129
|
+
/>
|
|
130
|
+
<div className="space-y-2">
|
|
131
|
+
<label className="text-sm font-medium leading-none">Bio</label>
|
|
132
|
+
<textarea
|
|
133
|
+
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
134
|
+
value={formData.bio}
|
|
135
|
+
disabled
|
|
136
|
+
/>
|
|
137
|
+
<p className="text-[0.8rem] text-muted-foreground">Bio editing is disabled in this demo.</p>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<div className="flex justify-end gap-4">
|
|
142
|
+
<Button type="submit" disabled={isLoading}>
|
|
143
|
+
{isLoading ? 'Saving...' : 'Save Changes'}
|
|
144
|
+
</Button>
|
|
145
|
+
</div>
|
|
146
|
+
</form>
|
|
147
|
+
</Card>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export default ProfilePage;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
// --- 1. Import the new generic page ---
|
|
3
|
-
import GenericContentPage from '
|
|
3
|
+
import GenericContentPage from '../../GenericContentPage';
|
|
4
4
|
|
|
5
5
|
// A simple page component for settings
|
|
6
6
|
const TeamPage: React.FC = () => {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
|
|
3
|
+
import { Sidebar, type SidebarItem, type IconName, Icon } from '@ramme-io/ui';
|
|
4
|
+
import { useSitemap } from '../../engine/runtime/SitemapContext';
|
|
5
|
+
|
|
6
|
+
const Styleguide: React.FC = () => {
|
|
7
|
+
const location = useLocation();
|
|
8
|
+
const navigate = useNavigate();
|
|
9
|
+
const sitemap = useSitemap();
|
|
10
|
+
|
|
11
|
+
// 1. Get Styleguide Section Data
|
|
12
|
+
const styleguideSection = useMemo(() => {
|
|
13
|
+
return sitemap.find(item => item.id === 'styleguide');
|
|
14
|
+
}, [sitemap]);
|
|
15
|
+
|
|
16
|
+
// 2. Transform to Sidebar Items
|
|
17
|
+
const navItems = useMemo<SidebarItem[]>(() => {
|
|
18
|
+
if (!styleguideSection?.children) return [];
|
|
19
|
+
|
|
20
|
+
// ✅ FIX: Remove the explicit ": { ... }" type. Let TS infer 'child' automatically.
|
|
21
|
+
return styleguideSection.children.map((child) => ({
|
|
22
|
+
id: child.id,
|
|
23
|
+
label: child.title,
|
|
24
|
+
// We cast to IconName because we know the string is a valid icon,
|
|
25
|
+
// and we provide a fallback 'hash' if it's undefined.
|
|
26
|
+
icon: (child.icon as IconName) || 'hash',
|
|
27
|
+
href: child.path ? `/docs/styleguide/${child.path}` : '/docs/styleguide',
|
|
28
|
+
}));
|
|
29
|
+
}, [styleguideSection]);
|
|
30
|
+
|
|
31
|
+
// 3. Determine Active Item
|
|
32
|
+
const activeItemId = useMemo(() => {
|
|
33
|
+
const active = navItems.find(item =>
|
|
34
|
+
location.pathname === item.href ||
|
|
35
|
+
(item.href && location.pathname.startsWith(item.href))
|
|
36
|
+
);
|
|
37
|
+
return active?.id;
|
|
38
|
+
}, [location.pathname, navItems]);
|
|
39
|
+
|
|
40
|
+
if (!location.pathname.startsWith('/docs') || !styleguideSection) {
|
|
41
|
+
return <Outlet />;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="flex w-full min-h-[calc(100vh-7rem)]">
|
|
46
|
+
{/* SIDEBAR */}
|
|
47
|
+
<div className="sticky top-[7rem] h-[calc(100vh-7rem)] z-20">
|
|
48
|
+
<Sidebar
|
|
49
|
+
className="h-full border-r border-border bg-card/50 backdrop-blur-sm"
|
|
50
|
+
items={navItems}
|
|
51
|
+
activeItemId={activeItemId}
|
|
52
|
+
onNavigate={(item) => {
|
|
53
|
+
if (item.href) navigate(item.href);
|
|
54
|
+
}}
|
|
55
|
+
logo={
|
|
56
|
+
<div className="flex items-center gap-2 px-1 py-2 text-muted-foreground">
|
|
57
|
+
<Icon name="book-open" className="h-4 w-4" />
|
|
58
|
+
<span className="font-semibold text-xs uppercase tracking-wider">Reference</span>
|
|
59
|
+
</div>
|
|
60
|
+
}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
{/* MAIN CONTENT */}
|
|
65
|
+
<main className="flex-1 min-w-0 bg-background overflow-x-hidden">
|
|
66
|
+
{/* ADDED: Max width constraint + centering */}
|
|
67
|
+
<div className="container max-w-7xl mx-auto p-6 md:p-10 animate-in fade-in duration-500">
|
|
68
|
+
<Outlet />
|
|
69
|
+
</div>
|
|
70
|
+
</main>
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export default Styleguide;
|