diff --git a/app/Events/Models/Message/MessageCreated.php b/app/Events/Models/Message/MessageCreated.php index 9e610ec..d284250 100644 --- a/app/Events/Models/Message/MessageCreated.php +++ b/app/Events/Models/Message/MessageCreated.php @@ -6,11 +6,22 @@ use App\Events\AbstractLogicalEvent; use App\Models\Message; +use Illuminate\Broadcasting\PrivateChannel; +use Illuminate\Contracts\Broadcasting\ShouldBroadcast; -class MessageCreated extends AbstractLogicalEvent +class MessageCreated extends AbstractLogicalEvent implements ShouldBroadcast { public function __construct( public Message $model, ) { } + + public function broadcastOn() + { + $this->model->load('credential'); + + return [ + new PrivateChannel('App.Models.User.'.$this->model->credential->user_id,) + ]; + } } diff --git a/app/Http/Controllers/Api/Mail/MarkAsReadController.php b/app/Http/Controllers/Api/Mail/MarkAsReadController.php index 6bcbb6f..34ec203 100644 --- a/app/Http/Controllers/Api/Mail/MarkAsReadController.php +++ b/app/Http/Controllers/Api/Mail/MarkAsReadController.php @@ -5,18 +5,27 @@ namespace App\Http\Controllers\Api\Mail; use App\Http\Controllers\Controller; -use App\Http\Requests\Messages\MarkAsReadRequest; +use App\Http\Requests\Messages\MailOwnerRequest; use App\Models\Message; use App\Services\ImapService; use App\Services\Messaging\ImapFactoryService; class MarkAsReadController extends Controller { - public function __invoke(MarkAsReadRequest $request, ImapFactoryService $factoryService) + public function __invoke(MailOwnerRequest $request, ImapFactoryService $factoryService) { request()->validate([ 'id' => 'integer', ]); + $message = Message::query() + ->with('credential') + ->findOrFail($request->get('id')); + + $service = $factoryService->make($message->credential); + $service->markAsRead($message->event_id); + $message->update([ + 'seen' => true, + ]); } } diff --git a/app/Http/Controllers/Api/Mail/MarkAsUnreadController.php b/app/Http/Controllers/Api/Mail/MarkAsUnreadController.php index 334c5ef..4457e5e 100644 --- a/app/Http/Controllers/Api/Mail/MarkAsUnreadController.php +++ b/app/Http/Controllers/Api/Mail/MarkAsUnreadController.php @@ -5,16 +5,27 @@ namespace App\Http\Controllers\Api\Mail; use App\Http\Controllers\Controller; +use App\Http\Requests\Messages\MailOwnerRequest; +use App\Models\Message; use App\Services\ImapService; +use App\Services\Messaging\ImapFactoryService; class MarkAsUnreadController extends Controller { - public function __invoke(ImapService $imap) + public function __invoke(MailOwnerRequest $request, ImapFactoryService $factoryService) { request()->validate([ 'id' => 'integer', ]); - $imap->markAsUnread(request('id')); + $message = Message::query() + ->with('credential') + ->findOrFail($request->get('id')); + + $service = $factoryService->make($message->credential); + $service->markAsUnread($message->event_id); + $message->update([ + 'seen' => false, + ]); } } diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 50aafaf..44a9c13 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -48,6 +48,13 @@ public function share(Request $request): array 'page', request('page') ), + 'unread_email_count' => $request->user() ? + $request->user()->messages() + ->where('messages.type', 'email') + ->where('seen', false) + ->count() + : 0, + 'notifications' => $request->user()?->notifications ?? [], ]); } } diff --git a/app/Http/Requests/Messages/MarkAsReadRequest.php b/app/Http/Requests/Messages/MailOwnerRequest.php similarity index 50% rename from app/Http/Requests/Messages/MarkAsReadRequest.php rename to app/Http/Requests/Messages/MailOwnerRequest.php index 8ac732b..4afe5c5 100644 --- a/app/Http/Requests/Messages/MarkAsReadRequest.php +++ b/app/Http/Requests/Messages/MailOwnerRequest.php @@ -5,26 +5,15 @@ use App\Models\Message; use Illuminate\Foundation\Http\FormRequest; -class MarkAsReadRequest extends FormRequest +class MailOwnerRequest extends FormRequest { - /** - * Determine if the user is authorized to make this request. - */ public function authorize(): bool { $messageId = $this->get('id'); $message = Message::findOrFail($messageId); - -dd($message); - - return false; + return $this->user()->credentials()->where('id', $message->credential_id)->exists(); } - /** - * Get the validation rules that apply to the request. - * - * @return array|string> - */ public function rules(): array { return [ diff --git a/app/Jobs/SyncMailboxIfCredentialsAreSet.php b/app/Jobs/SyncMailboxIfCredentialsAreSet.php index a7a745a..4707b7a 100644 --- a/app/Jobs/SyncMailboxIfCredentialsAreSet.php +++ b/app/Jobs/SyncMailboxIfCredentialsAreSet.php @@ -28,7 +28,7 @@ public function __construct( protected Credential $credential, protected ?Carbon $since = null, ) { - $this->since = now()->subDay(); + $this->since = now()->subMonth(); } public function handle(ImapFactoryService $imapFactory): void diff --git a/app/Models/Message.php b/app/Models/Message.php index f009b2e..5ef5ac2 100644 --- a/app/Models/Message.php +++ b/app/Models/Message.php @@ -15,6 +15,9 @@ use Spatie\Tags\HasTags; use Staudenmeir\EloquentJsonRelations\HasJsonRelationships; +/** + * @property-read Credential $credential + */ /** @mixin \Eloquent */ class Message extends Model { @@ -64,6 +67,11 @@ public function getIsUserAttribute() return auth()->id() === $this->from_person; } + public function credential() + { + return $this->belongsTo(Credential::class); + } + public function fromPerson() { return $this->belongsTo(Person::class, 'from_person'); diff --git a/app/Models/User.php b/app/Models/User.php index e28319f..13086e8 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -108,6 +108,7 @@ public function accounts() { return $this->hasManyThrough(Account::class, Credential::class); } + public function messages() { return $this->hasManyThrough(Message::class, Credential::class)->orderByDesc('originated_at'); diff --git a/config/app.php b/config/app.php index 63bb19c..5fd1355 100644 --- a/config/app.php +++ b/config/app.php @@ -167,7 +167,7 @@ */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, - // App\Providers\BroadcastServiceProvider::class, + App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\HorizonServiceProvider::class, App\Providers\Filament\AdminPanelProvider::class, diff --git a/package.json b/package.json index dc73ef8..432ab65 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "vue-draggable-next": "^2.2.1", "vue-json-pretty": "^2.2.4", "vue-select": "^4.0.0-beta.6", + "vue3-markdown-it": "^1.0.10", "vuedraggable": "^4.1.0", "vuex": "^4.1.0", "ws": "^8.14.2", diff --git a/resources/js/Components/Spork/CrudView.vue b/resources/js/Components/Spork/CrudView.vue index 095102b..38952dc 100644 --- a/resources/js/Components/Spork/CrudView.vue +++ b/resources/js/Components/Spork/CrudView.vue @@ -76,7 +76,7 @@
- +
fallback: {{ datum}}
@@ -119,9 +119,9 @@ -
-
-
+
+
+
Create Modal
- -
- +
+ + Close + + - Save - + primary + medium + > + Save +
-
+
diff --git a/resources/js/Components/Spork/SporkDynamicInput.vue b/resources/js/Components/Spork/SporkDynamicInput.vue index 852e3e5..f982fbf 100644 --- a/resources/js/Components/Spork/SporkDynamicInput.vue +++ b/resources/js/Components/Spork/SporkDynamicInput.vue @@ -1,12 +1,14 @@ - diff --git a/resources/js/Layouts/AppLayout.vue b/resources/js/Layouts/AppLayout.vue index 5fa3cf4..068f69f 100644 --- a/resources/js/Layouts/AppLayout.vue +++ b/resources/js/Layouts/AppLayout.vue @@ -44,6 +44,9 @@ const userNavigation = [ { name: 'Sign out', href: '#' }, ] +const notificationCount = computed(() => { + return (page.props.unread_email_count ?? 0) + page.props.notifications.length +}); const sidebarOpen = ref(false) const showingNavigationDropdown = ref(false); const $settings = computed(() => page.props) @@ -82,7 +85,7 @@ const logout = () => { - +
@@ -120,11 +123,11 @@ const logout = () => { -