@djangocfg/ext-payments 1.0.4 → 1.0.7
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.
- package/dist/config.cjs +3 -2
- package/dist/config.js +3 -2
- package/dist/hooks.cjs +559 -543
- package/dist/hooks.js +558 -543
- package/dist/index.cjs +559 -543
- package/dist/index.js +558 -543
- package/package.json +9 -8
- package/src/api/generated/ext_payments/CLAUDE.md +76 -0
- package/src/api/generated/ext_payments/_utils/fetchers/ext_payments__payments.ts +1 -0
- package/src/api/generated/ext_payments/_utils/fetchers/index.ts +1 -0
- package/src/api/generated/ext_payments/_utils/hooks/ext_payments__payments.ts +1 -0
- package/src/api/generated/ext_payments/_utils/hooks/index.ts +1 -0
- package/src/api/generated/ext_payments/_utils/schemas/index.ts +1 -0
- package/src/api/generated/ext_payments/api-instance.ts +1 -0
- package/src/api/generated/ext_payments/enums.ts +1 -0
- package/src/api/generated/ext_payments/errors.ts +1 -0
- package/src/api/generated/ext_payments/ext_payments__payments/index.ts +1 -0
- package/src/api/generated/ext_payments/ext_payments__payments/models.ts +1 -0
- package/src/api/generated/ext_payments/http.ts +1 -0
- package/src/api/generated/ext_payments/index.ts +1 -0
- package/src/api/generated/ext_payments/logger.ts +1 -0
- package/src/api/generated/ext_payments/retry.ts +1 -0
- package/src/api/generated/ext_payments/storage.ts +1 -0
- package/src/api/generated/ext_payments/validation-events.ts +1 -0
- package/src/api/index.ts +2 -1
- package/src/config.ts +1 -0
- package/src/contexts/BalancesContext.tsx +2 -1
- package/src/contexts/CurrenciesContext.tsx +2 -1
- package/src/contexts/OverviewContext.tsx +5 -5
- package/src/contexts/PaymentsContext.tsx +6 -5
- package/src/contexts/PaymentsExtensionProvider.tsx +3 -2
- package/src/contexts/RootPaymentsContext.tsx +2 -1
- package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +5 -7
- package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +10 -27
- package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +15 -18
- package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +6 -13
- package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +8 -11
- package/src/layouts/PaymentsLayout/views/overview/index.tsx +1 -0
- package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +43 -42
- package/src/layouts/PaymentsLayout/views/payments/index.tsx +1 -0
- package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +71 -84
- package/src/layouts/PaymentsLayout/views/transactions/index.tsx +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ext-payments",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Payments system extension for DjangoCFG",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"django",
|
|
@@ -59,21 +59,22 @@
|
|
|
59
59
|
"check": "tsc --noEmit"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
|
-
"@djangocfg/api": "^2.1.
|
|
63
|
-
"@djangocfg/ext-base": "^1.0.
|
|
64
|
-
"@djangocfg/ui-nextjs": "^2.1.
|
|
62
|
+
"@djangocfg/api": "^2.1.43",
|
|
63
|
+
"@djangocfg/ext-base": "^1.0.7",
|
|
64
|
+
"@djangocfg/ui-nextjs": "^2.1.43",
|
|
65
65
|
"consola": "^3.4.2",
|
|
66
66
|
"lucide-react": "^0.545.0",
|
|
67
67
|
"next": "^15.5.7",
|
|
68
68
|
"p-retry": "^7.0.0",
|
|
69
69
|
"react": "^18 || ^19",
|
|
70
70
|
"swr": "^2.3.7",
|
|
71
|
-
"zod": "^4.1.13"
|
|
71
|
+
"zod": "^4.1.13",
|
|
72
|
+
"moment": "^2.30.1"
|
|
72
73
|
},
|
|
73
74
|
"devDependencies": {
|
|
74
|
-
"@djangocfg/api": "^2.1.
|
|
75
|
-
"@djangocfg/ext-base": "^1.0.
|
|
76
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
75
|
+
"@djangocfg/api": "^2.1.43",
|
|
76
|
+
"@djangocfg/ext-base": "^1.0.7",
|
|
77
|
+
"@djangocfg/typescript-config": "^2.1.43",
|
|
77
78
|
"@types/node": "^24.7.2",
|
|
78
79
|
"@types/react": "^19.0.0",
|
|
79
80
|
"consola": "^3.4.2",
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Django CFG API - Typescript Client
|
|
2
|
+
|
|
3
|
+
Auto-generated. **Do not edit manually.**
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
python manage.py generate_client --groups ext_payments --typescript
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Stats
|
|
10
|
+
|
|
11
|
+
| | |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Version | 3.0.3 |
|
|
14
|
+
| Operations | 8 |
|
|
15
|
+
| Schemas | 6 |
|
|
16
|
+
|
|
17
|
+
## Resources
|
|
18
|
+
|
|
19
|
+
- **payments** (8 ops)
|
|
20
|
+
|
|
21
|
+
## Operations
|
|
22
|
+
|
|
23
|
+
**payments:**
|
|
24
|
+
- `GET` /cfg/payments/balance/ → `cfg_payments_balance_retrieve`
|
|
25
|
+
- `GET` /cfg/payments/currencies/ → `cfg_payments_currencies_list`
|
|
26
|
+
- `POST` /cfg/payments/payments/{id}/confirm/ → `cfg_payments_payments_confirm_create`
|
|
27
|
+
- `POST` /cfg/payments/payments/create/ → `cfg_payments_payments_create_create`
|
|
28
|
+
- `GET` /cfg/payments/payments/ → `cfg_payments_payments_list`
|
|
29
|
+
- `GET` /cfg/payments/payments/{id}/ → `cfg_payments_payments_retrieve`
|
|
30
|
+
- `GET` /cfg/payments/payments/{id}/status/ → `cfg_payments_payments_status_retrieve`
|
|
31
|
+
- `GET` /cfg/payments/transactions/ → `cfg_payments_transactions_list`
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { APIClient } from './';
|
|
37
|
+
|
|
38
|
+
const client = new APIClient({ baseUrl, token });
|
|
39
|
+
|
|
40
|
+
await client.payments.list();
|
|
41
|
+
await client.payments.retrieve({ id: 1 });
|
|
42
|
+
await client.payments.create({ ... });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**SWR Hooks:**
|
|
46
|
+
```typescript
|
|
47
|
+
import { usePaymentsList } from './hooks';
|
|
48
|
+
const { data, isLoading } = usePaymentsList();
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## How It Works
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
DRF ViewSets → drf-spectacular → OpenAPI → IR Parser → Generator → This Client
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Configuration** (`api/config.py`):
|
|
58
|
+
```python
|
|
59
|
+
openapi_client = OpenAPIClientConfig(
|
|
60
|
+
enabled=True,
|
|
61
|
+
groups=[OpenAPIGroupConfig(name="ext_payments", apps=["..."])],
|
|
62
|
+
generate_zod_schemas=True, # → schemas.ts
|
|
63
|
+
generate_fetchers=True, # → fetchers.ts
|
|
64
|
+
generate_swr_hooks=True, # → hooks.ts
|
|
65
|
+
)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Copy to Next.js** (if `nextjs_admin` configured):
|
|
69
|
+
```python
|
|
70
|
+
nextjs_admin = NextJsAdminConfig(
|
|
71
|
+
project_path="../frontend/apps/...",
|
|
72
|
+
api_output_path="app/_lib/api/generated",
|
|
73
|
+
)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
@see https://djangocfg.com/docs/features/api-generation
|
package/src/api/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Payments Extension API
|
|
3
5
|
*
|
|
4
6
|
* Pre-configured API instance with shared authentication
|
|
5
7
|
*/
|
|
6
8
|
import { API } from './generated/ext_payments';
|
|
7
|
-
import { createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
8
9
|
|
|
9
10
|
export const apiPayments = createExtensionAPI(API);
|
package/src/config.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React, { createContext,
|
|
3
|
+
import React, { createContext, ReactNode, useContext } from 'react';
|
|
4
|
+
|
|
4
5
|
import { apiPayments } from '../api';
|
|
5
6
|
import { usePaymentsBalanceRetrieve } from '../api/generated/ext_payments/_utils/hooks';
|
|
6
7
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React, { createContext,
|
|
3
|
+
import React, { createContext, ReactNode, useContext } from 'react';
|
|
4
|
+
|
|
4
5
|
import { apiPayments } from '../api';
|
|
5
6
|
import { usePaymentsCurrenciesList } from '../api/generated/ext_payments/_utils/hooks';
|
|
6
7
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React, { createContext,
|
|
3
|
+
import React, { createContext, ReactNode, useContext } from 'react';
|
|
4
4
|
import { SWRConfig } from 'swr';
|
|
5
|
+
|
|
5
6
|
import { apiPayments } from '../api';
|
|
6
7
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
usePaymentsTransactionsList,
|
|
10
|
-
useCreatePaymentsPaymentsCreateCreate,
|
|
8
|
+
useCreatePaymentsPaymentsCreateCreate, usePaymentsBalanceRetrieve, usePaymentsPaymentsList,
|
|
9
|
+
usePaymentsTransactionsList
|
|
11
10
|
} from '../api/generated/ext_payments/_utils/hooks';
|
|
11
|
+
|
|
12
12
|
import type {
|
|
13
13
|
PaginatedPaymentListList,
|
|
14
14
|
PaymentList,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React, { createContext,
|
|
4
|
-
|
|
3
|
+
import React, { createContext, ReactNode, useContext } from 'react';
|
|
4
|
+
|
|
5
5
|
import { apiPayments } from '../api';
|
|
6
|
+
import * as ExtPaymentsFetchers from '../api/generated/ext_payments/_utils/fetchers';
|
|
6
7
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
useCreatePaymentsPaymentsConfirmCreate,
|
|
8
|
+
useCreatePaymentsPaymentsConfirmCreate, useCreatePaymentsPaymentsCreateCreate,
|
|
9
|
+
usePaymentsPaymentsList
|
|
10
10
|
} from '../api/generated/ext_payments/_utils/hooks';
|
|
11
|
+
|
|
11
12
|
import type {
|
|
12
13
|
PaginatedPaymentListList,
|
|
13
14
|
PaymentDetail,
|
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
|
|
9
9
|
import type { ReactNode } from 'react';
|
|
10
10
|
import { ExtensionProvider } from '@djangocfg/ext-base/hooks';
|
|
11
|
+
|
|
11
12
|
import { extensionConfig } from '../config';
|
|
12
|
-
import { RootPaymentsProvider } from './RootPaymentsContext';
|
|
13
|
-
import { PaymentsProvider } from './PaymentsContext';
|
|
14
13
|
import { BalancesProvider } from './BalancesContext';
|
|
15
14
|
import { CurrenciesProvider } from './CurrenciesContext';
|
|
16
15
|
import { OverviewProvider } from './OverviewContext';
|
|
16
|
+
import { PaymentsProvider } from './PaymentsContext';
|
|
17
|
+
import { RootPaymentsProvider } from './RootPaymentsContext';
|
|
17
18
|
|
|
18
19
|
interface PaymentsExtensionProviderProps {
|
|
19
20
|
children: ReactNode;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React, { createContext,
|
|
3
|
+
import React, { createContext, ReactNode, useContext } from 'react';
|
|
4
|
+
|
|
4
5
|
import { apiPayments } from '../api';
|
|
5
6
|
import { usePaymentsCurrenciesList } from '../api/generated/ext_payments/_utils/hooks';
|
|
6
7
|
|
|
@@ -8,18 +8,16 @@
|
|
|
8
8
|
|
|
9
9
|
'use client';
|
|
10
10
|
|
|
11
|
+
import { CreditCard, History, Wallet } from 'lucide-react';
|
|
11
12
|
import React from 'react';
|
|
12
|
-
|
|
13
|
-
PaymentsProvider,
|
|
14
|
-
OverviewProvider,
|
|
15
|
-
RootPaymentsProvider,
|
|
16
|
-
} from '../../contexts';
|
|
13
|
+
|
|
17
14
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@djangocfg/ui-nextjs';
|
|
18
|
-
|
|
15
|
+
|
|
16
|
+
import { OverviewProvider, PaymentsProvider, RootPaymentsProvider } from '../../contexts';
|
|
17
|
+
import { CreatePaymentDialog, PaymentDetailsDialog } from './components';
|
|
19
18
|
import { OverviewView } from './views/overview';
|
|
20
19
|
import { PaymentsView } from './views/payments';
|
|
21
20
|
import { TransactionsView } from './views/transactions';
|
|
22
|
-
import { CreatePaymentDialog, PaymentDetailsDialog } from './components';
|
|
23
21
|
|
|
24
22
|
// ─────────────────────────────────────────────────────────────────────────
|
|
25
23
|
// Payments Layout
|
|
@@ -6,38 +6,21 @@
|
|
|
6
6
|
|
|
7
7
|
'use client';
|
|
8
8
|
|
|
9
|
-
import React, { useState, useEffect, useMemo } from 'react';
|
|
10
|
-
import {
|
|
11
|
-
Dialog,
|
|
12
|
-
DialogContent,
|
|
13
|
-
DialogDescription,
|
|
14
|
-
DialogFooter,
|
|
15
|
-
DialogHeader,
|
|
16
|
-
DialogTitle,
|
|
17
|
-
Form,
|
|
18
|
-
FormControl,
|
|
19
|
-
FormDescription,
|
|
20
|
-
FormField,
|
|
21
|
-
FormItem,
|
|
22
|
-
FormLabel,
|
|
23
|
-
FormMessage,
|
|
24
|
-
Input,
|
|
25
|
-
Select,
|
|
26
|
-
SelectContent,
|
|
27
|
-
SelectItem,
|
|
28
|
-
SelectTrigger,
|
|
29
|
-
SelectValue,
|
|
30
|
-
Button,
|
|
31
|
-
TokenIcon,
|
|
32
|
-
} from '@djangocfg/ui-nextjs';
|
|
33
9
|
import { Plus, RefreshCw } from 'lucide-react';
|
|
10
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
34
11
|
import { useForm } from 'react-hook-form';
|
|
35
|
-
import { zodResolver } from '@hookform/resolvers/zod';
|
|
36
12
|
import { z } from 'zod';
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Form,
|
|
16
|
+
FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Input, Select,
|
|
17
|
+
SelectContent, SelectItem, SelectTrigger, SelectValue, TokenIcon
|
|
18
|
+
} from '@djangocfg/ui-nextjs';
|
|
19
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
20
|
+
|
|
37
21
|
import { usePaymentsContext, useRootPaymentsContext } from '../../../contexts';
|
|
38
|
-
import { PAYMENT_EVENTS, closePaymentsDialog } from '../events';
|
|
39
|
-
import { openPaymentDetailsDialog } from '../events';
|
|
40
22
|
import { paymentsLogger } from '../../../utils/logger';
|
|
23
|
+
import { closePaymentsDialog, openPaymentDetailsDialog, PAYMENT_EVENTS } from '../events';
|
|
41
24
|
|
|
42
25
|
// Payment creation schema
|
|
43
26
|
const PaymentCreateSchema = z.object({
|
|
@@ -5,19 +5,15 @@
|
|
|
5
5
|
|
|
6
6
|
'use client';
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import { AlertCircle, CheckCircle2, Clock, ExternalLink, RefreshCw, XCircle } from 'lucide-react';
|
|
9
|
+
import moment from 'moment';
|
|
10
|
+
import React, { useEffect, useState } from 'react';
|
|
11
|
+
|
|
9
12
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
DialogDescription,
|
|
13
|
-
DialogFooter,
|
|
14
|
-
DialogHeader,
|
|
15
|
-
DialogTitle,
|
|
16
|
-
Button,
|
|
17
|
-
TokenIcon,
|
|
18
|
-
CopyButton,
|
|
13
|
+
Button, CopyButton, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader,
|
|
14
|
+
DialogTitle, TokenIcon
|
|
19
15
|
} from '@djangocfg/ui-nextjs';
|
|
20
|
-
|
|
16
|
+
|
|
21
17
|
import { apiPayments } from '../../../api';
|
|
22
18
|
import { usePaymentsPaymentsRetrieve } from '../../../api/generated/ext_payments/_utils/hooks';
|
|
23
19
|
import { PAYMENT_EVENTS } from '../events';
|
|
@@ -66,18 +62,19 @@ export const PaymentDetailsDialog: React.FC = () => {
|
|
|
66
62
|
if (!payment?.expires_at) return;
|
|
67
63
|
|
|
68
64
|
const updateTimeLeft = () => {
|
|
69
|
-
const now =
|
|
70
|
-
const expires =
|
|
71
|
-
const diff = expires
|
|
65
|
+
const now = moment();
|
|
66
|
+
const expires = moment.utc(payment.expires_at!);
|
|
67
|
+
const diff = expires.diff(now);
|
|
72
68
|
|
|
73
69
|
if (diff <= 0) {
|
|
74
70
|
setTimeLeft('Expired');
|
|
75
71
|
return;
|
|
76
72
|
}
|
|
77
73
|
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
74
|
+
const duration = moment.duration(diff);
|
|
75
|
+
const hours = Math.floor(duration.asHours());
|
|
76
|
+
const minutes = duration.minutes();
|
|
77
|
+
const seconds = duration.seconds();
|
|
81
78
|
|
|
82
79
|
setTimeLeft(`${hours}h ${minutes}m ${seconds}s`);
|
|
83
80
|
};
|
|
@@ -264,7 +261,7 @@ export const PaymentDetailsDialog: React.FC = () => {
|
|
|
264
261
|
</div>
|
|
265
262
|
<div className="flex justify-between">
|
|
266
263
|
<span>Created</span>
|
|
267
|
-
<span>{
|
|
264
|
+
<span>{moment.utc(payment.created_at!).local().format('MMM D, YYYY HH:mm')}</span>
|
|
268
265
|
</div>
|
|
269
266
|
{payment.confirmations_count !== undefined && (
|
|
270
267
|
<div className="flex justify-between">
|
|
@@ -5,17 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
'use client';
|
|
7
7
|
|
|
8
|
+
import { Plus, RefreshCw, Wallet } from 'lucide-react';
|
|
9
|
+
import moment from 'moment';
|
|
8
10
|
import React from 'react';
|
|
11
|
+
|
|
9
12
|
import {
|
|
10
|
-
|
|
11
|
-
CardContent,
|
|
12
|
-
CardHeader,
|
|
13
|
-
CardTitle,
|
|
14
|
-
Button,
|
|
15
|
-
Badge,
|
|
16
|
-
Skeleton,
|
|
13
|
+
Badge, Button, Card, CardContent, CardHeader, CardTitle, Skeleton
|
|
17
14
|
} from '@djangocfg/ui-nextjs';
|
|
18
|
-
|
|
15
|
+
|
|
19
16
|
import { useOverviewContext } from '../../../../../contexts';
|
|
20
17
|
import { openCreatePaymentDialog } from '../../../events';
|
|
21
18
|
|
|
@@ -38,11 +35,7 @@ export const BalanceCard: React.FC = () => {
|
|
|
38
35
|
const formatDate = (dateStr?: string) => {
|
|
39
36
|
if (!dateStr) return 'No transactions yet';
|
|
40
37
|
try {
|
|
41
|
-
return
|
|
42
|
-
year: 'numeric',
|
|
43
|
-
month: 'short',
|
|
44
|
-
day: 'numeric',
|
|
45
|
-
});
|
|
38
|
+
return moment.utc(dateStr).local().format('MMM D, YYYY');
|
|
46
39
|
} catch {
|
|
47
40
|
return 'Invalid date';
|
|
48
41
|
}
|
|
@@ -5,17 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
'use client';
|
|
7
7
|
|
|
8
|
+
import { ExternalLink, History } from 'lucide-react';
|
|
9
|
+
import moment from 'moment';
|
|
8
10
|
import React from 'react';
|
|
11
|
+
|
|
9
12
|
import {
|
|
10
|
-
|
|
11
|
-
CardContent,
|
|
12
|
-
CardHeader,
|
|
13
|
-
CardTitle,
|
|
14
|
-
Button,
|
|
15
|
-
Badge,
|
|
16
|
-
Skeleton,
|
|
13
|
+
Badge, Button, Card, CardContent, CardHeader, CardTitle, Skeleton
|
|
17
14
|
} from '@djangocfg/ui-nextjs';
|
|
18
|
-
|
|
15
|
+
|
|
19
16
|
import { useOverviewContext } from '../../../../../contexts';
|
|
20
17
|
import { openPaymentDetailsDialog } from '../../../events';
|
|
21
18
|
|
|
@@ -35,9 +32,9 @@ export const RecentPayments: React.FC = () => {
|
|
|
35
32
|
const getRelativeTime = (date: string | null | undefined): string => {
|
|
36
33
|
if (!date) return 'N/A';
|
|
37
34
|
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const diffInSeconds =
|
|
35
|
+
const m = moment.utc(date).local();
|
|
36
|
+
const now = moment();
|
|
37
|
+
const diffInSeconds = now.diff(m, 'seconds');
|
|
41
38
|
|
|
42
39
|
if (diffInSeconds < 60) return 'Just now';
|
|
43
40
|
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
|