Skip to content

Commit dde115b

Browse files
Merge pull request #11 from botble/feat/export-counter
feat: Export counter
2 parents 1fd9d55 + 81f35a6 commit dde115b

File tree

10 files changed

+194
-52
lines changed

10 files changed

+194
-52
lines changed

resources/lang/en/data-synchronize.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
'heading' => 'Export :label',
4343

4444
'form' => [
45-
'total' => 'Total :total :name',
4645
'all_columns_disabled' => 'Following columns will be exported: :columns.',
4746
'columns' => 'Columns',
4847
'format' => 'Format',
@@ -51,5 +50,11 @@
5150

5251
'success_message' => 'Exported successfully.',
5352
'error_message' => 'Export failed.',
53+
54+
'empty_state' => [
55+
'title' => 'No data to export',
56+
'description' => 'Looks like there is no data to export.',
57+
'back' => 'Back to :page',
58+
],
5459
],
5560
];

resources/views/export.blade.php

Lines changed: 64 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,60 +15,82 @@ class="data-synchronize-export-form"
1515
<x-core::card.title>
1616
{{ $exporter->getHeading() }}
1717
</x-core::card.title>
18-
<x-core::card.subtitle class="ms-3">
19-
{{ trans('packages/data-synchronize::data-synchronize.export.form.total', ['total' => $exporter->getTotal(), 'name' => $exporter->getLabel()]) }}
20-
</x-core::card.subtitle>
2118
</x-core::card.header>
2219
@endif
2320

2421
<x-core::card.body>
25-
<div>
26-
@if($exporter->allColumnsIsDisabled())
27-
<x-core::form.label>
28-
{!! BaseHelper::clean(trans(
29-
'packages/data-synchronize::data-synchronize.export.form.all_columns_disabled',
30-
['columns' => Arr::join(array_map(fn ($column) => "<strong>{$column->getLabel()}</strong>", $exporter->getColumns()), ', ')]
31-
)) !!}
32-
</x-core::form.label>
33-
@else
34-
<x-core::form.label>
35-
{{ trans('packages/data-synchronize::data-synchronize.export.form.columns') }}
36-
<a href="javascript:void(0)" class="ms-2 text-primary" data-bb-toggle="check-all" data-bb-target=".export-column">Check all</a>
37-
</x-core::form.label>
22+
@if($exporter->hasDataToExport())
23+
@php
24+
$countersCount = count($exporter->getCounters());
25+
@endphp
3826

39-
<div @class(['row row-cols-1', 'row-cols-sm-2 row-cols-lg-3' => count($exporter->getColumns()) > 6])>
40-
@foreach ($exporter->getColumns() as $column)
41-
<x-core::form-group>
42-
<x-core::form.checkbox
43-
class="export-column"
44-
name="columns[]"
45-
:value="$column->getName()"
46-
:label="$column->getLabel()"
47-
:disabled="$column->isDisabled()"
48-
checked
49-
/>
50-
</x-core::form-group>
51-
@endforeach
27+
@if($countersCount)
28+
<div class="mb-5">
29+
<div @class(['row g-3', 'row-cols-2' => $countersCount > 1, 'row-cols-sm-3' => $countersCount > 2, 'row-cols-lg-4' => $countersCount > 3])>
30+
@foreach($exporter->getCounters() as $counter)
31+
<div class="col">
32+
<div class="text-center bg-body-tertiary rounded p-3">
33+
<h3 class="text-muted mb-2">{{ $counter->getLabel() }}</h3>
34+
<div class="fs-1 fw-bold">{{ $counter->getValue() }}</div>
35+
</div>
36+
</div>
37+
@endforeach
38+
</div>
5239
</div>
5340
@endif
54-
</div>
5541

