feat: [게시판] 게시판 관리 UI 개선
- BoardDetail, BoardForm, DynamicBoard 폼 개선 - CommentItem, BoardDetailClientV2 UI 개선 - 게시판 페이지 라우팅 개선 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,8 @@ import { DynamicBoardEditForm } from '@/components/board/DynamicBoard/DynamicBoa
|
||||
import { useState, useEffect, useCallback, Suspense } from 'react';
|
||||
import { DetailPageSkeleton } from '@/components/ui/skeleton';
|
||||
import { format } from 'date-fns';
|
||||
import { ArrowLeft, Pencil, Trash2, MessageSquare, Eye } from 'lucide-react';
|
||||
import { ArrowLeft, Edit, Trash2, MessageSquare, Eye } from 'lucide-react';
|
||||
import { useMenuStore } from '@/stores/menuStore';
|
||||
import { PageLayout } from '@/components/organisms/PageLayout';
|
||||
import { PageHeader } from '@/components/organisms/PageHeader';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
@@ -100,6 +101,7 @@ function DetailModeRouter() {
|
||||
// 실제 상세 컴포넌트 (자체 hooks 사용)
|
||||
function DynamicBoardDetailContent({ boardCode, postId }: { boardCode: string; postId: string }) {
|
||||
const router = useRouter();
|
||||
const sidebarCollapsed = useMenuStore((state) => state.sidebarCollapsed);
|
||||
|
||||
// 게시판 정보
|
||||
const [boardName, setBoardName] = useState<string>('게시판');
|
||||
@@ -261,6 +263,7 @@ function DynamicBoardDetailContent({ boardCode, postId }: { boardCode: string; p
|
||||
icon={MessageSquare}
|
||||
/>
|
||||
|
||||
<div className="pb-24">
|
||||
{/* 게시글 상세 */}
|
||||
<Card className="mb-6">
|
||||
<CardHeader>
|
||||
@@ -282,9 +285,9 @@ function DynamicBoardDetailContent({ boardCode, postId }: { boardCode: string; p
|
||||
</div>
|
||||
</div>
|
||||
{isAuthor && (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="hidden md:flex items-center gap-2">
|
||||
<Button variant="outline" size="sm" onClick={handleEdit}>
|
||||
<Pencil className="h-4 w-4 mr-1" />
|
||||
<Edit className="h-4 w-4 mr-1" />
|
||||
수정
|
||||
</Button>
|
||||
<Button variant="destructive" size="sm" onClick={() => setShowDeleteDialog(true)}>
|
||||
@@ -400,13 +403,33 @@ function DynamicBoardDetailContent({ boardCode, postId }: { boardCode: string; p
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* 하단 버튼 */}
|
||||
<div className="mt-6 flex justify-start">
|
||||
<Button variant="outline" onClick={handleBack}>
|
||||
<ArrowLeft className="h-4 w-4 mr-2" />
|
||||
목록으로
|
||||
{/* 하단 액션 버튼 (sticky) */}
|
||||
<div
|
||||
className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[48px] ${sidebarCollapsed ? 'md:left-[156px]' : 'md:left-[316px]'} flex items-center justify-between`}
|
||||
>
|
||||
<Button variant="outline" onClick={handleBack} size="sm" className="md:size-default">
|
||||
<ArrowLeft className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">목록으로</span>
|
||||
</Button>
|
||||
{isAuthor && (
|
||||
<div className="flex items-center gap-1 md:gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setShowDeleteDialog(true)}
|
||||
size="sm"
|
||||
className="text-destructive hover:bg-destructive hover:text-destructive-foreground md:size-default"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">삭제</span>
|
||||
</Button>
|
||||
<Button onClick={handleEdit} size="sm" className="md:size-default">
|
||||
<Edit className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">수정</span>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 게시글 삭제 확인 다이얼로그 */}
|
||||
|
||||
@@ -223,7 +223,7 @@ function DynamicBoardListContent({ boardCode }: { boardCode: string }) {
|
||||
|
||||
const handleRowClick = useCallback(
|
||||
(item: BoardPost) => {
|
||||
router.push(`/ko/boards/${boardCode}/${item.id}`);
|
||||
router.push(`/ko/boards/${boardCode}/${item.id}?mode=view`);
|
||||
},
|
||||
[router, boardCode]
|
||||
);
|
||||
|
||||
@@ -125,17 +125,11 @@ export function BoardDetail({ post, comments: initialComments, currentUserId }:
|
||||
</h2>
|
||||
|
||||
{/* 메타 정보: 작성자 | 날짜 | 조회수 */}
|
||||
<div className="flex items-center gap-2 text-sm text-gray-500 mt-2">
|
||||
<span>{post.authorName}</span>
|
||||
{post.authorDepartment && (
|
||||
<>
|
||||
<span className="text-gray-300">|</span>
|
||||
<span>{post.authorDepartment}</span>
|
||||
</>
|
||||
)}
|
||||
<span className="text-gray-300">|</span>
|
||||
<div className="flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-2 text-sm text-gray-500 mt-2">
|
||||
<span>{post.authorName}{post.authorDepartment ? ` / ${post.authorDepartment}` : ''}</span>
|
||||
<span className="hidden sm:inline text-gray-300">|</span>
|
||||
<span>{format(new Date(post.createdAt), 'yyyy-MM-dd HH:mm')}</span>
|
||||
<span className="text-gray-300">|</span>
|
||||
<span className="hidden sm:inline text-gray-300">|</span>
|
||||
<span>조회수 {post.viewCount}</span>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { ClipboardList, ArrowLeft, Edit, Trash2 } from 'lucide-react';
|
||||
import { useMenuStore } from '@/stores/menuStore';
|
||||
import type { Board } from './types';
|
||||
import {
|
||||
BOARD_STATUS_LABELS,
|
||||
@@ -33,6 +34,7 @@ const formatDateTime = (dateString: string): string => {
|
||||
|
||||
export function BoardDetail({ board, onEdit, onDelete }: BoardDetailProps) {
|
||||
const router = useRouter();
|
||||
const sidebarCollapsed = useMenuStore((state) => state.sidebarCollapsed);
|
||||
|
||||
const handleBack = () => {
|
||||
router.push('/ko/board/board-management');
|
||||
@@ -54,7 +56,7 @@ export function BoardDetail({ board, onEdit, onDelete }: BoardDetailProps) {
|
||||
icon={ClipboardList}
|
||||
/>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-6 pb-24">
|
||||
{/* 게시판 정보 */}
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between">
|
||||
@@ -93,28 +95,36 @@ export function BoardDetail({ board, onEdit, onDelete }: BoardDetailProps) {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 버튼 영역 */}
|
||||
<div className="flex items-center justify-between">
|
||||
<Button variant="outline" onClick={handleBack}>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
목록으로
|
||||
</div>
|
||||
|
||||
{/* 하단 액션 버튼 (sticky) */}
|
||||
<div
|
||||
className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[48px] ${sidebarCollapsed ? 'md:left-[156px]' : 'md:left-[316px]'} flex items-center justify-between`}
|
||||
>
|
||||
<Button variant="outline" onClick={handleBack} size="sm" className="md:size-default">
|
||||
<ArrowLeft className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">목록으로</span>
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-1 md:gap-2">
|
||||
{onDelete && (
|
||||
<Button variant="outline" onClick={onDelete} className="text-destructive hover:bg-destructive hover:text-destructive-foreground">
|
||||
<Trash2 className="w-4 h-4 mr-2" />
|
||||
삭제
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={onDelete}
|
||||
size="sm"
|
||||
className="text-destructive hover:bg-destructive hover:text-destructive-foreground md:size-default"
|
||||
>
|
||||
<Trash2 className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">삭제</span>
|
||||
</Button>
|
||||
)}
|
||||
{onEdit && (
|
||||
<Button onClick={onEdit}>
|
||||
<Edit className="w-4 h-4 mr-2" />
|
||||
수정
|
||||
<Button onClick={onEdit} size="sm" className="md:size-default">
|
||||
<Edit className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">수정</span>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
@@ -93,9 +93,10 @@ export function BoardDetailClientV2({ boardId, initialMode }: BoardDetailClientV
|
||||
|
||||
// URL 쿼리 변경 감지
|
||||
useEffect(() => {
|
||||
if (!isNewMode && modeFromQuery === 'edit') {
|
||||
if (isNewMode) return;
|
||||
if (modeFromQuery === 'edit') {
|
||||
setMode('edit');
|
||||
} else if (!isNewMode && !modeFromQuery) {
|
||||
} else {
|
||||
setMode('view');
|
||||
}
|
||||
}, [modeFromQuery, isNewMode]);
|
||||
|
||||
@@ -17,7 +17,8 @@ import {
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { ClipboardList, ArrowLeft, Save } from 'lucide-react';
|
||||
import { ClipboardList, ArrowLeft, Save, X } from 'lucide-react';
|
||||
import { useMenuStore } from '@/stores/menuStore';
|
||||
import type { Board, BoardFormData, BoardTarget, BoardStatus } from './types';
|
||||
import { BOARD_TARGETS, BOARD_STATUS_LABELS } from './types';
|
||||
|
||||
@@ -62,6 +63,7 @@ const getCurrentDateTime = (): string => {
|
||||
|
||||
export function BoardForm({ mode, board, onSubmit }: BoardFormProps) {
|
||||
const router = useRouter();
|
||||
const sidebarCollapsed = useMenuStore((state) => state.sidebarCollapsed);
|
||||
const [formData, setFormData] = useState<BoardFormData>({
|
||||
target: 'all',
|
||||
targetName: '',
|
||||
@@ -129,7 +131,7 @@ export function BoardForm({ mode, board, onSubmit }: BoardFormProps) {
|
||||
icon={ClipboardList}
|
||||
/>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<form onSubmit={handleSubmit} className="space-y-6 pb-24">
|
||||
{/* 게시판 정보 */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
@@ -254,18 +256,21 @@ export function BoardForm({ mode, board, onSubmit }: BoardFormProps) {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 버튼 영역 */}
|
||||
<div className="flex items-center justify-between">
|
||||
<Button type="button" variant="outline" onClick={handleBack}>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
취소
|
||||
</form>
|
||||
|
||||
{/* 하단 액션 버튼 (sticky) */}
|
||||
<div
|
||||
className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[48px] ${sidebarCollapsed ? 'md:left-[156px]' : 'md:left-[316px]'} flex items-center justify-between`}
|
||||
>
|
||||
<Button type="button" variant="outline" onClick={handleBack} size="sm" className="md:size-default">
|
||||
<X className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">취소</span>
|
||||
</Button>
|
||||
<Button type="submit">
|
||||
<Save className="w-4 h-4 mr-2" />
|
||||
{mode === 'create' ? '등록' : '저장'}
|
||||
<Button onClick={() => onSubmit(formData)} size="sm" className="md:size-default">
|
||||
<Save className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">{mode === 'create' ? '등록' : '저장'}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import { useState, useCallback, memo } from 'react';
|
||||
import { format } from 'date-fns';
|
||||
import { User, Pencil, Trash2 } from 'lucide-react';
|
||||
import { User, Edit, Trash2 } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
|
||||
@@ -90,7 +90,7 @@ export const CommentItem = memo(function CommentItem({
|
||||
{/* 댓글 내용 */}
|
||||
<div className="flex-1 min-w-0">
|
||||
{/* 작성자 정보 + 날짜 + 버튼 */}
|
||||
<div className="flex items-center justify-between gap-2 mb-1">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-1 sm:gap-2 mb-1">
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<span className="font-medium text-gray-900">{authorInfo}</span>
|
||||
<span className="text-gray-400">
|
||||
@@ -107,7 +107,7 @@ export const CommentItem = memo(function CommentItem({
|
||||
className="h-7 px-2 text-gray-500 hover:text-gray-700"
|
||||
onClick={handleEditClick}
|
||||
>
|
||||
<Pencil className="h-3 w-3 mr-1" />
|
||||
<Edit className="h-3 w-3 mr-1" />
|
||||
수정
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { ArrowLeft, Save, MessageSquare } from 'lucide-react';
|
||||
import { X, Save, MessageSquare } from 'lucide-react';
|
||||
import { PageLayout } from '@/components/organisms/PageLayout';
|
||||
import { PageHeader } from '@/components/organisms/PageHeader';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
@@ -16,6 +16,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { useMenuStore } from '@/stores/menuStore';
|
||||
import { createDynamicBoardPost } from '@/components/board/DynamicBoard/actions';
|
||||
import { getBoardByCode } from '@/components/board/BoardManagement/actions';
|
||||
|
||||
@@ -25,6 +26,7 @@ interface DynamicBoardCreateFormProps {
|
||||
|
||||
export function DynamicBoardCreateForm({ boardCode }: DynamicBoardCreateFormProps) {
|
||||
const router = useRouter();
|
||||
const sidebarCollapsed = useMenuStore((state) => state.sidebarCollapsed);
|
||||
|
||||
// 게시판 정보
|
||||
const [boardName, setBoardName] = useState<string>('게시판');
|
||||
@@ -71,7 +73,7 @@ export function DynamicBoardCreateForm({ boardCode }: DynamicBoardCreateFormProp
|
||||
});
|
||||
|
||||
if (result.success && result.data) {
|
||||
router.push(`/ko/boards/${boardCode}/${result.data.id}`);
|
||||
router.push(`/ko/boards/${boardCode}/${result.data.id}?mode=view`);
|
||||
} else {
|
||||
setError(result.error || '게시글 등록에 실패했습니다.');
|
||||
setIsSubmitting(false);
|
||||
@@ -91,7 +93,7 @@ export function DynamicBoardCreateForm({ boardCode }: DynamicBoardCreateFormProp
|
||||
icon={MessageSquare}
|
||||
/>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<form onSubmit={handleSubmit} className="pb-24">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">게시글 작성</CardTitle>
|
||||
@@ -143,23 +145,21 @@ export function DynamicBoardCreateForm({ boardCode }: DynamicBoardCreateFormProp
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 버튼 영역 */}
|
||||
<div className="mt-6 flex items-center justify-between">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={handleCancel}
|
||||
disabled={isSubmitting}
|
||||
</form>
|
||||
|
||||
{/* 하단 액션 버튼 (sticky) */}
|
||||
<div
|
||||
className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[48px] ${sidebarCollapsed ? 'md:left-[156px]' : 'md:left-[316px]'} flex items-center justify-between`}
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4 mr-2" />
|
||||
취소
|
||||
<Button type="button" variant="outline" onClick={handleCancel} disabled={isSubmitting} size="sm" className="md:size-default">
|
||||
<X className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">취소</span>
|
||||
</Button>
|
||||
<Button type="submit" disabled={isSubmitting}>
|
||||
<Save className="h-4 w-4 mr-2" />
|
||||
{isSubmitting ? '등록 중...' : '등록'}
|
||||
<Button onClick={(e) => { e.preventDefault(); const form = document.querySelector('form'); form?.requestSubmit(); }} disabled={isSubmitting} size="sm" className="md:size-default">
|
||||
<Save className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">{isSubmitting ? '등록 중...' : '등록'}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { ArrowLeft, Save, MessageSquare } from 'lucide-react';
|
||||
import { ArrowLeft, X, Save, MessageSquare } from 'lucide-react';
|
||||
import { DetailPageSkeleton } from '@/components/ui/skeleton';
|
||||
import { PageLayout } from '@/components/organisms/PageLayout';
|
||||
import { PageHeader } from '@/components/organisms/PageHeader';
|
||||
@@ -17,6 +17,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { useMenuStore } from '@/stores/menuStore';
|
||||
import { getDynamicBoardPost, updateDynamicBoardPost } from '@/components/board/DynamicBoard/actions';
|
||||
import { getBoardByCode } from '@/components/board/BoardManagement/actions';
|
||||
import type { PostApiData } from '@/components/customer-center/shared/types';
|
||||
@@ -59,6 +60,7 @@ interface DynamicBoardEditFormProps {
|
||||
|
||||
export function DynamicBoardEditForm({ boardCode, postId }: DynamicBoardEditFormProps) {
|
||||
const router = useRouter();
|
||||
const sidebarCollapsed = useMenuStore((state) => state.sidebarCollapsed);
|
||||
|
||||
// 게시판 정보
|
||||
const [boardName, setBoardName] = useState<string>('게시판');
|
||||
@@ -134,7 +136,7 @@ export function DynamicBoardEditForm({ boardCode, postId }: DynamicBoardEditForm
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
router.push(`/ko/boards/${boardCode}/${postId}`);
|
||||
router.push(`/ko/boards/${boardCode}/${postId}?mode=view`);
|
||||
} else {
|
||||
setError(result.error || '게시글 수정에 실패했습니다.');
|
||||
setIsSubmitting(false);
|
||||
@@ -143,7 +145,7 @@ export function DynamicBoardEditForm({ boardCode, postId }: DynamicBoardEditForm
|
||||
|
||||
// 취소
|
||||
const handleCancel = () => {
|
||||
router.push(`/ko/boards/${boardCode}/${postId}`);
|
||||
router.push(`/ko/boards/${boardCode}/${postId}?mode=view`);
|
||||
};
|
||||
|
||||
// 로딩 상태
|
||||
@@ -178,7 +180,7 @@ export function DynamicBoardEditForm({ boardCode, postId }: DynamicBoardEditForm
|
||||
icon={MessageSquare}
|
||||
/>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<form onSubmit={handleSubmit} className="pb-24">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">게시글 수정</CardTitle>
|
||||
@@ -230,23 +232,21 @@ export function DynamicBoardEditForm({ boardCode, postId }: DynamicBoardEditForm
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 버튼 영역 */}
|
||||
<div className="mt-6 flex items-center justify-between">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={handleCancel}
|
||||
disabled={isSubmitting}
|
||||
</form>
|
||||
|
||||
{/* 하단 액션 버튼 (sticky) */}
|
||||
<div
|
||||
className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[48px] ${sidebarCollapsed ? 'md:left-[156px]' : 'md:left-[316px]'} flex items-center justify-between`}
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4 mr-2" />
|
||||
취소
|
||||
<Button type="button" variant="outline" onClick={handleCancel} disabled={isSubmitting} size="sm" className="md:size-default">
|
||||
<X className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">취소</span>
|
||||
</Button>
|
||||
<Button type="submit" disabled={isSubmitting}>
|
||||
<Save className="h-4 w-4 mr-2" />
|
||||
{isSubmitting ? '저장 중...' : '저장'}
|
||||
<Button onClick={(e) => { e.preventDefault(); const form = document.querySelector('form'); form?.requestSubmit(); }} disabled={isSubmitting} size="sm" className="md:size-default">
|
||||
<Save className="w-4 h-4 md:mr-2" />
|
||||
<span className="hidden md:inline">{isSubmitting ? '저장 중...' : '저장'}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user