Reduce duplication in Counter and the Blade view #64
Labels
No labels
bug
duplicate
enhancement
good first issue
help wanted
question
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lvl0/incr#64
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Refactor pass over the code v0.4.0 left behind. The whole application is 286 lines, so none of this is urgent — but there is one real piece of duplication and a few inconsistencies worth settling before they get copied.
The two forms in
counter.blade.phpare near-identicalresources/views/livewire/counter.blade.phphas an onboarding form (line 6) and a set-value form (line 62). Both contain:<input type="number" min="0" step="1" autofocus wire:model="value">with an identical 200-character Tailwind class string@error('value')blockThe class strings appear twice each, verbatim. Only three things actually differ: the label text, the
wire:submithandler, and whether a cancel button is present.Roughly 40 of the view's 100 lines are duplicated. Extract a Blade component — something like
<x-counter-form :action="..." :label="..." :cancel="true|false">— so the terminal styling lives in one place. It is the styling that matters here: it is the app's whole visual identity and currently has two copies that can drift.Tracker::current()and null-guard repeated four timesapp/Livewire/Counter.php—initialise(),increment(),save()andmount()all open by fetching the tracker and handling its absence. A private accessor would collapse that, though note the four cases are not identical:mount()uses null to setneedsOnboardinginitialise()uses??to adopt an existing trackerincrement()andsave()return earlyWorth checking the abstraction actually simplifies rather than adding a layer over four slightly different needs. If it does not, leave it.
Small inconsistencies in
Countersave()writes$this->count = (int) $this->value;butinitialise()writes$this->count = $tracker->count;— both correct, differently expressedincrement()resyncs$this->value = $this->countafterwards;initialise()does not. Harmless today because onboarding transitions away immediately, but the asymmetry is the kind of thing that becomes a bug when someone adds a fourth pathapp/Http/Controllers/Controller.phpis an empty abstract with no subclasses#52 removed the last controller. The file is eight lines and framework convention, so it is probably worth keeping for whenever a controller reappears — but it is currently dead. Decide deliberately rather than leaving it unexamined.
Not in scope
AppServiceProvideris empty but registered inbootstrap/providers.php; that is framework wiring, not dead code. Leave it.Acceptance criteria
counter.blade.phpno longer contains two copies of the same formCounter's tracker access is consistent, or documented as deliberately variedDone —
e5c257dThe duplicated forms
New
resources/views/components/counter-form.blade.php. The input, its 200-character class string, the@errorblock and the submit button now exist in exactly one place. Props:action,label,submit,id,cancel.counter.blade.phpwent 100 → 57 lines; the two forms became two component calls.CounterconsistencyAdded a private
syncFrom(Tracker). Before, the same intent was written four ways:mount()— ternary on nullinitialise()— set$count, left$valuestaleincrement()— set bothsave()—(int) $this->valuecastNow every mutation ends with
syncFrom($tracker), so$countand$valuecannot drift. The tracker is the single source of truth.Verified visually unchanged
Beyond the three gates, I diffed the rendered HTML before and after:
A per-request CSRF token is the only difference — the markup is otherwise byte-identical. The compiled CSS also stayed at exactly 13.58 kB, confirming Tailwind produced the same class set from the extracted component.
Added
test_the_edit_form_renders_with_both_actions, since the edit form sits behind$editingand appeared in no rendered page the tests checked. 18 tests now.Declined: the shared tracker accessor
The ticket flagged that this might not simplify, and it does not. The four
Tracker::current()call sites need different things —mount()uses null to set a flag,initialise()uses??to adopt an existing tracker,increment()andsave()return early. A shared accessor would return null and leave every caller guarding anyway, hiding control flow without removing it. Left as-is.Declined: removing
Controller.phpThe empty abstract stays. Eight lines, framework convention, and the natural place for a controller if one returns.
Acceptance criteria
counter.blade.phpno longer contains two copies of the same formCounter's tracker access is consistent — viasyncFrom(); the four fetch sites are deliberately varied, documented above