251011 start
This commit is contained in:
150
frontend/app/_auth/client.js
Executable file
150
frontend/app/_auth/client.js
Executable file
@@ -0,0 +1,150 @@
|
||||
// frontend/app/page.jsx
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs';
|
||||
import {
|
||||
Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { login as authLogin, logout as authLogout, me as fetchMe, credentials, authHeaders } from '@/app/_auth/client';
|
||||
|
||||
export default function HomePage() {
|
||||
const router = useRouter();
|
||||
const [me, setMe] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// login dialog states
|
||||
const [open, setOpen] = useState(false);
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [err, setErr] = useState('');
|
||||
|
||||
// โหลดสถานะผู้ใช้แบบไม่ redirect
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
(async () => {
|
||||
try {
|
||||
const user = await fetchMe();
|
||||
if (!cancelled) setMe(user);
|
||||
} finally {
|
||||
if (!cancelled) setLoading(false);
|
||||
}
|
||||
})();
|
||||
return () => { cancelled = true; };
|
||||
}, []);
|
||||
|
||||
async function handleLogin(e) {
|
||||
e?.preventDefault();
|
||||
setSubmitting(true);
|
||||
setErr('');
|
||||
try {
|
||||
const user = await authLogin({ username, password });
|
||||
if (!user) {
|
||||
setErr('ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง');
|
||||
return;
|
||||
}
|
||||
setMe(user);
|
||||
setOpen(false);
|
||||
router.push('/dashboard');
|
||||
} catch {
|
||||
setErr('เกิดข้อผิดพลาดในการเชื่อมต่อเซิร์ฟเวอร์');
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleLogout() {
|
||||
await authLogout().catch(() => {});
|
||||
setMe(null);
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="w-56 rounded h-7 bg-muted animate-pulse" />
|
||||
<div className="grid gap-4 md:grid-cols-3">
|
||||
{[...Array(3)].map((_, i) => <div key={i} className="rounded h-28 bg-muted animate-pulse" />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-2xl font-bold">Welcome to DMS</h2>
|
||||
|
||||
{/* แถบสถานะล็อกอิน + ปุ่ม */}
|
||||
<div className="flex items-center gap-2">
|
||||
{me ? (
|
||||
<>
|
||||
<span className="text-sm text-muted-foreground">สวัสดี, <b>{me.first_name || me.username}</b></span>
|
||||
<Button variant="secondary" onClick={() => router.push('/dashboard')}>Go to Dashboard</Button>
|
||||
<Button variant="outline" onClick={handleLogout}>Logout</Button>
|
||||
</>
|
||||
) : (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button>Login</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[420px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>เข้าสู่ระบบ</DialogTitle>
|
||||
<DialogDescription>กรอกชื่อผู้ใช้และรหัสผ่านของคุณ</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form onSubmit={handleLogin} className="grid gap-3">
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="username">Username</Label>
|
||||
<Input id="username" value={username} onChange={e => setUsername(e.target.value)} required />
|
||||
</div>
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Input id="password" type="password" value={password} onChange={e => setPassword(e.target.value)} required />
|
||||
</div>
|
||||
{err && <p className="text-sm text-red-600">{err}</p>}
|
||||
<Button type="submit" disabled={submitting}>{submitting ? 'กำลังเข้าสู่ระบบ...' : 'Login'}</Button>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* เนื้อหาอื่น ๆ (เหมือนเดิม) */}
|
||||
<Tabs defaultValue="overview" className="w-full">
|
||||
<TabsList>
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="activity">Activity</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="overview">
|
||||
<div className="grid gap-4 mt-4 md:grid-cols-3">
|
||||
<Card><CardHeader><CardTitle>📑 RFAs</CardTitle></CardHeader><CardContent><p className="text-3xl font-bold">24</p></CardContent></Card>
|
||||
<Card><CardHeader><CardTitle>📐 Drawings</CardTitle></CardHeader><CardContent><p className="text-3xl font-bold">112</p></CardContent></Card>
|
||||
<Card><CardHeader><CardTitle>📤 Transmittals</CardTitle></CardHeader><CardContent><p className="text-3xl font-bold">8</p></CardContent></Card>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="activity">
|
||||
<div className="mt-4 space-y-3">
|
||||
<p>✔️ User <b>editor01</b> uploaded Drawing D-2025-07</p>
|
||||
<p>✔️ Transmittal T-2025-02 issued to Contractor</p>
|
||||
<p>✔️ RFA R-2025-03 marked as Resolved</p>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
<div className="pt-2">
|
||||
<Button asChild disabled={!me}><Link href="/dashboard">Go to Dashboard</Link></Button>
|
||||
{!me && <span className="ml-2 text-sm text-muted-foreground">กรุณา Login ก่อน</span>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,64 +1,142 @@
|
||||
// app/page.jsx
|
||||
"use client";
|
||||
// frontend/app/page.jsx
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
|
||||
import { useEffect, useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import {
|
||||
Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
|
||||
// 👉 ใช้ driver เดิมของโปรเจ็กต์ (relative path + credentials: 'include')
|
||||
import cookieDriver from '@/app/_auth/drivers/cookieDriver';
|
||||
|
||||
export default function HomePage() {
|
||||
const router = useRouter();
|
||||
|
||||
const [me, setMe] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// dialog/login state
|
||||
const [open, setOpen] = useState(false);
|
||||
const [username, setUsername] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [err, setErr] = useState('');
|
||||
|
||||
// โหลดสถานะผู้ใช้แบบไม่ redirect
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
(async () => {
|
||||
try {
|
||||
const res = await cookieDriver.me(); // ภายในยิง /api/auth/me ด้วย credentials: 'include'
|
||||
if (!cancelled && res && (res.user || res.username)) {
|
||||
const u = res.user ?? res;
|
||||
setMe(u);
|
||||
}
|
||||
} finally {
|
||||
if (!cancelled) setLoading(false);
|
||||
}
|
||||
})();
|
||||
return () => { cancelled = true; };
|
||||
}, []);
|
||||
|
||||
async function onSubmit(e) {
|
||||
e?.preventDefault();
|
||||
setErr('');
|
||||
if (!username.trim() || !password) {
|
||||
setErr('กรอกชื่อผู้ใช้และรหัสผ่านให้ครบ');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setSubmitting(true);
|
||||
const ok = await cookieDriver.login({ username, password }); // ยิง /api/auth/login แบบ relative
|
||||
if (!ok) {
|
||||
setErr('ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง');
|
||||
return;
|
||||
}
|
||||
// ตรวจ me อีกรอบให้ชัวร์ว่ามีคุกกี้แล้ว
|
||||
const res = await cookieDriver.me();
|
||||
const u = res?.user ?? res ?? { username };
|
||||
setMe(u);
|
||||
setOpen(false);
|
||||
router.push('/dashboard');
|
||||
} catch {
|
||||
setErr('เชื่อมต่อเซิร์ฟเวอร์ไม่ได้');
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function onLogout() {
|
||||
try { await cookieDriver.logout?.(); } catch {}
|
||||
setMe(null);
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<h2 className="text-2xl font-bold">Welcome to DMS</h2>
|
||||
|
||||
<Tabs defaultValue="overview" className="w-full">
|
||||
<TabsList>
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="activity">Activity</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="overview">
|
||||
<div className="grid gap-4 mt-4 md:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>📑 RFAs</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-3xl font-bold">24</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>📐 Drawings</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-3xl font-bold">112</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>📤 Transmittals</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-3xl font-bold">8</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<div className="w-56 rounded h-7 bg-muted animate-pulse" />
|
||||
<div className="grid gap-4 md:grid-cols-3">
|
||||
{[...Array(3)].map((_, i) => <div key={i} className="h-24 rounded bg-muted animate-pulse" />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-2xl font-bold">Welcome to DMS</h2>
|
||||
<div className="flex items-center gap-2">
|
||||
{me ? (
|
||||
<>
|
||||
<span className="text-sm text-muted-foreground">สวัสดี, <b>{me.first_name || me.username}</b></span>
|
||||
<Button variant="secondary" onClick={() => router.push('/dashboard')}>Go to Dashboard</Button>
|
||||
<Button variant="outline" onClick={onLogout}>Logout</Button>
|
||||
</>
|
||||
) : (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild><Button>Login</Button></DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[420px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>เข้าสู่ระบบ</DialogTitle>
|
||||
<DialogDescription>กรอกชื่อผู้ใช้และรหัสผ่านของคุณ</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form onSubmit={onSubmit} className="grid gap-3">
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="username">Username</Label>
|
||||
<Input id="username" value={username} onChange={(e) => setUsername(e.target.value)} required />
|
||||
</div>
|
||||
<div className="grid gap-1.5">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Input id="password" type="password" value={password} onChange={(e) => setPassword(e.target.value)} required />
|
||||
</div>
|
||||
{err && <p className="text-sm text-red-600">{err}</p>}
|
||||
<Button type="submit" disabled={submitting}>{submitting ? 'กำลังเข้าสู่ระบบ…' : 'Login'}</Button>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* เนื้อหาย่อก่อนเข้าดาชบอร์ด */}
|
||||
<div className="grid gap-4 mt-2 md:grid-cols-3">
|
||||
<Card><CardHeader><CardTitle>📑 RFAs</CardTitle></CardHeader><CardContent><p className="text-3xl font-bold">—</p></CardContent></Card>
|
||||
<Card><CardHeader><CardTitle>📐 Drawings</CardTitle></CardHeader><CardContent><p className="text-3xl font-bold">—</p></CardContent></Card>
|
||||
<Card><CardHeader><CardTitle>📤 Transmittals</CardTitle></CardHeader><CardContent><p className="text-3xl font-bold">—</p></CardContent></Card>
|
||||
</div>
|
||||
|
||||
<div className="pt-2">
|
||||
<Button asChild disabled={!me}><Link href="/dashboard">Go to Dashboard</Link></Button>
|
||||
{!me && <span className="ml-2 text-sm text-muted-foreground">กรุณา Login ก่อน</span>}
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="activity">
|
||||
<div className="mt-4 space-y-3">
|
||||
<p>
|
||||
✔️ User <b>editor01</b> uploaded Drawing D-2025-07
|
||||
</p>
|
||||
<p>✔️ Transmittal T-2025-02 issued to Contractor</p>
|
||||
<p>✔️ RFA R-2025-03 marked as Resolved</p>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
<Button className="mt-6">Go to Dashboard</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user