Skip to content

Commit 3218b17

Browse files
committed
feat: update layout components and navigation with theme support
1 parent 8aad16a commit 3218b17

File tree

4 files changed

+113
-139
lines changed

4 files changed

+113
-139
lines changed

src/App.jsx

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
import React, { useState, useEffect } from 'react';
22
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
3-
import Sidebar from './components/layout/Sidebar';
3+
import { AuthProvider } from './context/AuthContext';
4+
import ProtectedRoute from './components/auth/ProtectedRoute';
5+
import Homepage from './pages/Homepage';
6+
import DashboardLayout from './components/layout/DashboardLayout';
47
import Dashboard from './pages/Dashboard';
58
import Portfolio from './pages/Portfolio';
69
import Watchlist from './pages/Watchlist';
10+
import Profile from './pages/Profile';
11+
import Settings from './pages/Settings';
12+
import StockDetail from './pages/StockDetail';
13+
import News from './pages/News';
14+
import MarketCalendar from './pages/MarketCalendar';
715

816
export default function App() {
917
const [theme, setTheme] = useState(localStorage.getItem('theme') || 'light');
@@ -39,17 +47,71 @@ export default function App() {
3947
}, [theme]);
4048

4149
return (
42-
<Router>
43-
<div className={`flex h-screen ${theme === 'dark' ? 'bg-[#171717]' : 'bg-white'}`}>
44-
<Sidebar theme={theme} />
45-
<div className="flex-1 overflow-auto">
46-
<Routes>
47-
<Route path="/" element={<Dashboard theme={theme} />} />
48-
<Route path="/portfolio" element={<Portfolio theme={theme} />} />
49-
<Route path="/watchlist" element={<Watchlist theme={theme} />} />
50-
</Routes>
51-
</div>
52-
</div>
53-
</Router>
50+
<AuthProvider>
51+
<Router>
52+
<Routes>
53+
{/* Public routes */}
54+
<Route path="/" element={<Homepage />} />
55+
56+
{/* Protected dashboard routes */}
57+
<Route path="/dashboard" element={
58+
<ProtectedRoute>
59+
<DashboardLayout theme={theme}>
60+
<Dashboard theme={theme} />
61+
</DashboardLayout>
62+
</ProtectedRoute>
63+
} />
64+
<Route path="/portfolio" element={
65+
<ProtectedRoute>
66+
<DashboardLayout theme={theme}>
67+
<Portfolio theme={theme} />
68+
</DashboardLayout>
69+
</ProtectedRoute>
70+
} />
71+
<Route path="/watchlist" element={
72+
<ProtectedRoute>
73+
<DashboardLayout theme={theme}>
74+
<Watchlist theme={theme} />
75+
</DashboardLayout>
76+
</ProtectedRoute>
77+
} />
78+
<Route path="/profile" element={
79+
<ProtectedRoute>
80+
<DashboardLayout theme={theme}>
81+
<Profile theme={theme} />
82+
</DashboardLayout>
83+
</ProtectedRoute>
84+
} />
85+
<Route path="/settings" element={
86+
<ProtectedRoute>
87+
<DashboardLayout theme={theme}>
88+
<Settings theme={theme} />
89+
</DashboardLayout>
90+
</ProtectedRoute>
91+
} />
92+
<Route path="/stock/:id" element={
93+
<ProtectedRoute>
94+
<DashboardLayout theme={theme}>
95+
<StockDetail theme={theme} />
96+
</DashboardLayout>
97+
</ProtectedRoute>
98+
} />
99+
<Route path="/news" element={
100+
<ProtectedRoute>
101+
<DashboardLayout theme={theme}>
102+
<News theme={theme} />
103+
</DashboardLayout>
104+
</ProtectedRoute>
105+
} />
106+
<Route path="/calendar" element={
107+
<ProtectedRoute>
108+
<DashboardLayout theme={theme}>
109+
<MarketCalendar theme={theme} />
110+
</DashboardLayout>
111+
</ProtectedRoute>
112+
} />
113+
</Routes>
114+
</Router>
115+
</AuthProvider>
54116
);
55117
}
Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
1-
import { useState } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import Sidebar from './Sidebar';
3-
import Navbar from './Navbar';
4-
5-
export default function DashboardLayout({ children }) {
6-
const [sidebarOpen, setSidebarOpen] = useState(false);
73

4+
const DashboardLayout = ({ children, theme }) => {
85
return (
9-
<div className="min-h-screen bg-gray-50">
10-
<Sidebar open={sidebarOpen} setOpen={setSidebarOpen} />
11-
12-
<div className="lg:pl-72">
13-
<Navbar onMenuClick={() => setSidebarOpen(true)} />
14-
15-
<main className="py-6">
16-
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
17-
{children}
18-
</div>
19-
</main>
6+
<div className={`flex h-screen ${theme === 'dark' ? 'bg-[#171717]' : 'bg-white'}`}>
7+
<Sidebar theme={theme} />
8+
<div className="flex-1 overflow-auto">
9+
{children}
2010
</div>
2111
</div>
2212
);
23-
}
13+
};
14+
15+
export default DashboardLayout;