56-
<x-core::form.radio-list
57-
:label="trans('packages/data-synchronize::data-synchronize.export.form.format')"
58-
name="format"
59-
:options="[
42+
<div>
43+
@if($exporter->allColumnsIsDisabled())
44+
<x-core::form.label>
45+
{!! BaseHelper::clean(trans(
46+
'packages/data-synchronize::data-synchronize.export.form.all_columns_disabled',
47+
['columns' => Arr::join(array_map(fn ($column) => "<strong>{$column->getLabel()}</strong>", $exporter->getColumns()), ', ')]
48+
)) !!}
49+
</x-core::form.label>
50+
@else
51+
<x-core::form.label>
52+
{{ trans('packages/data-synchronize::data-synchronize.export.form.columns') }}
53+
<a href="javascript:void(0)" class="ms-2 text-primary" data-bb-toggle="check-all" data-bb-target=".export-column">Check all</a>
54+
</x-core::form.label>
55+
56+
<div @class(['row row-cols-1', 'row-cols-sm-2 row-cols-lg-3' => count($exporter->getColumns()) > 6])>
57+
@foreach ($exporter->getColumns() as $column)
58+
<x-core::form-group>
59+
<x-core::form.checkbox
60+
class="export-column"
61+
name="columns[]"
62+
:value="$column->getName()"
63+
:label="$column->getLabel()"
64+
:disabled="$column->isDisabled()"
65+
checked
66+
/>
67+
</x-core::form-group>
68+
@endforeach
69+
</div>
70+
@endif
71+
</div>
72+
73+
<x-core::form.radio-list
74+
:label="trans('packages/data-synchronize::data-synchronize.export.form.format')"
75+
name="format"
76+
:options="[
6077
'csv' => 'CSV',
6178
'xlsx' => 'Excel',
6279
]"
63-
value="csv"
64-
>
65-
</x-core::form.radio-list>
80+
value="csv"
81+
>
82+
</x-core::form.radio-list>
83+
@else
84+
{!! $exporter->getEmptyStateContent() !!}
85+
@endif
6686
</x-core::card.body>
67-
<x-core::card.footer>
68-
<x-core::button type="submit" color="primary" :disabled="$exporter->getTotal() === 0">
69-
{{ trans('packages/data-synchronize::data-synchronize.export.form.export_button') }}
70-
</x-core::button>
71-
</x-core::card.footer>
87+
@if($exporter->hasDataToExport())
88+
<x-core::card.footer>
89+
<x-core::button type="submit" color="primary">
90+
{{ trans('packages/data-synchronize::data-synchronize.export.form.export_button') }}
91+
</x-core::button>
92+
</x-core::card.footer>
93+
@endif
7294
</x-core::card>
7395
</x-core::form>
7496
@stop
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<x-core::empty-state
2+
:$title
3+
:subtitle="$description"
4+
:$icon
5+
>
6+
@if($actionLabel)
7+
<x-slot:action>
8+
<x-core::button tag="a" :href="$actionUrl" color="primary" icon="ti ti-arrow-left">
9+
{{ $actionLabel }}
10+
</x-core::button>
11+
</x-slot:action>
12+
@endif
13+
</x-core::empty-state>

