Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Persian Datepicker Laravel Package

aloko/nova-persian-datepicker

aloko/nova-persian-datepicker adds a Persian (Jalali) date picker field to Laravel Nova, making it easy to select and display dates in the Persian calendar within your Nova resources with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Confirm compatibility before anything else. This is a Nova field package, and Nova is a paid, closed-source dependency — so the package's composer.json constraints (Nova 3 vs Nova 4, Vue 2 vs Vue 3) decide whether it works at all. Open the repo's composer.json and package.json first, then check the latest commit date against your Nova major version.

composer require aloko/nova-persian-datepicker

Nova auto-discovers field packages via package:discover. If the field class isn't found, check the package's service provider for a Nova::serves() or manual registration step, and run:

php artisan vendor:publish --provider="Aloko\NovaPersianDatepicker\FieldServiceProvider"

2. Look here first, in order: src/ for the field class name and namespace (the README may lag behind renames), then resources/js/ to see which Jalali library is bundled (moment-jalaali, dayjs, persian-date, or a hand-rolled converter). That single fact predicts most of the behavior you'll care about.

3. First use case: the drop-in swap on an existing model attribute.

use Aloko\NovaPersianDatepicker\PersianDate;

public function fields(Request $request)
{
    return [
        PersianDate::make('birthday')
            ->rules('nullable', 'date'),
    ];
}

Keep the underlying database column a plain DATE/DATETIME in Gregorian. The field converts on input and display; the storage layer stays boring. That is the whole value proposition — Jalali in the UI, Gregorian in the DB — and it's the pattern you should enforce across the codebase.

Implementation Patterns

Treat it as a presentation layer, not a data layer. The healthiest architecture is: Gregorian in the database, Jalali only at the Nova boundary. Everything past Nova — APIs, exports, queued jobs, mail — reads the raw Carbon value.

Pair it with a cast so conversion isn't Nova-only. If users think in Jalali, they'll ask for Jalali in PDFs and emails too. Centralize it:

// app/Casts/JalaliDate.php
public function get($model, $key, $value, $attributes)
{
    return $value ? \Morilog\Jalali\Jalalian::fromCarbon(Carbon::parse($value)) : null;
}

Then the Nova field only handles input, and display formatting lives in one place.

Form field patterns. Mirror the Nova Date API so the upgrade path is easy if you fork or replace it:

PersianDate::make('delivered_at')
    ->nullable()
    ->sortable()
    ->hideFromIndex()
    ->help('Gregorian stored as: ' . optional($this->delivered_at)->toDateString())
    ->withMeta(['format' => 'YYYY/MM/DD'])

Use withMeta() for anything the bundled JS picker accepts. This is the package's main extension point — read the Vue component's props to see what it honors.

Index and detail views are separate code paths. Nova renders index cells server-side and detail values through the field's resolve/display. Always open a record in both index and detail after installing; a field that works on the form but prints a raw 2024-03-21 00:00:00 in the table is the classic failure.

Validation needs its own rule. Laravel's date and date_format:Y-m-d validate Gregorian only. If the picker posts 1403/01/01, stock rules reject it. Either have the field post a Gregorian value in a companion hidden input, or write a rule that converts before validating:

Validator::extend('jalali_date', function ($attr, $value) {
    return \Morilog\Jalali\Jalalian::fromFormat('Y/m/d', $value)->isValid();
});

Filters are a known seam. Nova's date range filters assume Gregorian boundaries. If users filter by Jalali dates, expect off-by-one-day results unless you verify the conversion both ways.

Gotchas and Tips

Nova version drift is the real risk, not bugs. With 20 stars and zero dependents, there is no crowd to find the breakage before you do. Nova 4 (Vue 3) silently breaks Vue 2 field components — usually as a blank input with no PHP error. Test on a staging Nova install before promising it to anyone.

Assets not loading. If the field renders as a plain text input, the compiled JS never reached the browser. Check the console for 404s on the field's chunk, then run php artisan nova:publish and clear storage/framework/cache and the browser cache. Some field packages require a npm run build inside Nova's own directory — check the README's install section for that step specifically.

Timezone day-shift. Jalali conversion is midnight-sensitive. A date entered as 1403/01/01 can land on the previous Gregorian day if app.timezone and Nova's timezone config disagree, or if you're storing DATETIME and letting UTC coercion happen. Set both consistently and store pure DATE columns for date-only fields.

Don't hand-roll the arithmetic. Jalali leap years follow a 33-year cycle, not the Gregorian rule. Let the bundled library do conversions. If you ever fork, keep that library and only rewrite the Vue wrapper.

Empty strings, not nulls. Persian pickers frequently submit "" on clear. Without ->nullable() plus a mutator normalizing empty to null, you'll write 0000-00-00 into MySQL in non-strict mode. Add an assertion for this in your tests.

Never store Jalali strings in the DB. Lexical sorting and whereBetween both break across month boundaries (1403/12/29 sorts after 1403/02/01), and every index filter silently lies. Keep the sorting on the Gregorian column.

Debugging order of operations: (1) does the PHP field class resolve, (2) does the JS chunk load, (3) does the posted value reach the model as Gregorian. Isolate those three before touching the picker config — 90% of issues are #2.

Extension points worth knowing: withMeta() for picker options, resolveUsing() / displayUsing() for the index/detail formatting, and published assets for forking the component. Since it's MIT and small, a fork is a realistic fallback: the PHP side is a thin wrapper and can be replaced with Morilog\Jalali plus a ~60-line custom Nova field if the package falls behind Nova releases. Budget that risk explicitly — the dependency is small enough to absorb, but you should decide to absorb it before a Nova upgrade forces the issue.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager