forked from baron/baron-sso
개발자 등록 신청 입력 안내 및 역할 표기 개선
This commit is contained in:
@@ -7,7 +7,7 @@ import {
|
||||
X,
|
||||
XCircle,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useAuth } from "react-oidc-context";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
import { Button } from "../../components/ui/button";
|
||||
@@ -32,11 +32,13 @@ import {
|
||||
approveDeveloperRequest,
|
||||
cancelDeveloperRequestApproval,
|
||||
fetchDeveloperRequests,
|
||||
fetchMyTenants,
|
||||
rejectDeveloperRequest,
|
||||
requestDeveloperAccess,
|
||||
} from "../../lib/devApi";
|
||||
import { t } from "../../lib/i18n";
|
||||
import { resolveProfileRole } from "../../lib/role";
|
||||
import { fetchMe } from "../auth/authApi";
|
||||
|
||||
export default function DeveloperRequestPage() {
|
||||
const auth = useAuth();
|
||||
@@ -45,6 +47,7 @@ export default function DeveloperRequestPage() {
|
||||
const role = resolveProfileRole(userProfile);
|
||||
const isSuperAdmin = role === "super_admin";
|
||||
const tenantId = userProfile?.tenant_id as string | undefined;
|
||||
const companyCode = userProfile?.companyCode as string | undefined;
|
||||
|
||||
const [isRequestModalOpen, setIsRequestModalOpen] = useState(false);
|
||||
const [adminNotes, setAdminNotes] = useState<Record<number, string>>({});
|
||||
@@ -54,6 +57,30 @@ export default function DeveloperRequestPage() {
|
||||
queryFn: () => fetchDeveloperRequests(),
|
||||
enabled: !!auth.user?.access_token,
|
||||
});
|
||||
const { data: tenants } = useQuery({
|
||||
queryKey: ["myTenants"],
|
||||
queryFn: fetchMyTenants,
|
||||
enabled: !!auth.user?.access_token,
|
||||
});
|
||||
const { data: me } = useQuery({
|
||||
queryKey: ["userMe"],
|
||||
queryFn: fetchMe,
|
||||
enabled: !!auth.user?.access_token,
|
||||
});
|
||||
|
||||
const currentTenant = tenants?.find(
|
||||
(tenant) => tenant.id === tenantId || tenant.slug === companyCode,
|
||||
);
|
||||
const organizationName = currentTenant?.name || companyCode || "";
|
||||
const profileName = me?.name || (userProfile?.name as string) || "";
|
||||
const profileEmail = me?.email || (userProfile?.email as string) || "";
|
||||
const profilePhone =
|
||||
me?.phone ||
|
||||
(userProfile?.phone as string | undefined) ||
|
||||
(userProfile?.phone_number as string | undefined) ||
|
||||
"";
|
||||
const profileRole = me?.role || role;
|
||||
const profileRoleLabel = t(`ui.admin.role.${profileRole}`, profileRole);
|
||||
|
||||
const approveMutation = useMutation({
|
||||
mutationFn: ({ id, adminNotes }: { id: number; adminNotes: string }) =>
|
||||
@@ -189,8 +216,13 @@ export default function DeveloperRequestPage() {
|
||||
<TableCell className="font-medium">
|
||||
<div>{req.name}</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{req.userId}
|
||||
{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>
|
||||
@@ -302,8 +334,11 @@ export default function DeveloperRequestPage() {
|
||||
setIsRequestModalOpen(false);
|
||||
}}
|
||||
tenantId={tenantId || ""}
|
||||
initialName={(userProfile?.name as string) || ""}
|
||||
initialOrg={(userProfile?.companyCode as string) || ""}
|
||||
initialName={profileName}
|
||||
initialOrg={organizationName}
|
||||
initialEmail={profileEmail}
|
||||
initialPhone={profilePhone}
|
||||
initialRole={profileRoleLabel}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -352,6 +387,9 @@ interface RequestAccessModalProps {
|
||||
tenantId: string;
|
||||
initialName: string;
|
||||
initialOrg: string;
|
||||
initialEmail: string;
|
||||
initialPhone: string;
|
||||
initialRole: string;
|
||||
}
|
||||
|
||||
function RequestAccessModal({
|
||||
@@ -361,11 +399,20 @@ function RequestAccessModal({
|
||||
tenantId,
|
||||
initialName,
|
||||
initialOrg,
|
||||
initialEmail,
|
||||
initialPhone,
|
||||
initialRole,
|
||||
}: RequestAccessModalProps) {
|
||||
const [name, setName] = useState(initialName);
|
||||
const [organization, setOrganization] = useState(initialOrg);
|
||||
const [reason, setReason] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
setName(initialName);
|
||||
setOrganization(initialOrg);
|
||||
}, [initialName, initialOrg, isOpen]);
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: requestDeveloperAccess,
|
||||
onSuccess: () => {
|
||||
@@ -419,7 +466,8 @@ function RequestAccessModal({
|
||||
<Input
|
||||
id="name"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
readOnly
|
||||
className="focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-input"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
@@ -430,13 +478,50 @@ function RequestAccessModal({
|
||||
<Input
|
||||
id="org"
|
||||
value={organization}
|
||||
onChange={(e) => setOrganization(e.target.value)}
|
||||
readOnly
|
||||
className="focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-input"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">
|
||||
{t("ui.dev.request.modal.email", "이메일")}
|
||||
</Label>
|
||||
<Input
|
||||
id="email"
|
||||
value={initialEmail}
|
||||
readOnly
|
||||
className="focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="phone">
|
||||
{t("ui.dev.request.modal.phone", "전화번호")}
|
||||
</Label>
|
||||
<Input
|
||||
id="phone"
|
||||
value={initialPhone}
|
||||
readOnly
|
||||
className="focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="role">
|
||||
{t("ui.dev.request.modal.role", "역할")}
|
||||
</Label>
|
||||
<Input
|
||||
id="role"
|
||||
value={initialRole}
|
||||
readOnly
|
||||
className="focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:border-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="reason">
|
||||
{t("ui.dev.request.modal.reason", "신청 사유")}
|
||||
{t("ui.dev.request.modal.reason", "신청 사유")}{" "}
|
||||
<span className="text-destructive">*</span>
|
||||
</Label>
|
||||
<Textarea
|
||||
id="reason"
|
||||
@@ -446,7 +531,7 @@ function RequestAccessModal({
|
||||
"ui.dev.request.modal.reason_placeholder",
|
||||
"예: 자체 서비스 연동 및 테스트용 OIDC 클라이언트 생성이 필요합니다.",
|
||||
)}
|
||||
className="min-h-[120px] resize-none"
|
||||
className="min-h-[120px] resize-none border-primary/50 bg-background focus-visible:ring-primary/40"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user