I am working on a blogging application in Laravel 8.
I have put together a way to preview and remove the main article image.
In the ArticleController.php controller, I have a method for removing the image from the article and deleting the file from the directory:
public function deleteImage($id, $fileName) {
    $article = Article::find($id);
    $article->image = "default.jpg";
    $article->save();
    if (File::exists(public_path('images/articles/' . $fileName))) {
        File::delete(public_path('images/articles/' . $fileName));
    }
}
In resources/views/dashboard/edit-article.blade.php I have the edit article form, where the image preview code is the following:
<form method="POST" action="{{ route('dashboard.articles.update', [$article->id]) }}"
    enctype="multipart/form-data" novalidate>
    @csrf
    <input type="hidden" id="defaultImage" name="defaultImage" value="{{ asset('images/articles/default.jpg') }}" />
        <div class="col-md-12 post-image text-center">
            <img id="imagePreview" class="image-preview large"
                src="{{ asset('images/articles/' . $article->image) }}" alt="{{ $article->title }}">
                @if($article->image !== 'default.jpg')
                  <a class="remove-image edit" href="#" id="delete-image" data-uid="{{$article->id}}" title="Remove image" onclick="removeImage(event)">
                      <i class="fa fa-remove"></i>
                  </a>
                @endif
        </div>
    </div>                
</form>
@include('partials.image-preview-script')
In resources/views/dashboard/eadd-article.blade.php I have the add article form, where the image preview code is the following:
<form method="POST" action="{{ route('dashboard.articles.add') }}" enctype="multipart/form-data" novalidate>
    @csrf
    <input type="hidden" id="defaultImage" name="defaultImage" value="{{ asset('images/articles/default.jpg') }}" />              
    
    <div class="row mb-3">
        <label for="image" class="col-md-12">{{ __('Article image') }}</label>
        <div class="col-md-12 post-image @error('image') has-error @enderror">
            <input type="file" value="{{ old('image') }}" name="image" id="file"
                class="file-upload-btn" onchange="previewImage(event)">
            @error('image')
                <span class="invalid-feedback" role="alert">
                    <strong>{{ $message }}</strong>
                </span>
            @enderror
        </div>
    </div>
    <div class="row mb-3 d-none">
        <div class="col-md-12 post-image text-center">
            <img id="imagePreview" class="image-preview large" src="">
            <a class="remove-image" href="#" title="Remove image" onclick="removeImage(event)">
                <i class="fa fa-remove"></i>
            </a>
        </div>
    </div>
    
</form>
@include('partials.image-preview-script')
In routes/web.php I have added:
Route::post('/delete-image/{id}/{fileName}', [ArticleController::class, 'deleteImage'])->name('dashboard.articles.delete-image');
The script (used by both edit and delete actions):
<script>
    function previewImage(event) {
        var img = document.getElementById('imagePreview');
        var imageContainer = img.parentNode.parentNode;
        var input = event.target;
        var reader = new FileReader();
        reader.onload = function() {
            img.src = reader.result;
            if (window.getComputedStyle(imageContainer).display === 'none') {
                imageContainer.classList.remove('d-none');
            }
        };
        reader.readAsDataURL(input.files[0]);
    }
    function removeImage(event) {
        var defaultImg = document.getElementById('defaultImage').value;
        var input = document.getElementById('file');
        var img = document.getElementById('imagePreview');
        var imageContainer = img.parentNode.parentNode;
        event.preventDefault();
        if (event.currentTarget.classList.contains('edit')) {
            var id = event.currentTarget.dataset.uid;
            var fileName = img.getAttribute('src').split('/').reverse()[0];
            var url = `${APP_URL}/dashboard/articles/delete-image/${id}/${fileName}`;
            if (confirm('This action is irreversible. Are you sure?')) {
                var CSRF_TOKEN = document.querySelectorAll('meta[name="csrf-token"]')[0].getAttribute('content');
                var xmlhttp = new XMLHttpRequest();
                xmlhttp.onreadystatechange = function() {
                    if (xmlhttp.readyState == XMLHttpRequest.DONE) {
                        if (xmlhttp.status == 200) {
                            img.src = defaultImg;
                            document.getElementById('delete-image').remove();
                        }
                    }
                }
                xmlhttp.open('POST', url, true);
                xmlhttp.setRequestHeader("X-CSRF-TOKEN", CSRF_TOKEN);
                xmlhttp.send();
            }
        } else {
            imageContainer.classList.add('d-none');
            img.src = "";
            input.value = "";
        }
    }
</script>
Questions:
- Is there any redundancy in my code?
- Do you see any security issues?
- Do you see any usability or UX issues?


ArticleController::deleteImage()? \$\endgroup\$