|
@@ -0,0 +1,109 @@
|
|
|
|
|
+import { useMemo } from 'react'
|
|
|
|
|
+import {
|
|
|
|
|
+ Tooltip,
|
|
|
|
|
+ TooltipContent,
|
|
|
|
|
+ TooltipTrigger,
|
|
|
|
|
+} from '@/components/ui/tooltip'
|
|
|
|
|
+import { planDurations } from '@/constants/common-constansts'
|
|
|
|
|
+import { subscriptionStatusLabels } from '@/constants/users/users-constants'
|
|
|
|
|
+import { useActivityFields } from '@/hooks/activity-fields/useActivityFields'
|
|
|
|
|
+import { type Subscription } from '@/types/users.types'
|
|
|
|
|
+
|
|
|
|
|
+type Props = {
|
|
|
|
|
+ subscription: Subscription | null
|
|
|
|
|
+ subscriptions?: Subscription[]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function formatDate(value: string | null) {
|
|
|
|
|
+ if (!value) return '-'
|
|
|
|
|
+ return new Date(value).toLocaleDateString('fa-IR')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function formatPrice(value: string | number | null) {
|
|
|
|
|
+ const amount = Number(value)
|
|
|
|
|
+ if (Number.isNaN(amount)) return '-'
|
|
|
|
|
+ return amount.toLocaleString('fa-IR')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getSubscriptionLabel(
|
|
|
|
|
+ item: Subscription,
|
|
|
|
|
+ activityFieldName?: string
|
|
|
|
|
+) {
|
|
|
|
|
+ const duration = planDurations[item.plan?.duration]
|
|
|
|
|
+ const type = item.plan?.type_label || item.plan?.type
|
|
|
|
|
+ const planLabel = duration ? `${type} (${duration})` : type
|
|
|
|
|
+
|
|
|
|
|
+ return activityFieldName ? `${planLabel} - ${activityFieldName}` : planLabel
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export function UserSubscriptionCell({ subscription, subscriptions }: Props) {
|
|
|
|
|
+ const items = subscriptions?.length
|
|
|
|
|
+ ? subscriptions
|
|
|
|
|
+ : subscription
|
|
|
|
|
+ ? [subscription]
|
|
|
|
|
+ : []
|
|
|
|
|
+
|
|
|
|
|
+ const { data: activityFields = [] } = useActivityFields(items.length > 0)
|
|
|
|
|
+
|
|
|
|
|
+ const activityFieldNames = useMemo(
|
|
|
|
|
+ () => new Map(activityFields.map((field) => [field.id, field.name])),
|
|
|
|
|
+ [activityFields]
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ if (items.length === 0) {
|
|
|
|
|
+ return <div className='text-nowrap'>رایگان</div>
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const label = items
|
|
|
|
|
+ .map((item) =>
|
|
|
|
|
+ getSubscriptionLabel(
|
|
|
|
|
+ item,
|
|
|
|
|
+ activityFieldNames.get(item.activity_field_id)
|
|
|
|
|
+ )
|
|
|
|
|
+ )
|
|
|
|
|
+ .join('، ')
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Tooltip>
|
|
|
|
|
+ <TooltipTrigger asChild>
|
|
|
|
|
+ <div className='max-w-44 cursor-default truncate text-nowrap underline decoration-dotted underline-offset-4'>
|
|
|
|
|
+ {label}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </TooltipTrigger>
|
|
|
|
|
+ <TooltipContent
|
|
|
|
|
+ side='top'
|
|
|
|
|
+ align='start'
|
|
|
|
|
+ className='max-w-80 space-y-3 p-3 text-right whitespace-normal'
|
|
|
|
|
+ >
|
|
|
|
|
+ {items.map((item, index) => {
|
|
|
|
|
+ const fieldName = activityFieldNames.get(item.activity_field_id)
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div
|
|
|
|
|
+ key={item.id}
|
|
|
|
|
+ className={
|
|
|
|
|
+ index > 0
|
|
|
|
|
+ ? 'space-y-1.5 border-t border-primary-foreground/20 pt-3'
|
|
|
|
|
+ : 'space-y-1.5'
|
|
|
|
|
+ }
|
|
|
|
|
+ >
|
|
|
|
|
+ <p className='font-semibold'>
|
|
|
|
|
+ {getSubscriptionLabel(item, fieldName)}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <div className='space-y-0.5 text-xs opacity-90'>
|
|
|
|
|
+ {fieldName && <p>رشته: {fieldName}</p>}
|
|
|
|
|
+ <p>
|
|
|
|
|
+ وضعیت:{' '}
|
|
|
|
|
+ {subscriptionStatusLabels[item.status] ?? item.status}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <p>شروع: {formatDate(item.started_at)}</p>
|
|
|
|
|
+ <p>انقضا: {formatDate(item.expires_at)}</p>
|
|
|
|
|
+ <p>مبلغ پرداختی: {formatPrice(item.price_paid)}</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )
|
|
|
|
|
+ })}
|
|
|
|
|
+ </TooltipContent>
|
|
|
|
|
+ </Tooltip>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|