routes/web.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
AdminHelper::registerRoutes(function () {
1010
Route::group(['permission' => 'tools.data-synchronize'], function () {
1111
Route::get('tools/data-synchronize', [DataSynchronizeController::class, 'index'])
12-
->name('data-synchronize.tools.data-synchronize');
12+
->name('tools.data-synchronize');
1313

1414
Route::prefix('data-synchronize')->name('data-synchronize.')->group(function () {
1515
Route::post('upload', [UploadController::class, '__invoke'])
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace Botble\DataSynchronize\Concerns\Exporter;
4+
5+
use Illuminate\Contracts\View\View;
6+
7+
trait HasEmptyState
8+
{
9+
public function getEmptyStateTitle(): string
10+
{
11+
return trans('packages/data-synchronize::data-synchronize.export.empty_state.title');
12+
}
13+
14+
public function getEmptyStateDescription(): ?string
15+
{
16+
return trans('packages/data-synchronize::data-synchronize.export.empty_state.description');
17+
}
18+
19+
public function getEmptyStateIcon(): string
20+
{
21+
return 'ti ti-mood-empty';
22+
}
23+
24+
public function getEmptyStateActionLabel(): ?string
25+
{
26+
return trans(
27+
'packages/data-synchronize::data-synchronize.export.empty_state.back',
28+
['page' => trans('packages/data-synchronize::data-synchronize.tools.export_import_data')]
29+
);
30+
}
31+
32+
public function getEmptyStateActionUrl(): string
33+
{
34+
return route('tools.data-synchronize');
35+
}
36+
37+
public function getEmptyStateContent(): View|string
38+
{
39+
return view('packages/data-synchronize::partials.empty-state', [
40+
'title' => $this->getEmptyStateTitle(),
41+
'description' => $this->getEmptyStateDescription(),
42+
'icon' => $this->getEmptyStateIcon(),
43+
'actionUrl' => $this->getEmptyStateActionUrl(),
44+
'actionLabel' => $this->getEmptyStateActionLabel(),
45+
]);
46+
}
47+
}

src/Exporter/ExportCounter.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace Botble\DataSynchronize\Exporter;
4+
5+
class ExportCounter
6+
{
7+
protected string $value;
8+
9+
protected string $label;
10+
11+
public static function make(): static
12+
{
13+
return new static();
14+
}
15+
16+
public function value(string $value): static
17+
{
18+
$this->value = $value;
19+
20+
return $this;
21+
}
22+
23+
public function label(string $label): static
24+
{
25+
$this->label = $label;
26+
27+
return $this;
28+
}
29+
30+
public function getValue(): string
31+
{
32+
return $this->value;
33+
}
34+
35+
public function getLabel(): string
36+
{
37+
return $this->label;
38+
}
39+
}

src/Exporter/Exporter.php

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Botble\Base\Facades\Assets;
66
use Botble\Base\Facades\BaseHelper;
7+
use Botble\DataSynchronize\Concerns\Exporter\HasEmptyState;
78
use Botble\DataSynchronize\Enums\ExportColumnType;
89
use Illuminate\Contracts\View\View;
910
use Maatwebsite\Excel\Concerns\FromCollection;
@@ -23,6 +24,8 @@
2324

2425
abstract class Exporter implements FromCollection, ShouldAutoSize, WithColumnFormatting, WithEvents, WithHeadings, WithMapping
2526
{
27+
use HasEmptyState;
28+
2629
protected ?array $acceptedColumns = [];
2730

2831
protected string $format = Excel::XLSX;
@@ -34,6 +37,11 @@ abstract class Exporter implements FromCollection, ShouldAutoSize, WithColumnFor
3437
*/
3538
abstract public function columns(): array;
3639

40+
public function counters(): array
41+
{
42+
return [];
43+
}
44+
3745
public function getLabel(): string
3846
{
3947
return str(static::class)
@@ -44,11 +52,6 @@ public function getLabel(): string
4452
->title();
4553
}
4654

47-
public function getTotal(): int
48-
{
49-
return apply_filters('data_synchronize_exporter_total', $this->collection()->count(), $this);
50-
}
51-
5255
public function getHeading(): string
5356
{
5457
return trans(
@@ -57,6 +60,19 @@ public function getHeading(): string
5760
);
5861
}
5962

63+
/**
64+
* @return \Botble\DataSynchronize\Exporter\ExportCounter[]
65+
*/
66+
public function getCounters(): array
67+
{
68+
return apply_filters('data_synchronize_exporter_counters', $this->counters(), $this);
69+
}
70+
71+
public function hasDataToExport(): bool
72+
{
73+
return true;
74+
}
75+
6076
public function headings(): array
6177
{
6278
return array_map(fn (ExportColumn $column) => $column->getLabel(), $this->getAcceptedColumns());

src/Http/Controllers/ExportController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ protected function breadcrumb(): Breadcrumb
2222
{
2323
return parent::breadcrumb()
2424
->add(trans('core/base::layouts.tools'))
25-
->add(trans('packages/data-synchronize::data-synchronize.tools.export_import_data'), route('data-synchronize.tools.data-synchronize'));
25+
->add(trans('packages/data-synchronize::data-synchronize.tools.export_import_data'), route('tools.data-synchronize'));
2626
}
2727

2828
public function index()

src/Http/Controllers/ImportController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ protected function breadcrumb(): Breadcrumb
1919
{
2020
return parent::breadcrumb()
2121
->add(trans('core/base::layouts.tools'))
22-
->add(trans('packages/data-synchronize::data-synchronize.tools.export_import_data'), route('data-synchronize.tools.data-synchronize'));
22+
->add(trans('packages/data-synchronize::data-synchronize.tools.export_import_data'), route('tools.data-synchronize'));
2323
}
2424

2525
public function index()

src/Providers/DataSynchronizeServiceProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ protected function registerDashboardMenu(): self
7070
'priority' => 9000,
7171
'name' => 'packages/data-synchronize::data-synchronize.tools.export_import_data',
7272
'icon' => 'ti ti-package-import',
73-
'route' => 'data-synchronize.tools.data-synchronize',
73+
'route' => 'tools.data-synchronize',
7474
]);
7575
});
7676

0 commit comments

Comments
 (0)