Add device, platform, and country analytics to link show page.
Deploy Ladill Link / deploy (push) Successful in 32s
Deploy Ladill Link / deploy (push) Successful in 32s
Record parsed user-agent and geo data on clicks, then surface breakdowns and richer recent-click context on per-link and account analytics views. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\Link;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
final class LinkGeoResolver
|
||||
{
|
||||
public static function countryCode(Request $request): ?string
|
||||
{
|
||||
foreach (['CF-IPCountry', 'X-Country-Code', 'CloudFront-Viewer-Country'] as $header) {
|
||||
$value = $request->header($header);
|
||||
if (! is_string($value) || strlen($value) !== 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$code = strtoupper($value);
|
||||
if (! in_array($code, ['XX', 'T1'], true)) {
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function countryLabel(?string $code): string
|
||||
{
|
||||
if ($code === null || $code === '') {
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
if (function_exists('locale_get_display_region')) {
|
||||
$name = locale_get_display_region('_'.$code, 'en');
|
||||
|
||||
return is_string($name) && $name !== '' ? $name : $code;
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\Link;
|
||||
|
||||
final class LinkUserAgentParser
|
||||
{
|
||||
/**
|
||||
* @return array{device_type: string, browser: string, os: string}
|
||||
*/
|
||||
public static function parse(string $userAgent): array
|
||||
{
|
||||
$uaLower = strtolower($userAgent);
|
||||
|
||||
$device = str_contains($uaLower, 'mobile') || str_contains($uaLower, 'android') || str_contains($uaLower, 'iphone')
|
||||
? 'mobile'
|
||||
: (str_contains($uaLower, 'tablet') || str_contains($uaLower, 'ipad') ? 'tablet' : 'desktop');
|
||||
|
||||
$browser = match (true) {
|
||||
str_contains($uaLower, 'edg/') => 'Edge',
|
||||
str_contains($uaLower, 'chrome/') && ! str_contains($uaLower, 'edg/') => 'Chrome',
|
||||
str_contains($uaLower, 'safari/') && ! str_contains($uaLower, 'chrome/') => 'Safari',
|
||||
str_contains($uaLower, 'firefox/') => 'Firefox',
|
||||
str_contains($uaLower, 'instagram') => 'Instagram',
|
||||
str_contains($uaLower, 'whatsapp') => 'WhatsApp',
|
||||
default => 'Other',
|
||||
};
|
||||
|
||||
$os = match (true) {
|
||||
str_contains($uaLower, 'iphone') || str_contains($uaLower, 'ipad') => 'iOS',
|
||||
str_contains($uaLower, 'android') => 'Android',
|
||||
str_contains($uaLower, 'windows') => 'Windows',
|
||||
str_contains($uaLower, 'mac os') || str_contains($uaLower, 'macintosh') => 'macOS',
|
||||
str_contains($uaLower, 'linux') => 'Linux',
|
||||
default => 'Other',
|
||||
};
|
||||
|
||||
return [
|
||||
'device_type' => $device,
|
||||
'browser' => $browser,
|
||||
'os' => $os,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user