@hed-hog/finance 0.0.299 → 0.0.301
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/dto/create-bank-account.dto.d.ts +1 -0
- package/dist/dto/create-bank-account.dto.d.ts.map +1 -1
- package/dist/dto/create-bank-account.dto.js +7 -0
- package/dist/dto/create-bank-account.dto.js.map +1 -1
- package/dist/dto/update-bank-account.dto.d.ts +1 -0
- package/dist/dto/update-bank-account.dto.d.ts.map +1 -1
- package/dist/dto/update-bank-account.dto.js +7 -0
- package/dist/dto/update-bank-account.dto.js.map +1 -1
- package/dist/finance-bank-accounts.controller.d.ts +3 -0
- package/dist/finance-bank-accounts.controller.d.ts.map +1 -1
- package/dist/finance-data.controller.d.ts +1 -0
- package/dist/finance-data.controller.d.ts.map +1 -1
- package/dist/finance.contract-activated.subscriber.d.ts +24 -0
- package/dist/finance.contract-activated.subscriber.d.ts.map +1 -0
- package/dist/finance.contract-activated.subscriber.js +519 -0
- package/dist/finance.contract-activated.subscriber.js.map +1 -0
- package/dist/finance.contract-activated.subscriber.spec.d.ts +2 -0
- package/dist/finance.contract-activated.subscriber.spec.d.ts.map +1 -0
- package/dist/finance.contract-activated.subscriber.spec.js +302 -0
- package/dist/finance.contract-activated.subscriber.spec.js.map +1 -0
- package/dist/finance.module.d.ts.map +1 -1
- package/dist/finance.module.js +6 -1
- package/dist/finance.module.js.map +1 -1
- package/dist/finance.service.d.ts +4 -0
- package/dist/finance.service.d.ts.map +1 -1
- package/dist/finance.service.js +5 -0
- package/dist/finance.service.js.map +1 -1
- package/hedhog/data/dashboard.yaml +6 -0
- package/hedhog/data/dashboard_component.yaml +72 -17
- package/hedhog/data/dashboard_component_role.yaml +30 -0
- package/hedhog/data/dashboard_item.yaml +155 -0
- package/hedhog/data/dashboard_role.yaml +6 -0
- package/hedhog/data/role_menu.yaml +6 -0
- package/hedhog/data/role_route.yaml +127 -0
- package/hedhog/frontend/app/_components/finance-layout.tsx.ejs +108 -0
- package/hedhog/frontend/app/accounts-payable/approvals/page.tsx.ejs +91 -106
- package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +1306 -1145
- package/hedhog/frontend/app/accounts-receivable/collections-default/page.tsx.ejs +288 -268
- package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +491 -351
- package/hedhog/frontend/app/administration/audit-logs/page.tsx.ejs +157 -173
- package/hedhog/frontend/app/administration/categories/page.tsx.ejs +44 -62
- package/hedhog/frontend/app/administration/cost-centers/page.tsx.ejs +62 -80
- package/hedhog/frontend/app/administration/period-close/page.tsx.ejs +151 -170
- package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +586 -224
- package/hedhog/frontend/app/cash-and-banks/bank-reconciliation/page.tsx.ejs +204 -226
- package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +122 -140
- package/hedhog/frontend/app/cash-and-banks/transfers/page.tsx.ejs +32 -49
- package/hedhog/frontend/app/planning/cash-flow-forecast/page.tsx.ejs +84 -108
- package/hedhog/frontend/app/planning/receivables-calendar/page.tsx.ejs +53 -70
- package/hedhog/frontend/app/planning/scenarios/page.tsx.ejs +98 -95
- package/hedhog/frontend/app/reports/actual-vs-forecast/page.tsx.ejs +100 -125
- package/hedhog/frontend/app/reports/aging-default/page.tsx.ejs +77 -105
- package/hedhog/frontend/app/reports/cash-position/page.tsx.ejs +99 -134
- package/hedhog/frontend/app/reports/overview-results/page.tsx.ejs +147 -182
- package/hedhog/frontend/app/reports/top-customers/page.tsx.ejs +49 -61
- package/hedhog/frontend/app/reports/top-operational-expenses/page.tsx.ejs +49 -67
- package/hedhog/frontend/messages/en.json +224 -70
- package/hedhog/frontend/messages/pt.json +224 -70
- package/hedhog/frontend/widgets/alerts.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/bank-reconciliation-status.tsx.ejs +142 -0
- package/hedhog/frontend/widgets/cash-balance-kpi.tsx.ejs +9 -9
- package/hedhog/frontend/widgets/cash-flow-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/default-kpi.tsx.ejs +9 -9
- package/hedhog/frontend/widgets/payable-30d-kpi.tsx.ejs +9 -9
- package/hedhog/frontend/widgets/pending-approvals-kpi.tsx.ejs +78 -0
- package/hedhog/frontend/widgets/pending-approvals-list.tsx.ejs +147 -0
- package/hedhog/frontend/widgets/pending-reconciliation-kpi.tsx.ejs +84 -0
- package/hedhog/frontend/widgets/receivable-30d-kpi.tsx.ejs +9 -9
- package/hedhog/frontend/widgets/receivable-aging-analysis.tsx.ejs +163 -0
- package/hedhog/frontend/widgets/upcoming-payable.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/upcoming-receivable.tsx.ejs +1 -1
- package/hedhog/table/bank_account.yaml +8 -0
- package/package.json +7 -6
- package/src/dto/create-bank-account.dto.ts +7 -1
- package/src/dto/update-bank-account.dto.ts +7 -1
- package/src/finance.contract-activated.subscriber.spec.ts +392 -0
- package/src/finance.contract-activated.subscriber.ts +780 -0
- package/src/finance.module.ts +6 -1
- package/src/finance.service.ts +4 -0
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { FinancePageSection } from '@/app/(app)/(libraries)/finance/_components/finance-layout';
|
|
3
4
|
import { Page, PageHeader } from '@/components/entity-list';
|
|
4
5
|
import { Badge } from '@/components/ui/badge';
|
|
5
|
-
import {
|
|
6
|
-
Card,
|
|
7
|
-
CardContent,
|
|
8
|
-
CardDescription,
|
|
9
|
-
CardHeader,
|
|
10
|
-
CardTitle,
|
|
11
|
-
} from '@/components/ui/card';
|
|
6
|
+
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
12
7
|
import { Input } from '@/components/ui/input';
|
|
13
8
|
import { Label } from '@/components/ui/label';
|
|
14
9
|
import { Money } from '@/components/ui/money';
|
|
@@ -108,6 +103,56 @@ export default function OverviewResultsReportPage() {
|
|
|
108
103
|
[data.rows, groupBy, locale]
|
|
109
104
|
);
|
|
110
105
|
const totals = data.totals;
|
|
106
|
+
const summaryCards = [
|
|
107
|
+
{
|
|
108
|
+
key: 'revenue',
|
|
109
|
+
title: t('cards.revenue'),
|
|
110
|
+
value: <Money value={totals.faturamento} />,
|
|
111
|
+
icon: TrendingUp,
|
|
112
|
+
layout: 'compact' as const,
|
|
113
|
+
iconContainerClassName: 'bg-blue-500/10 text-blue-600',
|
|
114
|
+
accentClassName: 'from-blue-500/20 via-sky-500/10 to-transparent',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
key: 'expensesAndLoans',
|
|
118
|
+
title: t('cards.expensesAndLoans'),
|
|
119
|
+
value: <Money value={totals.despesasEmprestimos} />,
|
|
120
|
+
icon: TrendingDown,
|
|
121
|
+
layout: 'compact' as const,
|
|
122
|
+
iconContainerClassName: 'bg-orange-500/10 text-orange-600',
|
|
123
|
+
accentClassName: 'from-orange-500/20 via-amber-500/10 to-transparent',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
key: 'difference',
|
|
127
|
+
title: t('cards.resultDifference'),
|
|
128
|
+
value: <Money value={totals.diferenca} showSign />,
|
|
129
|
+
icon: totals.diferenca >= 0 ? TrendingUp : TrendingDown,
|
|
130
|
+
layout: 'compact' as const,
|
|
131
|
+
valueClassName: totals.diferenca >= 0 ? 'text-green-600' : 'text-red-600',
|
|
132
|
+
iconContainerClassName:
|
|
133
|
+
totals.diferenca >= 0
|
|
134
|
+
? 'bg-green-500/10 text-green-600'
|
|
135
|
+
: 'bg-red-500/10 text-red-600',
|
|
136
|
+
accentClassName:
|
|
137
|
+
totals.diferenca >= 0
|
|
138
|
+
? 'from-green-500/20 via-emerald-500/10 to-transparent'
|
|
139
|
+
: 'from-red-500/20 via-rose-500/10 to-transparent',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
key: 'margin',
|
|
143
|
+
title: t('cards.margin'),
|
|
144
|
+
value: `${totals.margem.toFixed(1)}%`,
|
|
145
|
+
description: (
|
|
146
|
+
<Badge variant={totals.margem >= 0 ? 'default' : 'destructive'}>
|
|
147
|
+
{totals.margem >= 0 ? t('status.positive') : t('status.negative')}
|
|
148
|
+
</Badge>
|
|
149
|
+
),
|
|
150
|
+
icon: Target,
|
|
151
|
+
layout: 'compact' as const,
|
|
152
|
+
iconContainerClassName: 'bg-violet-500/10 text-violet-600',
|
|
153
|
+
accentClassName: 'from-violet-500/20 via-fuchsia-500/10 to-transparent',
|
|
154
|
+
},
|
|
155
|
+
];
|
|
111
156
|
|
|
112
157
|
return (
|
|
113
158
|
<Page>
|
|
@@ -121,182 +166,102 @@ export default function OverviewResultsReportPage() {
|
|
|
121
166
|
]}
|
|
122
167
|
/>
|
|
123
168
|
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
<
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
>
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
</CardContent>
|
|
168
|
-
</Card>
|
|
169
|
-
|
|
170
|
-
<div className="grid gap-3 md:grid-cols-4">
|
|
171
|
-
<Card>
|
|
172
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-1 pt-3 px-4">
|
|
173
|
-
<CardTitle className="text-xs font-medium tracking-wide text-muted-foreground uppercase">
|
|
174
|
-
{t('cards.revenue')}
|
|
175
|
-
</CardTitle>
|
|
176
|
-
<div className="rounded-full bg-blue-500/10 p-1.5">
|
|
177
|
-
<TrendingUp className="h-4 w-4 text-blue-600" />
|
|
178
|
-
</div>
|
|
179
|
-
</CardHeader>
|
|
180
|
-
<CardContent className="pb-3 pt-0 px-4">
|
|
181
|
-
<div className="text-xl font-bold">
|
|
182
|
-
<Money value={totals.faturamento} />
|
|
183
|
-
</div>
|
|
184
|
-
</CardContent>
|
|
185
|
-
</Card>
|
|
186
|
-
|
|
187
|
-
<Card>
|
|
188
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-1 pt-3 px-4">
|
|
189
|
-
<CardTitle className="text-xs font-medium tracking-wide text-muted-foreground uppercase">
|
|
190
|
-
{t('cards.expensesAndLoans')}
|
|
191
|
-
</CardTitle>
|
|
192
|
-
<div className="rounded-full bg-orange-500/10 p-1.5">
|
|
193
|
-
<TrendingDown className="h-4 w-4 text-orange-600" />
|
|
194
|
-
</div>
|
|
195
|
-
</CardHeader>
|
|
196
|
-
<CardContent className="pb-3 pt-0 px-4">
|
|
197
|
-
<div className="text-xl font-bold">
|
|
198
|
-
<Money value={totals.despesasEmprestimos} />
|
|
199
|
-
</div>
|
|
200
|
-
</CardContent>
|
|
201
|
-
</Card>
|
|
202
|
-
|
|
203
|
-
<Card>
|
|
204
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-1 pt-3 px-4">
|
|
205
|
-
<CardTitle className="text-xs font-medium tracking-wide text-muted-foreground uppercase">
|
|
206
|
-
{t('cards.resultDifference')}
|
|
207
|
-
</CardTitle>
|
|
208
|
-
<div
|
|
209
|
-
className={`rounded-full p-1.5 ${totals.diferenca >= 0 ? 'bg-green-500/10' : 'bg-red-500/10'}`}
|
|
210
|
-
>
|
|
211
|
-
{totals.diferenca >= 0 ? (
|
|
212
|
-
<TrendingUp className="h-4 w-4 text-green-600" />
|
|
213
|
-
) : (
|
|
214
|
-
<TrendingDown className="h-4 w-4 text-red-600" />
|
|
215
|
-
)}
|
|
216
|
-
</div>
|
|
217
|
-
</CardHeader>
|
|
218
|
-
<CardContent className="pb-3 pt-0 px-4">
|
|
219
|
-
<div
|
|
220
|
-
className={`text-xl font-bold ${totals.diferenca >= 0 ? 'text-green-600' : 'text-red-600'}`}
|
|
221
|
-
>
|
|
222
|
-
<Money value={totals.diferenca} showSign />
|
|
223
|
-
</div>
|
|
224
|
-
</CardContent>
|
|
225
|
-
</Card>
|
|
169
|
+
<FinancePageSection
|
|
170
|
+
title={t('filters.title')}
|
|
171
|
+
description={t('filters.description')}
|
|
172
|
+
contentClassName="grid gap-4 p-4 md:grid-cols-3 sm:p-5"
|
|
173
|
+
>
|
|
174
|
+
<div className="space-y-2">
|
|
175
|
+
<Label htmlFor="from">{t('filters.from')}</Label>
|
|
176
|
+
<Input
|
|
177
|
+
id="from"
|
|
178
|
+
type="date"
|
|
179
|
+
value={from}
|
|
180
|
+
onChange={(event) => setFrom(event.target.value)}
|
|
181
|
+
max={to}
|
|
182
|
+
/>
|
|
183
|
+
</div>
|
|
184
|
+
<div className="space-y-2">
|
|
185
|
+
<Label htmlFor="to">{t('filters.to')}</Label>
|
|
186
|
+
<Input
|
|
187
|
+
id="to"
|
|
188
|
+
type="date"
|
|
189
|
+
value={to}
|
|
190
|
+
onChange={(event) => setTo(event.target.value)}
|
|
191
|
+
min={from}
|
|
192
|
+
/>
|
|
193
|
+
</div>
|
|
194
|
+
<div className="space-y-2">
|
|
195
|
+
<Label>{t('filters.groupBy')}</Label>
|
|
196
|
+
<Select
|
|
197
|
+
value={groupBy}
|
|
198
|
+
onValueChange={(value) => setGroupBy(value as GroupBy)}
|
|
199
|
+
>
|
|
200
|
+
<SelectTrigger>
|
|
201
|
+
<SelectValue />
|
|
202
|
+
</SelectTrigger>
|
|
203
|
+
<SelectContent>
|
|
204
|
+
<SelectItem value="day">{t('groupBy.day')}</SelectItem>
|
|
205
|
+
<SelectItem value="week">{t('groupBy.week')}</SelectItem>
|
|
206
|
+
<SelectItem value="month">{t('groupBy.month')}</SelectItem>
|
|
207
|
+
<SelectItem value="year">{t('groupBy.year')}</SelectItem>
|
|
208
|
+
</SelectContent>
|
|
209
|
+
</Select>
|
|
210
|
+
</div>
|
|
211
|
+
</FinancePageSection>
|
|
226
212
|
|
|
227
|
-
|
|
228
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-1 pt-3 px-4">
|
|
229
|
-
<CardTitle className="text-xs font-medium tracking-wide text-muted-foreground uppercase">
|
|
230
|
-
{t('cards.margin')}
|
|
231
|
-
</CardTitle>
|
|
232
|
-
<div className="rounded-full bg-violet-500/10 p-1.5">
|
|
233
|
-
<Target className="h-4 w-4 text-violet-600" />
|
|
234
|
-
</div>
|
|
235
|
-
</CardHeader>
|
|
236
|
-
<CardContent className="pb-3 pt-0 px-4">
|
|
237
|
-
<div className="text-xl font-bold">{totals.margem.toFixed(1)}%</div>
|
|
238
|
-
<Badge
|
|
239
|
-
className="mt-1"
|
|
240
|
-
variant={totals.margem >= 0 ? 'default' : 'destructive'}
|
|
241
|
-
>
|
|
242
|
-
{totals.margem >= 0 ? t('status.positive') : t('status.negative')}
|
|
243
|
-
</Badge>
|
|
244
|
-
</CardContent>
|
|
245
|
-
</Card>
|
|
246
|
-
</div>
|
|
213
|
+
<KpiCardsGrid items={summaryCards} columns={4} />
|
|
247
214
|
|
|
248
|
-
<
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
<
|
|
254
|
-
<
|
|
255
|
-
<
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
</CardContent>
|
|
292
|
-
</Card>
|
|
215
|
+
<FinancePageSection
|
|
216
|
+
title={t('chart.title')}
|
|
217
|
+
description={t('chart.description')}
|
|
218
|
+
contentClassName="p-4 sm:p-5"
|
|
219
|
+
>
|
|
220
|
+
<ResponsiveContainer width="100%" height={360}>
|
|
221
|
+
<LineChart data={rows}>
|
|
222
|
+
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
|
|
223
|
+
<XAxis dataKey="label" tick={{ fontSize: 12 }} />
|
|
224
|
+
<YAxis
|
|
225
|
+
tick={{ fontSize: 12 }}
|
|
226
|
+
tickFormatter={(value) => `${(value / 1000).toFixed(0)}k`}
|
|
227
|
+
/>
|
|
228
|
+
<Tooltip content={renderSolidTooltip} />
|
|
229
|
+
<Legend />
|
|
230
|
+
<Line
|
|
231
|
+
type="monotone"
|
|
232
|
+
dataKey="faturamento"
|
|
233
|
+
name={t('chart.revenueLabel')}
|
|
234
|
+
stroke={LINE_COLORS.faturamento}
|
|
235
|
+
strokeWidth={3}
|
|
236
|
+
dot={false}
|
|
237
|
+
/>
|
|
238
|
+
<Line
|
|
239
|
+
type="monotone"
|
|
240
|
+
dataKey="despesasEmprestimos"
|
|
241
|
+
name={t('chart.expensesLabel')}
|
|
242
|
+
stroke={LINE_COLORS.despesasEmprestimos}
|
|
243
|
+
strokeWidth={3}
|
|
244
|
+
dot={false}
|
|
245
|
+
/>
|
|
246
|
+
<Line
|
|
247
|
+
type="monotone"
|
|
248
|
+
dataKey="diferenca"
|
|
249
|
+
name={t('chart.differenceLabel')}
|
|
250
|
+
stroke={LINE_COLORS.diferenca}
|
|
251
|
+
strokeWidth={2}
|
|
252
|
+
strokeDasharray="6 4"
|
|
253
|
+
dot={false}
|
|
254
|
+
/>
|
|
255
|
+
</LineChart>
|
|
256
|
+
</ResponsiveContainer>
|
|
257
|
+
</FinancePageSection>
|
|
293
258
|
|
|
294
|
-
<
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
<
|
|
259
|
+
<FinancePageSection
|
|
260
|
+
title={t('table.title')}
|
|
261
|
+
description={t('table.description')}
|
|
262
|
+
contentClassName="p-4 sm:p-5"
|
|
263
|
+
>
|
|
264
|
+
<div className="overflow-x-auto">
|
|
300
265
|
<Table>
|
|
301
266
|
<TableHeader>
|
|
302
267
|
<TableRow>
|
|
@@ -348,8 +313,8 @@ export default function OverviewResultsReportPage() {
|
|
|
348
313
|
)}
|
|
349
314
|
</TableBody>
|
|
350
315
|
</Table>
|
|
351
|
-
</
|
|
352
|
-
</
|
|
316
|
+
</div>
|
|
317
|
+
</FinancePageSection>
|
|
353
318
|
</Page>
|
|
354
319
|
);
|
|
355
320
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { FinancePageSection } from '@/app/(app)/(libraries)/finance/_components/finance-layout';
|
|
3
4
|
import { Page, PageHeader } from '@/components/entity-list';
|
|
4
5
|
import { Button } from '@/components/ui/button';
|
|
5
6
|
import {
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
CardTitle,
|
|
11
12
|
} from '@/components/ui/card';
|
|
12
13
|
import { Input } from '@/components/ui/input';
|
|
14
|
+
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
13
15
|
import { Money } from '@/components/ui/money';
|
|
14
16
|
import {
|
|
15
17
|
Select,
|
|
@@ -90,6 +92,41 @@ export default function TopCustomersReportPage() {
|
|
|
90
92
|
setAppliedFilters(filters);
|
|
91
93
|
};
|
|
92
94
|
|
|
95
|
+
const summaryCards = [
|
|
96
|
+
{
|
|
97
|
+
key: 'total',
|
|
98
|
+
title: t('cards.total'),
|
|
99
|
+
value: <Money value={viewData.total} />,
|
|
100
|
+
icon: Users,
|
|
101
|
+
layout: 'compact' as const,
|
|
102
|
+
iconContainerClassName: 'bg-blue-500/10 text-blue-600',
|
|
103
|
+
accentClassName: 'from-blue-500/20 via-sky-500/10 to-transparent',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
key: 'top5Concentration',
|
|
107
|
+
title: t('cards.top5Concentration'),
|
|
108
|
+
value: `${viewData.top5Percent.toFixed(1)}%`,
|
|
109
|
+
icon: PieChartIcon,
|
|
110
|
+
layout: 'compact' as const,
|
|
111
|
+
iconContainerClassName: 'bg-purple-500/10 text-purple-600',
|
|
112
|
+
accentClassName: 'from-purple-500/20 via-fuchsia-500/10 to-transparent',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
key: 'leader',
|
|
116
|
+
title: t('cards.leader'),
|
|
117
|
+
value: viewData.leader?.customer || '-',
|
|
118
|
+
description: viewData.leader ? (
|
|
119
|
+
<Money value={viewData.leader.value} />
|
|
120
|
+
) : (
|
|
121
|
+
'-'
|
|
122
|
+
),
|
|
123
|
+
icon: Crown,
|
|
124
|
+
layout: 'compact' as const,
|
|
125
|
+
iconContainerClassName: 'bg-amber-500/10 text-amber-500',
|
|
126
|
+
accentClassName: 'from-amber-500/20 via-yellow-500/10 to-transparent',
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
|
|
93
130
|
const renderSolidTooltip = ({
|
|
94
131
|
active,
|
|
95
132
|
payload,
|
|
@@ -165,7 +202,7 @@ export default function TopCustomersReportPage() {
|
|
|
165
202
|
}))
|
|
166
203
|
}
|
|
167
204
|
max={filters.to}
|
|
168
|
-
className="w-full lg:w-
|
|
205
|
+
className="w-full lg:w-42.5"
|
|
169
206
|
aria-label={t('filters.fromAria')}
|
|
170
207
|
placeholder={t('filters.fromPlaceholder')}
|
|
171
208
|
/>
|
|
@@ -180,7 +217,7 @@ export default function TopCustomersReportPage() {
|
|
|
180
217
|
}))
|
|
181
218
|
}
|
|
182
219
|
min={filters.from}
|
|
183
|
-
className="w-full lg:w-
|
|
220
|
+
className="w-full lg:w-42.5"
|
|
184
221
|
aria-label={t('filters.toAria')}
|
|
185
222
|
placeholder={t('filters.toPlaceholder')}
|
|
186
223
|
/>
|
|
@@ -194,7 +231,7 @@ export default function TopCustomersReportPage() {
|
|
|
194
231
|
}
|
|
195
232
|
>
|
|
196
233
|
<SelectTrigger
|
|
197
|
-
className="w-full lg:w-
|
|
234
|
+
className="w-full lg:w-37.5"
|
|
198
235
|
aria-label={t('filters.groupByAria')}
|
|
199
236
|
>
|
|
200
237
|
<SelectValue placeholder={t('filters.groupByPlaceholder')} />
|
|
@@ -215,56 +252,7 @@ export default function TopCustomersReportPage() {
|
|
|
215
252
|
</Button>
|
|
216
253
|
</form>
|
|
217
254
|
|
|
218
|
-
<
|
|
219
|
-
<Card>
|
|
220
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-1 pt-3 px-4">
|
|
221
|
-
<CardTitle className="text-xs font-medium tracking-wide text-muted-foreground uppercase">
|
|
222
|
-
{t('cards.total')}
|
|
223
|
-
</CardTitle>
|
|
224
|
-
<div className="rounded-full bg-blue-500/10 p-1.5">
|
|
225
|
-
<Users className="h-4 w-4 text-blue-600" />
|
|
226
|
-
</div>
|
|
227
|
-
</CardHeader>
|
|
228
|
-
<CardContent className="pb-3 pt-0 px-4">
|
|
229
|
-
<div className="text-xl font-bold">
|
|
230
|
-
<Money value={viewData.total} />
|
|
231
|
-
</div>
|
|
232
|
-
</CardContent>
|
|
233
|
-
</Card>
|
|
234
|
-
<Card>
|
|
235
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-1 pt-3 px-4">
|
|
236
|
-
<CardTitle className="text-xs font-medium tracking-wide text-muted-foreground uppercase">
|
|
237
|
-
{t('cards.top5Concentration')}
|
|
238
|
-
</CardTitle>
|
|
239
|
-
<div className="rounded-full bg-purple-500/10 p-1.5">
|
|
240
|
-
<PieChartIcon className="h-4 w-4 text-purple-600" />
|
|
241
|
-
</div>
|
|
242
|
-
</CardHeader>
|
|
243
|
-
<CardContent className="pb-3 pt-0 px-4">
|
|
244
|
-
<div className="text-xl font-bold">
|
|
245
|
-
{viewData.top5Percent.toFixed(1)}%
|
|
246
|
-
</div>
|
|
247
|
-
</CardContent>
|
|
248
|
-
</Card>
|
|
249
|
-
<Card>
|
|
250
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-1 pt-3 px-4">
|
|
251
|
-
<CardTitle className="text-xs font-medium tracking-wide text-muted-foreground uppercase">
|
|
252
|
-
{t('cards.leader')}
|
|
253
|
-
</CardTitle>
|
|
254
|
-
<div className="rounded-full bg-amber-500/10 p-1.5">
|
|
255
|
-
<Crown className="h-4 w-4 text-amber-500" />
|
|
256
|
-
</div>
|
|
257
|
-
</CardHeader>
|
|
258
|
-
<CardContent className="pb-3 pt-0 px-4">
|
|
259
|
-
<div className="text-sm font-medium">
|
|
260
|
-
{viewData.leader?.customer || '-'}
|
|
261
|
-
</div>
|
|
262
|
-
<div className="text-xs text-muted-foreground">
|
|
263
|
-
{viewData.leader ? <Money value={viewData.leader.value} /> : '-'}
|
|
264
|
-
</div>
|
|
265
|
-
</CardContent>
|
|
266
|
-
</Card>
|
|
267
|
-
</div>
|
|
255
|
+
<KpiCardsGrid items={summaryCards} columns={3} />
|
|
268
256
|
|
|
269
257
|
<div className="grid gap-3 xl:grid-cols-5">
|
|
270
258
|
<Card className="xl:col-span-3">
|
|
@@ -362,12 +350,12 @@ export default function TopCustomersReportPage() {
|
|
|
362
350
|
</Card>
|
|
363
351
|
</div>
|
|
364
352
|
|
|
365
|
-
<
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
<
|
|
353
|
+
<FinancePageSection
|
|
354
|
+
title={t('table.title')}
|
|
355
|
+
description={t('table.description')}
|
|
356
|
+
contentClassName="p-4 sm:p-5"
|
|
357
|
+
>
|
|
358
|
+
<div className="overflow-x-auto">
|
|
371
359
|
<Table>
|
|
372
360
|
<TableHeader>
|
|
373
361
|
<TableRow>
|
|
@@ -412,8 +400,8 @@ export default function TopCustomersReportPage() {
|
|
|
412
400
|
)}
|
|
413
401
|
</TableBody>
|
|
414
402
|
</Table>
|
|
415
|
-
</
|
|
416
|
-
</
|
|
403
|
+
</div>
|
|
404
|
+
</FinancePageSection>
|
|
417
405
|
</Page>
|
|
418
406
|
);
|
|
419
407
|
}
|