11import { MiniMetricChartBox } from '@/components/Metrics/MiniMetricChartBox'
22import { OrderStatus } from '@/components/Orders/OrderStatus'
3+ import { SubscriptionStatus as SubscriptionStatusComponent } from '@/components/Subscriptions/SubscriptionStatus'
34import RevenueWidget from '@/components/Widgets/RevenueWidget'
45import { useDiscounts } from '@/hooks/queries'
56import { useOrders } from '@/hooks/queries/orders'
7+ import { useSubscriptions } from '@/hooks/queries/subscriptions'
68import { getDiscountDisplay } from '@/utils/discount'
79import { schemas } from '@polar-sh/client'
810import Avatar from '@polar-sh/ui/components/atoms/Avatar'
@@ -36,6 +38,18 @@ export const ProductOverview = ({
3638 } ,
3739 )
3840
41+ const { data : subscriptions , isLoading : subscriptionsIsLoading } =
42+ useSubscriptions (
43+ product . is_recurring ? organization . id : undefined ,
44+ product . is_recurring
45+ ? {
46+ product_id : product . id ,
47+ active : true ,
48+ limit : 10 ,
49+ }
50+ : undefined ,
51+ )
52+
3953 const { data : discountsData , isLoading : discountsLoading } = useDiscounts (
4054 organization . id ,
4155 {
@@ -52,29 +66,157 @@ export const ProductOverview = ({
5266 return (
5367 < div className = "flex flex-col gap-y-16" >
5468 < div className = "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3" >
55- < MiniMetricChartBox
56- metric = { metrics ?. metrics . orders }
57- value = { metrics ?. periods . reduce (
58- ( acc , current ) => acc + current . orders ,
59- 0 ,
60- ) }
61- />
62- < MiniMetricChartBox
63- title = "Today's Revenue"
64- metric = { todayMetrics ?. metrics . revenue }
65- value = { todayMetrics ?. periods [ todayMetrics . periods . length - 1 ] . revenue }
66- />
69+ { product . is_recurring ? (
70+ < >
71+ < MiniMetricChartBox
72+ title = "Active Subscriptions"
73+ metric = { metrics ?. metrics . active_subscriptions }
74+ value = { metrics ?. totals . active_subscriptions }
75+ />
76+ < MiniMetricChartBox
77+ title = "Monthly Recurring Revenue"
78+ metric = { metrics ?. metrics . monthly_recurring_revenue }
79+ value = { metrics ?. totals . monthly_recurring_revenue }
80+ />
81+ </ >
82+ ) : (
83+ < >
84+ < MiniMetricChartBox
85+ metric = { metrics ?. metrics . orders }
86+ value = { metrics ?. totals . orders }
87+ />
88+ < MiniMetricChartBox
89+ title = "Today's Revenue"
90+ metric = { todayMetrics ?. metrics . revenue }
91+ value = { todayMetrics ?. periods . at ( - 1 ) ?. revenue }
92+ />
93+ </ >
94+ ) }
6795 < MiniMetricChartBox
6896 metric = { metrics ?. metrics . cumulative_revenue }
69- value = {
70- metrics ?. periods [ metrics ?. periods . length - 1 ] . cumulative_revenue
71- }
97+ value = { metrics ?. periods . at ( - 1 ) ?. cumulative_revenue }
7298 />
7399 </ div >
100+ { product . is_recurring && (
101+ < div className = "flex flex-col gap-y-6" >
102+ < div className = "flex flex-row items-center justify-between gap-x-6" >
103+ < div className = "flex flex-col gap-y-1" >
104+ < h2 className = "text-lg" > Subscriptions</ h2 >
105+ < p className = "dark:text-polar-500 text-sm text-gray-500" >
106+ Showing 10 most recent subscriptions for { product . name }
107+ </ p >
108+ </ div >
109+ < Link
110+ href = { `/dashboard/${ organization . slug } /sales/subscriptions?product_id=${ product . id } ` }
111+ >
112+ < Button size = "sm" > View All</ Button >
113+ </ Link >
114+ </ div >
115+ < DataTable
116+ data = { subscriptions ?. items ?? [ ] }
117+ columns = { [
118+ {
119+ id : 'customer' ,
120+ accessorKey : 'customer' ,
121+ enableSorting : true ,
122+ header : ( { column } ) => (
123+ < DataTableColumnHeader column = { column } title = "Customer" />
124+ ) ,
125+ cell : ( { row : { original : subscription } } ) => {
126+ const customer = subscription . customer
127+ return (
128+ < div className = "flex flex-row items-center gap-2" >
129+ < Avatar
130+ avatar_url = { customer . avatar_url }
131+ name = { customer . name || customer . email }
132+ />
133+ < div className = "fw-medium overflow-hidden text-ellipsis" >
134+ { customer . email }
135+ </ div >
136+ </ div >
137+ )
138+ } ,
139+ } ,
140+ {
141+ accessorKey : 'status' ,
142+ enableSorting : true ,
143+ header : ( { column } ) => (
144+ < DataTableColumnHeader column = { column } title = "Status" />
145+ ) ,
146+ cell : ( { row : { original : subscription } } ) => {
147+ return (
148+ < SubscriptionStatusComponent subscription = { subscription } />
149+ )
150+ } ,
151+ } ,
152+ {
153+ accessorKey : 'started_at' ,
154+ enableSorting : true ,
155+ header : ( { column } ) => (
156+ < DataTableColumnHeader
157+ column = { column }
158+ title = "Subscription Date"
159+ />
160+ ) ,
161+ cell : ( props ) => (
162+ < FormattedDateTime datetime = { props . getValue ( ) as string } />
163+ ) ,
164+ } ,
165+ {
166+ accessorKey : 'current_period_end' ,
167+ enableSorting : true ,
168+ header : ( { column } ) => (
169+ < DataTableColumnHeader column = { column } title = "Renewal Date" />
170+ ) ,
171+ cell : ( {
172+ getValue,
173+ row : {
174+ original : { status, cancel_at_period_end } ,
175+ } ,
176+ } ) => {
177+ const datetime = getValue ( ) as string | null
178+ const willRenew =
179+ ( status === 'active' || status === 'trialing' ) &&
180+ ! cancel_at_period_end
181+ return datetime && willRenew ? (
182+ < FormattedDateTime datetime = { datetime } />
183+ ) : (
184+ '—'
185+ )
186+ } ,
187+ } ,
188+ {
189+ accessorKey : 'actions' ,
190+ enableSorting : false ,
191+ header : ( ) => null ,
192+ cell : ( props ) => (
193+ < span className = "flex flex-row justify-end gap-x-2" >
194+ < Link
195+ href = { `/dashboard/${ organization . slug } /customers?customerId=${ props . row . original . customer . id } ` }
196+ >
197+ < Button variant = "secondary" size = "sm" >
198+ View Customer
199+ </ Button >
200+ </ Link >
201+ < Link
202+ href = { `/dashboard/${ organization . slug } /sales/subscriptions/${ props . row . original . id } ` }
203+ >
204+ < Button variant = "secondary" size = "sm" >
205+ View Subscription
206+ </ Button >
207+ </ Link >
208+ </ span >
209+ ) ,
210+ } ,
211+ ] }
212+ isLoading = { subscriptionsIsLoading }
213+ />
214+ </ div >
215+ ) }
74216 < div className = "flex flex-col gap-y-6" >
75217 < div className = "flex flex-row items-center justify-between gap-x-6" >
76218 < div className = "flex flex-col gap-y-1" >
77- < h2 className = "text-lg" > Product Orders</ h2 >
219+ < h2 className = "text-lg" > Orders</ h2 >
78220 < p className = "dark:text-polar-500 text-sm text-gray-500" >
79221 Showing last 10 orders for { product . name }
80222 </ p >
0 commit comments