@hed-hog/billing 0.0.2 → 0.0.286

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +420 -0
  2. package/dist/billing-contracts.controller.d.ts +85 -4
  3. package/dist/billing-contracts.controller.d.ts.map +1 -1
  4. package/dist/billing-coupons.controller.d.ts +60 -4
  5. package/dist/billing-coupons.controller.d.ts.map +1 -1
  6. package/dist/billing-dashboard.controller.d.ts +20 -5
  7. package/dist/billing-dashboard.controller.d.ts.map +1 -1
  8. package/dist/billing-entitlements.controller.d.ts +28 -2
  9. package/dist/billing-entitlements.controller.d.ts.map +1 -1
  10. package/dist/billing-gateways.controller.d.ts +18 -2
  11. package/dist/billing-gateways.controller.d.ts.map +1 -1
  12. package/dist/billing-invoices.controller.d.ts +56 -2
  13. package/dist/billing-invoices.controller.d.ts.map +1 -1
  14. package/dist/billing-offers.controller.d.ts +61 -4
  15. package/dist/billing-offers.controller.d.ts.map +1 -1
  16. package/dist/billing-orders.controller.d.ts +39 -2
  17. package/dist/billing-orders.controller.d.ts.map +1 -1
  18. package/dist/billing-payments.controller.d.ts +16 -1
  19. package/dist/billing-payments.controller.d.ts.map +1 -1
  20. package/dist/billing-prices.controller.d.ts +80 -4
  21. package/dist/billing-prices.controller.d.ts.map +1 -1
  22. package/dist/billing-products.controller.d.ts +62 -4
  23. package/dist/billing-products.controller.d.ts.map +1 -1
  24. package/dist/billing-subscriptions.controller.d.ts +138 -5
  25. package/dist/billing-subscriptions.controller.d.ts.map +1 -1
  26. package/dist/billing.service.d.ts +663 -39
  27. package/dist/billing.service.d.ts.map +1 -1
  28. package/dist/billing.service.js +135 -16
  29. package/dist/billing.service.js.map +1 -1
  30. package/hedhog/data/menu.yaml +1 -1
  31. package/hedhog/frontend/app/contracts/page.tsx.ejs +68 -64
  32. package/hedhog/frontend/app/coupons/page.tsx.ejs +81 -77
  33. package/hedhog/frontend/app/entitlements/page.tsx.ejs +59 -58
  34. package/hedhog/frontend/app/gateways/page.tsx.ejs +125 -57
  35. package/hedhog/frontend/app/invoices/page.tsx.ejs +49 -43
  36. package/hedhog/frontend/app/offers/page.tsx.ejs +68 -64
  37. package/hedhog/frontend/app/orders/page.tsx.ejs +47 -46
  38. package/hedhog/frontend/app/page.tsx.ejs +186 -186
  39. package/hedhog/frontend/app/payments/page.tsx.ejs +51 -45
  40. package/hedhog/frontend/app/prices/page.tsx.ejs +81 -75
  41. package/hedhog/frontend/app/products/page.tsx.ejs +79 -73
  42. package/hedhog/frontend/app/refunds/page.tsx.ejs +50 -44
  43. package/hedhog/frontend/app/reports/page.tsx.ejs +1 -1
  44. package/hedhog/frontend/app/seats/page.tsx.ejs +826 -0
  45. package/hedhog/frontend/app/subscriptions/page.tsx.ejs +95 -90
  46. package/hedhog/frontend/app/webhooks/page.tsx.ejs +47 -39
  47. package/hedhog/frontend/messages/en.json +640 -551
  48. package/hedhog/frontend/messages/pt.json +652 -563
  49. package/hedhog/table/billing_payment_method.yaml +1 -1
  50. package/package.json +4 -3
  51. package/src/billing.service.ts +299 -17
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import {
4
+ EmptyState,
4
5
  Page,
5
6
  PageHeader,
6
7
  PaginationFooter,
@@ -27,7 +28,7 @@ import {
27
28
  TableRow,
28
29
  } from '@/components/ui/table';
29
30
  import { useApp, useQuery } from '@hed-hog/next-app-provider';
30
- import { Pause, Play, XCircle } from 'lucide-react';
31
+ import { FileText, Pause, Play, XCircle } from 'lucide-react';
31
32
  import { useTranslations } from 'next-intl';
32
33
  import { useState } from 'react';
33
34
 
@@ -65,7 +66,7 @@ const badgeClass = (value: string) => {
65
66
  };
66
67
 
67
68
  export default function BillingSubscriptionsPage() {
68
- const t = useTranslations('BillingSubscriptionsPage');
69
+ const t = useTranslations('billing.BillingSubscriptionsPage');
69
70
  const { request, currentLocaleCode, showToastHandler } = useApp();
70
71
  const [search, setSearch] = useState('');
71
72
  const [page, setPage] = useState(1);
@@ -150,96 +151,100 @@ export default function BillingSubscriptionsPage() {
150
151
  placeholder={t('filters.searchPlaceholder')}
151
152
  />
152
153
 
153
- <div className="overflow-x-auto rounded-md border">
154
- <Table>
155
- <TableHeader>
156
- <TableRow>
157
- <TableHead>{t('table.columns.id')}</TableHead>
158
- <TableHead>{t('table.columns.product')}</TableHead>
159
- <TableHead>{t('table.columns.price')}</TableHead>
160
- <TableHead>{t('table.columns.status')}</TableHead>
161
- <TableHead>{t('table.columns.gateway')}</TableHead>
162
- <TableHead>{t('table.columns.currentPeriodEnd')}</TableHead>
163
- <TableHead>{t('table.columns.createdAt')}</TableHead>
164
- <TableHead className="w-[200px] text-right">
165
- {t('table.columns.actions')}
166
- </TableHead>
167
- </TableRow>
168
- </TableHeader>
169
- <TableBody>
170
- {items.length === 0 && (
154
+ {items.length > 0 ? (
155
+ <div className="overflow-x-auto rounded-md border">
156
+ <Table>
157
+ <TableHeader>
171
158
  <TableRow>
172
- <TableCell
173
- colSpan={8}
174
- className="text-center text-muted-foreground"
175
- >
176
- {t('table.empty')}
177
- </TableCell>
159
+ <TableHead>{t('table.columns.id')}</TableHead>
160
+ <TableHead>{t('table.columns.product')}</TableHead>
161
+ <TableHead>{t('table.columns.price')}</TableHead>
162
+ <TableHead>{t('table.columns.status')}</TableHead>
163
+ <TableHead>{t('table.columns.gateway')}</TableHead>
164
+ <TableHead>{t('table.columns.currentPeriodEnd')}</TableHead>
165
+ <TableHead>{t('table.columns.createdAt')}</TableHead>
166
+ <TableHead className="w-[200px] text-right">
167
+ {t('table.columns.actions')}
168
+ </TableHead>
178
169
  </TableRow>
179
- )}
180
- {items.map((item) => (
181
- <TableRow key={item.id}>
182
- <TableCell className="font-medium">#{item.id}</TableCell>
183
- <TableCell>
184
- {item.product_name ?? item.product?.name ?? '-'}
185
- </TableCell>
186
- <TableCell>
187
- {item.price_name ?? item.price?.name ?? '-'}
188
- </TableCell>
189
- <TableCell>
190
- <Badge className={badgeClass(item.status)}>
191
- {item.status}
192
- </Badge>
193
- </TableCell>
194
- <TableCell>{item.gateway}</TableCell>
195
- <TableCell>
196
- {item.current_period_end
197
- ? new Intl.DateTimeFormat('pt-BR', {
198
- dateStyle: 'short',
199
- }).format(new Date(item.current_period_end))
200
- : '-'}
201
- </TableCell>
202
- <TableCell>
203
- {new Intl.DateTimeFormat('pt-BR', {
204
- dateStyle: 'short',
205
- }).format(new Date(item.created_at))}
206
- </TableCell>
207
- <TableCell>
208
- <div className="flex justify-end gap-2">
209
- <Button
210
- variant="outline"
211
- size="sm"
212
- disabled={processingId === item.id}
213
- onClick={() => void callAction(item.id, 'pause')}
214
- >
215
- <Pause className="mr-2 size-4" />
216
- {t('actions.pause')}
217
- </Button>
218
- <Button
219
- variant="outline"
220
- size="sm"
221
- disabled={processingId === item.id}
222
- onClick={() => void callAction(item.id, 'resume')}
223
- >
224
- <Play className="mr-2 size-4" />
225
- {t('actions.resume')}
226
- </Button>
227
- <Button
228
- variant="destructive"
229
- size="sm"
230
- disabled={processingId === item.id}
231
- onClick={() => setCancelId(item.id)}
232
- >
233
- <XCircle className="mr-2 size-4" />
234
- {t('actions.cancel')}
235
- </Button>
236
- </div>
237
- </TableCell>
238
- </TableRow>
239
- ))}
240
- </TableBody>
241
- </Table>
242
- </div>
170
+ </TableHeader>
171
+ <TableBody>
172
+ {items.map((item) => (
173
+ <TableRow key={item.id}>
174
+ <TableCell className="font-medium">#{item.id}</TableCell>
175
+ <TableCell>
176
+ {item.product_name ?? item.product?.name ?? '-'}
177
+ </TableCell>
178
+ <TableCell>
179
+ {item.price_name ?? item.price?.name ?? '-'}
180
+ </TableCell>
181
+ <TableCell>
182
+ <Badge className={badgeClass(item.status)}>
183
+ {item.status}
184
+ </Badge>
185
+ </TableCell>
186
+ <TableCell>{item.gateway}</TableCell>
187
+ <TableCell>
188
+ {item.current_period_end
189
+ ? new Intl.DateTimeFormat('pt-BR', {
190
+ dateStyle: 'short',
191
+ }).format(new Date(item.current_period_end))
192
+ : '-'}
193
+ </TableCell>
194
+ <TableCell>
195
+ {new Intl.DateTimeFormat('pt-BR', {
196
+ dateStyle: 'short',
197
+ }).format(new Date(item.created_at))}
198
+ </TableCell>
199
+ <TableCell>
200
+ <div className="flex justify-end gap-2">
201
+ <Button
202
+ variant="outline"
203
+ size="sm"
204
+ disabled={processingId === item.id}
205
+ onClick={() => void callAction(item.id, 'pause')}
206
+ >
207
+ <Pause className="mr-2 size-4" />
208
+ {t('actions.pause')}
209
+ </Button>
210
+ <Button
211
+ variant="outline"
212
+ size="sm"
213
+ disabled={processingId === item.id}
214
+ onClick={() => void callAction(item.id, 'resume')}
215
+ >
216
+ <Play className="mr-2 size-4" />
217
+ {t('actions.resume')}
218
+ </Button>
219
+ <Button
220
+ variant="destructive"
221
+ size="sm"
222
+ disabled={processingId === item.id}
223
+ onClick={() => setCancelId(item.id)}
224
+ >
225
+ <XCircle className="mr-2 size-4" />
226
+ {t('actions.cancel')}
227
+ </Button>
228
+ </div>
229
+ </TableCell>
230
+ </TableRow>
231
+ ))}
232
+ </TableBody>
233
+ </Table>
234
+ </div>
235
+ ) : (
236
+ <EmptyState
237
+ icon={<FileText className="h-12 w-12" />}
238
+ title={t('table.empty')}
239
+ description={t('description')}
240
+ actionLabel={t('emptyAction')}
241
+ onAction={() => {
242
+ setSearch('');
243
+ setPage(1);
244
+ void refetch();
245
+ }}
246
+ />
247
+ )}
243
248
 
244
249
  <PaginationFooter
245
250
  currentPage={page}
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import {
4
+ EmptyState,
4
5
  Page,
5
6
  PageHeader,
6
7
  PaginationFooter,
@@ -16,6 +17,7 @@ import {
16
17
  TableRow,
17
18
  } from '@/components/ui/table';
18
19
  import { useApp, useQuery } from '@hed-hog/next-app-provider';
20
+ import { FileText } from 'lucide-react';
19
21
  import { useTranslations } from 'next-intl';
20
22
  import { useState } from 'react';
21
23
 
@@ -58,7 +60,7 @@ const formatDate = (value: string | null) => {
58
60
  };
59
61
 
60
62
  export default function BillingWebhooksPage() {
61
- const t = useTranslations('BillingWebhooksPage');
63
+ const t = useTranslations('billing.BillingWebhooksPage');
62
64
  const { request, currentLocaleCode } = useApp();
63
65
  const [search, setSearch] = useState('');
64
66
  const [page, setPage] = useState(1);
@@ -116,46 +118,52 @@ export default function BillingWebhooksPage() {
116
118
  placeholder={t('filters.searchPlaceholder')}
117
119
  />
118
120
 
119
- <div className="overflow-x-auto rounded-md border">
120
- <Table>
121
- <TableHeader>
122
- <TableRow>
123
- <TableHead>{t('table.columns.eventType')}</TableHead>
124
- <TableHead>{t('table.columns.externalEventId')}</TableHead>
125
- <TableHead>{t('table.columns.processed')}</TableHead>
126
- <TableHead>{t('table.columns.processedAt')}</TableHead>
127
- <TableHead>{t('table.columns.createdAt')}</TableHead>
128
- </TableRow>
129
- </TableHeader>
130
- <TableBody>
131
- {items.length === 0 && (
121
+ {items.length > 0 ? (
122
+ <div className="overflow-x-auto rounded-md border">
123
+ <Table>
124
+ <TableHeader>
132
125
  <TableRow>
133
- <TableCell
134
- colSpan={5}
135
- className="text-center text-muted-foreground"
136
- >
137
- {t('table.empty')}
138
- </TableCell>
126
+ <TableHead>{t('table.columns.eventType')}</TableHead>
127
+ <TableHead>{t('table.columns.externalEventId')}</TableHead>
128
+ <TableHead>{t('table.columns.processed')}</TableHead>
129
+ <TableHead>{t('table.columns.processedAt')}</TableHead>
130
+ <TableHead>{t('table.columns.createdAt')}</TableHead>
139
131
  </TableRow>
140
- )}
141
- {items.map((item) => (
142
- <TableRow key={item.id}>
143
- <TableCell className="font-medium">{item.event_type}</TableCell>
144
- <TableCell>{item.external_event_id ?? '-'}</TableCell>
145
- <TableCell>
146
- <Badge className={badgeClass(String(item.processed))}>
147
- {item.processed
148
- ? t('status.processed')
149
- : t('status.pending')}
150
- </Badge>
151
- </TableCell>
152
- <TableCell>{formatDate(item.processed_at)}</TableCell>
153
- <TableCell>{formatDate(item.created_at)}</TableCell>
154
- </TableRow>
155
- ))}
156
- </TableBody>
157
- </Table>
158
- </div>
132
+ </TableHeader>
133
+ <TableBody>
134
+ {items.map((item) => (
135
+ <TableRow key={item.id}>
136
+ <TableCell className="font-medium">
137
+ {item.event_type}
138
+ </TableCell>
139
+ <TableCell>{item.external_event_id ?? '-'}</TableCell>
140
+ <TableCell>
141
+ <Badge className={badgeClass(String(item.processed))}>
142
+ {item.processed
143
+ ? t('status.processed')
144
+ : t('status.pending')}
145
+ </Badge>
146
+ </TableCell>
147
+ <TableCell>{formatDate(item.processed_at)}</TableCell>
148
+ <TableCell>{formatDate(item.created_at)}</TableCell>
149
+ </TableRow>
150
+ ))}
151
+ </TableBody>
152
+ </Table>
153
+ </div>
154
+ ) : (
155
+ <EmptyState
156
+ icon={<FileText className="h-12 w-12" />}
157
+ title={t('table.empty')}
158
+ description={t('description')}
159
+ actionLabel={t('emptyAction')}
160
+ onAction={() => {
161
+ setSearch('');
162
+ setPage(1);
163
+ void refetch();
164
+ }}
165
+ />
166
+ )}
159
167
 
160
168
  <PaginationFooter
161
169
  currentPage={page}