diff --git a/src/config/Paths.tsx b/src/config/Paths.tsx
index 6ae374f..422b0ee 100644
--- a/src/config/Paths.tsx
+++ b/src/config/Paths.tsx
@@ -27,7 +27,6 @@ export const Paths = {
tickets: {
list: '/tickets',
},
- criticisms: '/criticisms',
learning: '/learning',
auth: {
login: '/auth/login',
@@ -43,4 +42,8 @@ export const Paths = {
detail: "/announcement/detail/",
create: "/announcement/create",
},
+ criticisms: {
+ list: "/criticisms",
+ detail: "/criticisms/detail/",
+ },
}
\ No newline at end of file
diff --git a/src/pages/criticisms/Add.tsx b/src/pages/criticisms/Add.tsx
new file mode 100644
index 0000000..1d4057d
--- /dev/null
+++ b/src/pages/criticisms/Add.tsx
@@ -0,0 +1,96 @@
+import { FC } from 'react'
+import { useTranslation } from 'react-i18next'
+import Input from '../../components/Input'
+import Textarea from '../../components/Textarea'
+import UploadBox from '../../components/UploadBox'
+import Button from '../../components/Button'
+import { TickSquare } from 'iconsax-react'
+
+const AddCriticisms: FC = () => {
+
+ const { t } = useTranslation('global')
+
+ return (
+
+
+ {t('criticisms.criticisms')}
+
+
+
+
+
+ {t('criticisms.submit_your_criticisms')}
+
+
+
+ {t('criticisms.description_criticisms')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t('ticket.title_hint')}
+
+
+
+
+
+
+
+
+ سوالات - مشکلاتی که به یک موضوع مربوط میشوند را در یک درخواست پشتیبانی پیگیر باشید و چند درخواست برای یک موضوع باز نکنید.
+
+
+
+
+
+
+
+ لطفاً برای بررسی و رفع مشکلات احتمالی صبور باشید بررسی و رفع مشکلات در برخی موارد زمان گیر است.
+
+
+
+
+
+
+
+ پاسخگویی 24 ساعته تلفنی را تنها از میهن وب هاست می توانید انتظار داشته باشید .بخش پشتیبانی در هر ساعتی حتی در روز های تعطیل آماده پیگیری سریع مشکلات کاربران است.
+
+
+
+
+
+
+
+ )
+}
+
+export default AddCriticisms
\ No newline at end of file
diff --git a/src/pages/criticisms/Detail.tsx b/src/pages/criticisms/Detail.tsx
new file mode 100644
index 0000000..dd03b13
--- /dev/null
+++ b/src/pages/criticisms/Detail.tsx
@@ -0,0 +1,77 @@
+import { type FC, Fragment } from 'react'
+import { useGetDetailCriticisms } from './hooks/useCriticismsData'
+import { useParams } from 'react-router-dom'
+// import { useTranslation } from 'react-i18next'
+// import PageLoading from '../../components/PageLoading'
+import { Paperclip2 } from 'iconsax-react'
+
+const CriticismsDetail: FC = () => {
+
+ const { id } = useParams()
+ // const { t } = useTranslation('global')
+ const t = (key: string) => {
+ const translations: { [key: string]: string } = {
+ 'criticisms.criticism': 'انتقاد',
+ 'criticisms.documents': 'مدارک',
+ 'loading': 'در حال بارگذاری...'
+ };
+ return translations[key] || key;
+ };
+ const getDetail = useGetDetailCriticisms(id ? id : '')
+
+ return (
+
+ {
+ getDetail.isPending ?
+
+ :
+
+
+ {t('criticisms.criticism')}
+ {' #' + getDetail.data?.data?.criticism?.numericId}
+
+
+
+
+
+ {getDetail.data?.data?.criticism?.title}
+
+
+
+ {getDetail.data?.data?.criticism?.content}
+
+
+
+
+
+ {t('criticisms.documents')}
+
+
+
+
+
+
+ }
+
+ )
+}
+
+export default CriticismsDetail
\ No newline at end of file
diff --git a/src/pages/criticisms/List.tsx b/src/pages/criticisms/List.tsx
new file mode 100644
index 0000000..20ea975
--- /dev/null
+++ b/src/pages/criticisms/List.tsx
@@ -0,0 +1,139 @@
+import { type FC, useState } from 'react'
+import { useDeleteCriticismsDetail, useGetCriticismsList } from './hooks/useCriticismsData'
+// import { useTranslation } from 'react-i18next'
+import { Link } from 'react-router-dom'
+import { Eye, Trash } from 'iconsax-react'
+import { Paths } from '../../config/Paths'
+import type { CriticismsItemTypes } from './types/CriticismsTypes'
+import moment from 'moment-jalaali'
+import DefaulModal from '../../components/DefaulModal'
+import Table from '../../components/Table'
+import type { ColumnType } from '../../components/types/TableTypes'
+
+const CriticismsList: FC = () => {
+
+ const [itemId, setItemId] = useState('')
+ const [page, setPage] = useState(1)
+ const [openConfrim, setOpenConfrim] = useState(false)
+ const getCriticismsList = useGetCriticismsList(page)
+ const deleteCriticisms = useDeleteCriticismsDetail()
+
+ // const { t } = useTranslation('global')
+ const t = (key: string) => {
+ const translations: { [key: string]: string } = {
+ 'criticisms.criticisms_list': 'لیست انتقادات',
+ 'criticisms.number': 'شماره',
+ 'criticisms.title_criticisms': 'عنوان انتقاد',
+ 'criticisms.summary_criticisms': 'خلاصه انتقاد',
+ 'criticisms.date_created': 'تاریخ ایجاد',
+ 'detail': 'جزئیات',
+ 'delete_confirmation': 'تایید حذف',
+ 'are_you_sure_delete': 'آیا از حذف این مورد اطمینان دارید؟',
+ 'cancel': 'لغو',
+ 'delete': 'حذف',
+ 'deleting': 'در حال حذف...'
+ };
+ return translations[key] || key;
+ };
+
+ const handleDelete = (id?: string, confrim: boolean = false) => {
+ if (confrim) {
+
+ deleteCriticisms.mutate(itemId, {
+ onSuccess: () => {
+ getCriticismsList.refetch()
+ setOpenConfrim(false)
+ setItemId('')
+ }
+ })
+ } else if (id) {
+ setItemId(id)
+ setOpenConfrim(true)
+ }
+ }
+
+ // Define table columns
+ const columns: ColumnType[] = [
+ {
+ title: t('criticisms.number'),
+ key: 'numericId',
+ },
+ {
+ title: t('criticisms.title_criticisms'),
+ key: 'title',
+ },
+ {
+ title: t('criticisms.summary_criticisms'),
+ key: 'content',
+ render: (item) => item.content.substring(0, 100),
+ },
+ {
+ title: t('criticisms.date_created'),
+ key: 'createdAt',
+ render: (item) => moment(item.createdAt).format('HH:mm jYYYY-jMM-jDD'),
+ },
+ {
+ title: t('detail'),
+ key: 'detail',
+ render: (item) => (
+
+
+
+ ),
+ },
+ ];
+
+ return (
+
+
+ {t('criticisms.criticisms_list')}
+
+
+
[
+ {
+ label: t('delete'),
+ onClick: () => handleDelete(String(item.id)),
+ icon: ,
+ }
+ ]}
+ pagination={{
+ currentPage: page,
+ totalPages: getCriticismsList.data?.data?.pager?.totalPages || 1,
+ onPageChange: setPage,
+ }}
+ />
+
+ setOpenConfrim(false)}
+ isHeader={true}
+ title_header={t('delete_confirmation')}
+ >
+
+
{t('are_you_sure_delete')}
+
+ setOpenConfrim(false)}
+ className="px-4 py-2 bg-gray-200 rounded-lg"
+ >
+ {t('cancel')}
+
+ handleDelete('', true)}
+ disabled={deleteCriticisms.isPending}
+ className="px-4 py-2 bg-red-500 text-white rounded-lg disabled:opacity-50"
+ >
+ {deleteCriticisms.isPending ? t('deleting') : t('delete')}
+
+
+
+
+
+ )
+}
+
+export default CriticismsList
\ No newline at end of file
diff --git a/src/pages/criticisms/hooks/useCriticismsData.ts b/src/pages/criticisms/hooks/useCriticismsData.ts
new file mode 100644
index 0000000..e301cf4
--- /dev/null
+++ b/src/pages/criticisms/hooks/useCriticismsData.ts
@@ -0,0 +1,130 @@
+import { useMutation, useQuery } from "@tanstack/react-query";
+// import * as api from "../service/CriticismsService";
+import type { CriticismsItemTypes } from "../types/CriticismsTypes";
+
+// Static data for development
+const staticCriticismsData = {
+ data: {
+ criticisms: [
+ {
+ id: "1",
+ numericId: "1001",
+ title: "مشکل در سیستم پرداخت",
+ content:
+ "سلام، من در هنگام پرداخت با مشکل مواجه شدم. سیستم پرداخت به درستی کار نمیکند و پس از وارد کردن اطلاعات کارت، خطای عجیبی نمایش داده میشود. لطفاً این مشکل را بررسی کنید.",
+ createdAt: new Date("2024-01-15T10:30:00"),
+ isRead: false,
+ files: [
+ { id: "f1", fileUrl: "https://example.com/files/payment-error.png" },
+ { id: "f2", fileUrl: "https://example.com/files/screenshot.jpg" },
+ ],
+ },
+ {
+ id: "2",
+ numericId: "1002",
+ title: "کیفیت محصول مطابق انتظار نبود",
+ content:
+ "محصولی که سفارش دادم کیفیت مناسبی نداشت و با توضیحات ارائه شده در سایت مطابقت نداشت. انتظار داشتم کیفیت بهتری داشته باشد.",
+ createdAt: new Date("2024-01-14T14:20:00"),
+ isRead: true,
+ files: [
+ { id: "f3", fileUrl: "https://example.com/files/product-photo.jpg" },
+ ],
+ },
+ {
+ id: "3",
+ numericId: "1003",
+ title: "تاخیر در ارسال سفارش",
+ content:
+ "سفارش من با تاخیر زیادی ارسال شد. زمان تحویل اعلام شده رعایت نشد و این موضوع باعث نارضایتی من شده است.",
+ createdAt: new Date("2024-01-13T09:15:00"),
+ isRead: false,
+ files: [],
+ },
+ {
+ id: "4",
+ numericId: "1004",
+ title: "مشکل در پشتیبانی آنلاین",
+ content:
+ "سیستم چت آنلاین سایت به درستی کار نمیکند و نمیتوانم با پشتیبانی ارتباط برقرار کنم. لطفاً این مشکل را حل کنید.",
+ createdAt: new Date("2024-01-12T16:45:00"),
+ isRead: true,
+ files: [
+ { id: "f4", fileUrl: "https://example.com/files/chat-error.png" },
+ ],
+ },
+ {
+ id: "5",
+ numericId: "1005",
+ title: "پیشنهاد بهبود رابط کاربری",
+ content:
+ "رابط کاربری سایت نیاز به بهبود دارد. منوها کمی پیچیده هستند و یافتن محصولات مورد نظر دشوار است. پیشنهاد میکنم طراحی سادهتری استفاده کنید.",
+ createdAt: new Date("2024-01-11T11:30:00"),
+ isRead: false,
+ files: [],
+ },
+ ] as CriticismsItemTypes[],
+ pager: {
+ totalPages: 2,
+ currentPage: 1,
+ totalItems: 5,
+ },
+ },
+};
+
+export const useGetCriticismsList = (page: number) => {
+ // Commented out API call - using static data instead
+ // return useQuery({
+ // queryKey: ["criticisms", page],
+ // queryFn: () => api.getCriticismsList(page),
+ // });
+
+ return {
+ data: staticCriticismsData,
+ isPending: false,
+ isLoading: false,
+ refetch: () => Promise.resolve(staticCriticismsData),
+ };
+};
+
+export const useDeleteCriticismsDetail = () => {
+ // Commented out API call - using mock function instead
+ // return useMutation({
+ // mutationFn: (id: string) => api.deleteCriticisms(id),
+ // });
+
+ return {
+ mutate: (id: string, options?: { onSuccess?: () => void }) => {
+ // Mock delete - just call onSuccess after a brief delay
+ setTimeout(() => {
+ if (options?.onSuccess) {
+ options.onSuccess();
+ }
+ }, 500);
+ },
+ isPending: false,
+ };
+};
+
+export const useGetDetailCriticisms = (id: string) => {
+ // Commented out API call - using static data instead
+ // return useQuery({
+ // queryKey: ["criticisms", id],
+ // queryFn: () => api.getCriticismsDetail(id),
+ // enabled: !!id,
+ // });
+
+ const criticism = staticCriticismsData.data.criticisms.find(
+ (item) => item.id === id
+ );
+
+ return {
+ data: {
+ data: {
+ criticism: criticism || null,
+ },
+ },
+ isPending: false,
+ isLoading: false,
+ };
+};
diff --git a/src/pages/criticisms/service/CriticismsService.ts b/src/pages/criticisms/service/CriticismsService.ts
new file mode 100644
index 0000000..34a1785
--- /dev/null
+++ b/src/pages/criticisms/service/CriticismsService.ts
@@ -0,0 +1,17 @@
+// API service functions commented out - using static data instead
+// import axios from "../../../config/axios";
+
+// export const getCriticismsList = async (page: number) => {
+// const { data } = await axios.get(`/criticisms?page=${page}`);
+// return data;
+// };
+
+// export const getCriticismsDetail = async (id: string) => {
+// const { data } = await axios.get(`/criticisms/${id}`);
+// return data;
+// };
+
+// export const deleteCriticisms = async (id: string) => {
+// const { data } = await axios.delete(`/criticisms/${id}`);
+// return data;
+// };
diff --git a/src/pages/criticisms/types/CriticismsTypes.ts b/src/pages/criticisms/types/CriticismsTypes.ts
new file mode 100644
index 0000000..d2bee35
--- /dev/null
+++ b/src/pages/criticisms/types/CriticismsTypes.ts
@@ -0,0 +1,10 @@
+export interface CriticismsItemTypes {
+ id: string;
+ content: string;
+ createdAt: Date;
+ isRead: boolean;
+ title: string;
+ numericId: string;
+ files?: { id: string; fileUrl: string }[];
+ [key: string]: unknown;
+}
diff --git a/src/router/MainRouter.tsx b/src/router/MainRouter.tsx
index 8dc2625..f954814 100644
--- a/src/router/MainRouter.tsx
+++ b/src/router/MainRouter.tsx
@@ -20,6 +20,8 @@ import TicketCategory from '@/pages/ticket/Category'
import AnnouncementList from '@/pages/annoncement/List'
import AnnouncementUpdate from '@/pages/annoncement/Update'
import AnnouncementCreate from '@/pages/annoncement/Create'
+import CriticismsList from '@/pages/criticisms/List'
+import CriticismsDetail from '@/pages/criticisms/Detail'
const MainRouter: FC = () => {
return (
@@ -50,6 +52,9 @@ const MainRouter: FC = () => {
} />
} />
} />
+
+ } />
+ } />
diff --git a/src/shared/Sidebar.tsx b/src/shared/Sidebar.tsx
index c885e81..692683e 100644
--- a/src/shared/Sidebar.tsx
+++ b/src/shared/Sidebar.tsx
@@ -118,7 +118,7 @@ const SideBar: FC = () => {
icon={ }
title={t('sidebar.criticisms')}
isActive={isActive('/criticisms')}
- link={Paths.criticisms}
+ link={Paths.criticisms.list}
/>