Add approve and answer functionality to Questions page
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { type FC, useState } from 'react'
|
import { type FC, useState } from 'react'
|
||||||
import { useGetProductQuestions } from './hooks/useProductData'
|
import { useGetProductQuestions, useApproveProductQuestion, useAnswerProductQuestion } from './hooks/useProductData'
|
||||||
import { type ProductQuestionType } from './types/Types'
|
import { type ProductQuestionType } from './types/Types'
|
||||||
import PageLoading from '../../components/PageLoading'
|
import PageLoading from '../../components/PageLoading'
|
||||||
import Error from '../../components/Error'
|
import Error from '../../components/Error'
|
||||||
@@ -14,7 +14,9 @@ const Questions: FC = () => {
|
|||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [selectedQuestion, setSelectedQuestion] = useState<ProductQuestionType | null>(null);
|
const [selectedQuestion, setSelectedQuestion] = useState<ProductQuestionType | null>(null);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const { data, isLoading, error } = useGetProductQuestions(currentPage);
|
const { data, isLoading, error, refetch } = useGetProductQuestions(currentPage);
|
||||||
|
const approveMutation = useApproveProductQuestion();
|
||||||
|
const answerMutation = useAnswerProductQuestion();
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
@@ -63,6 +65,26 @@ const Questions: FC = () => {
|
|||||||
setSelectedQuestion(null);
|
setSelectedQuestion(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleApproveQuestion = async (questionId: string) => {
|
||||||
|
try {
|
||||||
|
await approveMutation.mutateAsync(questionId);
|
||||||
|
await refetch();
|
||||||
|
handleCloseModal();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('خطا در تایید سوال:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAnswerQuestion = async (questionId: string, answer: string) => {
|
||||||
|
try {
|
||||||
|
await answerMutation.mutateAsync({ id: questionId, answer });
|
||||||
|
await refetch();
|
||||||
|
handleCloseModal();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('خطا در پاسخ به سوال:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageTitle />
|
<PageTitle />
|
||||||
@@ -152,6 +174,10 @@ const Questions: FC = () => {
|
|||||||
isOpen={isModalOpen}
|
isOpen={isModalOpen}
|
||||||
onClose={handleCloseModal}
|
onClose={handleCloseModal}
|
||||||
question={selectedQuestion}
|
question={selectedQuestion}
|
||||||
|
onApprove={handleApproveQuestion}
|
||||||
|
onAnswer={handleAnswerQuestion}
|
||||||
|
isApproving={approveMutation.isPending}
|
||||||
|
isAnswering={answerMutation.isPending}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import { type FC } from 'react'
|
import { type FC, useState } from 'react'
|
||||||
import { type ProductQuestionType } from '../types/Types'
|
import { type ProductQuestionType } from '../types/Types'
|
||||||
import DefaulModal from '../../../components/DefaulModal'
|
import DefaulModal from '../../../components/DefaulModal'
|
||||||
import StatusWithText from '../../../components/StatusWithText'
|
import StatusWithText from '../../../components/StatusWithText'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { TickCircle } from 'iconsax-react'
|
import { Textarea } from '@/components/Textarea'
|
||||||
|
import { TickCircle, Send } from 'iconsax-react'
|
||||||
|
|
||||||
interface QuestionModalProps {
|
interface QuestionModalProps {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
question: ProductQuestionType | null
|
question: ProductQuestionType | null
|
||||||
onApprove?: (questionId: string) => void
|
onApprove?: (questionId: string) => void
|
||||||
|
onAnswer?: (questionId: string, answer: string) => void
|
||||||
isApproving?: boolean
|
isApproving?: boolean
|
||||||
|
isAnswering?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const QuestionModal: FC<QuestionModalProps> = ({
|
const QuestionModal: FC<QuestionModalProps> = ({
|
||||||
@@ -18,8 +21,11 @@ const QuestionModal: FC<QuestionModalProps> = ({
|
|||||||
onClose,
|
onClose,
|
||||||
question,
|
question,
|
||||||
onApprove,
|
onApprove,
|
||||||
isApproving = false
|
onAnswer,
|
||||||
|
isApproving = false,
|
||||||
|
isAnswering = false
|
||||||
}) => {
|
}) => {
|
||||||
|
const [answer, setAnswer] = useState('');
|
||||||
const getStatusVariant = (status: string) => {
|
const getStatusVariant = (status: string) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'accepted': return 'success';
|
case 'accepted': return 'success';
|
||||||
@@ -44,6 +50,13 @@ const QuestionModal: FC<QuestionModalProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAnswer = () => {
|
||||||
|
if (question && onAnswer && answer.trim()) {
|
||||||
|
onAnswer(question._id, answer.trim());
|
||||||
|
setAnswer('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaulModal
|
<DefaulModal
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
@@ -125,6 +138,29 @@ const QuestionModal: FC<QuestionModalProps> = ({
|
|||||||
تاریخ ارسال: {question.createdAt}
|
تاریخ ارسال: {question.createdAt}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* بخش پاسخ دادن */}
|
||||||
|
{onAnswer && (
|
||||||
|
<div className="bg-blue-50 p-4 rounded-lg border-t mt-4">
|
||||||
|
<h4 className="font-medium text-blue-900 mb-3">پاسخ به سوال:</h4>
|
||||||
|
<Textarea
|
||||||
|
value={answer}
|
||||||
|
onChange={(e) => setAnswer(e.target.value)}
|
||||||
|
placeholder="پاسخ خود را اینجا تایپ کنید..."
|
||||||
|
className="w-full min-h-[100px] mb-3"
|
||||||
|
/>
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<Button
|
||||||
|
onClick={handleAnswer}
|
||||||
|
disabled={isAnswering || !answer.trim()}
|
||||||
|
className="bg-blue-600 hover:bg-blue-700 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
<Send color="#fff" size={16} className="ml-2" />
|
||||||
|
{isAnswering ? 'در حال ارسال...' : 'ارسال پاسخ'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* دکمه تایید */}
|
{/* دکمه تایید */}
|
||||||
{question.status !== 'accepted' && onApprove && (
|
{question.status !== 'accepted' && onApprove && (
|
||||||
<div className="flex justify-end pt-4 border-t">
|
<div className="flex justify-end pt-4 border-t">
|
||||||
|
|||||||
@@ -123,4 +123,16 @@ export const useGetProductQuestions = (page: number = 1, limit: number = 10) =>
|
|||||||
queryKey: ['product-questions', page, limit],
|
queryKey: ['product-questions', page, limit],
|
||||||
queryFn: () => api.getProductQuestions(page, limit),
|
queryFn: () => api.getProductQuestions(page, limit),
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useApproveProductQuestion = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: api.approveProductQuestion,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAnswerProductQuestion = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: api.answerProductQuestion,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
@@ -117,4 +117,14 @@ export const getProductQuestions = async (page: number = 1, limit: number = 10):
|
|||||||
const params: Record<string, string | number> = { page, limit };
|
const params: Record<string, string | number> = { page, limit };
|
||||||
const { data } = await axios.get(`admin/products/questions`, { params });
|
const { data } = await axios.get(`admin/products/questions`, { params });
|
||||||
return data;
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const approveProductQuestion = async (id: string) => {
|
||||||
|
const { data } = await axios.post(`/admin/products/questions/${id}/approve`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const answerProductQuestion = async (params: {id: string, answer: string}) => {
|
||||||
|
const { data } = await axios.post(`/product/questions/${params.id}/answer`, { content:params.answer });
|
||||||
|
return data;
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user