diff --git a/.gitignore b/.gitignore index bec2973..ce96d2c 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ yarn-error.log /.nova /.vscode /.zed + +# Sentry Config File +.env.sentry-build-plugin diff --git a/app/Http/Controllers/Auth/RegisteredUserController.php b/app/Http/Controllers/Auth/RegisteredUserController.php index 9ec74be..a446ab9 100644 --- a/app/Http/Controllers/Auth/RegisteredUserController.php +++ b/app/Http/Controllers/Auth/RegisteredUserController.php @@ -34,7 +34,7 @@ class RegisteredUserController extends Controller { $request->validate([ 'name' => 'required|string|max:255', - 'email' => 'required|string|lowercase|email|max:255|contains:yumj.in|unique:'.User::class, + 'email' => 'required|string|lowercase|email|max:255|ends_with:@yumj.in|unique:'.User::class, 'password' => ['required', 'confirmed', Rules\Password::defaults()], ]); diff --git a/app/Http/Controllers/ComicController.php b/app/Http/Controllers/ComicController.php index 2a008b3..bcd6971 100644 --- a/app/Http/Controllers/ComicController.php +++ b/app/Http/Controllers/ComicController.php @@ -241,7 +241,12 @@ class ComicController extends Controller public function destroyHistories(Request $request): RedirectResponse { - $histories = $request->user()->readingHistories()->whereIn('reading_histories.id', $request->get('ids'))->delete(); + if (!is_array($request->get('ids')) && $request->get('ids') === 'all') { + $histories = $request->user()->readingHistories()->delete(); + } else { + $histories = $request->user()->readingHistories()->whereIn('reading_histories.id', $request->get('ids'))->delete(); + } + return redirect()->route('comics.histories'); } diff --git a/app/Http/Requests/ProfileUpdateRequest.php b/app/Http/Requests/ProfileUpdateRequest.php index e41248e..e5a56a8 100644 --- a/app/Http/Requests/ProfileUpdateRequest.php +++ b/app/Http/Requests/ProfileUpdateRequest.php @@ -20,7 +20,7 @@ class ProfileUpdateRequest extends FormRequest 'name' => ['required', 'string', 'max:255'], 'email' => [ 'required', - 'contains:@yumj.in', + 'ends_with:@yumj.in', 'string', 'lowercase', 'email', diff --git a/bootstrap/app.php b/bootstrap/app.php index f5a0a6b..682ced6 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -5,6 +5,7 @@ use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Middleware; use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets; +use Sentry\Laravel\Integration; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( @@ -22,5 +23,5 @@ return Application::configure(basePath: dirname(__DIR__)) // }) ->withExceptions(function (Exceptions $exceptions) { - // + Integration::handles($exceptions); })->create(); diff --git a/bun.lockb b/bun.lockb index 56f01cb..574592b 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/composer.json b/composer.json index 7f86f7e..d7b1b49 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,8 @@ "laravel/framework": "^11.31", "laravel/sanctum": "^4.0", "laravel/tinker": "^2.9", + "predis/predis": "^2.0", + "sentry/sentry-laravel": "^4.10", "tightenco/ziggy": "^2.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 626661e..23aa558 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "b63241c5adeaff665ae634a61377fcc6", + "content-hash": "cf7d41fc8c70877b1ded788c249463de", "packages": [ { "name": "brick/math", @@ -1128,6 +1128,65 @@ ], "time": "2024-12-13T02:48:29+00:00" }, + { + "name": "jean85/pretty-package-versions", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", + "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.1.0", + "php": "^7.4|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^7.5|^8.5|^9.6", + "vimeo/psalm": "^4.3 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0" + }, + "time": "2024-11-18T16:19:46+00:00" + }, { "name": "laravel/framework", "version": "v11.36.1", @@ -2646,6 +2705,84 @@ ], "time": "2024-11-21T10:39:51+00:00" }, + { + "name": "nyholm/psr7", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/a71f2b11690f4b24d099d6b16690a90ae14fc6f3", + "reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0" + }, + "provide": { + "php-http/message-factory-implementation": "1.0", + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.9", + "php-http/message-factory": "^1.0", + "php-http/psr7-integration-tests": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.4", + "symfony/error-handler": "^4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "https://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/Nyholm/psr7/issues", + "source": "https://github.com/Nyholm/psr7/tree/1.8.2" + }, + "funding": [ + { + "url": "https://github.com/Zegnat", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2024-09-09T07:06:30+00:00" + }, { "name": "phpoption/phpoption", "version": "1.9.3", @@ -2721,6 +2858,67 @@ ], "time": "2024-07-20T21:41:07+00:00" }, + { + "name": "predis/predis", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/predis/predis.git", + "reference": "bac46bfdb78cd6e9c7926c697012aae740cb9ec9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/predis/predis/zipball/bac46bfdb78cd6e9c7926c697012aae740cb9ec9", + "reference": "bac46bfdb78cd6e9c7926c697012aae740cb9ec9", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.3", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^8.0 || ^9.4" + }, + "suggest": { + "ext-relay": "Faster connection with in-memory caching (>=0.6.2)" + }, + "type": "library", + "autoload": { + "psr-4": { + "Predis\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Till Krüss", + "homepage": "https://till.im", + "role": "Maintainer" + } + ], + "description": "A flexible and feature-complete Redis client for PHP.", + "homepage": "http://github.com/predis/predis", + "keywords": [ + "nosql", + "predis", + "redis" + ], + "support": { + "issues": "https://github.com/predis/predis/issues", + "source": "https://github.com/predis/predis/tree/v2.3.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/tillkruss", + "type": "github" + } + ], + "time": "2024-11-21T20:00:02+00:00" + }, { "name": "psr/clock", "version": "1.0.0", @@ -3437,6 +3635,184 @@ ], "time": "2024-04-27T21:32:50+00:00" }, + { + "name": "sentry/sentry", + "version": "4.10.0", + "source": { + "type": "git", + "url": "https://github.com/getsentry/sentry-php.git", + "reference": "2af937d47d8aadb8dab0b1d7b9557e495dd12856" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/2af937d47d8aadb8dab0b1d7b9557e495dd12856", + "reference": "2af937d47d8aadb8dab0b1d7b9557e495dd12856", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "guzzlehttp/psr7": "^1.8.4|^2.1.1", + "jean85/pretty-package-versions": "^1.5|^2.0.4", + "php": "^7.2|^8.0", + "psr/log": "^1.0|^2.0|^3.0", + "symfony/options-resolver": "^4.4.30|^5.0.11|^6.0|^7.0" + }, + "conflict": { + "raven/raven": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.4", + "guzzlehttp/promises": "^2.0.3", + "guzzlehttp/psr7": "^1.8.4|^2.1.1", + "monolog/monolog": "^1.6|^2.0|^3.0", + "phpbench/phpbench": "^1.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^8.5|^9.6", + "symfony/phpunit-bridge": "^5.2|^6.0|^7.0", + "vimeo/psalm": "^4.17" + }, + "suggest": { + "monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler." + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Sentry\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sentry", + "email": "accounts@sentry.io" + } + ], + "description": "PHP SDK for Sentry (http://sentry.io)", + "homepage": "http://sentry.io", + "keywords": [ + "crash-reporting", + "crash-reports", + "error-handler", + "error-monitoring", + "log", + "logging", + "profiling", + "sentry", + "tracing" + ], + "support": { + "issues": "https://github.com/getsentry/sentry-php/issues", + "source": "https://github.com/getsentry/sentry-php/tree/4.10.0" + }, + "funding": [ + { + "url": "https://sentry.io/", + "type": "custom" + }, + { + "url": "https://sentry.io/pricing/", + "type": "custom" + } + ], + "time": "2024-11-06T07:44:19+00:00" + }, + { + "name": "sentry/sentry-laravel", + "version": "4.10.2", + "source": { + "type": "git", + "url": "https://github.com/getsentry/sentry-laravel.git", + "reference": "0e2e5bc4311da51349487afcf67b8fca937f6d94" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/0e2e5bc4311da51349487afcf67b8fca937f6d94", + "reference": "0e2e5bc4311da51349487afcf67b8fca937f6d94", + "shasum": "" + }, + "require": { + "illuminate/support": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0", + "nyholm/psr7": "^1.0", + "php": "^7.2 | ^8.0", + "sentry/sentry": "^4.10", + "symfony/psr-http-message-bridge": "^1.0 | ^2.0 | ^6.0 | ^7.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.11", + "guzzlehttp/guzzle": "^7.2", + "laravel/folio": "^1.1", + "laravel/framework": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0", + "livewire/livewire": "^2.0 | ^3.0", + "mockery/mockery": "^1.3", + "orchestra/testbench": "^4.7 | ^5.1 | ^6.0 | ^7.0 | ^8.0 | ^9.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.4 | ^9.3 | ^10.4" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Sentry": "Sentry\\Laravel\\Facade" + }, + "providers": [ + "Sentry\\Laravel\\ServiceProvider", + "Sentry\\Laravel\\Tracing\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-0": { + "Sentry\\Laravel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sentry", + "email": "accounts@sentry.io" + } + ], + "description": "Laravel SDK for Sentry (https://sentry.io)", + "homepage": "https://sentry.io", + "keywords": [ + "crash-reporting", + "crash-reports", + "error-handler", + "error-monitoring", + "laravel", + "log", + "logging", + "profiling", + "sentry", + "tracing" + ], + "support": { + "issues": "https://github.com/getsentry/sentry-laravel/issues", + "source": "https://github.com/getsentry/sentry-laravel/tree/4.10.2" + }, + "funding": [ + { + "url": "https://sentry.io/", + "type": "custom" + }, + { + "url": "https://sentry.io/pricing/", + "type": "custom" + } + ], + "time": "2024-12-17T11:38:58+00:00" + }, { "name": "symfony/clock", "version": "v7.2.0", @@ -4387,6 +4763,73 @@ ], "time": "2024-12-07T08:50:44+00:00" }, + { + "name": "symfony/options-resolver", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-20T11:17:29+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.31.0", @@ -5084,6 +5527,89 @@ ], "time": "2024-11-06T14:24:19+00:00" }, + { + "name": "symfony/psr-http-message-bridge", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/psr-http-message-bridge.git", + "reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/03f2f72319e7acaf2a9f6fcbe30ef17eec51594f", + "reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/http-message": "^1.0|^2.0", + "symfony/http-foundation": "^6.4|^7.0" + }, + "conflict": { + "php-http/discovery": "<1.15", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "nyholm/psr7": "^1.1", + "php-http/discovery": "^1.15", + "psr/log": "^1.1.4|^2|^3", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\PsrHttpMessage\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "PSR HTTP message bridge", + "homepage": "https://symfony.com", + "keywords": [ + "http", + "http-message", + "psr-17", + "psr-7" + ], + "support": { + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-26T08:57:56+00:00" + }, { "name": "symfony/routing", "version": "v7.2.0", @@ -6392,65 +6918,6 @@ }, "time": "2020-07-09T08:09:16+00:00" }, - { - "name": "jean85/pretty-package-versions", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", - "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2.1.0", - "php": "^7.4|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^1.4", - "phpunit/phpunit": "^7.5|^8.5|^9.6", - "vimeo/psalm": "^4.3 || ^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Jean85\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alessandro Lai", - "email": "alessandro.lai85@gmail.com" - } - ], - "description": "A library to get pretty versions strings of installed dependencies", - "keywords": [ - "composer", - "package", - "release", - "versions" - ], - "support": { - "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0" - }, - "time": "2024-11-18T16:19:46+00:00" - }, { "name": "laravel/breeze", "version": "v2.3.0", diff --git a/config/sentry.php b/config/sentry.php new file mode 100644 index 0000000..b159b0a --- /dev/null +++ b/config/sentry.php @@ -0,0 +1,129 @@ + env('SENTRY_LARAVEL_DSN', env('SENTRY_DSN')), + + // @see https://spotlightjs.com/ + // 'spotlight' => env('SENTRY_SPOTLIGHT', false), + + // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#logger + // 'logger' => Sentry\Logger\DebugFileLogger::class, // By default this will log to `storage_path('logs/sentry.log')` + + // The release version of your application + // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) + 'release' => env('SENTRY_RELEASE'), + + // When left empty or `null` the Laravel environment will be used (usually discovered from `APP_ENV` in your `.env`) + 'environment' => env('SENTRY_ENVIRONMENT'), + + // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#sample-rate + 'sample_rate' => env('SENTRY_SAMPLE_RATE') === null ? 1.0 : (float) env('SENTRY_SAMPLE_RATE'), + + // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces-sample-rate + 'traces_sample_rate' => env('SENTRY_TRACES_SAMPLE_RATE') === null ? null : (float) env('SENTRY_TRACES_SAMPLE_RATE'), + + // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#profiles-sample-rate + 'profiles_sample_rate' => env('SENTRY_PROFILES_SAMPLE_RATE') === null ? null : (float) env('SENTRY_PROFILES_SAMPLE_RATE'), + + // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send-default-pii + 'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', false), + + // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#ignore-exceptions + // 'ignore_exceptions' => [], + + // @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#ignore-transactions + 'ignore_transactions' => [ + // Ignore Laravel's default health URL + '/up', + ], + + // Breadcrumb specific configuration + 'breadcrumbs' => [ + // Capture Laravel logs as breadcrumbs + 'logs' => env('SENTRY_BREADCRUMBS_LOGS_ENABLED', true), + + // Capture Laravel cache events (hits, writes etc.) as breadcrumbs + 'cache' => env('SENTRY_BREADCRUMBS_CACHE_ENABLED', true), + + // Capture Livewire components like routes as breadcrumbs + 'livewire' => env('SENTRY_BREADCRUMBS_LIVEWIRE_ENABLED', true), + + // Capture SQL queries as breadcrumbs + 'sql_queries' => env('SENTRY_BREADCRUMBS_SQL_QUERIES_ENABLED', true), + + // Capture SQL query bindings (parameters) in SQL query breadcrumbs + 'sql_bindings' => env('SENTRY_BREADCRUMBS_SQL_BINDINGS_ENABLED', false), + + // Capture queue job information as breadcrumbs + 'queue_info' => env('SENTRY_BREADCRUMBS_QUEUE_INFO_ENABLED', true), + + // Capture command information as breadcrumbs + 'command_info' => env('SENTRY_BREADCRUMBS_COMMAND_JOBS_ENABLED', true), + + // Capture HTTP client request information as breadcrumbs + 'http_client_requests' => env('SENTRY_BREADCRUMBS_HTTP_CLIENT_REQUESTS_ENABLED', true), + + // Capture send notifications as breadcrumbs + 'notifications' => env('SENTRY_BREADCRUMBS_NOTIFICATIONS_ENABLED', true), + ], + + // Performance monitoring specific configuration + 'tracing' => [ + // Trace queue jobs as their own transactions (this enables tracing for queue jobs) + 'queue_job_transactions' => env('SENTRY_TRACE_QUEUE_ENABLED', true), + + // Capture queue jobs as spans when executed on the sync driver + 'queue_jobs' => env('SENTRY_TRACE_QUEUE_JOBS_ENABLED', true), + + // Capture SQL queries as spans + 'sql_queries' => env('SENTRY_TRACE_SQL_QUERIES_ENABLED', true), + + // Capture SQL query bindings (parameters) in SQL query spans + 'sql_bindings' => env('SENTRY_TRACE_SQL_BINDINGS_ENABLED', false), + + // Capture where the SQL query originated from on the SQL query spans + 'sql_origin' => env('SENTRY_TRACE_SQL_ORIGIN_ENABLED', true), + + // Define a threshold in milliseconds for SQL queries to resolve their origin + 'sql_origin_threshold_ms' => env('SENTRY_TRACE_SQL_ORIGIN_THRESHOLD_MS', 100), + + // Capture views rendered as spans + 'views' => env('SENTRY_TRACE_VIEWS_ENABLED', true), + + // Capture Livewire components as spans + 'livewire' => env('SENTRY_TRACE_LIVEWIRE_ENABLED', true), + + // Capture HTTP client requests as spans + 'http_client_requests' => env('SENTRY_TRACE_HTTP_CLIENT_REQUESTS_ENABLED', true), + + // Capture Laravel cache events (hits, writes etc.) as spans + 'cache' => env('SENTRY_TRACE_CACHE_ENABLED', true), + + // Capture Redis operations as spans (this enables Redis events in Laravel) + 'redis_commands' => env('SENTRY_TRACE_REDIS_COMMANDS', false), + + // Capture where the Redis command originated from on the Redis command spans + 'redis_origin' => env('SENTRY_TRACE_REDIS_ORIGIN_ENABLED', true), + + // Capture send notifications as spans + 'notifications' => env('SENTRY_TRACE_NOTIFICATIONS_ENABLED', true), + + // Enable tracing for requests without a matching route (404's) + 'missing_routes' => env('SENTRY_TRACE_MISSING_ROUTES_ENABLED', false), + + // Configures if the performance trace should continue after the response has been sent to the user until the application terminates + // This is required to capture any spans that are created after the response has been sent like queue jobs dispatched using `dispatch(...)->afterResponse()` for example + 'continue_after_response' => env('SENTRY_TRACE_CONTINUE_AFTER_RESPONSE', true), + + // Enable the tracing integrations supplied by Sentry (recommended) + 'default_integrations' => env('SENTRY_TRACE_DEFAULT_INTEGRATIONS_ENABLED', true), + ], + +]; diff --git a/package.json b/package.json index eeb6c64..39754b8 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,8 @@ "@radix-ui/react-tabs": "^1.1.2", "@radix-ui/react-toast": "^1.2.4", "@radix-ui/react-tooltip": "^1.1.6", + "@sentry/react": "^8.47.0", + "@sentry/vite-plugin": "^2.22.7", "@tanstack/react-table": "^8.20.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/resources/js/Layouts/AppLayout.jsx b/resources/js/Layouts/AppLayout.jsx index 949efab..2edf37d 100644 --- a/resources/js/Layouts/AppLayout.jsx +++ b/resources/js/Layouts/AppLayout.jsx @@ -1,14 +1,16 @@ -import { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'; +import { useEffect, useState } from 'react'; +import { Link } from '@inertiajs/react'; +import { Moon, Sun } from 'lucide-react'; + +import { Separator } from '@radix-ui/react-separator'; +import { Tooltip, TooltipProvider, TooltipTrigger } from '@radix-ui/react-tooltip'; + import { AppSidebar } from '@/components/ui/app-sidebar.jsx'; -import { Separator } from "@radix-ui/react-separator"; -import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList } from "@/components/ui/breadcrumb"; -import { Toaster } from '@/components/ui/toaster'; +import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList } from '@/components/ui/breadcrumb'; import { Button } from '@/components/ui/button'; -import { Moon, Settings, Sun } from 'lucide-react'; -import { Link, usePage } from '@inertiajs/react'; -import { useEffect, useState } from "react"; -import { Tooltip, TooltipProvider, TooltipTrigger } from "@radix-ui/react-tooltip"; -import { TooltipContent } from "@/components/ui/tooltip.jsx"; +import { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'; +import { TooltipContent } from '@/components/ui/tooltip.jsx'; +import { Toaster } from '@/components/ui/toaster'; export default function AppLayout({ auth, header, children, toolbar }) { diff --git a/resources/js/Pages/Comic/Histories.jsx b/resources/js/Pages/Comic/Histories.jsx index 6b7f13b..67dd464 100644 --- a/resources/js/Pages/Comic/Histories.jsx +++ b/resources/js/Pages/Comic/Histories.jsx @@ -1,5 +1,5 @@ -import { useState } from "react"; -import { Head, router } from '@inertiajs/react'; +import { useState } from 'react'; +import { Head, Link, router } from '@inertiajs/react'; import AppLayout from '@/Layouts/AppLayout.jsx'; import { BreadcrumbItem, BreadcrumbPage, BreadcrumbSeparator } from "@/components/ui/breadcrumb"; @@ -24,16 +24,9 @@ export default function Histories({ auth, histories }) { } } - const deleteButtonOnClickHandler = (e) => { - if (ids.length === 0) { - toast({ - title: "Error", - description: `No items selected.`, - }); - return; - } + const deleteButtonOnClickHandler = () => { router.visit(route('comics.destroyHistories'), { - data: { ids: ids }, + data: (ids.length > 0) ? { ids: ids } : { ids: 'all' }, method: "PATCH", only: ['histories'], onSuccess: data => { @@ -58,15 +51,17 @@ export default function Histories({ auth, histories }) { Histories
-
- +
+
Select - Comic Chapter + Comic Read at @@ -80,8 +75,16 @@ export default function Histories({ auth, histories }) { onChange={ (e) => checkboxOnChangeHandler(e) } /> - { h.name } - { h.comic.name } + + + { h.name } + + + + + { h.comic.name } + + { h.created_at } )) } diff --git a/resources/js/Pages/Comic/Index.jsx b/resources/js/Pages/Comic/Index.jsx index a85871b..e09a0b6 100644 --- a/resources/js/Pages/Comic/Index.jsx +++ b/resources/js/Pages/Comic/Index.jsx @@ -58,8 +58,9 @@ export default function Index({ comics, offset, auth }) { Home -
+
+ ;
diff --git a/resources/js/Pages/Comic/Read.jsx b/resources/js/Pages/Comic/Read.jsx index 45cbc2b..dc4b315 100644 --- a/resources/js/Pages/Comic/Read.jsx +++ b/resources/js/Pages/Comic/Read.jsx @@ -1,18 +1,22 @@ import { Head, Link, router } from '@inertiajs/react'; import AppLayout from '@/Layouts/AppLayout.jsx'; import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'; -import { BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator } from "@/components/ui/breadcrumb.jsx"; -import { Button } from "@/components/ui/button"; import { ChevronFirst, ChevronLast, Rows3, Settings } from "lucide-react"; +import { Tooltip, TooltipProvider, TooltipTrigger } from '@radix-ui/react-tooltip'; + +import { throttle } from 'lodash'; + +import { BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator } from '@/components/ui/breadcrumb'; +import { Button } from '@/components/ui/button'; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import PrimaryButton from "@/components/PrimaryButton.jsx"; -import { Switch } from "@/components/ui/switch"; -import { Tooltip, TooltipProvider, TooltipTrigger } from "@radix-ui/react-tooltip"; -import { TooltipContent } from "@/components/ui/tooltip.jsx"; -import { throttle } from "lodash"; +import PrimaryButton from '@/components/PrimaryButton'; +import { Switch } from '@/components/ui/switch'; +import { TooltipContent } from "@/components/ui/tooltip"; export default function Read({ auth, comic, chapter }) { + const validReadingModes = ['rtl', 'utd']; + const [readingMode, setReadingMode] = useState('rtl'); // rtl, utd const [isTwoPagesPerScreen, setIsTwoPagePerScreen] = useState(false); const [currentImage, setCurrentImage] = useState(1); @@ -24,6 +28,14 @@ export default function Read({ auth, comic, chapter }) { const [loading, setLoading] = useState(true); + const getLocalStorageReadingMode = () => { + if (window.localStorage.getItem('readingMode') !== null && validReadingModes.includes(window.localStorage.getItem('readingMode'))) { + return window.localStorage.getItem('readingMode'); + } + + return "rtl"; + } + function useWindowSize() { const [size, setSize] = useState([0, 0]); useLayoutEffect(() => { @@ -41,8 +53,10 @@ export default function Read({ auth, comic, chapter }) { const toggleReadingMode = (e) => { if (e) { + window.localStorage.setItem('readingMode', 'utd'); setReadingMode('utd'); } else { + window.localStorage.setItem('readingMode', 'rtl'); setReadingMode('rtl'); } } @@ -154,7 +168,7 @@ export default function Read({ auth, comic, chapter }) {

Turn on for UTD mode

- toggleReadingMode(e) } /> @@ -227,6 +241,8 @@ export default function Read({ auth, comic, chapter }) { }, [windowSize]); useEffect(() => { + setReadingMode(getLocalStorageReadingMode()); + if (!ref.current) return; const handleScroll = () => { diff --git a/resources/js/app.jsx b/resources/js/app.jsx index 9f00218..e2f8fa9 100644 --- a/resources/js/app.jsx +++ b/resources/js/app.jsx @@ -4,9 +4,25 @@ import './bootstrap'; import { createInertiaApp } from '@inertiajs/react'; import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'; import { createRoot } from 'react-dom/client'; +import * as Sentry from "@sentry/react"; const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; +Sentry.init({ + dsn: "https://2adec7430e89618582219032ea835a8d@o1017868.ingest.us.sentry.io/4508547646029824", + integrations: [ + Sentry.browserTracingIntegration(), + Sentry.replayIntegration(), + ], + // Tracing + tracesSampleRate: 0.1, // Capture 10% of the transactions + // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled + tracePropagationTargets: ["localhost", /^https:\/\/c\.yumj\.in/], + // Session Replay + replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production. + replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur. +}); + createInertiaApp({ title: (title) => `${title} - ${appName}`, resolve: (name) => diff --git a/vite.config.js b/vite.config.js index 19f2908..d7b2ea6 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,13 +1,18 @@ +import { sentryVitePlugin } from "@sentry/vite-plugin"; import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import react from '@vitejs/plugin-react'; export default defineConfig({ - plugins: [ - laravel({ - input: 'resources/js/app.jsx', - refresh: true, - }), - react(), - ], -}); + plugins: [laravel({ + input: 'resources/js/app.jsx', + refresh: true, + }), react(), sentryVitePlugin({ + org: "pokebeacon", + project: "cv4-react" + })], + + build: { + sourcemap: true + } +}); \ No newline at end of file