src/components/layout/Sidebar.jsx

Lines changed: 19 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import React, { useState } from 'react';
22
import { motion } from 'framer-motion';
3-
import { Link, useLocation } from 'react-router-dom';
3+
import { Link, useLocation, useNavigate } from 'react-router-dom';
4+
import { useAuth } from '../../context/AuthContext';
45
import axios from 'axios';
56
import {
67
HiHome,
78
HiChartBar,
89
HiStar,
10+
HiNewspaper,
11+
HiCalendar,
912
HiChevronLeft,
1013
HiChevronRight,
1114
HiSun,
@@ -33,134 +36,41 @@ const LoadingOverlay = ({ message }) => (
3336

3437
export default function Sidebar({ theme }) {
3538
const location = useLocation();
39+
const navigate = useNavigate();
40+
const { signOut } = useAuth();
3641
const [isExpanded, setIsExpanded] = useState(true);
3742
const [isLoading, setIsLoading] = useState(false);
3843
const [loadingMessage, setLoadingMessage] = useState('');
3944

4045
const navItems = [
41-
{ path: '/', icon: HiHome, label: 'Dashboard' },
46+
{ path: '/dashboard', icon: HiHome, label: 'Dashboard' },
4247
{ path: '/portfolio', icon: HiChartBar, label: 'Portfolio' },
43-
{ path: '/watchlist', icon: HiStar, label: 'Watchlist' }
48+
{ path: '/watchlist', icon: HiStar, label: 'Watchlist' },
49+
{ path: '/news', icon: HiNewspaper, label: 'News' },
50+
{ path: '/calendar', icon: HiCalendar, label: 'Calendar' }
4451
];
4552

46-
const randomStocks = [
47-
{ name: 'Apple Inc.', ticker: 'AAPL', buy_price: 175.50, targetPrice: 200.00, current_price: 175.50 },
48-
{ name: 'Microsoft Corporation', ticker: 'MSFT', buy_price: 340.20, targetPrice: 380.00, current_price: 340.20 },
49-
{ name: 'Amazon.com Inc.', ticker: 'AMZN', buy_price: 125.30, targetPrice: 150.00, current_price: 125.30 },
50-
{ name: 'Alphabet Inc.', ticker: 'GOOGL', buy_price: 135.60, targetPrice: 160.00, current_price: 135.60 },
51-
{ name: 'NVIDIA Corporation', ticker: 'NVDA', buy_price: 450.80, targetPrice: 500.00, current_price: 450.80 },
52-
{ name: 'Meta Platforms Inc.', ticker: 'META', buy_price: 290.40, targetPrice: 320.00, current_price: 290.40 },
53-
{ name: 'Tesla Inc.', ticker: 'TSLA', buy_price: 240.50, targetPrice: 280.00, current_price: 240.50 },
54-
{ name: 'Netflix Inc.', ticker: 'NFLX', buy_price: 385.70, targetPrice: 420.00, current_price: 385.70 },
55-
{ name: 'Adobe Inc.', ticker: 'ADBE', buy_price: 420.30, targetPrice: 460.00, current_price: 420.30 },
56-
{ name: 'Salesforce Inc.', ticker: 'CRM', buy_price: 210.90, targetPrice: 240.00, current_price: 210.90 }
57-
];
53+
5854

5955
const handleLogout = async () => {
60-
if (window.confirm('Are you sure you want to logout? This will reset your portfolio..')) {
56+
if (window.confirm('Are you sure you want to logout?')) {
6157
try {
6258
setIsLoading(true);
63-
setLoadingMessage('Resetting your portfolio...');
64-
65-
// Get all current stocks
66-
const portfolioResponse = await api.get('/stocks');
67-
const portfolioStocks = portfolioResponse.data || [];
59+
setLoadingMessage('Logging out...');
6860

69-
console.log('Current portfolio stocks:', portfolioStocks);
70-
71-
// Delete all current stocks if there are any
72-
if (portfolioStocks.length > 0) {
73-
await Promise.all(portfolioStocks.map(stock =>
74-
api.delete(`/stocks/${stock.id}`)
75-
));
76-
console.log('Successfully deleted all portfolio stocks');
61+
const { error } = await signOut();
62+
if (error) {
63+
throw error;
7764
}
78-
79-
// Shuffle and pick 5 random stocks
80-
const shuffled = [...randomStocks].sort(() => 0.5 - Math.random());
81-
const selectedStocks = shuffled.slice(0, 5);
82-
console.log('Selected stocks to add:', selectedStocks);
83-
84-
// Keep track of successful and failed additions
85-
const results = {
86-
successful: [],
87-
failed: []
88-
};
89-
90-
// Add the random stocks one by one
91-
for (const stock of selectedStocks) {
92-
try {
93-
console.log('Adding stock:', stock);
94-
95-
// Add to portfolio with all required fields
96-
const portfolioStock = {
97-
name: stock.name,
98-
ticker: stock.ticker,
99-
shares: 1,
100-
buy_price: parseFloat(stock.buy_price),
101-
current_price: parseFloat(stock.current_price),
102-
target_price: parseFloat(stock.targetPrice)
103-
};
104-
105-
// Add to portfolio
106-
const response = await api.post('/stocks', portfolioStock);
107-
console.log(`Successfully added stock ${stock.ticker}`);
108-
results.successful.push(stock.ticker);
109-
} catch (error) {
110-
console.error(`Error adding stock ${stock.ticker}:`, error);
111-
results.failed.push(stock.ticker);
112-
113-
// If a stock fails, try to add a different one from our list
114-
const remainingStocks = randomStocks.filter(s =>
115-
!selectedStocks.includes(s) &&
116-
!results.successful.includes(s.ticker) &&
117-
!results.failed.includes(s.ticker)
118-
);
119-
120-
if (remainingStocks.length > 0) {
121-
const replacementStock = remainingStocks[0];
122-
console.log(`Trying replacement stock: ${replacementStock.ticker}`);
123-
try {
124-
const portfolioStock = {
125-
name: replacementStock.name,
126-
ticker: replacementStock.ticker,
127-
shares: 1,
128-
buy_price: parseFloat(replacementStock.buy_price),
129-
current_price: parseFloat(replacementStock.current_price),
130-
target_price: parseFloat(replacementStock.targetPrice)
131-
};
132-
133-
const response = await api.post('/stocks', portfolioStock);
134-
console.log(`Successfully added replacement stock ${replacementStock.ticker}`);
135-
results.successful.push(replacementStock.ticker);
136-
} catch (retryError) {
137-
console.error(`Error adding replacement stock ${replacementStock.ticker}:`, retryError);
138-
results.failed.push(replacementStock.ticker);
139-
}
140-
}
141-
}
142-
}
143-
144-
// Check if we have 5 successful additions
145-
if (results.successful.length === 5) {
146-
console.log('Successfully added all 5 stocks:', results.successful);
147-
} else {
148-
console.warn(`Only added ${results.successful.length} stocks successfully:`, results.successful);
149-
console.warn('Failed stocks:', results.failed);
150-
throw new Error(`Could only add ${results.successful.length} out of 5 stocks`);
151-
}
152-
153-
// Small delay before refreshing
154-
await new Promise(resolve => setTimeout(resolve, 1000));
15565

156-
// Refresh the page
157-
window.location.reload();
66+
// Navigate to homepage
67+
navigate('/');
15868
} catch (error) {
15969
console.error('Error during logout:', error);
16070
setLoadingMessage('Error occurred. Please try again.');
16171
await new Promise(resolve => setTimeout(resolve, 2000));
16272
setIsLoading(false);
163-
alert(error.message || 'Failed to logout. Please try again.');
73+
alert('Failed to logout. Please try again.');
16474
}
16575
}
16676
};

src/index.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22
@tailwind components;
33
@tailwind utilities;
44

5+
.no-visible-scrollbar {
6+
scrollbar-width: none;
7+
-ms-overflow-style: none;
8+
-webkit-overflow-scrolling: touch;
9+
}
10+
11+
.no-visible-scrollbar::-webkit-scrollbar {
12+
display: none;
13+
}
14+
515
:root {
616
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
717
line-height: 1.5;

0 commit comments

Comments
 (0)