The console was wearing an approximation of the bank. Everything here was read off HDFC Bank's own production assets instead. The mark was inside out. It had been drawn as a blue square with a red square inset; HDFC's is the reverse — a red ground, a white channel cross splitting it into four corner blocks, and a small blue square at the centre. Every coordinate now comes verbatim from the SVG the bank serves in its own site header, including the "HDFC BANK" wordmark outlines, so the lockup is the bank's rather than a redrawing of it. The favicon in index.html carried the same inversion and is fixed with the same numbers. Open Sans replaces the Segoe UI stack. hdfcbank.com preloads OpenSans Regular / SemiBold / Bold / ExtraBold and sets its whole site in it. It is self-hosted through @fontsource-variable/open-sans rather than pulled from a CDN, for the reason the API URL is read at runtime: this build gets promoted between environments and dropped behind bank proxies, and a font that sometimes fails to arrive is a product that sometimes looks like someone else's. The header stops being a navy band. HDFC puts the full lockup on a light ground on every one of its own digital surfaces, and a navy header made the real logo unusable — the lockup's own blue bar would have dissolved into it. The blue now does its work as the rule under the header, the active queue and the primary button, which is how the bank uses it. The lockup's 3px white keyline is the bank's own, so it sits correctly on the panel in dark mode too and no reversed variant is needed. Palette, grounded rather than invented: the page canvas is #F0F6FB, the tint hdfcbank.com uses behind content; the good/ tokens sit on the hue of the bank's #00B947 instead of a generic emerald, darkened to #00713D because #00B947 is 2.6:1 on white and unreadable as a label. The two brand hexes were already right and are unchanged. Also closes three AA failures the palette claimed it did not have — --color-faint in light, and --color-faint / --color-brand in dark, each below 4.5:1 on --color-panel3. White on --color-signal (4.31:1) is left alone knowingly: darkening HDFC red for the Decline button would have made it a different red from the logo beside it.
92 lines
3.3 KiB
TypeScript
92 lines
3.3 KiB
TypeScript
import { useState } from 'react';
|
|
import { useZino } from '../api/provider';
|
|
import { ORG_ID } from '../api/config';
|
|
import { Button, ErrorNote, Input, Label } from '../components/core';
|
|
import { HdfcAppLogo, HdfcLogo } from '../components/HdfcLogo';
|
|
import { ThemeToggle } from '../components/ThemeToggle';
|
|
|
|
/**
|
|
* Sign in.
|
|
*
|
|
* The org is fixed — this build serves one tenant — so it is not a field the
|
|
* user has to know. It still goes over the wire as a STRING: the gateway
|
|
* rejects a number with "cannot unmarshal number into Go struct field
|
|
* LoginRequest.org_id", which is a confusing failure to hit from a login form.
|
|
*/
|
|
export function Login() {
|
|
const { login } = useZino();
|
|
const [email, setEmail] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [busy, setBusy] = useState(false);
|
|
const [err, setErr] = useState<string | null>(null);
|
|
|
|
async function submit() {
|
|
if (!email || !password) {
|
|
setErr('Enter your email and password');
|
|
return;
|
|
}
|
|
setBusy(true);
|
|
setErr(null);
|
|
try {
|
|
await login(email, password, ORG_ID);
|
|
} catch (e) {
|
|
setErr((e as { message?: string })?.message ?? 'Could not sign in');
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="flex min-h-full flex-col bg-bg">
|
|
<header className="bg-panel">
|
|
<div className="flex items-center justify-between px-4 py-2.5">
|
|
<HdfcAppLogo />
|
|
<ThemeToggle />
|
|
</div>
|
|
<div aria-hidden="true" className="h-[3px] bg-navy" />
|
|
</header>
|
|
|
|
<div className="flex flex-1 items-center justify-center p-4">
|
|
<form
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
void submit();
|
|
}}
|
|
className="lift w-full max-w-sm rounded-lg border border-line bg-panel p-6"
|
|
>
|
|
{/* The lockup again, above the fold of the only screen a signed-out
|
|
person sees. A sign-in page is where someone checks they are at
|
|
the right bank before typing a password into it. */}
|
|
<HdfcLogo height={30} />
|
|
<h1 className="mt-5 text-lg font-semibold text-ink">Sign in</h1>
|
|
<p className="mt-1 text-sm text-muted">
|
|
Loan Desk — MSME and personal loan origination.
|
|
</p>
|
|
|
|
<div className="mt-5 space-y-3">
|
|
{err && <ErrorNote>{err}</ErrorNote>}
|
|
<div>
|
|
<Label required>Email</Label>
|
|
<Input value={email} onChange={setEmail} type="email" placeholder="name@hdfcbank.com" />
|
|
</div>
|
|
<div>
|
|
<Label required>Password</Label>
|
|
<Input value={password} onChange={setPassword} type="password" placeholder="••••••••" />
|
|
</div>
|
|
<Button kind="primary" type="submit" busy={busy} className="w-full">
|
|
Sign in
|
|
</Button>
|
|
</div>
|
|
|
|
{/* The bank's line, set the way the bank sets it — under the mark,
|
|
light, small, and not shouted. It belongs on the one screen that
|
|
is purely the bank talking to its own staff, and nowhere else. */}
|
|
<p className="mt-6 border-t border-line pt-4 text-center text-[11px] tracking-wide text-faint">
|
|
We understand your world
|
|
</p>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|