Compare commits
2 Commits
2ef5014919
...
fix/submit
| Author | SHA1 | Date | |
|---|---|---|---|
| e01caf678b | |||
| de6e7e6632 |
@@ -1,129 +0,0 @@
|
|||||||
---
|
|
||||||
name: tailwindcss-development
|
|
||||||
description: "Styles applications using Tailwind CSS v4 utilities. Activates when adding styles, restyling components, working with gradients, spacing, layout, flex, grid, responsive design, dark mode, colors, typography, or borders; or when the user mentions CSS, styling, classes, Tailwind, restyle, hero section, cards, buttons, or any visual/UI changes."
|
|
||||||
license: MIT
|
|
||||||
metadata:
|
|
||||||
author: laravel
|
|
||||||
---
|
|
||||||
|
|
||||||
# Tailwind CSS Development
|
|
||||||
|
|
||||||
## When to Apply
|
|
||||||
|
|
||||||
Activate this skill when:
|
|
||||||
|
|
||||||
- Adding styles to components or pages
|
|
||||||
- Working with responsive design
|
|
||||||
- Implementing dark mode
|
|
||||||
- Extracting repeated patterns into components
|
|
||||||
- Debugging spacing or layout issues
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Use `search-docs` for detailed Tailwind CSS v4 patterns and documentation.
|
|
||||||
|
|
||||||
## Basic Usage
|
|
||||||
|
|
||||||
- Use Tailwind CSS classes to style HTML. Check and follow existing Tailwind conventions in the project before introducing new patterns.
|
|
||||||
- Offer to extract repeated patterns into components that match the project's conventions (e.g., Blade, JSX, Vue).
|
|
||||||
- Consider class placement, order, priority, and defaults. Remove redundant classes, add classes to parent or child elements carefully to reduce repetition, and group elements logically.
|
|
||||||
|
|
||||||
## Tailwind CSS v4 Specifics
|
|
||||||
|
|
||||||
- Always use Tailwind CSS v4 and avoid deprecated utilities.
|
|
||||||
- `corePlugins` is not supported in Tailwind v4.
|
|
||||||
|
|
||||||
### CSS-First Configuration
|
|
||||||
|
|
||||||
In Tailwind v4, configuration is CSS-first using the `@theme` directive — no separate `tailwind.config.js` file is needed:
|
|
||||||
|
|
||||||
<!-- CSS-First Config -->
|
|
||||||
```css
|
|
||||||
@theme {
|
|
||||||
--color-brand: oklch(0.72 0.11 178);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Import Syntax
|
|
||||||
|
|
||||||
In Tailwind v4, import Tailwind with a regular CSS `@import` statement instead of the `@tailwind` directives used in v3:
|
|
||||||
|
|
||||||
<!-- v4 Import Syntax -->
|
|
||||||
```diff
|
|
||||||
- @tailwind base;
|
|
||||||
- @tailwind components;
|
|
||||||
- @tailwind utilities;
|
|
||||||
+ @import "tailwindcss";
|
|
||||||
```
|
|
||||||
|
|
||||||
### Replaced Utilities
|
|
||||||
|
|
||||||
Tailwind v4 removed deprecated utilities. Use the replacements shown below. Opacity values remain numeric.
|
|
||||||
|
|
||||||
| Deprecated | Replacement |
|
|
||||||
|------------|-------------|
|
|
||||||
| bg-opacity-* | bg-black/* |
|
|
||||||
| text-opacity-* | text-black/* |
|
|
||||||
| border-opacity-* | border-black/* |
|
|
||||||
| divide-opacity-* | divide-black/* |
|
|
||||||
| ring-opacity-* | ring-black/* |
|
|
||||||
| placeholder-opacity-* | placeholder-black/* |
|
|
||||||
| flex-shrink-* | shrink-* |
|
|
||||||
| flex-grow-* | grow-* |
|
|
||||||
| overflow-ellipsis | text-ellipsis |
|
|
||||||
| decoration-slice | box-decoration-slice |
|
|
||||||
| decoration-clone | box-decoration-clone |
|
|
||||||
|
|
||||||
## Spacing
|
|
||||||
|
|
||||||
Use `gap` utilities instead of margins for spacing between siblings:
|
|
||||||
|
|
||||||
<!-- Gap Utilities -->
|
|
||||||
```html
|
|
||||||
<div class="flex gap-8">
|
|
||||||
<div>Item 1</div>
|
|
||||||
<div>Item 2</div>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dark Mode
|
|
||||||
|
|
||||||
If existing pages and components support dark mode, new pages and components must support it the same way, typically using the `dark:` variant:
|
|
||||||
|
|
||||||
<!-- Dark Mode -->
|
|
||||||
```html
|
|
||||||
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
|
|
||||||
Content adapts to color scheme
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Patterns
|
|
||||||
|
|
||||||
### Flexbox Layout
|
|
||||||
|
|
||||||
<!-- Flexbox Layout -->
|
|
||||||
```html
|
|
||||||
<div class="flex items-center justify-between gap-4">
|
|
||||||
<div>Left content</div>
|
|
||||||
<div>Right content</div>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Grid Layout
|
|
||||||
|
|
||||||
<!-- Grid Layout -->
|
|
||||||
```html
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
||||||
<div>Card 1</div>
|
|
||||||
<div>Card 2</div>
|
|
||||||
<div>Card 3</div>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Pitfalls
|
|
||||||
|
|
||||||
- Using deprecated v3 utilities (bg-opacity-*, flex-shrink-*, etc.)
|
|
||||||
- Using `@tailwind` directives instead of `@import "tailwindcss"`
|
|
||||||
- Trying to use `tailwind.config.js` instead of CSS `@theme` directive
|
|
||||||
- Using margins for spacing between siblings instead of gap utilities
|
|
||||||
- Forgetting to add dark mode variants when the project uses dark mode
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
---
|
|
||||||
name: tailwindcss-development
|
|
||||||
description: "Styles applications using Tailwind CSS v4 utilities. Activates when adding styles, restyling components, working with gradients, spacing, layout, flex, grid, responsive design, dark mode, colors, typography, or borders; or when the user mentions CSS, styling, classes, Tailwind, restyle, hero section, cards, buttons, or any visual/UI changes."
|
|
||||||
license: MIT
|
|
||||||
metadata:
|
|
||||||
author: laravel
|
|
||||||
---
|
|
||||||
|
|
||||||
# Tailwind CSS Development
|
|
||||||
|
|
||||||
## When to Apply
|
|
||||||
|
|
||||||
Activate this skill when:
|
|
||||||
|
|
||||||
- Adding styles to components or pages
|
|
||||||
- Working with responsive design
|
|
||||||
- Implementing dark mode
|
|
||||||
- Extracting repeated patterns into components
|
|
||||||
- Debugging spacing or layout issues
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
Use `search-docs` for detailed Tailwind CSS v4 patterns and documentation.
|
|
||||||
|
|
||||||
## Basic Usage
|
|
||||||
|
|
||||||
- Use Tailwind CSS classes to style HTML. Check and follow existing Tailwind conventions in the project before introducing new patterns.
|
|
||||||
- Offer to extract repeated patterns into components that match the project's conventions (e.g., Blade, JSX, Vue).
|
|
||||||
- Consider class placement, order, priority, and defaults. Remove redundant classes, add classes to parent or child elements carefully to reduce repetition, and group elements logically.
|
|
||||||
|
|
||||||
## Tailwind CSS v4 Specifics
|
|
||||||
|
|
||||||
- Always use Tailwind CSS v4 and avoid deprecated utilities.
|
|
||||||
- `corePlugins` is not supported in Tailwind v4.
|
|
||||||
|
|
||||||
### CSS-First Configuration
|
|
||||||
|
|
||||||
In Tailwind v4, configuration is CSS-first using the `@theme` directive — no separate `tailwind.config.js` file is needed:
|
|
||||||
|
|
||||||
<!-- CSS-First Config -->
|
|
||||||
```css
|
|
||||||
@theme {
|
|
||||||
--color-brand: oklch(0.72 0.11 178);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Import Syntax
|
|
||||||
|
|
||||||
In Tailwind v4, import Tailwind with a regular CSS `@import` statement instead of the `@tailwind` directives used in v3:
|
|
||||||
|
|
||||||
<!-- v4 Import Syntax -->
|
|
||||||
```diff
|
|
||||||
- @tailwind base;
|
|
||||||
- @tailwind components;
|
|
||||||
- @tailwind utilities;
|
|
||||||
+ @import "tailwindcss";
|
|
||||||
```
|
|
||||||
|
|
||||||
### Replaced Utilities
|
|
||||||
|
|
||||||
Tailwind v4 removed deprecated utilities. Use the replacements shown below. Opacity values remain numeric.
|
|
||||||
|
|
||||||
| Deprecated | Replacement |
|
|
||||||
|------------|-------------|
|
|
||||||
| bg-opacity-* | bg-black/* |
|
|
||||||
| text-opacity-* | text-black/* |
|
|
||||||
| border-opacity-* | border-black/* |
|
|
||||||
| divide-opacity-* | divide-black/* |
|
|
||||||
| ring-opacity-* | ring-black/* |
|
|
||||||
| placeholder-opacity-* | placeholder-black/* |
|
|
||||||
| flex-shrink-* | shrink-* |
|
|
||||||
| flex-grow-* | grow-* |
|
|
||||||
| overflow-ellipsis | text-ellipsis |
|
|
||||||
| decoration-slice | box-decoration-slice |
|
|
||||||
| decoration-clone | box-decoration-clone |
|
|
||||||
|
|
||||||
## Spacing
|
|
||||||
|
|
||||||
Use `gap` utilities instead of margins for spacing between siblings:
|
|
||||||
|
|
||||||
<!-- Gap Utilities -->
|
|
||||||
```html
|
|
||||||
<div class="flex gap-8">
|
|
||||||
<div>Item 1</div>
|
|
||||||
<div>Item 2</div>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dark Mode
|
|
||||||
|
|
||||||
If existing pages and components support dark mode, new pages and components must support it the same way, typically using the `dark:` variant:
|
|
||||||
|
|
||||||
<!-- Dark Mode -->
|
|
||||||
```html
|
|
||||||
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
|
|
||||||
Content adapts to color scheme
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Patterns
|
|
||||||
|
|
||||||
### Flexbox Layout
|
|
||||||
|
|
||||||
<!-- Flexbox Layout -->
|
|
||||||
```html
|
|
||||||
<div class="flex items-center justify-between gap-4">
|
|
||||||
<div>Left content</div>
|
|
||||||
<div>Right content</div>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Grid Layout
|
|
||||||
|
|
||||||
<!-- Grid Layout -->
|
|
||||||
```html
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
||||||
<div>Card 1</div>
|
|
||||||
<div>Card 2</div>
|
|
||||||
<div>Card 3</div>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Pitfalls
|
|
||||||
|
|
||||||
- Using deprecated v3 utilities (bg-opacity-*, flex-shrink-*, etc.)
|
|
||||||
- Using `@tailwind` directives instead of `@import "tailwindcss"`
|
|
||||||
- Trying to use `tailwind.config.js` instead of CSS `@theme` directive
|
|
||||||
- Using margins for spacing between siblings instead of gap utilities
|
|
||||||
- Forgetting to add dark mode variants when the project uses dark mode
|
|
||||||
20
AGENTS.md
20
AGENTS.md
@@ -9,25 +9,24 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for
|
|||||||
|
|
||||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
||||||
|
|
||||||
- php - 8.5.3
|
- php - 8.4.1
|
||||||
- filament/filament (FILAMENT) - v5
|
- filament/filament (FILAMENT) - v5
|
||||||
- laravel/framework (LARAVEL) - v12
|
- laravel/framework (LARAVEL) - v12
|
||||||
- laravel/prompts (PROMPTS) - v0
|
- laravel/prompts (PROMPTS) - v0
|
||||||
- livewire/livewire (LIVEWIRE) - v4
|
- livewire/livewire (LIVEWIRE) - v4
|
||||||
|
- larastan/larastan (LARASTAN) - v3
|
||||||
- laravel/boost (BOOST) - v2
|
- laravel/boost (BOOST) - v2
|
||||||
- laravel/mcp (MCP) - v0
|
- laravel/mcp (MCP) - v0
|
||||||
- laravel/pail (PAIL) - v1
|
- laravel/pail (PAIL) - v1
|
||||||
- laravel/pint (PINT) - v1
|
- laravel/pint (PINT) - v1
|
||||||
- laravel/sail (SAIL) - v1
|
- laravel/sail (SAIL) - v1
|
||||||
- phpunit/phpunit (PHPUNIT) - v11
|
- phpunit/phpunit (PHPUNIT) - v11
|
||||||
- tailwindcss (TAILWINDCSS) - v4
|
|
||||||
|
|
||||||
## Skills Activation
|
## Skills Activation
|
||||||
|
|
||||||
This project has domain-specific skills available. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
|
This project has domain-specific skills available. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
|
||||||
|
|
||||||
- `livewire-development` — Develops reactive Livewire 4 components. Activates when creating, updating, or modifying Livewire components; working with wire:model, wire:click, wire:loading, or any wire: directives; adding real-time updates, loading states, or reactivity; debugging component behavior; writing Livewire tests; or when the user mentions Livewire, component, counter, or reactive UI.
|
- `livewire-development` — Develops reactive Livewire 4 components. Activates when creating, updating, or modifying Livewire components; working with wire:model, wire:click, wire:loading, or any wire: directives; adding real-time updates, loading states, or reactivity; debugging component behavior; writing Livewire tests; or when the user mentions Livewire, component, counter, or reactive UI.
|
||||||
- `tailwindcss-development` — Styles applications using Tailwind CSS v4 utilities. Activates when adding styles, restyling components, working with gradients, spacing, layout, flex, grid, responsive design, dark mode, colors, typography, or borders; or when the user mentions CSS, styling, classes, Tailwind, restyle, hero section, cards, buttons, or any visual/UI changes.
|
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
@@ -133,6 +132,13 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
|||||||
|
|
||||||
- Add useful array shape type definitions when appropriate.
|
- Add useful array shape type definitions when appropriate.
|
||||||
|
|
||||||
|
=== tests rules ===
|
||||||
|
|
||||||
|
# Test Enforcement
|
||||||
|
|
||||||
|
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
||||||
|
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test --compact` with a specific filename or filter.
|
||||||
|
|
||||||
=== laravel/core rules ===
|
=== laravel/core rules ===
|
||||||
|
|
||||||
# Do Things the Laravel Way
|
# Do Things the Laravel Way
|
||||||
@@ -247,12 +253,4 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
|||||||
- To run all tests in a file: `php artisan test --compact tests/Feature/ExampleTest.php`.
|
- To run all tests in a file: `php artisan test --compact tests/Feature/ExampleTest.php`.
|
||||||
- To filter on a particular test name: `php artisan test --compact --filter=testName` (recommended after making a change to a related file).
|
- To filter on a particular test name: `php artisan test --compact --filter=testName` (recommended after making a change to a related file).
|
||||||
|
|
||||||
=== tailwindcss/core rules ===
|
|
||||||
|
|
||||||
# Tailwind CSS
|
|
||||||
|
|
||||||
- Always use existing Tailwind conventions; check project patterns before adding new ones.
|
|
||||||
- IMPORTANT: Always use `search-docs` tool for version-specific Tailwind CSS documentation and updated code examples. Never rely on training data.
|
|
||||||
- IMPORTANT: Activate `tailwindcss-development` every time you're working with a Tailwind CSS or styling-related task.
|
|
||||||
|
|
||||||
</laravel-boost-guidelines>
|
</laravel-boost-guidelines>
|
||||||
|
|||||||
20
CLAUDE.md
20
CLAUDE.md
@@ -9,25 +9,24 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for
|
|||||||
|
|
||||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
||||||
|
|
||||||
- php - 8.5.3
|
- php - 8.4.1
|
||||||
- filament/filament (FILAMENT) - v5
|
- filament/filament (FILAMENT) - v5
|
||||||
- laravel/framework (LARAVEL) - v12
|
- laravel/framework (LARAVEL) - v12
|
||||||
- laravel/prompts (PROMPTS) - v0
|
- laravel/prompts (PROMPTS) - v0
|
||||||
- livewire/livewire (LIVEWIRE) - v4
|
- livewire/livewire (LIVEWIRE) - v4
|
||||||
|
- larastan/larastan (LARASTAN) - v3
|
||||||
- laravel/boost (BOOST) - v2
|
- laravel/boost (BOOST) - v2
|
||||||
- laravel/mcp (MCP) - v0
|
- laravel/mcp (MCP) - v0
|
||||||
- laravel/pail (PAIL) - v1
|
- laravel/pail (PAIL) - v1
|
||||||
- laravel/pint (PINT) - v1
|
- laravel/pint (PINT) - v1
|
||||||
- laravel/sail (SAIL) - v1
|
- laravel/sail (SAIL) - v1
|
||||||
- phpunit/phpunit (PHPUNIT) - v11
|
- phpunit/phpunit (PHPUNIT) - v11
|
||||||
- tailwindcss (TAILWINDCSS) - v4
|
|
||||||
|
|
||||||
## Skills Activation
|
## Skills Activation
|
||||||
|
|
||||||
This project has domain-specific skills available. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
|
This project has domain-specific skills available. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
|
||||||
|
|
||||||
- `livewire-development` — Develops reactive Livewire 4 components. Activates when creating, updating, or modifying Livewire components; working with wire:model, wire:click, wire:loading, or any wire: directives; adding real-time updates, loading states, or reactivity; debugging component behavior; writing Livewire tests; or when the user mentions Livewire, component, counter, or reactive UI.
|
- `livewire-development` — Develops reactive Livewire 4 components. Activates when creating, updating, or modifying Livewire components; working with wire:model, wire:click, wire:loading, or any wire: directives; adding real-time updates, loading states, or reactivity; debugging component behavior; writing Livewire tests; or when the user mentions Livewire, component, counter, or reactive UI.
|
||||||
- `tailwindcss-development` — Styles applications using Tailwind CSS v4 utilities. Activates when adding styles, restyling components, working with gradients, spacing, layout, flex, grid, responsive design, dark mode, colors, typography, or borders; or when the user mentions CSS, styling, classes, Tailwind, restyle, hero section, cards, buttons, or any visual/UI changes.
|
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
@@ -133,6 +132,13 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
|||||||
|
|
||||||
- Add useful array shape type definitions when appropriate.
|
- Add useful array shape type definitions when appropriate.
|
||||||
|
|
||||||
|
=== tests rules ===
|
||||||
|
|
||||||
|
# Test Enforcement
|
||||||
|
|
||||||
|
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
||||||
|
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test --compact` with a specific filename or filter.
|
||||||
|
|
||||||
=== laravel/core rules ===
|
=== laravel/core rules ===
|
||||||
|
|
||||||
# Do Things the Laravel Way
|
# Do Things the Laravel Way
|
||||||
@@ -247,12 +253,4 @@ protected function isAccessible(User $user, ?string $path = null): bool
|
|||||||
- To run all tests in a file: `php artisan test --compact tests/Feature/ExampleTest.php`.
|
- To run all tests in a file: `php artisan test --compact tests/Feature/ExampleTest.php`.
|
||||||
- To filter on a particular test name: `php artisan test --compact --filter=testName` (recommended after making a change to a related file).
|
- To filter on a particular test name: `php artisan test --compact --filter=testName` (recommended after making a change to a related file).
|
||||||
|
|
||||||
=== tailwindcss/core rules ===
|
|
||||||
|
|
||||||
# Tailwind CSS
|
|
||||||
|
|
||||||
- Always use existing Tailwind conventions; check project patterns before adding new ones.
|
|
||||||
- IMPORTANT: Always use `search-docs` tool for version-specific Tailwind CSS documentation and updated code examples. Never rely on training data.
|
|
||||||
- IMPORTANT: Activate `tailwindcss-development` every time you're working with a Tailwind CSS or styling-related task.
|
|
||||||
|
|
||||||
</laravel-boost-guidelines>
|
</laravel-boost-guidelines>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class ApprovalService
|
|||||||
$workflow = $travelRequest->workflow;
|
$workflow = $travelRequest->workflow;
|
||||||
|
|
||||||
if (! $workflow) {
|
if (! $workflow) {
|
||||||
return;
|
throw new \RuntimeException('No active approval workflow is configured.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$steps = $workflow->steps()->orderBy('order')->get();
|
$steps = $workflow->steps()->orderBy('order')->get();
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
"nightwatch_mcp": false,
|
"nightwatch_mcp": false,
|
||||||
"sail": false,
|
"sail": false,
|
||||||
"skills": [
|
"skills": [
|
||||||
"livewire-development",
|
"livewire-development"
|
||||||
"tailwindcss-development"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
216
package-lock.json
generated
216
package-lock.json
generated
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "travel",
|
"name": "html",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
@@ -439,7 +439,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
@@ -970,16 +969,6 @@
|
|||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/detect-libc": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/dunder-proto": {
|
"node_modules/dunder-proto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
@@ -1305,146 +1294,6 @@
|
|||||||
"vite": "^7.0.0"
|
"vite": "^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lightningcss-android-arm64": {
|
|
||||||
"version": "1.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz",
|
|
||||||
"integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"android"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-darwin-arm64": {
|
|
||||||
"version": "1.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz",
|
|
||||||
"integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-darwin-x64": {
|
|
||||||
"version": "1.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz",
|
|
||||||
"integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-freebsd-x64": {
|
|
||||||
"version": "1.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz",
|
|
||||||
"integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-linux-arm-gnueabihf": {
|
|
||||||
"version": "1.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz",
|
|
||||||
"integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-linux-arm64-gnu": {
|
|
||||||
"version": "1.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz",
|
|
||||||
"integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-linux-arm64-musl": {
|
|
||||||
"version": "1.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz",
|
|
||||||
"integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-linux-x64-gnu": {
|
"node_modules/lightningcss-linux-x64-gnu": {
|
||||||
"version": "1.31.1",
|
"version": "1.31.1",
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz",
|
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz",
|
||||||
@@ -1465,66 +1314,6 @@
|
|||||||
"url": "https://opencollective.com/parcel"
|
"url": "https://opencollective.com/parcel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lightningcss-linux-x64-musl": {
|
|
||||||
"version": "1.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz",
|
|
||||||
"integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-win32-arm64-msvc": {
|
|
||||||
"version": "1.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz",
|
|
||||||
"integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-win32-x64-msvc": {
|
|
||||||
"version": "1.31.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz",
|
|
||||||
"integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
@@ -1584,7 +1373,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -1611,7 +1399,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.11",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@@ -1800,7 +1587,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
||||||
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}"
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}"
|
||||||
x-data="{ theme: localStorage.getItem('theme') || 'dark' }"
|
x-data="{ theme: localStorage.getItem('theme') || 'light' }"
|
||||||
x-init="$watch('theme', val => { document.documentElement.setAttribute('data-bs-theme', val); localStorage.setItem('theme', val); }); document.documentElement.setAttribute('data-bs-theme', theme);"
|
x-init="$watch('theme', val => { document.documentElement.setAttribute('data-bs-theme', val); localStorage.setItem('theme', val); }); document.documentElement.setAttribute('data-bs-theme', theme);"
|
||||||
:data-bs-theme="theme"
|
:data-bs-theme="theme"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}"
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}"
|
||||||
x-data="{ theme: localStorage.getItem('theme') || 'dark' }"
|
x-data="{ theme: localStorage.getItem('theme') || 'light' }"
|
||||||
x-init="document.documentElement.setAttribute('data-bs-theme', theme);"
|
x-init="document.documentElement.setAttribute('data-bs-theme', theme);"
|
||||||
:data-bs-theme="theme"
|
:data-bs-theme="theme"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ new #[Layout('components.layouts.app')] class extends Component {
|
|||||||
public function saveDraft(): void
|
public function saveDraft(): void
|
||||||
{
|
{
|
||||||
$this->saveRequest(submit: false);
|
$this->saveRequest(submit: false);
|
||||||
session()->flash('success', 'Draft saved successfully.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submit(): void
|
public function submit(): void
|
||||||
@@ -102,6 +101,12 @@ new #[Layout('components.layouts.app')] class extends Component {
|
|||||||
|
|
||||||
private function saveRequest(bool $submit): void
|
private function saveRequest(bool $submit): void
|
||||||
{
|
{
|
||||||
|
if ($submit && ! ApprovalWorkflow::where('is_active', true)->exists()) {
|
||||||
|
$this->addError('workflow', 'No active approval workflow is configured. Please contact an administrator.');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->validate([
|
$this->validate([
|
||||||
'emergencyFullName' => ['required', 'string', 'max:255'],
|
'emergencyFullName' => ['required', 'string', 'max:255'],
|
||||||
'emergencyPhone' => ['required', 'string', 'max:50'],
|
'emergencyPhone' => ['required', 'string', 'max:50'],
|
||||||
@@ -182,6 +187,8 @@ new #[Layout('components.layouts.app')] class extends Component {
|
|||||||
if ($submit) {
|
if ($submit) {
|
||||||
app(ApprovalService::class)->submit($travelRequest);
|
app(ApprovalService::class)->submit($travelRequest);
|
||||||
session()->flash('success', 'Travel request submitted for approval.');
|
session()->flash('success', 'Travel request submitted for approval.');
|
||||||
|
} else {
|
||||||
|
session()->flash('success', 'Draft saved successfully.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->redirect(route('travel-requests.show', $travelRequest), navigate: true);
|
$this->redirect(route('travel-requests.show', $travelRequest), navigate: true);
|
||||||
@@ -209,6 +216,10 @@ new #[Layout('components.layouts.app')] class extends Component {
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@error('workflow')
|
||||||
|
<div class="alert alert-danger">{{ $message }}</div>
|
||||||
|
@enderror
|
||||||
|
|
||||||
<form wire:submit.prevent>
|
<form wire:submit.prevent>
|
||||||
|
|
||||||
{{-- Applicant Details --}}
|
{{-- Applicant Details --}}
|
||||||
|
|||||||
124
tests/Feature/TravelRequestSubmissionTest.php
Normal file
124
tests/Feature/TravelRequestSubmissionTest.php
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Enums\ApprovalStatus;
|
||||||
|
use App\Enums\JourneyMethod;
|
||||||
|
use App\Enums\TravelStatus;
|
||||||
|
use App\Models\ApprovalStep;
|
||||||
|
use App\Models\ApprovalWorkflow;
|
||||||
|
use App\Models\TravelRequest;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
use Spatie\Permission\Models\Role;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class TravelRequestSubmissionTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
private User $staff;
|
||||||
|
|
||||||
|
/** @var array<string, mixed> */
|
||||||
|
private array $validFormData;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
Role::firstOrCreate(['name' => 'staff']);
|
||||||
|
Role::firstOrCreate(['name' => 'travel_approver']);
|
||||||
|
Role::firstOrCreate(['name' => 'administrator']);
|
||||||
|
|
||||||
|
$this->staff = User::factory()->create();
|
||||||
|
$this->staff->assignRole('staff');
|
||||||
|
|
||||||
|
$this->validFormData = [
|
||||||
|
'emergencyFullName' => 'Jane Doe',
|
||||||
|
'emergencyPhone' => '0400000000',
|
||||||
|
'emergencyRelationship' => 'Spouse',
|
||||||
|
'reasonSummary' => 'Attending a medical conference in Sydney',
|
||||||
|
'journeys' => [
|
||||||
|
[
|
||||||
|
'origin' => 'Perth',
|
||||||
|
'destination' => 'Sydney',
|
||||||
|
'date' => '2026-04-01',
|
||||||
|
'time' => '09:00',
|
||||||
|
'method' => JourneyMethod::Air->value,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'costCodes' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function makeWorkflow(): ApprovalWorkflow
|
||||||
|
{
|
||||||
|
$workflow = ApprovalWorkflow::factory()->create(['is_active' => true]);
|
||||||
|
|
||||||
|
ApprovalStep::factory()->create([
|
||||||
|
'workflow_id' => $workflow->id,
|
||||||
|
'order' => 1,
|
||||||
|
'name' => 'Travel Approver Review',
|
||||||
|
'role' => 'travel_approver',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $workflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_submitting_form_with_active_workflow_sets_status_to_pending(): void
|
||||||
|
{
|
||||||
|
$this->makeWorkflow();
|
||||||
|
|
||||||
|
Livewire::actingAs($this->staff)
|
||||||
|
->test('travel-request.create')
|
||||||
|
->set($this->validFormData)
|
||||||
|
->call('submit');
|
||||||
|
|
||||||
|
$request = TravelRequest::first();
|
||||||
|
$this->assertNotNull($request);
|
||||||
|
$this->assertSame(TravelStatus::Pending, $request->status);
|
||||||
|
$this->assertNotNull($request->submitted_at);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_submitting_form_with_active_workflow_creates_pending_approval(): void
|
||||||
|
{
|
||||||
|
$this->makeWorkflow();
|
||||||
|
|
||||||
|
Livewire::actingAs($this->staff)
|
||||||
|
->test('travel-request.create')
|
||||||
|
->set($this->validFormData)
|
||||||
|
->call('submit');
|
||||||
|
|
||||||
|
$request = TravelRequest::first();
|
||||||
|
$this->assertCount(1, $request->approvals);
|
||||||
|
$this->assertSame(ApprovalStatus::Pending->value, $request->approvals->first()->status->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_submitting_form_with_no_active_workflow_shows_error(): void
|
||||||
|
{
|
||||||
|
Livewire::actingAs($this->staff)
|
||||||
|
->test('travel-request.create')
|
||||||
|
->set($this->validFormData)
|
||||||
|
->call('submit')
|
||||||
|
->assertHasErrors(['workflow']);
|
||||||
|
|
||||||
|
$this->assertDatabaseCount('travel_requests', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_saving_draft_does_not_submit_for_approval(): void
|
||||||
|
{
|
||||||
|
$this->makeWorkflow();
|
||||||
|
|
||||||
|
Livewire::actingAs($this->staff)
|
||||||
|
->test('travel-request.create')
|
||||||
|
->set($this->validFormData)
|
||||||
|
->call('saveDraft');
|
||||||
|
|
||||||
|
$request = TravelRequest::first();
|
||||||
|
$this->assertNotNull($request);
|
||||||
|
$this->assertSame(TravelStatus::Draft, $request->status);
|
||||||
|
$this->assertNull($request->submitted_at);
|
||||||
|
$this->assertCount(0, $request->approvals);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user