From 5cfe3c81a152a6b0f93d312af06d9b1bc2345949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Falco=CC=81n?= Date: Wed, 26 Nov 2025 11:24:37 +0100 Subject: [PATCH] Better input field UX --- bun.lock | 11 +- composer.json | 1 + composer.lock | 1563 ++++++++++++++++- package.json | 1 + resources/js/components/ui/amount-input.tsx | 113 +- tests/Browser/AmountInputTest.php | 74 + tests/Browser/AutomationRuleBuilderTest.php | 2 +- ...an_type_integer_values_in_amount_field.png | Bin 0 -> 47172 bytes tests/Pest.php | 4 + 9 files changed, 1707 insertions(+), 62 deletions(-) create mode 100644 tests/Browser/AmountInputTest.php create mode 100644 tests/Browser/Screenshots/it_can_type_integer_values_in_amount_field.png diff --git a/bun.lock b/bun.lock index 97597355..94430d1f 100644 --- a/bun.lock +++ b/bun.lock @@ -62,6 +62,7 @@ "eslint-config-prettier": "^10.0.1", "eslint-plugin-react": "^7.37.3", "eslint-plugin-react-hooks": "^7.0.0", + "playwright": "^1.57.0", "prettier": "^3.4.2", "prettier-plugin-organize-imports": "^4.1.0", "prettier-plugin-tailwindcss": "^0.6.11", @@ -666,7 +667,7 @@ "frac": ["frac@1.1.2", "", {}, "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA=="], - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], @@ -908,6 +909,10 @@ "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "playwright": ["playwright@1.57.0", "", { "dependencies": { "playwright-core": "1.57.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw=="], + + "playwright-core": ["playwright-core@1.57.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ=="], + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], @@ -1158,6 +1163,10 @@ "rollup/@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.46.2", "", { "os": "win32", "cpu": "x64" }, "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg=="], + "rollup/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "vite-plugin-full-reload/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], diff --git a/composer.json b/composer.json index 814f91cd..16a0910e 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,7 @@ "mockery/mockery": "^1.6", "nunomaduro/collision": "^8.6", "pestphp/pest": "^4.1", + "pestphp/pest-plugin-browser": "^4.0", "pestphp/pest-plugin-laravel": "^4.0" }, "autoload": { diff --git a/composer.lock b/composer.lock index 66623f05..998daab6 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": "430e7205707242b2bfd1f9fd7d609970", + "content-hash": "c486936c59a7be23c521c87384d243bf", "packages": [ { "name": "bacon/bacon-qr-code", @@ -6453,6 +6453,1228 @@ } ], "packages-dev": [ + { + "name": "amphp/amp", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/fa0ab33a6f47a82929c38d03ca47ebb71086a93f", + "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "5.23.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Future/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "https://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "support": { + "issues": "https://github.com/amphp/amp/issues", + "source": "https://github.com/amphp/amp/tree/v3.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-08-27T21:42:00+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/55a6bd071aec26fa2a3e002618c20c35e3df1b46", + "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/parser": "^1.1", + "amphp/pipeline": "^1", + "amphp/serialization": "^1", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2.3" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.22.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\ByteStream\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "https://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "support": { + "issues": "https://github.com/amphp/byte-stream/issues", + "source": "https://github.com/amphp/byte-stream/tree/v2.1.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-03-16T17:10:27+00:00" + }, + { + "name": "amphp/cache", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/cache.git", + "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/cache/zipball/46912e387e6aa94933b61ea1ead9cf7540b7797c", + "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/serialization": "^1", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Cache\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A fiber-aware cache API based on Amp and Revolt.", + "homepage": "https://amphp.org/cache", + "support": { + "issues": "https://github.com/amphp/cache/issues", + "source": "https://github.com/amphp/cache/tree/v2.0.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-19T03:38:06+00:00" + }, + { + "name": "amphp/dns", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/dns.git", + "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/dns/zipball/78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", + "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/cache": "^2", + "amphp/parser": "^1", + "amphp/process": "^2", + "daverandom/libdns": "^2.0.2", + "ext-filter": "*", + "ext-json": "*", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.20" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Dns\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Wright", + "email": "addr@daverandom.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Async DNS resolution for Amp.", + "homepage": "https://github.com/amphp/dns", + "keywords": [ + "amp", + "amphp", + "async", + "client", + "dns", + "resolve" + ], + "support": { + "issues": "https://github.com/amphp/dns/issues", + "source": "https://github.com/amphp/dns/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-01-19T15:43:40+00:00" + }, + { + "name": "amphp/hpack", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/hpack.git", + "reference": "4f293064b15682a2b178b1367ddf0b8b5feb0239" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/hpack/zipball/4f293064b15682a2b178b1367ddf0b8b5feb0239", + "reference": "4f293064b15682a2b178b1367ddf0b8b5feb0239", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "http2jp/hpack-test-case": "^1", + "nikic/php-fuzzer": "^0.0.10", + "phpunit/phpunit": "^7 | ^8 | ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\Http\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "HTTP/2 HPack implementation.", + "homepage": "https://github.com/amphp/hpack", + "keywords": [ + "headers", + "hpack", + "http-2" + ], + "support": { + "issues": "https://github.com/amphp/hpack/issues", + "source": "https://github.com/amphp/hpack/tree/v3.2.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-03-21T19:00:16+00:00" + }, + { + "name": "amphp/http", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/http.git", + "reference": "3680d80bd38b5d6f3c2cef2214ca6dd6cef26588" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http/zipball/3680d80bd38b5d6f3c2cef2214ca6dd6cef26588", + "reference": "3680d80bd38b5d6f3c2cef2214ca6dd6cef26588", + "shasum": "" + }, + "require": { + "amphp/hpack": "^3", + "amphp/parser": "^1.1", + "league/uri-components": "^2.4.2 | ^7.1", + "php": ">=8.1", + "psr/http-message": "^1 | ^2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "league/uri": "^6.8 | ^7.1", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.26.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/constants.php" + ], + "psr-4": { + "Amp\\Http\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Basic HTTP primitives which can be shared by servers and clients.", + "support": { + "issues": "https://github.com/amphp/http/issues", + "source": "https://github.com/amphp/http/tree/v2.1.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-11-23T14:57:26+00:00" + }, + { + "name": "amphp/http-client", + "version": "v5.3.4", + "source": { + "type": "git", + "url": "https://github.com/amphp/http-client.git", + "reference": "75ad21574fd632594a2dd914496647816d5106bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http-client/zipball/75ad21574fd632594a2dd914496647816d5106bc", + "reference": "75ad21574fd632594a2dd914496647816d5106bc", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/hpack": "^3", + "amphp/http": "^2", + "amphp/pipeline": "^1", + "amphp/socket": "^2", + "amphp/sync": "^2", + "league/uri": "^7", + "league/uri-components": "^7", + "league/uri-interfaces": "^7.1", + "php": ">=8.1", + "psr/http-message": "^1 | ^2", + "revolt/event-loop": "^1" + }, + "conflict": { + "amphp/file": "<3 | >=5" + }, + "require-dev": { + "amphp/file": "^3 | ^4", + "amphp/http-server": "^3", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "ext-json": "*", + "kelunik/link-header-rfc5988": "^1", + "laminas/laminas-diactoros": "^2.3", + "phpunit/phpunit": "^9", + "psalm/phar": "~5.23" + }, + "suggest": { + "amphp/file": "Required for file request bodies and HTTP archive logging", + "ext-json": "Required for logging HTTP archives", + "ext-zlib": "Allows using compression for response bodies." + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\Http\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "An advanced async HTTP client library for PHP, enabling efficient, non-blocking, and concurrent requests and responses.", + "homepage": "https://amphp.org/http-client", + "keywords": [ + "async", + "client", + "concurrent", + "http", + "non-blocking", + "rest" + ], + "support": { + "issues": "https://github.com/amphp/http-client/issues", + "source": "https://github.com/amphp/http-client/tree/v5.3.4" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-08-16T20:41:23+00:00" + }, + { + "name": "amphp/http-server", + "version": "v3.4.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/http-server.git", + "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http-server/zipball/7aa962b0569f664af3ba23bc819f2a69884329cd", + "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/cache": "^2", + "amphp/hpack": "^3", + "amphp/http": "^2", + "amphp/pipeline": "^1", + "amphp/socket": "^2.1", + "amphp/sync": "^2.2", + "league/uri": "^7.1", + "league/uri-interfaces": "^7.1", + "php": ">=8.1", + "psr/http-message": "^1 | ^2", + "psr/log": "^1 | ^2 | ^3", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/http-client": "^5", + "amphp/log": "^2", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "league/uri-components": "^7.1", + "monolog/monolog": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "~5.23" + }, + "suggest": { + "ext-zlib": "Allows GZip compression of response bodies" + }, + "type": "library", + "autoload": { + "files": [ + "src/Driver/functions.php", + "src/Middleware/functions.php", + "src/functions.php" + ], + "psr-4": { + "Amp\\Http\\Server\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "A non-blocking HTTP application server for PHP based on Amp.", + "homepage": "https://github.com/amphp/http-server", + "keywords": [ + "amp", + "amphp", + "async", + "http", + "non-blocking", + "server" + ], + "support": { + "issues": "https://github.com/amphp/http-server/issues", + "source": "https://github.com/amphp/http-server/tree/v3.4.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-05-18T15:43:42+00:00" + }, + { + "name": "amphp/parser", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/parser.git", + "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7", + "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7", + "shasum": "" + }, + "require": { + "php": ">=7.4" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Parser\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A generator parser to make streaming parsers simple.", + "homepage": "https://github.com/amphp/parser", + "keywords": [ + "async", + "non-blocking", + "parser", + "stream" + ], + "support": { + "issues": "https://github.com/amphp/parser/issues", + "source": "https://github.com/amphp/parser/tree/v1.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-03-21T19:16:53+00:00" + }, + { + "name": "amphp/pipeline", + "version": "v1.2.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/pipeline.git", + "reference": "7b52598c2e9105ebcddf247fc523161581930367" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367", + "reference": "7b52598c2e9105ebcddf247fc523161581930367", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "php": ">=8.1", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.18" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Pipeline\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Asynchronous iterators and operators.", + "homepage": "https://amphp.org/pipeline", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "iterator", + "non-blocking" + ], + "support": { + "issues": "https://github.com/amphp/pipeline/issues", + "source": "https://github.com/amphp/pipeline/tree/v1.2.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-03-16T16:33:53+00:00" + }, + { + "name": "amphp/process", + "version": "v2.0.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/process.git", + "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/process/zipball/52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", + "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Process\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A fiber-aware process manager based on Amp and Revolt.", + "homepage": "https://amphp.org/process", + "support": { + "issues": "https://github.com/amphp/process/issues", + "source": "https://github.com/amphp/process/tree/v2.0.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-19T03:13:44+00:00" + }, + { + "name": "amphp/serialization", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/serialization.git", + "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1", + "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "phpunit/phpunit": "^9 || ^8 || ^7" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Serialization\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Serialization tools for IPC and data storage in PHP.", + "homepage": "https://github.com/amphp/serialization", + "keywords": [ + "async", + "asynchronous", + "serialization", + "serialize" + ], + "support": { + "issues": "https://github.com/amphp/serialization/issues", + "source": "https://github.com/amphp/serialization/tree/master" + }, + "time": "2020-03-25T21:39:07+00:00" + }, + { + "name": "amphp/socket", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/socket.git", + "reference": "58e0422221825b79681b72c50c47a930be7bf1e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/socket/zipball/58e0422221825b79681b72c50c47a930be7bf1e1", + "reference": "58e0422221825b79681b72c50c47a930be7bf1e1", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/dns": "^2", + "ext-openssl": "*", + "kelunik/certificate": "^1.1", + "league/uri": "^6.5 | ^7", + "league/uri-interfaces": "^2.3 | ^7", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "amphp/process": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "5.20" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php", + "src/SocketAddress/functions.php" + ], + "psr-4": { + "Amp\\Socket\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Non-blocking socket connection / server implementations based on Amp and Revolt.", + "homepage": "https://github.com/amphp/socket", + "keywords": [ + "amp", + "async", + "encryption", + "non-blocking", + "sockets", + "tcp", + "tls" + ], + "support": { + "issues": "https://github.com/amphp/socket/issues", + "source": "https://github.com/amphp/socket/tree/v2.3.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-21T14:33:03+00:00" + }, + { + "name": "amphp/sync", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/sync.git", + "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/sync/zipball/217097b785130d77cfcc58ff583cf26cd1770bf1", + "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/pipeline": "^1", + "amphp/serialization": "^1", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.23" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Sync\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Stephen Coakley", + "email": "me@stephencoakley.com" + } + ], + "description": "Non-blocking synchronization primitives for PHP based on Amp and Revolt.", + "homepage": "https://github.com/amphp/sync", + "keywords": [ + "async", + "asynchronous", + "mutex", + "semaphore", + "synchronization" + ], + "support": { + "issues": "https://github.com/amphp/sync/issues", + "source": "https://github.com/amphp/sync/tree/v2.3.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-08-03T19:31:26+00:00" + }, + { + "name": "amphp/websocket", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/amphp/websocket.git", + "reference": "963904b6a883c4b62d9222d1d9749814fac96a3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/websocket/zipball/963904b6a883c4b62d9222d1d9749814fac96a3b", + "reference": "963904b6a883c4b62d9222d1d9749814fac96a3b", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/parser": "^1", + "amphp/pipeline": "^1", + "amphp/socket": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.18" + }, + "suggest": { + "ext-zlib": "Required for compression" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Websocket\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + } + ], + "description": "Shared code for websocket servers and clients.", + "homepage": "https://github.com/amphp/websocket", + "keywords": [ + "amp", + "amphp", + "async", + "http", + "non-blocking", + "websocket" + ], + "support": { + "issues": "https://github.com/amphp/websocket/issues", + "source": "https://github.com/amphp/websocket/tree/v2.0.4" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-10-28T21:28:45+00:00" + }, + { + "name": "amphp/websocket-client", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/websocket-client.git", + "reference": "dc033fdce0af56295a23f63ac4f579b34d470d6c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/websocket-client/zipball/dc033fdce0af56295a23f63ac4f579b34d470d6c", + "reference": "dc033fdce0af56295a23f63ac4f579b34d470d6c", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2.1", + "amphp/http": "^2.1", + "amphp/http-client": "^5", + "amphp/socket": "^2.2", + "amphp/websocket": "^2", + "league/uri": "^7.1", + "php": ">=8.1", + "psr/http-message": "^1|^2", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/http-server": "^3", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "amphp/websocket-server": "^3|^4", + "phpunit/phpunit": "^9", + "psalm/phar": "~5.26.1", + "psr/log": "^1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Websocket\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Async WebSocket client for PHP based on Amp.", + "keywords": [ + "amp", + "amphp", + "async", + "client", + "http", + "non-blocking", + "websocket" + ], + "support": { + "issues": "https://github.com/amphp/websocket-client/issues", + "source": "https://github.com/amphp/websocket-client/tree/v2.0.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-08-24T17:25:34+00:00" + }, { "name": "brianium/paratest", "version": "v7.14.2", @@ -6546,6 +7768,50 @@ ], "time": "2025-10-24T07:20:53+00:00" }, + { + "name": "daverandom/libdns", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/DaveRandom/LibDNS.git", + "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", + "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "Required for IDN support" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "LibDNS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "DNS protocol implementation written in pure PHP", + "keywords": [ + "dns" + ], + "support": { + "issues": "https://github.com/DaveRandom/LibDNS/issues", + "source": "https://github.com/DaveRandom/LibDNS/tree/v2.1.0" + }, + "time": "2024-04-12T12:12:48+00:00" + }, { "name": "doctrine/deprecations", "version": "1.1.5", @@ -6900,6 +8166,64 @@ }, "time": "2025-03-19T14:43:43+00:00" }, + { + "name": "kelunik/certificate", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/kelunik/certificate.git", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=7.0" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^6 | 7 | ^8 | ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Kelunik\\Certificate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Access certificate details and transform between different formats.", + "keywords": [ + "DER", + "certificate", + "certificates", + "openssl", + "pem", + "x509" + ], + "support": { + "issues": "https://github.com/kelunik/certificate/issues", + "source": "https://github.com/kelunik/certificate/tree/v1.1.3" + }, + "time": "2023-02-03T21:26:53+00:00" + }, { "name": "laravel/boost", "version": "v1.7.1", @@ -7308,6 +8632,88 @@ }, "time": "2025-10-28T13:55:29+00:00" }, + { + "name": "league/uri-components", + "version": "7.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-components.git", + "reference": "4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f", + "reference": "4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f", + "shasum": "" + }, + "require": { + "league/uri": "^7.5", + "php": "^8.1" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "ext-mbstring": "to use the sorting algorithm of URLSearchParams", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI components manipulation library", + "homepage": "http://uri.thephpleague.com", + "keywords": [ + "authority", + "components", + "fragment", + "host", + "middleware", + "modifier", + "path", + "port", + "query", + "rfc3986", + "scheme", + "uri", + "url", + "userinfo" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-components/tree/7.5.1" + }, + "funding": [ + { + "url": "https://github.com/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:40:02+00:00" + }, { "name": "mockery/mockery", "version": "1.6.12", @@ -7806,6 +9212,89 @@ ], "time": "2025-08-20T13:10:51+00:00" }, + { + "name": "pestphp/pest-plugin-browser", + "version": "v4.1.1", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-browser.git", + "reference": "da70fce21e4b33ba22bef1276f654e77676213d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-browser/zipball/da70fce21e4b33ba22bef1276f654e77676213d7", + "reference": "da70fce21e4b33ba22bef1276f654e77676213d7", + "shasum": "" + }, + "require": { + "amphp/amp": "^3.1.1", + "amphp/http-server": "^3.4.3", + "amphp/websocket-client": "^2.0.2", + "ext-sockets": "*", + "pestphp/pest": "^4.1.0", + "pestphp/pest-plugin": "^4.0.0", + "php": "^8.3", + "symfony/process": "^7.3.4" + }, + "require-dev": { + "ext-pcntl": "*", + "ext-posix": "*", + "livewire/livewire": "^3.6.4", + "nunomaduro/collision": "^8.8.2", + "orchestra/testbench": "^10.6.0", + "pestphp/pest-dev-tools": "^4.0.0", + "pestphp/pest-plugin-laravel": "^4.0", + "pestphp/pest-plugin-type-coverage": "^4.0.2" + }, + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Browser\\Plugin" + ] + } + }, + "autoload": { + "files": [ + "src/Autoload.php" + ], + "psr-4": { + "Pest\\Browser\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Pest plugin to test browser interactions", + "keywords": [ + "browser", + "framework", + "pest", + "php", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-browser/tree/v4.1.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2025-09-29T01:31:33+00:00" + }, { "name": "pestphp/pest-plugin-laravel", "version": "v4.0.0", @@ -8744,6 +10233,78 @@ ], "time": "2025-10-09T14:08:29+00:00" }, + { + "name": "revolt/event-loop", + "version": "v1.0.7", + "source": { + "type": "git", + "url": "https://github.com/revoltphp/event-loop.git", + "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3", + "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.15" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Revolt\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "ceesjank@gmail.com" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Rock-solid event loop for concurrent PHP applications.", + "keywords": [ + "async", + "asynchronous", + "concurrency", + "event", + "event-loop", + "non-blocking", + "scheduler" + ], + "support": { + "issues": "https://github.com/revoltphp/event-loop/issues", + "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7" + }, + "time": "2025-01-25T19:27:39+00:00" + }, { "name": "sebastian/cli-parser", "version": "4.2.0", diff --git a/package.json b/package.json index 3cf1b501..7a32949c 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "eslint-config-prettier": "^10.0.1", "eslint-plugin-react": "^7.37.3", "eslint-plugin-react-hooks": "^7.0.0", + "playwright": "^1.57.0", "prettier": "^3.4.2", "prettier-plugin-organize-imports": "^4.1.0", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/resources/js/components/ui/amount-input.tsx b/resources/js/components/ui/amount-input.tsx index 48ec4614..aff78046 100644 --- a/resources/js/components/ui/amount-input.tsx +++ b/resources/js/components/ui/amount-input.tsx @@ -1,11 +1,6 @@ import * as React from 'react'; -import { - InputGroup, - InputGroupAddon, - InputGroupInput, - InputGroupText, -} from '@/components/ui/input-group'; +import { Input } from '@/components/ui/input'; interface AmountInputProps { value: number; @@ -27,6 +22,26 @@ const getCurrencySymbol = (currencyCode: string): string => { return symbols[currencyCode] || currencyCode; }; +const formatCurrency = (value: number): string => { + const amount = value / 100; + return new Intl.NumberFormat(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }).format(amount); +}; + +const parseInputValue = (input: string): number => { + const cleaned = input.replace(/[^\d.,]/g, ''); + const normalized = cleaned.replace(',', '.'); + const parsed = parseFloat(normalized); + + if (isNaN(parsed)) { + return 0; + } + + return Math.round(parsed * 100); +}; + export const AmountInput = React.forwardRef( ( { @@ -41,80 +56,60 @@ export const AmountInput = React.forwardRef( ref, ) => { const [displayValue, setDisplayValue] = React.useState(''); + const [isFocused, setIsFocused] = React.useState(false); React.useEffect(() => { - if (value === 0) { - setDisplayValue(''); + if (!isFocused) { + if (value === 0) { + setDisplayValue(''); + } else { + setDisplayValue(formatCurrency(value)); + } + } + }, [value, isFocused]); + + const handleFocus = () => { + setIsFocused(true); + if (value > 0) { + const amount = (value / 100).toFixed(2); + setDisplayValue(amount); } else { - setDisplayValue((value / 100).toFixed(2)); + setDisplayValue(''); } - }, [value]); - - const handleChange = (e: React.ChangeEvent) => { - const inputValue = e.target.value; - - if (inputValue === '' || inputValue === '-') { - setDisplayValue(inputValue); - onChange(0); - return; - } - - const numericValue = inputValue.replace(/[^\d.-]/g, ''); - - if (numericValue === '' || numericValue === '-') { - setDisplayValue(numericValue); - onChange(0); - return; - } - - const parsedValue = parseFloat(numericValue); - - if (isNaN(parsedValue)) { - return; - } - - setDisplayValue(numericValue); - - const valueInCents = Math.round(parsedValue * 100); - onChange(valueInCents); }; const handleBlur = () => { - if (displayValue === '' || displayValue === '-') { - setDisplayValue(''); - onChange(0); - return; - } - - const parsedValue = parseFloat(displayValue); - if (!isNaN(parsedValue)) { - setDisplayValue(parsedValue.toFixed(2)); - } + setIsFocused(false); + const valueInCents = parseInputValue(displayValue); + onChange(valueInCents); }; + const handleChange = (e: React.ChangeEvent) => { + setDisplayValue(e.target.value); + }; + + const currencySymbol = getCurrencySymbol(currencyCode); + return ( - - - - {getCurrencySymbol(currencyCode)} - - - + + {currencySymbol} + + - - {currencyCode} - - + ); }, ); diff --git a/tests/Browser/AmountInputTest.php b/tests/Browser/AmountInputTest.php new file mode 100644 index 00000000..4b6165ed --- /dev/null +++ b/tests/Browser/AmountInputTest.php @@ -0,0 +1,74 @@ +create(['encryption_salt' => str_repeat('a', 24)]); + $category = Category::factory()->create(['user_id' => $user->id]); + $account = Account::factory()->create(['user_id' => $user->id]); + + actingAs($user); + + $page = visit('/transactions'); + + $page->assertSee('Transactions') + ->click('Add Transaction') + ->wait(1) + ->fill('#amount', '123.45') + ->click('description') + ->wait(0.5) + ->assertNoJavascriptErrors(); +}); + +it('accepts comma as decimal separator', function () { + $user = User::factory()->create(['encryption_salt' => str_repeat('a', 24)]); + $category = Category::factory()->create(['user_id' => $user->id]); + $account = Account::factory()->create(['user_id' => $user->id]); + + actingAs($user); + + $page = visit('/transactions'); + + $page->assertSee('Transactions') + ->click('Add Transaction') + ->wait(1) + ->fill('#amount', '10,50') + ->click('description') + ->wait(0.5) + ->assertNoJavascriptErrors(); +}); + +it('can create a transaction with amount input', function () { + $user = User::factory()->create(['encryption_salt' => str_repeat('a', 24)]); + $category = Category::factory()->create(['user_id' => $user->id]); + $account = Account::factory()->create(['user_id' => $user->id]); + + actingAs($user); + + $page = visit('/transactions'); + + $page->assertSee('Transactions') + ->click('Add Transaction') + ->wait(1) + ->fill('description', 'Test Transaction') + ->click('Select Account') + ->wait(0.5) + ->click($account->name) + ->click('Select Category') + ->wait(0.5) + ->click($category->name) + ->fill('#amount', '123.45') + ->click('Create') + ->wait(2) + ->assertNoJavascriptErrors(); + + $this->assertDatabaseHas('transactions', [ + 'user_id' => $user->id, + 'description' => 'Test Transaction', + 'amount' => 12345, + ]); +}); diff --git a/tests/Browser/AutomationRuleBuilderTest.php b/tests/Browser/AutomationRuleBuilderTest.php index 556a3bfb..b28eecd7 100644 --- a/tests/Browser/AutomationRuleBuilderTest.php +++ b/tests/Browser/AutomationRuleBuilderTest.php @@ -11,7 +11,7 @@ beforeEach(function () { }); it('can create an automation rule with visual builder', function () { - $user = User::factory()->create(); + $user = User::factory()->create(['encryption_salt' => str_repeat('a', 24)]); $category = Category::factory()->create(['user_id' => $user->id]); actingAs($user); diff --git a/tests/Browser/Screenshots/it_can_type_integer_values_in_amount_field.png b/tests/Browser/Screenshots/it_can_type_integer_values_in_amount_field.png new file mode 100644 index 0000000000000000000000000000000000000000..11facfa7770e3402474ba51b7d25fe15a1d0406c GIT binary patch literal 47172 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 kJf~lG}^x&()K-+*i>3Bux zfj%jrd?|fHeZ)nXOb*Kh)8~HlsVY?i;?JK~OxkGUw~jNe*!ziZI-cJ$tZ;>=k!we3 z%oS_#FqhQjH<$lvQKRbNu!Ab^-juIoAFBWKw%?w`^n-zWSsGDcG&pWztK@sMWqpUz#I5%ym9svQr;D*_*(Y7 zBqP3Z`!+0X>i>EvN$-8zWHr{_#oN60_U%bMy_A999LhVgRyU5XWxx7AGc5UEE$7-X za5e>W8b75;0I{vliTg{ne^T}&yXTFV4~L=r?d}$bYZR8}hsJ)$Oedne<2TUl^?ddT z4J|sJi!UgccZ@EeTaMKpR}uYoKu}O4;_B6_w4RReofdVPya;?5&<6#@#23>QCl7-w zMd*nPQWc-mb}z!tD=hvtD}kcjyO@w}*wqyxXg!(Fqr@;Q^aE>VjL+ny)iG4kyJN264#%04 z*I5Uf(9e|261z^vf6 zv{(aeaBu=h(;wb#@T}L!BMyE@{0vvj+?*W?8Iyi>ZMDnPaLfyyX?-xIpnZ#6P^~mX zWy#2e<`c-2tmW5M6ut`EA z9*t~ww`3&bSXb=~BVzvy#Zz;9A_RKulxd#x$6X!d9EipbP2F7cG_r27pWBFZBH5C2(J$v;GUft0u)*K)qA48cJpU zp~wm7#f&?3;3D(bvLlBZ5+Ra=f`8#nuj)?N4Rjz@@nSdf5kEsVxG|(b5Ib`6%;#Rv z*(_&6T3dd^N044?V1$ref*Pzmy^$K6ar<-ACiNA`#Nc1$1PTMWQ`{$h zqMX%p9%6}M1FwRC=c1QTT7{0xB_!!XC%9m$li@l47VSv65F@7qZmp$cQ_KiZ8;(Vr zRw+NhNVIM^x=G%2Yy65UXUy6%P6d{;>e{BXE#xX29-97qn+YPiBJ3{o)HkeMTNke0 zbXs+PjeCQ&sH_H`GEMWEV~Ibp#SPjLt6^4sVI~=+{&VSJtEx{{>g!oyne<>?*+!w0 z4P3{LmZ2f$0C75THU*G=C$i1xdP)$R8XRT$wsGlb(A{A3!PcS^b9F>&O+ZdzXNt{w zlvKN3=!~dmOlu`?`xbwUt`q|vs6^!XDW^I8B_ zR9ga$4!6J;z{I@iLKigZpGHQ6&zDeatQFB!;^S}n6UpG*%sAAd?lkQMPA}Vt(1xg4 zWI*F=8~~>T_5tsTzCd<<5XE#QcnzzWnO!QLNoC;V5pp$P72CHH*e&eq{I3kbswYUA zAqXV8sEyIvydtYlo6 zI?N!p?KTN(Y89Mk9W4`sfGVs+tx$Ji%?*|Jb{ad|8of;CkBGRd^Rt_WS)(TB4lz%&HM*u|_zDm=DFg|vl+#;8n|Dk- ztW`SLq3)I14=bsg{_Do%Qz19%RN0XR;sw|onsAeB?juf1?D2hVF<^tK34Z_|wso~i zM5B^6Hgsk>dt(EmIq2T~u^?r@XSEMR1gQ8QQcKu)ryyZX*gGtD{pT=qf6%dwXMc^8&j(3;+%4`@q_z`Nrcg{%g0kYB)WKZ@d0#~3SaoPL(a&7Aw|PcX1o1sb8O#1>r4Q=jhYEJZ?QFLRrFX78#R=wmZ2|Tx^(P z+;%rMm5s#~s>npoc0IdY|Kh?4&QUO5>T@!(}Lt?dtA;+N0 z_?IGBIMIvj2T*mzF1+0-EZTTR$K8uEsB$Ch-Dr~w>qTuUn_yX_iVXJXyH*Hh`qNnZ z-D;+_;_VWUU}IAF91fPOT3AfktTwyczNkro#LNS`^upZ zVB3}EvXXh%48y~sVZ{oLcCCa=Gj>|_Dx%W_$$MQlX{>%ab1CC{eSM0kLN%kbc0wme z5;Ye5>QZHkD~*!HwDi8Fg2CRn=iWlC?M#H{{3!@NGKDq3!3RLAAJ1)~TLrC9g;>b# zO(C(A6gjMz2y`Jgh2`s)sI7)`2}0qz62g2lliUtrhQ%;%v&i?gckQ1LtjigfGic@6 z%>~J)#Dk~apRj$BHY*N1CVo^%XqW`A>_*IbxBi^VDBsy~og+pMRx^Y)!KU)qb+?_- z(|f0D4yK(%+J^HIu!HRc??7hb)5W+Lclas=zV-ok9igUHM58SO2~!^oZ^(QB+!n+m z0^Y)~4Oetw$a=*7lB4C)_34pbbhOBXCAdy9BYO%OiCiHRR|Oxy=2Q?V<=O3U&YHRk z0?Vw!xYVfP8p^zNFod(qZ@NYnyR$t-O9Ks;=SHgH|Ww!VemcCjJ<+?7vEpP*4M%je#$>y%5th@W#ii z)7B$v@6D+{1P0kZ}A+U&63TdZSl2t6kT9(@Uq+gdtNCeI)wZ^UQ;n;@ z{}CM@Y}-V6l<4&m$r7v0RjpC}B@6h&oaUy^h6)r>`(w zOm^IXeru}i^1 zCiOdnbQv}#%CmN0AF*Q8Lh@?H+^i|49m zE+?((hzpt}0k);CJ7}dO!z<&<$qW5xL*cHn$eq4B*VuIhaTHK-)43enrdC7C&k}&Z z+S7q9^Y_`)&T`XaF*3t4#0jhs(~z_i$0L4+&7>Uyq_|N@5!VoL3|SYYTX^;Y z!+!kZSKRa?AJclFS>uHa1uDtGr>A9%`mLs{i1-Tk^p)-PCrT70Ff3w!vaQgDL};#* z?}8R|kgIX-0cfyf8o-DyGN8b=HjPMd)4EJ7D(TxXxFd=_q*-t3m?#8h6`pyI*m=yw<1)}<$WRW6K$5@5_aHGg!*eoasi!9*zYhBkhJi}!QdLi} zH^RvLtCF(EV}5WH(_a{WfFdbT->okYq97c=h&9gbA=D?IXN1NnMqX3%-E-nr+-Gd` zZ2e^Ja)rd$X(I@f;iW78_5C_R{ogt)AxCLD#;KiY664*6gVp*zJR<686bVecEl z)mf<<+d-rpWHo0|(KAO!+;1bz*3;tZU&ikiO3(CB>qDawvxE~az$x>K$=EWS* z=8lLkVr=+4;hUBqK081ET}4sk1@4EHIpfB$@rCBqZ$^a$kKetd9?BtjliER|T~(Dc zLpL+xyv4T-lDk(JyPdr$Rw~7Ms(R~;KF`b=Zxiu4wK_^ojtPql&fc(?+q89iK1uA1 z3V{%IJVQUPc~6iCF&Ef#$}wnTn+@D zuAXM}7Z53uVX;4`qo3v9C-SRXdr=woZ=}pCAfU%$VFqP6TEm z%7CVoW5Vd=zW_G(;4m3jd7#eXLY7YI20t&a50?XcDtN@Wgo4yO-!5z?cpk;>u^hO+ zPFHJfKkaNZ`|B@b*^{y$kN+XV^Bc2zaA+k&H_LziKfc!g>fF-5R7?K`%kObPyWxP} zsMVEjf_CpiCiPqH1q0z5ryu{VnEFrj5C4Dqfq(zVQYk6Q{r~}_phl$B8kqUMQ1!w6d!yRcrgP4Yv?4OYqky&t_FlFRqYD!#KI3^ z^ZPOglToH#tjjx!#GD?9*KxXd;%iU)wdigj&vyQ7T~ExIG+-A zm<+k3;RSL5w_Ou)hz$t>e%A~lc+#m4e?UAlfz&3u%4HWF(gss_ZGn1{7#YI8Ijmn9 zZxFU?O!;pRi~%;WO<#qEQX?|f@HF1fR|02`9a;9iK4}=R(23}VX%=^y&v9aO-@w4Y z3|`n3&Of-jM#xl)rQwm0d8{4#zO#QkzXdnm#6HBQZl{4TK{Xq3xn^buMlT&9OG(Q<8A zy2z0qNJTKr@>Cd^9Y>!AtK%qeTiMPw2?fo0^OItsid!s5BV zszHM0i}}YF$J`XJf(Qmt7Cl`rJYje88r`Gk4FCbAf`N|zg@=AEzB#eBgf#Rn(}kG_#G+0j)6cS3ytkO$4%;d+|Vhua(c*&KoGOJ zbOl;wzSS@&O`%X)`5*^F~Kwb#A;Xi zd(tO9Kb5Y$>p$P*0by0vnz|e-gDM&^wy$S@U1nU&fpZ_sZB6O9;=IY zktYyj9ayR10b-lu#^vgi)Cz)e>mpHh`rP#5pKjgLOIb9of9=a*PiKHk$`N9OMm zex=cek}vwt<&Zjqy1?L)3Xzm0eZXld*kwCKC>MjPLVDEwQQ`+N3afIFqeZk43Skp6 z$Cb#!RK|dLp~wnbJ5O5LKZtA@FxJ=lm@3c=-ak1Sy@g#V>P9E!O$+bc26Qn*4ul7c zThV^!l#VEO4Jx>_Snlcj6N9z=4=Sz_S2>(b`$yozXrg1~zHIRBd2t99w7UKJ*=yIX ztqc`NT~NJx9!O6U&-5bZA2wTHHfjVl%s%~^P`rrH)V;+HsHQ?+ITOzj;5iYsAyXv? zvlfw!qqcIv$}Dbq(n7x(ypTUR=1|hCKgucefrVM!sa=ccc7yM1@5>0==b1 zxr|lhEsJ77DPCP})-PH6dX+eAD$(6ipvL`c-08>DjFVlpNZ=Se?hgOuYxtgy=uC$V zatuYS%SHUg^^$2V2!S+}hz`*pUm}(B3tB}mC(Y0b0l~zrEJpil@v31iy!~}pPq-Yg zSJ_SIN=n|KhvQZF0j^yF7CJDU(Sok000$W9pXzBE#p?@6B}jOj3fwf@++pBQ?c&RK z6&q>+WN@19`x6I(a#a8o6O`+S%o|^pYZ;klt=0&E#5#g?&UVx0n$zkC>sR!4{|@WG zFTTSm^!dq&B@gcNXhK2kojjNTp(2rCCGg=QF$yDtTM<)%G7y`Js0BjlBsSI&@8-Mk z+St3Ffi$OWCI#m*b4UfL92)wjWfMyz?0cYwDqM)JZD%uGr)ZW)QX z$m3@gwk0osvZ%_bluq|@03odw(<1D)@9Ql!<~lf0U~cPJu?m~`+(4P)@p)Sh4-eIc zDh5`TXFRVjx+6|0XyF{M~F`3157qcW@@J{OgCd0Y$0C?)aBITGFE8w12jcg3cVxVQt!=g|)) zP5b2^l&GIZmkZs22BauXnD{9dO3L;)B?Aby$h4V0mjB;Ck(FRllRqcxkr}2!pWiwZ ziEK3%SEq?3p+)@u^6pdZFE5`#dpA0hL-A<|SdU3JWd43!%*HUat%31TMv#dOK9Zzk zpzLzOg`bt64g!V%3t}TqP^G|sN&uXqMMx08fAPtBh~J&i2{7U$W1K;Tp8xq%bM0O2 zkl)Ma$()R|3ueUr-rm;BmbaPN)L_T_{^@(qaFq}|5j!rkJqf8Pe8Is%z_(-{ULF%b zL2*h8oD%7~J0?J;#yAZ)29Yrd(1k0Yv5y?vghhl5+*<(8`=KHrChstV)x&bc4Z^(C3wY}uu#NO-2a!)a&h0)`ZpSz zcmFk*k-1U-4_a!U6fyLUR#V%tve-3;XTD~_=uJs~uMM9S3p%fI# zE0-VCJ!<&P;Qk8u9q*p~u^bb3v;02B2UjddvVVT`pJn=IOZ;3u+kU<*P=mV=I&Q+~;a~_|Ku{W# zotbE)X)HpedK$ll;>9}+s!d8*n;JCvw=<15#J)$P+`iMUrM^V~PMheA&tUkJS$o!~ z*!)+UZ?7mTJ^|R?E4%oGRh*7nU$VMjs#zOT3+r~8XDFprk?EPl96hJQFx1>nXgJPS zpi6KKq06C}zSMWfqt&)S-s9VKrms1@e%y{2ZX%O(mzt0`$xy2Pj`P((?(#1%#zDkF6%o3GaXIMpS?^=IkO#5r4RZEkIhb{dgzkH z@ucbE5nnZ78Xq68`Hqu-zi(~8s__0MfZiZ`N=_6gyTx-&sZ=80O2ii@{NXL(ZJv;r z2-@bA7F`Faw){`m)`M^0(4?wf^XLex8sRKK0VMqO#T%~NFArdFSTUxwp#KXrjg+{! zoUiFs)0iw8YLOS8bLP0KJut`mu!RgEWv_1&l=_oaKIo+t5Eu|(8C}~5`8#=FUjV}e=OUzHq%r) z3^|4b2rO20?0*9ho*p=2LGzkFTLPdT?*2nOzb@9s?if}=mCNvV#m$cWC=wDhE^Wva>s;b4E~BsN#W|U z$nLZ+JN~82JiC*hNAE`|h%*^+w{L22DKLtB@?2g8GR|{S4@`4pzdXF&I-*HHtA0X;*9;WJ&LA2Z8XMEVz(6}V)mVrG`J9TH&~^NL6DMC?$Eu94 zMd#)0*7LM9`5Z#0aMYr;%2x!KFilh6R?0T<7oDEP0>cLP7d~=J*s?V>1$$B8(1z0E z5S#3yI_J=7M~=VG?I0X-V<+x{No7FCetMt3h%&bG(6{HI z7W7B0FLsvWxI7lL>H+uH;0hjHSzy^b{O2J!i>5B0gbl|$i2%WO`yCMs3UG2_+JqU= zY`-{hJI@x*dG8F;3c!pieZuX;0q2HML_sc#f*eWW0D^ss#yB;1+A`e8e&>?=nx0!b zEq0_T4K{0D4qL-des{0kkR{cQ39jLDyrqu5(+*>~16}s*=Af7^nIQ1@`Ux{ym2N3B z#I8)Uhu<|g&w4gBe0a^TJ@0y$76xTN86l?fPEJnS3eloA&+QB1cJHvNz*%&|IrlNn zZZk=g8h@zq5sh<8d=-J0ODqapD!AE`!I?g{`D8@D;w;&hC^7ch1?$=$B$q(RyXYh@ zy{bkm$KrtaQf_*B`c-qVcQUak(*Epj>nFA-t%_btYblQDtr$sv#N>P$n^;uWG-PT| zFe0GyjYhf?tpEu1A<4!KOA&goSI?Yfp1R8*Oq_2DhZ7QIlPG#3#OSTC0YR=_4&ni_ z_=J|w9`dH)1*IyAeOz`^#i?pd)1JApG1a?U|IX*st4{04-ifj-PG`IYx<}I0^-st< zK3|rh+_lQ;AWWld!BpT%rhpuQ+p4D&@i+hXLkJx2p*Ga0%eg_O&O8n8b6ShRa%9i^ zS3-d^t5@l(sy1M;jj58RR*tb6$+S!jGBRu5Uuo{40j4wagmU!e@j>Gdk_tlb2t!>J85(FK}GE zTlALZTI}{gkvsSEy$9oZ=mPtscbcmRbYY?yu5jMNst73f4@|$A$B!SA01)QTm5Uj` zM0%;ts($hQ>V2!ps8Wy!H=6Nd)FgOh`WPou)_$Z`Fd7{|7V@Ap6oTG}Zbm}!228Ph zyze^aoPc*r7rtv@zH&~FH#-+Tb;yeheV@VBD~z1P1pwKNon=0>x68L_-{qeol9#YR zQdHIve`5jc_~T~kf;|JO2bepSgw;1OO|ESOPz;I6uiPIBHlYEQ_Yi+5h*|j3JZ!KD zlLwkLsX$?*E$-7VBa&a%3YGDvkr}Eo_jh4*II@;~Uqs1DD0RwvN2)hd=& zPqqtKHTukAd)3^a2!L0bIDB$J4*H#Olq;UoV$^EZa&@hHI3A?@rQm>R+BZ;k@OYTD zx-JFlHvhi#5p+Yj#lRwjG=oQMEV%er-yWn0NPsXpL#&+W|J2phTWYrUS)jF=b{Lx( zr}Zlc_#&ej4Hzu%uWgabVt;3tL_O)vcOPh&iDOnBvMVOUyrsF+C5$F~IO_#rdHF0d z5&Mzk>?{!OR`yW|f4u_hn(|m=D_qcjdS|k>csuP^crtri{8uCtjY^y(Ph$;tj4CJ) zQ6n+2j?&;WrTFYIZf!)HRoyA+={zRAt2T*jUORdBNUh^Qm_yX*AhN}t-sgz${OHxJ z>(JSgRESa67Fn%^lnl0tUvkOD$MM=StN)8UzZN_l_h?^!WF&=qe}ej&_4%m5YjPs7 zU2zj%u`P^q#D>Qi^d%!-K4#}oAKmZ&s|5tHK{p6~=HUF@joDrLGnjrp8vw81a#I|3 z1J@e9mJXaoebpbYG`t?8#a<1z6`#F-O;3m(>{~VRrIPhSH}ZcxUw7hNkuJHIdnrh= zWS-T!zYW^9B8}zEE}ibmb-_ZC45=m;&w5C!#J`oS8Yz#iK{k2<3P-PrNmbE(&a#AHfMFO%<)SZi~BCJz^+Hw7wEij z#N4f{$;f#jjII?R)8dDRhf$PN%u*i;KGzu4!V|o>W!;EmU}CnLRi-t+1UF3Q5Q(}3M#1CgJ< zp%UJfsP6=yY=7IFq35AQ^lg_fc?ECA5D8_~yLaAHJMak==Y*pAFptt6IRPx{UAU<^ zQ^%Mq)--m0neg}c)w_an*OiYKZkJ7>&WMuYDyoS}w^UzV`Af!+C`)^W+eq42cON1b z9@-RW?VW?iAo(i#+-hP1*Yi)%j5%UYGa_9^a%738epeNj>3bx=#SIF=7{J2)oK#jm zGDj-jdTrTv&Uq*X+tLmW*8-ik4Vye>-|Xl%iuT3dw>sgzJ!NTXCq-X}qbym8K2q}~Y5#zjpqjP$+z+P-}2^WgUB3DUN} zdy?_nDUf3E1-UTJ(tCqF*V>}Wz70nEb8$)6Vkp+sEv+prd)v#ZNd^xO0hOdqs|p5? zIXu8HMk;rxYYe2{vQesihsd0%8SEhBRf!1+RG?hoad4K;PmOHfDURs3h1XwrET>1Q z_H-(!iw<2*1DG)029h=(;uy#+8ynxe#x>?%#hDFe;EyCkS?u4Xh3+L$>Wg=ge!3uS zY-(ysGr>9bJ3$6<;W?f;+82=L_R?g8ss4F1V zQ5~-?GV6`WAXA#~?7h8Xy4^u5CFL+XyXmI}gId8_mUEH6I5&kH|8=6Vu~Aad&%YDivZ?Xdj@g=vZsvD-yLrmXQgeSyz4+l@A>`2)D>GPa zsJMwN^eh)=#F5Pxep;{Di@!;TvNzK$x2H>FkNsalyD9!FBiwEdE7B60Vetv$jvcAU zZUHq+kZ@0%xtzt9tTV(3dV3Sq3Zmbgo6f!Ww-`j`6nGBzWG(~dODAYDo z@$Xh^P6(z7j!QX`m7x0jUn#2Cc1v%5@>}0nJa!IuR!T|=v|7Grw=8Fix!U_zaIgCW zeo=4c58rLsvUhKN%!t2SKz?V*q{=xHGoT`%V$PONy-;L+8iQBQ8QUT!NELP7BJ4RFxSUe@sEqY^(INH5vj?j3hDO@)PH+;o$5U0L& z;Sxp#g&`U*kfHh1Zf+n`0h5wA<_Afw0!%;~vF1GrJiP1}h8)u)`LWGLjH&R832Xos z(27!g_6|7vbcKh4C^zi*P%@2dzzhjeZ?^gQP>ct;h!kt04OH3scb^E};4uT0LoQkM z66<=S72L-^_guff+W%;O2(F3lD{nR;7d;zLbkb$ZJR|DmjRGAnKK3IW@}1tk-ebPK zyB3KRRzwF;)8`E11o!+P91aRVP$x+k($j604v5}w1CSK~^pQa{WeQSLsGHqOU;diE z-OL7v7dg!vDNEu0EF)p&SPQ=nZtqbwZF5yEI!S6bq%Hc9prs*TT_!W1Jo_T+xGtR2 zm)HebHsB@)#H+7)BSgpVYisxU=63tR51#?9=(_eIxu28~pR0pmM_Rzc?L?qVawC}F zatvR%fQxnv(o%?7wFMwx4E8QZ) zp>_CB-e6Qz2N_b2CoDYPfn7h6lAoe6PqJEsaEX{a;1+Ge1b)+WH*ukw|N*$XpFO5MI^}yv|rbDw2C7wSM>*DHO zy~`N>7IVoGdiRNFDa}Rk%%1Z-<{Ostu-RHZEs3O*lyk0!(^VR?d;WMM6pMKc)a)0$ z+CE}8#ylzb2G@fMQ}8B-eZ_Gf02^@Y99#PJehDs;6@R)Scb>&|&`l5(=3zUx>obz& z226lNR;UjZI5*+wcO%m->-(s*1190LG2_@DU%QK!AQq0UkdpNocEFV!U~(wcZ`BSF z$8U%fXK*MLk(-#R%2p9kLc@vIYcXD5c?p9Ool?HgNB3c_hh6mnIJ_@jzrz&qF(Ogz8X{d$tw?0q=2U=)^6T zx8t~u0qWt2R{)d_b-7Wcs?JR34ut#s!H;Q-8eVzZCoB%K9wNe_i9AG;VES#hts0eN z0!<=*P#@*E)&{r|RR(Z5b&U38Ehj0*pI%!UdqxR7!pi787>R1h){4IasYy@12$F;{ z%D~`YnKqwvHMw(2N)!3r3n?LAo;_5U172K@tXFwds&&gcA9f!DVk#xtA7Vfso}i#o z3rUDn?K~3Ky{}UM`f~3$c6be8@jLob31c!I9*c#knGb!cSLyM9$8j zcR7DFi@i&_#MdKzR%RLW_!efG;kn~fO4ms{yD5|$St$H?3wl-6bu&@4H8(aEOul39 zMrE_TkUIBjKD}~5rTm9l+7=4pvq<8PZ2(p?iJ#b=rC#@`8j_0j(0YY zDd}PtB%b=AA04i5>!){I(q655W%h{d6ZVTBnN#BZoU+{$Rw1FQj2 zo`|1T$?y46DmaT9tDHN)Hi@819DGQrq)9Bk@3aCoj475r4$ zcD;b2=Vl3O?C+RE`NF`Bb$1|>QHRS(X*V00g{xe7^o+{cvuE#;5tJnM=c<|6kbE4w z_6BP9;wM(c4-(X`k~rY$vd4;f0G?h#`Jz8xjNIEjV|w| zRWE4%js}CE)@QP-2S1_2(Bn;IQQ%2!u9rJEfVkn?f`JJg& zSWb7pRaTffmi)0Fc*$M&Y+x$E*c@aQd}`is!e29bCQdWjHIgx)cU6I-6LexPgF+}j zXOYye$+TC{(N|Sf^|mC&#l;DDtUAldW<3Bty9ZW{Ajfs0hjKn$E6X;voha)KCgYEM zvbPBIns>f@`8(4l7l}jd`OnBwMmlo8;~I)KS5;T{-zhNmdi|j%yvE8Ca-W@}Hj~JJjNa0e9uP?9RW7KWO-RtCH%+nv!h#r) z0?;2_jh(~8A8EDCloH&|TTSpQ_YxEpArDhjj)>_4y6_87o0AT*PCzdRODZq!_7ia^pYfvRP`)5G$!l?{@=lgoJYOTBQ@rz2a!1MyK*6*(A#VCpz|%F10QBLTPD z!h_RXcjDA7A3)qoq@+Jok;)4~y_L6fnlom0b^=RukZcRQw)Don1Q90pubraI-y_7D}7w!3k40vBN?-hYJYj|CK zN~8sFS0HBS;ql&Pu-CZLcNxIqgx<9HVz0QYul#bo700^X%XfNnU`RF^YKY=B{6=sg z8`}Ak$|6twJqqeP3TeQu4aii+#Y{9Rm1Xv}Q)*t?8Ee+wg3gqm72 zR#f`v<-^A>%1wodPA?k-Xz29nG3@$GW(#-o{F1t6mb7_!%BZVB)w2&$C(Q6(QPIkF zp9Fr?0_;z^U>iMov01~%K|#Kglaufys6jIr)ds4X)5YpY>M_G;8FMdLcV2UK>G5YJ zC}dUC)M}ym257p`OjAt_+dC2CfZxe4*R1Eu(#%%r$7gL&YfMPUJpbz2fjjtR%VnF! z&Qwm5K=O*7G}S*%a9<32omAc~H=InpSu=)!&}7YDyh}_;sa0F+l@t~AJUBRb{qk>(X?vNp zHxM3*7f#`q(0b5pEVWzy#WIo)PO_ZVVcDJT&6Y^B9uIc8!=3aRrP$dg?t>d7XPL?( zB(Zh~#-p0m_@NRu_SYxB+(#OQHo>q@vG@K=SjR5I#~LhBJB%SD-1dN_`OO2*w+Ts( zezL!AN*a-Ch&+$;G+R$GzdnhF`m$lu>6LpEb7tRo6~T_|J4zOSVgpz&QZag}N?g3> zwdcO%-n+b4<}MsSe(Luq_(mM4W{yC#hyextend(Tests\TestCase::class) ->use(Illuminate\Foundation\Testing\RefreshDatabase::class) ->in('Feature'); +pest()->extend(Tests\TestCase::class) + ->use(Illuminate\Foundation\Testing\RefreshDatabase::class) + ->in('Browser'); + /* |-------------------------------------------------------------------------- | Expectations