saade / filament-autograph

A Filament package to collect signatures.
https://filamentphp.com/plugins/saade-autograph
MIT License
46 stars 9 forks source link

[Bug]: Trying to save the signature to database but failed #14

Open abhi051002 opened 8 months ago

abhi051002 commented 8 months ago

What happened?

Is their any way to save the signature in to database

How to reproduce the bug

I'm trying every possible way i know to save the signature

Package Version

2.0.0

PHP Version

8.2.0

Laravel Version

10.0.0

Which operating systems does with happen with?

Linux

Notes

No response

nourdar commented 4 months ago

I have solved that by creating a hidden field

` SignaturePad::make('signature_pad')
                                            ->label('Signature')
                                            ->clearable()
                                            ->disabled(fn ($state) => !empty($state))
                                            ->downloadable(false)
                                            ->undoable()
                                            ->live()
                                            ->visible(fn ($get) => empty($get('signature')))
                                            ->afterStateUpdated(fn ($state, $set) => $set('signature', $state))
                                            ->confirmable(false),

                                        Hidden::make('signature'),

                                        ViewField::make('signature')
                                            ->visibleOn('edit')
                                            ->visible(fn ($state) => !empty($state))
                                            ->view('filament.forms.components.image'),

`

saade commented 4 months ago

It should just work. I'm using it. Would you mind creating a reproduction repo?

amrmsccs commented 3 months ago

@nourdar please share full details the view file how it looks like and the signature column type in DB?

uarefans commented 1 month ago

@amrmsccs @saade @abhi051002 Maybe it helps

Concept

  1. Set Signature
  2. Convert base64PNGencode to File
  3. Save to Livewire Temporary File with afterStateUpdate and
  4. Auto Passing to Filament FileUpload Forms so you can upload to S3 or whatever you want
  5. File Upload in the background with AlpineJS help
  6. Hint Action to Delete a. If save to DB then delete file from storage and set back record to NULL b. Else delete file from livewire-tmp then you can re-assign signature

Reference

Credit to silvanhagen Video https://www.youtube.com/watch?v=sIsxq7j_4vY Code Snippet https://silvanhagen.com/writing/background-file-upload-in-filament-forms/

Implementation

    public function form(Form $form): Form
    {
        return $form
            ->schema([
                SignaturePad::make('signature')
                    ->label(__('Sign here'))
                    ->downloadable(false)
                    ->undoable()
                    ->live()
                    ->visible(fn($get) => empty($get('ttd')))
                    ->confirmable(true)
                    ->afterStateUpdated(function ($state, $livewire) {
                        if ($state) {
                            $base64_string = substr($state, strpos($state, ',') + 1);
                            $image_data = base64_decode($base64_string);
                            $file_name = Str::random(40);
                            $file = self::createTemporaryFileUploadFromUrl($image_data, $file_name);
                            $livewire->dispatch('test', $file);
                        }
                    })
                    ->columnSpan(4),

                Forms\Components\FileUpload::make('ttd')
                    ->label('Signature Result')
                    ->downloadable()
                    ->disabled()
                    ->dehydrated()
                    ->directory('abc')
                    ->required()
                    ->hintAction(
                        Action::make('Delete')
                            ->icon('heroicon-m-trash')
                            ->visible(fn($state) => filled($this->user['ttd']) || $state)
                            ->requiresConfirmation()
                            ->action(function ($state, $set) {
                                if (!empty($this->user['ttd'] ?? null)) {
                                    Storage::disk('public')->delete($this->user['ttd']);
                                    $this->user['ttd'] = null;
                                    $this->user->save();

                                    return redirect(request()->header('Referer'));
                                } else {
                                    $file = reset($state);
                                    if ($file instanceof \Livewire\Features\SupportFileUploads\TemporaryUploadedFile) {
                                        Storage::delete($file->getPathName());
                                        $set('ttd', null);
                                    }
                                }
                            })
                    )
                    ->extraAlpineAttributes([
                        'x-on:test.window' => '
                                    const pond = FilePond.find($el.querySelector(".filepond--root"));
                                    setTimeout(() => {
                                        pond.removeFiles({ revert: false });
                                        pond.addFile($event.detail);
                                    }, 750);',
                    ])
                    ->image()
                    ->columnSpanFull(),
            ])
            ->statePath('data');
    }

    public static function createTemporaryFileUploadFromUrl($favicon, $filename): string
    {
        // Step 1: Save the file to a temporary location
        $tempFilePath = tempnam(sys_get_temp_dir(), 'upload');
        file_put_contents($tempFilePath, $favicon);

        // Step 2: Create a UploadedFile instance
        $mimeType = mime_content_type($tempFilePath);
        $tempFile = new UploadedFile($tempFilePath, basename($filename), $mimeType);
        $path = Storage::put('livewire-tmp', $tempFile);

        // Step 3: Create a TemporaryUploadedFile instance
        $file = TemporaryUploadedFile::createFromLivewire($path);

        return URL::temporarySignedRoute(
            'livewire.preview-file',
            now()->addMinutes(30)->endOfHour(),
            ['filename' => $file->getFilename()]
        );
    }

Video Preview

https://github.com/user-attachments/assets/cac6d671-979e-44eb-9608-d10a6a0845b9