forked from baron/baron-sso
프론트엔드 UI/UX를 전면 개편
This commit is contained in:
@@ -3,6 +3,7 @@ import type { AxiosError } from "axios";
|
||||
import { Plus, Save, Trash2 } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "../../../components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
@@ -39,7 +40,9 @@ export function TenantSchemaPage() {
|
||||
|
||||
if (!tenantId) {
|
||||
return (
|
||||
<div>{t("msg.admin.tenants.schema.missing_id", "Tenant ID missing")}</div>
|
||||
<div className="p-8 text-center text-muted-foreground">
|
||||
{t("msg.admin.tenants.schema.missing_id", "테넌트 ID가 없습니다.")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -78,18 +81,10 @@ export function TenantSchemaPage() {
|
||||
}),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["tenant", tenantId] });
|
||||
alert(
|
||||
t(
|
||||
"msg.admin.tenants.schema.update_success",
|
||||
"Schema updated successfully",
|
||||
),
|
||||
);
|
||||
toast.success(t("msg.admin.tenants.schema.update_success", "스키마가 저장되었습니다."));
|
||||
},
|
||||
onError: (err: AxiosError<{ error?: string }>) => {
|
||||
alert(
|
||||
err.response?.data?.error ||
|
||||
t("msg.admin.tenants.schema.update_error", "Failed to update schema"),
|
||||
);
|
||||
toast.error(err.response?.data?.error || t("msg.admin.tenants.schema.update_error", "저장에 실패했습니다."));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -118,56 +113,57 @@ export function TenantSchemaPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-6 mt-6">
|
||||
<Card>
|
||||
<Card className="border-none shadow-sm bg-[var(--color-panel)]">
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<CardTitle>
|
||||
{t("ui.admin.tenants.schema.title", "User Schema Extension")}
|
||||
<div className="space-y-1">
|
||||
<CardTitle className="text-2xl font-bold">
|
||||
{t("ui.admin.tenants.schema.title", "사용자 스키마 확장")}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
{t(
|
||||
"msg.admin.tenants.schema.subtitle",
|
||||
"Define custom attributes for users in this tenant.",
|
||||
"이 테넌트 사용자를 위한 커스텀 속성을 정의합니다.",
|
||||
)}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Button onClick={addField} size="sm">
|
||||
<Plus size={16} className="mr-2" />
|
||||
{t("ui.admin.tenants.schema.add_field", "Add Field")}
|
||||
{t("ui.admin.tenants.schema.add_field", "필드 추가")}
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{fields.length === 0 && (
|
||||
<div className="py-8 text-center text-muted-foreground border border-dashed rounded-md">
|
||||
<div className="py-12 text-center text-muted-foreground border border-dashed rounded-lg bg-muted/10">
|
||||
{t(
|
||||
"msg.admin.tenants.schema.empty",
|
||||
'No custom fields defined. Click "Add Field" to begin.',
|
||||
'정의된 커스텀 필드가 없습니다. "필드 추가"를 눌러 시작하세요.',
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{fields.map((field, index) => (
|
||||
<div
|
||||
key={field.id}
|
||||
className="flex items-end gap-4 p-4 border rounded-md bg-muted/30"
|
||||
className="flex items-end gap-4 p-5 border border-border rounded-xl bg-muted/20 hover:bg-muted/30 transition-colors"
|
||||
>
|
||||
<div className="flex-1 space-y-2">
|
||||
<Label>
|
||||
{t("ui.admin.tenants.schema.field.key", "Field Key (ID)")}
|
||||
<Label className="text-xs font-bold uppercase tracking-wider text-muted-foreground">
|
||||
{t("ui.admin.tenants.schema.field.key", "필드 키 (ID)")}
|
||||
</Label>
|
||||
<Input
|
||||
value={field.key}
|
||||
onChange={(e) => updateField(index, { key: e.target.value })}
|
||||
placeholder={t(
|
||||
"ui.admin.tenants.schema.field.key_placeholder",
|
||||
"e.g. employee_id",
|
||||
"예: employee_id",
|
||||
)}
|
||||
className="h-10"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 space-y-2">
|
||||
<Label>
|
||||
{t("ui.admin.tenants.schema.field.label", "Display Label")}
|
||||
<Label className="text-xs font-bold uppercase tracking-wider text-muted-foreground">
|
||||
{t("ui.admin.tenants.schema.field.label", "표시 라벨")}
|
||||
</Label>
|
||||
<Input
|
||||
value={field.label}
|
||||
@@ -176,14 +172,17 @@ export function TenantSchemaPage() {
|
||||
}
|
||||
placeholder={t(
|
||||
"ui.admin.tenants.schema.field.label_placeholder",
|
||||
"e.g. 사번",
|
||||
"예: 사번",
|
||||
)}
|
||||
className="h-10"
|
||||
/>
|
||||
</div>
|
||||
<div className="w-32 space-y-2">
|
||||
<Label>{t("ui.admin.tenants.schema.field.type", "Type")}</Label>
|
||||
<div className="w-40 space-y-2">
|
||||
<Label className="text-xs font-bold uppercase tracking-wider text-muted-foreground">
|
||||
{t("ui.admin.tenants.schema.field.type", "유형")}
|
||||
</Label>
|
||||
<select
|
||||
className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm"
|
||||
className="flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus:ring-1 focus:ring-primary"
|
||||
value={field.type}
|
||||
onChange={(e) => {
|
||||
const nextType = e.target.value;
|
||||
@@ -197,36 +196,37 @@ export function TenantSchemaPage() {
|
||||
}}
|
||||
>
|
||||
<option value="text">
|
||||
{t("ui.admin.tenants.schema.field.type_text", "Text")}
|
||||
{t("ui.admin.tenants.schema.field.type_text", "텍스트 (Text)")}
|
||||
</option>
|
||||
<option value="number">
|
||||
{t("ui.admin.tenants.schema.field.type_number", "Number")}
|
||||
{t("ui.admin.tenants.schema.field.type_number", "숫자 (Number)")}
|
||||
</option>
|
||||
<option value="boolean">
|
||||
{t("ui.admin.tenants.schema.field.type_boolean", "Boolean")}
|
||||
{t("ui.admin.tenants.schema.field.type_boolean", "불리언 (Boolean)")}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="text-destructive"
|
||||
className="text-destructive hover:bg-destructive/10 h-10 w-10"
|
||||
onClick={() => removeField(index)}
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
<Trash2 size={18} />
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<div className="flex justify-end pt-2">
|
||||
<Button
|
||||
onClick={() => updateMutation.mutate(fields)}
|
||||
disabled={updateMutation.isPending || tenantQuery.isLoading}
|
||||
className="px-8 h-11"
|
||||
>
|
||||
<Save size={16} className="mr-2" />
|
||||
{t("ui.admin.tenants.schema.save", "Save Schema Changes")}
|
||||
<Save size={18} className="mr-2" />
|
||||
{t("ui.admin.tenants.schema.save", "변경사항 저장")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user