Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"axios-mock-adapter": "^2.1.0"
}
}
135 changes: 135 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -1537,3 +1537,138 @@
}

}

/* ---------------------------------------------------------------------------
Auth pages (/login, /register, /verify-email, /account)
--------------------------------------------------------------------------- */

.auth-hero {
padding-bottom: 24px;
}

.auth-wrap {
max-width: 520px;
}

.auth-card {
background: var(--panel);
border: 1px solid var(--panel-outline);
border-radius: var(--radius-md);
box-shadow: var(--shadow);
padding: 32px;
display: flex;
flex-direction: column;
gap: 18px;
}

.auth-card--info {
gap: 20px;
}

.auth-field {
display: flex;
flex-direction: column;
gap: 6px;
}

.auth-label {
font-size: 0.82rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
}

.auth-input {
border: 1px solid var(--panel-outline);
border-radius: 14px;
padding: 13px 16px;
background: var(--panel-strong);
color: var(--text);
font-size: 1rem;
transition: border-color 120ms ease, box-shadow 120ms ease;
}

.auth-input:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-soft);
}

.auth-hint {
font-size: 0.82rem;
color: var(--muted);
}

.auth-alert {
background: rgba(229, 107, 85, 0.1);
border: 1px solid rgba(229, 107, 85, 0.35);
color: #8b2d1b;
padding: 12px 14px;
border-radius: 14px;
font-size: 0.93rem;
}

.auth-foot {
margin: 0;
font-size: 0.92rem;
color: var(--muted);
}

.auth-foot a {
color: var(--accent);
font-weight: 600;
}

.auth-foot a:hover {
color: var(--accent-strong);
}

.auth-linklike {
border: 0;
background: transparent;
padding: 0;
color: var(--accent);
font: inherit;
font-weight: 600;
cursor: pointer;
}

.auth-linklike:hover {
color: var(--accent-strong);
}

.auth-kv {
display: flex;
flex-direction: column;
gap: 10px;
margin: 0;
}

.auth-kv__row {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
}

.auth-kv__row dt {
font-size: 0.82rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
margin: 0;
}

.auth-kv__row dd {
margin: 0;
font-weight: 500;
color: var(--text);
}

@media (max-width: 600px) {
.auth-card {
padding: 24px 20px;
}
}
43 changes: 28 additions & 15 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@ import { Redirect, Route, Switch, useLocation } from 'react-router-dom';

import Header from './parts/Header';
import Footer from './parts/Footer';
import PrivateRoute from './parts/PrivateRoute';

import Home from './pages/Home';
import Learn from './pages/Learn';
import Setup from './pages/Setup';
import Network from './pages/Network';
import Governance from './pages/Governance';
import Error from './pages/Error';
import Login from './pages/Login';
import Register from './pages/Register';
import VerifyEmail from './pages/VerifyEmail';
import Account from './pages/Account';

import { AuthProvider } from './context/AuthContext';

function ScrollToTop() {
const location = useLocation();
Expand All @@ -27,20 +34,26 @@ function ScrollToTop() {

export default function App() {
return (
<div className="site-shell">
<ScrollToTop />
<Header />
<Switch>
<Route path="/" component={Home} exact />
<Route path="/network" component={Network} />
<Route path="/stats" render={() => <Redirect to="/network" />} />
<Route path="/setup" component={Setup} />
<Route path="/governance" component={Governance} />
<Route path="/learn" component={Learn} />
<Route path="/about" render={() => <Redirect to="/learn" />} />
<Route component={Error} />
</Switch>
<Footer />
</div>
<AuthProvider>
<div className="site-shell">
<ScrollToTop />
<Header />
<Switch>
<Route path="/" component={Home} exact />
<Route path="/network" component={Network} />
<Route path="/stats" render={() => <Redirect to="/network" />} />
<Route path="/setup" component={Setup} />
<Route path="/governance" component={Governance} />
<Route path="/learn" component={Learn} />
<Route path="/about" render={() => <Redirect to="/learn" />} />
<Route path="/login" component={Login} />
<Route path="/register" component={Register} />
<Route path="/verify-email" component={VerifyEmail} />
<PrivateRoute path="/account" component={Account} />
<Route component={Error} />
</Switch>
<Footer />
</div>
</AuthProvider>
);
}
28 changes: 28 additions & 0 deletions src/App.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,34 @@ jest.mock('./pages/Error', () => function MockError() {
return <div>Not found page</div>;
});

jest.mock('./pages/Login', () => function MockLogin() {
return <div>Login page</div>;
});

jest.mock('./pages/Register', () => function MockRegister() {
return <div>Register page</div>;
});

jest.mock('./pages/VerifyEmail', () => function MockVerify() {
return <div>Verify email page</div>;
});

jest.mock('./pages/Account', () => function MockAccount() {
return <div>Account page</div>;
});

jest.mock('./lib/authService', () => ({
authService: {
me: () =>
Promise.reject(Object.assign(new Error('unauth'), { status: 401 })),
login: jest.fn(),
logout: jest.fn(),
register: jest.fn(),
verifyEmail: jest.fn(),
},
createAuthService: jest.fn(),
}));

import App from './App';

beforeEach(() => {
Expand Down
Loading