order list
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
import { type FC } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Call, Edit2, Location, Paperclip2, Profile2User, User } from 'iconsax-react'
|
||||
import { clx } from '@/helpers/utils'
|
||||
import { getFileNameAndExtensionFromUrl } from '@/config/func'
|
||||
import { Paths } from '@/config/Paths'
|
||||
import {
|
||||
getAttachmentUrl,
|
||||
formatJalaliDateTime,
|
||||
getCreatorDisplayName,
|
||||
getUserDisplayName,
|
||||
} from '../utils/orderDetailUtils'
|
||||
import {
|
||||
getOrderStatusBadgeClass,
|
||||
getOrderStatusLabel,
|
||||
} from '../constants/orderStatus'
|
||||
import type { OrderDetailDataType } from '../types/Types'
|
||||
|
||||
type Props = {
|
||||
order?: OrderDetailDataType
|
||||
}
|
||||
|
||||
type InfoRowProps = {
|
||||
label: string
|
||||
value?: string | number | null
|
||||
mono?: boolean
|
||||
}
|
||||
|
||||
const InfoRow: FC<InfoRowProps> = ({ label, value, mono }) => (
|
||||
<div className="flex items-start justify-between gap-3 py-2.5 border-b border-gray-100 last:border-b-0">
|
||||
<dt className="text-xs text-gray-500 shrink-0">{label}</dt>
|
||||
<dd
|
||||
className={clx(
|
||||
'text-sm text-gray-900 text-left min-w-0 break-words',
|
||||
mono && 'font-mono text-xs',
|
||||
)}
|
||||
title={value != null ? String(value) : undefined}
|
||||
>
|
||||
{value ?? '—'}
|
||||
</dd>
|
||||
</div>
|
||||
)
|
||||
|
||||
const PersonCard: FC<{
|
||||
title: string
|
||||
name: string
|
||||
subtitle?: string
|
||||
phone?: string
|
||||
icon?: 'user' | 'designer'
|
||||
}> = ({ title, name, subtitle, phone, icon = 'user' }) => (
|
||||
<div className="rounded-2xl border border-gray-100 bg-gray-50/80 p-4">
|
||||
<p className="text-xs text-gray-500 mb-3">{title}</p>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="size-11 shrink-0 rounded-full bg-white border border-gray-200 flex items-center justify-center">
|
||||
{icon === 'designer' ? (
|
||||
<Profile2User size={22} className="text-gray-400" />
|
||||
) : (
|
||||
<User size={22} className="text-gray-400" />
|
||||
)}
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-medium text-gray-900 truncate">{name}</p>
|
||||
{subtitle && <p className="text-xs text-gray-500 mt-0.5">{subtitle}</p>}
|
||||
{phone && (
|
||||
<p className="text-xs text-gray-600 mt-1 flex items-center gap-1 dltr">
|
||||
<Call size={14} className="text-gray-400 shrink-0" />
|
||||
{phone}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const OrderDetailSidebar: FC<Props> = ({ order }) => {
|
||||
const attachments = (order?.attachments ?? [])
|
||||
.map(getAttachmentUrl)
|
||||
.filter((url): url is string => Boolean(url))
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<section className="bg-white rounded-3xl p-5 shadow-sm">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<p className="text-xs text-gray-500">شماره سفارش</p>
|
||||
<p className="mt-1 text-2xl font-medium text-gray-900 tabular-nums">
|
||||
#{order?.orderNumber ?? '—'}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
{order?.id && (
|
||||
<Link
|
||||
to={Paths.order.edit + order.id}
|
||||
title="ویرایش سفارش"
|
||||
className="inline-flex size-8 items-center justify-center rounded-lg border border-gray-200 text-[#0037FF] hover:bg-blue-50 transition-colors"
|
||||
>
|
||||
<Edit2 size={18} color="#0037FF" />
|
||||
</Link>
|
||||
)}
|
||||
{order?.status && (
|
||||
<span
|
||||
className={clx(
|
||||
'inline-flex h-7 items-center rounded-full px-3 text-xs font-medium',
|
||||
getOrderStatusBadgeClass(order.status),
|
||||
)}
|
||||
>
|
||||
{getOrderStatusLabel(order.status)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<dl className="mt-5">
|
||||
<InfoRow label="عنوان" value={order?.title} />
|
||||
<InfoRow
|
||||
label="تاریخ ایجاد"
|
||||
value={formatJalaliDateTime(order?.createdAt)}
|
||||
/>
|
||||
<InfoRow
|
||||
label="تخمین زمان"
|
||||
value={
|
||||
order?.estimatedDays != null
|
||||
? `${order.estimatedDays} روز`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<InfoRow label="نوع / دستهبندی" value={order?.type?.title} />
|
||||
<InfoRow label="محصول" value={order?.product?.title} />
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
{order?.user && (
|
||||
<section className="bg-white rounded-3xl p-5 shadow-sm space-y-4">
|
||||
<h3 className="text-sm font-medium text-gray-900">مشتری</h3>
|
||||
<PersonCard
|
||||
title="اطلاعات تماس"
|
||||
name={getUserDisplayName(order.user)}
|
||||
phone={order.user.phone}
|
||||
/>
|
||||
{order.user.addresse && (
|
||||
<div className="flex items-start gap-2 text-sm text-gray-700 rounded-2xl border border-gray-100 bg-gray-50/80 p-4">
|
||||
<Location size={18} className="text-gray-400 shrink-0 mt-0.5" />
|
||||
<p className="leading-6">{order.user.addresse}</p>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
)}
|
||||
|
||||
{(order?.creator || order?.designer) && (
|
||||
<section className="bg-white rounded-3xl p-5 shadow-sm space-y-3">
|
||||
<h3 className="text-sm font-medium text-gray-900">تیم</h3>
|
||||
{order.creator && (
|
||||
<PersonCard
|
||||
title="ایجادکننده"
|
||||
name={getCreatorDisplayName(order.creator)}
|
||||
subtitle="ادمین ثبتکننده"
|
||||
phone={order.creator.phone}
|
||||
/>
|
||||
)}
|
||||
{order.designer && (
|
||||
<PersonCard
|
||||
title="طراح / مجری"
|
||||
name={getCreatorDisplayName(order.designer)}
|
||||
subtitle="مسئول طراحی"
|
||||
phone={order.designer.phone}
|
||||
icon="designer"
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
)}
|
||||
|
||||
{attachments.length > 0 && (
|
||||
<section className="bg-white rounded-3xl p-5 shadow-sm">
|
||||
<h3 className="text-sm font-medium text-gray-900 mb-4">پیوستها</h3>
|
||||
<div className="flex flex-col gap-2">
|
||||
{attachments.map((url, idx) => {
|
||||
const { fileName } = getFileNameAndExtensionFromUrl(url)
|
||||
return (
|
||||
<a
|
||||
key={url}
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-2 rounded-xl border border-gray-100 bg-gray-50/80 px-3 py-2.5 text-sm text-[#0037FF] hover:bg-blue-50 transition-colors"
|
||||
>
|
||||
<Paperclip2 size={18} className="shrink-0" />
|
||||
<span className="truncate">{fileName || `پیوست ${idx + 1}`}</span>
|
||||
</a>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default OrderDetailSidebar
|
||||
Reference in New Issue
Block a user