questions
This commit is contained in:
@@ -2,31 +2,25 @@
|
|||||||
|
|
||||||
import { FC, Fragment, useMemo, useState } from 'react'
|
import { FC, Fragment, useMemo, useState } from 'react'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { ArrowDown2, MessageQuestion } from 'iconsax-react'
|
import { MessageQuestion } from 'iconsax-react'
|
||||||
import { Product, Question } from '@/types/product.types'
|
import { Product } from '@/types/product.types'
|
||||||
import AddQuestion from './AddQuestion'
|
import AddQuestion from './AddQuestion'
|
||||||
import { PRIMARY_COLOR } from '@/config/const'
|
import { useGetProductQuestion } from '../hooks/useProductData'
|
||||||
|
import moment from 'moment-jalaali'
|
||||||
|
|
||||||
interface QuestionsProps {
|
interface QuestionsProps {
|
||||||
product: Product
|
product: Product
|
||||||
questions?: Question[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Questions: FC<QuestionsProps> = ({ questions = [] }) => {
|
const Questions: FC<QuestionsProps> = ({ product }) => {
|
||||||
const [sort, setSort] = useState<'new' | 'answers'>('new')
|
const { data: questionsData, isLoading } = useGetProductQuestion(product._id)
|
||||||
const [expandedId, setExpandedId] = useState<string | null>(null)
|
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const sorted = useMemo(() => {
|
|
||||||
if (sort === 'new') {
|
|
||||||
return [...questions].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
|
||||||
}
|
|
||||||
return [...questions].sort((a, b) => b.answers.length - a.answers.length)
|
|
||||||
}, [sort, questions])
|
|
||||||
|
|
||||||
const formatDate = (dateString: string) => {
|
const sorted = useMemo(() => {
|
||||||
const date = new Date(dateString)
|
const apiQuestions = questionsData?.results?.questions || []
|
||||||
return date.toLocaleDateString('fa-IR')
|
if (!apiQuestions.length) return []
|
||||||
}
|
return [...apiQuestions].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
||||||
|
}, [questionsData?.results?.questions])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-12 sm:mt-16 w-full">
|
<div className="mt-12 sm:mt-16 w-full">
|
||||||
@@ -37,30 +31,12 @@ const Questions: FC<QuestionsProps> = ({ questions = [] }) => {
|
|||||||
|
|
||||||
<div className="mt-4 sm:mt-6 grid grid-cols-12 gap-4 sm:gap-6">
|
<div className="mt-4 sm:mt-6 grid grid-cols-12 gap-4 sm:gap-6">
|
||||||
<div className="col-span-12 md:col-span-9 md:order-last">
|
<div className="col-span-12 md:col-span-9 md:order-last">
|
||||||
<div className="flex flex-col sm:flex-row sm:items-center justify-end gap-2 sm:gap-4 text-xs sm:text-sm text-[#7F7F7F]">
|
|
||||||
<span>مرتب سازی بر اساس:</span>
|
|
||||||
<div className="flex items-center gap-4 sm:gap-6">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setSort('new')}
|
|
||||||
className={sort === 'new' ? 'text-primary font-medium' : 'text-[#B2B2B2] hover:text-primary'}
|
|
||||||
>
|
|
||||||
جدیدترین
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setSort('answers')}
|
|
||||||
className={
|
|
||||||
sort === 'answers' ? 'text-primary font-medium' : 'text-[#B2B2B2] hover:text-primary'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
بیشترین پاسخ
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-4 sm:mt-6 rounded-xl bg-white divide-y divide-[#E6E6E6]">
|
<div className="mt-4 sm:mt-6 rounded-xl bg-white divide-y divide-[#E6E6E6]">
|
||||||
{sorted.length > 0 ? (
|
{isLoading ? (
|
||||||
|
<div className="px-4 sm:px-6 py-8 text-center text-[#999999] text-sm">
|
||||||
|
در حال بارگذاری...
|
||||||
|
</div>
|
||||||
|
) : sorted.length > 0 ? (
|
||||||
sorted.map((question) => (
|
sorted.map((question) => (
|
||||||
<Fragment key={question._id}>
|
<Fragment key={question._id}>
|
||||||
<div className="px-4 sm:px-6 py-4 sm:py-5">
|
<div className="px-4 sm:px-6 py-4 sm:py-5">
|
||||||
@@ -70,40 +46,24 @@ const Questions: FC<QuestionsProps> = ({ questions = [] }) => {
|
|||||||
<MessageQuestion size={14} color="#2F80ED" className="sm:w-[18px] sm:h-[18px]" />
|
<MessageQuestion size={14} color="#2F80ED" className="sm:w-[18px] sm:h-[18px]" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-[#333333] text-xs sm:text-sm leading-6 sm:leading-7 text-right flex-1">
|
<div className="text-[#333333] flex gap-2 items-center text-xs sm:text-sm leading-6 sm:leading-7 text-right flex-1">
|
||||||
{question.question}
|
{question.content}
|
||||||
|
<div className="text-xs text-[#999999]">
|
||||||
|
{moment(question.createdAt, 'jYYYY/jMM/jDD HH:mm:ss').format('jYYYY/jMM/jD')}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-2 text-xs text-[#999999]">
|
|
||||||
{question.user.name} • {formatDate(question.date)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{question.answers.length === 0 && (
|
|
||||||
<div className="mt-3 text-primary text-xs cursor-pointer w-fit">ثبت پاسخ</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{question.answers.length > 0 && (
|
{question.answers && question.answers.length > 0 && (
|
||||||
<div className="mt-3 sm:mt-4 text-[#7F7F7F]">
|
<div className="mt-2 pr-8 sm:pr-11">
|
||||||
{(expandedId === question._id ? question.answers : question.answers.slice(0, 1)).map((answer) => (
|
{question.answers.map((answer, index) => (
|
||||||
<div key={answer._id} className='flex gap-2 items-start mt-2 first:mt-0'>
|
<div key={index} className="text-[#666666] text-xs sm:text-sm leading-6 sm:leading-7 text-right mt-2">
|
||||||
<div className="text-xs shrink-0">پاسخ</div>
|
<span className="text-primary font-medium">پاسخ: </span>
|
||||||
<div className="text-xs leading-6 sm:leading-7 text-right text-[#333333]">
|
{answer.content}
|
||||||
{answer.answer}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{question.answers.length > 1 && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setExpandedId(expandedId === question._id ? null : question._id)}
|
|
||||||
className="mt-3 flex items-center gap-1 text-xs text-primary"
|
|
||||||
>
|
|
||||||
{expandedId === question._id ? 'بستن پاسخها' : 'مشاهده پاسخ های دیگر'}
|
|
||||||
<ArrowDown2 size={12} color={PRIMARY_COLOR} className={expandedId === question._id ? 'rotate-180 transition' : 'transition sm:w-[14px] sm:h-[14px]'} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { ProductDetailResponse } from "@/types/product.types";
|
|||||||
import {
|
import {
|
||||||
AddCommentProps,
|
AddCommentProps,
|
||||||
AddQuestionProps,
|
AddQuestionProps,
|
||||||
|
AddQuestionResponse,
|
||||||
SubmitReportProps,
|
SubmitReportProps,
|
||||||
PriceHistoryResponse,
|
PriceHistoryResponse,
|
||||||
ProductQuestionsResponse,
|
ProductQuestionsResponse,
|
||||||
@@ -24,7 +25,9 @@ export const addComment = async (params: AddCommentProps) => {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addQuestion = async (params: AddQuestionProps) => {
|
export const addQuestion = async (
|
||||||
|
params: AddQuestionProps
|
||||||
|
): Promise<AddQuestionResponse> => {
|
||||||
const { data } = await axios.post(
|
const { data } = await axios.post(
|
||||||
`/product/${params.productId}/questions`,
|
`/product/${params.productId}/questions`,
|
||||||
params
|
params
|
||||||
@@ -52,7 +55,7 @@ export const getPriceHistory = async (
|
|||||||
export const getProductQuestion = async (
|
export const getProductQuestion = async (
|
||||||
productId: number
|
productId: number
|
||||||
): Promise<ProductQuestionsResponse> => {
|
): Promise<ProductQuestionsResponse> => {
|
||||||
const { data } = await axios.get(`/product/${productId}/report/questions`);
|
const { data } = await axios.get(`/product/${productId}/questions`);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -47,13 +47,69 @@ export type PriceHistoryResponse = {
|
|||||||
results: PriceHistoryResults;
|
results: PriceHistoryResults;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProductQuestion = {
|
export type QuestionAnswer = {
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type QuestionUser = {
|
||||||
|
fullName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type QuestionProductBrand = {
|
||||||
|
_id: string;
|
||||||
|
status: string;
|
||||||
|
title_en: string;
|
||||||
|
title_fa: string;
|
||||||
|
images: string[];
|
||||||
|
logoUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type QuestionProductCategory = {
|
||||||
|
_id: string;
|
||||||
|
title_fa: string;
|
||||||
|
title_en: string;
|
||||||
|
icon: string;
|
||||||
|
imageUrl: string;
|
||||||
|
theme: string;
|
||||||
|
description: string;
|
||||||
|
leaf: boolean;
|
||||||
|
parent: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type QuestionProductImages = {
|
||||||
|
cover: string;
|
||||||
|
list: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type QuestionProduct = {
|
||||||
_id: number;
|
_id: number;
|
||||||
title: string;
|
url: string;
|
||||||
type: string;
|
title_fa: string;
|
||||||
placeholder: string | null;
|
title_en: string;
|
||||||
|
seoTitle: string;
|
||||||
|
seoDescription: string | null;
|
||||||
|
source: string;
|
||||||
|
description: string;
|
||||||
|
metaDescription: string;
|
||||||
|
tags: string[];
|
||||||
|
advantages: string[];
|
||||||
|
disAdvantages: string[];
|
||||||
|
imagesUrl: QuestionProductImages;
|
||||||
|
isFake: string;
|
||||||
|
voice: string | null;
|
||||||
|
specifications: unknown[];
|
||||||
|
brand: QuestionProductBrand;
|
||||||
|
category: QuestionProductCategory;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ProductQuestion = {
|
||||||
|
_id: string;
|
||||||
|
content: string;
|
||||||
|
status: string;
|
||||||
|
product: QuestionProduct;
|
||||||
|
user: QuestionUser;
|
||||||
|
answers: QuestionAnswer[];
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProductQuestionsResults = {
|
export type ProductQuestionsResults = {
|
||||||
@@ -71,3 +127,14 @@ export type SaveReportTypes = {
|
|||||||
description: string;
|
description: string;
|
||||||
productId: string;
|
productId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AddQuestionResults = {
|
||||||
|
message: string;
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AddQuestionResponse = {
|
||||||
|
status: number;
|
||||||
|
success: boolean;
|
||||||
|
results: AddQuestionResults;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user