Skip to content

Commit 41e9819

Browse files
author
Chri$
committed
feat:[LAR-60] Add send mail for decline article and fix unsend mail for approve article
1 parent d2a5ecb commit 41e9819

File tree

11 files changed

+330
-55
lines changed

11 files changed

+330
-55
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
namespace App\Http\Livewire\Modals;
4+
5+
6+
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
7+
use App\Notifications\SendDeclinedArticle;
8+
use Illuminate\Support\Facades\Cache;
9+
use LivewireUI\Modal\ModalComponent;
10+
use App\Policies\ArticlePolicy;
11+
use App\Models\Article;
12+
13+
class DeclinedArticle extends ModalComponent
14+
{
15+
use AuthorizesRequests;
16+
17+
public ?string $raison = null;
18+
19+
public ?string $description = null;
20+
21+
public ?Article $article = null;
22+
23+
protected $rules = [
24+
'raison' => 'required|string|min:6',
25+
'description' => 'required|string',
26+
];
27+
28+
public function mount(int $id): void
29+
{
30+
$this->article = Article::find($id);
31+
}
32+
33+
public static function modalMaxWidth(): string
34+
{
35+
return 'xl';
36+
}
37+
38+
public function declined(): void
39+
{
40+
$data = $this->validate();
41+
42+
$this->authorize(ArticlePolicy::DISAPPROVE, $this->article);
43+
44+
$this->article->update(['declined_at' => now()]); // @phpstan-ignore-line
45+
46+
Cache::forget('post-'.$this->article->id); // @phpstan-ignore-line
47+
48+
$this->article->user->notify(new SendDeclinedArticle($this->article, $data)); // @phpstan-ignore-line
49+
50+
session()->flash('status', __('L\'article a été décliné et le mail a été envoyé à l\'auteur pour le notifier.'));
51+
52+
$this->redirectRoute('articles');
53+
}
54+
55+
56+
public function render()
57+
{
58+
return view('livewire.modals.declined-article');
59+
}
60+
}

app/Notifications/SendApprovedArticle.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66

77
use App\Models\Article;
88
use Illuminate\Bus\Queueable;
9-
use Illuminate\Contracts\Queue\ShouldQueue;
109
use Illuminate\Notifications\Messages\MailMessage;
1110
use Illuminate\Notifications\Notification;
1211

