Compare commits
1 Commits
format-maj
...
style2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
112c9d0627 |
@@ -1,5 +1,6 @@
|
||||
import { Routes, Route, Link, Navigate } from "react-router-dom";
|
||||
import { Routes, Route, Navigate } from "react-router-dom";
|
||||
import { useAuth } from "./contexts/AuthContext";
|
||||
import Navbar from "./components/Navbar";
|
||||
import Login from "./pages/Login";
|
||||
import Signup from "./pages/Signup";
|
||||
import Addresses from "./pages/Addresses";
|
||||
@@ -7,9 +8,8 @@ import Alerts from "./pages/Alerts";
|
||||
import AlertHistory from "./pages/AlertHistory";
|
||||
|
||||
export default function App() {
|
||||
const { currentUser, logout } = useAuth();
|
||||
const { currentUser } = useAuth();
|
||||
|
||||
// Show login/signup routes if not authenticated
|
||||
if (!currentUser) {
|
||||
return (
|
||||
<Routes>
|
||||
@@ -20,51 +20,9 @@ export default function App() {
|
||||
);
|
||||
}
|
||||
|
||||
// Show main app if authenticated
|
||||
return (
|
||||
<div style={{ padding: "1rem" }}>
|
||||
<nav
|
||||
style={{
|
||||
marginBottom: "1rem",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<Link to="/addresses">Addresses</Link>
|
||||
{" | "}
|
||||
<Link to="/alerts">Alerts</Link>
|
||||
{" | "}
|
||||
<Link to="/history">History</Link>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "1rem",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: "0.9rem", color: "#999" }}>
|
||||
{currentUser.email}
|
||||
</span>
|
||||
<button
|
||||
onClick={logout}
|
||||
style={{
|
||||
padding: "0.5rem 1rem",
|
||||
fontSize: "0.9rem",
|
||||
backgroundColor: "#333",
|
||||
color: "white",
|
||||
border: "1px solid #555",
|
||||
borderRadius: "4px",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div>
|
||||
<Navbar />
|
||||
<Routes>
|
||||
<Route path="/" element={<Addresses />} />
|
||||
<Route path="/addresses" element={<Addresses />} />
|
||||
|
||||
85
frontend/src/components/Navbar.jsx
Normal file
85
frontend/src/components/Navbar.jsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
import { useAuth } from "../contexts/AuthContext";
|
||||
|
||||
const navLinks = [
|
||||
{ to: "/addresses", label: "Addresses" },
|
||||
{ to: "/alerts", label: "Configure Alerts" },
|
||||
{ to: "/history", label: "Alert History" },
|
||||
];
|
||||
|
||||
export default function Navbar() {
|
||||
const { currentUser, logout } = useAuth();
|
||||
const location = useLocation();
|
||||
|
||||
if (!currentUser) return null;
|
||||
|
||||
return (
|
||||
<nav style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
padding: "1rem 2rem",
|
||||
marginBottom: "1.5rem",
|
||||
backgroundColor: "#1a1a1a",
|
||||
borderBottom: "1px solid #333",
|
||||
}}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
|
||||
<span style={{
|
||||
fontWeight: 700,
|
||||
fontSize: "1.1rem",
|
||||
color: "#fff",
|
||||
marginRight: "2rem",
|
||||
letterSpacing: "0.5px",
|
||||
}}>
|
||||
Koin Ping
|
||||
</span>
|
||||
|
||||
<div style={{ display: "flex", gap: "0.25rem" }}>
|
||||
{navLinks.map(({ to, label }) => {
|
||||
const isActive = location.pathname === to;
|
||||
return (
|
||||
<Link
|
||||
key={to}
|
||||
to={to}
|
||||
style={{
|
||||
padding: "0.5rem 1.25rem",
|
||||
borderRadius: "6px",
|
||||
textDecoration: "none",
|
||||
fontSize: "1.425rem",
|
||||
fontWeight: isActive ? 600 : 200,
|
||||
color: isActive ? "#fff" : "#999",
|
||||
backgroundColor: isActive ? "#333" : "transparent",
|
||||
transition: "all 0.15s ease",
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "1.25rem" }}>
|
||||
<span style={{ fontSize: "1.275rem", color: "#777" }}>
|
||||
{currentUser.email}
|
||||
</span>
|
||||
<button
|
||||
onClick={logout}
|
||||
style={{
|
||||
padding: "0.4rem 1rem",
|
||||
fontSize: "1.275rem",
|
||||
fontWeight: 400,
|
||||
backgroundColor: "transparent",
|
||||
color: "#999",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "6px",
|
||||
cursor: "pointer",
|
||||
transition: "all 0.15s ease",
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
33
frontend/src/index.css
Normal file
33
frontend/src/index.css
Normal file
@@ -0,0 +1,33 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap');
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Nunito', sans-serif;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 200;
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Nunito', sans-serif;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
input, select, textarea, button {
|
||||
font-family: 'Nunito', sans-serif;
|
||||
font-size: 1rem;
|
||||
font-weight: 200;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import ReactDOM from "react-dom/client";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import { AuthProvider } from "./contexts/AuthContext";
|
||||
import App from "./App";
|
||||
import "./index.css";
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")).render(
|
||||
<React.StrictMode>
|
||||
|
||||
@@ -51,7 +51,7 @@ export default function Addresses() {
|
||||
{loading && <p>Loading addresses...</p>}
|
||||
{error && <p style={{ color: "red" }}>Error: {error}</p>}
|
||||
{!loading && !error && addresses.length === 0 && (
|
||||
<p style={{ color: "#666" }}>
|
||||
<p style={{ color: "#808080" }}>
|
||||
No addresses tracked yet. Add one above to get started.
|
||||
</p>
|
||||
)}
|
||||
@@ -63,8 +63,9 @@ export default function Addresses() {
|
||||
style={{
|
||||
padding: "1rem",
|
||||
marginBottom: "0.5rem",
|
||||
border: "1px solid #ddd",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "4px",
|
||||
backgroundColor: "#333",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
@@ -78,7 +79,8 @@ export default function Addresses() {
|
||||
<div
|
||||
style={{
|
||||
fontFamily: "monospace",
|
||||
fontSize: "0.9rem",
|
||||
fontSize: "1.035rem",
|
||||
color: "#b3b3b3",
|
||||
}}
|
||||
>
|
||||
{addr.address}
|
||||
|
||||
@@ -39,7 +39,7 @@ export default function AlertHistory() {
|
||||
<h1>Recent Alerts</h1>
|
||||
|
||||
{alertEvents.length === 0 ? (
|
||||
<p style={{ color: "#666" }}>No alerts yet</p>
|
||||
<p style={{ color: "#808080" }}>No alerts yet</p>
|
||||
) : (
|
||||
<ul style={{ listStyle: "none", padding: 0 }}>
|
||||
{alertEvents.map((event) => (
|
||||
@@ -48,8 +48,9 @@ export default function AlertHistory() {
|
||||
style={{
|
||||
padding: "1rem",
|
||||
marginBottom: "0.75rem",
|
||||
border: "1px solid #ddd",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "4px",
|
||||
backgroundColor: "#333",
|
||||
}}
|
||||
>
|
||||
<div style={{ marginBottom: "0.5rem" }}>
|
||||
@@ -58,15 +59,15 @@ export default function AlertHistory() {
|
||||
{event.address_label && (
|
||||
<div
|
||||
style={{
|
||||
fontSize: "0.9rem",
|
||||
color: "#666",
|
||||
fontSize: "1.035rem",
|
||||
color: "#808080",
|
||||
marginBottom: "0.25rem",
|
||||
}}
|
||||
>
|
||||
Address: {event.address_label}
|
||||
</div>
|
||||
)}
|
||||
<small style={{ color: "#999" }}>
|
||||
<small style={{ color: "#b3b3b3" }}>
|
||||
{formatTimestamp(event.timestamp)}
|
||||
</small>
|
||||
</li>
|
||||
|
||||
@@ -250,15 +250,15 @@ export default function Alerts() {
|
||||
style={{
|
||||
padding: "1rem",
|
||||
marginBottom: "2rem",
|
||||
backgroundColor: "#2a2a2a",
|
||||
backgroundColor: "#333",
|
||||
borderRadius: "4px",
|
||||
border: "1px solid #444",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "0.9rem",
|
||||
color: "#999",
|
||||
fontSize: "1.035rem",
|
||||
color: "#b3b3b3",
|
||||
}}
|
||||
>
|
||||
Managing alerts for:
|
||||
@@ -274,8 +274,8 @@ export default function Alerts() {
|
||||
<div
|
||||
style={{
|
||||
fontFamily: "monospace",
|
||||
fontSize: "0.9rem",
|
||||
color: "#999",
|
||||
fontSize: "1.035rem",
|
||||
color: "#b3b3b3",
|
||||
}}
|
||||
>
|
||||
{selectedAddress.address}
|
||||
@@ -316,7 +316,7 @@ export default function Alerts() {
|
||||
marginBottom: "0.5rem",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "4px",
|
||||
backgroundColor: "#2a2a2a",
|
||||
backgroundColor: "#333",
|
||||
opacity: alert.enabled
|
||||
? 1
|
||||
: 0.6,
|
||||
@@ -348,8 +348,8 @@ export default function Alerts() {
|
||||
<div
|
||||
style={{
|
||||
fontSize:
|
||||
"0.9rem",
|
||||
color: "#999",
|
||||
"1.035rem",
|
||||
color: "#b3b3b3",
|
||||
}}
|
||||
>
|
||||
Threshold:{" "}
|
||||
@@ -362,8 +362,8 @@ export default function Alerts() {
|
||||
<div
|
||||
style={{
|
||||
fontSize:
|
||||
"0.85rem",
|
||||
color: "#666",
|
||||
"0.978rem",
|
||||
color: "#808080",
|
||||
marginTop:
|
||||
"0.25rem",
|
||||
}}
|
||||
@@ -451,7 +451,7 @@ export default function Alerts() {
|
||||
style={{
|
||||
marginBottom: "2rem",
|
||||
padding: "1rem",
|
||||
backgroundColor: "#f5f5f5",
|
||||
backgroundColor: "#333",
|
||||
borderRadius: "4px",
|
||||
}}
|
||||
>
|
||||
@@ -480,8 +480,8 @@ export default function Alerts() {
|
||||
</label>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "0.85rem",
|
||||
color: "#666",
|
||||
fontSize: "0.978rem",
|
||||
color: "#808080",
|
||||
marginTop: "0.5rem",
|
||||
marginLeft: "26px",
|
||||
}}
|
||||
@@ -524,8 +524,8 @@ export default function Alerts() {
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "0.85rem",
|
||||
color: "#999",
|
||||
fontSize: "0.978rem",
|
||||
color: "#b3b3b3",
|
||||
marginTop: "0.5rem",
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function Login() {
|
||||
width: "100%",
|
||||
padding: "0.5rem",
|
||||
fontSize: "1rem",
|
||||
backgroundColor: "#1a1a1a",
|
||||
backgroundColor: "#242424",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "4px",
|
||||
color: "white",
|
||||
@@ -103,7 +103,7 @@ export default function Login() {
|
||||
width: "100%",
|
||||
padding: "0.5rem",
|
||||
fontSize: "1rem",
|
||||
backgroundColor: "#1a1a1a",
|
||||
backgroundColor: "#242424",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "4px",
|
||||
color: "white",
|
||||
@@ -131,7 +131,7 @@ export default function Login() {
|
||||
</form>
|
||||
|
||||
<div style={{ marginTop: "1.5rem", textAlign: "center" }}>
|
||||
<p style={{ color: "#999" }}>
|
||||
<p style={{ color: "#b3b3b3" }}>
|
||||
Don't have an account?{" "}
|
||||
<Link
|
||||
to="/signup"
|
||||
|
||||
@@ -101,7 +101,7 @@ export default function Signup() {
|
||||
width: "100%",
|
||||
padding: "0.5rem",
|
||||
fontSize: "1rem",
|
||||
backgroundColor: "#1a1a1a",
|
||||
backgroundColor: "#242424",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "4px",
|
||||
color: "white",
|
||||
@@ -123,7 +123,7 @@ export default function Signup() {
|
||||
width: "100%",
|
||||
padding: "0.5rem",
|
||||
fontSize: "1rem",
|
||||
backgroundColor: "#1a1a1a",
|
||||
backgroundColor: "#242424",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "4px",
|
||||
color: "white",
|
||||
@@ -145,7 +145,7 @@ export default function Signup() {
|
||||
width: "100%",
|
||||
padding: "0.5rem",
|
||||
fontSize: "1rem",
|
||||
backgroundColor: "#1a1a1a",
|
||||
backgroundColor: "#242424",
|
||||
border: "1px solid #444",
|
||||
borderRadius: "4px",
|
||||
color: "white",
|
||||
@@ -173,7 +173,7 @@ export default function Signup() {
|
||||
</form>
|
||||
|
||||
<div style={{ marginTop: "1.5rem", textAlign: "center" }}>
|
||||
<p style={{ color: "#999" }}>
|
||||
<p style={{ color: "#b3b3b3" }}>
|
||||
Already have an account?{" "}
|
||||
<Link
|
||||
to="/login"
|
||||
|
||||
Reference in New Issue
Block a user