저장버튼 제어기능 (insert)
This commit is contained in:
@@ -11,6 +11,7 @@ import { Check, ChevronsUpDown, Search } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ComponentData } from "@/types/screen";
|
||||
import { apiClient } from "@/lib/api/client";
|
||||
import { ButtonDataflowConfigPanel } from "./ButtonDataflowConfigPanel";
|
||||
|
||||
interface ButtonConfigPanelProps {
|
||||
component: ComponentData;
|
||||
@@ -66,7 +67,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
|
||||
return screens.filter(
|
||||
(screen) =>
|
||||
screen.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
(screen.description && screen.description.toLowerCase().includes(searchTerm.toLowerCase()))
|
||||
(screen.description && screen.description.toLowerCase().includes(searchTerm.toLowerCase())),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -205,7 +206,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={modalScreenOpen}
|
||||
className="w-full justify-between h-10"
|
||||
className="h-10 w-full justify-between"
|
||||
disabled={screensLoading}
|
||||
>
|
||||
{config.action?.targetScreenId
|
||||
@@ -215,7 +216,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0" align="start" style={{ width: 'var(--radix-popover-trigger-width)' }}>
|
||||
<PopoverContent className="p-0" align="start" style={{ width: "var(--radix-popover-trigger-width)" }}>
|
||||
<div className="flex flex-col">
|
||||
{/* 검색 입력 */}
|
||||
<div className="flex items-center border-b px-3 py-2">
|
||||
@@ -284,7 +285,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={navScreenOpen}
|
||||
className="w-full justify-between h-10"
|
||||
className="h-10 w-full justify-between"
|
||||
disabled={screensLoading}
|
||||
>
|
||||
{config.action?.targetScreenId
|
||||
@@ -294,7 +295,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0" align="start" style={{ width: 'var(--radix-popover-trigger-width)' }}>
|
||||
<PopoverContent className="p-0" align="start" style={{ width: "var(--radix-popover-trigger-width)" }}>
|
||||
<div className="flex flex-col">
|
||||
{/* 검색 입력 */}
|
||||
<div className="flex items-center border-b px-3 py-2">
|
||||
@@ -369,57 +370,15 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({ component,
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 확인 메시지 설정 (모든 액션 공통) */}
|
||||
{config.action?.type && config.action.type !== "cancel" && config.action.type !== "close" && (
|
||||
<div className="mt-4 space-y-4 rounded-lg border bg-blue-50 p-4">
|
||||
<h4 className="text-sm font-medium text-gray-700">확인 메시지 설정</h4>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="confirm-message">실행 전 확인 메시지</Label>
|
||||
<Input
|
||||
id="confirm-message"
|
||||
placeholder="예: 정말 저장하시겠습니까?"
|
||||
value={config.action?.confirmMessage || ""}
|
||||
onChange={(e) =>
|
||||
onUpdateProperty("componentConfig.action", {
|
||||
...config.action,
|
||||
confirmMessage: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="success-message">성공 메시지</Label>
|
||||
<Input
|
||||
id="success-message"
|
||||
placeholder="예: 저장되었습니다."
|
||||
value={config.action?.successMessage || ""}
|
||||
onChange={(e) =>
|
||||
onUpdateProperty("componentConfig.action", {
|
||||
...config.action,
|
||||
successMessage: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="error-message">오류 메시지</Label>
|
||||
<Input
|
||||
id="error-message"
|
||||
placeholder="예: 저장 중 오류가 발생했습니다."
|
||||
value={config.action?.errorMessage || ""}
|
||||
onChange={(e) =>
|
||||
onUpdateProperty("componentConfig.action", {
|
||||
...config.action,
|
||||
errorMessage: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{/* 🔥 NEW: 제어관리 기능 섹션 */}
|
||||
<div className="mt-8 border-t border-gray-200 pt-6">
|
||||
<div className="mb-4">
|
||||
<h3 className="text-lg font-medium text-gray-900">🔧 고급 기능</h3>
|
||||
<p className="mt-1 text-sm text-gray-600">버튼 액션과 함께 실행될 추가 기능을 설정합니다</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ButtonDataflowConfigPanel component={component} onUpdateProperty={onUpdateProperty} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,435 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { Check, ChevronsUpDown, Search, Info, Settings } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ComponentData, ButtonDataflowConfig } from "@/types/screen";
|
||||
import { apiClient } from "@/lib/api/client";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
|
||||
interface ButtonDataflowConfigPanelProps {
|
||||
component: ComponentData;
|
||||
onUpdateProperty: (path: string, value: any) => void;
|
||||
}
|
||||
|
||||
interface DiagramOption {
|
||||
id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
relationshipCount: number;
|
||||
}
|
||||
|
||||
interface RelationshipOption {
|
||||
id: string;
|
||||
name: string;
|
||||
sourceTable: string;
|
||||
targetTable: string;
|
||||
category: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔥 버튼 제어관리 설정 패널 (Phase 1: 간편 모드만)
|
||||
*
|
||||
* 성능 최적화를 위해 간편 모드만 구현:
|
||||
* - 기존 관계도 선택
|
||||
* - "after" 타이밍만 지원
|
||||
* - 복잡한 고급 모드는 Phase 2에서
|
||||
*/
|
||||
export const ButtonDataflowConfigPanel: React.FC<ButtonDataflowConfigPanelProps> = ({
|
||||
component,
|
||||
onUpdateProperty,
|
||||
}) => {
|
||||
const config = component.webTypeConfig || {};
|
||||
const dataflowConfig = config.dataflowConfig || {};
|
||||
|
||||
// 🔥 State 관리
|
||||
const [diagrams, setDiagrams] = useState<DiagramOption[]>([]);
|
||||
const [relationships, setRelationships] = useState<RelationshipOption[]>([]);
|
||||
const [diagramsLoading, setDiagramsLoading] = useState(false);
|
||||
const [relationshipsLoading, setRelationshipsLoading] = useState(false);
|
||||
const [diagramOpen, setDiagramOpen] = useState(false);
|
||||
const [relationshipOpen, setRelationshipOpen] = useState(false);
|
||||
const [previewData, setPreviewData] = useState<any>(null);
|
||||
|
||||
// 🔥 관계도 목록 로딩
|
||||
useEffect(() => {
|
||||
if (config.enableDataflowControl) {
|
||||
loadDiagrams();
|
||||
}
|
||||
}, [config.enableDataflowControl]);
|
||||
|
||||
// 🔥 관계도 변경 시 관계 목록 로딩
|
||||
useEffect(() => {
|
||||
if (dataflowConfig.selectedDiagramId) {
|
||||
loadRelationships(dataflowConfig.selectedDiagramId);
|
||||
}
|
||||
}, [dataflowConfig.selectedDiagramId]);
|
||||
|
||||
/**
|
||||
* 🔥 관계도 목록 로딩 (캐시 활용)
|
||||
*/
|
||||
const loadDiagrams = async () => {
|
||||
try {
|
||||
setDiagramsLoading(true);
|
||||
console.log("🔍 데이터플로우 관계도 목록 로딩...");
|
||||
|
||||
const response = await apiClient.get("/test-button-dataflow/diagrams");
|
||||
|
||||
if (response.data.success && Array.isArray(response.data.data)) {
|
||||
const diagramList = response.data.data.map((diagram: any) => ({
|
||||
id: diagram.diagram_id,
|
||||
name: diagram.diagram_name,
|
||||
description: diagram.description,
|
||||
relationshipCount: diagram.relationships?.relationships?.length || 0,
|
||||
}));
|
||||
|
||||
setDiagrams(diagramList);
|
||||
console.log(`✅ 관계도 ${diagramList.length}개 로딩 완료`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ 관계도 목록 로딩 실패:", error);
|
||||
setDiagrams([]);
|
||||
} finally {
|
||||
setDiagramsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 🔥 관계 목록 로딩
|
||||
*/
|
||||
const loadRelationships = async (diagramId: number) => {
|
||||
try {
|
||||
setRelationshipsLoading(true);
|
||||
console.log(`🔍 관계도 ${diagramId} 관계 목록 로딩...`);
|
||||
|
||||
const response = await apiClient.get(`/test-button-dataflow/diagrams/${diagramId}/relationships`);
|
||||
|
||||
if (response.data.success && Array.isArray(response.data.data)) {
|
||||
const relationshipList = response.data.data.map((rel: any) => ({
|
||||
id: rel.id,
|
||||
name: rel.name || `${rel.sourceTable} → ${rel.targetTable}`,
|
||||
sourceTable: rel.sourceTable,
|
||||
targetTable: rel.targetTable,
|
||||
category: rel.category || "data-save",
|
||||
}));
|
||||
|
||||
setRelationships(relationshipList);
|
||||
console.log(`✅ 관계 ${relationshipList.length}개 로딩 완료`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ 관계 목록 로딩 실패:", error);
|
||||
setRelationships([]);
|
||||
} finally {
|
||||
setRelationshipsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 🔥 선택된 관계 미리보기 로딩
|
||||
*/
|
||||
const loadRelationshipPreview = async () => {
|
||||
if (!dataflowConfig.selectedDiagramId || !dataflowConfig.selectedRelationshipId) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await apiClient.get(
|
||||
`/test-button-dataflow/diagrams/${dataflowConfig.selectedDiagramId}/relationships/${dataflowConfig.selectedRelationshipId}/preview`,
|
||||
);
|
||||
|
||||
if (response.data.success) {
|
||||
setPreviewData(response.data.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ 관계 미리보기 로딩 실패:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 선택된 관계가 변경되면 미리보기 로딩
|
||||
useEffect(() => {
|
||||
if (dataflowConfig.selectedRelationshipId) {
|
||||
loadRelationshipPreview();
|
||||
}
|
||||
}, [dataflowConfig.selectedRelationshipId]);
|
||||
|
||||
/**
|
||||
* 현재 액션 타입별 표시명
|
||||
*/
|
||||
const getActionDisplayName = (actionType: string): string => {
|
||||
const displayNames: Record<string, string> = {
|
||||
save: "저장",
|
||||
delete: "삭제",
|
||||
edit: "수정",
|
||||
add: "추가",
|
||||
search: "검색",
|
||||
reset: "초기화",
|
||||
submit: "제출",
|
||||
close: "닫기",
|
||||
popup: "팝업",
|
||||
navigate: "페이지 이동",
|
||||
};
|
||||
return displayNames[actionType] || actionType;
|
||||
};
|
||||
|
||||
/**
|
||||
* 타이밍별 설명 (간소화)
|
||||
*/
|
||||
const getTimingDescription = (timing: string): string => {
|
||||
switch (timing) {
|
||||
case "before":
|
||||
return "액션 실행 전 제어관리";
|
||||
case "after":
|
||||
return "액션 실행 후 제어관리";
|
||||
case "replace":
|
||||
return "제어관리로 완전 대체";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
// 선택된 관계도 정보
|
||||
const selectedDiagram = diagrams.find((d) => d.id === dataflowConfig.selectedDiagramId);
|
||||
const selectedRelationship = relationships.find((r) => r.id === dataflowConfig.selectedRelationshipId);
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* 🔥 제어관리 활성화 스위치 */}
|
||||
<div className="flex items-center justify-between rounded-lg border bg-blue-50 p-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Settings className="h-4 w-4 text-blue-600" />
|
||||
<div>
|
||||
<Label className="text-sm font-medium">📊 제어관리 기능</Label>
|
||||
<p className="mt-1 text-xs text-gray-600">버튼 클릭 시 데이터 흐름을 자동으로 제어합니다</p>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={config.enableDataflowControl || false}
|
||||
onCheckedChange={(checked) => onUpdateProperty("webTypeConfig.enableDataflowControl", checked)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 🔥 제어관리가 활성화된 경우에만 설정 표시 */}
|
||||
{config.enableDataflowControl && (
|
||||
<div className="space-y-6 border-l-2 border-blue-200 pl-4">
|
||||
{/* 현재 액션 정보 (간소화) */}
|
||||
<div className="rounded bg-gray-100 p-2">
|
||||
<p className="text-xs text-gray-600">
|
||||
<strong>{getActionDisplayName(config.actionType || "save")}</strong> 액션에 제어관리 연결
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 실행 타이밍 선택 (Phase 1: after만 지원) */}
|
||||
<div>
|
||||
<Label className="text-sm font-medium">실행 타이밍</Label>
|
||||
<Select
|
||||
value={config.dataflowTiming || "after"}
|
||||
onValueChange={(value) => onUpdateProperty("webTypeConfig.dataflowTiming", value)}
|
||||
>
|
||||
<SelectTrigger className="mt-2">
|
||||
<SelectValue placeholder="실행 타이밍을 선택하세요" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="after">액션 실행 후 (권장)</SelectItem>
|
||||
<SelectItem value="before" disabled>
|
||||
액션 실행 전 (개발중)
|
||||
</SelectItem>
|
||||
<SelectItem value="replace" disabled>
|
||||
액션 대신 (개발중)
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* 제어 모드 선택 (Phase 1: simple만 지원) */}
|
||||
<div>
|
||||
<Label className="text-sm font-medium">제어 모드</Label>
|
||||
<Select
|
||||
value={dataflowConfig.controlMode || "simple"}
|
||||
onValueChange={(value) => onUpdateProperty("webTypeConfig.dataflowConfig.controlMode", value)}
|
||||
>
|
||||
<SelectTrigger className="mt-2">
|
||||
<SelectValue placeholder="제어 모드를 선택하세요" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="simple">간편 모드 (관계도 선택)</SelectItem>
|
||||
<SelectItem value="advanced" disabled>
|
||||
고급 모드 (개발중)
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* 간편 모드 설정 */}
|
||||
{(dataflowConfig.controlMode === "simple" || !dataflowConfig.controlMode) && (
|
||||
<div className="space-y-3 rounded border bg-gray-50 p-3">
|
||||
<h4 className="text-sm font-medium text-gray-700">관계도 선택</h4>
|
||||
|
||||
{/* 관계도 선택 */}
|
||||
<div>
|
||||
<Label className="text-xs">관계도</Label>
|
||||
<Popover open={diagramOpen} onOpenChange={setDiagramOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={diagramOpen}
|
||||
className="mt-2 w-full justify-between"
|
||||
disabled={diagramsLoading}
|
||||
>
|
||||
{selectedDiagram ? (
|
||||
<div className="flex items-center space-x-2">
|
||||
<span>{selectedDiagram.name}</span>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{selectedDiagram.relationshipCount}개 관계
|
||||
</Badge>
|
||||
</div>
|
||||
) : (
|
||||
"관계도를 선택하세요"
|
||||
)}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80 p-0">
|
||||
<div className="p-2">
|
||||
{diagramsLoading ? (
|
||||
<div className="p-4 text-center text-sm text-gray-500">관계도 목록을 불러오는 중...</div>
|
||||
) : diagrams.length === 0 ? (
|
||||
<div className="p-4 text-center text-sm text-gray-500">사용 가능한 관계도가 없습니다</div>
|
||||
) : (
|
||||
<div className="max-h-60 overflow-y-auto">
|
||||
{diagrams.map((diagram) => (
|
||||
<Button
|
||||
key={diagram.id}
|
||||
variant="ghost"
|
||||
className="h-auto w-full justify-start p-2"
|
||||
onClick={() => {
|
||||
onUpdateProperty("webTypeConfig.dataflowConfig.selectedDiagramId", diagram.id);
|
||||
// 관계도 변경 시 기존 관계 선택 초기화
|
||||
onUpdateProperty("webTypeConfig.dataflowConfig.selectedRelationshipId", null);
|
||||
setDiagramOpen(false);
|
||||
}}
|
||||
>
|
||||
<div className="flex w-full items-center space-x-2">
|
||||
<Check
|
||||
className={cn(
|
||||
"h-4 w-4",
|
||||
selectedDiagram?.id === diagram.id ? "opacity-100" : "opacity-0",
|
||||
)}
|
||||
/>
|
||||
<div className="flex-1 text-left">
|
||||
<div className="font-medium">{diagram.name}</div>
|
||||
<div className="text-xs text-gray-500">{diagram.relationshipCount}개 관계</div>
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
{/* 관계 선택 */}
|
||||
{dataflowConfig.selectedDiagramId && (
|
||||
<div>
|
||||
<Label className="text-xs">관계</Label>
|
||||
<Popover open={relationshipOpen} onOpenChange={setRelationshipOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={relationshipOpen}
|
||||
className="mt-2 w-full justify-between"
|
||||
disabled={relationshipsLoading}
|
||||
>
|
||||
{selectedRelationship ? (
|
||||
<div className="flex items-center space-x-2">
|
||||
<span>{selectedRelationship.name}</span>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{selectedRelationship.category}
|
||||
</Badge>
|
||||
</div>
|
||||
) : (
|
||||
"관계를 선택하세요"
|
||||
)}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-96 p-0">
|
||||
<div className="p-2">
|
||||
{relationshipsLoading ? (
|
||||
<div className="p-4 text-center text-sm text-gray-500">관계 목록을 불러오는 중...</div>
|
||||
) : relationships.length === 0 ? (
|
||||
<div className="p-4 text-center text-sm text-gray-500">
|
||||
이 관계도에는 사용 가능한 관계가 없습니다
|
||||
</div>
|
||||
) : (
|
||||
<div className="max-h-60 overflow-y-auto">
|
||||
{relationships.map((relationship) => (
|
||||
<Button
|
||||
key={relationship.id}
|
||||
variant="ghost"
|
||||
className="h-auto w-full justify-start p-2"
|
||||
onClick={() => {
|
||||
onUpdateProperty(
|
||||
"webTypeConfig.dataflowConfig.selectedRelationshipId",
|
||||
relationship.id,
|
||||
);
|
||||
setRelationshipOpen(false);
|
||||
}}
|
||||
>
|
||||
<div className="flex w-full items-center space-x-2">
|
||||
<Check
|
||||
className={cn(
|
||||
"h-4 w-4",
|
||||
selectedRelationship?.id === relationship.id ? "opacity-100" : "opacity-0",
|
||||
)}
|
||||
/>
|
||||
<div className="flex-1 text-left">
|
||||
<div className="font-medium">{relationship.name}</div>
|
||||
<div className="text-xs text-gray-500">
|
||||
{relationship.sourceTable} → {relationship.targetTable}
|
||||
</div>
|
||||
<Badge variant="outline" className="mt-1 text-xs">
|
||||
{relationship.category}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 선택된 관계 간단 정보 */}
|
||||
{selectedRelationship && (
|
||||
<div className="mt-2 rounded border bg-blue-50 p-2">
|
||||
<p className="text-xs text-blue-700">
|
||||
<strong>{selectedRelationship.sourceTable}</strong> →{" "}
|
||||
<strong>{selectedRelationship.targetTable}</strong>
|
||||
{previewData && (
|
||||
<span className="ml-2">
|
||||
(조건 {previewData.conditionsCount || 0}개, 액션 {previewData.actionsCount || 0}개)
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user