feat: complete url deeplinking across all admin modal/tab pages
All checks were successful
Deploy Canina / deploy (push) Successful in 30s
All checks were successful
Deploy Canina / deploy (push) Successful in 30s
This commit is contained in:
parent
5029edaaeb
commit
fc324aacaf
@ -11,6 +11,8 @@ import Modal from '../components/ui/Modal';
|
||||
|
||||
|
||||
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
export interface BlogPost {
|
||||
author?: {
|
||||
firstName?: string;
|
||||
@ -29,10 +31,11 @@ export interface BlogPost {
|
||||
}
|
||||
|
||||
export default function Blogs() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [blogs, setBlogs] = useState<BlogPost[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [search, setSearch] = useState('');
|
||||
const [page, setPage] = useState(1);
|
||||
const [search, setSearch] = useState(() => searchParams.get('search') || '');
|
||||
const [page, setPage] = useState(() => Number(searchParams.get('page')) || 1);
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const limit = 10;
|
||||
|
||||
@ -41,6 +44,16 @@ export default function Blogs() {
|
||||
const [editingBlog, setEditingBlog] = useState<BlogPost | null>(null);
|
||||
const [deleteTargetId, setDeleteTargetId] = useState<string | null>(null);
|
||||
|
||||
const updateUrlParams = (paramsObj: Record<string, string | number | undefined | null>) => {
|
||||
const current = Object.fromEntries(searchParams.entries());
|
||||
const merged = { ...current, ...paramsObj };
|
||||
const cleaned: Record<string, string> = {};
|
||||
Object.entries(merged).forEach(([k, v]) => {
|
||||
if (v !== undefined && v !== null && String(v).trim() !== '') cleaned[k] = String(v);
|
||||
});
|
||||
setSearchParams(cleaned, { replace: true });
|
||||
};
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
title: '',
|
||||
slug: '',
|
||||
@ -57,15 +70,25 @@ export default function Blogs() {
|
||||
setIsLoading(true);
|
||||
const res = await api.get('/admin/blogs', { params: { page, limit, search } });
|
||||
if (res.data?.data) {
|
||||
setBlogs(res.data.data);
|
||||
const blogList: BlogPost[] = res.data.data;
|
||||
setBlogs(blogList);
|
||||
setTotalPages(res.data.meta?.lastPage || 1);
|
||||
|
||||
const modalParam = searchParams.get('modal');
|
||||
const blogId = searchParams.get('blogId');
|
||||
if (modalParam === 'create') {
|
||||
openModal(null);
|
||||
} else if (modalParam === 'edit' && blogId) {
|
||||
const found = blogList.find((b) => b.id === blogId);
|
||||
if (found) openModal(found);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [page, search]);
|
||||
}, [page, search, searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
@ -84,7 +107,7 @@ export default function Blogs() {
|
||||
await api.post('/admin/blogs', formData);
|
||||
toast.success('مقاله جدید با موفقیت ذخیره شد');
|
||||
}
|
||||
setIsModalOpen(false);
|
||||
closeModal();
|
||||
fetchBlogs();
|
||||
} catch (error) {
|
||||
console.error('Save failed', error);
|
||||
@ -109,6 +132,7 @@ export default function Blogs() {
|
||||
const openModal = (blog: BlogPost | null = null) => {
|
||||
if (blog) {
|
||||
setEditingBlog(blog);
|
||||
updateUrlParams({ modal: 'edit', blogId: blog.id });
|
||||
setFormData({
|
||||
title: blog.title,
|
||||
slug: blog.slug,
|
||||
@ -121,6 +145,7 @@ export default function Blogs() {
|
||||
});
|
||||
} else {
|
||||
setEditingBlog(null);
|
||||
updateUrlParams({ modal: 'create', blogId: undefined });
|
||||
setFormData({
|
||||
title: '', slug: '', content: '', isPublished: true, metaTitle: '', metaDescription: '', keywords: '', imageUrl: ''
|
||||
});
|
||||
@ -128,6 +153,12 @@ export default function Blogs() {
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setIsModalOpen(false);
|
||||
updateUrlParams({ modal: undefined, blogId: undefined });
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-col sm:flex-row justify-between gap-4">
|
||||
@ -234,7 +265,7 @@ export default function Blogs() {
|
||||
{isModalOpen && (
|
||||
<Modal
|
||||
isOpen={isModalOpen}
|
||||
onClose={() => setIsModalOpen(false)}
|
||||
onClose={closeModal}
|
||||
title={editingBlog ? 'ویرایش مقاله' : 'افزودن مقاله جدید'}
|
||||
icon={FileText}
|
||||
maxWidth="4xl"
|
||||
@ -244,10 +275,11 @@ export default function Blogs() {
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
type="button"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
onClick={closeModal}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
|
||||
@ -11,6 +11,8 @@ import Modal from '../components/ui/Modal';
|
||||
|
||||
|
||||
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
export interface Category {
|
||||
id: string;
|
||||
name: string;
|
||||
@ -24,10 +26,11 @@ export interface Category {
|
||||
}
|
||||
|
||||
export default function Categories() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [categories, setCategories] = useState<Category[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [search, setSearch] = useState('');
|
||||
const [page, setPage] = useState(1);
|
||||
const [search, setSearch] = useState(() => searchParams.get('search') || '');
|
||||
const [page, setPage] = useState(() => Number(searchParams.get('page')) || 1);
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const limit = 10;
|
||||
|
||||
@ -36,6 +39,16 @@ export default function Categories() {
|
||||
const [editingCategory, setEditingCategory] = useState<Category | null>(null);
|
||||
const [deleteTargetId, setDeleteTargetId] = useState<string | null>(null);
|
||||
|
||||
const updateUrlParams = (paramsObj: Record<string, string | number | undefined | null>) => {
|
||||
const current = Object.fromEntries(searchParams.entries());
|
||||
const merged = { ...current, ...paramsObj };
|
||||
const cleaned: Record<string, string> = {};
|
||||
Object.entries(merged).forEach(([k, v]) => {
|
||||
if (v !== undefined && v !== null && String(v).trim() !== '') cleaned[k] = String(v);
|
||||
});
|
||||
setSearchParams(cleaned, { replace: true });
|
||||
};
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
name: '',
|
||||
slug: '',
|
||||
@ -51,15 +64,25 @@ export default function Categories() {
|
||||
setIsLoading(true);
|
||||
const res = await api.get('/admin/categories', { params: { page, limit, search } });
|
||||
if (res.data?.data) {
|
||||
setCategories(res.data.data);
|
||||
const catList: Category[] = res.data.data;
|
||||
setCategories(catList);
|
||||
setTotalPages(res.data.meta?.lastPage || 1);
|
||||
|
||||
const modalParam = searchParams.get('modal');
|
||||
const catId = searchParams.get('categoryId');
|
||||
if (modalParam === 'create') {
|
||||
openModal(null);
|
||||
} else if (modalParam === 'edit' && catId) {
|
||||
const found = catList.find((c) => c.id === catId);
|
||||
if (found) openModal(found);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [page, search]);
|
||||
}, [page, search, searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
@ -78,7 +101,7 @@ export default function Categories() {
|
||||
await api.post('/admin/categories', formData);
|
||||
toast.success('دستهبندی جدید با موفقیت ایجاد شد');
|
||||
}
|
||||
setIsModalOpen(false);
|
||||
closeModal();
|
||||
fetchCategories();
|
||||
} catch (error) {
|
||||
console.error('Save failed', error);
|
||||
@ -103,6 +126,7 @@ export default function Categories() {
|
||||
const openModal = (category: Category | null = null) => {
|
||||
if (category) {
|
||||
setEditingCategory(category);
|
||||
updateUrlParams({ modal: 'edit', categoryId: category.id });
|
||||
setFormData({
|
||||
name: category.name,
|
||||
slug: category.slug,
|
||||
@ -114,6 +138,7 @@ export default function Categories() {
|
||||
});
|
||||
} else {
|
||||
setEditingCategory(null);
|
||||
updateUrlParams({ modal: 'create', categoryId: undefined });
|
||||
setFormData({
|
||||
name: '', slug: '', description: '', metaTitle: '', metaDescription: '', keywords: '', imageUrl: ''
|
||||
});
|
||||
@ -121,6 +146,12 @@ export default function Categories() {
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setIsModalOpen(false);
|
||||
updateUrlParams({ modal: undefined, categoryId: undefined });
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-col sm:flex-row justify-between gap-4">
|
||||
@ -237,7 +268,7 @@ export default function Categories() {
|
||||
{isModalOpen && (
|
||||
<Modal
|
||||
isOpen={isModalOpen}
|
||||
onClose={() => setIsModalOpen(false)}
|
||||
onClose={closeModal}
|
||||
title={editingCategory ? 'ویرایش دستهبندی' : 'افزودن دستهبندی جدید'}
|
||||
icon={FolderTree}
|
||||
maxWidth="2xl"
|
||||
@ -247,10 +278,11 @@ export default function Categories() {
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
type="button"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
onClick={closeModal}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
|
||||
@ -37,14 +37,17 @@ export interface UserRecord {
|
||||
pets?: PetSummary[];
|
||||
}
|
||||
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
export default function Users() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [users, setUsers] = useState<UserRecord[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
// Queries
|
||||
const [page, setPage] = useState(1);
|
||||
const [search, setSearch] = useState('');
|
||||
const [role, setRole] = useState('');
|
||||
const [page, setPage] = useState(() => Number(searchParams.get('page')) || 1);
|
||||
const [search, setSearch] = useState(() => searchParams.get('search') || '');
|
||||
const [role, setRole] = useState(() => searchParams.get('role') || '');
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const [totalCount, setTotalCount] = useState(0);
|
||||
|
||||
@ -55,6 +58,16 @@ export default function Users() {
|
||||
const [userToDelete, setUserToDelete] = useState<UserRecord | null>(null);
|
||||
const [walletUser, setWalletUser] = useState<UserRecord | null>(null);
|
||||
|
||||
const updateUrlParams = (paramsObj: Record<string, string | number | undefined | null>) => {
|
||||
const current = Object.fromEntries(searchParams.entries());
|
||||
const merged = { ...current, ...paramsObj };
|
||||
const cleaned: Record<string, string> = {};
|
||||
Object.entries(merged).forEach(([k, v]) => {
|
||||
if (v !== undefined && v !== null && String(v).trim() !== '') cleaned[k] = String(v);
|
||||
});
|
||||
setSearchParams(cleaned, { replace: true });
|
||||
};
|
||||
|
||||
// Form States
|
||||
const [createFormData, setCreateFormData] = useState({
|
||||
firstName: '',
|
||||
@ -101,16 +114,30 @@ export default function Users() {
|
||||
|
||||
const response = await api.get(`/admin/users?${params.toString()}`);
|
||||
if (response.data?.success) {
|
||||
setUsers(response.data.data || []);
|
||||
const userList = response.data.data || [];
|
||||
setUsers(userList);
|
||||
setTotalPages(response.data.meta?.lastPage || 1);
|
||||
setTotalCount(response.data.meta?.total || 0);
|
||||
|
||||
const modalParam = searchParams.get('modal');
|
||||
const userId = searchParams.get('userId');
|
||||
if (modalParam === 'create') {
|
||||
handleOpenCreate();
|
||||
} else if (userId && userList.length > 0) {
|
||||
const found = userList.find((u: UserRecord) => u.id === userId);
|
||||
if (found) {
|
||||
if (modalParam === 'view') handleOpenView(found);
|
||||
else if (modalParam === 'edit') handleOpenEdit(found);
|
||||
else if (modalParam === 'wallet') handleOpenWallet(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch users', err);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [page, search, role]);
|
||||
}, [page, search, role, searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
@ -120,9 +147,32 @@ export default function Users() {
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
}, [fetchUsers]);
|
||||
|
||||
// Open View Modal
|
||||
const handleOpenView = (user: UserRecord) => {
|
||||
setViewUser(user);
|
||||
updateUrlParams({ modal: 'view', userId: user.id });
|
||||
};
|
||||
|
||||
const handleCloseView = () => {
|
||||
setViewUser(null);
|
||||
updateUrlParams({ modal: undefined, userId: undefined });
|
||||
};
|
||||
|
||||
// Open Create Modal
|
||||
const handleOpenCreate = () => {
|
||||
setShowCreateModal(true);
|
||||
updateUrlParams({ modal: 'create', userId: undefined });
|
||||
};
|
||||
|
||||
const handleCloseCreate = () => {
|
||||
setShowCreateModal(false);
|
||||
updateUrlParams({ modal: undefined, userId: undefined });
|
||||
};
|
||||
|
||||
// Open Edit Modal
|
||||
const handleOpenEdit = (user: UserRecord) => {
|
||||
setEditUser(user);
|
||||
updateUrlParams({ modal: 'edit', userId: user.id });
|
||||
setEditFormData({
|
||||
firstName: user.firstName || '',
|
||||
lastName: user.lastName || '',
|
||||
@ -134,9 +184,15 @@ export default function Users() {
|
||||
});
|
||||
};
|
||||
|
||||
const handleCloseEdit = () => {
|
||||
setEditUser(null);
|
||||
updateUrlParams({ modal: undefined, userId: undefined });
|
||||
};
|
||||
|
||||
// Open Wallet Modal
|
||||
const handleOpenWallet = (user: UserRecord) => {
|
||||
setWalletUser(user);
|
||||
updateUrlParams({ modal: 'wallet', userId: user.id });
|
||||
setWalletFormData({
|
||||
amount: 50000,
|
||||
type: 'deposit',
|
||||
@ -144,6 +200,17 @@ export default function Users() {
|
||||
});
|
||||
};
|
||||
|
||||
const handleCloseWallet = () => {
|
||||
setWalletUser(null);
|
||||
updateUrlParams({ modal: undefined, userId: undefined });
|
||||
};
|
||||
|
||||
const handleCloseDelete = () => {
|
||||
setUserToDelete(null);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Create User
|
||||
const handleCreateUser = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@ -441,7 +508,7 @@ export default function Users() {
|
||||
{showCreateModal && (
|
||||
<Modal
|
||||
isOpen={showCreateModal}
|
||||
onClose={() => setShowCreateModal(false)}
|
||||
onClose={handleCloseCreate}
|
||||
title="افزودن کاربر جدید"
|
||||
icon={Plus}
|
||||
maxWidth="lg"
|
||||
@ -450,7 +517,7 @@ export default function Users() {
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setShowCreateModal(false)}
|
||||
onClick={handleCloseCreate}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
@ -562,6 +629,7 @@ export default function Users() {
|
||||
type="number"
|
||||
min="0"
|
||||
step="1000"
|
||||
placeholder="0"
|
||||
value={createFormData.walletBalance}
|
||||
onChange={(e) => setCreateFormData({ ...createFormData, walletBalance: Number(e.target.value) })}
|
||||
className="w-full px-3 py-2.5 rounded-xl border border-gray-200 focus:border-purple-500 outline-none font-mono"
|
||||
@ -575,7 +643,7 @@ export default function Users() {
|
||||
{editUser && (
|
||||
<Modal
|
||||
isOpen={!!editUser}
|
||||
onClose={() => setEditUser(null)}
|
||||
onClose={handleCloseEdit}
|
||||
title="ویرایش اطلاعات کاربر"
|
||||
icon={Edit3}
|
||||
maxWidth="lg"
|
||||
@ -584,7 +652,7 @@ export default function Users() {
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setEditUser(null)}
|
||||
onClick={handleCloseEdit}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
@ -691,7 +759,7 @@ export default function Users() {
|
||||
{walletUser && (
|
||||
<Modal
|
||||
isOpen={!!walletUser}
|
||||
onClose={() => setWalletUser(null)}
|
||||
onClose={handleCloseWallet}
|
||||
title="مدیریت کیف پول کاربر"
|
||||
icon={Wallet}
|
||||
maxWidth="md"
|
||||
@ -700,7 +768,7 @@ export default function Users() {
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setWalletUser(null)}
|
||||
onClick={handleCloseWallet}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
@ -774,7 +842,6 @@ export default function Users() {
|
||||
type="number"
|
||||
min="1000"
|
||||
step="1000"
|
||||
required
|
||||
value={walletFormData.amount}
|
||||
onChange={(e) => setWalletFormData({ ...walletFormData, amount: Number(e.target.value) })}
|
||||
className="w-full px-3 py-2.5 rounded-xl border border-gray-200 focus:border-purple-500 outline-none font-mono font-bold text-sm"
|
||||
@ -800,7 +867,7 @@ export default function Users() {
|
||||
{userToDelete && (
|
||||
<Modal
|
||||
isOpen={!!userToDelete}
|
||||
onClose={() => setUserToDelete(null)}
|
||||
onClose={handleCloseDelete}
|
||||
title="تایید حذف کاربر"
|
||||
icon={AlertTriangle}
|
||||
maxWidth="md"
|
||||
@ -809,7 +876,7 @@ export default function Users() {
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setUserToDelete(null)}
|
||||
onClick={handleCloseDelete}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
@ -840,7 +907,7 @@ export default function Users() {
|
||||
{viewUser && (
|
||||
<Modal
|
||||
isOpen={!!viewUser}
|
||||
onClose={() => setViewUser(null)}
|
||||
onClose={handleCloseView}
|
||||
title="مشاهده جزئیات پروفایل کاربر"
|
||||
icon={UsersIcon}
|
||||
maxWidth="lg"
|
||||
|
||||
@ -7,6 +7,7 @@ import Pagination from '../components/ui/Pagination';
|
||||
import ConfirmModal from '../components/ui/ConfirmModal';
|
||||
import Button from '../components/ui/Button';
|
||||
import Modal from '../components/ui/Modal';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
|
||||
export interface WikiTerm {
|
||||
@ -27,10 +28,11 @@ export interface ProductItem {
|
||||
}
|
||||
|
||||
export default function Wiki() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [terms, setTerms] = useState<WikiTerm[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [search, setSearch] = useState('');
|
||||
const [page, setPage] = useState(1);
|
||||
const [search, setSearch] = useState(() => searchParams.get('search') || '');
|
||||
const [page, setPage] = useState(() => Number(searchParams.get('page')) || 1);
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
const limit = 10;
|
||||
|
||||
@ -38,6 +40,17 @@ export default function Wiki() {
|
||||
const [editingTerm, setEditingTerm] = useState<WikiTerm | null>(null);
|
||||
const [deleteTargetKey, setDeleteTargetKey] = useState<string | null>(null);
|
||||
const [productsList, setProductsList] = useState<ProductItem[]>([]);
|
||||
|
||||
const updateUrlParams = (paramsObj: Record<string, string | number | undefined | null>) => {
|
||||
const current = Object.fromEntries(searchParams.entries());
|
||||
const merged = { ...current, ...paramsObj };
|
||||
const cleaned: Record<string, string> = {};
|
||||
Object.entries(merged).forEach(([k, v]) => {
|
||||
if (v !== undefined && v !== null && String(v).trim() !== '') cleaned[k] = String(v);
|
||||
});
|
||||
setSearchParams(cleaned, { replace: true });
|
||||
};
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
key: '',
|
||||
term: '',
|
||||
@ -54,15 +67,25 @@ export default function Wiki() {
|
||||
setIsLoading(true);
|
||||
const res = await api.get('/admin/wiki', { params: { page, limit, search } });
|
||||
if (res.data?.data) {
|
||||
setTerms(res.data.data);
|
||||
const termList: WikiTerm[] = res.data.data;
|
||||
setTerms(termList);
|
||||
setTotalPages(res.data.meta?.lastPage || 1);
|
||||
|
||||
const modalParam = searchParams.get('modal');
|
||||
const termKey = searchParams.get('termKey');
|
||||
if (modalParam === 'create') {
|
||||
openModal(null);
|
||||
} else if (modalParam === 'edit' && termKey) {
|
||||
const found = termList.find((t) => t.key === termKey);
|
||||
if (found) openModal(found);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [page, search]);
|
||||
}, [page, search, searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
@ -81,7 +104,7 @@ export default function Wiki() {
|
||||
await api.post('/admin/wiki', formData);
|
||||
toast.success('اصطلاح علمی جدید با موفقیت ایجاد شد');
|
||||
}
|
||||
setIsModalOpen(false);
|
||||
closeModal();
|
||||
fetchTerms();
|
||||
} catch (error) {
|
||||
console.error('Save failed', error);
|
||||
@ -112,6 +135,7 @@ export default function Wiki() {
|
||||
const openModal = (term: WikiTerm | null = null) => {
|
||||
if (term) {
|
||||
setEditingTerm(term);
|
||||
updateUrlParams({ modal: 'edit', termKey: term.key });
|
||||
setFormData({
|
||||
key: term.key,
|
||||
term: term.term,
|
||||
@ -124,6 +148,7 @@ export default function Wiki() {
|
||||
});
|
||||
} else {
|
||||
setEditingTerm(null);
|
||||
updateUrlParams({ modal: 'create', termKey: undefined });
|
||||
setFormData({
|
||||
key: '', term: '', definition: '', relatedProducts: [], wikiId: 'general', metaTitle: '', metaDescription: '', keywords: ''
|
||||
});
|
||||
@ -131,6 +156,11 @@ export default function Wiki() {
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setIsModalOpen(false);
|
||||
updateUrlParams({ modal: undefined, termKey: undefined });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-col sm:flex-row justify-between gap-4">
|
||||
@ -221,7 +251,7 @@ export default function Wiki() {
|
||||
{isModalOpen && (
|
||||
<Modal
|
||||
isOpen={isModalOpen}
|
||||
onClose={() => setIsModalOpen(false)}
|
||||
onClose={closeModal}
|
||||
title={editingTerm ? 'ویرایش دانشنامه' : 'افزودن مفهوم جدید'}
|
||||
icon={BookOpen}
|
||||
maxWidth="2xl"
|
||||
@ -231,10 +261,11 @@ export default function Wiki() {
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
type="button"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
onClick={closeModal}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user