[agent-pipeline] pipe-20260306194817-rw8w round-1
This commit is contained in:
parent
8b9f9a3a67
commit
e07cf00171
|
|
@ -14,8 +14,14 @@ export default function LoginPage() {
|
|||
useLogin();
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100 p-4">
|
||||
<div className="w-full max-w-md space-y-8">
|
||||
<div className="relative flex min-h-screen items-center justify-center bg-gradient-to-br from-background to-muted p-4">
|
||||
{/* 배경 장식 원 */}
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<div className="absolute -top-40 -right-40 h-80 w-80 rounded-full bg-primary/5" />
|
||||
<div className="absolute -bottom-40 -left-40 h-80 w-80 rounded-full bg-primary/5" />
|
||||
</div>
|
||||
|
||||
<div className="relative w-full max-w-md space-y-8">
|
||||
<LoginHeader />
|
||||
|
||||
<LoginForm
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { UI_CONFIG } from "@/constants/auth";
|
|||
*/
|
||||
export function LoginFooter() {
|
||||
return (
|
||||
<div className="text-center text-sm text-slate-500">
|
||||
<div className="text-center text-sm text-muted-foreground">
|
||||
<p>{UI_CONFIG.COPYRIGHT}</p>
|
||||
<p className="mt-1">{UI_CONFIG.POWERED_BY}</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export function LoginForm({
|
|||
onTogglePassword,
|
||||
}: LoginFormProps) {
|
||||
return (
|
||||
<Card className="border-0 shadow-xl">
|
||||
<Card className="border-0 shadow-xl bg-card/80 backdrop-blur-sm">
|
||||
<CardHeader className="space-y-1">
|
||||
<CardTitle className="text-center text-2xl">로그인</CardTitle>
|
||||
<CardDescription className="text-center">계정 정보를 입력해주세요</CardDescription>
|
||||
|
|
@ -74,7 +74,7 @@ export function LoginForm({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onTogglePassword}
|
||||
className="absolute top-1/2 right-3 -translate-y-1/2 transform text-slate-400 transition-colors hover:text-slate-600"
|
||||
className="absolute top-1/2 right-3 -translate-y-1/2 transform text-muted-foreground transition-colors hover:text-foreground"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
|
||||
|
|
@ -85,7 +85,7 @@ export function LoginForm({
|
|||
{/* 로그인 버튼 */}
|
||||
<Button
|
||||
type="submit"
|
||||
className="h-11 w-full bg-slate-900 font-medium text-white hover:bg-slate-800"
|
||||
className="h-11 w-full font-medium"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
|
|
|
|||
|
|
@ -407,12 +407,12 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
return (
|
||||
<div key={menu.id}>
|
||||
<div
|
||||
className={`group flex h-10 cursor-pointer items-center justify-between rounded-lg px-3 py-2 text-sm font-medium transition-colors duration-200 ease-in-out ${
|
||||
className={`group flex h-10 cursor-pointer items-center justify-between rounded-lg px-3 py-2 text-sm font-medium transition-colors duration-150 ease-in-out ${
|
||||
pathname === menu.url
|
||||
? "border-primary border-l-4 bg-gradient-to-br from-slate-100 to-blue-100/40 text-slate-900"
|
||||
? "bg-primary/10 text-primary font-semibold"
|
||||
: isExpanded
|
||||
? "bg-slate-100 text-slate-900"
|
||||
: "text-slate-600 hover:bg-slate-50 hover:text-slate-900"
|
||||
? "bg-accent text-foreground"
|
||||
: "text-muted-foreground hover:bg-accent hover:text-foreground"
|
||||
} ${level > 0 ? "ml-6" : ""}`}
|
||||
onClick={() => handleMenuClick(menu)}
|
||||
>
|
||||
|
|
@ -431,14 +431,14 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
|
||||
{/* 서브메뉴 */}
|
||||
{menu.hasChildren && isExpanded && (
|
||||
<div className="mt-1 space-y-1 pl-6">
|
||||
<div className="mt-0.5 space-y-0.5 pl-9">
|
||||
{menu.children?.map((child: any) => (
|
||||
<div
|
||||
key={child.id}
|
||||
className={`flex cursor-pointer items-center rounded-lg px-3 py-2 text-sm transition-colors hover:cursor-pointer ${
|
||||
className={`flex cursor-pointer items-center rounded-lg px-3 py-2 text-sm transition-colors duration-150 hover:cursor-pointer ${
|
||||
pathname === child.url
|
||||
? "border-primary border-l-4 bg-gradient-to-br from-slate-100 to-blue-100/40 text-slate-900"
|
||||
: "text-slate-600 hover:bg-slate-50 hover:text-slate-900"
|
||||
? "bg-primary/10 text-primary font-semibold"
|
||||
: "text-muted-foreground hover:bg-accent hover:text-foreground"
|
||||
}`}
|
||||
onClick={() => handleMenuClick(child)}
|
||||
>
|
||||
|
|
@ -459,7 +459,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
// 프리뷰 모드: 사이드바/헤더 없이 화면만 표시 (인증 대기 없이 즉시 렌더링)
|
||||
if (isPreviewMode) {
|
||||
return (
|
||||
<div className="h-screen w-full overflow-auto bg-white p-4">
|
||||
<div className="h-screen w-full overflow-auto bg-background p-4">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
|
@ -481,10 +481,10 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
const uiMenus = convertMenuToUI(currentMenus, user as ExtendedUserInfo);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen flex-col bg-white">
|
||||
<div className="flex h-screen flex-col bg-background">
|
||||
{/* 모바일 헤더 - 모바일에서만 표시 */}
|
||||
{isMobile && (
|
||||
<header className="fixed top-0 left-0 right-0 z-50 flex h-14 items-center justify-between border-b border-slate-200 bg-white px-4">
|
||||
<header className="fixed top-0 left-0 right-0 z-50 flex h-14 items-center justify-between border-b border-border bg-background/95 backdrop-blur-sm px-4">
|
||||
<div className="flex items-center gap-3">
|
||||
{/* 햄버거 메뉴 버튼 */}
|
||||
<SideMenu onSidebarToggle={() => setSidebarOpen(!sidebarOpen)} />
|
||||
|
|
@ -493,7 +493,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
{/* 사용자 드롭다운 */}
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button className="flex items-center gap-2 rounded-lg px-2 py-1 transition-colors hover:bg-slate-100">
|
||||
<button className="flex items-center gap-2 rounded-lg px-2 py-1 transition-colors hover:bg-accent">
|
||||
<div className="relative flex h-8 w-8 shrink-0 overflow-hidden rounded-full">
|
||||
{user.photo && user.photo.trim() !== "" && user.photo !== "null" ? (
|
||||
<img
|
||||
|
|
@ -502,7 +502,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
className="aspect-square h-full w-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-full w-full items-center justify-center rounded-full bg-slate-200 text-sm font-semibold text-slate-700">
|
||||
<div className="flex h-full w-full items-center justify-center rounded-full bg-muted text-sm font-semibold text-foreground">
|
||||
{user.userName?.substring(0, 1)?.toUpperCase() || "U"}
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -543,7 +543,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
<div className={`flex flex-1 ${isMobile ? "pt-14" : ""}`}>
|
||||
{/* 모바일 사이드바 오버레이 */}
|
||||
{sidebarOpen && isMobile && (
|
||||
<div className="fixed inset-0 z-30 bg-black/50 lg:hidden" onClick={() => setSidebarOpen(false)} />
|
||||
<div className="fixed inset-0 z-30 bg-black/40 backdrop-blur-sm lg:hidden" onClick={() => setSidebarOpen(false)} />
|
||||
)}
|
||||
|
||||
{/* 왼쪽 사이드바 */}
|
||||
|
|
@ -552,11 +552,11 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
isMobile
|
||||
? (sidebarOpen ? "translate-x-0" : "-translate-x-full") + " fixed top-14 left-0 z-40 h-[calc(100vh-56px)]"
|
||||
: "relative z-auto h-screen translate-x-0"
|
||||
} flex w-[200px] flex-col border-r border-slate-200 bg-white transition-transform duration-300`}
|
||||
} flex w-[220px] lg:w-[240px] flex-col border-r border-border bg-background transition-transform duration-300`}
|
||||
>
|
||||
{/* 사이드바 최상단 - 로고 (데스크톱에서만 표시) */}
|
||||
{!isMobile && (
|
||||
<div className="flex h-14 items-center justify-between border-b border-slate-200 px-4">
|
||||
<div className="flex h-14 items-center justify-between border-b border-border px-4">
|
||||
<Logo />
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -580,14 +580,14 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
{((user as ExtendedUserInfo)?.userType === "SUPER_ADMIN" ||
|
||||
(user as ExtendedUserInfo)?.userType === "COMPANY_ADMIN" ||
|
||||
(user as ExtendedUserInfo)?.userType === "admin") && (
|
||||
<div className="space-y-2 border-b border-slate-200 p-3">
|
||||
<div className="space-y-2 border-b border-border p-3">
|
||||
{/* 관리자/사용자 메뉴 전환 */}
|
||||
<Button
|
||||
onClick={handleModeSwitch}
|
||||
className={`flex w-full items-center justify-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-colors duration-200 hover:cursor-pointer ${
|
||||
className={`flex w-full items-center justify-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-colors duration-150 hover:cursor-pointer ${
|
||||
isAdminMode
|
||||
? "border border-orange-200 bg-orange-50 text-orange-700 hover:bg-orange-100"
|
||||
: "border-primary/20 bg-accent hover:bg-primary/20 border text-blue-700"
|
||||
? "border border-warning/20 bg-warning/10 text-warning hover:bg-warning/20"
|
||||
: "border border-primary/20 bg-primary/10 text-primary hover:bg-primary/20"
|
||||
}`}
|
||||
>
|
||||
{isAdminMode ? (
|
||||
|
|
@ -607,7 +607,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
{(user as ExtendedUserInfo)?.userType === "SUPER_ADMIN" && (
|
||||
<Button
|
||||
onClick={() => { console.log("🔴 회사 선택 버튼 클릭!"); setShowCompanySwitcher(true); }}
|
||||
className="flex w-full items-center justify-center gap-2 rounded-lg border border-purple-200 bg-purple-50 px-3 py-2 text-sm font-medium text-purple-700 transition-colors duration-200 hover:cursor-pointer hover:bg-purple-100"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-lg border border-primary/20 bg-primary/10 px-3 py-2 text-sm font-medium text-primary transition-colors duration-150 hover:cursor-pointer hover:bg-primary/20"
|
||||
>
|
||||
<Building2 className="h-4 w-4" />
|
||||
회사 선택
|
||||
|
|
@ -618,11 +618,11 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
|
||||
{/* 메뉴 영역 */}
|
||||
<div className="flex-1 overflow-y-auto py-4">
|
||||
<nav className="space-y-1 px-3">
|
||||
<nav className="space-y-0.5 px-3">
|
||||
{loading ? (
|
||||
<div className="animate-pulse space-y-2">
|
||||
{[...Array(5)].map((_, i) => (
|
||||
<div key={i} className="h-8 rounded bg-slate-200"></div>
|
||||
<div key={i} className="h-8 rounded bg-muted"></div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -632,10 +632,10 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
</div>
|
||||
|
||||
{/* 사이드바 하단 - 사용자 프로필 */}
|
||||
<div className="border-t border-slate-200 p-3">
|
||||
<div className="border-t border-border bg-muted/30 p-3">
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button className="flex w-full items-center gap-3 rounded-lg px-2 py-2 text-left transition-colors hover:bg-slate-100">
|
||||
<button className="flex w-full items-center gap-3 rounded-lg px-2 py-2 text-left transition-colors hover:bg-accent">
|
||||
{/* 프로필 아바타 */}
|
||||
<div className="relative flex h-9 w-9 shrink-0 overflow-hidden rounded-full">
|
||||
{user.photo && user.photo.trim() !== "" && user.photo !== "null" ? (
|
||||
|
|
@ -645,17 +645,17 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
className="aspect-square h-full w-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-full w-full items-center justify-center rounded-full bg-slate-200 text-sm font-semibold text-slate-700">
|
||||
<div className="flex h-full w-full items-center justify-center rounded-full bg-muted text-sm font-semibold text-foreground">
|
||||
{user.userName?.substring(0, 1)?.toUpperCase() || "U"}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* 사용자 정보 */}
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate text-sm font-medium text-slate-900">
|
||||
<p className="truncate text-sm font-medium text-foreground">
|
||||
{user.userName || "사용자"}
|
||||
</p>
|
||||
<p className="truncate text-xs text-slate-500">
|
||||
<p className="truncate text-xs text-muted-foreground">
|
||||
{user.deptName || user.email || user.userId}
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -673,7 +673,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
className="aspect-square h-full w-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-full w-full items-center justify-center rounded-full bg-slate-200 text-base font-semibold text-slate-700">
|
||||
<div className="flex h-full w-full items-center justify-center rounded-full bg-muted text-base font-semibold text-foreground">
|
||||
{user.userName?.substring(0, 1)?.toUpperCase() || "U"}
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -713,7 +713,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|||
</aside>
|
||||
|
||||
{/* 가운데 컨텐츠 영역 - 스크롤 가능 */}
|
||||
<main className={`min-w-0 flex-1 overflow-auto bg-white ${isMobile ? "h-[calc(100vh-56px)]" : "h-screen"}`}>
|
||||
<main className={`min-w-0 flex-1 overflow-auto bg-background ${isMobile ? "h-[calc(100vh-56px)]" : "h-screen"}`}>
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
cd /Users/gbpark/ERP-node
|
||||
./node_modules/.bin/playwright test ".agent-pipeline/browser-tests/e2e-test.spec.ts" --config=".agent-pipeline/browser-tests/playwright.config.ts" --reporter=line 2>&1 | tee /tmp/playwright-result.txt
|
||||
echo "EXIT_CODE: $?" >> /tmp/playwright-result.txt
|
||||
Loading…
Reference in New Issue