forked from baron/baron-sso
개발자 권한 신청 테이블 공통 스타일 적용
This commit is contained in:
@@ -27,6 +27,10 @@ import {
|
|||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "../../components/ui/table";
|
} from "../../components/ui/table";
|
||||||
|
import {
|
||||||
|
commonTableShellClass,
|
||||||
|
commonTableViewportClass,
|
||||||
|
} from "../../../../common/ui/table";
|
||||||
import { Textarea } from "../../components/ui/textarea";
|
import { Textarea } from "../../components/ui/textarea";
|
||||||
import {
|
import {
|
||||||
approveDeveloperRequest,
|
approveDeveloperRequest,
|
||||||
@@ -185,158 +189,162 @@ export default function DeveloperRequestPage() {
|
|||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Table>
|
<div className={commonTableShellClass}>
|
||||||
<TableHeader>
|
<div className={commonTableViewportClass}>
|
||||||
<TableRow>
|
<Table>
|
||||||
{isSuperAdmin && (
|
<TableHeader className="sticky top-0 z-10 bg-secondary shadow-sm">
|
||||||
<TableHead>
|
<TableRow>
|
||||||
{t("ui.dev.request.table.user", "사용자")}
|
|
||||||
</TableHead>
|
|
||||||
)}
|
|
||||||
<TableHead>{t("ui.dev.request.table.org", "소속")}</TableHead>
|
|
||||||
<TableHead>
|
|
||||||
{t("ui.dev.request.table.reason", "신청 사유")}
|
|
||||||
</TableHead>
|
|
||||||
<TableHead>
|
|
||||||
{t("ui.dev.request.table.status", "상태")}
|
|
||||||
</TableHead>
|
|
||||||
<TableHead>
|
|
||||||
{t("ui.dev.request.table.date", "신청일")}
|
|
||||||
</TableHead>
|
|
||||||
{isSuperAdmin && (
|
|
||||||
<TableHead className="text-right">
|
|
||||||
{t("ui.dev.request.table.actions", "관리")}
|
|
||||||
</TableHead>
|
|
||||||
)}
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{!requests || requests.length === 0 ? (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell
|
|
||||||
colSpan={isSuperAdmin ? 6 : 4}
|
|
||||||
className="h-32 text-center text-muted-foreground"
|
|
||||||
>
|
|
||||||
{t("msg.dev.request.empty", "신청 내역이 없습니다.")}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
) : (
|
|
||||||
requests.map((req) => (
|
|
||||||
<TableRow key={req.id}>
|
|
||||||
{isSuperAdmin && (
|
{isSuperAdmin && (
|
||||||
<TableCell className="font-medium">
|
<TableHead>
|
||||||
<div>{req.name}</div>
|
{t("ui.dev.request.table.user", "사용자")}
|
||||||
<div className="text-xs text-muted-foreground">
|
</TableHead>
|
||||||
{req.email || req.userId}
|
|
||||||
</div>
|
|
||||||
{(req.phone || req.role) && (
|
|
||||||
<div className="mt-1 text-xs text-muted-foreground">
|
|
||||||
{[req.phone, req.role].filter(Boolean).join(" / ")}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
)}
|
)}
|
||||||
<TableCell>{req.organization}</TableCell>
|
<TableHead>{t("ui.dev.request.table.org", "소속")}</TableHead>
|
||||||
<TableCell className="max-w-md">
|
<TableHead>
|
||||||
<div className="truncate" title={req.reason}>
|
{t("ui.dev.request.table.reason", "신청 사유")}
|
||||||
{req.reason}
|
</TableHead>
|
||||||
</div>
|
<TableHead>
|
||||||
{req.adminNotes && (
|
{t("ui.dev.request.table.status", "상태")}
|
||||||
<div className="mt-1 text-xs text-amber-600 bg-amber-50 dark:bg-amber-900/20 p-1.5 rounded">
|
</TableHead>
|
||||||
<strong>Admin:</strong> {req.adminNotes}
|
<TableHead>
|
||||||
</div>
|
{t("ui.dev.request.table.date", "신청일")}
|
||||||
)}
|
</TableHead>
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<StatusBadge status={req.status} />
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-muted-foreground text-sm">
|
|
||||||
{new Date(req.createdAt).toLocaleDateString()}
|
|
||||||
</TableCell>
|
|
||||||
{isSuperAdmin && (
|
{isSuperAdmin && (
|
||||||
<TableCell className="text-right">
|
<TableHead className="text-right">
|
||||||
{req.status === "pending" ? (
|
{t("ui.dev.request.table.actions", "관리")}
|
||||||
<div className="flex flex-col gap-2 min-w-[200px] items-end ml-auto">
|
</TableHead>
|
||||||
<Input
|
|
||||||
placeholder={t(
|
|
||||||
"ui.dev.request.admin_notes_placeholder",
|
|
||||||
"메모 입력 (선택)...",
|
|
||||||
)}
|
|
||||||
className="h-8 text-xs"
|
|
||||||
value={adminNotes[req.id] || ""}
|
|
||||||
onChange={(e) =>
|
|
||||||
setAdminNotes({
|
|
||||||
...adminNotes,
|
|
||||||
[req.id]: e.target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
className="text-destructive hover:bg-destructive/10"
|
|
||||||
onClick={() => handleReject(req.id)}
|
|
||||||
disabled={isActionPending}
|
|
||||||
>
|
|
||||||
<XCircle className="mr-1 h-3 w-3" />
|
|
||||||
{t("ui.common.reject", "반려")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
className="bg-emerald-600 hover:bg-emerald-700"
|
|
||||||
onClick={() => handleApprove(req.id)}
|
|
||||||
disabled={isActionPending}
|
|
||||||
>
|
|
||||||
<CheckCircle2 className="mr-1 h-3 w-3" />
|
|
||||||
{t("ui.common.approve", "승인")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : req.status === "approved" ? (
|
|
||||||
<div className="flex flex-col gap-2 min-w-[200px] items-end ml-auto">
|
|
||||||
<Input
|
|
||||||
placeholder={t(
|
|
||||||
"ui.dev.request.cancel_notes_placeholder",
|
|
||||||
"승인 취소 사유 입력...",
|
|
||||||
)}
|
|
||||||
className="h-8 text-xs"
|
|
||||||
value={adminNotes[req.id] || ""}
|
|
||||||
onChange={(e) =>
|
|
||||||
setAdminNotes({
|
|
||||||
...adminNotes,
|
|
||||||
[req.id]: e.target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
className="text-destructive hover:bg-destructive/10"
|
|
||||||
onClick={() => handleCancelApproval(req.id)}
|
|
||||||
disabled={isActionPending}
|
|
||||||
>
|
|
||||||
<XCircle className="mr-1 h-3 w-3" />
|
|
||||||
{t("ui.dev.request.cancel_approval", "승인 취소")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<span className="text-muted-foreground text-xs italic">
|
|
||||||
{req.status === "cancelled"
|
|
||||||
? t(
|
|
||||||
"ui.dev.request.status.cancelled",
|
|
||||||
"승인 취소됨",
|
|
||||||
)
|
|
||||||
: t("ui.common.rejected", "반려됨")}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
)}
|
)}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
</TableHeader>
|
||||||
)}
|
<TableBody>
|
||||||
</TableBody>
|
{!requests || requests.length === 0 ? (
|
||||||
</Table>
|
<TableRow>
|
||||||
|
<TableCell
|
||||||
|
colSpan={isSuperAdmin ? 6 : 4}
|
||||||
|
className="h-32 text-center text-muted-foreground"
|
||||||
|
>
|
||||||
|
{t("msg.dev.request.empty", "신청 내역이 없습니다.")}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : (
|
||||||
|
requests.map((req) => (
|
||||||
|
<TableRow key={req.id}>
|
||||||
|
{isSuperAdmin && (
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
<div>{req.name}</div>
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
{req.email || req.userId}
|
||||||
|
</div>
|
||||||
|
{(req.phone || req.role) && (
|
||||||
|
<div className="mt-1 text-xs text-muted-foreground">
|
||||||
|
{[req.phone, req.role].filter(Boolean).join(" / ")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
)}
|
||||||
|
<TableCell>{req.organization}</TableCell>
|
||||||
|
<TableCell className="max-w-md">
|
||||||
|
<div className="truncate" title={req.reason}>
|
||||||
|
{req.reason}
|
||||||
|
</div>
|
||||||
|
{req.adminNotes && (
|
||||||
|
<div className="mt-1 rounded bg-amber-50 p-1.5 text-xs text-amber-600 dark:bg-amber-900/20">
|
||||||
|
<strong>Admin:</strong> {req.adminNotes}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<StatusBadge status={req.status} />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-sm text-muted-foreground">
|
||||||
|
{new Date(req.createdAt).toLocaleDateString()}
|
||||||
|
</TableCell>
|
||||||
|
{isSuperAdmin && (
|
||||||
|
<TableCell className="text-right">
|
||||||
|
{req.status === "pending" ? (
|
||||||
|
<div className="ml-auto flex min-w-[200px] flex-col items-end gap-2">
|
||||||
|
<Input
|
||||||
|
placeholder={t(
|
||||||
|
"ui.dev.request.admin_notes_placeholder",
|
||||||
|
"메모 입력 (선택)...",
|
||||||
|
)}
|
||||||
|
className="h-8 text-xs"
|
||||||
|
value={adminNotes[req.id] || ""}
|
||||||
|
onChange={(e) =>
|
||||||
|
setAdminNotes({
|
||||||
|
...adminNotes,
|
||||||
|
[req.id]: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="text-destructive hover:bg-destructive/10"
|
||||||
|
onClick={() => handleReject(req.id)}
|
||||||
|
disabled={isActionPending}
|
||||||
|
>
|
||||||
|
<XCircle className="mr-1 h-3 w-3" />
|
||||||
|
{t("ui.common.reject", "반려")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
className="bg-emerald-600 hover:bg-emerald-700"
|
||||||
|
onClick={() => handleApprove(req.id)}
|
||||||
|
disabled={isActionPending}
|
||||||
|
>
|
||||||
|
<CheckCircle2 className="mr-1 h-3 w-3" />
|
||||||
|
{t("ui.common.approve", "승인")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : req.status === "approved" ? (
|
||||||
|
<div className="ml-auto flex min-w-[200px] flex-col items-end gap-2">
|
||||||
|
<Input
|
||||||
|
placeholder={t(
|
||||||
|
"ui.dev.request.cancel_notes_placeholder",
|
||||||
|
"승인 취소 사유 입력...",
|
||||||
|
)}
|
||||||
|
className="h-8 text-xs"
|
||||||
|
value={adminNotes[req.id] || ""}
|
||||||
|
onChange={(e) =>
|
||||||
|
setAdminNotes({
|
||||||
|
...adminNotes,
|
||||||
|
[req.id]: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="text-destructive hover:bg-destructive/10"
|
||||||
|
onClick={() => handleCancelApproval(req.id)}
|
||||||
|
disabled={isActionPending}
|
||||||
|
>
|
||||||
|
<XCircle className="mr-1 h-3 w-3" />
|
||||||
|
{t("ui.dev.request.cancel_approval", "승인 취소")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<span className="text-xs italic text-muted-foreground">
|
||||||
|
{req.status === "cancelled"
|
||||||
|
? t(
|
||||||
|
"ui.dev.request.status.cancelled",
|
||||||
|
"승인 취소됨",
|
||||||
|
)
|
||||||
|
: t("ui.common.rejected", "반려됨")}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
)}
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user