13-
final class SendApprovedArticle extends Notification implements ShouldQueue
12+
final class SendApprovedArticle extends Notification
1413
{
1514
use Queueable;
1615

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Notifications;
6+
7+
use App\Models\Article;
8+
use Illuminate\Bus\Queueable;
9+
use Illuminate\Notifications\Messages\MailMessage;
10+
use Illuminate\Notifications\Notification;
11+
12+
final class SendDeclinedArticle extends Notification
13+
{
14+
use Queueable;
15+
16+
public function __construct(public Article $article, public array $data)
17+
{
18+
}
19+
20+
public function via(object $notifiable): array
21+
{
22+
return ['mail'];
23+
}
24+
25+
public function toMail(object $notifiable): MailMessage
26+
{
27+
return (new MailMessage())
28+
->subject(__('Article Décliné ❌.'))
29+
->greeting(__('Article Décliné : '.$this->data['raison']))
30+
->line(__('Nous avons le regret de vous informer que votre article a été décliné.'))
31+
->line($this->data['description'])
32+
->action(__('Voir mon article'), route('articles.show', $this->article))
33+
->line(__('Merci d\'avoir utilisé Laravel Cameroun.!'));
34+
}
35+
}

resources/views/articles/show.blade.php

+60-52
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
<button {{ $attributes->merge(['class' => 'inline-flex justify-center w-full rounded-md border border-transparent px-4 py-2 bg-negative-600 text-base leading-6 font-medium text-white shadow-sm hover:bg-negative-500 focus:outline-none focus:border-negative-700 sm:text-sm sm:leading-5 focus:ring-2 focus:ring-offset-2 focus:ring-offset-body focus:ring-negative-500']) }}>
1+
<button {{ $attributes->merge(['class' => 'button inline-flex items-center justify-center rounded-md border border-transparent px-4 py-2 bg-danger-600 text-base leading-6 font-medium text-white shadow-sm hover:bg-danger-500 focus:outline-none focus:border-danger-700 sm:text-sm sm:leading-5 focus:ring-2 focus:ring-offset-2 focus:ring-offset-body focus:ring-danger-500']) }}>
22
{{ $slot }}
33
</button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<x-modal
2+
header-classes="p-4 border-b border-gray-100 sm:px-6 sm:py-4"
3+
content-classes="relative p-4 flex-1 sm:max-h-[500px] sm:px-6 sm:px-5"
4+
footer-classes="px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"
5+
form-action="save"
6+
>
7+
<x-slot name="title">
8+
{{ $title }}
9+
</x-slot>
10+
11+
<div class="space-y-4 pb-5">
12+
<div class="grid grid-cols-2 gap-4">
13+
<div class="space-y-2">
14+
<x-forms.label for="first_name" :value="__('First name')" required />
15+
<x-forms.input wire:model="first_name" id="first_name" name="first_name" type="text"/>
16+
<x-forms.errors :messages="$errors->get('first_name')" />
17+
</div>
18+
19+
<div class="space-y-2">
20+
<x-forms.label for="last_name" :value="__('Last name')" required />
21+
<x-forms.input wire:model="last_name" id="last_name" name="last_name" type="text"/>
22+
<x-forms.errors :messages="$errors->get('last_name')" />
23+
</div>
24+
</div>
25+
26+
<div class="space-y-2">
27+
<x-forms.label for="street_address" :value="__('Street Address')" required />
28+
<x-forms.input
29+
wire:model="street_address"
30+
id="street_address"
31+
placeholder="Akwa Avenue 34"
32+
class="w-full"
33+
name="street_address"
34+
type="text"
35+
/>
36+
<x-forms.errors :messages="$errors->get('street_address')" />
37+
</div>
38+
39+
<div class="space-y-2">
40+
<x-forms.label for="street_address_plus" :value="__('Apartment, suite, etc.')" />
41+
<x-forms.input
42+
wire:model="street_address_plus"
43+
class="w-full"
44+
id="street_address_plus"
45+
name="street_address_plus"
46+
type="text"
47+
/>
48+
<x-forms.errors :messages="$errors->get('street_address_plus')" />
49+
</div>
50+
51+
<div class="grid grid-cols-2 gap-4">
52+
<div class="space-y-2">
53+
<x-forms.label for="city" :value="__('City')" required/>
54+
<x-forms.input wire:model="city" id="city" name="city" type="text" />
55+
<x-forms.errors :messages="$errors->get('city')" class="mt-2" />
56+
</div>
57+
58+
<div class="space-y-2">
59+
<x-forms.label for="postal_code" :value="__('Postal / Zip code')" required />
60+
<x-forms.input wire:model="postal_code" id="postal_code" name="postal_code" type="text"/>
61+
<x-forms.errors :messages="$errors->get('postal_code')" class="mt-2" />
62+
</div>
63+
64+
</div>
65+
66+
<div class="space-y-2">
67+
<x-forms.label for="country_id" :value="__('Country')" required />
68+
<x-forms.select wire:model="country_id" id="country_id" class="w-full">
69+
@foreach ($countries as $key => $country)
70+
<option value="{{ $key }}">{{ $country }}</option>
71+
@endforeach
72+
</x-forms.select>
73+
<x-forms.errors :messages="$errors->get('country_id')" />
74+
</div>
75+
76+
<div class="space-y-2">
77+
<x-forms.label for="phone_number" :value="__('Phone Number')" />
78+
<x-forms.input wire:model="phone_number" class="w-full" id="phone_number" name="phone_number" type="text" />
79+
<x-forms.errors :messages="$errors->get('phone_number')" />
80+
</div>
81+
82+
<div class="grid gap-y-2 sm:grid-cols-3 sm:gap-x-4 sm:items-start">
83+
<div class="flex items-center justify-between gap-x-3 ">
84+
<x-forms.label for="adress_type" :value="__('Address type')" />
85+
</div>
86+
87+
<div class="grid auto-cols-fr gap-y-2 sm:col-span-2">
88+
<div class="columns-[--cols-default] fi-fo-radio gap-4 flex flex-wrap">
89+
<div>
90+
<x-forms.label class="flex items-center gap-3">
91+
<x-forms.radio id="type-billing" name="type" value="billing" wire:model="type"/>
92+
{{ __('Billing address') }}
93+
</x-forms.label>
94+
</div>
95+
96+
<div>
97+
<x-forms.label class="flex items-center gap-3">
98+
<x-forms.radio id="type-shipping" name="type" value="shipping" wire:model="type"/>
99+
{{ __('Shipping address') }}
100+
</x-forms.label>
101+
</div>
102+
</div>
103+
</div>
104+
<x-forms.errors :messages="$errors->get('type')" class="mt-2" />
105+
</div>
106+
</div>
107+
108+
<x-slot name="buttons">
109+
<x-buttons.submit
110+
:title="__('shopper::forms.actions.save')"
111+
wire:loading.attr="data-loading"
112+
class="w-full sm:ml-3 sm:w-auto"
113+
/>
114+
<x-buttons.default
115+
type="button"
116+
wire:click="$dispatch('closeModal')"
117+
class="w-full px-4 py-2 mt-3 text-sm sm:mt-0 sm:w-auto"
118+
>
119+
{{ __('shopper::forms.actions.cancel') }}
120+
</x-buttons.default>
121+
</x-slot>
122+
</x-modal>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@props(['messages'])
2+
3+
@if ($messages)
4+
<ul {{ $attributes->merge(['class' => 'text-sm text-danger-600 space-y-1']) }}>
5+
@foreach ((array) $messages as $message)
6+
<li>{{ $message }}</li>
7+
@endforeach
8+
</ul>
9+
@endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@props(['disabled' => false])
2+
3+
<input {{ $disabled ? 'disabled' : '' }} {!! $attributes->merge(['class' => 'inline-flex w-full py-2 rounded-lg placeholder-gray-500 border-gray-200 focus:ring-primary-500 focus:ring-2 focus:border-transparent focus:outline-none sm:text-sm']) !!}>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@props(['value', 'required'])
2+
3+
<label {{ $attributes->merge(['class' => 'block font-medium text-sm text-gray-700']) }}>
4+
{{ $value ?? $slot }}
5+
@if(isset($required))
6+
<span class="text-red-600">*</span>
7+
@endif
8+
</label>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@props(['disabled' => false])
2+
3+
<textarea {{ $disabled ? 'disabled' : '' }} {!! $attributes->merge(['class' => 'block p-2.5 w-full text-sm placeholder-gray-500 bg-gray-50 rounded-lg border border-gray-200 focus:ring-primary-500 focus:border-primary-500']) !!}>{{ $slot }}</textarea>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<x-modal footerClasses="px-4 pb-5 sm:px-4 sm:flex sm:flex-row-reverse">
2+
<x-slot name="content" class="space-y-4">
3+
<div class="space-y-2">
4+
<x-forms.label for="raison" :value="__('Motif du rejet')" required/>
5+
<x-forms.input wire:model="raison" id="raison" name="raison" type="text"/>
6+
<x-forms.errors :messages="$errors->get('raison')" />
7+
</div>
8+
<div class="space-y-2">
9+
<x-forms.label for='description' :value="__('Description')" required />
10+
<x-forms.textarea id='description' rows='4' wire:model='description' placeholder='Descrition du rejet' name="description"></x-forms.textarea>
11+
<x-forms.errors :messages="$errors->get('description')" />
12+
</div>
13+
</x-slot>
14+
15+
<x-slot name="buttons">
16+
<span class="flex w-full rounded-md shadow-sm sm:ml-3 sm:w-auto">
17+
<x-danger-button wire:click="declined" type="button">
18+
<x-loader class="text-white" wire:loading wire:target="declined" />
19+
{{ __('Decliner') }}
20+
</x-danger-button>
21+
</span>
22+
<span class="flex w-full mt-3 rounded-md shadow-sm sm:mt-0 sm:w-auto">
23+
<x-default-button wire:click="$emit('closeModal')" type="button">
24+
{{ __('Annuler') }}
25+
</x-default-button>
26+
</span>
27+
</x-slot>
28+
</x-modal>

0 commit comments

Comments
 (0)