Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support discounts specifying fields in the discount UI #1653

Open
wants to merge 3 commits into
base: 1.x
Choose a base branch
from

Conversation

ryanmitchell
Copy link
Contributor

Currently custom discounts cant specify fields the filament UI.

This PR attempts to fix that by allowing discounts to specify 3 'magic' methods:

lunarPanelSchema(): array
The Filament schema for the fields to be displayed when the discount type is specified

lunarPanelOnFill(array $data): array
To allow the discount to modify the data associated with the discount before its rendered (only called if the discount type is selected)

lunarPanelOnSave(array $data): array
To allow the discount to modify the data associated with the discount before its saved (only called if the discount type is selected)

Here is an example of how it is used, in a Amount off (Retail price) discount that we use in one of our systems:

    public function lunarPanelSchema(): array
    {
        $currencies = Currency::get();

        $currencyInputs = [];

        foreach ($currencies as $currency) {
            $currencyInputs[] = Forms\Components\TextInput::make(
                'data.retail.fixed_values.'.$currency->code
            )
            ->label($currency->name)
            ->afterStateHydrated(function (Forms\Components\TextInput $component, $state) use ($currencies) {
                $currencyCode = last(explode('.', $component->getStatePath()));
                $currency = $currencies->first(
                    fn ($currency) => $currency->code == $currencyCode
                );

                if ($currency) {
                    $component->state($state / $currency->factor);
                }
            });
        }

        return [
            Forms\Components\Toggle::make('data.retail.fixed_value')->live(),
            Forms\Components\TextInput::make('data.retail.percentage')->visible(
                fn (Forms\Get $get) => ! $get('data.retail.fixed_value')
            )->numeric(),
            Forms\Components\Group::make(
                $currencyInputs
            )->visible(
                fn (Forms\Get $get) => (bool) $get('data.retail.fixed_value')
            )->columns(3),
        ];
    }

    public function lunarPanelOnFill(array $data): array
    {
        if (! Arr::get($data, 'data.retail', false)) {
            $dataValues = $data['data'] ?? [];

            $dataValues['retail'] = [];

            if (isset($dataValues['fixed_value'])) {
                $dataValues['retail']['fixed_value'] = $dataValues['fixed_value'];
                unset($dataValues['fixed_value']);
            }

            if (isset($dataValues['fixed_values'])) {
                $dataValues['retail']['fixed_values'] = $dataValues['fixed_values'];
                unset($dataValues['fixed_values']);
            }

            if (isset($dataValues['percentage'])) {
                $dataValues['retail']['percentage'] = $dataValues['percentage'];
                unset($dataValues['percentage']);
            }

            $data['data'] = $dataValues;
        }

        return $data;
    }

    public function lunarPanelOnSave(array $data): array
    {
        if ($retail = Arr::get($data, 'data.retail', false)) {
            $data['data'] = array_merge($data['data'], $retail);
            unset($data['data']['retail']);

            $currencies = Currency::enabled()->get();
            $fixedPrices = $data['data']['fixed_values'] ?? [];
            foreach ($fixedPrices as $currencyCode => $fixedPrice) {
                $currency = $currencies->first(
                    fn ($currency) => $currency->code == $currencyCode
                );

                if (! $currency) {
                    continue;
                }
                $data['data']['fixed_values'][$currencyCode] = (int) round($fixedPrice * $currency->factor);
            }
        }

        return $data;
    }

As you can see we are using some of the same data values as the standard "Amount off" discount, but we have to prefix them in the schema to avoid collisions on the filament side... then on fill/save we add/undo those prefixes so they dont get saved to the database. This is just a simple example to show how they can used and why they are necessary.

The benefit of this approach is that the discount is just registered once, making the DX experience simpler.

        Discounts::addType(
            DiscountTypes\AmountOffRetail::class
        );

Copy link

vercel bot commented Mar 18, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
lunar-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 22, 2024 8:17pm

@alecritson
Copy link
Collaborator

Thanks @ryanmitchell Going to try and get my head into and take a look at this soon :) @glennjacobs did you have any opinions in the meantime?

@glennjacobs glennjacobs self-assigned this May 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants