From 4ddd2e8267de3a732b91b20c5a9c3dd28deeed92 Mon Sep 17 00:00:00 2001 From: jakub-przepiora Date: Sun, 30 Aug 2026 01:22:20 +0200 Subject: [PATCH 1/2] feat(onboarding): make the module-preset choice a screen before the wizard The Lightweight/Advanced/Custom preset selection was rendered as step 1 of the wizard (stepper 'Modules -> Line -> ...', 5 steps). It's now an independent screen that PRECEDES the wizard: - OnboardingLayout: 4-step stepper (Line/Product/Process/Work Order); the stepper is hidden on the preset screen (step 0). - Controller: renumbered the step props (modules=0, step1..4=1..4, complete=5). - Modules screen reframed ('Before the setup wizard' / 'Choose your setup') and the per-step 'X/5' labels renumbered to 'X/4'. Test asserts the preset screen renders at step 0 and the wizard starts at 1. en/pl strings. Full suite 2507 passed. --- CHANGELOG.md | 3 +++ .../Controllers/Web/OnboardingController.php | 14 ++++++++------ backend/lang/en.json | 5 ++++- backend/lang/pl.json | 5 ++++- .../resources/js/Pages/onboarding/Modules.jsx | 6 +++--- backend/resources/js/Pages/onboarding/Step1.jsx | 2 +- backend/resources/js/Pages/onboarding/Step2.jsx | 2 +- backend/resources/js/Pages/onboarding/Step3.jsx | 2 +- backend/resources/js/Pages/onboarding/Step4.jsx | 2 +- .../resources/js/layouts/OnboardingLayout.jsx | 15 ++++++++++----- backend/tests/Feature/OnboardingWizardTest.php | 16 ++++++++++++++++ 11 files changed, 52 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d25dc940..84b7a71d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ Format based on [Keep a Changelog](https://keepachangelog.com/). ## [Unreleased] +### Changed +- **Onboarding: the module-preset choice now precedes the setup wizard** *(admin)* — picking Lightweight / Advanced / Custom is an **independent screen shown before** the wizard, not its first step. The wizard's stepper is hidden on that screen and now counts **4 steps** (Line → Product → Process → Work Order) instead of five. You choose the feature set first, then the wizard walks you through the rest. No change to what each preset enables. + ### Added - **Plant timezone is changeable after installation** *(admin)* — Settings → System → General now carries a timezone picker (region + zone), writing the same `system_settings` row the installer's step does; the wizard already promised this was possible. The chosen zone is re-applied per request and before each queued job, so on Octane a change reaches every worker immediately instead of waiting for a container restart. Saving reloads the page so every displayed time switches over at once. - **Product types as Bill-of-Materials components** *(admin)* — a BOM line can now be a manufactured **product type** (a sub-assembly), not only a material. In the BOM editor a Material / Product type switch picks the component kind; product-type lines carry the same quantity-per-unit, step, scrap %, consumption timing and notes as materials. A product type can't be a component of itself, and each appears once per template. Lines are captured in the work-order snapshot as sub-assembly references; they're a simple component reference (they don't explode into their own BOM) and are skipped by the material stock/consumption engine. Additive — existing material BOMs are unaffected. diff --git a/backend/app/Http/Controllers/Web/OnboardingController.php b/backend/app/Http/Controllers/Web/OnboardingController.php index b09eda775..3fcaad36c 100644 --- a/backend/app/Http/Controllers/Web/OnboardingController.php +++ b/backend/app/Http/Controllers/Web/OnboardingController.php @@ -34,7 +34,9 @@ public function index() public function modules() { return Inertia::render('onboarding/Modules', [ - 'step' => 1, + // step 0 = the preset screen precedes the wizard (no stepper); the + // wizard's own steps start at 1 (Line) after a preset is chosen. + 'step' => 0, 'modules' => ModuleRegistry::forForm(), 'presets' => ModuleRegistry::PRESETS, ]); @@ -58,7 +60,7 @@ public function storeModules(Request $request) public function step1() { - return Inertia::render('onboarding/Step1', ['step' => 2]); + return Inertia::render('onboarding/Step1', ['step' => 1]); } public function storeStep1(Request $request) @@ -83,7 +85,7 @@ public function step2(Request $request) return redirect()->route('onboarding.step1'); } - return Inertia::render('onboarding/Step2', ['step' => 3]); + return Inertia::render('onboarding/Step2', ['step' => 2]); } public function storeStep2(Request $request) @@ -115,7 +117,7 @@ public function step3(Request $request) return redirect()->route('onboarding.step1'); } - return Inertia::render('onboarding/Step3', ['step' => 4]); + return Inertia::render('onboarding/Step3', ['step' => 3]); } public function storeStep3(Request $request) @@ -183,7 +185,7 @@ public function step4(Request $request) return redirect()->route('onboarding.step1'); } - return Inertia::render('onboarding/Step4', ['step' => 5]); + return Inertia::render('onboarding/Step4', ['step' => 4]); } public function storeStep4(Request $request, WorkOrderService $workOrderService) @@ -210,7 +212,7 @@ public function complete(Request $request) $this->markCompleted(); $request->session()->forget('onboarding'); - return Inertia::render('onboarding/Complete', ['step' => 6]); + return Inertia::render('onboarding/Complete', ['step' => 5]); } public function skip(Request $request) diff --git a/backend/lang/en.json b/backend/lang/en.json index f7f6173c1..e500ec536 100644 --- a/backend/lang/en.json +++ b/backend/lang/en.json @@ -5669,5 +5669,8 @@ "Region": "Region", "Select timezone": "Select timezone", "Plant timezone. Every timestamp, report boundary and shift edge in the app is expressed in it.": "Plant timezone. Every timestamp, report boundary and shift edge in the app is expressed in it.", - "Changing the timezone reloads the page so every displayed time switches over at once.": "Changing the timezone reloads the page so every displayed time switches over at once." + "Changing the timezone reloads the page so every displayed time switches over at once.": "Changing the timezone reloads the page so every displayed time switches over at once.", + "Choose your setup": "Choose your setup", + "Before the setup wizard": "Before the setup wizard", + "First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product and work order.": "First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product and work order." } diff --git a/backend/lang/pl.json b/backend/lang/pl.json index e6ad59beb..f7fe05928 100644 --- a/backend/lang/pl.json +++ b/backend/lang/pl.json @@ -5669,5 +5669,8 @@ "Region": "Region", "Select timezone": "Wybierz strefę czasową", "Plant timezone. Every timestamp, report boundary and shift edge in the app is expressed in it.": "Strefa czasowa zakładu. Wszystkie znaczniki czasu, granice raportów i zmian w aplikacji są w niej wyrażone.", - "Changing the timezone reloads the page so every displayed time switches over at once.": "Zmiana strefy czasowej przeładowuje stronę, aby wszystkie wyświetlane godziny zmieniły się naraz." + "Changing the timezone reloads the page so every displayed time switches over at once.": "Zmiana strefy czasowej przeładowuje stronę, aby wszystkie wyświetlane godziny zmieniły się naraz.", + "Choose your setup": "Wybierz konfigurację", + "Before the setup wizard": "Przed kreatorem konfiguracji", + "First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product and work order.": "Najpierw wybierz zestaw funkcji. Obszary rdzeniowe (Panel, Zlecenia, Produkcja, Administracja) są zawsze włączone. Możesz to zmienić w każdej chwili w Ustawienia → System → Moduły. Następnie kreator konfiguracji przeprowadzi Cię przez pierwszą linię, produkt i zlecenie." } diff --git a/backend/resources/js/Pages/onboarding/Modules.jsx b/backend/resources/js/Pages/onboarding/Modules.jsx index a34da28c4..c6a183d10 100644 --- a/backend/resources/js/Pages/onboarding/Modules.jsx +++ b/backend/resources/js/Pages/onboarding/Modules.jsx @@ -65,11 +65,11 @@ export default function OnboardingModules() { return ( <> - -
Step 1/5
+ +
{__('Before the setup wizard')}

{__('Choose your modules')}

- {__('Turn on only the feature areas your team needs. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules.')} + {__('First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product and work order.')}

diff --git a/backend/resources/js/Pages/onboarding/Step1.jsx b/backend/resources/js/Pages/onboarding/Step1.jsx index b947437a5..897eee426 100644 --- a/backend/resources/js/Pages/onboarding/Step1.jsx +++ b/backend/resources/js/Pages/onboarding/Step1.jsx @@ -21,7 +21,7 @@ export default function Step1() { return ( <> -
Step 2/5
+
Step 1/4

{__('Create a Production Line')}

{__('A production line is a physical area where manufacturing happens. Start by creating your first one.')} diff --git a/backend/resources/js/Pages/onboarding/Step2.jsx b/backend/resources/js/Pages/onboarding/Step2.jsx index 913df15b7..46e56b9f4 100644 --- a/backend/resources/js/Pages/onboarding/Step2.jsx +++ b/backend/resources/js/Pages/onboarding/Step2.jsx @@ -21,7 +21,7 @@ export default function Step2() { return ( <> -

Step 3/5
+
Step 2/4

{__('Add a Product Type')}

{__('What product does this line produce? Define the product type.')}

diff --git a/backend/resources/js/Pages/onboarding/Step3.jsx b/backend/resources/js/Pages/onboarding/Step3.jsx index d92f172c5..499beedfa 100644 --- a/backend/resources/js/Pages/onboarding/Step3.jsx +++ b/backend/resources/js/Pages/onboarding/Step3.jsx @@ -78,7 +78,7 @@ export default function Step3() { return ( <> -
Step 4/5
+
Step 3/4

{__('Define Process Template')}

A process template defines the production steps (recipe) for your product. Add each step in the order diff --git a/backend/resources/js/Pages/onboarding/Step4.jsx b/backend/resources/js/Pages/onboarding/Step4.jsx index 9880340b7..f1b4e7afb 100644 --- a/backend/resources/js/Pages/onboarding/Step4.jsx +++ b/backend/resources/js/Pages/onboarding/Step4.jsx @@ -25,7 +25,7 @@ export default function Step4() { return ( <> -

Step 5/5
+
Step 4/4

{__('Create First Work Order')}

{__('A work order represents a production batch to manufacture. Create your first one.')} diff --git a/backend/resources/js/layouts/OnboardingLayout.jsx b/backend/resources/js/layouts/OnboardingLayout.jsx index 131bbf001..8dc660c98 100644 --- a/backend/resources/js/layouts/OnboardingLayout.jsx +++ b/backend/resources/js/layouts/OnboardingLayout.jsx @@ -3,17 +3,20 @@ import { __ } from '../lib/i18n'; /** * Wizard chrome for the onboarding flow. - * Reproduces onboarding/layout.blade.php: centred card, logo, 5-step stepper - * (Modules → Line → Product → Process → Work Order), skip link at bottom. + * Reproduces onboarding/layout.blade.php: centred card, logo, 4-step stepper + * (Line → Product → Process → Work Order), skip link at bottom. * - * Reads `step` (1–6) from page props; 6 = Complete (all steps shown as done). + * Reads `step` from page props: 0 = the module-preset screen that PRECEDES the + * wizard (stepper hidden — it's an independent choice, not a wizard step); 1–4 = + * the wizard steps; 5 = Complete (all steps shown as done). * * Geist White restyle: light-only v1 — om-* tokens, hairline card, mono labels. */ export default function OnboardingLayout({ children }) { const { step = 1, csrf_token } = usePage().props; - const steps = ['Modules', 'Line', 'Product', 'Process', 'Work Order']; + const steps = ['Line', 'Product', 'Process', 'Work Order']; + const showStepper = step >= 1; const skipWizard = (e) => { e.preventDefault(); @@ -30,7 +33,8 @@ export default function OnboardingLayout({ children }) {

{__('Setup Wizard')}

- {/* Stepper */} + {/* Stepper — hidden on the preset screen, which precedes the wizard */} + {showStepper && (
{steps.map((label, i) => { const stepNum = i + 1; @@ -74,6 +78,7 @@ export default function OnboardingLayout({ children }) { ); })}
+ )} {/* Content card */}
{children}
diff --git a/backend/tests/Feature/OnboardingWizardTest.php b/backend/tests/Feature/OnboardingWizardTest.php index 14f49a48e..ae33dc9fd 100644 --- a/backend/tests/Feature/OnboardingWizardTest.php +++ b/backend/tests/Feature/OnboardingWizardTest.php @@ -11,6 +11,7 @@ use App\Support\ModuleRegistry; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; +use Inertia\Testing\AssertableInertia; use Spatie\Permission\Models\Permission; use Spatie\Permission\Models\Role; use Tests\TestCase; @@ -63,6 +64,21 @@ public function test_wizard_skipped_when_marked_completed(): void $this->assertFalse(OnboardingController::shouldShowWizard()); } + public function test_preset_screen_precedes_the_wizard(): void + { + // The module-preset screen is an independent screen (step 0, no wizard + // stepper) shown before the wizard, whose own steps start at 1 (Line). + $this->actingAs($this->admin)->get(route('onboarding.modules')) + ->assertInertia(fn (AssertableInertia $p) => $p + ->component('onboarding/Modules') + ->where('step', 0)); + + $this->actingAs($this->admin)->get(route('onboarding.step1')) + ->assertInertia(fn (AssertableInertia $p) => $p + ->component('onboarding/Step1') + ->where('step', 1)); + } + public function test_step1_creates_line(): void { $response = $this->actingAs($this->admin)->post(route('onboarding.step1'), [ From 80ad0564e9e7b88bfd348990ad1786a4c77224ed Mon Sep 17 00:00:00 2001 From: jakub-przepiora Date: Sun, 30 Aug 2026 23:36:32 +0200 Subject: [PATCH 2/2] fix(onboarding): address CodeRabbit on the module-preset screen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Mention the process template in the preset intro so it lists all four wizard steps (line, product, process template, work order). - Use the established Polish terms on the preset screen — 'Obszary podstawowe' and 'Pulpit' (matching the existing onboarding copy), not 'Obszary rdzeniowe' and 'Panel'. --- backend/lang/en.json | 2 +- backend/lang/pl.json | 2 +- backend/resources/js/Pages/onboarding/Modules.jsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/lang/en.json b/backend/lang/en.json index 0da19e08b..71986bad9 100644 --- a/backend/lang/en.json +++ b/backend/lang/en.json @@ -5672,7 +5672,7 @@ "Changing the timezone reloads the page so every displayed time switches over at once.": "Changing the timezone reloads the page so every displayed time switches over at once.", "Choose your setup": "Choose your setup", "Before the setup wizard": "Before the setup wizard", - "First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product and work order.": "First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product and work order.", + "First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product, process template and work order.": "First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product, process template and work order.", "Count at Station / Step": "Count at Station / Step", "Station (workstation)": "Station (workstation)", "…or step number": "…or step number", diff --git a/backend/lang/pl.json b/backend/lang/pl.json index ae70ba5b8..77c5dce1e 100644 --- a/backend/lang/pl.json +++ b/backend/lang/pl.json @@ -5672,7 +5672,7 @@ "Changing the timezone reloads the page so every displayed time switches over at once.": "Zmiana strefy czasowej przeładowuje stronę, aby wszystkie wyświetlane godziny zmieniły się naraz.", "Choose your setup": "Wybierz konfigurację", "Before the setup wizard": "Przed kreatorem konfiguracji", - "First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product and work order.": "Najpierw wybierz zestaw funkcji. Obszary rdzeniowe (Panel, Zlecenia, Produkcja, Administracja) są zawsze włączone. Możesz to zmienić w każdej chwili w Ustawienia → System → Moduły. Następnie kreator konfiguracji przeprowadzi Cię przez pierwszą linię, produkt i zlecenie.", + "First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product, process template and work order.": "Najpierw wybierz zestaw funkcji. Obszary podstawowe (Pulpit, Zlecenia, Produkcja, Admin) są zawsze włączone. Możesz to zmienić w każdej chwili w Ustawienia → System → Moduły. Następnie kreator konfiguracji przeprowadzi Cię przez pierwszą linię, produkt, szablon procesu i zlecenie.", "Count at Station / Step": "Licz na stanowisku / kroku", "Station (workstation)": "Stanowisko (workstation)", "…or step number": "…lub numer kroku", diff --git a/backend/resources/js/Pages/onboarding/Modules.jsx b/backend/resources/js/Pages/onboarding/Modules.jsx index c6a183d10..083d2f28a 100644 --- a/backend/resources/js/Pages/onboarding/Modules.jsx +++ b/backend/resources/js/Pages/onboarding/Modules.jsx @@ -69,7 +69,7 @@ export default function OnboardingModules() {
{__('Before the setup wizard')}

{__('Choose your modules')}

- {__('First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product and work order.')} + {__('First pick the feature set you want. Core areas (Dashboard, Orders, Production, Admin) are always on. You can change this anytime in Settings → System → Modules. Next, the setup wizard will walk you through your first line, product, process template and work order.')}