feat: wire frontend to platform data, migrate to Jotai + Vercel AI SDK

- Replace mock DataProvider with real GraphQL queries through sidecar
- Add queries.ts and transforms.ts for platform field name mapping
- Migrate SIP state from React Context to Jotai atoms (React 19 compat)
- Add singleton SIP manager to survive StrictMode remounts
- Remove hardcoded Olivia/Sienna accounts from nav menu
- Add password eye toggle, remember me checkbox, forgot password link
- Fix worklist hook to transform platform field names
- Add seed scripts for clinics, health packages, lab tests
- Update test harness for new doctor→clinic relation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-18 16:44:45 +05:30
parent e01a4d7747
commit 61901eb8fb
14 changed files with 1208 additions and 108 deletions

View File

@@ -1,8 +1,11 @@
import { useState } from 'react';
import { useNavigate } from 'react-router';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faEye, faEyeSlash } from '@fortawesome/pro-duotone-svg-icons';
import { useAuth } from '@/providers/auth-provider';
import { Button } from '@/components/base/buttons/button';
import { SocialButton } from '@/components/base/buttons/social-button';
import { Checkbox } from '@/components/base/checkbox/checkbox';
import { Input } from '@/components/base/input/input';
const features = [
@@ -25,8 +28,13 @@ export const LoginPage = () => {
const { loginWithUser } = useAuth();
const navigate = useNavigate();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const saved = localStorage.getItem('helix_remember');
const savedCreds = saved ? JSON.parse(saved) : null;
const [email, setEmail] = useState(savedCreds?.email ?? '');
const [password, setPassword] = useState(savedCreds?.password ?? '');
const [showPassword, setShowPassword] = useState(false);
const [rememberMe, setRememberMe] = useState(!!savedCreds);
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
@@ -51,6 +59,12 @@ export const LoginPage = () => {
const name = `${firstName} ${lastName}`.trim() || email;
const initials = `${firstName[0] ?? ''}${lastName[0] ?? ''}`.toUpperCase() || email[0].toUpperCase();
if (rememberMe) {
localStorage.setItem('helix_remember', JSON.stringify({ email, password }));
} else {
localStorage.removeItem('helix_remember');
}
loginWithUser({
id: u?.id,
name,
@@ -181,16 +195,41 @@ export const LoginPage = () => {
/>
</div>
{/* Password input */}
<div className="mt-4">
{/* Password input with eye toggle */}
<div className="mt-4 relative">
<Input
label="Password"
type="password"
type={showPassword ? 'text' : 'password'}
placeholder="Enter your password"
value={password}
onChange={(value) => setPassword(value)}
size="md"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-3 top-[38px] text-fg-quaternary hover:text-fg-secondary transition duration-100 ease-linear"
tabIndex={-1}
>
<FontAwesomeIcon icon={showPassword ? faEyeSlash : faEye} className="size-4" />
</button>
</div>
{/* Remember me + Forgot password */}
<div className="mt-3 flex items-center justify-between">
<Checkbox
label="Remember me"
size="sm"
isSelected={rememberMe}
onChange={setRememberMe}
/>
<button
type="button"
className="text-sm font-semibold text-brand-secondary hover:text-brand-secondary_hover transition duration-100 ease-linear"
onClick={() => setError('Password reset is not yet configured. Contact your administrator.')}
>
Forgot password?
</button>
</div>
{/* Error message */}