feat: Add visitor tracking functionality with Filament resource and footer statistics.
This commit is contained in:
parent
a4f85c53c5
commit
9742097d2b
13
app/Filament/Resources/Visitors/Pages/ManageVisitors.php
Normal file
13
app/Filament/Resources/Visitors/Pages/ManageVisitors.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Visitors\Pages;
|
||||
|
||||
use App\Filament\Resources\Visitors\VisitorResource;
|
||||
use Filament\Resources\Pages\ManageRecords;
|
||||
|
||||
class ManageVisitors extends ManageRecords
|
||||
{
|
||||
protected static ?string $title = 'Pengunjung';
|
||||
|
||||
protected static string $resource = VisitorResource::class;
|
||||
}
|
||||
101
app/Filament/Resources/Visitors/VisitorResource.php
Normal file
101
app/Filament/Resources/Visitors/VisitorResource.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\Visitors;
|
||||
|
||||
use App\Filament\Resources\Visitors\Pages\ManageVisitors;
|
||||
use App\Models\Visitor;
|
||||
use BackedEnum;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\Filter;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
use UnitEnum;
|
||||
|
||||
class VisitorResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Visitor::class;
|
||||
|
||||
protected static string|UnitEnum|null $navigationGroup = 'Monitoring';
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::ChartBar;
|
||||
|
||||
protected static ?string $navigationLabel = 'Pengunjung';
|
||||
|
||||
protected static ?int $navigationSort = 7;
|
||||
|
||||
protected static ?string $slug = 'monitoring/visitors';
|
||||
|
||||
public static function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('date')
|
||||
->label('Tanggal & Waktu')
|
||||
->date('l, d F Y')
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('route')
|
||||
->label('Halaman')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('method')
|
||||
->label('Method')
|
||||
->badge()
|
||||
->color(fn (string $state): string => match ($state) {
|
||||
'GET' => 'success',
|
||||
'POST' => 'warning',
|
||||
default => 'gray',
|
||||
}),
|
||||
|
||||
TextColumn::make('status')
|
||||
->label('Status')
|
||||
->badge()
|
||||
->color(fn (int $state): string => $state >= 200 && $state < 300 ? 'success' : 'danger'),
|
||||
|
||||
TextColumn::make('ip')
|
||||
->label('IP Address')
|
||||
->searchable(),
|
||||
|
||||
TextColumn::make('counter')
|
||||
->label('Hits')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('user.name')
|
||||
->label('User')
|
||||
->placeholder('Guest'),
|
||||
])
|
||||
->defaultSort('date', 'desc')
|
||||
->filters([
|
||||
SelectFilter::make('method')
|
||||
->options([
|
||||
'GET' => 'GET',
|
||||
'POST' => 'POST',
|
||||
]),
|
||||
|
||||
Filter::make('date')
|
||||
->schema([
|
||||
DatePicker::make('from')->time(),
|
||||
DatePicker::make('until')->time(),
|
||||
])
|
||||
->query(function ($query, array $data) {
|
||||
return $query
|
||||
->when($data['from'], fn ($q) => $q->whereDate('date', '>=', $data['from']))
|
||||
->when($data['until'], fn ($q) => $q->whereDate('date', '<=', $data['until']));
|
||||
}),
|
||||
])
|
||||
->recordActions([])
|
||||
->toolbarActions([]);
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
'index' => ManageVisitors::route('/'),
|
||||
];
|
||||
}
|
||||
}
|
||||
55
app/Http/Middleware/TrackVisitor.php
Normal file
55
app/Http/Middleware/TrackVisitor.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\Visitor;
|
||||
use Carbon\Carbon;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class TrackVisitor
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$response = $next($request);
|
||||
|
||||
// Only track GET requests that are successful and not Livewire internal requests
|
||||
if ($request->method() === 'GET' && $response->getStatusCode() === 200 && ! $request->header('X-Livewire')) {
|
||||
$ip = $request->ip();
|
||||
$route = $request->route() ? $request->route()->getName() : $request->path();
|
||||
|
||||
// Skip if route is not defined or route is Livewire
|
||||
if (! $route || str_contains($route, 'livewire')) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$today = Carbon::today();
|
||||
|
||||
// Check if IP has already visited this route today
|
||||
$alreadyVisited = Visitor::where('ip', $ip)
|
||||
->where('route', $route)
|
||||
->whereDate('date', $today)
|
||||
->exists();
|
||||
|
||||
if (! $alreadyVisited) {
|
||||
Visitor::create([
|
||||
'user_id' => auth()->id(),
|
||||
'method' => $request->method(),
|
||||
'route' => $route,
|
||||
'status' => $response->getStatusCode(),
|
||||
'ip' => $ip,
|
||||
'date' => Carbon::now(),
|
||||
'counter' => 1, // Set 1 because this is the first unique visit today
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@ -76,4 +76,9 @@ public function verificationReviews(): HasMany
|
||||
{
|
||||
return $this->hasMany(VerificationReview::class, 'reviewer_id');
|
||||
}
|
||||
|
||||
public function visitors(): HasMany
|
||||
{
|
||||
return $this->hasMany(Visitor::class);
|
||||
}
|
||||
}
|
||||
|
||||
16
app/Models/Visitor.php
Normal file
16
app/Models/Visitor.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Bilfeldt\LaravelRouteStatistics\Models\RouteStatistic as BaseRouteStatistic;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Visitor extends BaseRouteStatistic
|
||||
{
|
||||
protected $table = 'visitors';
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
@ -2,9 +2,11 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Visitor;
|
||||
use App\Settings\GeneralSettings;
|
||||
use App\Settings\SeoSettings;
|
||||
use App\Settings\SocialMediaSettings;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class ViewServiceProvider extends ServiceProvider
|
||||
@ -25,5 +27,23 @@ public function boot(): void
|
||||
view()->share('general', app(GeneralSettings::class));
|
||||
view()->share('social', app(SocialMediaSettings::class));
|
||||
view()->share('seo', app(SeoSettings::class));
|
||||
|
||||
view()->composer('components.partials.footer', function ($view) {
|
||||
$routeStatisticModel = config('route-statistics.model', Visitor::class);
|
||||
|
||||
$today = $routeStatisticModel::whereDate('date', Carbon::today())->sum('counter');
|
||||
$yesterday = $routeStatisticModel::whereDate('date', Carbon::yesterday())->sum('counter');
|
||||
$thisMonth = $routeStatisticModel::whereMonth('date', Carbon::now()->month)
|
||||
->whereYear('date', Carbon::now()->year)
|
||||
->sum('counter');
|
||||
$total = $routeStatisticModel::sum('counter');
|
||||
|
||||
$view->with('visitorStats', [
|
||||
'today' => number_format($today),
|
||||
'yesterday' => number_format($yesterday),
|
||||
'thisMonth' => number_format($thisMonth),
|
||||
'total' => number_format($total),
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
"php": "^8.2",
|
||||
"asmit/filament-upload": "^1.1",
|
||||
"bezhansalleh/filament-shield": "^4.0",
|
||||
"bilfeldt/laravel-route-statistics": "^4.2",
|
||||
"filament/filament": "^4.0",
|
||||
"filament/spatie-laravel-media-library-plugin": "^4.0",
|
||||
"filament/spatie-laravel-settings-plugin": "^4.4",
|
||||
|
||||
210
composer.lock
generated
210
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "37c52f60c416d783d4922313800eb7b5",
|
||||
"content-hash": "a8225cac91593cfe6465c7be71fbbdc6",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anourvalar/eloquent-serialize",
|
||||
@ -292,6 +292,214 @@
|
||||
],
|
||||
"time": "2025-12-26T09:31:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bilfeldt/laravel-correlation-id",
|
||||
"version": "v1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bilfeldt/laravel-correlation-id.git",
|
||||
"reference": "0a12cddc777d84529b798f5c1105bbd227c7e2e8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bilfeldt/laravel-correlation-id/zipball/0a12cddc777d84529b798f5c1105bbd227c7e2e8",
|
||||
"reference": "0a12cddc777d84529b798f5c1105bbd227c7e2e8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/contracts": "^10.0 || ^11.0 || ^12.0",
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nunomaduro/collision": "^7.8 || ^8.0",
|
||||
"orchestra/testbench": "^8.0 || ^9.0 || ^10.0",
|
||||
"phpunit/phpunit": "^10.0 || ^11.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Bilfeldt\\CorrelationId\\CorrelationIdServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Bilfeldt\\CorrelationId\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Anders Bilfeldt",
|
||||
"email": "abilfeldt@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Deal with Request-ID and Correlation-ID in Laravel applications",
|
||||
"homepage": "https://github.com/bilfeldt/laravel-correlation-id",
|
||||
"keywords": [
|
||||
"bilfeldt",
|
||||
"correlation id",
|
||||
"request id"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/bilfeldt/laravel-correlation-id/issues",
|
||||
"source": "https://github.com/bilfeldt/laravel-correlation-id"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/bilfeldt",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-28T18:40:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bilfeldt/laravel-request-logger",
|
||||
"version": "v3.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bilfeldt/laravel-request-logger.git",
|
||||
"reference": "40c22bbddc469a38dee1a4574bcd809ada352813"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bilfeldt/laravel-request-logger/zipball/40c22bbddc469a38dee1a4574bcd809ada352813",
|
||||
"reference": "40c22bbddc469a38dee1a4574bcd809ada352813",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"bilfeldt/laravel-correlation-id": "^1.0",
|
||||
"ext-json": "*",
|
||||
"illuminate/contracts": "^10.0 || ^11.0 || ^12.0",
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nunomaduro/collision": "^7.2 || ^8.0",
|
||||
"orchestra/testbench": "^8.0 || ^9.0 || ^10.0",
|
||||
"phpunit/phpunit": "^10.0 || ^11.5.3",
|
||||
"spatie/laravel-ray": "^1.32"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"RequestLogger": "Bilfeldt\\RequestLogger\\RequestLoggerFacade"
|
||||
},
|
||||
"providers": [
|
||||
"Bilfeldt\\RequestLogger\\RequestLoggerServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Bilfeldt\\RequestLogger\\": "src",
|
||||
"Bilfeldt\\RequestLogger\\Database\\Factories\\": "database/factories"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Anders Bilfeldt",
|
||||
"email": "abilfeldt@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Log Laravel application request and responses for debugging or statistics",
|
||||
"homepage": "https://github.com/bilfeldt/laravel-request-logger",
|
||||
"keywords": [
|
||||
"bilfeldt",
|
||||
"laravel",
|
||||
"laravel-request-logger"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/bilfeldt/laravel-route-statistics/issues",
|
||||
"source": "https://github.com/bilfeldt/laravel-route-statistics"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/bilfeldt",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-17T09:51:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bilfeldt/laravel-route-statistics",
|
||||
"version": "v4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bilfeldt/laravel-route-statistics.git",
|
||||
"reference": "9b314244248f43615049f102ba563ed5b7858db0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bilfeldt/laravel-route-statistics/zipball/9b314244248f43615049f102ba563ed5b7858db0",
|
||||
"reference": "9b314244248f43615049f102ba563ed5b7858db0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"bilfeldt/laravel-request-logger": "^3.0",
|
||||
"illuminate/contracts": "^10.0 || ^11.0 || ^12.0",
|
||||
"php": "~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nunomaduro/collision": "^7.2 || ^8.0",
|
||||
"orchestra/testbench": "^8.0 || ^9.0 || ^10.0",
|
||||
"phpunit/phpunit": "^10.0 || ^11.5.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Bilfeldt\\LaravelRouteStatistics\\LaravelRouteStatisticsServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Bilfeldt\\LaravelRouteStatistics\\": "src",
|
||||
"Bilfeldt\\LaravelRouteStatistics\\Database\\Factories\\": "database/factories"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Anders Bilfeldt",
|
||||
"email": "abilfeldt@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Log statistics about route usage per user/team",
|
||||
"homepage": "https://github.com/bilfeldt/laravel-route-statistics",
|
||||
"keywords": [
|
||||
"bilfeldt",
|
||||
"laravel",
|
||||
"route",
|
||||
"statistics"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/bilfeldt/laravel-route-statistics/issues",
|
||||
"source": "https://github.com/bilfeldt/laravel-route-statistics"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/bilfeldt",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-12T20:18:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "blade-ui-kit/blade-heroicons",
|
||||
"version": "2.6.0",
|
||||
|
||||
74
config/route-statistics.php
Normal file
74
config/route-statistics.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Visitor;
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Enabled
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is a 'master' switch to enable/disable logging. Setting this to
|
||||
| false will disable all logging.
|
||||
|
|
||||
*/
|
||||
'enabled' => env('ROUTE_STATISTICS_ENABLED', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Store parameters
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If this setting is set to true the route parameters will also be logged.
|
||||
|
|
||||
*/
|
||||
'store_route_parameters' => env('ROUTE_STATISTICS_STORE_ROUTE_PARAMETERS', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Aggregation
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This setting controls how we should aggregate requests.
|
||||
| Possible values are: SECOND, MINUTE, HOUR, DAY, MONTH, YEAR
|
||||
|
|
||||
*/
|
||||
'aggregate' => env('ROUTE_STATISTICS_AGGREGATE', 'DAY'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Model
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the model used to store request statistics.
|
||||
| It is possible to implement a custom model which extends the default model
|
||||
| or alternatively implement a completely new model which implements
|
||||
| Bilfeldt\RequestLogger\Contracts\RequestLoggerInterface
|
||||
|
|
||||
*/
|
||||
'model' => env('ROUTE_STATISTICS_MODEL', Visitor::class),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Store Strategy
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If you set this to true, the Logs stored in the database using queues
|
||||
| It is good when you have large database
|
||||
|
|
||||
*/
|
||||
'queued' => env('ROUTE_STATISTICS_QUEUED', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| User Model
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the model used for user relationships.
|
||||
| You can set a custom user model for relationships.
|
||||
|
|
||||
| Leaving this empty will use the model from the 'users' auth provider.
|
||||
|
|
||||
*/
|
||||
'user_model' => env('ROUTE_STATISTICS_USER_MODEL'),
|
||||
];
|
||||
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::create('visitors', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignIdFor(User::class)->nullable()->constrained()->cascadeOnDelete();
|
||||
$table->unsignedBigInteger('team_id')->nullable(); // Can be changed to the following if your application uses teams: $table->foreignId('team_id')->nullable()->constrained();
|
||||
$table->string('method')->nullable();
|
||||
$table->string('route')->nullable();
|
||||
$table->json('parameters')->nullable();
|
||||
$table->integer('status')->nullable();
|
||||
$table->ipAddress('ip')->nullable();
|
||||
$table->timestamp('date');
|
||||
$table->unsignedInteger('counter');
|
||||
|
||||
$table->index('date');
|
||||
$table->index(['user_id', 'date', 'route', 'method']);
|
||||
$table->index(['team_id', 'date', 'route', 'method']);
|
||||
$table->index(['route', 'method', 'date']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('visitors');
|
||||
}
|
||||
};
|
||||
@ -82,16 +82,16 @@ class="col-12 col-xl-4 col-lg-4 col-sm-6 last-paragraph-no-margin text-xl-start
|
||||
|
||||
<!-- Samping Kanan (Paling Kanan): Statistik Pengunjung -->
|
||||
<div class="col-6 col-xl-3 col-lg-2 col-sm-4 xs-mb-30px">
|
||||
<span class="fw-600 d-block text-dark-gray mb-10px">Statistik Pengunjung</span>
|
||||
<span class="fw-600 d-block text-dark-gray mb-10px">Statistik Visitor</span>
|
||||
<ul class="list-style-01">
|
||||
<li class="border-color-extra-medium-gray pt-5px pb-5px">Hari ini: <span
|
||||
class="fw-600 text-dark-gray float-end">123</span></li>
|
||||
class="fw-600 text-dark-gray float-end">{{ $visitorStats['today'] }}</span></li>
|
||||
<li class="border-color-extra-medium-gray pt-5px pb-5px">Kemarin: <span
|
||||
class="fw-600 text-dark-gray float-end">456</span></li>
|
||||
class="fw-600 text-dark-gray float-end">{{ $visitorStats['yesterday'] }}</span></li>
|
||||
<li class="border-color-extra-medium-gray pt-5px pb-5px">Bulan ini: <span
|
||||
class="fw-600 text-dark-gray float-end">7,890</span></li>
|
||||
class="fw-600 text-dark-gray float-end">{{ $visitorStats['thisMonth'] }}</span></li>
|
||||
<li class="border-color-extra-medium-gray pt-5px pb-5px">Total: <span
|
||||
class="fw-600 text-dark-gray float-end">12,345</span></li>
|
||||
class="fw-600 text-dark-gray float-end">{{ $visitorStats['total'] }}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Middleware\TrackVisitor;
|
||||
use App\Livewire\Home\AboutUs;
|
||||
use App\Livewire\Home\Announcement;
|
||||
use App\Livewire\Home\Index;
|
||||
@ -7,12 +8,14 @@
|
||||
use App\Livewire\Home\News\Show as NewsShow;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', Index::class)->name('home');
|
||||
Route::get('/about-us', AboutUs::class)->name('about-us');
|
||||
Route::middleware([TrackVisitor::class])->group(function () {
|
||||
Route::get('/', Index::class)->name('home');
|
||||
Route::get('/about-us', AboutUs::class)->name('about-us');
|
||||
|
||||
Route::prefix('news')->group(function () {
|
||||
Route::get('/', NewsIndex::class)->name('news.index');
|
||||
Route::get('/{news:slug}', NewsShow::class)->name('news.show');
|
||||
Route::prefix('news')->group(function () {
|
||||
Route::get('/', NewsIndex::class)->name('news.index');
|
||||
Route::get('/{news:slug}', NewsShow::class)->name('news.show');
|
||||
});
|
||||
|
||||
Route::get('/announcements', Announcement::class)->name('announcement');
|
||||
});
|
||||
|
||||
Route::get('/announcements', Announcement::class)->name('announcement');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user